commit e7dcfb47d2ae66191784083edd9c889a85411b9a
parent f5a8a94c5c98df3dc98447fff0bed52012cc1b94
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 19:42:11 +0000
test: expose swallowed failures and qualify harness (C001A)
Diffstat:
14 files changed, 219 insertions(+), 50 deletions(-)
diff --git a/pixi.toml b/pixi.toml
@@ -20,6 +20,8 @@ flare = { git = "https://github.com/triesap/mojo_flare.git", rev = "14aa338d8c4f
[tasks]
run = "mojo run -I src src/main.mojo"
test-unit = "mojo -I src tests/test_hyf.mojo"
+test-harness = "mojo -I src -I tests tests/test_harness_self_test.mojo"
+test-harness-runner-exit = "sh tools/check_harness_runner_exit.sh"
test-runtime = "mojo -I src tests/test_runtime_paths.mojo"
test-repo-local-process = "mojo -I src tests/test_repo_local_process_contract.mojo"
test-stdio = "mojo -I src tests/test_stdio_contract.mojo"
@@ -49,6 +51,8 @@ test-runtime-contract = { depends-on = [
] }
test = { depends-on = [
"test-unit",
+ "test-harness",
+ "test-harness-runner-exit",
"test-domain",
"test-assist",
"test-jev",
diff --git a/tests/harness_canary_assert_fail.mojo b/tests/harness_canary_assert_fail.mojo
@@ -0,0 +1,13 @@
+from std.testing import TestSuite, assert_true
+
+from safe_tempdir import SafeTempDir
+
+
+def test_canary_assertion_fails() raises:
+ with SafeTempDir() as temp_dir:
+ _ = temp_dir
+ assert_true(False)
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()
diff --git a/tests/harness_canary_error_fail.mojo b/tests/harness_canary_error_fail.mojo
@@ -0,0 +1,13 @@
+from std.testing import TestSuite
+
+from safe_tempdir import SafeTempDir
+
+
+def test_canary_generic_error_fails() raises:
+ with SafeTempDir() as temp_dir:
+ _ = temp_dir
+ raise Error("intentional harness canary error")
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()
diff --git a/tests/harness_canary_pass.mojo b/tests/harness_canary_pass.mojo
@@ -0,0 +1,12 @@
+from std.testing import TestSuite, assert_true
+
+from safe_tempdir import SafeTempDir
+
+
+def test_canary_passes() raises:
+ with SafeTempDir() as temp_dir:
+ assert_true(temp_dir.byte_length() > 0)
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()
diff --git a/tests/safe_tempdir.mojo b/tests/safe_tempdir.mojo
@@ -0,0 +1,30 @@
+"""Non-swallowing temporary-directory context manager for tests.
+
+The Mojo 1.0.0b1 `std.tempfile.TemporaryDirectory.__exit__` suppresses an
+exception raised inside its `with` body, which silently masks failing
+assertions. This wrapper delegates enter/exit to the standard implementation
+but discards the suppression return value so body exceptions propagate
+normally.
+
+Use `SafeTempDir` anywhere a test currently uses `TemporaryDirectory` as a
+`with` context manager. The interface is identical: `__enter__` returns the
+temporary directory path as a `String`.
+"""
+
+from std.tempfile import TemporaryDirectory as _StdTemporaryDirectory
+
+
+struct SafeTempDir:
+ var _inner: _StdTemporaryDirectory
+
+ def __init__(out self) raises:
+ self._inner = _StdTemporaryDirectory()
+
+ def __enter__(mut self) raises -> String:
+ return self._inner.__enter__()
+
+ def __exit__(mut self) raises:
+ # Discard the inner return value deliberately: the standard
+ # implementation returns a suppression flag that would otherwise swallow
+ # an exception raised in the `with` body.
+ self._inner.__exit__()
diff --git a/tests/stdio_process_helper.mojo b/tests/stdio_process_helper.mojo
@@ -2,7 +2,7 @@ import std.os
from std.os import Pipe, Process
from std.ffi import CStringSlice, c_int, external_call
from std.sys._libc import close
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from json import Value, loads
@@ -151,7 +151,7 @@ def run_stdio_entrypoint_with_2_args(
def run_hyf_stdio(request_json: String) raises -> Value:
var response = Value(None)
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, temp_dir):
response = run_stdio_entrypoint("src/main.mojo", request_json)
diff --git a/tests/test_harness_self_test.mojo b/tests/test_harness_self_test.mojo
@@ -0,0 +1,57 @@
+from std.os.path import exists
+from std.testing import TestSuite, assert_true
+
+from safe_tempdir import SafeTempDir
+
+
+def test_safe_tempdir_propagates_assertion_failure() raises:
+ var caught = False
+ try:
+ with SafeTempDir() as temp_dir:
+ _ = temp_dir
+ assert_true(False)
+ except:
+ caught = True
+ assert_true(caught)
+
+
+def test_safe_tempdir_propagates_generic_error() raises:
+ var caught = False
+ try:
+ with SafeTempDir() as temp_dir:
+ _ = temp_dir
+ raise Error("intentional generic harness error")
+ except:
+ caught = True
+ assert_true(caught)
+
+
+def test_safe_tempdir_nested_contexts_are_distinct_and_cleaned() raises:
+ var outer_path = String("")
+ var inner_path = String("")
+ with SafeTempDir() as outer:
+ outer_path = outer
+ with SafeTempDir() as inner:
+ inner_path = inner
+ assert_true(exists(inner_path))
+ assert_true(exists(outer_path))
+ assert_true(outer_path != inner_path)
+ assert_true(not exists(outer_path))
+ assert_true(not exists(inner_path))
+
+
+def test_safe_tempdir_cleans_up_on_exception() raises:
+ var path = String("")
+ var caught = False
+ try:
+ with SafeTempDir() as temp_dir:
+ path = temp_dir
+ raise Error("intentional cleanup harness error")
+ except:
+ caught = True
+ assert_true(caught)
+ assert_true(not exists(path))
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()
diff --git a/tests/test_hyf.mojo b/tests/test_hyf.mojo
@@ -7,7 +7,7 @@ from std.testing import (
assert_raises,
assert_true,
)
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from json import Value, loads, validate
@@ -78,7 +78,7 @@ struct ScopedEnvVar:
def _dispatch(line: String) raises -> Value:
var result = Value(None)
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var runtime_context = resolve_startup_context(
RuntimeStartupInput(
env_paths_profile="repo_local",
@@ -381,7 +381,7 @@ 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:
+ with SafeTempDir() as temp_dir:
var scenario_path = Path(temp_dir) / "scenario.json"
scenario_path.write_text(
"{"
@@ -883,7 +883,7 @@ def test_invalid_request_preserves_request_and_trace_correlation() raises:
def test_internal_error_is_bounded_on_wire() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var diagnostics_dir = Path(temp_dir) / "hyf-internal-diagnostics"
with ScopedEnvVar(
_HYF_DIAGNOSTICS_DIR_ENV, diagnostics_dir.__fspath__()
@@ -913,7 +913,7 @@ def _assert_internal_error_is_bounded(result: Value) raises:
def test_internal_error_diagnostics_records_detail() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var diagnostics_dir = Path(temp_dir) / "hyf-internal-diagnostics"
with ScopedEnvVar(
@@ -1262,7 +1262,7 @@ def test_fixture_validator_accepts_corpus_and_rejects_corruptions() raises:
mutations.append("empty_requirements")
mutations.append("activation_step_mismatch")
for mutation in mutations:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var base = Path(temp_dir)
_write_min_fixture_corpus(base, mutation)
assert_true(
diff --git a/tests/test_persistent_stdio.mojo b/tests/test_persistent_stdio.mojo
@@ -1,5 +1,5 @@
from std.collections import List
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from std.testing import TestSuite, assert_equal, assert_true
from fixture_assertions import load_scenario_request_json
@@ -23,7 +23,7 @@ def _context(temp_dir: String) raises -> RuntimeStartupContext:
def test_persistent_session_processes_multiple_frames() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var frames = List[String]()
frames.append(load_scenario_request_json("scenarios/status_ok.json"))
@@ -36,7 +36,7 @@ def test_persistent_session_processes_multiple_frames() raises:
def test_session_recovers_from_malformed_frame() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var frames = List[String]()
frames.append(load_scenario_request_json("scenarios/status_ok.json"))
@@ -54,7 +54,7 @@ def main() raises:
def test_session_preserves_order_and_recovers_after_malformed() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var frames = List[String]()
frames.append(load_scenario_request_json("scenarios/status_ok.json"))
@@ -69,7 +69,7 @@ def test_session_preserves_order_and_recovers_after_malformed() raises:
def test_session_rejects_oversized_frame() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var huge = "{\"version\":1,\"request_id\":\"big\","
for _ in range(200000):
@@ -83,7 +83,7 @@ def test_session_rejects_oversized_frame() raises:
def test_farm_update_operation_is_gated_until_enabled() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var request = (
'{"version":1,"request_id":"farm-op-1","capability":"farm_update.interpret",'
@@ -99,7 +99,7 @@ def test_farm_update_operation_is_gated_until_enabled() raises:
def test_buyer_match_operation_is_gated_until_enabled() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var request = (
'{"version":1,"request_id":"match-op-1","capability":"buyer_request.match",'
@@ -119,7 +119,7 @@ def test_new_operation_wire_frames_are_gated() raises:
var wire_dir = _dir_of() / "fixtures" / "hyf_v1_jev" / "wire"
var manifest = _load_fixture_json(wire_dir / "manifest.json")
assert_equal(manifest["spec_id"].string_value(), "hyf_v1_jev")
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
for name in manifest["scenarios"].array_items():
var scenario = _load_fixture_json(wire_dir / name.string_value())
@@ -132,7 +132,7 @@ def test_new_operation_wire_frames_are_gated() raises:
def test_long_session_processes_many_frames_in_order() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var frames = List[String]()
for index in range(50):
diff --git a/tests/test_repo_local_process_contract.mojo b/tests/test_repo_local_process_contract.mojo
@@ -1,5 +1,5 @@
from std.testing import TestSuite, assert_equal, assert_true
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from json import Value
from fixture_assertions import load_scenario_request_json
@@ -25,7 +25,7 @@ def _assert_runtime_status_path_under_repo_local_root(
def test_src_main_consumes_repo_local_env_without_outer_wrapper() raises:
- with TemporaryDirectory() as repo_local_root:
+ with SafeTempDir() as repo_local_root:
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, repo_local_root):
var response = run_stdio_entrypoint(
diff --git a/tests/test_soak.mojo b/tests/test_soak.mojo
@@ -1,5 +1,5 @@
from std.collections import List
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from std.testing import TestSuite, assert_equal, assert_true
from fixture_assertions import load_scenario_request_json
@@ -23,7 +23,7 @@ def _context(temp_dir: String) raises -> RuntimeStartupContext:
def test_bounded_process_soak_200_frames() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var context = _context(temp_dir)
var frames = List[String]()
for _ in range(200):
diff --git a/tests/test_stdio_contract.mojo b/tests/test_stdio_contract.mojo
@@ -2,7 +2,7 @@ import std.os
from std.os.path import exists
from std.pathlib import Path
from std.testing import assert_equal, assert_true, TestSuite
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from json import Value
from fixture_assertions import (
@@ -191,7 +191,7 @@ def _assert_query_rewrite_provider_fallback_with_deadline(
deadline_ms: Int,
requests: Int,
) raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(provider_port, mode, requests)
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
@@ -256,7 +256,7 @@ def _assert_query_rewrite_provider_fallback(
def _assert_query_rewrite_runtime_config_fallback(
config_text: String, expected_reason: String, request_id: String
) raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(config_text)
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
@@ -301,7 +301,7 @@ def _assert_query_rewrite_runtime_config_fallback(
def _assert_query_rewrite_runtime_config_fallback_without_provenance(
config_text: String, expected_reason: String, request_id: String
) raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(config_text)
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
@@ -338,7 +338,7 @@ def _assert_query_rewrite_runtime_config_fallback_without_provenance(
def _assert_invalid_runtime_config_load_error(
config_text: String, expected_error_fragment: String
) raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "invalid-hyf-config.toml"
startup_config_path.write_text(config_text)
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
@@ -370,7 +370,7 @@ def _assert_invalid_runtime_config_load_error(
def _assert_valid_runtime_config_load(config_text: String) raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(config_text)
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
@@ -465,7 +465,7 @@ def test_status_success() raises:
def test_status_reports_repo_local_runtime_truth() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, temp_dir):
@@ -678,7 +678,7 @@ def test_status_reports_repo_local_runtime_truth() raises:
def test_status_loads_valid_runtime_config_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(
_unavailable_max_local_runtime_config_toml()
@@ -856,7 +856,7 @@ def test_status_loads_valid_runtime_config_truthfully() raises:
def test_status_reports_invalid_runtime_config_without_crashing() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "invalid-hyf-config.toml"
startup_config_path.write_text(
'[runtime]\ndefault_execution_mode = "assisted"\n'
@@ -932,7 +932,7 @@ def test_status_reports_invalid_runtime_config_without_crashing() raises:
def test_status_reports_unconfigured_assisted_runtime_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(
'[service]\ntransport = "stdio"\n\n'
@@ -978,7 +978,7 @@ def test_status_reports_unconfigured_assisted_runtime_truthfully() raises:
def test_status_reports_non_2xx_max_local_health_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "health_non_2xx", 1
@@ -1021,7 +1021,7 @@ def test_status_reports_non_2xx_max_local_health_truthfully() raises:
def test_status_reports_ready_max_local_provider_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "query_rewrite_ok", 1
@@ -1101,7 +1101,7 @@ def test_status_reports_ready_max_local_provider_truthfully() raises:
def test_status_bounds_max_local_health_probe_timeout() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "health_timeout", 1
@@ -1410,7 +1410,7 @@ def test_status_allows_inline_table_quoted_route_mentions() raises:
def test_capabilities_reports_configured_provider_runtime_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(
_unavailable_max_local_runtime_config_toml()
@@ -1470,7 +1470,7 @@ def test_capabilities_reports_configured_provider_runtime_truthfully() raises:
def test_capabilities_reports_ready_max_local_provider_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "query_rewrite_ok", 1
@@ -1534,7 +1534,7 @@ def test_capabilities_reports_ready_max_local_provider_truthfully() raises:
def test_capabilities_bounds_max_local_health_probe_timeout() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "health_timeout", 1
@@ -1586,7 +1586,7 @@ def test_capabilities_bounds_max_local_health_probe_timeout() raises:
def test_query_rewrite_falls_back_deterministically_when_provider_is_unavailable() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(
_unavailable_max_local_runtime_config_toml()
@@ -1658,7 +1658,7 @@ def test_query_rewrite_fallback_metadata_is_visible_without_provenance() raises:
def test_assisted_semantic_rank_falls_back_as_unsupported_provider_capability() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var startup_config_path = Path(temp_dir) / "explicit-hyf-config.toml"
startup_config_path.write_text(
_unavailable_max_local_runtime_config_toml()
@@ -1705,7 +1705,7 @@ def test_assisted_semantic_rank_falls_back_as_unsupported_provider_capability()
def test_query_rewrite_uses_max_local_provider_when_ready() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var provider_port = reserve_loopback_port()
var provider_stub = spawn_max_local_stub(
provider_port, "query_rewrite_ok", 2
@@ -1875,7 +1875,7 @@ def test_query_rewrite_falls_back_on_provider_error_payload() raises:
def test_status_reports_configured_but_deferred_custody_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var identity_dir = Path(temp_dir) / "secrets" / "services" / "hyf"
_ = std.os.makedirs(identity_dir.__fspath__(), exist_ok=True)
(identity_dir / "identity.secret.json").write_text(
@@ -1952,7 +1952,7 @@ def test_status_reports_configured_but_deferred_custody_truthfully() raises:
def test_status_clears_repo_local_root_outside_repo_local_profile() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "interactive_user"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, temp_dir):
var response = run_stdio_entrypoint(
@@ -1981,7 +1981,7 @@ def test_status_clears_repo_local_root_outside_repo_local_profile() raises:
def test_status_reports_effective_diagnostics_override_truthfully() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var diagnostics_override_dir = (
Path(temp_dir) / "debug-diagnostics-override"
)
@@ -2074,7 +2074,7 @@ def test_query_rewrite_success() raises:
def test_query_rewrite_does_not_create_protected_local_artifacts() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, temp_dir):
var response = run_stdio_entrypoint(
@@ -2189,7 +2189,7 @@ def test_missing_input_fails_explicitly() raises:
def test_internal_error_is_bounded_on_wire() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
with ScopedEnvVar(HYF_PATHS_PROFILE_ENV, "repo_local"):
with ScopedEnvVar(HYF_PATHS_REPO_LOCAL_ROOT_ENV, temp_dir):
var response = run_stdio_entrypoint(
@@ -2223,7 +2223,7 @@ def test_internal_error_is_bounded_on_wire() raises:
def test_internal_error_records_detail_in_canonical_runtime_diagnostics_dir() raises:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var diagnostics_dir = (
Path(temp_dir) / "logs" / "services" / "hyf" / "diagnostics"
)
diff --git a/tests/test_traceability.mojo b/tests/test_traceability.mojo
@@ -1,7 +1,7 @@
import std.os
from std.collections import List
from std.pathlib import Path, _dir_of_current_file
-from std.tempfile import TemporaryDirectory
+from safe_tempdir import SafeTempDir
from std.testing import TestSuite, assert_equal, assert_true
from json import loads
@@ -84,7 +84,7 @@ def test_requirement_traceability_accepts_registry_and_rejects_dangling() raises
mutations.append("dangling_dependency")
mutations.append("duplicate_step")
for mutation in mutations:
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var base = Path(temp_dir)
_make_corpus(base, mutation)
assert_true(
@@ -97,7 +97,7 @@ def test_step_state_contract_is_valid_and_rejects_corruption() raises:
var path = _dir_of_current_file() / "requirements" / "hyf_v1_jev.step_states.json"
assert_equal(len(validate_step_states(path.__fspath__())), 0)
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var base = Path(temp_dir)
_write(
base / "states.json",
@@ -105,7 +105,7 @@ def test_step_state_contract_is_valid_and_rejects_corruption() raises:
'"passed_requires_executed_evidence":true,"rules":["x"]}',
)
assert_true(len(validate_step_states((base / "states.json").__fspath__())) > 0)
- with TemporaryDirectory() as temp_dir:
+ with SafeTempDir() as temp_dir:
var base = Path(temp_dir)
_write(
base / "states.json",
diff --git a/tools/check_harness_runner_exit.sh b/tools/check_harness_runner_exit.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env sh
+# Negative controls for test-harness exception propagation.
+#
+# A failing assertion or a raised error inside SafeTempDir must make the Mojo
+# test runner exit nonzero. A passing canary must exit zero. This proves the
+# SafeTempDir wrapper does not reintroduce the TemporaryDirectory masking
+# behavior.
+set -eu
+
+root="$(cd "$(dirname "$0")/.." && pwd)"
+
+run_canary() {
+ if mojo -I "$root/src" -I "$root/tests" "$1" >/dev/null 2>&1; then
+ printf '0'
+ else
+ printf '1'
+ fi
+}
+
+assert_fail="$(run_canary "$root/tests/harness_canary_assert_fail.mojo")"
+error_fail="$(run_canary "$root/tests/harness_canary_error_fail.mojo")"
+pass_ok="$(run_canary "$root/tests/harness_canary_pass.mojo")"
+
+status=0
+if [ "$assert_fail" -eq 0 ]; then
+ echo "harness canary: failing assertion did not fail the runner" >&2
+ status=1
+fi
+if [ "$error_fail" -eq 0 ]; then
+ echo "harness canary: raised error did not fail the runner" >&2
+ status=1
+fi
+if [ "$pass_ok" -ne 0 ]; then
+ echo "harness canary: passing canary unexpectedly failed" >&2
+ status=1
+fi
+if [ "$status" -eq 0 ]; then
+ echo "harness runner-exit canaries: ok"
+fi
+exit "$status"