Skip to content

Commit 30346c5

Browse files
authored
Merge pull request #16 from macalinao/igm/more-assertions
Add more assertions for tests
2 parents 41621d8 + 3d324e3 commit 30346c5

File tree

6 files changed

+67
-26
lines changed

6 files changed

+67
-26
lines changed

crates/solana-address-book/src/address_book.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::collections::{HashMap, HashSet};
1414
/// Solana addresses by their public keys, labels, and roles. It's designed
1515
/// to help with debugging and transaction analysis by providing meaningful
1616
/// context for addresses.
17-
#[derive(Debug, Default)]
17+
#[derive(Clone, Debug, Default)]
1818
pub struct AddressBook {
1919
addresses: HashMap<Pubkey, Vec<(String, RegisteredAddress)>>,
2020
registered_addresses: HashSet<RegisteredAddress>,

crates/testsvm-assertions/src/lib.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
1616
use anyhow::*;
1717
use litesvm::types::TransactionMetadata;
18-
use solana_sdk::instruction::InstructionError;
18+
use solana_sdk::{instruction::InstructionError, program_error::ProgramError};
1919
use testsvm_core::prelude::*;
2020

2121
/// Provides assertion methods for failed transactions.
@@ -128,6 +128,30 @@ impl TXErrorAssertions {
128128
}
129129
}
130130

131+
/// Asserts that the transaction failed with a specific program error.
132+
pub fn with_program_error<T: Into<ProgramError>>(&self, err: T) -> Result<()> {
133+
let program_error: ProgramError = err.into();
134+
match self.error.metadata.err.clone() {
135+
solana_sdk::transaction::TransactionError::InstructionError(_, err) => {
136+
let result_program_error: ProgramError = err.try_into()?;
137+
if result_program_error == program_error {
138+
Ok(())
139+
} else {
140+
Err(anyhow!(
141+
"Expected custom program error {}, but got '{}'",
142+
program_error,
143+
result_program_error
144+
))
145+
}
146+
}
147+
_ => Err(anyhow!(
148+
"Expected custom program error {}, but got instruction error '{}'",
149+
program_error,
150+
self.error.metadata.err.to_string()
151+
)),
152+
}
153+
}
154+
131155
/// Returns the underlying transaction error for custom assertions.
132156
pub fn error(&self) -> &TXError {
133157
&self.error
@@ -270,7 +294,13 @@ impl TXResultAssertions for TXResult {
270294
}
271295

272296
fn succeeds(self) -> Result<TXSuccessAssertions> {
273-
let metadata = self?;
274-
Ok(TXSuccessAssertions { metadata })
297+
match self {
298+
Result::Ok(metadata) => Ok(TXSuccessAssertions { metadata }),
299+
Result::Err(e) => {
300+
e.print_error();
301+
e.address_book.print_all();
302+
Err(anyhow::anyhow!("Unexpected failed transaction: {}", e))
303+
}
304+
}
275305
}
276306
}

