File size: 5,601 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# 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 20 β€” Round-trip and equivalence invariants."""

import pytest
from semantic_engine.boolean_engine import (
    AND, OR, NOT, XOR, IMPLIES, EQUIV,
    BooleanLiteral, BooleanVar,
    normalize, var, lit,
)
from semantic_engine.token_engine import encode, decode, round_trip, BoolEncoder, encode_binary, decode_binary
from semantic_engine.latin import LatinCanonicalizer
from semantic_engine.rosetta import RosettaMapper


# ── Boolean round-trips ───────────────────────────────────────────────────────

CANONICAL_EXPRS = [
    BooleanLiteral(True),
    BooleanLiteral(False),
    BooleanVar("x"),
    BooleanVar("x", negated=True),
    AND(BooleanVar("a"), BooleanVar("b")),
    OR(BooleanVar("a"), BooleanVar("b")),
    NOT(BooleanVar("x")),
    AND(BooleanVar("a"), OR(BooleanVar("b"), BooleanVar("c"))),
    OR(AND(BooleanVar("a"), BooleanVar("b")), NOT(BooleanVar("c"))),
]


@pytest.mark.parametrize("expr", CANONICAL_EXPRS)
def test_token_round_trip(expr):
    """decode(encode(x)) == x for all canonical Boolean structures."""
    result = round_trip(expr)
    assert repr(result) == repr(expr), f"Round-trip failed for {expr}"


@pytest.mark.parametrize("expr", CANONICAL_EXPRS)
def test_normalize_idempotent(expr):
    """normalize(normalize(x)) == normalize(x)"""
    n1 = normalize(expr)
    n2 = normalize(n1)
    assert repr(n1) == repr(n2), f"Normalization not idempotent for {expr}"


# ── Binary serialization round-trips ─────────────────────────────────────────

@pytest.mark.parametrize("expr", CANONICAL_EXPRS)
def test_binary_round_trip(expr):
    """Binary encode/decode preserves all tokens."""
    stream = BoolEncoder().encode_expr(expr)
    binary = encode_binary(stream)
    decoded_stream = decode_binary(binary)
    assert len(stream.tokens) == len(decoded_stream.tokens)
    for orig, dec in zip(stream.tokens, decoded_stream.tokens):
        assert orig.token_type == dec.token_type
        assert orig.payload == dec.payload


# ── Latin round-trip ─────────────────────────────────────────────────────────

@pytest.mark.parametrize("expr", CANONICAL_EXPRS)
def test_latin_derivable_from_tokens(expr):
    """Latin canonical form must derive from the token stream without loss."""
    stream = BoolEncoder().encode_expr(expr)
    latin = LatinCanonicalizer().canonicalize(stream)
    assert len(latin.tokens) > 0


# ── Pipeline semantic preservation ───────────────────────────────────────────

def test_pipeline_preserves_intent():
    from semantic_engine import SemanticPipeline, RawInput, OutputMode
    r = RawInput("build a matrix multiplication function")
    result = SemanticPipeline().run(r)
    assert result.ir is not None
    from semantic_engine.types import IntentClass
    assert result.ir.intent == IntentClass.BUILD


def test_pipeline_verified_on_valid_input():
    from semantic_engine import SemanticPipeline, RawInput
    from semantic_engine.types import VerificationState
    r = RawInput("multiply two matrices")
    result = SemanticPipeline().run(r)
    assert result.verification_state == VerificationState.VERIFIED


def test_pipeline_artifact_traces_to_ir():
    from semantic_engine import SemanticPipeline, RawInput
    r = RawInput("generate a parser for binary format")
    result = SemanticPipeline().run(r)
    assert result.artifact is not None
    assert result.artifact.semantic_root == result.ir.ir_id


def test_pipeline_hashes_recorded():
    from semantic_engine import SemanticPipeline, RawInput
    r = RawInput("validate packet structure")
    result = SemanticPipeline().run(r)
    assert "input" in result.hashes
    assert "semantic_ir" in result.hashes
    assert "subleq" in result.hashes
    assert "artifact" in result.hashes


def test_pipeline_deterministic_on_same_input():
    """Same input β†’ same semantic IR hash (modulo UUIDs)."""
    from semantic_engine import SemanticPipeline, RawInput
    text = "compute matrix product"
    r1 = RawInput(text)
    r2 = RawInput(text)
    p = SemanticPipeline()
    res1 = p.run(r1)
    res2 = p.run(r2)
    # Both must succeed and produce same intent
    assert res1.ir.intent == res2.ir.intent
    assert res1.ir.root.id == res2.ir.root.id  # node ID is content-addressed


def test_pipeline_two_output_modes():
    """Same IR must be able to produce both NL and code artifacts."""
    from semantic_engine import SemanticPipeline, RawInput, OutputMode
    r = RawInput("build a validation service")
    p = SemanticPipeline()
    nl = p.run(r, output_mode=OutputMode.NATURAL_LANGUAGE)
    code = p.run(RawInput("build a validation service"), output_mode=OutputMode.CODE)
    assert nl.artifact is not None
    assert code.artifact is not None
    assert nl.artifact.type.value != code.artifact.type.value


def test_pipeline_rejects_empty_input():
    from semantic_engine import SemanticPipeline, RawInput
    r = RawInput("")
    result = SemanticPipeline().run(r)
    # May complete but should not crash
    assert result is not None