crucible_test_context/
account_builders.rs1use crate::TestContext;
2use anchor_lang::solana_program::program_pack::Pack;
3use anyhow::Result;
4use solana_account::Account;
5use solana_pubkey::Pubkey;
6use spl_token::solana_program::program_option::COption;
7
8pub struct GenericAccountBuilder<'a> {
9 pub(crate) ctx: &'a mut TestContext,
10 pub(crate) address: Pubkey,
11 pub(crate) account_state: Account,
12}
13
14pub trait AccountBuilderBase: Sized {
15 fn account_state_mut(&mut self) -> &mut Account;
16 fn address_mut(&mut self) -> &mut Pubkey;
17
18 fn pubkey(mut self, pk: Pubkey) -> Self {
19 *self.address_mut() = pk;
20 self
21 }
22
23 fn owner(mut self, pk: Pubkey) -> Self {
24 self.account_state_mut().owner = pk;
25 self
26 }
27
28 fn executable(mut self, val: bool) -> Self {
29 self.account_state_mut().executable = val;
30 self
31 }
32
33 fn rent_epoch(mut self, val: u64) -> Self {
34 self.account_state_mut().rent_epoch = val;
35 self
36 }
37
38 fn lamports(mut self, amount: u64) -> Self {
39 self.account_state_mut().lamports = amount;
40 self
41 }
42
43 fn size(mut self, length: usize) -> Self {
44 self.account_state_mut().data = vec![0; length];
45 self
46 }
47
48 fn data(mut self, bytes: &[u8]) -> Self {
49 self.account_state_mut().data = Vec::from(bytes);
50 self
51 }
52}
53
54impl AccountBuilderBase for GenericAccountBuilder<'_> {
55 fn account_state_mut(&mut self) -> &mut Account {
56 &mut self.account_state
57 }
58 fn address_mut(&mut self) -> &mut Pubkey {
59 &mut self.address
60 }
61}
62
63impl GenericAccountBuilder<'_> {
64 pub fn create(self) -> Result<Pubkey> {
65 if self.address == Pubkey::default() {
67 return Err(anyhow::anyhow!("Address must be set with .pubkey()"));
68 }
69 self.ctx.track_account(self.address);
70 let _ = self.ctx.svm.set_account(self.address, self.account_state);
71 Ok(self.address)
72 }
73}
74
75pub struct MintAccountBuilder<'a> {
76 pub(crate) ctx: &'a mut TestContext,
77 pub(crate) address: Pubkey,
78 pub(crate) account_state: Account,
79 pub(crate) mint: spl_token::state::Mint,
80}
81
82impl AccountBuilderBase for MintAccountBuilder<'_> {
83 fn account_state_mut(&mut self) -> &mut Account {
84 &mut self.account_state
85 }
86 fn address_mut(&mut self) -> &mut Pubkey {
87 &mut self.address
88 }
89}
90
91impl MintAccountBuilder<'_> {
92 pub fn create(self) -> Result<Pubkey> {
93 if self.address == Pubkey::default() {
94 return Err(anyhow::anyhow!("Address must be set with .pubkey()"));
95 }
96
97 let mut account = self.account_state;
98 spl_token::state::Mint::pack(self.mint, &mut account.data)?;
99 self.ctx.track_account(self.address);
100 let _ = self.ctx.svm.set_account(self.address, account);
101 Ok(self.address)
102 }
103
104 pub fn mint_authority(mut self, authority: Pubkey) -> Self {
105 self.mint.mint_authority = COption::Some(authority);
106 self
107 }
108
109 pub fn supply(mut self, supply: u64) -> Self {
110 self.mint.supply = supply;
111 self
112 }
113
114 pub fn decimals(mut self, decimals: u8) -> Self {
115 self.mint.decimals = decimals;
116 self
117 }
118
119 pub fn is_initialized(mut self, initialized: bool) -> Self {
120 self.mint.is_initialized = initialized;
121 self
122 }
123
124 pub fn freeze_authority(mut self, authority: Option<Pubkey>) -> Self {
125 self.mint.freeze_authority = match authority {
126 Some(pk) => COption::Some(pk),
127 None => COption::None,
128 };
129 self
130 }
131}
132
133pub struct TokenAccountBuilder<'a> {
134 pub(crate) ctx: &'a mut TestContext,
135 pub(crate) address: Pubkey,
136 pub(crate) account_state: Account,
137 pub(crate) token_state: spl_token::state::Account,
138}
139
140impl AccountBuilderBase for TokenAccountBuilder<'_> {
141 fn account_state_mut(&mut self) -> &mut Account {
142 &mut self.account_state
143 }
144 fn address_mut(&mut self) -> &mut Pubkey {
145 &mut self.address
146 }
147}
148
149impl TokenAccountBuilder<'_> {
150 pub fn create(self) -> Result<Pubkey> {
151 if self.address == Pubkey::default() {
152 return Err(anyhow::anyhow!("Address must be set with .pubkey()"));
153 }
154
155 if self.token_state.mint == Pubkey::default() {
156 return Err(anyhow::anyhow!("Mint must be set with .mint()"));
157 }
158
159 if self.token_state.owner == Pubkey::default() {
160 return Err(anyhow::anyhow!("Owner must be set with .token_owner()"));
161 }
162
163 let mut account = self.account_state;
164 spl_token::state::Account::pack(self.token_state, &mut account.data)?;
165 self.ctx.track_account(self.address);
166 let _ = self.ctx.svm.set_account(self.address, account);
167 Ok(self.address)
168 }
169
170 pub fn mint(mut self, mint: Pubkey) -> Self {
171 self.token_state.mint = mint;
172 self
173 }
174
175 pub fn token_owner(mut self, owner: Pubkey) -> Self {
176 self.token_state.owner = owner;
177 self
178 }
179
180 pub fn amount(mut self, amount: u64) -> Self {
181 self.token_state.amount = amount;
182 self
183 }
184
185 pub fn delegate(mut self, delegate: Option<Pubkey>) -> Self {
186 self.token_state.delegate = match delegate {
187 Some(pk) => COption::Some(pk),
188 None => COption::None,
189 };
190 self
191 }
192
193 pub fn state(mut self, state: spl_token::state::AccountState) -> Self {
194 self.token_state.state = state;
195 self
196 }
197
198 pub fn is_native(mut self, native_amount: Option<u64>) -> Self {
199 self.token_state.is_native = match native_amount {
200 Some(amount) => COption::Some(amount),
201 None => COption::None,
202 };
203 self
204 }
205
206 pub fn delegated_amount(mut self, amount: u64) -> Self {
207 self.token_state.delegated_amount = amount;
208 self
209 }
210
211 pub fn close_authority(mut self, authority: Option<Pubkey>) -> Self {
212 self.token_state.close_authority = match authority {
213 Some(pk) => COption::Some(pk),
214 None => COption::None,
215 };
216 self
217 }
218}