mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
67 lines
4.0 KiB
GDScript
67 lines
4.0 KiB
GDScript
extends "res://tests/test_case.gd"
|
|
|
|
const MatchmakingState = preload("res://scripts/matchmaking_state.gd")
|
|
|
|
|
|
func test_ticket_projection_accepts_ordered_updates_and_exposes_cancel() -> void:
|
|
var state := MatchmakingState.new()
|
|
assert_true(state.begin_queue("ticket-1", "ranked"), "valid queue starts in QUEUED")
|
|
assert_true(state.apply_ticket_update({"ticket_id": "ticket-1", "revision": 1, "state": "PROPOSED", "playlist": "ranked"}), "next revision applies")
|
|
assert_eq(state.phase, MatchmakingState.PROPOSED, "proposal is visible")
|
|
assert_true(state.can_cancel(), "authoritative cancel remains available before allocation")
|
|
|
|
|
|
func test_ticket_projection_rejects_gap_and_wrong_ticket_without_mutation() -> void:
|
|
var state := MatchmakingState.new()
|
|
state.begin_queue("ticket-1", "casual")
|
|
var resync_id := ""
|
|
state.resync_required.connect(func(id: String) -> void: resync_id = id)
|
|
assert_true(not state.apply_ticket_update({"ticket_id": "ticket-2", "revision": 1, "state": "PROPOSED"}), "another player's ticket is rejected")
|
|
assert_eq(resync_id, "ticket-1", "wrong resource requests recovery for current ticket")
|
|
assert_eq(state.phase, MatchmakingState.QUEUED, "invalid update cannot mutate phase")
|
|
assert_true(state.needs_resync, "invalid identity is visible to recovery")
|
|
|
|
state.needs_resync = false
|
|
assert_true(not state.apply_ticket_update({"ticket_id": "ticket-1", "revision": 3, "state": "ALLOCATING"}), "revision gap is rejected")
|
|
assert_eq(state.phase, MatchmakingState.QUEUED, "gap cannot skip authoritative state")
|
|
|
|
|
|
func test_duplicate_conflict_and_stale_updates_are_safe() -> void:
|
|
var state := MatchmakingState.new()
|
|
state.begin_queue("ticket-1", "casual")
|
|
var update := {"ticket_id": "ticket-1", "revision": 1, "state": "PROPOSED", "playlist": "casual", "expires_at_unix": 100}
|
|
assert_true(state.apply_ticket_update(update), "first update applies")
|
|
assert_true(state.apply_ticket_update(update), "identical duplicate is idempotent")
|
|
assert_true(not state.apply_ticket_update({"ticket_id": "ticket-1", "revision": 1, "state": "QUEUED", "playlist": "casual", "expires_at_unix": 100}), "same-revision conflict requests recovery")
|
|
assert_eq(state.phase, MatchmakingState.PROPOSED, "conflicting replay cannot rewind state")
|
|
assert_true(not state.apply_ticket_update({"ticket_id": "ticket-1", "revision": 0, "state": "QUEUED"}), "stale update is ignored")
|
|
assert_eq(state.phase, MatchmakingState.PROPOSED, "stale update cannot mutate state")
|
|
|
|
|
|
func test_proposal_terminal_states_are_visible_and_not_cancellable() -> void:
|
|
var state := MatchmakingState.new()
|
|
state.begin_queue("ticket-1", "casual")
|
|
assert_true(state.apply_proposal_update({"proposal_id": "proposal-1", "revision": 1, "state": "OPEN"}), "open proposal applies")
|
|
assert_eq(state.phase, MatchmakingState.PROPOSED, "open proposal is visible")
|
|
assert_true(state.apply_proposal_update({"proposal_id": "proposal-1", "revision": 2, "state": "DECLINED"}), "declined proposal applies")
|
|
assert_eq(state.phase, MatchmakingState.FAILED, "decline is terminal and visible")
|
|
assert_true(not state.can_cancel(), "terminal proposal cannot issue queue cancel")
|
|
|
|
var expired := MatchmakingState.new()
|
|
expired.begin_queue("ticket-2", "casual")
|
|
assert_true(expired.apply_proposal_update({"proposal_id": "proposal-2", "revision": 1, "state": "OPEN"}), "second proposal opens")
|
|
assert_true(expired.apply_proposal_update({"proposal_id": "proposal-2", "revision": 2, "state": "EXPIRED"}), "expired proposal applies")
|
|
assert_eq(expired.phase, MatchmakingState.EXPIRED, "expiry is visible")
|
|
assert_true(not expired.can_cancel(), "expired proposal cannot be cancelled")
|
|
|
|
|
|
func test_assignment_lifecycle_has_explicit_connecting_and_live_states() -> void:
|
|
var state := MatchmakingState.new()
|
|
state.begin_queue("ticket-1", "ranked")
|
|
state.mark_assignment_ready()
|
|
assert_eq(state.phase, MatchmakingState.ASSIGNMENT_READY, "assignment readiness is visible")
|
|
state.mark_connecting()
|
|
assert_eq(state.phase, MatchmakingState.CONNECTING, "transport connection is visible")
|
|
state.mark_live()
|
|
assert_eq(state.phase, MatchmakingState.LIVE, "live match is visible")
|