crates/testsvm-core/src/lib.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,11 @@ impl TestSVM {
6565
pub fn execute_transaction(&mut self, transaction: Transaction) -> TXResult {
6666
match self.svm.send_transaction(transaction.clone()) {
6767
Result::Ok(tx_result) => Result::Ok(tx_result),
68-
Err(e) => {
69-
let tx_error = TXError {
70-
transaction,
71-
metadata: e.clone(),
72-
};
73-
tx_error.print_error(&self.address_book);
74-
self.address_book.print_all();
75-
Err(Box::new(tx_error))
76-
}
68+
Err(e) => Err(Box::new(TXError {
69+
transaction,
70+
metadata: e.clone(),
71+
address_book: self.address_book.clone(),
72+
})),
7773
}
7874
}
7975

@@ -160,10 +156,21 @@ impl TestSVM {
160156
seeds: &[&[u8]],
161157
program_id: Pubkey,
162158
) -> Result<AccountRef<T>> {
163-
let (pubkey, _bump) = self
159+
let (pda, _) = self.get_pda_with_bump(label, seeds, program_id)?;
160+
Ok(pda)
161+
}
162+
163+
/// Finds a program derived address and return an [AccountRef] with proper type information and bump seed.
164+
pub fn get_pda_with_bump<T: anchor_lang::AccountDeserialize>(
165+
&mut self,
166+
label: &str,
167+
seeds: &[&[u8]],
168+
program_id: Pubkey,
169+
) -> Result<(AccountRef<T>, u8)> {
170+
let (pubkey, bump) = self
164171
.address_book
165172
.find_pda_with_bump(label, seeds, program_id)?;
166-
Ok(AccountRef::new(pubkey))
173+
Ok((AccountRef::new(pubkey), bump))
167174
}
168175

169176
/// Advance the time by the specified number of seconds

crates/testsvm-core/src/tx_result.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub struct TXError {
3434
pub transaction: Transaction,
3535
/// Underlying failed transaction metadata
3636
pub metadata: FailedTransactionMetadata,
37+
/// Address book at the time of transaction failure
38+
pub address_book: AddressBook,
3739
}
3840

3941
impl Error for TXError {}
@@ -46,7 +48,7 @@ impl Display for TXError {
4648

4749
impl TXError {
4850
/// Print the error details, formatted using an [AddressBook].
49-
pub fn print_error(&self, address_book: &AddressBook) {
51+
pub fn print_error(&self) {
5052
println!(
5153
"\n{} {}",
5254
"❌".red(),
@@ -61,7 +63,8 @@ impl TXError {
6163
);
6264
println!(
6365
"{}",
64-
address_book.replace_addresses_in_text(&self.metadata.meta.pretty_logs())
66+
self.address_book
67+
.replace_addresses_in_text(&self.metadata.meta.pretty_logs())
6568
);
6669

6770
// Log each instruction for debugging
@@ -76,7 +79,7 @@ impl TXError {
7679
" {} {}: {}",
7780
"Instruction".dimmed(),
7881
i.to_string().bold(),
79-
address_book.format_address(&program_id)
82+
self.address_book.format_address(&program_id)
8083
);
8184
println!(
8285
" {} {}",
@@ -111,7 +114,7 @@ impl TXError {
111114
" {} {}: {}{}",
112115
"Account".dimmed(),
113116
j.to_string().bold(),
114-
address_book.format_address(&account_key),
117+
self.address_book.format_address(&account_key),
115118
flags_str
116119
);
117120
}

crates/testsvm-quarry/src/tests/test_rewarder_management.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ fn test_set_rewards_share_authority_check() -> Result<()> {
5757
);
5858

5959
env.execute_ixs_with_signers(&[unauthorized_ix], &[&unauthorized])
60-
.fails()?;
60+
.fails()?
61+
.with_anchor_error("Unauthorized")?;
6162

6263
// Verify share remains unchanged
6364
let quarry_data = quarry.fetch_quarry(&env)?;

devenv.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"devenv": {
44
"locked": {
55
"dir": "src/modules",
6-
"lastModified": 1756415044,
6+
"lastModified": 1759939975,
77
"owner": "cachix",
88
"repo": "devenv",
9-
"rev": "c570189b38b549141179647da3ddde249ac50fec",
9+
"rev": "6eda3b7af3010d289e6e8e047435956fc80c1395",
1010
"type": "github"
1111
},
1212
"original": {
@@ -40,10 +40,10 @@
4040
]
4141
},
4242
"locked": {
43-
"lastModified": 1755960406,
43+
"lastModified": 1759523803,
4444
"owner": "cachix",
4545
"repo": "git-hooks.nix",
46-
"rev": "e891a93b193fcaf2fc8012d890dc7f0befe86ec2",
46+
"rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835",
4747
"type": "github"
4848
},
4949
"original": {
@@ -74,10 +74,10 @@
7474
},
7575
"nixpkgs": {
7676
"locked": {
77-
"lastModified": 1755783167,
77+
"lastModified": 1758532697,
7878
"owner": "cachix",
7979
"repo": "devenv-nixpkgs",
80-
"rev": "4a880fb247d24fbca57269af672e8f78935b0328",
80+
"rev": "207a4cb0e1253c7658c6736becc6eb9cace1f25f",
8181
"type": "github"
8282
},
8383
"original": {

0 commit comments

Comments
 (0)