extends SceneTree
## Layer 1: GDExtension Load + P2P API Smoke
##
## Tests that libhyperswarm_peer.so loads in Godot 4.6 headless,
## all P2P-relevant methods and signals exist, and keypair generation works.
## Single process, no network.
var _pass := 0
var _fail := 0
var _total := 0
func _init() -> void:
_run_tests()
_report()
quit()
func _run_tests() -> void:
# Test 1: ClassDB can instantiate
_test("ClassDB can instantiate HyperswarmMultiplayerPeer",
ClassDB.can_instantiate(&"HyperswarmMultiplayerPeer"))
# Test 2: Instantiate and verify P2P methods exist
var peer := ClassDB.instantiate(&"HyperswarmMultiplayerPeer") as MultiplayerPeerExtension
_test("Instantiation returns non-null", peer != null)
if peer == null:
_skip_rest("Cannot instantiate — aborting remaining tests")
return
# DHT methods
_test("has generate_dht_keypair()", peer.has_method("generate_dht_keypair"))
_test("has join_dht()", peer.has_method("join_dht"))
_test("has listen_on_dht()", peer.has_method("listen_on_dht"))
_test("has connect_to_peer()", peer.has_method("connect_to_peer"))
_test("has announce_topic()", peer.has_method("announce_topic"))
_test("has lookup_topic()", peer.has_method("lookup_topic"))
_test("has join_topic()", peer.has_method("join_topic"))
_test("has leave_topic()", peer.has_method("leave_topic"))
_test("has get_dht_status()", peer.has_method("get_dht_status"))
_test("has get_peer_public_key()", peer.has_method("get_peer_public_key"))
# DHT storage methods
_test("has dht_put()", peer.has_method("dht_put"))
_test("has dht_get()", peer.has_method("dht_get"))
_test("has dht_mutable_put()", peer.has_method("dht_mutable_put"))
_test("has dht_mutable_get()", peer.has_method("dht_mutable_get"))
# Encryption methods
_test("has generate_keypair()", peer.has_method("generate_keypair"))
_test("has create_server_with_keypair()", peer.has_method("create_server_with_keypair"))
_test("has create_client_with_key()", peer.has_method("create_client_with_key"))
# Basic networking
_test("has create_server()", peer.has_method("create_server"))
_test("has create_client()", peer.has_method("create_client"))
_test("has get_stats()", peer.has_method("get_stats"))
# Test 3: generate_dht_keypair() returns correct format
var dht_kp: Dictionary = peer.generate_dht_keypair()
_test("generate_dht_keypair() returns Dictionary", dht_kp is Dictionary)
_test("dht_kp has public_key", dht_kp.has("public_key"))
_test("dht_kp has secret_key", dht_kp.has("secret_key"))
if dht_kp.has("public_key") and dht_kp.has("secret_key"):
var dht_pk: PackedByteArray = dht_kp["public_key"]
var dht_sk: PackedByteArray = dht_kp["secret_key"]
_test("dht public_key is 32 bytes", dht_pk.size() == 32)
_test("dht secret_key is 64 bytes", dht_sk.size() == 64)
_test("dht public_key is non-zero", not _is_zero(dht_pk))
# Test 4: generate_keypair() (Curve25519) returns correct format
var kp: Dictionary = peer.generate_keypair()
_test("generate_keypair() returns Dictionary", kp is Dictionary)
_test("kp has public_key", kp.has("public_key"))
_test("kp has secret_key", kp.has("secret_key"))
if kp.has("public_key") and kp.has("secret_key"):
var pk: PackedByteArray = kp["public_key"]
var sk: PackedByteArray = kp["secret_key"]
_test("curve25519 public_key is 32 bytes", pk.size() == 32)
_test("curve25519 secret_key is 32 bytes", sk.size() == 32)
_test("curve25519 public_key is non-zero", not _is_zero(pk))
# Two keypairs should be different
var kp2: Dictionary = peer.generate_keypair()
if kp.has("public_key") and kp2.has("public_key"):
_test("two keypairs differ", kp["public_key"] != kp2["public_key"])
# Test 5: Verify signals registered
_test("signal dht_peer_found", peer.has_signal("dht_peer_found"))
_test("signal dht_put_complete", peer.has_signal("dht_put_complete"))
_test("signal dht_get_complete", peer.has_signal("dht_get_complete"))
_test("signal dht_mutable_put_complete", peer.has_signal("dht_mutable_put_complete"))
_test("signal dht_mutable_get_complete", peer.has_signal("dht_mutable_get_complete"))
# Standard MultiplayerPeer signals
_test("signal peer_connected", peer.has_signal("peer_connected"))
_test("signal peer_disconnected", peer.has_signal("peer_disconnected"))
# Test 6: Swarm Manager API methods exist
_test("has swarm_join()", peer.has_method("swarm_join"))
_test("has swarm_leave()", peer.has_method("swarm_leave"))
_test("has swarm_join_peer()", peer.has_method("swarm_join_peer"))
_test("has swarm_leave_peer()", peer.has_method("swarm_leave_peer"))
_test("has get_swarm_status()", peer.has_method("get_swarm_status"))
_test("swarm_connection signal exists", peer.has_signal("swarm_connection"))
# Test 7: get_swarm_status() returns valid dict before DHT active
var ss: Dictionary = peer.get_swarm_status()
_test("swarm status has peers_known", ss.has("peers_known"))
_test("swarm status peers_known is 0 initially", ss.get("peers_known", -1) == 0)
_test("swarm status has max_peers", ss.get("max_peers", 0) == 64)
_test("swarm status has max_parallel", ss.get("max_parallel", 0) == 3)
_test("swarm status has explicit_count", ss.has("explicit_count"))
# Test 8: get_stats() works before any connection
var stats: Dictionary = peer.get_stats()
_test("get_stats() returns Dictionary", stats is Dictionary)
_test("stats has connection_status", stats.has("connection_status"))
# Test 7: get_dht_status() works before joining
var dht_status: Dictionary = peer.get_dht_status()
_test("get_dht_status() returns Dictionary", dht_status is Dictionary)
# Test 8: Close with no crash
peer.close()
_test("close() without crash", true)
func _test(name: String, condition: bool) -> void:
_total += 1
if condition:
_pass += 1
print(" PASS %s" % name)
else:
_fail += 1
print(" FAIL %s" % name)
func _skip_rest(reason: String) -> void:
print(" SKIP %s" % reason)
func _is_zero(arr: PackedByteArray) -> bool:
for b: int in arr:
if b != 0:
return false
return true
func _report() -> void:
print("")
print("=== Layer 1: %d/%d passed ===" % [_pass, _total])
if _fail > 0:
print("FAILED: %d tests" % _fail)