extends SceneTree const SurvivalModelScript = preload("res://src/survival_model.gd") const SonarModelScript = preload("res://src/sonar_model.gd") var _failures: Array[String] = [] func _init() -> void: _test_oxygen_drains_while_idle() _test_battery_only_drains_under_thrust() _test_nominal_depth_is_safe() _test_excess_depth_damages_hull() _test_collision_damage_is_applied() _test_battery_depletion_is_not_immediate_death() _test_alert_thresholds() _test_return_estimate() _test_critical_debug_state() _test_sonar_deduplicates_nearby_echoes() _test_sonar_keeps_strongest_echo() _test_sonar_intensity_falls_with_distance() _test_sonar_does_not_reveal_unobserved_space() if _failures.is_empty(): print("Prototype tests: 13 passed, 0 failed.") quit(0) else: for failure in _failures: push_error(failure) print("POC A tests: %d failed." % _failures.size()) quit(1) func _test_oxygen_drains_while_idle() -> void: var model = SurvivalModelScript.new() model.tick(10.0, 0.0, 12.0) _expect_near(model.oxygen, 590.0, 0.001, "oxygen drains while idle") func _test_battery_only_drains_under_thrust() -> void: var model = SurvivalModelScript.new() model.tick(10.0, 0.0, 12.0) _expect_near(model.battery, 100.0, 0.001, "battery remains stable at idle") model.tick(10.0, 1.0, 12.0) _expect_near(model.battery, 94.0, 0.001, "battery drains under full thrust") func _test_nominal_depth_is_safe() -> void: var model = SurvivalModelScript.new() model.tick(30.0, 0.0, 60.0) _expect_near(model.hull, 100.0, 0.001, "nominal depth does not damage hull") func _test_excess_depth_damages_hull() -> void: var model = SurvivalModelScript.new() model.tick(2.0, 0.0, 74.0) _expect(model.hull < 100.0, "depth above critical damages hull") func _test_collision_damage_is_applied() -> void: var model = SurvivalModelScript.new() model.tick(0.1, 0.0, 12.0, 12.0) _expect_near(model.hull, 88.0, 0.001, "collision damage is applied exactly once") func _test_battery_depletion_is_not_immediate_death() -> void: var model = SurvivalModelScript.new() model.battery = 0.0 _expect(model.loss_reason().is_empty(), "empty battery is not immediate death") func _test_alert_thresholds() -> void: var model = SurvivalModelScript.new() _expect( model.alert_level(30.0, 100.0) == SurvivalModel.AlertLevel.CAUTION, "30 percent is caution" ) _expect( model.alert_level(15.0, 100.0) == SurvivalModel.AlertLevel.RETURN, "15 percent recommends return" ) _expect( model.alert_level(5.0, 100.0) == SurvivalModel.AlertLevel.CRITICAL, "5 percent is critical" ) func _test_return_estimate() -> void: var model = SurvivalModelScript.new() var short_trip: float = model.estimated_return_energy(100.0, 0.0) var long_trip: float = model.estimated_return_energy(300.0, 20.0) _expect(long_trip > short_trip, "return estimate grows with distance and ascent") func _test_critical_debug_state() -> void: var model = SurvivalModelScript.new() model.force_critical_state() _expect(model.oxygen == 30.0, "critical debug state lowers oxygen") _expect(model.battery == 12.0, "critical debug state lowers battery") _expect(model.hull == 28.0, "critical debug state lowers hull") func _test_sonar_deduplicates_nearby_echoes() -> void: var model = SonarModelScript.new() model.record_echo(Vector3(1.0, 2.0, 3.0), 0.7, SonarModelScript.MaterialCategory.ROCK) model.record_echo(Vector3(1.1, 2.1, 3.1), 0.5, SonarModelScript.MaterialCategory.ROCK) _expect(model.observed_point_count() == 1, "nearby sonar echoes share one spatial cell") func _test_sonar_keeps_strongest_echo() -> void: var model = SonarModelScript.new() model.record_echo(Vector3.ZERO, 0.25, SonarModelScript.MaterialCategory.ROCK) model.record_echo(Vector3(0.1, 0.1, 0.1), 0.85, SonarModelScript.MaterialCategory.METAL) var point: Dictionary = model.observed_points()[0] _expect_near(float(point["intensity"]), 0.85, 0.001, "stronger sonar echo replaces weak echo") _expect( int(point["material"]) == SonarModelScript.MaterialCategory.METAL, "stronger sonar echo updates material" ) func _test_sonar_intensity_falls_with_distance() -> void: var model = SonarModelScript.new() var near_echo: float = model.calculate_intensity(10.0, 100.0, 1.0, 1.0) var far_echo: float = model.calculate_intensity(80.0, 100.0, 1.0, 1.0) _expect(near_echo > far_echo, "sonar intensity falls with distance") func _test_sonar_does_not_reveal_unobserved_space() -> void: var model = SonarModelScript.new() _expect(model.observed_points().is_empty(), "unobserved sonar space starts empty") func _expect(condition: bool, label: String) -> void: if not condition: _failures.append(label) func _expect_near(actual: float, expected: float, tolerance: float, label: String) -> void: if absf(actual - expected) > tolerance: _failures.append("%s: expected %.3f, got %.3f" % [label, expected, actual])