From 719efe6137c4252f22e8b2f6e82f01f532e4301e Mon Sep 17 00:00:00 2001 From: Victor Edeh Date: Mon, 27 Jul 2026 08:26:46 +0100 Subject: [PATCH] test(project_registry): add unit tests and validation for issues #196, #197, #198, and #199 --- project_registry/src/lib.rs | 11 +++++ project_registry/src/test.rs | 78 +++++++++++++++++++++++++++++++++++ project_registry/src/types.rs | 2 + 3 files changed, 91 insertions(+) diff --git a/project_registry/src/lib.rs b/project_registry/src/lib.rs index fd3ca4b..1290568 100644 --- a/project_registry/src/lib.rs +++ b/project_registry/src/lib.rs @@ -429,6 +429,9 @@ impl ProjectRegistry { .persistent() .get(&DataKey::Project(project_id)) .unwrap_or_else(|| panic_with_error!(&env, RegistryError::ProjectNotFound)); + if project.certification_status == status { + panic_with_error!(&env, RegistryError::AlreadyCertified); + } project.certification_status = status.clone(); env.storage() .persistent() @@ -1121,6 +1124,14 @@ fn update_credit_quality_score_internal(env: Env, project_id: u32, credit_qualit } fn liquidate_collateral_internal(env: Env, project_id: u32, token: Address, recipient: Address) { + let project: ProjectData = env + .storage() + .persistent() + .get(&DataKey::Project(project_id)) + .unwrap_or_else(|| panic_with_error!(&env, RegistryError::ProjectNotFound)); + if project.maturity_date > 0 && env.ledger().timestamp() < project.maturity_date { + panic_with_error!(&env, RegistryError::ProjectNotMature); + } let key = DataKey::Collateral(project_id, token.clone()); let balance: i128 = env.storage().persistent().get(&key).unwrap_or(0); if balance <= 0 { diff --git a/project_registry/src/test.rs b/project_registry/src/test.rs index b1484e3..68ee51a 100644 --- a/project_registry/src/test.rs +++ b/project_registry/src/test.rs @@ -416,6 +416,23 @@ fn test_certify_project() { assert_eq!(project.certification_status, CertificationStatus::Certified); } +#[test] +#[should_panic] +fn test_certify_already_certified_project_panics() { + let (env, _admin, whitelister, client) = setup(); + let creator = Address::generate(&env); + client.set_whitelist(&creator, &true); + let id = client.create_project( + &creator, + &String::from_str(&env, "ipfs://Qm"), + &0u64, + &test_metadata_hash(&env), + ); + + client.certify_project(&whitelister, &id, &CertificationStatus::Certified); + client.certify_project(&whitelister, &id, &CertificationStatus::Certified); +} + #[test] fn test_maturity_date_is_mature() { let (env, _admin, _whitelister, client) = setup(); @@ -593,6 +610,20 @@ fn test_uri_below_min_length_panics() { ); } +#[test] +#[should_panic] +fn test_create_project_empty_uri_panics() { + let (env, _admin, _whitelister, client) = setup(); + let creator = Address::generate(&env); + client.set_whitelist(&creator, &true); + client.create_project( + &creator, + &String::from_str(&env, ""), + &0u64, + &test_metadata_hash(&env), + ); +} + #[test] fn test_uri_exactly_max_length_accepted() { let (env, _admin, _whitelister, client) = setup(); @@ -664,6 +695,28 @@ fn test_deposit_and_get_collateral() { assert_eq!(client.get_collateral(&project_id, &token_sac), 500i128); } +#[test] +#[should_panic] +fn test_deposit_zero_collateral_panics() { + let (env, _admin, _whitelister, client) = setup(); + let creator = Address::generate(&env); + client.set_whitelist(&creator, &true); + let project_id = client.create_project( + &creator, + &String::from_str(&env, "ipfs://Qm"), + &0u64, + &test_metadata_hash(&env), + ); + + let token_admin = Address::generate(&env); + let token_sac = env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(); + soroban_sdk::token::StellarAssetClient::new(&env, &token_sac).mint(&creator, &1_000i128); + + client.deposit_collateral(&project_id, &creator, &token_sac, &0i128); +} + #[test] #[should_panic] fn test_non_owner_cannot_deposit_collateral() { @@ -711,6 +764,31 @@ fn test_liquidate_collateral_by_admin() { assert_eq!(client.get_collateral(&project_id, &token_sac), 0i128); } +#[test] +#[should_panic] +fn test_liquidate_collateral_before_maturity_panics() { + let (env, admin, _whitelister, client) = setup(); + let creator = Address::generate(&env); + client.set_whitelist(&creator, &true); + + let now = env.ledger().timestamp(); + let project_id = client.create_project( + &creator, + &String::from_str(&env, "ipfs://Qm"), + &(now + 1000), + &test_metadata_hash(&env), + ); + + let token_sac = env + .register_stellar_asset_contract_v2(admin.clone()) + .address(); + soroban_sdk::token::StellarAssetClient::new(&env, &token_sac).mint(&creator, &1_000i128); + client.deposit_collateral(&project_id, &creator, &token_sac, &800i128); + + let recipient = Address::generate(&env); + client.liquidate_collateral(&project_id, &token_sac, &recipient); +} + #[test] fn test_release_collateral_after_maturity() { let (env, admin, _whitelister, client) = setup(); diff --git a/project_registry/src/types.rs b/project_registry/src/types.rs index 51b7a9d..0051d8e 100644 --- a/project_registry/src/types.rs +++ b/project_registry/src/types.rs @@ -90,6 +90,8 @@ pub enum RegistryError { NotEmergencyAdmin = 36, /// Batch score update request exceeds the configured maximum batch size (#31). BatchTooLarge = 37, + /// Project is already certified with the target status. + AlreadyCertified = 38, } /// Certification state for a green project (#130).