59 lines
2.4 KiB
Python
59 lines
2.4 KiB
Python
import pytest
|
|
from app.services import ai_tree_builder as atb
|
|
|
|
|
|
def test_validate_node_rejects_hard_floor_text():
|
|
node = {"node_type": "instruction", "id": "n1", "text": "Open regedit and change the key", "next": "generate"}
|
|
with pytest.raises(atb.UnsafeNodeError):
|
|
atb.validate_node(node)
|
|
|
|
|
|
def test_validate_node_accepts_safe_instruction():
|
|
node = {"node_type": "instruction", "id": "n1", "text": "Restart the printer.", "next": "generate"}
|
|
assert atb.validate_node(node)["node_type"] == "instruction"
|
|
|
|
|
|
def test_depth_cap_forces_escalate():
|
|
walked = [{"node_type": "question", "id": f"n{i}", "text": "?", "answer": "no"} for i in range(atb.MAX_DEPTH)]
|
|
node = atb.escalate_if_depth_exceeded(walked)
|
|
assert node is not None and node["node_type"] == "escalate"
|
|
|
|
|
|
def test_normalize_walked_path_builds_valid_tree():
|
|
walked = [
|
|
{"node_type": "question", "id": "n1", "text": "Powered on?", "answer": "no"},
|
|
{"node_type": "instruction", "id": "n2", "text": "Power it on.", "answer": "ack"},
|
|
{"node_type": "resolved", "id": "n3", "text": "Fixed."},
|
|
]
|
|
tree = atb.normalize_walked_path(walked)
|
|
assert isinstance(tree, dict) and tree.get("id") == "n1"
|
|
# untraversed 'yes' branch of n1 became a needs_review stub
|
|
assert any(n["node_type"] == "needs_review" for n in tree["nodes"].values())
|
|
|
|
|
|
def test_normalize_walk_ending_on_question_has_no_none_branches():
|
|
walked = [
|
|
{"node_type": "question", "id": "n1", "text": "Powered on?", "answer": "no"},
|
|
]
|
|
tree = atb.normalize_walked_path(walked)
|
|
n1 = tree["nodes"]["n1"]
|
|
assert n1["yes_next"] is not None and n1["no_next"] is not None
|
|
# both branches must reference real nodes present in the tree
|
|
assert n1["yes_next"] in tree["nodes"] and n1["no_next"] in tree["nodes"]
|
|
|
|
|
|
def test_normalize_preserves_escalate_reason_category():
|
|
walked = [
|
|
{"node_type": "question", "id": "n1", "text": "On?", "answer": "no"},
|
|
{"node_type": "escalate", "id": "n2", "text": "Beyond L1.",
|
|
"reason_category": "exhausted_safe_steps"},
|
|
]
|
|
tree = atb.normalize_walked_path(walked)
|
|
assert tree["nodes"]["n2"]["reason_category"] == "exhausted_safe_steps"
|
|
|
|
|
|
def test_normalize_empty_walk_returns_needs_review_root():
|
|
tree = atb.normalize_walked_path([])
|
|
assert tree["id"] in tree["nodes"]
|
|
assert tree["nodes"][tree["id"]]["node_type"] == "needs_review"
|