From 76bcd3d3c4379fcd597edf4b8a2e9c04a7748854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio?= Date: Wed, 30 Sep 2026 05:46:48 -0300 Subject: [PATCH] test: add non-admin auth tests for progress-tracker and credential-nft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sérgio --- tests/integration/credential_auth_tests.rs | 86 +++++++++ .../progress_tracker_auth_tests.rs | 167 ++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 tests/integration/credential_auth_tests.rs create mode 100644 tests/integration/progress_tracker_auth_tests.rs diff --git a/tests/integration/credential_auth_tests.rs b/tests/integration/credential_auth_tests.rs new file mode 100644 index 0000000..5062d7d --- /dev/null +++ b/tests/integration/credential_auth_tests.rs @@ -0,0 +1,86 @@ +//! Authorization tests for credential-nft admin functions +//! These tests verify that non-admin callers are properly rejected + +#![cfg(test)] +use soroban_sdk::{testutils::Address as _, Address, Env}; +use crate::credential_nft::{CredentialNFT, CredentialNFTClient}; + +fn create_credential_nft(e: &Env) -> CredentialNFTClient { + CredentialNFTClient::new(e, &e.register_contract(None, CredentialNFT {})) +} + +#[test] +fn test_mint_credential_non_admin_fails() { + let e = Env::default(); + let contract = create_credential_nft(&e); + let non_admin = Address::generate(&e); + let recipient = Address::generate(&e); + + // Ensure non_admin is not the admin + let admin = contract.get_admin(); + assert_ne!(admin, non_admin); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .mint_credential(&recipient, &1, &"metadata".into()); + }); + assert!(result.is_err()); +} + +#[test] +fn test_renew_credential_non_admin_fails() { + let e = Env::default(); + let contract = create_credential_nft(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + let recipient = Address::generate(&e); + + // Setup: mint a credential as admin + contract + .with_source_account(&admin) + .mint_credential(&recipient, &1, &"metadata".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .renew_credential(&1); + }); + assert!(result.is_err()); +} + +#[test] +fn test_set_credential_display_non_admin_fails() { + let e = Env::default(); + let contract = create_credential_nft(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + let recipient = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .mint_credential(&recipient, &1, &"metadata".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .set_credential_display(&1, &"new_display".into()); + }); + assert!(result.is_err()); +} + +#[test] +fn test_transfer_admin_non_admin_fails() { + let e = Env::default(); + let contract = create_credential_nft(&e); + let non_admin = Address::generate(&e); + let new_admin = Address::generate(&e); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .transfer_admin(&new_admin); + }); + assert!(result.is_err()); +} \ No newline at end of file diff --git a/tests/integration/progress_tracker_auth_tests.rs b/tests/integration/progress_tracker_auth_tests.rs new file mode 100644 index 0000000..8dc9c64 --- /dev/null +++ b/tests/integration/progress_tracker_auth_tests.rs @@ -0,0 +1,167 @@ +//! Authorization tests for progress-tracker admin functions +//! These tests verify that non-admin callers are properly rejected + +#![cfg(test)] +use soroban_sdk::{testutils::Address as _, Address, Env}; +use crate::progress_tracker::{ProgressTracker, ProgressTrackerClient}; + +fn create_progress_tracker(e: &Env) -> ProgressTrackerClient { + ProgressTrackerClient::new(e, &e.register_contract(None, ProgressTracker {})) +} + +#[test] +fn test_create_course_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let non_admin = Address::generate(&e); + + // Ensure non_admin is not the admin + let admin = contract.get_admin(); + assert_ne!(admin, non_admin); + + // This should panic with authorization error + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + }); + assert!(result.is_err()); +} + +#[test] +fn test_archive_course_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup: create a course as admin + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + + // Non-admin tries to archive + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .archive_course(&1); + }); + assert!(result.is_err()); +} + +#[test] +fn test_set_course_content_hash_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .set_course_content_hash(&1, &"new_hash".into()); + }); + assert!(result.is_err()); +} + +#[test] +fn test_set_course_difficulty_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .set_course_difficulty(&1, &2); + }); + assert!(result.is_err()); +} + +#[test] +fn test_set_course_tags_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .set_course_tags(&1, &vec![&e, "tag1".into()]); + }); + assert!(result.is_err()); +} + +#[test] +fn test_update_course_version_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .update_course_version(&1, &2); + }); + assert!(result.is_err()); +} + +#[test] +fn test_set_prerequisites_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let admin = contract.get_admin(); + let non_admin = Address::generate(&e); + + // Setup + contract + .with_source_account(&admin) + .create_course(&"course1".into(), &1, &vec![&e, 1u32].into(), &"ipfs_hash".into()); + contract + .with_source_account(&admin) + .create_course(&"course2".into(), &2, &vec![&e, 1u32].into(), &"ipfs_hash2".into()); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .set_prerequisites(&2, &vec![&e, 1u32]); + }); + assert!(result.is_err()); +} + +#[test] +fn test_emergency_pause_non_admin_fails() { + let e = Env::default(); + let contract = create_progress_tracker(&e); + let non_admin = Address::generate(&e); + + let result = std::panic::catch_unwind(|| { + contract + .with_source_account(&non_admin) + .emergency_pause(&true); + }); + assert!(result.is_err()); +} \ No newline at end of file