@layerzerolabs/framework-solana-anchor-trait 0.2.62 → 0.2.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +3 -0
- package/README.md +316 -0
- package/examples/shapes/Cargo.lock +4126 -0
- package/examples/shapes/Cargo.toml +16 -0
- package/examples/shapes/macros/src/audit.rs +15 -0
- package/examples/shapes/macros/src/instructions/clear.rs +19 -0
- package/examples/shapes/macros/src/instructions/compute_area.rs +18 -20
- package/examples/shapes/macros/src/instructions/compute_perimeter.rs +18 -20
- package/examples/shapes/macros/src/instructions/get_dimension.rs +19 -0
- package/examples/shapes/macros/src/instructions/get_dimension_count.rs +19 -17
- package/examples/shapes/macros/src/instructions/mod.rs +8 -0
- package/examples/shapes/macros/src/instructions/reset.rs +50 -0
- package/examples/shapes/macros/src/instructions/scale.rs +52 -0
- package/examples/shapes/macros/src/lib.rs +14 -11
- package/examples/shapes/macros/src/shapes.rs +21 -26
- package/examples/shapes/macros/src/state_types.rs +14 -0
- package/examples/shapes/programs/ellipse/Cargo.toml +7 -0
- package/examples/shapes/programs/ellipse/src/lib.rs +69 -17
- package/examples/shapes/programs/ellipse/tests/ellipse/helpers.rs +110 -0
- package/examples/shapes/programs/ellipse/tests/ellipse/negative.rs +49 -0
- package/examples/shapes/programs/ellipse/tests/ellipse/positive.rs +231 -0
- package/examples/shapes/programs/ellipse/tests/ellipse.rs +23 -0
- package/examples/shapes/programs/triangle/Cargo.toml +7 -0
- package/examples/shapes/programs/triangle/src/lib.rs +69 -16
- package/examples/shapes/programs/triangle/tests/triangle/helpers.rs +123 -0
- package/examples/shapes/programs/triangle/tests/triangle/negative.rs +49 -0
- package/examples/shapes/programs/triangle/tests/triangle/positive.rs +225 -0
- package/examples/shapes/programs/triangle/tests/triangle.rs +23 -0
- package/examples/shapes/target/deploy/shapes_ellipse-keypair.json +1 -0
- package/examples/shapes/target/deploy/shapes_ellipse.so +0 -0
- package/examples/shapes/target/deploy/shapes_triangle-keypair.json +1 -0
- package/examples/shapes/target/deploy/shapes_triangle.so +0 -0
- package/package.json +20 -9
- package/src/assembly.rs +41 -6
- package/src/generation.rs +108 -131
- package/src/lib.rs +6 -4
- package/src/overrides.rs +56 -81
- package/tests/assembly.rs +154 -23
- package/tests/common/mod.rs +68 -14
- package/tests/generation.rs +137 -65
- package/tests/override.rs +93 -55
- package/tests/snapshots/snapshots__tests__snapshot_all_defaults.snap +32 -5
- package/tests/snapshots/snapshots__tests__snapshot_full_override.snap +35 -7
- package/tests/snapshots/snapshots__tests__snapshot_handler_override.snap +37 -7
- package/tests/snapshots/snapshots__tests__snapshot_mixed_overrides.snap +40 -9
- package/tests/snapshots/snapshots__tests__snapshot_with_extend_macro.snap +82 -0
- package/tests/snapshots.rs +51 -18
- package/examples/shapes/Anchor.toml +0 -19
- package/examples/shapes/programs/ellipse/src/state.rs +0 -9
- package/examples/shapes/programs/triangle/src/state.rs +0 -9
package/tests/generation.rs
CHANGED
|
@@ -3,7 +3,7 @@ mod common;
|
|
|
3
3
|
#[cfg(test)]
|
|
4
4
|
mod tests {
|
|
5
5
|
use super::common::*;
|
|
6
|
-
use quote::ToTokens;
|
|
6
|
+
use quote::{quote, ToTokens};
|
|
7
7
|
|
|
8
8
|
// -----------------------------------------------------------------------
|
|
9
9
|
// Tests — override level resolution
|
|
@@ -11,24 +11,21 @@ mod tests {
|
|
|
11
11
|
|
|
12
12
|
#[test]
|
|
13
13
|
fn default_level_emits_context_and_entrypoint() {
|
|
14
|
-
// All defaults — no overrides except required lz_receive
|
|
15
14
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
16
15
|
mod my_program {
|
|
17
16
|
#[test_instruction]
|
|
18
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
17
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
19
18
|
Ok(())
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
};
|
|
23
22
|
let gen = generate_ok(&module);
|
|
24
23
|
|
|
25
|
-
// Default impls should be generated for each provided instruction
|
|
26
24
|
let structs = parse_structs(&gen.default_impls);
|
|
27
25
|
assert!(find_struct(&structs, "StdSetPeer").is_some(), "should emit StdSetPeer");
|
|
28
26
|
assert!(find_struct(&structs, "StdGetPeer").is_some(), "should emit StdGetPeer");
|
|
29
27
|
assert!(find_struct(&structs, "StdToken").is_some(), "should emit StdToken");
|
|
30
28
|
|
|
31
|
-
// Entrypoints should include all instructions
|
|
32
29
|
let fns = parse_fns(&gen.entrypoints);
|
|
33
30
|
assert!(find_fn(&fns, "set_peer").is_some(), "should have set_peer entrypoint");
|
|
34
31
|
assert!(find_fn(&fns, "get_peer").is_some(), "should have get_peer entrypoint");
|
|
@@ -41,7 +38,7 @@ mod tests {
|
|
|
41
38
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
42
39
|
mod my_program {
|
|
43
40
|
#[test_instruction]
|
|
44
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
41
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
45
42
|
Ok(())
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -55,11 +52,11 @@ mod tests {
|
|
|
55
52
|
assert!(is_mut, "set_peer should have `mut ctx`");
|
|
56
53
|
assert_eq!(ctx_type, "StdSetPeer", "should use default context type");
|
|
57
54
|
|
|
58
|
-
// Default handler called by reference: StdSetPeer::apply(&mut ctx,
|
|
55
|
+
// Default handler called by reference: StdSetPeer::apply(&mut ctx, ¶ms)
|
|
59
56
|
let body = set_peer.block.to_token_stream().to_string();
|
|
60
57
|
assert!(
|
|
61
|
-
body.contains("StdSetPeer :: apply (& mut ctx"),
|
|
62
|
-
"mutable default should pass &mut ctx to handler: {body}"
|
|
58
|
+
body.contains("StdSetPeer :: apply (& mut ctx , & params)"),
|
|
59
|
+
"mutable default should pass &mut ctx and ¶ms to handler: {body}"
|
|
63
60
|
);
|
|
64
61
|
}
|
|
65
62
|
|
|
@@ -68,7 +65,7 @@ mod tests {
|
|
|
68
65
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
69
66
|
mod my_program {
|
|
70
67
|
#[test_instruction]
|
|
71
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
68
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
72
69
|
Ok(())
|
|
73
70
|
}
|
|
74
71
|
}
|
|
@@ -82,40 +79,38 @@ mod tests {
|
|
|
82
79
|
assert!(!is_mut, "view default should use `ctx` (no mut)");
|
|
83
80
|
assert_eq!(ctx_type, "StdGetPeer", "should use default context type");
|
|
84
81
|
|
|
85
|
-
// Default handler called by immutable reference: StdGetPeer::apply(&ctx,
|
|
82
|
+
// Default handler called by immutable reference: StdGetPeer::apply(&ctx, ¶ms)
|
|
86
83
|
let body = get_peer.block.to_token_stream().to_string();
|
|
87
84
|
assert!(
|
|
88
|
-
body.contains("StdGetPeer :: apply (& ctx"),
|
|
89
|
-
"view default should pass &ctx to handler: {body}"
|
|
85
|
+
body.contains("StdGetPeer :: apply (& ctx , & params)"),
|
|
86
|
+
"view default should pass &ctx and ¶ms to handler: {body}"
|
|
90
87
|
);
|
|
91
88
|
}
|
|
92
89
|
|
|
93
90
|
#[test]
|
|
94
|
-
fn
|
|
95
|
-
// Override set_peer but reuse StdSetPeer context
|
|
91
|
+
fn override_with_default_context_emits_default() {
|
|
92
|
+
// Override set_peer but reuse StdSetPeer context.
|
|
96
93
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
97
94
|
mod my_program {
|
|
98
95
|
#[test_instruction]
|
|
99
|
-
pub fn set_peer(ctx: Context<StdSetPeer>, params: SetPeerParams) -> Result<()> {
|
|
96
|
+
pub fn set_peer(ctx: &mut Context<StdSetPeer>, params: &SetPeerParams) -> Result<()> {
|
|
100
97
|
Ok(())
|
|
101
98
|
}
|
|
102
99
|
|
|
103
100
|
#[test_instruction]
|
|
104
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
101
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
105
102
|
Ok(())
|
|
106
103
|
}
|
|
107
104
|
}
|
|
108
105
|
};
|
|
109
106
|
let gen = generate_ok(&module);
|
|
110
107
|
|
|
111
|
-
// Default impl should still be generated (handler reuses it)
|
|
112
108
|
let structs = parse_structs(&gen.default_impls);
|
|
113
109
|
assert!(
|
|
114
110
|
find_struct(&structs, "StdSetPeer").is_some(),
|
|
115
|
-
"
|
|
111
|
+
"override should still emit StdSetPeer context"
|
|
116
112
|
);
|
|
117
113
|
|
|
118
|
-
// Entrypoint should dispatch to wrapper
|
|
119
114
|
let fns = parse_fns(&gen.entrypoints);
|
|
120
115
|
let set_peer = find_fn(&fns, "set_peer").expect("set_peer entrypoint should exist");
|
|
121
116
|
let body = set_peer.block.to_token_stream().to_string();
|
|
@@ -126,29 +121,29 @@ mod tests {
|
|
|
126
121
|
}
|
|
127
122
|
|
|
128
123
|
#[test]
|
|
129
|
-
fn
|
|
130
|
-
// Override set_peer with a custom context type (not StdSetPeer)
|
|
124
|
+
fn override_with_custom_context_still_emits_default() {
|
|
125
|
+
// Override set_peer with a custom context type (not StdSetPeer).
|
|
126
|
+
// Default struct is always emitted for provided instructions, even when
|
|
127
|
+
// the override handler uses a different context type.
|
|
131
128
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
132
129
|
mod my_program {
|
|
133
130
|
#[test_instruction]
|
|
134
|
-
pub fn set_peer(ctx: Context<MyCustomAccounts>, params: SetPeerParams) -> Result<()> {
|
|
131
|
+
pub fn set_peer(ctx: &mut Context<MyCustomAccounts>, params: &SetPeerParams) -> Result<()> {
|
|
135
132
|
Ok(())
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
#[test_instruction]
|
|
139
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
136
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
140
137
|
Ok(())
|
|
141
138
|
}
|
|
142
139
|
}
|
|
143
140
|
};
|
|
144
141
|
let gen = generate_ok(&module);
|
|
145
142
|
|
|
146
|
-
// Full override should NOT emit default impl for set_peer.
|
|
147
|
-
// Other provided instructions (get_peer, token) still get their defaults.
|
|
148
143
|
let structs = parse_structs(&gen.default_impls);
|
|
149
144
|
assert!(
|
|
150
|
-
find_struct(&structs, "StdSetPeer").
|
|
151
|
-
"
|
|
145
|
+
find_struct(&structs, "StdSetPeer").is_some(),
|
|
146
|
+
"override should still emit StdSetPeer (always available)"
|
|
152
147
|
);
|
|
153
148
|
assert!(
|
|
154
149
|
find_struct(&structs, "StdGetPeer").is_some(),
|
|
@@ -156,14 +151,12 @@ mod tests {
|
|
|
156
151
|
);
|
|
157
152
|
assert!(find_struct(&structs, "StdToken").is_some(), "token should still have default");
|
|
158
153
|
|
|
159
|
-
// Entrypoint should use the custom context type
|
|
160
154
|
let fns = parse_fns(&gen.entrypoints);
|
|
161
155
|
let set_peer = find_fn(&fns, "set_peer").expect("set_peer entrypoint should exist");
|
|
162
156
|
let (is_mut, ctx_type) = first_param_context_type(set_peer);
|
|
163
157
|
assert!(is_mut, "set_peer should have `mut ctx`");
|
|
164
|
-
assert_eq!(ctx_type, "MyCustomAccounts", "
|
|
158
|
+
assert_eq!(ctx_type, "MyCustomAccounts", "override should use custom context type");
|
|
165
159
|
|
|
166
|
-
// Should dispatch to wrapper
|
|
167
160
|
let body = set_peer.block.to_token_stream().to_string();
|
|
168
161
|
assert!(
|
|
169
162
|
body.contains("__test_instruction__set_peer_handler :: set_peer"),
|
|
@@ -172,16 +165,16 @@ mod tests {
|
|
|
172
165
|
}
|
|
173
166
|
|
|
174
167
|
#[test]
|
|
175
|
-
fn
|
|
168
|
+
fn override_receives_params_by_ref() {
|
|
176
169
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
177
170
|
mod my_program {
|
|
178
171
|
#[test_instruction]
|
|
179
|
-
pub fn set_peer(ctx: Context<MyAccounts>, params: SetPeerParams) -> Result<()> {
|
|
172
|
+
pub fn set_peer(ctx: &mut Context<MyAccounts>, params: &SetPeerParams) -> Result<()> {
|
|
180
173
|
Ok(())
|
|
181
174
|
}
|
|
182
175
|
|
|
183
176
|
#[test_instruction]
|
|
184
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
177
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
185
178
|
Ok(())
|
|
186
179
|
}
|
|
187
180
|
}
|
|
@@ -190,11 +183,10 @@ mod tests {
|
|
|
190
183
|
let fns = parse_fns(&gen.entrypoints);
|
|
191
184
|
let set_peer = find_fn(&fns, "set_peer").expect("set_peer entrypoint should exist");
|
|
192
185
|
|
|
193
|
-
// Override handlers get (ctx, params) by value — no & or &mut on the call
|
|
194
186
|
let body = set_peer.block.to_token_stream().to_string();
|
|
195
187
|
assert!(
|
|
196
|
-
body.contains("set_peer (ctx , params)"),
|
|
197
|
-
"override should pass ctx and params by
|
|
188
|
+
body.contains("set_peer (& mut ctx , & params)"),
|
|
189
|
+
"override should pass ctx by &mut and params by &: {body}"
|
|
198
190
|
);
|
|
199
191
|
}
|
|
200
192
|
|
|
@@ -203,7 +195,7 @@ mod tests {
|
|
|
203
195
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
204
196
|
mod my_program {
|
|
205
197
|
#[test_instruction]
|
|
206
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
198
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
207
199
|
Ok(())
|
|
208
200
|
}
|
|
209
201
|
}
|
|
@@ -212,7 +204,6 @@ mod tests {
|
|
|
212
204
|
let fns = parse_fns(&gen.entrypoints);
|
|
213
205
|
let token = find_fn(&fns, "token").expect("token entrypoint should exist");
|
|
214
206
|
|
|
215
|
-
// Token instruction has no params — entrypoint should only have ctx
|
|
216
207
|
assert_eq!(token.sig.inputs.len(), 1, "no-params instruction should have only ctx");
|
|
217
208
|
let (is_mut, ctx_type) = first_param_context_type(token);
|
|
218
209
|
assert!(!is_mut, "token is a view — should not be mut");
|
|
@@ -224,18 +215,18 @@ mod tests {
|
|
|
224
215
|
// -----------------------------------------------------------------------
|
|
225
216
|
|
|
226
217
|
#[test]
|
|
227
|
-
fn
|
|
228
|
-
// Override get_peer (view, has params) — entrypoint
|
|
229
|
-
//
|
|
218
|
+
fn view_override_with_params_gets_immutable_ref() {
|
|
219
|
+
// Override get_peer (view, has params) — entrypoint must have immutable ctx
|
|
220
|
+
// and dispatch to wrapper with (&ctx, ¶ms).
|
|
230
221
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
231
222
|
mod my_program {
|
|
232
223
|
#[test_instruction]
|
|
233
|
-
pub fn get_peer(ctx: Context<MyGetPeerAccounts>, params: GetPeerParams) -> Result<[u8; 32]> {
|
|
224
|
+
pub fn get_peer(ctx: &Context<MyGetPeerAccounts>, params: &GetPeerParams) -> Result<[u8; 32]> {
|
|
234
225
|
Ok([0u8; 32])
|
|
235
226
|
}
|
|
236
227
|
|
|
237
228
|
#[test_instruction]
|
|
238
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
229
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
239
230
|
Ok(())
|
|
240
231
|
}
|
|
241
232
|
}
|
|
@@ -244,32 +235,29 @@ mod tests {
|
|
|
244
235
|
let fns = parse_fns(&gen.entrypoints);
|
|
245
236
|
let get_peer = find_fn(&fns, "get_peer").expect("get_peer entrypoint should exist");
|
|
246
237
|
|
|
247
|
-
// View override: ctx should NOT be mut
|
|
248
238
|
let (is_mut, ctx_type) = first_param_context_type(get_peer);
|
|
249
239
|
assert!(!is_mut, "view override should have immutable ctx");
|
|
250
240
|
assert_eq!(ctx_type, "MyGetPeerAccounts", "should use override's context type");
|
|
251
241
|
|
|
252
|
-
// Dispatches to wrapper by value
|
|
253
242
|
let body = get_peer.block.to_token_stream().to_string();
|
|
254
243
|
assert!(
|
|
255
|
-
body.contains("get_peer (ctx , params)"),
|
|
256
|
-
"view override should pass ctx and params by
|
|
244
|
+
body.contains("get_peer (& ctx , & params)"),
|
|
245
|
+
"view override should pass ctx by & and params by &: {body}"
|
|
257
246
|
);
|
|
258
247
|
}
|
|
259
248
|
|
|
260
249
|
#[test]
|
|
261
|
-
fn
|
|
262
|
-
// Override
|
|
263
|
-
// dispatch to wrapper with just `ctx` by value.
|
|
250
|
+
fn override_no_params_receives_ctx_by_ref() {
|
|
251
|
+
// Override token (no params, view) — entrypoint must dispatch with just `&ctx`.
|
|
264
252
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
265
253
|
mod my_program {
|
|
266
254
|
#[test_instruction]
|
|
267
|
-
pub fn token(ctx: Context<MyTokenAccounts>) -> Result<Pubkey> {
|
|
255
|
+
pub fn token(ctx: &Context<MyTokenAccounts>) -> Result<Pubkey> {
|
|
268
256
|
Ok(Pubkey::default())
|
|
269
257
|
}
|
|
270
258
|
|
|
271
259
|
#[test_instruction]
|
|
272
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
260
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
273
261
|
Ok(())
|
|
274
262
|
}
|
|
275
263
|
}
|
|
@@ -278,13 +266,9 @@ mod tests {
|
|
|
278
266
|
let fns = parse_fns(&gen.entrypoints);
|
|
279
267
|
let token = find_fn(&fns, "token").expect("token entrypoint should exist");
|
|
280
268
|
|
|
281
|
-
// No-params override: entrypoint has only ctx, dispatches wrapper::handler(ctx)
|
|
282
269
|
assert_eq!(token.sig.inputs.len(), 1, "no-params override should have only ctx");
|
|
283
270
|
let body = token.block.to_token_stream().to_string();
|
|
284
|
-
assert!(
|
|
285
|
-
body.contains("token (ctx)"),
|
|
286
|
-
"no-params override should pass ctx by value: {body}"
|
|
287
|
-
);
|
|
271
|
+
assert!(body.contains("token (& ctx)"), "no-params override should pass ctx by &: {body}");
|
|
288
272
|
}
|
|
289
273
|
|
|
290
274
|
#[test]
|
|
@@ -292,7 +276,7 @@ mod tests {
|
|
|
292
276
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
293
277
|
mod my_program {
|
|
294
278
|
#[test_instruction]
|
|
295
|
-
pub fn lz_receive(ctx: Context<MyReceive>, params: LzReceiveParams) -> Result<()> {
|
|
279
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
296
280
|
Ok(())
|
|
297
281
|
}
|
|
298
282
|
}
|
|
@@ -300,17 +284,15 @@ mod tests {
|
|
|
300
284
|
let gen = generate_ok(&module);
|
|
301
285
|
let fns = parse_fns(&gen.entrypoints);
|
|
302
286
|
|
|
303
|
-
//
|
|
287
|
+
// Return types come from the spec, not the override handler.
|
|
304
288
|
let get_peer = find_fn(&fns, "get_peer").expect("get_peer should exist");
|
|
305
289
|
let ret = get_peer.sig.output.to_token_stream().to_string();
|
|
306
290
|
assert!(ret.contains("[u8 ; 32]"), "get_peer return type should be [u8; 32]: {ret}");
|
|
307
291
|
|
|
308
|
-
// token returns Pubkey per spec
|
|
309
292
|
let token = find_fn(&fns, "token").expect("token should exist");
|
|
310
293
|
let ret = token.sig.output.to_token_stream().to_string();
|
|
311
294
|
assert!(ret.contains("Pubkey"), "token return type should be Pubkey: {ret}");
|
|
312
295
|
|
|
313
|
-
// set_peer returns () per spec
|
|
314
296
|
let set_peer = find_fn(&fns, "set_peer").expect("set_peer should exist");
|
|
315
297
|
let ret = set_peer.sig.output.to_token_stream().to_string();
|
|
316
298
|
assert!(ret.contains("()"), "set_peer return type should be (): {ret}");
|
|
@@ -323,8 +305,8 @@ mod tests {
|
|
|
323
305
|
mod my_program {
|
|
324
306
|
#[test_instruction]
|
|
325
307
|
pub fn lz_receive<'info>(
|
|
326
|
-
ctx: Context<'_, '_, '_, 'info, MyReceive<'info>>,
|
|
327
|
-
params: LzReceiveParams,
|
|
308
|
+
ctx: &mut Context<'_, '_, '_, 'info, MyReceive<'info>>,
|
|
309
|
+
params: &LzReceiveParams,
|
|
328
310
|
) -> Result<()> {
|
|
329
311
|
Ok(())
|
|
330
312
|
}
|
|
@@ -341,13 +323,103 @@ mod tests {
|
|
|
341
323
|
);
|
|
342
324
|
}
|
|
343
325
|
|
|
326
|
+
// -----------------------------------------------------------------------
|
|
327
|
+
// Tests — extend rules
|
|
328
|
+
// -----------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
#[test]
|
|
331
|
+
fn extend_rules_generated_for_provided_instructions() {
|
|
332
|
+
let module: syn::ItemMod = syn::parse_quote! {
|
|
333
|
+
mod my_program {
|
|
334
|
+
#[test_instruction]
|
|
335
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
336
|
+
Ok(())
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
let gen = generate_ok(&module);
|
|
341
|
+
|
|
342
|
+
let rules = gen.extend_rules.to_string();
|
|
343
|
+
assert!(
|
|
344
|
+
!rules.is_empty(),
|
|
345
|
+
"extend_rules should be non-empty when provided instructions exist"
|
|
346
|
+
);
|
|
347
|
+
assert!(rules.contains("set_peer"), "should contain a rule for set_peer");
|
|
348
|
+
assert!(rules.contains("get_peer"), "should contain a rule for get_peer");
|
|
349
|
+
assert!(rules.contains("token"), "should contain a rule for token");
|
|
350
|
+
assert!(
|
|
351
|
+
!rules.contains("lz_receive"),
|
|
352
|
+
"required instruction should NOT have an extend rule"
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
#[test]
|
|
357
|
+
fn extend_rule_contains_base_fields_and_extra_placeholder() {
|
|
358
|
+
let module: syn::ItemMod = syn::parse_quote! {
|
|
359
|
+
mod my_program {
|
|
360
|
+
#[test_instruction]
|
|
361
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
362
|
+
Ok(())
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
let gen = generate_ok(&module);
|
|
367
|
+
|
|
368
|
+
let rules = gen.extend_rules.to_string();
|
|
369
|
+
assert!(rules.contains("placeholder"), "extend rules should include base fields");
|
|
370
|
+
assert!(
|
|
371
|
+
rules.contains("extra"),
|
|
372
|
+
"extend rules should include $($extra)* for appended accounts"
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
#[test]
|
|
377
|
+
fn extend_rule_preserves_struct_attributes() {
|
|
378
|
+
let module: syn::ItemMod = syn::parse_quote! {
|
|
379
|
+
mod my_program {
|
|
380
|
+
#[test_instruction]
|
|
381
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
382
|
+
Ok(())
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
let gen = generate_ok(&module);
|
|
387
|
+
|
|
388
|
+
let rules = gen.extend_rules.to_string();
|
|
389
|
+
// Compare against the tokenized form rather than a raw string to be precise.
|
|
390
|
+
let expected = quote! { #[derive(Accounts)] }.to_string();
|
|
391
|
+
assert!(
|
|
392
|
+
rules.contains(&expected),
|
|
393
|
+
"extend rules should preserve struct attributes `{expected}`: {rules}"
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
#[test]
|
|
398
|
+
fn extend_rule_handler_uses_context_self() {
|
|
399
|
+
let module: syn::ItemMod = syn::parse_quote! {
|
|
400
|
+
mod my_program {
|
|
401
|
+
#[test_instruction]
|
|
402
|
+
pub fn lz_receive(ctx: &mut Context<MyReceive>, params: &LzReceiveParams) -> Result<()> {
|
|
403
|
+
Ok(())
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
let gen = generate_ok(&module);
|
|
408
|
+
|
|
409
|
+
let rules = gen.extend_rules.to_string();
|
|
410
|
+
assert!(
|
|
411
|
+
rules.contains("Context < Self >"),
|
|
412
|
+
"extend rule handlers must use Context<Self> so they work for any extended struct name: {rules}"
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
344
416
|
// -----------------------------------------------------------------------
|
|
345
417
|
// Tests — signature validation errors
|
|
346
418
|
// -----------------------------------------------------------------------
|
|
347
419
|
|
|
348
420
|
#[test]
|
|
349
421
|
fn error_required_instruction_missing_handler() {
|
|
350
|
-
// lz_receive is required (no default) but not overridden
|
|
422
|
+
// lz_receive is required (no default) but not overridden.
|
|
351
423
|
let module: syn::ItemMod = syn::parse_quote! {
|
|
352
424
|
mod my_program {}
|
|
353
425
|
};
|