From 8988296fe41985e05d056795c9565e6cf1a38eab Mon Sep 17 00:00:00 2001 From: Samuel1505 Date: Fri, 27 Feb 2026 15:21:26 +0100 Subject: [PATCH 1/2] test: cleanup_expired_bids return value and state --- quicklendx-contracts/src/test_bid.rs | 69 +++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/quicklendx-contracts/src/test_bid.rs b/quicklendx-contracts/src/test_bid.rs index de91d2c8..85ec1a67 100644 --- a/quicklendx-contracts/src/test_bid.rs +++ b/quicklendx-contracts/src/test_bid.rs @@ -553,6 +553,73 @@ fn test_cleanup_expired_bids_returns_count() { assert_eq!(placed_bids.len(), 0, "No bids should be in Placed status"); } +/// Test: cleanup_expired_bids is idempotent when called multiple times +#[test] +fn test_cleanup_expired_bids_idempotent() { + let (env, client) = setup(); + env.mock_all_auths(); + let admin = Address::generate(&env); + let _ = client.set_admin(&admin); + let investor1 = add_verified_investor(&env, &client, 100_000); + let investor2 = add_verified_investor(&env, &client, 100_000); + let business = Address::generate(&env); + + let invoice_id = create_verified_invoice(&env, &client, &admin, &business, 100_000); + + // Place 2 bids that will both expire + let bid_1 = client.place_bid(&investor1, &invoice_id, &10_000, &12_000); + let bid_2 = client.place_bid(&investor2, &invoice_id, &15_000, &18_000); + + // Advance time past expiration + env.ledger() + .set_timestamp(env.ledger().timestamp() + 604800 + 1); + + // First cleanup should expire both bids and return count 2 + let removed_first = client.cleanup_expired_bids(&invoice_id); + assert_eq!(removed_first, 2, "First cleanup should remove 2 expired bids"); + + // Verify both bids are marked Expired and removed from invoice list + assert_eq!( + client.get_bid(&bid_1).unwrap().status, + BidStatus::Expired, + "Bid 1 should be expired after first cleanup" + ); + assert_eq!( + client.get_bid(&bid_2).unwrap().status, + BidStatus::Expired, + "Bid 2 should be expired after first cleanup" + ); + let bids_after_first = client.get_bids_for_invoice(&invoice_id); + assert_eq!( + bids_after_first.len(), + 0, + "Invoice bid list should be empty after first cleanup" + ); + + // Second cleanup should be a no-op and return 0, with state unchanged + let removed_second = client.cleanup_expired_bids(&invoice_id); + assert_eq!( + removed_second, 0, + "Second cleanup should be idempotent and remove 0 bids" + ); + assert_eq!( + client.get_bid(&bid_1).unwrap().status, + BidStatus::Expired, + "Bid 1 should remain expired after second cleanup" + ); + assert_eq!( + client.get_bid(&bid_2).unwrap().status, + BidStatus::Expired, + "Bid 2 should remain expired after second cleanup" + ); + let bids_after_second = client.get_bids_for_invoice(&invoice_id); + assert_eq!( + bids_after_second.len(), + 0, + "Invoice bid list should remain empty after second cleanup" + ); +} + /// Test: get_ranked_bids excludes expired bids #[test] fn test_get_ranked_bids_excludes_expired() { @@ -1604,4 +1671,4 @@ fn test_cannot_accept_second_bid_after_first_accepted() { assert_eq!(invoice.status, InvoiceStatus::Funded); assert_eq!(invoice.funded_amount, 10_000); assert_eq!(invoice.investor, Some(investor1)); - } + } From 3f69324e2a915cb00778fa6521a3a9b63a66d9ec Mon Sep 17 00:00:00 2001 From: Samuel1505 Date: Fri, 27 Feb 2026 15:51:12 +0100 Subject: [PATCH 2/2] update errors type to implement Debug --- quicklendx-contracts/src/errors.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quicklendx-contracts/src/errors.rs b/quicklendx-contracts/src/errors.rs index c7ac4430..06da12c5 100644 --- a/quicklendx-contracts/src/errors.rs +++ b/quicklendx-contracts/src/errors.rs @@ -5,8 +5,7 @@ use soroban_sdk::{contracterror, symbol_short, Symbol}; /// The Soroban XDR spec allows a maximum of 50 error variants per contract. /// All 50 slots are used; new variants require replacing an existing one. #[contracterror] -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] -#[cfg_attr(test, derive(Debug))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum QuickLendXError { // Invoice lifecycle (1000–1006)