File size: 2,073 Bytes
fc3e70a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | # This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
"""Tests: Phase 3 — Decoder FSM."""
import pytest
from semantic_engine.fsm import FSMContext, TRANSITION_TABLE, validate_constraints
from semantic_engine.types import FSMState, PipelineError
def test_initial_state():
ctx = FSMContext()
assert ctx.state == FSMState.INPUT
def test_valid_transition():
ctx = FSMContext()
ctx.set("raw_text", "hello world")
t = ctx.transition("raw_input")
assert ctx.state == FSMState.NORMALIZE
assert t.source_state == FSMState.INPUT
def test_invalid_transition_fails_closed():
ctx = FSMContext()
with pytest.raises(PipelineError) as exc_info:
ctx.transition("invalid_class_xyz")
assert "fail" in str(exc_info.value).lower() or "transition" in str(exc_info.value).lower()
def test_transition_history_recorded():
ctx = FSMContext()
ctx.set("raw_text", "hello")
ctx.transition("raw_input")
assert len(ctx.history) == 1
src, inp, dst = ctx.history[0]
assert src == FSMState.INPUT
assert dst == FSMState.NORMALIZE
def test_all_transitions_explicit():
"""Every transition in the table must have source, input_class, destination."""
for t in TRANSITION_TABLE:
assert t.source_state is not None
assert t.input_class
assert t.destination_state is not None
assert t.invariant
def test_transition_table_no_duplicate_keys():
keys = [(t.source_state, t.input_class) for t in TRANSITION_TABLE]
assert len(keys) == len(set(keys)), "Duplicate transition keys found"
def test_is_terminal():
ctx = FSMContext()
assert not ctx.is_terminal()
ctx.state = FSMState.COMPLETE
assert ctx.is_terminal()
ctx.state = FSMState.ERROR
assert ctx.is_terminal()
def test_context_set_get():
ctx = FSMContext()
ctx.set("foo", 42)
assert ctx.get("foo") == 42
assert ctx.get("missing") is None
|