Files
TheTree_mock/tests/s2/test_mana_network_service.gd
T

136 lines
7.0 KiB
GDScript

extends SceneTree
const ManaNetworkServiceScript = preload("res://scripts/mana/mana_network_service.gd")
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
print("S2: deterministic Mana network")
_test_graph_and_priority_allocation()
_test_brownout_threshold_and_hold()
_test_storage_flow()
_test_cadence_and_disabled_nodes()
_test_snapshot_and_invariants()
if _failures == 0:
print("PASS: %d checks" % _checks)
else:
push_error("FAIL: %d of %d checks failed" % [_failures, _checks])
quit(_failures)
func _test_graph_and_priority_allocation() -> void:
var service = ManaNetworkServiceScript.new()
_expect(service.register_source(&"tree", 10), "a source registers with integer output")
_expect(service.register_connector(&"trunk_bus"), "a connector registers independently from the walking graph")
_expect(service.register_consumer(&"clinic", 6, service.ConsumerPriority.ESSENTIAL), "an essential consumer registers")
_expect(service.register_consumer(&"casino", 5, service.ConsumerPriority.LUXURY), "a luxury consumer registers")
service.connect_nodes(&"tree", &"trunk_bus")
service.connect_nodes(&"clinic", &"trunk_bus")
service.connect_nodes(&"casino", &"trunk_bus")
var report: Dictionary = service.evaluate_now(0)
_expect(report[&"evaluated"] and report[&"components"].size() == 1, "connected nodes evaluate as one Mana component")
_expect(service.get_consumer_state(&"clinic") == service.ConsumerState.ACTIVE, "essential demand is supplied first")
_expect(service.get_allocated_mana(&"clinic") == 6, "essential consumer receives its full demand")
_expect(service.get_consumer_state(&"casino") == service.ConsumerState.DEGRADED, "remaining 80 percent supply creates a brownout")
_expect(service.get_allocated_mana(&"casino") == 4, "lower-priority consumer receives only the deterministic remainder")
var isolated = ManaNetworkServiceScript.new()
isolated.register_source(&"source", 4)
isolated.register_consumer(&"z_consumer", 4, isolated.ConsumerPriority.NORMAL)
isolated.register_consumer(&"a_consumer", 4, isolated.ConsumerPriority.NORMAL)
isolated.connect_nodes(&"source", &"z_consumer")
isolated.connect_nodes(&"source", &"a_consumer")
isolated.evaluate_now(0)
_expect(isolated.get_allocated_mana(&"a_consumer") == 4, "equal priorities use consumer id as a stable tie break")
_expect(isolated.get_allocated_mana(&"z_consumer") == 0, "stable tie break leaves the later consumer unpowered")
func _test_brownout_threshold_and_hold() -> void:
var service = ManaNetworkServiceScript.new()
service.register_source(&"source", 75)
service.register_consumer(&"workshop", 100)
service.connect_nodes(&"source", &"workshop")
service.evaluate_now(0)
_expect(service.get_consumer_state(&"workshop") == service.ConsumerState.DEGRADED, "exactly 75 percent supply is DEGRADED")
service.set_source_output(&"source", 74)
service.evaluate_now(10)
_expect(service.get_consumer_state(&"workshop") == service.ConsumerState.NO_POWER, "supply below 75 percent becomes NO_POWER")
_expect(service.get_node(&"workshop")[&"hold_until"] == 20, "NO_POWER starts a ten-minute minimum off hold")
service.set_source_output(&"source", 100)
service.evaluate_now(15)
_expect(service.get_allocated_mana(&"workshop") == 0, "consumer cannot oscillate on during its off hold")
service.evaluate_now(20)
_expect(service.get_consumer_state(&"workshop") == service.ConsumerState.ACTIVE, "consumer recovers at the first evaluation after its hold")
_expect(service.get_allocated_mana(&"workshop") == 100, "recovered consumer receives full demand")
func _test_storage_flow() -> void:
var service = ManaNetworkServiceScript.new()
service.register_source(&"source", 4)
service.register_storage(&"battery", 20, 10, 6)
service.register_consumer(&"lights", 10, service.ConsumerPriority.ESSENTIAL)
service.connect_nodes(&"source", &"battery")
service.connect_nodes(&"battery", &"lights")
var discharge_report: Dictionary = service.evaluate_now(0)
_expect(discharge_report[&"components"][0][&"discharged"] == 6, "storage discharge is capped by its max flow")
_expect(service.get_storage_current(&"battery") == 4, "discharged Mana is removed exactly once")
_expect(service.get_consumer_state(&"lights") == service.ConsumerState.ACTIVE, "stored Mana completes essential supply")
service.set_source_output(&"source", 20)
var charge_report: Dictionary = service.evaluate_now(10)
_expect(charge_report[&"components"][0][&"charged"] == 6, "surplus charges storage at its max flow")
_expect(service.get_storage_current(&"battery") == 10, "charging preserves storage capacity invariants")
func _test_cadence_and_disabled_nodes() -> void:
var service = ManaNetworkServiceScript.new()
service.register_source(&"source", 5)
service.register_consumer(&"pump", 5)
service.connect_nodes(&"source", &"pump")
_expect(not service.advance_one_minute(1)[&"evaluated"], "Mana allocation skips non-ten-minute ticks")
_expect(service.advance_one_minute(10)[&"evaluated"], "Mana allocation runs on a ten-minute boundary")
_expect(not service.advance_one_minute(10)[&"evaluated"], "the same boundary cannot evaluate twice")
_expect(service.set_node_enabled(&"pump", false), "a consumer can be administratively disabled")
_expect(service.get_consumer_state(&"pump") == service.ConsumerState.DISABLED, "disabled state applies immediately")
service.evaluate_now(20)
_expect(service.get_allocated_mana(&"pump") == 0, "disabled consumer receives no Mana")
_expect(service.set_node_enabled(&"pump", true), "a disabled consumer can be enabled")
service.evaluate_now(30)
_expect(service.get_consumer_state(&"pump") == service.ConsumerState.ACTIVE, "enabled consumer returns at the next evaluation")
func _test_snapshot_and_invariants() -> void:
var original = ManaNetworkServiceScript.new()
original.register_source(&"tree", 12)
original.register_connector(&"junction")
original.register_storage(&"crystal", 30, 8, 4)
original.register_consumer(&"room", 10)
original.connect_nodes(&"tree", &"junction")
original.connect_nodes(&"junction", &"crystal")
original.connect_nodes(&"junction", &"room")
original.evaluate_now(10)
var snapshot: Dictionary = original.create_snapshot()
var restored = ManaNetworkServiceScript.new()
_expect(restored.restore_snapshot(snapshot), "Mana graph and runtime state restore from a snapshot")
_expect(restored.create_snapshot() == snapshot, "restored Mana snapshot is byte-structure equivalent")
_expect(restored.node_count() == 4 and restored.edge_count() == 3, "snapshot restores all nodes and undirected edges")
_expect(restored.validate_invariants()[&"valid"], "restored allocation, storage and graph invariants hold")
_expect(restored.unregister_node(&"junction"), "removing a node also removes its incident edges")
_expect(restored.edge_count() == 0, "node removal cannot leave orphan Mana edges")
_expect(restored.validate_invariants()[&"valid"], "node removal keeps graph symmetry valid")
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
return
_failures += 1
push_error(" ✗ %s" % label)