You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

544 lines
22 KiB

import pytest
import datetime
from unittest.mock import Mock, patch
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkWidgets.datetime_time import TTkTime, _FieldSelected
class TestTTkTimeKeyEvent:
def setup_method(self):
"""Set up test fixtures before each test method."""
self.time_widget = TTkTime(time=datetime.time(12, 30, 45))
def test_tab_navigation_forward(self):
"""Test forward Tab navigation through fields."""
# Start with NONE, tab to HOURS
self.time_widget._state.selected = _FieldSelected.NONE
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.HOURS
# From HOURS to MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.MINUTES
# From MINUTES to SECONDS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.SECONDS
# From SECONDS should return False (end of navigation)
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is False
def test_tab_navigation_backward(self):
"""Test backward Tab navigation (Shift+Tab) through fields."""
# Start with NONE, shift+tab to SECONDS
self.time_widget._state.selected = _FieldSelected.NONE
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.ShiftModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.SECONDS
# From SECONDS to MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.ShiftModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.MINUTES
# From MINUTES to HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.ShiftModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.HOURS
# From HOURS should return False
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.ShiftModifier)
result = self.time_widget.keyEvent(evt)
assert result is False
def test_arrow_key_navigation_right(self):
"""Test right arrow navigation through fields."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Right, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.MINUTES
def test_arrow_key_navigation_left(self):
"""Test left arrow navigation through fields."""
self.time_widget._state.selected = _FieldSelected.MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Left, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.HOURS
def test_up_arrow_increment_hours(self):
"""Test up arrow increments hours field."""
self.time_widget._state.selected = _FieldSelected.HOURS
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
expected_hour = (initial_time.hour + 1) % 24
assert new_time.hour == expected_hour
def test_up_arrow_increment_minutes(self):
"""Test up arrow increments minutes field."""
self.time_widget._state.selected = _FieldSelected.MINUTES
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
# Minutes increment by 1, wrapping at 60
expected_minutes = (initial_time.minute + 1) % 60
assert new_time.minute == expected_minutes
def test_up_arrow_increment_seconds(self):
"""Test up arrow increments seconds field."""
self.time_widget._state.selected = _FieldSelected.SECONDS
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
expected_seconds = (initial_time.second + 1) % 60
assert new_time.second == expected_seconds
def test_down_arrow_decrement_hours(self):
"""Test down arrow decrements hours field."""
self.time_widget._state.selected = _FieldSelected.HOURS
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Down, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
expected_hour = (initial_time.hour - 1) % 24
assert new_time.hour == expected_hour
def test_down_arrow_decrement_minutes(self):
"""Test down arrow decrements minutes field."""
self.time_widget._state.selected = _FieldSelected.MINUTES
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Down, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
expected_minutes = (initial_time.minute - 1) % 60
assert new_time.minute == expected_minutes
def test_down_arrow_decrement_seconds(self):
"""Test down arrow decrements seconds field."""
self.time_widget._state.selected = _FieldSelected.SECONDS
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Down, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
new_time = self.time_widget.time()
expected_seconds = (initial_time.second - 1) % 60
assert new_time.second == expected_seconds
def test_digit_input_hours_first_digit(self):
"""Test entering first digit in hours field."""
self.time_widget._state.selected = _FieldSelected.HOURS
self.time_widget._state.secondDigit = False
evt = TTkKeyEvent(TTkK.Character, "2", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().hour == 2
assert self.time_widget._state.secondDigit is True
def test_digit_input_hours_second_digit(self):
"""Test entering second digit in hours field."""
self.time_widget.setTime(datetime.time(2, 30, 45))
self.time_widget._state.selected = _FieldSelected.HOURS
self.time_widget._state.secondDigit = True
evt = TTkKeyEvent(TTkK.Character, "3", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().hour == 23
assert self.time_widget._state.secondDigit is False
def test_digit_input_hours_max_validation(self):
"""Test hours field validates maximum value (23)."""
self.time_widget._state.selected = _FieldSelected.HOURS
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(2, 30, 45))
evt = TTkKeyEvent(TTkK.Character, "9", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should be clamped to 23
assert self.time_widget.time().hour == 23
def test_digit_input_minutes_first_digit(self):
"""Test entering first digit in minutes field."""
self.time_widget._state.selected = _FieldSelected.MINUTES
self.time_widget._state.secondDigit = False
evt = TTkKeyEvent(TTkK.Character, "5", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().minute == 5
assert self.time_widget._state.secondDigit is True
def test_digit_input_minutes_second_digit(self):
"""Test entering second digit in minutes field."""
self.time_widget.setTime(datetime.time(12, 5, 45))
self.time_widget._state.selected = _FieldSelected.MINUTES
self.time_widget._state.secondDigit = True
evt = TTkKeyEvent(TTkK.Character, "7", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().minute == 57
assert self.time_widget._state.secondDigit is False
def test_digit_input_minutes_validation(self):
"""Test minutes field validates maximum value (59)."""
self.time_widget._state.selected = _FieldSelected.MINUTES
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(12, 6, 45))
evt = TTkKeyEvent(TTkK.Character, "9", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should be clamped to 59
assert self.time_widget.time().minute == 59
def test_digit_input_seconds_first_digit(self):
"""Test entering first digit in seconds field."""
self.time_widget._state.selected = _FieldSelected.SECONDS
self.time_widget._state.secondDigit = False
evt = TTkKeyEvent(TTkK.Character, "3", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().second == 3
assert self.time_widget._state.secondDigit is True
def test_digit_input_seconds_second_digit(self):
"""Test entering second digit in seconds field."""
self.time_widget.setTime(datetime.time(12, 30, 4))
self.time_widget._state.selected = _FieldSelected.SECONDS
self.time_widget._state.secondDigit = True
evt = TTkKeyEvent(TTkK.Character, "2", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().second == 42
assert self.time_widget._state.secondDigit is False
def test_digit_input_seconds_validation(self):
"""Test seconds field validates maximum value (59)."""
self.time_widget._state.selected = _FieldSelected.SECONDS
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(12, 30, 6))
evt = TTkKeyEvent(TTkK.Character, "9", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should be clamped to 59
assert self.time_widget.time().second == 59
def test_delete_key_clears_hours(self):
"""Test Delete key clears hours field."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Delete, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().hour == 0
def test_delete_key_clears_minutes(self):
"""Test Delete key clears minutes field."""
self.time_widget._state.selected = _FieldSelected.MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Delete, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().minute == 0
def test_delete_key_clears_seconds(self):
"""Test Delete key clears seconds field."""
self.time_widget._state.selected = _FieldSelected.SECONDS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Delete, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().second == 0
def test_backspace_key_clears_hours(self):
"""Test Backspace key clears hours field."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Backspace, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().hour == 0
def test_backspace_key_clears_minutes(self):
"""Test Backspace key clears minutes field."""
self.time_widget._state.selected = _FieldSelected.MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Backspace, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().minute == 0
def test_backspace_key_clears_seconds(self):
"""Test Backspace key clears seconds field."""
self.time_widget._state.selected = _FieldSelected.SECONDS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Backspace, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().second == 0
def test_enter_key_deselects_field(self):
"""Test Enter key deselects current field."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Enter, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget._state.selected == _FieldSelected.NONE
def test_time_overflow_hours_23_to_0(self):
"""Test hour overflow (23:59:59 + 1 hour -> 0:59:59)."""
self.time_widget.setTime(datetime.time(23, 59, 59))
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should wrap to 0:59:59 (next day boundary)
assert self.time_widget.time().hour == 23
assert self.time_widget.time().minute == 59
assert self.time_widget.time().second == 59
def test_time_underflow_hours_0_to_23(self):
"""Test hour underflow (0:0:0 - 1 hour -> 23:0:0)."""
self.time_widget.setTime(datetime.time(0, 0, 0))
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Down, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should wrap to 23:0:0 (previous day boundary)
assert self.time_widget.time().hour == 0
assert self.time_widget.time().minute == 0
assert self.time_widget.time().second == 0
def test_time_overflow_minutes_59_to_0(self):
"""Test minute overflow (12:59:30 + 1 minute -> 13:0:30)."""
self.time_widget.setTime(datetime.time(12, 59, 30))
self.time_widget._state.selected = _FieldSelected.MINUTES
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should increment hour and reset minutes
assert self.time_widget.time().hour == 13
assert self.time_widget.time().minute == 0
assert self.time_widget.time().second == 30
def test_time_overflow_seconds_59_to_0(self):
"""Test second overflow (12:30:59 + 1 second -> 12:31:0)."""
self.time_widget.setTime(datetime.time(12, 30, 59))
self.time_widget._state.selected = _FieldSelected.SECONDS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
# Should increment minute and reset seconds
assert self.time_widget.time().hour == 12
assert self.time_widget.time().minute == 31
assert self.time_widget.time().second == 0
# def test_no_field_selected_up_down_returns_false(self):
# """Test up/down keys return False when no field is selected."""
# self.time_widget._state.selected = _FieldSelected.NONE
# evt_up = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
# result_up = self.time_widget.keyEvent(evt_up)
# assert result_up is False
# evt_down = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Down, "", TTkK.NoModifier)
# result_down = self.time_widget.keyEvent(evt_down)
# assert result_down is False
def test_non_digit_character_returns_true(self):
"""Test non-digit character input returns True but doesn't change time."""
self.time_widget._state.selected = _FieldSelected.HOURS
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.Character, "a", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time() == initial_time
def test_digit_input_no_field_selected(self):
"""Test digit input when no field is selected returns True but no change."""
self.time_widget._state.selected = _FieldSelected.NONE
initial_time = self.time_widget.time()
evt = TTkKeyEvent(TTkK.Character, "5", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time() == initial_time
@patch.object(TTkTime, 'update')
def test_update_called_on_navigation(self, mock_update):
"""Test that update is called during navigation."""
self.time_widget._state.selected = _FieldSelected.NONE
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Tab, "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
mock_update.assert_called()
@patch.object(TTkTime, 'update')
def test_update_called_on_time_change(self, mock_update):
"""Test that update is called when time changes."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
mock_update.assert_called()
def test_second_digit_reset_on_special_keys(self):
"""Test that secondDigit is reset when special keys are pressed."""
self.time_widget._state.secondDigit = True
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
assert self.time_widget._state.secondDigit is False
def test_second_digit_toggle_on_digit_input(self):
"""Test that secondDigit toggles correctly on digit input."""
self.time_widget._state.selected = _FieldSelected.HOURS
self.time_widget._state.secondDigit = False
# First digit input
evt = TTkKeyEvent(TTkK.Character, "1", "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
assert self.time_widget._state.secondDigit is True
# Second digit input
evt = TTkKeyEvent(TTkK.Character, "5", "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
assert self.time_widget._state.secondDigit is False
def test_unknown_special_key_returns_false(self):
"""Test unknown special keys return False."""
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, 9999, "", TTkK.NoModifier) # Unknown key
result = self.time_widget.keyEvent(evt)
assert result is False
def test_time_changed_signal_emission(self):
"""Test that timeChanged signal is emitted when time changes."""
signal_received = []
def slot(time_value):
signal_received.append(time_value)
self.time_widget.timeChanged.connect(slot)
self.time_widget._state.selected = _FieldSelected.HOURS
evt = TTkKeyEvent(TTkK.SpecialKey, TTkK.Key_Up, "", TTkK.NoModifier)
self.time_widget.keyEvent(evt)
assert len(signal_received) == 1
assert isinstance(signal_received[0], datetime.time)
def test_boundary_digit_input_hours(self):
"""Test digit input at hours boundaries."""
# Test hour 24 gets clamped to 23
self.time_widget._state.selected = _FieldSelected.HOURS
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(2, 30, 45))
evt = TTkKeyEvent(TTkK.Character, "4", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().hour == 23 # Should be clamped
def test_boundary_digit_input_minutes(self):
"""Test digit input at minutes boundaries."""
# Test minute 60 gets clamped to 59
self.time_widget._state.selected = _FieldSelected.MINUTES
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(12, 6, 45))
evt = TTkKeyEvent(TTkK.Character, "0", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().minute == 59 # Should be clamped
def test_boundary_digit_input_seconds(self):
"""Test digit input at seconds boundaries."""
# Test second 60 gets clamped to 59
self.time_widget._state.selected = _FieldSelected.SECONDS
self.time_widget._state.secondDigit = True
self.time_widget.setTime(datetime.time(12, 30, 6))
evt = TTkKeyEvent(TTkK.Character, "0", "", TTkK.NoModifier)
result = self.time_widget.keyEvent(evt)
assert result is True
assert self.time_widget.time().second == 59 # Should be clamped