File size: 3,180 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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 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 8 — Boolean token engine."""

import pytest
from semantic_engine.boolean_engine import AND, OR, NOT, var, lit, BooleanLiteral, BooleanVar
from semantic_engine.token_engine import (
    BoolEncoder, BoolDecoder, BooleanTokenStream,
    encode_binary, decode_binary, encode, decode, round_trip,
    TTYPE_AND, TTYPE_OR, TTYPE_NOT, TTYPE_TRUE, TTYPE_FALSE,
    TTYPE_VAR, TTYPE_VAR_NEG, TTYPE_OPEN, TTYPE_CLOSE,
)
from semantic_engine.types import FSMState, TokenError


def encode_and_check(expr):
    stream = BoolEncoder().encode_expr(expr)
    binary = encode_binary(stream)
    decoded = decode_binary(binary)
    return stream, binary, decoded


def test_encode_literal_true():
    stream, binary, decoded = encode_and_check(BooleanLiteral(True))
    assert len(decoded.tokens) == 1
    assert decoded.tokens[0].token_type == TTYPE_TRUE


def test_encode_literal_false():
    stream, binary, decoded = encode_and_check(BooleanLiteral(False))
    assert decoded.tokens[0].token_type == TTYPE_FALSE


def test_encode_var():
    stream, binary, decoded = encode_and_check(BooleanVar("x"))
    assert decoded.tokens[0].token_type == TTYPE_VAR
    assert decoded.tokens[0].payload == b"x"


def test_encode_var_negated():
    stream, binary, decoded = encode_and_check(BooleanVar("x", negated=True))
    assert decoded.tokens[0].token_type == TTYPE_VAR_NEG
    assert decoded.tokens[0].payload == b"x"


def test_encode_and():
    expr = AND(var("a"), var("b"))
    stream = BoolEncoder().encode_expr(expr)
    types = [t.token_type for t in stream]
    assert TTYPE_AND in types
    assert TTYPE_OPEN in types
    assert TTYPE_CLOSE in types


def test_encode_not():
    expr = NOT(var("x"))
    stream = BoolEncoder().encode_expr(expr)
    types = [t.token_type for t in stream]
    assert TTYPE_NOT in types


def test_round_trip_literal():
    expr = BooleanLiteral(True)
    result = round_trip(expr)
    assert isinstance(result, BooleanLiteral)
    assert result.value is True


def test_round_trip_var():
    expr = BooleanVar("myvar")
    result = round_trip(expr)
    assert isinstance(result, BooleanVar)
    assert result.name == "myvar"
    assert not result.negated


def test_round_trip_complex():
    expr = AND(var("a"), OR(var("b"), NOT(var("c"))))
    result = round_trip(expr)
    # repr should match after round-trip
    assert repr(result) == repr(expr)


def test_binary_bad_magic():
    with pytest.raises(TokenError):
        decode_binary(b"XXXX\x01\x00\x01")


def test_binary_too_short():
    with pytest.raises(TokenError):
        decode_binary(b"BO")


def test_token_positions():
    expr = AND(var("a"), var("b"))
    stream = BoolEncoder().encode_expr(expr)
    for i, tok in enumerate(stream):
        assert tok.position == i


def test_token_ids_unique():
    expr = AND(var("a"), OR(var("b"), var("c")))
    stream = BoolEncoder().encode_expr(expr)
    ids = [t.token_id for t in stream]
    assert len(ids) == len(set(ids))