Files

155 lines
5.6 KiB
Python
Raw Permalink Normal View History

"""
Test for MposKeyboard mode switching crash.
This test reproduces the crash that occurs when clicking the UP arrow
to switch to uppercase mode in MposKeyboard.
Usage:
Desktop: ./tests/unittest.sh tests/test_graphical_keyboard_mode_switch.py
Device: ./tests/unittest.sh tests/test_graphical_keyboard_mode_switch.py --ondevice
"""
import unittest
import lvgl as lv
2026-01-13 00:38:17 +01:00
from mpos import MposKeyboard, wait_for_render
class TestKeyboardModeSwitch(unittest.TestCase):
"""Test keyboard mode switching doesn't crash."""
def setUp(self):
"""Set up test fixtures."""
self.screen = lv.obj()
self.screen.set_size(320, 240)
# Create textarea
self.textarea = lv.textarea(self.screen)
self.textarea.set_size(280, 40)
self.textarea.align(lv.ALIGN.TOP_MID, 0, 10)
self.textarea.set_one_line(True)
# Load screen
lv.screen_load(self.screen)
wait_for_render(5)
def tearDown(self):
"""Clean up."""
lv.screen_load(lv.obj())
wait_for_render(5)
def test_switch_to_uppercase_with_symbol_up(self):
"""
Test switching to uppercase mode.
This reproduces the crash that occurred when clicking the UP arrow button.
The bug was that set_mode() was called without set_map() first.
"""
print("\n=== Testing uppercase mode switch ===")
# Create keyboard
keyboard = MposKeyboard(self.screen)
keyboard.set_textarea(self.textarea)
keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0)
wait_for_render(10)
# Keyboard starts in lowercase mode
print("Initial mode: MODE_LOWERCASE")
# Find the UP symbol button by searching all buttons
up_button_index = None
for i in range(100): # Try up to 100 buttons
try:
text = keyboard.get_button_text(i)
if text == lv.SYMBOL.UP:
up_button_index = i
print(f"Found UP symbol at button index {i}")
break
except:
pass
self.assertIsNotNone(up_button_index, "Should find UP symbol button")
# Test mode switching (this is what happens when the user clicks UP)
print("Switching to uppercase mode...")
try:
keyboard.set_mode(MposKeyboard.MODE_UPPERCASE)
wait_for_render(5)
print("SUCCESS: No crash when switching to uppercase!")
# Verify we're now in uppercase mode by checking the button changed
down_button_text = keyboard.get_button_text(up_button_index)
print(f"After switch, button {up_button_index} text: {down_button_text}")
self.assertEqual(down_button_text, lv.SYMBOL.DOWN,
"Should show DOWN symbol in uppercase mode")
# Switch back to lowercase
keyboard.set_mode(MposKeyboard.MODE_LOWERCASE)
wait_for_render(5)
up_button_text = keyboard.get_button_text(up_button_index)
self.assertEqual(up_button_text, lv.SYMBOL.UP,
"Should show UP symbol in lowercase mode")
except Exception as e:
self.fail(f"CRASH: Switching to uppercase caused exception: {e}")
def test_switch_modes_multiple_times(self):
"""
Test switching between all keyboard modes multiple times.
Tests the full mode switching cycle to ensure all modes work.
"""
print("\n=== Testing multiple mode switches ===")
keyboard = MposKeyboard(self.screen)
keyboard.set_textarea(self.textarea)
keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0)
wait_for_render(10)
modes_to_test = [
(MposKeyboard.MODE_UPPERCASE, "MODE_UPPERCASE"),
(MposKeyboard.MODE_LOWERCASE, "MODE_LOWERCASE"),
(MposKeyboard.MODE_NUMBERS, "MODE_NUMBERS"),
(MposKeyboard.MODE_SPECIALS, "MODE_SPECIALS"),
(MposKeyboard.MODE_LOWERCASE, "MODE_LOWERCASE (again)"),
]
for mode, mode_name in modes_to_test:
print(f"Switching to {mode_name}...")
try:
keyboard.set_mode(mode)
wait_for_render(5)
print(f" SUCCESS: Switched to {mode_name}")
except Exception as e:
self.fail(f" CRASH: Switching to {mode_name} caused exception: {e}")
2025-11-16 19:12:49 +01:00
def test_event_handler_exists(self):
"""
Verify that the event handler exists and is properly connected.
The _handle_events method should filter events to only process
VALUE_CHANGED events. This prevents duplicate characters from being
typed when other events (like PRESSED, RELEASED, etc.) are fired.
The fix ensures:
1. Only VALUE_CHANGED events are processed
2. None/invalid button text is ignored
3. Each button press results in exactly ONE character being added
"""
print("\n=== Verifying event handler exists ===")
keyboard = MposKeyboard(self.screen)
keyboard.set_textarea(self.textarea)
keyboard.align(lv.ALIGN.BOTTOM_MID, 0, 0)
wait_for_render(10)
# Verify the event handler method exists and is callable
self.assertTrue(hasattr(keyboard, '_handle_events'),
"Keyboard should have _handle_events method")
self.assertTrue(callable(keyboard._handle_events),
"_handle_events should be callable")
print("SUCCESS: Event handler exists and is properly set up")
print("Note: The handler filters for VALUE_CHANGED events only")