Skip to content

Commit 0a64761

Browse files
committed
[wip]: Switch processor tests to mollusk
1 parent 62ff9d3 commit 0a64761

File tree

3 files changed

+150
-7
lines changed

3 files changed

+150
-7
lines changed

Cargo.lock

Lines changed: 3 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ thiserror = "2.0"
2222

2323
[dev-dependencies]
2424
lazy_static = "1.5.0"
25-
mollusk-svm = "0.0.13"
25+
mollusk-svm = { version = "0.0.13", git = "https://github.com/febo/mollusk.git", branch = "data-slice-check" }
2626
proptest = "1.5"
2727
serial_test = "3.2.0"
2828
solana-sdk = "2.1.0"

program/tests/processor.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#![cfg(feature = "test-sbf")]
2+
3+
//! Program state processor tests
4+
5+
use std::collections::HashSet;
6+
7+
use mollusk_svm::{
8+
result::{Check, InstructionResult},
9+
Mollusk,
10+
};
11+
use solana_sdk::{
12+
account::{create_account_for_test, Account as SolanaAccount, AccountSharedData},
13+
instruction::Instruction,
14+
program_pack::Pack,
15+
pubkey::Pubkey,
16+
rent::Rent,
17+
};
18+
use spl_token::{error::TokenError, instruction::initialize_mint, state::Mint};
19+
20+
type InstructionPack<'a> = (Instruction, Vec<&'a SolanaAccount>);
21+
22+
fn do_process_instruction(
23+
instruction: Instruction,
24+
accounts: Vec<&SolanaAccount>,
25+
checks: &[Check],
26+
) -> InstructionResult {
27+
let accounts = instruction
28+
.accounts
29+
.iter()
30+
.zip(accounts)
31+
.map(|(account_meta, account)| {
32+
(
33+
account_meta.pubkey,
34+
AccountSharedData::from(account.clone()),
35+
)
36+
})
37+
.collect::<Vec<_>>();
38+
39+
let mollusk = Mollusk::new(&spl_token::id(), "spl_token");
40+
mollusk.process_and_validate_instruction(&instruction, accounts.as_slice(), checks)
41+
}
42+
43+
fn do_process_instructions(
44+
instructions: &[InstructionPack],
45+
checks: &[Check],
46+
) -> InstructionResult {
47+
let mut present = HashSet::new();
48+
let mut tx_instructions = Vec::new();
49+
let mut tx_accounts = Vec::new();
50+
51+
instructions.iter().for_each(|(instruction, accounts)| {
52+
instruction
53+
.accounts
54+
.iter()
55+
.zip(accounts)
56+
.map(|(account_meta, account)| {
57+
(
58+
account_meta.pubkey,
59+
AccountSharedData::from((*account).clone()),
60+
)
61+
})
62+
.for_each(|(pubkey, account)| {
63+
if !present.contains(&pubkey) {
64+
present.insert(pubkey);
65+
tx_accounts.push((pubkey, account));
66+
}
67+
});
68+
tx_instructions.push(instruction.clone());
69+
});
70+
71+
let mollusk = Mollusk::new(&spl_token::id(), "spl_token");
72+
mollusk.process_and_validate_instruction_chain(
73+
tx_instructions.as_slice(),
74+
tx_accounts.as_slice(),
75+
checks,
76+
)
77+
}
78+
79+
fn mint_minimum_balance() -> u64 {
80+
Rent::default().minimum_balance(Mint::get_packed_len())
81+
}
82+
83+
fn rent_sysvar() -> SolanaAccount {
84+
create_account_for_test(&Rent::default())
85+
}
86+
87+
#[test]
88+
fn test_initialize_mint() {
89+
let program_id = spl_token::id();
90+
let owner_key = Pubkey::new_unique();
91+
let mint_key = Pubkey::new_unique();
92+
let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id);
93+
let mint2_key = Pubkey::new_unique();
94+
let mint2_account =
95+
SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id);
96+
let rent_sysvar = rent_sysvar();
97+
98+
// mint is not rent exempt
99+
do_process_instruction(
100+
initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
101+
vec![&mint_account, &rent_sysvar],
102+
&[Check::err(TokenError::NotRentExempt.into())],
103+
);
104+
105+
mint_account.lamports = mint_minimum_balance();
106+
107+
// create new mint
108+
do_process_instruction(
109+
initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
110+
vec![&mint_account, &rent_sysvar],
111+
&[Check::success()],
112+
);
113+
114+
// create twice
115+
do_process_instructions(
116+
&[
117+
(
118+
initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
119+
vec![&mint_account, &rent_sysvar],
120+
),
121+
(
122+
initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(),
123+
vec![&mint_account, &rent_sysvar],
124+
),
125+
],
126+
&[Check::err(TokenError::AlreadyInUse.into())],
127+
);
128+
129+
// create another mint that can freeze
130+
do_process_instruction(
131+
initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(),
132+
vec![&mint2_account, &rent_sysvar],
133+
&[
134+
// Account successfully re-initialized.
135+
Check::success(),
136+
// mint authority is set
137+
Check::account(&mint2_key)
138+
.data_slice(46, &[1, 0, 0, 0])
139+
.build(),
140+
// mint authority matches owner
141+
Check::account(&mint2_key)
142+
.data_slice(50, owner_key.as_ref())
143+
.build(),
144+
],
145+
);
146+
}

0 commit comments

Comments
 (0)