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