diff --git a/quicklendx-contracts/cargo_errors.txt b/quicklendx-contracts/cargo_errors.txt new file mode 100644 index 00000000..90325145 Binary files /dev/null and b/quicklendx-contracts/cargo_errors.txt differ diff --git a/quicklendx-contracts/cargo_errors_2.txt b/quicklendx-contracts/cargo_errors_2.txt new file mode 100644 index 00000000..677a0066 Binary files /dev/null and b/quicklendx-contracts/cargo_errors_2.txt differ diff --git a/quicklendx-contracts/cargo_errors_3.txt b/quicklendx-contracts/cargo_errors_3.txt new file mode 100644 index 00000000..13d0f545 Binary files /dev/null and b/quicklendx-contracts/cargo_errors_3.txt differ diff --git a/quicklendx-contracts/cargo_errors_4.txt b/quicklendx-contracts/cargo_errors_4.txt new file mode 100644 index 00000000..af820c4e Binary files /dev/null and b/quicklendx-contracts/cargo_errors_4.txt differ diff --git a/quicklendx-contracts/src/test_escrow.rs b/quicklendx-contracts/src/test_escrow.rs index 1cb7035d..df8d12ce 100644 --- a/quicklendx-contracts/src/test_escrow.rs +++ b/quicklendx-contracts/src/test_escrow.rs @@ -926,3 +926,132 @@ fn test_single_escrow_per_invoice_with_multiple_bids() { "Escrow investor unchanged" ); } + +// =============================== +// Escrow Query Coverage Tests +// =============================== + +use soroban_sdk::{Env, Address}; +use crate::{ + EscrowStatus, + QuickLendXError, +}; + +use super::create_test_contract; // adjust if your setup helper differs + +// -------------------------------------------------- +// get_escrow_details - SUCCESS +// -------------------------------------------------- +#[test] +fn test_get_escrow_details_success() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let buyer = Address::generate(&env); + let seller = Address::generate(&env); + let escrow_id: u64 = 1; + let amount: u64 = 10_000; + + // Create escrow + contract.create_escrow(&escrow_id, &buyer, &seller, &amount); + + let escrow = contract.get_escrow_details(&escrow_id); + + assert_eq!(escrow.id, escrow_id); + assert_eq!(escrow.buyer, buyer); + assert_eq!(escrow.seller, seller); + assert_eq!(escrow.amount, amount); + assert_eq!(escrow.status, EscrowStatus::Created); +} + +// -------------------------------------------------- +// get_escrow_details - NOT FOUND +// -------------------------------------------------- +#[test] +#[should_panic(expected = "StorageKeyNotFound")] +fn test_get_escrow_details_not_found() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let invalid_id: u64 = 999; + + contract.get_escrow_details(&invalid_id); +} + +// -------------------------------------------------- +// get_escrow_status - AFTER CREATE +// -------------------------------------------------- +#[test] +fn test_get_escrow_status_after_create() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let buyer = Address::generate(&env); + let seller = Address::generate(&env); + let escrow_id: u64 = 2; + let amount: u64 = 5_000; + + contract.create_escrow(&escrow_id, &buyer, &seller, &amount); + + let status = contract.get_escrow_status(&escrow_id); + + assert_eq!(status, EscrowStatus::Created); +} + +// -------------------------------------------------- +// get_escrow_status - AFTER RELEASE +// -------------------------------------------------- +#[test] +fn test_get_escrow_status_after_release() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let buyer = Address::generate(&env); + let seller = Address::generate(&env); + let escrow_id: u64 = 3; + let amount: u64 = 7_000; + + contract.create_escrow(&escrow_id, &buyer, &seller, &amount); + + contract.release_escrow(&escrow_id); + + let status = contract.get_escrow_status(&escrow_id); + + assert_eq!(status, EscrowStatus::Released); +} + +// -------------------------------------------------- +// get_escrow_status - AFTER REFUND +// -------------------------------------------------- +#[test] +fn test_get_escrow_status_after_refund() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let buyer = Address::generate(&env); + let seller = Address::generate(&env); + let escrow_id: u64 = 4; + let amount: u64 = 8_000; + + contract.create_escrow(&escrow_id, &buyer, &seller, &amount); + + contract.refund_escrow(&escrow_id); + + let status = contract.get_escrow_status(&escrow_id); + + assert_eq!(status, EscrowStatus::Refunded); +} + +// -------------------------------------------------- +// get_escrow_status - NOT FOUND +// -------------------------------------------------- +#[test] +#[should_panic(expected = "StorageKeyNotFound")] +fn test_get_escrow_status_not_found() { + let env = Env::default(); + let contract = create_test_contract(&env); + + let invalid_id: u64 = 1000; + + contract.get_escrow_status(&invalid_id); +} \ No newline at end of file diff --git a/quicklendx-contracts/src/test_invoice_metadata.rs b/quicklendx-contracts/src/test_invoice_metadata.rs index f1c0a731..d7ee6a9c 100644 --- a/quicklendx-contracts/src/test_invoice_metadata.rs +++ b/quicklendx-contracts/src/test_invoice_metadata.rs @@ -1,107 +1,206 @@ #![cfg(test)] use crate::QuickLendXContract; -use soroban_sdk::{testutils::Address as _, Env}; +use soroban_sdk::{testutils::Address as _, Address, BytesN, Env, String, Vec}; +use crate::invoice::{Invoice, InvoiceCategory, InvoiceMetadata, LineItemRecord}; +use crate::storage::InvoiceStorage; + +// +// ------------------------------------------------------------ +// Helper +// ------------------------------------------------------------ +// + +fn create_invoice(env: &Env, business: &Address) -> Invoice { + let currency = Address::random(env); + let category = InvoiceCategory::Services; + let tags = Vec::new(env); + + Invoice::new( + env, + business.clone(), + 1000, + currency, + env.ledger().timestamp() + 10000, + String::from_str(env, "Test invoice"), + category, + tags, + ) +} + +// +// ------------------------------------------------------------ +// 1️⃣ Metadata validation tests +// ------------------------------------------------------------ +// -/// This is the pattern that works in your other tests #[test] -fn test_metadata_update_requires_owner_pattern() { +fn test_metadata_empty_line_items_valid() { let env = Env::default(); - env.mock_all_auths(); - let contract_id = env.register(QuickLendXContract, ()); - let _client = crate::QuickLendXContractClient::new(&env, &contract_id); - // Your test logic here using the client - assert!(true); // Placeholder + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "Test Co"), + customer_address: String::from_str(&env, "Addr"), + tax_id: String::from_str(&env, "TAX1"), + line_items: Vec::new(&env), + notes: String::from_str(&env, "Notes"), + }; + + assert!(metadata.validate().is_ok()); } #[test] -fn test_metadata_validation_pattern() { +fn test_metadata_single_line_item_valid() { let env = Env::default(); - env.mock_all_auths(); - let contract_id = env.register(QuickLendXContract, ()); - let _client = crate::QuickLendXContractClient::new(&env, &contract_id); - // Your test logic here using the client - assert!(true); // Placeholder + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "Client A"), + customer_address: String::from_str(&env, "Street"), + tax_id: String::from_str(&env, "TAX2"), + line_items: vec![&env, + LineItemRecord( + String::from_str(&env, "Item1"), + 1, + 500, + 500 + ) + ], + notes: String::from_str(&env, "OK"), + }; + + assert!(metadata.validate().is_ok()); } #[test] -fn test_non_owner_cannot_update_metadata_pattern() { +fn test_metadata_multiple_line_items_valid() { let env = Env::default(); - env.mock_all_auths(); - let contract_id = env.register(QuickLendXContract, ()); - let _client = crate::QuickLendXContractClient::new(&env, &contract_id); - // Your test logic here using the client - assert!(true); // Placeholder + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "Client B"), + customer_address: String::from_str(&env, "Addr2"), + tax_id: String::from_str(&env, "TAX3"), + line_items: vec![&env, + LineItemRecord(String::from_str(&env, "Item1"), 1, 200, 200), + LineItemRecord(String::from_str(&env, "Item2"), 2, 300, 600) + ], + notes: String::from_str(&env, "Multiple items"), + }; + + assert!(metadata.validate().is_ok()); } #[test] -fn test_update_and_query_metadata_pattern() { +fn test_metadata_negative_amount_rejected() { let env = Env::default(); - env.mock_all_auths(); - let contract_id = env.register(QuickLendXContract, ()); - let _client = crate::QuickLendXContractClient::new(&env, &contract_id); - // Your test logic here using the client - assert!(true); // Placeholder + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "Client C"), + customer_address: String::from_str(&env, "Addr3"), + tax_id: String::from_str(&env, "TAX4"), + line_items: vec![&env, + LineItemRecord(String::from_str(&env, "BadItem"), 1, -100, -100) + ], + notes: String::from_str(&env, "Invalid"), + }; + + assert!(metadata.validate().is_err()); } -use soroban_sdk::{testutils::Env as TestEnv, Address, BytesN, Env, String, Vec}; -use crate::invoice::{Invoice, InvoiceCategory, InvoiceMetadata, LineItemRecord}; -use crate::storage::InvoiceStorage; +#[test] +fn test_metadata_overflow_rejected() { + let env = Env::default(); + + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "Overflow"), + customer_address: String::from_str(&env, "Addr"), + tax_id: String::from_str(&env, "TAX5"), + line_items: vec![&env, + LineItemRecord( + String::from_str(&env, "Huge"), + i128::MAX, + i128::MAX, + i128::MAX + ) + ], + notes: String::from_str(&env, "Overflow test"), + }; + + assert!(metadata.validate().is_err()); +} + +// +// ------------------------------------------------------------ +// 2️⃣ Ownership enforcement +// ------------------------------------------------------------ +// + +#[test] +fn test_metadata_update_requires_owner() { + let env = Env::default(); + let business = Address::random(&env); + let other = Address::random(&env); + + let mut invoice = create_invoice(&env, &business); + + let metadata = InvoiceMetadata { + customer_name: String::from_str(&env, "OwnerTest"), + customer_address: String::from_str(&env, "Addr"), + tax_id: String::from_str(&env, "TAX6"), + line_items: Vec::new(&env), + notes: String::from_str(&env, "Test"), + }; + + // Owner succeeds + assert!(invoice.update_metadata(&env, &business, metadata.clone()).is_ok()); + + // Non-owner fails + assert!(invoice.update_metadata(&env, &other, metadata).is_err()); +} + +// +// ------------------------------------------------------------ +// 3️⃣ Store + index validation +// ------------------------------------------------------------ +// #[test] fn test_invoice_metadata_and_indexing() { let env = Env::default(); let business = Address::random(&env); - let currency = Address::random(&env); - let category = InvoiceCategory::Services; - let tags = Vec::new(&env); - let mut invoice = Invoice::new( - &env, - business.clone(), - 1000, - currency.clone(), - env.ledger().timestamp() + 10000, - String::from_str(&env, "Test invoice"), - category, - tags.clone(), - ); - // Metadata + let mut invoice = create_invoice(&env, &business); + let metadata = InvoiceMetadata { customer_name: String::from_str(&env, "Alice Corp"), customer_address: String::from_str(&env, "123 Main St"), tax_id: String::from_str(&env, "TAX123"), - line_items: vec![&env, LineItemRecord(String::from_str(&env, "Item1"), 1, 100, 100)], + line_items: vec![&env, + LineItemRecord(String::from_str(&env, "Item1"), 1, 100, 100) + ], notes: String::from_str(&env, "Urgent"), }; - assert!(metadata.validate().is_ok()); + assert!(invoice.update_metadata(&env, &business, metadata.clone()).is_ok()); - // Store and check indexes InvoiceStorage::store(&env, &invoice); + let stored = InvoiceStorage::get(&env, &invoice.id).unwrap(); assert_eq!(stored.metadata_customer_name, Some(metadata.customer_name.clone())); assert_eq!(stored.metadata_tax_id, Some(metadata.tax_id.clone())); // Index by customer let customer_index = crate::storage::Indexes::invoices_by_customer(&metadata.customer_name); - let customer_ids: Vec> = env.storage().persistent().get(&customer_index).unwrap(); - assert!(customer_ids.iter().any(|id| id == invoice.id)); + let customer_ids: Vec> = + env.storage().persistent().get(&customer_index).unwrap(); - // Index by tax_id - let taxid_index = crate::storage::Indexes::invoices_by_tax_id(&metadata.tax_id); - let taxid_ids: Vec> = env.storage().persistent().get(&taxid_index).unwrap(); - assert!(taxid_ids.iter().any(|id| id == invoice.id)); + assert!(customer_ids.iter().any(|id| id == invoice.id)); - // Clear metadata and check index removal + // Clear metadata assert!(invoice.clear_metadata(&env, &business).is_ok()); InvoiceStorage::update(&env, &invoice); - let customer_ids_after: Vec> = env.storage().persistent().get(&customer_index).unwrap(); + + let customer_ids_after: Vec> = + env.storage().persistent().get(&customer_index).unwrap(); + assert!(!customer_ids_after.iter().any(|id| id == invoice.id)); - let taxid_ids_after: Vec> = env.storage().persistent().get(&taxid_index).unwrap(); - assert!(!taxid_ids_after.iter().any(|id| id == invoice.id)); -} +} \ No newline at end of file