Phase 7: netfox + godot-jolt stack upgrade
Stack installed: - netfox v1.35.3 (core + extras + noray + internals) - godot-jolt v0.16.0-stable Architecture: - Server: ENet transport (works headless, no netfox deps) - Client/Editor: netfox rollback (RollbackSynchronizer, TickInterpolator) New/modified: - docs/migration-netfox-plan.md — migration architecture - scripts/network/network_manager.gd — netfox-aware ENet fallback - scripts/network/player.gd — clean base player - client/characters/player_netfox.gd — rollback player w/ WeaponManager - client/characters/input/player_net_input.gd — BaseNetInput subclass - client/characters/character/fps_character_controller.gd — netfox input feed - client/weapons/ — weapon data, registry, TacticalWeaponHitscan, WeaponManager - client/scripts/round_replicator.gd — client-side round state bridge - server/scripts/round_manager.gd — improved state machine - server/scripts/plugin_api/plugin_manager.gd — refined plugin system - config: enemy_tag, ally_tag for meatball targeting Removed: old C++ SimulationServer GDExtension (replaced by netfox rollback)
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
extends Node
|
||||
class_name TestUtils
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# TestUtils — Minimal assertion framework for headless Godot unit tests
|
||||
#
|
||||
# Usage:
|
||||
# var tu = TestUtils.new()
|
||||
# add_child(tu)
|
||||
# tu.describe("Movement validation")
|
||||
# tu.assert_eq(result.x, 5, "x should be 5")
|
||||
# tu.assert_true(valid, "should be valid")
|
||||
# tu.finish() # prints summary
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
var _passed: int = 0
|
||||
var _failed: int = 0
|
||||
var _current_suite: String = ""
|
||||
var _assertions_in_suite: int = 0
|
||||
|
||||
func describe(name: String) -> void:
|
||||
"""Start a named test suite/section."""
|
||||
_current_suite = name
|
||||
_assertions_in_suite = 0
|
||||
print("\n === " + name + " ===")
|
||||
|
||||
func assert_eq(got, expected, msg: String = "") -> void:
|
||||
_assertions_in_suite += 1
|
||||
if got == expected:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
var detail = "got '%s', expected '%s'" % [str(got), str(expected)]
|
||||
print(" [FAIL] " + msg + " — " + detail)
|
||||
|
||||
func assert_ne(got, unexpected, msg: String = "") -> void:
|
||||
_assertions_in_suite += 1
|
||||
if got != unexpected:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — got '%s' which matches unexpected value" % str(got))
|
||||
|
||||
func assert_true(cond: bool, msg: String = "") -> void:
|
||||
_assertions_in_suite += 1
|
||||
if cond:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — expected true, got false")
|
||||
|
||||
func assert_false(cond: bool, msg: String = "") -> void:
|
||||
_assertions_in_suite += 1
|
||||
if not cond:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — expected false, got true")
|
||||
|
||||
func assert_almost_eq(got: float, expected: float, tolerance: float = 0.001, msg: String = "") -> void:
|
||||
_assertions_in_suite += 1
|
||||
if abs(got - expected) <= tolerance:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
var detail = "got %.4f, expected %.4f ± %.4f" % [got, expected, tolerance]
|
||||
print(" [FAIL] " + msg + " — " + detail)
|
||||
|
||||
func assert_violation(result: Dictionary, category: int, msg: String = "") -> void:
|
||||
"""Assert the validation result contains at least one violation of the given category."""
|
||||
_assertions_in_suite += 1
|
||||
for v in result.get("violations", []):
|
||||
if v.get("category", -1) == category:
|
||||
_passed += 1
|
||||
return
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — expected violation category " + str(category) + ", none found")
|
||||
|
||||
func assert_no_violation(result: Dictionary, msg: String = "") -> void:
|
||||
"""Assert the validation result has zero violations."""
|
||||
_assertions_in_suite += 1
|
||||
var count = result.get("violations", []).size()
|
||||
if count == 0:
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — expected 0 violations, got " + str(count) + ": " + str(result["violations"]))
|
||||
|
||||
func assert_corrected(result: Dictionary, field: String, msg: String = "") -> void:
|
||||
"""Assert the result's corrected dict has a different value for `field` than the original."""
|
||||
_assertions_in_suite += 1
|
||||
if result.get("corrected", {}).has(field):
|
||||
_passed += 1
|
||||
else:
|
||||
_failed += 1
|
||||
print(" [FAIL] " + msg + " — expected correction in field '%s', none found" % field)
|
||||
|
||||
func finish() -> void:
|
||||
"""Print test summary and return exit code via OS."""
|
||||
var total = _passed + _failed
|
||||
print("\n ──────────────────────────────────────")
|
||||
print(" Suite: " + _current_suite)
|
||||
print(" Passed: %d / %d" % [_passed, total])
|
||||
if _failed > 0:
|
||||
print(" FAILED: %d test(s)" % _failed)
|
||||
else:
|
||||
print(" All passed.")
|
||||
print("")
|
||||
|
||||
func exit_code() -> int:
|
||||
return 0 if _failed == 0 else 1
|
||||
Reference in New Issue
Block a user