Skip to content

Commit 8876df8

Browse files
committed
Add precision tests
1 parent 7511655 commit 8876df8

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

p-token/tests/amount_to_ui_amount.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
mod setup;
22

33
use {
4-
setup::{mint, TOKEN_PROGRAM_ID},
4+
mollusk_svm::result::Check,
5+
setup::{
6+
mint,
7+
mollusk::{create_mint_account, mollusk},
8+
TOKEN_PROGRAM_ID,
9+
},
510
solana_program_test::{tokio, ProgramTest},
611
solana_pubkey::Pubkey,
712
solana_signer::Signer,
@@ -45,3 +50,36 @@ async fn amount_to_ui_amount() {
4550

4651
assert!(account.is_some());
4752
}
53+
54+
#[test]
55+
fn amount_to_ui_amount_with_maximum_decimals() {
56+
// Given a mint account with `u8::MAX` as decimals.
57+
58+
let mint = Pubkey::new_unique();
59+
let mint_authority = Pubkey::new_unique();
60+
let freeze_authority = Pubkey::new_unique();
61+
62+
let mint_account = create_mint_account(
63+
mint_authority,
64+
Some(freeze_authority),
65+
u8::MAX,
66+
&TOKEN_PROGRAM_ID,
67+
);
68+
69+
// When we convert a 20 amount using the mint the transaction should succeed and
70+
// return the correct UI amount.
71+
72+
let instruction =
73+
spl_token::instruction::amount_to_ui_amount(&spl_token::ID, &mint, 20).unwrap();
74+
75+
// The expected UI amount is "0.000....002" without the trailing zeros.
76+
let mut ui_amount = [b'0'; u8::MAX as usize + 1];
77+
ui_amount[1] = b'.';
78+
ui_amount[ui_amount.len() - 1] = b'2';
79+
80+
mollusk().process_and_validate_instruction(
81+
&instruction,
82+
&[(mint, mint_account)],
83+
&[Check::success(), Check::return_data(&ui_amount)],
84+
);
85+
}

p-token/tests/setup/mint.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ pub async fn initialize(
1515
mint_authority: Pubkey,
1616
freeze_authority: Option<Pubkey>,
1717
program_id: &Pubkey,
18+
) -> Result<Pubkey, ProgramError> {
19+
initialize_with_decimals(context, mint_authority, freeze_authority, 4, program_id).await
20+
}
21+
22+
pub async fn initialize_with_decimals(
23+
context: &mut ProgramTestContext,
24+
mint_authority: Pubkey,
25+
freeze_authority: Option<Pubkey>,
26+
decimals: u8,
27+
program_id: &Pubkey,
1828
) -> Result<Pubkey, ProgramError> {
1929
// Mint account keypair.
2030
let account = Keypair::new();
@@ -27,7 +37,7 @@ pub async fn initialize(
2737
&account.pubkey(),
2838
&mint_authority,
2939
freeze_authority.as_ref(),
30-
4,
40+
decimals,
3141
)
3242
.unwrap();
3343
// Switches the program id in case we are using a "custom" one.

p-token/tests/setup/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ use solana_pubkey::Pubkey;
44
pub mod account;
55
#[allow(dead_code)]
66
pub mod mint;
7+
#[allow(dead_code)]
8+
pub mod mollusk;
79

810
pub const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array(pinocchio_token_interface::program::ID);

p-token/tests/setup/mollusk.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use mollusk_svm::Mollusk;
2+
use pinocchio_token_interface::state::{load_mut_unchecked, mint::Mint};
3+
use solana_account::Account;
4+
use solana_pubkey::Pubkey;
5+
use solana_rent::Rent;
6+
use solana_sdk_ids::bpf_loader_upgradeable;
7+
8+
use crate::setup::TOKEN_PROGRAM_ID;
9+
10+
pub fn create_mint_account(
11+
mint_authority: Pubkey,
12+
freeze_authority: Option<Pubkey>,
13+
decimals: u8,
14+
program_owner: &Pubkey,
15+
) -> Account {
16+
let space = size_of::<Mint>();
17+
let lamports = Rent::default().minimum_balance(space);
18+
19+
let mut data: Vec<u8> = vec![0u8; space];
20+
let mint = unsafe { load_mut_unchecked::<Mint>(data.as_mut_slice()).unwrap() };
21+
mint.set_mint_authority(mint_authority.as_array());
22+
if let Some(freeze_authority) = freeze_authority {
23+
mint.set_freeze_authority(freeze_authority.as_array());
24+
}
25+
mint.set_initialized();
26+
mint.decimals = decimals;
27+
28+
Account {
29+
lamports,
30+
data,
31+
owner: *program_owner,
32+
executable: false,
33+
..Default::default()
34+
}
35+
}
36+
37+
/// Creates a Mollusk instance with the default feature set.
38+
pub fn mollusk() -> Mollusk {
39+
let mut mollusk = Mollusk::default();
40+
mollusk.add_program(
41+
&TOKEN_PROGRAM_ID,
42+
"pinocchio_token_program",
43+
&bpf_loader_upgradeable::id(),
44+
);
45+
mollusk
46+
}

p-token/tests/ui_amount_to_amount.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
mod setup;
22

33
use {
4+
crate::setup::mollusk::{create_mint_account, mollusk},
5+
core::str::from_utf8,
6+
mollusk_svm::result::Check,
47
setup::{mint, TOKEN_PROGRAM_ID},
58
solana_program_test::{tokio, ProgramTest},
69
solana_pubkey::Pubkey,
@@ -45,3 +48,38 @@ async fn ui_amount_to_amount() {
4548

4649
assert!(account.is_some());
4750
}
51+
52+
#[test]
53+
fn ui_amount_to_amount_with_maximum_decimals() {
54+
// Given a mint account with `u8::MAX` as decimals.
55+
56+
let mint = Pubkey::new_unique();
57+
let mint_authority = Pubkey::new_unique();
58+
let freeze_authority = Pubkey::new_unique();
59+
60+
let mint_account = create_mint_account(
61+
mint_authority,
62+
Some(freeze_authority),
63+
u8::MAX,
64+
&TOKEN_PROGRAM_ID,
65+
);
66+
67+
// String representing the ui value `0.000....002`
68+
let mut ui_amount = [b'0'; u8::MAX as usize + 1];
69+
ui_amount[1] = b'.';
70+
ui_amount[ui_amount.len() - 1] = b'2';
71+
72+
let input = from_utf8(&ui_amount).unwrap();
73+
74+
// When we convert the ui amount using the mint, the transaction should
75+
// succeed and return 20 as the amount.
76+
77+
let instruction =
78+
spl_token::instruction::ui_amount_to_amount(&spl_token::ID, &mint, input).unwrap();
79+
80+
mollusk().process_and_validate_instruction(
81+
&instruction,
82+
&[(mint, mint_account)],
83+
&[Check::success(), Check::return_data(&20u64.to_le_bytes())],
84+
);
85+
}

0 commit comments

Comments
 (0)