from styles.blink import ( STATE_BLINKING, STATE_EVALUATING, STATE_WAIT_BEFORE_BLINK, STATE_WAIT_BEFORE_RETRY, STATE_WAIT_FOR_INPUT, BlinkStyle, ) def _led(): """Return (calls list, set_led callable recording each call).""" calls = [] return calls, lambda on: calls.append(on) def test_press_starts_puzzle(): _, set_led = _led() style = BlinkStyle(set_led) assert style.update(100.0, True) is True assert style.state == STATE_WAIT_BEFORE_BLINK def test_blink_correct_sequence_stops(monkeypatch): _, set_led = _led() style = BlinkStyle(set_led) style.update(100.0, True) # press -> start puzzle assert style.state == STATE_WAIT_BEFORE_BLINK monkeypatch.setattr("styles.blink.random.randint", lambda a, b: 3) style.update(103.1, False) # 3s passed -> blinking, 3 blinks assert style.state == STATE_BLINKING assert style.target_blinks == 3 style.update(105.0, False) # run through the blink sequence assert style.state == STATE_WAIT_FOR_INPUT # Press exactly 3 times for t in (105.5, 106.0, 106.5): style.update(t, True) style.update(t + 0.05, False) assert style.user_presses == 3 style.update(109.7, False) # 3s idle -> evaluating assert style.state == STATE_EVALUATING assert style.update(109.8, False) is False # correct -> stop def test_blink_incorrect_retries(): _, set_led = _led() style = BlinkStyle(set_led) style.state = STATE_WAIT_FOR_INPUT style.target_blinks = 3 style.update(100.0, True) # one press style.update(100.1, False) style.last_interaction_time = 100.1 style.update(103.2, False) # -> evaluating keep_running = style.update(103.3, False) # 1 != 3 -> retry assert keep_running is True assert style.state == STATE_WAIT_BEFORE_RETRY def test_blinking_non_blocking(): calls, set_led = _led() style = BlinkStyle(set_led) style.state = STATE_BLINKING style.target_blinks = 2 style.update(100.0, False) # start of blinking: LED on assert style.state == STATE_BLINKING assert calls[-1] is True style.update(100.3, False) # mid-blink toggles by elapsed time assert calls[-1] is False # 2 blinks * 2 phases * 0.3s = 1.2s style.update(101.2, False) assert style.state == STATE_WAIT_FOR_INPUT assert calls[-1] is False def test_blinking_advances_time(): _, set_led = _led() style = BlinkStyle(set_led) style.state = STATE_BLINKING style.target_blinks = 4 # 4 blinks * 2 phases * 0.3s = 2.4s style.update(100.0, False) style.update(102.4, False) assert style.state == STATE_WAIT_FOR_INPUT assert style.last_interaction_time == 102.4