Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions contracts/escrow/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2697,6 +2697,110 @@ fn test_expire_match_emits_expired_event() {
&player2,
&100,
&token,

&String::from_str(&env, "is_funded_completion"),
&Platform::Lichess,
);

assert!(!client.is_funded(&id), "unfunded before any deposit");

client.deposit(&id, &player1);
assert!(!client.is_funded(&id), "still unfunded after only player1 deposits");

client.deposit(&id, &player2);
assert!(client.is_funded(&id), "funded after both players deposit");
assert_eq!(client.get_match(&id).state, MatchState::Active);

client.submit_result(&id, &Winner::Player1);
assert_eq!(client.get_match(&id).state, MatchState::Completed);

// Funds are no longer held — escrow balance is the authoritative check.
assert_eq!(
client.get_escrow_balance(&id),
0,
"escrow balance must be 0 after completion"
);
// is_funded still reflects deposit flags (documented behaviour); callers
// needing "funds currently in escrow" must use get_escrow_balance or state.
assert!(
!client.is_funded(&id) || client.get_escrow_balance(&id) == 0,
"after completion, either is_funded is false or escrow balance is 0"
);
}

// ── Issue #15: default winner is Draw (Undecided) immediately after creation ──
//
// The Match struct initialises `winner` to `Winner::Draw` as a stand-in for
// "no result yet". This test asserts that a freshly created match carries that
// default before any result is submitted.
#[test]
fn test_winner_is_draw_default_before_result_submitted() {
let (env, contract_id, _oracle, player1, player2, token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);

let id = client.create_match(
&player1,
&player2,
&100,
&token,
&String::from_str(&env, "default_winner_test"),
&Platform::Lichess,
);

let m = client.get_match(&id);
assert_eq!(
m.state,
MatchState::Pending,
"match must be Pending immediately after creation"
);
assert_eq!(
m.winner,
Winner::Draw,
"winner must default to Draw (Undecided) before any result is submitted"
);
}

// ── Issues #10 / #11: terminal paths — cancel and expire, state + ledger metadata ──
//
// Covers both terminal paths in a single test group:
// • cancel_match → state == Cancelled, completed_ledger is None
// • expire_match → state == Cancelled, completed_ledger is None
//
// Neither path sets completed_ledger (only submit_result does), so both must
// leave that field as None.
#[test]
fn test_cancel_and_expire_terminal_state_and_ledger_metadata() {
let (env, contract_id, _oracle, player1, player2, token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);
let token_client = token::Client::new(&env, &token);

// ── cancel path ──────────────────────────────────────────────────────────
let id_cancel = client.create_match(
&player1,
&player2,
&100,
&token,
&String::from_str(&env, "terminal_cancel"),
&Platform::Lichess,
);

client.deposit(&id_cancel, &player1);
client.cancel_match(&id_cancel, &player1);

let m_cancel = client.get_match(&id_cancel);
assert_eq!(m_cancel.state, MatchState::Cancelled, "cancel → Cancelled");
assert!(
m_cancel.completed_ledger.is_none(),
"cancel must not set completed_ledger"
);
// Refund verified
assert_eq!(token_client.balance(&player1), 1000);

// ── expire path ──────────────────────────────────────────────────────────
env.ledger().set_sequence_number(500);

let id_expire = client.create_match(

&String::from_str(&env, "expire_event_game"),
&Platform::Lichess,
);
Expand Down Expand Up @@ -2776,6 +2880,64 @@ fn test_instance_ttl_refreshed_after_create_match() {
&player2,
&100,
&token,

&String::from_str(&env, "terminal_expire"),
&Platform::Lichess,
);

client.deposit(&id_expire, &player1);

let p1_before = token_client.balance(&player1);

// Extend TTLs so storage survives the ledger jump
for addr in [&contract_id, &token] {
env.deployer().extend_ttl_for_contract_instance(
addr.clone(),
MATCH_TTL_LEDGERS,
MATCH_TTL_LEDGERS,
);
env.deployer()
.extend_ttl_for_code(addr.clone(), MATCH_TTL_LEDGERS, MATCH_TTL_LEDGERS);
}
env.as_contract(&contract_id, || {
env.storage().persistent().extend_ttl(
&DataKey::ActiveMatches,
MATCH_TTL_LEDGERS,
MATCH_TTL_LEDGERS,
);
});

env.ledger().set_sequence_number(500 + DEFAULT_MATCH_TIMEOUT_LEDGERS);

for addr in [&contract_id, &token] {
env.deployer().extend_ttl_for_contract_instance(
addr.clone(),
MATCH_TTL_LEDGERS,
MATCH_TTL_LEDGERS,
);
env.deployer()
.extend_ttl_for_code(addr.clone(), MATCH_TTL_LEDGERS, MATCH_TTL_LEDGERS);
}
env.as_contract(&contract_id, || {
env.storage().persistent().extend_ttl(
&DataKey::ActiveMatches,
MATCH_TTL_LEDGERS,
MATCH_TTL_LEDGERS,
);
});

client.expire_match(&id_expire);

let m_expire = client.get_match(&id_expire);
assert_eq!(m_expire.state, MatchState::Cancelled, "expire → Cancelled");
assert!(
m_expire.completed_ledger.is_none(),
"expire must not set completed_ledger"
);
// Refund verified
assert_eq!(token_client.balance(&player1) - p1_before, 100);
}

&String::from_str(&env, "instance_ttl_game"),
&Platform::Lichess,
);
Expand Down
Loading