commit 65454d6e9e3e6cad2ee28186283783bc79598b92
parent b57f1d9d9bea7cafac1cb21d8a20729efea5d389
Author: triesap <tyson@radroots.org>
Date: Thu, 9 Apr 2026 02:55:13 +0000
tests: harden mirrored fixture extraction
- replace the raw substring scan with exact top-level json field parsing
- keep scenario request and expected loading clone-local and structurally checked
- avoid the mojson nested-subvalue edge in fixture helper serialization
- add a regression for descriptions that mention request and expected
Diffstat:
3 files changed, 148 insertions(+), 69 deletions(-)
diff --git a/tests/fixture_assertions.mojo b/tests/fixture_assertions.mojo
@@ -2,11 +2,14 @@ from std.testing import assert_equal, assert_true
from mojson import Value, dumps, loads
-from fixture_loader import load_fixture_scenario_field
+from fixture_loader import (
+ load_fixture_scenario_expected,
+ load_fixture_scenario_request,
+)
def load_scenario_request(relative_path: String) raises -> Value:
- return load_fixture_scenario_field(relative_path, "request")
+ return load_fixture_scenario_request(relative_path)
def load_scenario_request_json(relative_path: String) raises -> String:
@@ -22,7 +25,7 @@ def status_request_with_invalid_version_json() raises -> String:
def assert_matches_scenario_response(
actual: Value, relative_path: String
) raises:
- var expected = load_fixture_scenario_field(relative_path, "expected")
+ var expected = load_fixture_scenario_expected(relative_path)
if _has_key(expected, "ok"):
_assert_json_equal(actual["ok"], expected["ok"])
@@ -110,49 +113,32 @@ def _compact_json(value: Value) raises -> String:
if value.is_string():
return dumps(Value(value.string_value()))
- if value.is_array() or value.is_object():
- return _minify_json(value.raw_json())
+ if value.is_array():
+ var result = String("[")
+ var items = value.array_items()
+ for index in range(len(items)):
+ if index > 0:
+ result += ","
+ result += _compact_json(items[index])
+ result += "]"
+ return result^
+
+ if value.is_object():
+ var result = String("{")
+ var first = True
+ for key in value.object_keys():
+ if not first:
+ result += ","
+ first = False
+ result += dumps(Value(String(key)))
+ result += ":"
+ result += _compact_json(value[key])
+ result += "}"
+ return result^
return dumps(value)
-def _minify_json(raw: String) -> String:
- var result = String("")
- var in_string = False
- var escaped = False
-
- for byte in raw.as_bytes():
- if escaped:
- result += chr(Int(byte))
- escaped = False
- continue
-
- if in_string:
- result += chr(Int(byte))
- if byte == UInt8(ord("\\")):
- escaped = True
- elif byte == UInt8(ord('"')):
- in_string = False
- continue
-
- if byte == UInt8(ord('"')):
- in_string = True
- result += chr(Int(byte))
- continue
-
- if (
- byte == UInt8(ord(" "))
- or byte == UInt8(ord("\n"))
- or byte == UInt8(ord("\t"))
- or byte == UInt8(ord("\r"))
- ):
- continue
-
- result += chr(Int(byte))
-
- return result^
-
-
def _assert_contains_all(actual: Value, expected_subset: Value) raises:
if expected_subset.is_array():
assert_true(actual.is_array())
diff --git a/tests/fixture_loader.mojo b/tests/fixture_loader.mojo
@@ -11,12 +11,8 @@ def fixture_manifest_path() raises -> Path:
return fixture_root_path() / "manifest.json"
-def load_fixture_manifest() raises -> Value:
- return loads(fixture_manifest_path().read_text())
-
-
-def load_fixture_scenario(relative_path: String) raises -> Value:
- return loads((fixture_root_path() / String(relative_path)).read_text())
+def load_fixture_json_file(path: Path) raises -> Value:
+ return loads(path.read_text())
def _skip_whitespace(raw: String, start_index: Int) -> Int:
@@ -64,16 +60,11 @@ def _extract_json_value(raw: String, start_index: Int) raises -> String:
elif byte == UInt8(ord("}")) or byte == UInt8(ord("]")):
depth -= 1
if depth == 0:
- return String(
- raw[
- byte=start_index : index + 1
- ]
- )
+ return String(raw[byte=start_index : index + 1])
index += 1
raise Error("unterminated fixture object or array field")
if first == UInt8(ord('"')):
- var in_string = True
var escaped = False
var index = start_index + 1
while index < len(data):
@@ -82,7 +73,7 @@ def _extract_json_value(raw: String, start_index: Int) raises -> String:
escaped = False
elif byte == UInt8(ord("\\")):
escaped = True
- elif byte == UInt8(ord('"')) and in_string:
+ elif byte == UInt8(ord('"')):
return String(raw[byte=start_index : index + 1])
index += 1
raise Error("unterminated fixture string field")
@@ -101,20 +92,75 @@ def _extract_json_value(raw: String, start_index: Int) raises -> String:
return String(raw[byte=start_index:])
-def load_fixture_scenario_field(relative_path: String, key: String) raises -> Value:
- var raw = (fixture_root_path() / String(relative_path)).read_text()
- var pattern = "\"" + key + "\""
- var key_index = raw.find(pattern)
- if key_index < 0:
- raise Error("fixture scenario missing field '" + key + "'")
-
+def load_fixture_top_level_field_from_path(path: Path, key: String) raises -> Value:
+ var raw = path.read_text()
var data = raw.as_bytes()
- var index = key_index + pattern.byte_length()
- while index < len(data) and data[index] != UInt8(ord(":")):
- index += 1
+ var index = _skip_whitespace(raw, 0)
+ if index >= len(data) or data[index] != UInt8(ord("{")):
+ raise Error("fixture scenario must be a top-level JSON object")
+
+ index += 1
+ while index < len(data):
+ index = _skip_whitespace(raw, index)
+ if index >= len(data):
+ break
+
+ if data[index] == UInt8(ord("}")):
+ break
+
+ if data[index] != UInt8(ord('"')):
+ raise Error("fixture scenario object key must be a JSON string")
+
+ var key_json = _extract_json_value(raw, index)
+ var parsed_key = loads(key_json)
+ if not parsed_key.is_string():
+ raise Error("fixture scenario object key did not parse as a string")
+
+ index += key_json.byte_length()
+ index = _skip_whitespace(raw, index)
+ if index >= len(data) or data[index] != UInt8(ord(":")):
+ raise Error(
+ "fixture scenario field '" + parsed_key.string_value()
+ + "' missing colon"
+ )
+
+ var value_start = _skip_whitespace(raw, index + 1)
+ var value_json = _extract_json_value(raw, value_start)
+ if parsed_key.string_value() == key:
+ return loads(value_json)
+
+ index = value_start + value_json.byte_length()
+ index = _skip_whitespace(raw, index)
+ if index >= len(data):
+ break
+ if data[index] == UInt8(ord(",")):
+ index += 1
+ continue
+ if data[index] == UInt8(ord("}")):
+ break
+ raise Error(
+ "fixture scenario field '" + parsed_key.string_value()
+ + "' missing delimiter"
+ )
+
+ raise Error("fixture scenario missing field '" + key + "'")
+
+
+def load_fixture_manifest() raises -> Value:
+ return load_fixture_json_file(fixture_manifest_path())
+
+
+def load_fixture_scenario(relative_path: String) raises -> Value:
+ return load_fixture_json_file(fixture_root_path() / String(relative_path))
+
+
+def load_fixture_scenario_request(relative_path: String) raises -> Value:
+ return load_fixture_top_level_field_from_path(
+ fixture_root_path() / String(relative_path), "request"
+ )
- if index >= len(data):
- raise Error("fixture scenario field '" + key + "' missing colon")
- var value_start = _skip_whitespace(raw, index + 1)
- return loads(_extract_json_value(raw, value_start))
+def load_fixture_scenario_expected(relative_path: String) raises -> Value:
+ return load_fixture_top_level_field_from_path(
+ fixture_root_path() / String(relative_path), "expected"
+ )
diff --git a/tests/test_hyf.mojo b/tests/test_hyf.mojo
@@ -19,8 +19,12 @@ from fixture_assertions import (
from fixture_loader import (
fixture_manifest_path,
+ load_fixture_json_file,
load_fixture_manifest,
load_fixture_scenario,
+ load_fixture_scenario_expected,
+ load_fixture_scenario_request,
+ load_fixture_top_level_field_from_path,
)
from hyf_core.backends.selector import (
execute_capability as execute_core_capability,
@@ -355,6 +359,49 @@ def test_repo_local_fixture_loader_reads_all_mirrored_scenarios() raises:
)
+def test_fixture_loader_reads_top_level_request_and_expected_structurally() raises:
+ with TemporaryDirectory() as temp_dir:
+ var scenario_path = Path(temp_dir) / "scenario.json"
+ scenario_path.write_text(
+ '{'
+ + '"fixture_id":"shadowed-top-level-fields",'
+ + '"description":"this description mentions request and expected before the real fields",'
+ + '"request":{"version":1,"request_id":"shadow-1","capability":"sys.status","input":{}},'
+ + '"expected":{"ok":true,"equals":{"output.kind":"status"}}'
+ + '}'
+ )
+
+ var scenario = load_fixture_json_file(scenario_path)
+ var request = load_fixture_scenario_request("scenarios/status_ok.json")
+ var expected = load_fixture_scenario_expected("scenarios/status_ok.json")
+ var temp_request = load_fixture_top_level_field_from_path(
+ scenario_path, "request"
+ )
+ var temp_expected = load_fixture_top_level_field_from_path(
+ scenario_path, "expected"
+ )
+
+ assert_equal(
+ scenario["fixture_id"].string_value(),
+ "shadowed-top-level-fields",
+ )
+ assert_equal(
+ temp_request["request_id"].string_value(),
+ "shadow-1",
+ )
+ assert_equal(
+ temp_request["capability"].string_value(),
+ "sys.status",
+ )
+ assert_true(temp_expected["ok"].bool_value())
+ assert_equal(
+ temp_expected["equals"]["output.kind"].string_value(),
+ "status",
+ )
+ assert_equal(request["capability"].string_value(), "sys.status")
+ assert_true(expected["ok"].bool_value())
+
+
def test_status_reports_registered_deterministic_ready() raises:
var result = _dispatch(load_scenario_request_json("scenarios/status_ok.json"))
assert_matches_scenario_response(result, "scenarios/status_ok.json")