Skip to content
Merged
Show file tree
Hide file tree
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
45 changes: 45 additions & 0 deletions tests/unit/credential_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,49 @@ mod credential_unit_tests {
let info = client.verify_credential(&cred_id);
assert_eq!(info.metadata_uri, valid_uri);
}

#[test]
fn test_renew_credential_extends_expiry() {
let env = Env::default();
let (_admin, contract_id, tracker_id) = setup_contract(&env);
let client = CredentialNftClient::new(&env, &contract_id);

let learner = Address::generate(&env);
env.mock_all_auths();

let course_id = Symbol::new(&env, "rust_101");
enrolled_and_completed_with_score(&env, &tracker_id, &learner, &course_id, 90);
let metadata_uri = Symbol::new(&env, "ipfs_Qm123ValidURI");
let cred_id = client.mint_credential(&learner, &course_id, &90, &metadata_uri);

let before = client.verify_credential(&cred_id);
let new_expiry = before.expiry + 10_000;

client.renew_credential(&cred_id, &new_expiry);

let after = client.verify_credential(&cred_id);
assert_eq!(after.expiry, new_expiry);
assert!(after.expiry > before.expiry);
}

#[test]
fn test_revoke_credential_with_reason_is_stored_and_queryable() {
let env = Env::default();
let (_admin, contract_id, tracker_id) = setup_contract(&env);
let client = CredentialNftClient::new(&env, &contract_id);

let learner = Address::generate(&env);
env.mock_all_auths();

let course_id = Symbol::new(&env, "rust_101");
enrolled_and_completed_with_score(&env, &tracker_id, &learner, &course_id, 90);
let metadata_uri = Symbol::new(&env, "ipfs_Qm123ValidURI");
let cred_id = client.mint_credential(&learner, &course_id, &90, &metadata_uri);

let reason = Symbol::new(&env, "fraud_detected");
client.revoke_credential_with_reason(&cred_id, &reason);

let stored_reason = client.get_revocation_reason(&cred_id);
assert_eq!(stored_reason, Some(reason));
}
}
31 changes: 31 additions & 0 deletions tests/unit/progress_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1992,4 +1992,35 @@ mod progress_unit_tests {
soroban_sdk::String::from_str(&env, "progress-tracker")
);
}

// ── Issue #299: course archiving ──────────────────────────────────────

#[test]
fn test_archive_course_rejects_new_enrollments_but_preserves_progress() {
let env = Env::default();
let (_admin, contract_id) = setup_contract(&env);
let client = ProgressTrackerClient::new(&env, &contract_id);
env.mock_all_auths();

let course_id = create_test_course(&env, &client);

let existing_learner = Address::generate(&env);
client.enroll(&existing_learner, &course_id);
client.complete_module(&existing_learner, &course_id, &Symbol::new(&env, "mod_1"));

let progress_before = client.get_progress(&existing_learner, &course_id);

client.archive_course(&course_id);

let new_learner = Address::generate(&env);
let result = client.try_enroll(&new_learner, &course_id);
assert!(result.is_err(), "enrollment on an archived course should be rejected");

let progress_after = client.get_progress(&existing_learner, &course_id);
assert_eq!(
progress_after.overall_progress,
progress_before.overall_progress,
"existing progress must be preserved after archiving"
);
}
}
42 changes: 42 additions & 0 deletions tests/unit/token_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,4 +638,46 @@ mod token_unit_tests {
.expect("expected a typed contract error, not a host trap");
assert_eq!(contract_err, learn_token::ContractError::AlreadyInitialized);
}

#[test]
fn test_governance_proposal_lifecycle() {
let env = Env::default();
let (admin, contract_id, _) = setup_token(&env);
let client = LearnTokenClient::new(&env, &contract_id);
env.mock_all_auths();

let voter = Address::generate(&env);
client.mint(&admin, &voter, &1000);

let snapshot_ledger = env.ledger().sequence();
let proposal_id = client.create_proposal(
&SorobanString::from_str(&env, "Increase rewards"),
&2,
&0,
&1000,
&snapshot_ledger,
);

let proposal = client.get_proposal(&proposal_id).unwrap();
assert_eq!(proposal.choices, 2);
assert!(!proposal.executed);

// Voting power equals the voter's balance at the snapshot ledger.
assert_eq!(client.balance(&voter), 1000);

client.vote(&voter, &proposal_id, &0);

let after_vote = client.get_proposal(&proposal_id).unwrap();
assert_eq!(after_vote.vote_totals.get(0).unwrap(), 1000);

env.ledger().with_mut(|l| {
l.timestamp = 2000;
});

let winning_choice = client.execute_proposal(&proposal_id);
assert_eq!(winning_choice, 0);

let executed = client.get_proposal(&proposal_id).unwrap();
assert!(executed.executed);
}
}