|
| 1 | +""" |
| 2 | +Test for MposKeyboard mode switching crash. |
| 3 | +
|
| 4 | +This test reproduces the crash that occurs when clicking the UP arrow |
| 5 | +to switch to uppercase mode in MposKeyboard. |
| 6 | +
|
| 7 | +Usage: |
| 8 | + Desktop: ./tests/unittest.sh tests/test_graphical_keyboard_mode_switch.py |
| 9 | + Device: ./tests/unittest.sh tests/test_graphical_keyboard_mode_switch.py --ondevice |
| 10 | +""" |
| 11 | + |
| 12 | +import unittest |
| 13 | +import lvgl as lv |
| 14 | +from mpos.ui.keyboard import MposKeyboard |
| 15 | +from graphical_test_helper import wait_for_render |
| 16 | + |
| 17 | + |
| 18 | +class TestKeyboardModeSwitch(unittest.TestCase): |
| 19 | + """Test keyboard mode switching doesn't crash.""" |
| 20 | + |
| 21 | + def setUp(self): |
| 22 | + """Set up test fixtures.""" |
| 23 | + self.screen = lv.obj() |
| 24 | + self.screen.set_size(320, 240) |
| 25 | + |
| 26 | + # Create textarea |
| 27 | + self.textarea = lv.textarea(self.screen) |
| 28 | + self.textarea.set_size(280, 40) |
| 29 | + self.textarea.align(lv.ALIGN.TOP_MID, 0, 10) |
| 30 | + self.textarea.set_one_line(True) |
| 31 | + |
| 32 | + # Load screen |
| 33 | + lv.screen_load(self.screen) |
| 34 | + wait_for_render(5) |
| 35 | + |
| 36 | + def tearDown(self): |
| 37 | + """Clean up.""" |
| 38 | + lv.screen_load(lv.obj()) |
| 39 | + wait_for_render(5) |
| 40 | + |
| 41 | + def test_switch_to_uppercase_with_symbol_up(self): |
| 42 | + """ |
| 43 | + Test switching to uppercase mode. |
| 44 | +
|
| 45 | + This reproduces the crash that occurred when clicking the UP arrow button. |
| 46 | + The bug was that set_mode() was called without set_map() first. |
| 47 | + """ |
| 48 | + print("\n=== Testing uppercase mode switch ===") |
| 49 | + |
| 50 | + # Create keyboard |
| 51 | + keyboard = MposKeyboard(self.screen) |
| 52 | + keyboard.set_textarea(self.textarea) |
| 53 | + keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) |
| 54 | + wait_for_render(10) |
| 55 | + |
| 56 | + # Keyboard starts in lowercase mode |
| 57 | + print("Initial mode: MODE_LOWERCASE") |
| 58 | + |
| 59 | + # Find the UP symbol button by searching all buttons |
| 60 | + up_button_index = None |
| 61 | + for i in range(100): # Try up to 100 buttons |
| 62 | + try: |
| 63 | + text = keyboard.get_button_text(i) |
| 64 | + if text == lv.SYMBOL.UP: |
| 65 | + up_button_index = i |
| 66 | + print(f"Found UP symbol at button index {i}") |
| 67 | + break |
| 68 | + except: |
| 69 | + pass |
| 70 | + |
| 71 | + self.assertIsNotNone(up_button_index, "Should find UP symbol button") |
| 72 | + |
| 73 | + # Test mode switching (this is what happens when the user clicks UP) |
| 74 | + print("Switching to uppercase mode...") |
| 75 | + try: |
| 76 | + keyboard.set_mode(MposKeyboard.MODE_UPPERCASE) |
| 77 | + wait_for_render(5) |
| 78 | + print("SUCCESS: No crash when switching to uppercase!") |
| 79 | + |
| 80 | + # Verify we're now in uppercase mode by checking the button changed |
| 81 | + down_button_text = keyboard.get_button_text(up_button_index) |
| 82 | + print(f"After switch, button {up_button_index} text: {down_button_text}") |
| 83 | + self.assertEqual(down_button_text, lv.SYMBOL.DOWN, |
| 84 | + "Should show DOWN symbol in uppercase mode") |
| 85 | + |
| 86 | + # Switch back to lowercase |
| 87 | + keyboard.set_mode(MposKeyboard.MODE_LOWERCASE) |
| 88 | + wait_for_render(5) |
| 89 | + up_button_text = keyboard.get_button_text(up_button_index) |
| 90 | + self.assertEqual(up_button_text, lv.SYMBOL.UP, |
| 91 | + "Should show UP symbol in lowercase mode") |
| 92 | + |
| 93 | + except Exception as e: |
| 94 | + self.fail(f"CRASH: Switching to uppercase caused exception: {e}") |
| 95 | + |
| 96 | + def test_switch_modes_multiple_times(self): |
| 97 | + """ |
| 98 | + Test switching between all keyboard modes multiple times. |
| 99 | +
|
| 100 | + Tests the full mode switching cycle to ensure all modes work. |
| 101 | + """ |
| 102 | + print("\n=== Testing multiple mode switches ===") |
| 103 | + |
| 104 | + keyboard = MposKeyboard(self.screen) |
| 105 | + keyboard.set_textarea(self.textarea) |
| 106 | + keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0) |
| 107 | + wait_for_render(10) |
| 108 | + |
| 109 | + modes_to_test = [ |
| 110 | + (MposKeyboard.MODE_UPPERCASE, "MODE_UPPERCASE"), |
| 111 | + (MposKeyboard.MODE_LOWERCASE, "MODE_LOWERCASE"), |
| 112 | + (MposKeyboard.MODE_NUMBERS, "MODE_NUMBERS"), |
| 113 | + (MposKeyboard.MODE_SPECIALS, "MODE_SPECIALS"), |
| 114 | + (MposKeyboard.MODE_LOWERCASE, "MODE_LOWERCASE (again)"), |
| 115 | + ] |
| 116 | + |
| 117 | + for mode, mode_name in modes_to_test: |
| 118 | + print(f"Switching to {mode_name}...") |
| 119 | + try: |
| 120 | + keyboard.set_mode(mode) |
| 121 | + wait_for_render(5) |
| 122 | + print(f" SUCCESS: Switched to {mode_name}") |
| 123 | + except Exception as e: |
| 124 | + self.fail(f" CRASH: Switching to {mode_name} caused exception: {e}") |
| 125 | + |
| 126 | + |
| 127 | +if __name__ == "__main__": |
| 128 | + unittest.main() |
0 commit comments