diff --git a/dongle-smartcontract/src/tests/endorsements.rs b/dongle-smartcontract/src/tests/endorsements.rs index f62d46d4..e39a0090 100644 --- a/dongle-smartcontract/src/tests/endorsements.rs +++ b/dongle-smartcontract/src/tests/endorsements.rs @@ -5,7 +5,18 @@ use crate::ContractError; use soroban_sdk::{testutils::Address as _, Address, Env}; #[test] -fn test_endorse_project() { +fn endorsement_defaults_are_empty() { + let env = Env::default(); + + let (client, _admin) = setup_contract(&env); + let user = Address::generate(&env); + + assert_eq!(client.get_endorsement_count(&999), 0); + assert!(!client.has_endorsed(&999, &user)); +} + +#[test] +fn endorse_project_updates_count_and_membership() { let env = Env::default(); env.mock_all_auths(); @@ -17,15 +28,12 @@ fn test_endorse_project() { client.endorse_project(&project_id, &user); - let count = client.get_endorsement_count(&project_id); - assert_eq!(count, 1); - - let endorsed = client.has_endorsed(&project_id, &user); - assert!(endorsed); + assert_eq!(client.get_endorsement_count(&project_id), 1); + assert!(client.has_endorsed(&project_id, &user)); } #[test] -fn test_unendorse_project() { +fn unendorse_project_updates_count_and_membership() { let env = Env::default(); env.mock_all_auths(); @@ -41,12 +49,11 @@ fn test_unendorse_project() { client.unendorse_project(&project_id, &user); assert_eq!(client.get_endorsement_count(&project_id), 0); - let endorsed = client.has_endorsed(&project_id, &user); - assert!(!endorsed); + assert!(!client.has_endorsed(&project_id, &user)); } #[test] -fn test_duplicate_endorse_returns_error() { +fn duplicate_endorse_returns_exact_error_without_changing_state() { let env = Env::default(); env.mock_all_auths(); @@ -60,10 +67,12 @@ fn test_duplicate_endorse_returns_error() { let result = client.try_endorse_project(&project_id, &user); assert_eq!(result, Err(Ok(ContractError::AlreadyEndorsed))); + assert_eq!(client.get_endorsement_count(&project_id), 1); + assert!(client.has_endorsed(&project_id, &user)); } #[test] -fn test_endorse_nonexistent_project_returns_error() { +fn endorse_nonexistent_project_returns_exact_error() { let env = Env::default(); env.mock_all_auths(); @@ -75,7 +84,23 @@ fn test_endorse_nonexistent_project_returns_error() { } #[test] -fn test_unendorse_without_endorsement_returns_error() { +fn endorse_project_requires_user_authorization() { + let env = Env::default(); + + let (client, _admin) = setup_contract(&env); + let owner = Address::generate(&env); + let user = Address::generate(&env); + let project_id = create_test_project(&client, &owner, "UnauthorizedEndorseProject"); + + let result = client.try_endorse_project(&project_id, &user); + + assert!(result.is_err()); + assert_eq!(client.get_endorsement_count(&project_id), 0); + assert!(!client.has_endorsed(&project_id, &user)); +} + +#[test] +fn unendorse_without_endorsement_returns_exact_error_without_changing_state() { let env = Env::default(); env.mock_all_auths(); @@ -87,10 +112,49 @@ fn test_unendorse_without_endorsement_returns_error() { let result = client.try_unendorse_project(&project_id, &user); assert_eq!(result, Err(Ok(ContractError::NotEndorsed))); + assert_eq!(client.get_endorsement_count(&project_id), 0); + assert!(!client.has_endorsed(&project_id, &user)); +} + +#[test] +fn unendorse_project_requires_user_authorization() { + let env = Env::default(); + + let (client, _admin) = setup_contract(&env); + let owner = Address::generate(&env); + let user = Address::generate(&env); + let project_id = create_test_project(&client, &owner, "UnauthorizedUnendorseProject"); + client.mock_all_auths().endorse_project(&project_id, &user); + + let result = client.try_unendorse_project(&project_id, &user); + + assert!(result.is_err()); + assert_eq!(client.get_endorsement_count(&project_id), 1); + assert!(client.has_endorsed(&project_id, &user)); } #[test] -fn test_endorse_count_multiple_users() { +fn duplicate_unendorse_returns_exact_error_without_changing_state() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin) = setup_contract(&env); + let owner = Address::generate(&env); + let user = Address::generate(&env); + + let project_id = create_test_project(&client, &owner, "DoubleUnendorseProject"); + + client.endorse_project(&project_id, &user); + client.unendorse_project(&project_id, &user); + + let result = client.try_unendorse_project(&project_id, &user); + assert_eq!(result, Err(Ok(ContractError::NotEndorsed))); + assert_eq!(client.get_endorsement_count(&project_id), 0); + assert!(!client.has_endorsed(&project_id, &user)); +} + +#[test] +fn endorsement_count_tracks_multiple_users_and_partial_removal() { let env = Env::default(); env.mock_all_auths(); @@ -99,21 +163,66 @@ fn test_endorse_count_multiple_users() { let project_id = create_test_project(&client, &owner, "MultiEndorseProject"); - let user_count = 5u32; - for _ in 0..user_count { - let u = Address::generate(&env); - client.endorse_project(&project_id, &u); - } - - assert_eq!( - client.get_endorsement_count(&project_id), - user_count, - "endorsement count should match total unique endorsers" - ); + let first_user = Address::generate(&env); + let second_user = Address::generate(&env); + let third_user = Address::generate(&env); + + client.endorse_project(&project_id, &first_user); + client.endorse_project(&project_id, &second_user); + client.endorse_project(&project_id, &third_user); + + assert_eq!(client.get_endorsement_count(&project_id), 3); + assert!(client.has_endorsed(&project_id, &first_user)); + assert!(client.has_endorsed(&project_id, &second_user)); + assert!(client.has_endorsed(&project_id, &third_user)); + + client.unendorse_project(&project_id, &second_user); + + assert_eq!(client.get_endorsement_count(&project_id), 2); + assert!(client.has_endorsed(&project_id, &first_user)); + assert!(!client.has_endorsed(&project_id, &second_user)); + assert!(client.has_endorsed(&project_id, &third_user)); +} + +#[test] +fn endorsement_state_is_isolated_by_project_and_user() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin) = setup_contract(&env); + let owner = Address::generate(&env); + let endorsing_user = Address::generate(&env); + let other_user = Address::generate(&env); + + let first_project = create_test_project(&client, &owner, "FirstEndorsementProject"); + let second_project = create_test_project(&client, &owner, "SecondEndorsementProject"); + + client.endorse_project(&first_project, &endorsing_user); + + assert_eq!(client.get_endorsement_count(&first_project), 1); + assert_eq!(client.get_endorsement_count(&second_project), 0); + assert!(client.has_endorsed(&first_project, &endorsing_user)); + assert!(!client.has_endorsed(&first_project, &other_user)); + assert!(!client.has_endorsed(&second_project, &endorsing_user)); +} + +#[test] +fn project_owner_can_self_endorse_under_current_policy() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin) = setup_contract(&env); + let owner = Address::generate(&env); + let project_id = create_test_project(&client, &owner, "SelfEndorseProject"); + + client.endorse_project(&project_id, &owner); + + assert_eq!(client.get_endorsement_count(&project_id), 1); + assert!(client.has_endorsed(&project_id, &owner)); } #[test] -fn test_endorse_after_unendorse_allows_reendorse() { +fn endorse_after_unendorse_allows_reendorsement() { let env = Env::default(); env.mock_all_auths(); @@ -130,6 +239,5 @@ fn test_endorse_after_unendorse_allows_reendorse() { client.endorse_project(&project_id, &user); assert_eq!(client.get_endorsement_count(&project_id), 1); - let endorsed = client.has_endorsed(&project_id, &user); - assert!(endorsed); + assert!(client.has_endorsed(&project_id, &user)); }