1use litesvm::LiteSVM;
7use litesvm_token::spl_token;
8use solana_program::pubkey::Pubkey;
9use solana_program_pack::Pack;
10
11pub trait AssertionHelpers {
13 fn assert_account_closed(&self, pubkey: &Pubkey);
25
26 fn assert_account_exists(&self, pubkey: &Pubkey);
38
39 fn assert_token_balance(&self, token_account: &Pubkey, expected: u64);
51
52 fn assert_sol_balance(&self, pubkey: &Pubkey, expected: u64);
64
65 fn assert_mint_supply(&self, mint: &Pubkey, expected: u64);
77
78 fn assert_account_owner(&self, account: &Pubkey, expected_owner: &Pubkey);
91
92 fn assert_account_data_len(&self, account: &Pubkey, expected_len: usize);
104}
105
106impl AssertionHelpers for LiteSVM {
107 fn assert_account_closed(&self, pubkey: &Pubkey) {
108 let account = self.get_account(pubkey);
109 assert!(
110 account.is_none()
111 || (account.as_ref().unwrap().lamports == 0
112 && account.as_ref().unwrap().data.is_empty()),
113 "Expected account {} to be closed, but it exists with {} lamports and {} bytes of data",
114 pubkey,
115 account.as_ref().map_or(0, |a| a.lamports),
116 account.as_ref().map_or(0, |a| a.data.len())
117 );
118 }
119
120 fn assert_account_exists(&self, pubkey: &Pubkey) {
121 let account = self.get_account(pubkey);
122 assert!(
123 account.is_some(),
124 "Expected account {} to exist, but it doesn't",
125 pubkey
126 );
127 }
128
129 fn assert_token_balance(&self, token_account: &Pubkey, expected: u64) {
130 let account = self
131 .get_account(token_account)
132 .unwrap_or_else(|| panic!("Token account {} not found", token_account));
133
134 let token_data = spl_token::state::Account::unpack(&account.data)
135 .unwrap_or_else(|_| panic!("Failed to unpack token account {}", token_account));
136
137 assert_eq!(
138 token_data.amount, expected,
139 "Token balance mismatch for account {}. Expected: {}, Actual: {}",
140 token_account, expected, token_data.amount
141 );
142 }
143
144 fn assert_sol_balance(&self, pubkey: &Pubkey, expected: u64) {
145 let account = self.get_account(pubkey);
146 let actual = account.map_or(0, |a| a.lamports);
147 assert_eq!(
148 actual, expected,
149 "SOL balance mismatch for account {}. Expected: {}, Actual: {}",
150 pubkey, expected, actual
151 );
152 }
153
154 fn assert_mint_supply(&self, mint: &Pubkey, expected: u64) {
155 let account = self
156 .get_account(mint)
157 .unwrap_or_else(|| panic!("Mint {} not found", mint));
158
159 let mint_data = spl_token::state::Mint::unpack(&account.data)
160 .unwrap_or_else(|_| panic!("Failed to unpack mint {}", mint));
161
162 assert_eq!(
163 mint_data.supply, expected,
164 "Mint supply mismatch for {}. Expected: {}, Actual: {}",
165 mint, expected, mint_data.supply
166 );
167 }
168
169 fn assert_account_owner(&self, account: &Pubkey, expected_owner: &Pubkey) {
170 let acc = self
171 .get_account(account)
172 .unwrap_or_else(|| panic!("Account {} not found", account));
173
174 assert_eq!(
175 &acc.owner, expected_owner,
176 "Account owner mismatch for {}. Expected: {}, Actual: {}",
177 account, expected_owner, acc.owner
178 );
179 }
180
181 fn assert_account_data_len(&self, account: &Pubkey, expected_len: usize) {
182 let acc = self
183 .get_account(account)
184 .unwrap_or_else(|| panic!("Account {} not found", account));
185
186 assert_eq!(
187 acc.data.len(),
188 expected_len,
189 "Account data length mismatch for {}. Expected: {}, Actual: {}",
190 account,
191 expected_len,
192 acc.data.len()
193 );
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::test_helpers::TestHelpers;
201 use solana_signer::Signer;
202
203 #[test]
204 fn test_assert_account_closed_nonexistent() {
205 let svm = LiteSVM::new();
206 let nonexistent_account = Pubkey::new_unique();
207
208 svm.assert_account_closed(&nonexistent_account);
210 }
211
212 #[test]
213 fn test_assert_account_exists() {
214 let mut svm = LiteSVM::new();
215 let account = svm.create_funded_account(1_000_000_000).unwrap();
216
217 svm.assert_account_exists(&account.pubkey());
219 }
220
221 #[test]
222 #[should_panic(expected = "Expected account")]
223 fn test_assert_account_exists_fails() {
224 let svm = LiteSVM::new();
225 let nonexistent = Pubkey::new_unique();
226
227 svm.assert_account_exists(&nonexistent);
229 }
230
231 #[test]
232 fn test_assert_token_balance() {
233 let mut svm = LiteSVM::new();
234 let authority = svm.create_funded_account(10_000_000_000).unwrap();
235 let mint = svm.create_token_mint(&authority, 9).unwrap();
236 let token_account = svm
237 .create_associated_token_account(&mint.pubkey(), &authority)
238 .unwrap();
239
240 let amount = 1_000_000;
242 svm.mint_to(&mint.pubkey(), &token_account, &authority, amount)
243 .unwrap();
244
245 svm.assert_token_balance(&token_account, amount);
247 }
248
249 #[test]
250 #[should_panic(expected = "Token balance mismatch")]
251 fn test_assert_token_balance_fails() {
252 let mut svm = LiteSVM::new();
253 let authority = svm.create_funded_account(10_000_000_000).unwrap();
254 let mint = svm.create_token_mint(&authority, 9).unwrap();
255 let token_account = svm
256 .create_associated_token_account(&mint.pubkey(), &authority)
257 .unwrap();
258
259 svm.mint_to(&mint.pubkey(), &token_account, &authority, 1000)
261 .unwrap();
262
263 svm.assert_token_balance(&token_account, 2000);
265 }
266
267 #[test]
268 fn test_assert_sol_balance() {
269 let mut svm = LiteSVM::new();
270 let lamports = 5_000_000_000;
271 let account = svm.create_funded_account(lamports).unwrap();
272
273 svm.assert_sol_balance(&account.pubkey(), lamports);
275 }
276
277 #[test]
278 #[should_panic(expected = "SOL balance mismatch")]
279 fn test_assert_sol_balance_fails() {
280 let mut svm = LiteSVM::new();
281 let account = svm.create_funded_account(1_000_000_000).unwrap();
282
283 svm.assert_sol_balance(&account.pubkey(), 2_000_000_000);
285 }
286
287 #[test]
288 fn test_assert_sol_balance_zero_for_nonexistent() {
289 let svm = LiteSVM::new();
290 let nonexistent = Pubkey::new_unique();
291
292 svm.assert_sol_balance(&nonexistent, 0);
294 }
295
296 #[test]
297 fn test_assert_mint_supply() {
298 let mut svm = LiteSVM::new();
299 let authority = svm.create_funded_account(10_000_000_000).unwrap();
300 let mint = svm.create_token_mint(&authority, 9).unwrap();
301 let token_account = svm
302 .create_associated_token_account(&mint.pubkey(), &authority)
303 .unwrap();
304
305 let amount = 5_000_000;
307 svm.mint_to(&mint.pubkey(), &token_account, &authority, amount)
308 .unwrap();
309
310 svm.assert_mint_supply(&mint.pubkey(), amount);
312 }
313
314 #[test]
315 #[should_panic(expected = "Mint supply mismatch")]
316 fn test_assert_mint_supply_fails() {
317 let mut svm = LiteSVM::new();
318 let authority = svm.create_funded_account(10_000_000_000).unwrap();
319 let mint = svm.create_token_mint(&authority, 9).unwrap();
320 let token_account = svm
321 .create_associated_token_account(&mint.pubkey(), &authority)
322 .unwrap();
323
324 svm.mint_to(&mint.pubkey(), &token_account, &authority, 100)
326 .unwrap();
327
328 svm.assert_mint_supply(&mint.pubkey(), 200);
330 }
331
332 #[test]
333 fn test_assert_mint_supply_zero_for_new_mint() {
334 let mut svm = LiteSVM::new();
335 let authority = svm.create_funded_account(10_000_000_000).unwrap();
336 let mint = svm.create_token_mint(&authority, 9).unwrap();
337
338 svm.assert_mint_supply(&mint.pubkey(), 0);
340 }
341
342 #[test]
343 fn test_assert_account_owner() {
344 let mut svm = LiteSVM::new();
345 let owner = svm.create_funded_account(10_000_000_000).unwrap();
346 let mint = svm.create_token_mint(&owner, 9).unwrap();
347
348 svm.assert_account_owner(&mint.pubkey(), &spl_token::id());
350 }
351
352 #[test]
353 #[should_panic(expected = "Account owner mismatch")]
354 fn test_assert_account_owner_fails() {
355 let mut svm = LiteSVM::new();
356 let owner = svm.create_funded_account(10_000_000_000).unwrap();
357 let mint = svm.create_token_mint(&owner, 9).unwrap();
358
359 let wrong_owner = Pubkey::new_unique();
361 svm.assert_account_owner(&mint.pubkey(), &wrong_owner);
362 }
363
364 #[test]
365 fn test_assert_account_data_len() {
366 let mut svm = LiteSVM::new();
367 let owner = svm.create_funded_account(10_000_000_000).unwrap();
368 let mint = svm.create_token_mint(&owner, 9).unwrap();
369
370 svm.assert_account_data_len(&mint.pubkey(), 82);
372 }
373
374 #[test]
375 #[should_panic(expected = "Account data length mismatch")]
376 fn test_assert_account_data_len_fails() {
377 let mut svm = LiteSVM::new();
378 let owner = svm.create_funded_account(10_000_000_000).unwrap();
379 let mint = svm.create_token_mint(&owner, 9).unwrap();
380
381 svm.assert_account_data_len(&mint.pubkey(), 100);
383 }
384
385 #[test]
386 fn test_assert_account_data_len_token_account() {
387 let mut svm = LiteSVM::new();
388 let owner = svm.create_funded_account(10_000_000_000).unwrap();
389 let mint = svm.create_token_mint(&owner, 9).unwrap();
390 let token_account = svm.create_token_account(&mint.pubkey(), &owner).unwrap();
391
392 svm.assert_account_data_len(&token_account.pubkey(), 165);
394 }
395}