tests/test_step.py
3.0 KB · 85 lines · python Raw
1 """Tests for ReasoningStep."""
2
3 from __future__ import annotations
4
5 from pqc_reasoning_ledger import ReasoningStep, StepKind, StepReference
6
7
8 def test_hash_content_is_deterministic() -> None:
9 a = ReasoningStep.hash_content("hello world")
10 b = ReasoningStep.hash_content("hello world")
11 c = ReasoningStep.hash_content("hello world!")
12 assert a == b
13 assert a != c
14 assert len(a) == 64
15
16
17 def test_create_sets_step_hash_correctly() -> None:
18 step = ReasoningStep.create(
19 kind=StepKind.OBSERVATION,
20 content="the sky is blue",
21 step_number=1,
22 )
23 assert step.step_hash
24 assert step.step_hash == step.compute_step_hash()
25 assert step.content_hash == ReasoningStep.hash_content("the sky is blue")
26
27
28 def test_compute_step_hash_changes_with_content() -> None:
29 s1 = ReasoningStep.create(StepKind.THOUGHT, "A", step_number=1)
30 s2 = ReasoningStep.create(StepKind.THOUGHT, "B", step_number=1)
31 assert s1.step_hash != s2.step_hash
32
33
34 def test_compute_step_hash_changes_with_previous_step_hash() -> None:
35 prev_a = "a" * 64
36 prev_b = "b" * 64
37 s1 = ReasoningStep.create(
38 StepKind.DEDUCTION, "same content", step_number=2, previous_step_hash=prev_a
39 )
40 s2 = ReasoningStep.create(
41 StepKind.DEDUCTION, "same content", step_number=2, previous_step_hash=prev_b
42 )
43 assert s1.step_hash != s2.step_hash
44
45
46 def test_to_dict_from_dict_roundtrip() -> None:
47 ref = StepReference(step_id="urn:pqc-step:abc", relationship="cites")
48 original = ReasoningStep.create(
49 kind=StepKind.DEDUCTION,
50 content="thus the clause is enforceable",
51 step_number=4,
52 previous_step_hash="f" * 64,
53 references=[ref],
54 confidence=0.87,
55 metadata={"model_temp": 0.2},
56 )
57 d = original.to_dict()
58 restored = ReasoningStep.from_dict(d)
59 assert restored.step_id == original.step_id
60 assert restored.step_number == original.step_number
61 assert restored.kind == original.kind
62 assert restored.content == original.content
63 assert restored.content_hash == original.content_hash
64 assert restored.step_hash == original.step_hash
65 assert restored.previous_step_hash == original.previous_step_hash
66 assert restored.confidence == original.confidence
67 assert restored.metadata == original.metadata
68 assert restored.references == original.references
69
70
71 def test_references_preserved_in_hash() -> None:
72 ref_a = StepReference(step_id="s:1", relationship="depends-on")
73 ref_b = StepReference(step_id="s:2", relationship="cites")
74 s1 = ReasoningStep.create(
75 StepKind.DEDUCTION, "c", step_number=2, references=[ref_a]
76 )
77 s2 = ReasoningStep.create(
78 StepKind.DEDUCTION, "c", step_number=2, references=[ref_b]
79 )
80 # Different references must produce different hashes
81 # Note: different step_ids (uuid) also contribute, but references are canonical
82 assert s1.references == [ref_a]
83 assert s2.references == [ref_b]
84 assert s1.canonical_bytes() != s2.canonical_bytes()
85