@layerzerolabs/common-utils-macros-stellar-contracts 0.2.122
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 +21 -0
- package/LICENSE +23 -0
- package/clippy.toml +7 -0
- package/package.json +37 -0
- package/rust-toolchain.toml +4 -0
- package/rustfmt.toml +15 -0
- package/src/auth.rs +95 -0
- package/src/contract_ttl.rs +92 -0
- package/src/error.rs +43 -0
- package/src/lib.rs +585 -0
- package/src/lz_contract.rs +105 -0
- package/src/rbac.rs +90 -0
- package/src/storage.rs +522 -0
- package/src/tests/auth.rs +230 -0
- package/src/tests/contract_ttl.rs +695 -0
- package/src/tests/error.rs +156 -0
- package/src/tests/lz_contract.rs +87 -0
- package/src/tests/mod.rs +11 -0
- package/src/tests/rbac.rs +523 -0
- package/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +31 -0
- package/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +39 -0
- package/src/tests/snapshots/common_macros__tests__auth__snapshot_only_auth_preserves_function_signature.snap +19 -0
- package/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +77 -0
- package/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contracttrait_code.snap +46 -0
- package/src/tests/snapshots/common_macros__tests__error__snapshot_generated_contract_error_code.snap +20 -0
- package/src/tests/snapshots/common_macros__tests__lz_contract__snapshot_generated_lz_contract_code.snap +51 -0
- package/src/tests/snapshots/common_macros__tests__rbac__snapshot_authorizer_role.snap +21 -0
- package/src/tests/snapshots/common_macros__tests__rbac__snapshot_preserve_function_signature.snap +21 -0
- package/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +10 -0
- package/src/tests/snapshots/common_macros__tests__ttl_extendable__snapshot_generated_ttl_extendable_code.snap +8 -0
- package/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +28 -0
- package/src/tests/storage/extract_fields.rs +87 -0
- package/src/tests/storage/gen_accessor_methods.rs +223 -0
- package/src/tests/storage/gen_args.rs +65 -0
- package/src/tests/storage/gen_enum_variant.rs +78 -0
- package/src/tests/storage/gen_key.rs +108 -0
- package/src/tests/storage/gen_params.rs +105 -0
- package/src/tests/storage/generate_storage.rs +410 -0
- package/src/tests/storage/is_primitive_type.rs +48 -0
- package/src/tests/storage/mod.rs +16 -0
- package/src/tests/storage/parse_default.rs +164 -0
- package/src/tests/storage/parse_name.rs +158 -0
- package/src/tests/storage/parse_no_ttl_extension.rs +124 -0
- package/src/tests/storage/parse_storage_type.rs +174 -0
- package/src/tests/storage/snapshots/common_macros__tests__storage__generate_storage__snapshot_generated_storage_code.snap +412 -0
- package/src/tests/storage/storage_kind.rs +39 -0
- package/src/tests/storage/test_setup.rs +25 -0
- package/src/tests/storage/validate_attrs.rs +138 -0
- package/src/tests/storage/variant_config.rs +226 -0
- package/src/tests/test_helpers.rs +87 -0
- package/src/tests/ttl_configurable.rs +34 -0
- package/src/tests/ttl_extendable.rs +32 -0
- package/src/tests/upgradeable.rs +169 -0
- package/src/tests/utils.rs +267 -0
- package/src/ttl_configurable.rs +24 -0
- package/src/ttl_extendable.rs +28 -0
- package/src/upgradeable.rs +136 -0
- package/src/utils.rs +56 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
use proc_macro2::TokenStream;
|
|
2
|
+
use quote::quote;
|
|
3
|
+
|
|
4
|
+
use crate::tests::test_helpers::{assert_panics_contains, filter_item_inputs_excluding_labels};
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// Snapshot Test: Ownable Code Generation
|
|
8
|
+
// ============================================
|
|
9
|
+
|
|
10
|
+
#[test]
|
|
11
|
+
fn snapshot_generated_ownable_code() {
|
|
12
|
+
let input = quote! {
|
|
13
|
+
pub struct MyContract;
|
|
14
|
+
};
|
|
15
|
+
let result = crate::auth::generate_ownable_impl(input);
|
|
16
|
+
let formatted = prettyplease::unparse(&syn::parse2::<syn::File>(result).expect("failed to parse generated code"));
|
|
17
|
+
|
|
18
|
+
let input = quote! {
|
|
19
|
+
#[derive(Clone, Debug)]
|
|
20
|
+
pub struct MyContract<T>
|
|
21
|
+
where
|
|
22
|
+
T: Clone,
|
|
23
|
+
{
|
|
24
|
+
pub value: T,
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
let result = crate::auth::generate_ownable_impl(input);
|
|
28
|
+
let formatted_with_generics_and_fields =
|
|
29
|
+
prettyplease::unparse(&syn::parse2::<syn::File>(result).expect("failed to parse generated code"));
|
|
30
|
+
|
|
31
|
+
let combined = format!(
|
|
32
|
+
"// === Unit struct ===\n\n{}\n\n// === Generics + fields ===\n\n{}",
|
|
33
|
+
formatted, formatted_with_generics_and_fields
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
insta::assert_snapshot!(combined);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ============================================
|
|
40
|
+
// Snapshot Test: MultiSig Code Generation
|
|
41
|
+
// ============================================
|
|
42
|
+
|
|
43
|
+
#[test]
|
|
44
|
+
fn snapshot_generated_multisig_code() {
|
|
45
|
+
let input = quote! {
|
|
46
|
+
pub struct MyContract;
|
|
47
|
+
};
|
|
48
|
+
let result = crate::auth::generate_multisig_impl(input);
|
|
49
|
+
let formatted = prettyplease::unparse(&syn::parse2::<syn::File>(result).expect("failed to parse generated code"));
|
|
50
|
+
|
|
51
|
+
let input = quote! {
|
|
52
|
+
#[derive(Copy, Clone)]
|
|
53
|
+
pub struct MyContract(pub u32);
|
|
54
|
+
};
|
|
55
|
+
let result = crate::auth::generate_multisig_impl(input);
|
|
56
|
+
let formatted_with_tuple_struct =
|
|
57
|
+
prettyplease::unparse(&syn::parse2::<syn::File>(result).expect("failed to parse generated code"));
|
|
58
|
+
|
|
59
|
+
let combined = format!(
|
|
60
|
+
"// === Unit struct ===\n\n{}\n\n// === Tuple struct ===\n\n{}",
|
|
61
|
+
formatted, formatted_with_tuple_struct
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
insta::assert_snapshot!(combined);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================
|
|
68
|
+
// Snapshot Test: Only Auth Macro
|
|
69
|
+
// ============================================
|
|
70
|
+
|
|
71
|
+
#[test]
|
|
72
|
+
fn snapshot_only_auth_preserves_function_signature() {
|
|
73
|
+
// Test with borrowed Env (&Env) - should use env directly
|
|
74
|
+
let input_borrowed = quote! {
|
|
75
|
+
pub(crate) async fn admin_action<T: Clone>(env: &Env, value: T) -> Result<T, Error> {
|
|
76
|
+
Ok(value.clone())
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
let result_borrowed = crate::auth::prepend_only_auth_check(input_borrowed);
|
|
80
|
+
let formatted_borrowed =
|
|
81
|
+
prettyplease::unparse(&syn::parse2::<syn::File>(result_borrowed).expect("failed to parse generated code"));
|
|
82
|
+
|
|
83
|
+
// Test with owned Env - should produce &env reference in the generated code
|
|
84
|
+
let input_owned = quote! {
|
|
85
|
+
pub(crate) async fn admin_action<T: Clone>(env: Env, value: T) -> Result<T, Error> {
|
|
86
|
+
Ok(value.clone())
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
let result_owned = crate::auth::prepend_only_auth_check(input_owned);
|
|
90
|
+
let formatted_owned =
|
|
91
|
+
prettyplease::unparse(&syn::parse2::<syn::File>(result_owned).expect("failed to parse generated code"));
|
|
92
|
+
|
|
93
|
+
// Combine all for single snapshot
|
|
94
|
+
let combined = format!(
|
|
95
|
+
"// === Borrowed Env (&Env) ===\n\n{}\n\n// === Owned Env (Env) ===\n\n{}",
|
|
96
|
+
formatted_borrowed, formatted_owned
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
insta::assert_snapshot!(combined);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ============================================
|
|
103
|
+
// prepend_only_auth_check Tests
|
|
104
|
+
// ============================================
|
|
105
|
+
|
|
106
|
+
/// Helper function to verify that the auth check is correctly inserted at the beginning of a function.
|
|
107
|
+
fn assert_auth_check_inserted(input: TokenStream, expected_env_ref: &str, test_name: &str) {
|
|
108
|
+
let result_tokens = crate::auth::prepend_only_auth_check(input);
|
|
109
|
+
let output_fn: syn::ItemFn =
|
|
110
|
+
syn::parse2(result_tokens).unwrap_or_else(|e| panic!("{}: failed to parse output function: {}", test_name, e));
|
|
111
|
+
|
|
112
|
+
assert!(!output_fn.block.stmts.is_empty(), "{}: function body should contain at least one statement", test_name);
|
|
113
|
+
|
|
114
|
+
let first_stmt = &output_fn.block.stmts[0];
|
|
115
|
+
let expected_stmt = format!("utils::auth::require_auth::<Self>({});", expected_env_ref);
|
|
116
|
+
let actual_stmt = quote::quote!(#first_stmt).to_string().replace(" ", "");
|
|
117
|
+
|
|
118
|
+
assert_eq!(
|
|
119
|
+
actual_stmt, expected_stmt,
|
|
120
|
+
"{}: expected auth check statement '{}', but got '{}'",
|
|
121
|
+
test_name, expected_stmt, actual_stmt
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#[test]
|
|
126
|
+
fn test_only_auth_inserts_correct_code_at_the_beginning() {
|
|
127
|
+
// (description, input, expected_env_ref)
|
|
128
|
+
// Owned Env should produce &env, reference Env should produce env directly
|
|
129
|
+
let test_cases = vec![
|
|
130
|
+
("Env by value", quote! { pub fn f(my_custom_env: Env) {} }, "&my_custom_env"),
|
|
131
|
+
("Env not first param (ref)", quote! { pub fn f(x: u32, my_custom_env: &Env) {} }, "my_custom_env"),
|
|
132
|
+
("Env after receiver", quote! { pub fn f(&self, my_custom_env: &Env) {} }, "my_custom_env"),
|
|
133
|
+
("Env after mut receiver", quote! { pub fn f(&mut self, my_custom_env: &Env) {} }, "my_custom_env"),
|
|
134
|
+
("Env after value receiver", quote! { pub fn f(self, my_custom_env: &Env) {} }, "my_custom_env"),
|
|
135
|
+
("Env after mut value receiver", quote! { pub fn f(mut self, my_custom_env: &Env) {} }, "my_custom_env"),
|
|
136
|
+
("Env with lifetime", quote! { pub fn f<'a>(my_custom_env: &'a Env) {} }, "my_custom_env"),
|
|
137
|
+
("Env with mut ref", quote! { pub fn f(my_custom_env: &mut Env) {} }, "my_custom_env"),
|
|
138
|
+
("Env with mut binding", quote! { pub fn f(mut my_custom_env: Env) {} }, "&my_custom_env"),
|
|
139
|
+
("Ref Env with mut binding", quote! { pub fn f(mut my_custom_env: &Env) {} }, "my_custom_env"),
|
|
140
|
+
(
|
|
141
|
+
"Qualified path (soroban_sdk::Env)",
|
|
142
|
+
quote! { pub fn f(my_custom_env: soroban_sdk::Env) {} },
|
|
143
|
+
"&my_custom_env",
|
|
144
|
+
),
|
|
145
|
+
("Reference to qualified path", quote! { pub fn f(my_custom_env: &soroban_sdk::Env) {} }, "my_custom_env"),
|
|
146
|
+
(
|
|
147
|
+
"Leading :: qualified path (::soroban_sdk::Env)",
|
|
148
|
+
quote! { pub fn f(my_custom_env: ::soroban_sdk::Env) {} },
|
|
149
|
+
"&my_custom_env",
|
|
150
|
+
),
|
|
151
|
+
("Leading :: ref qualified path", quote! { pub fn f(my_custom_env: &::soroban_sdk::Env) {} }, "my_custom_env"),
|
|
152
|
+
(
|
|
153
|
+
"Mut reference to qualified path",
|
|
154
|
+
quote! { pub fn f(my_custom_env: &mut soroban_sdk::Env) {} },
|
|
155
|
+
"my_custom_env",
|
|
156
|
+
),
|
|
157
|
+
("Nested reference (&&Env)", quote! { pub fn f(my_custom_env: &&Env) {} }, "my_custom_env"),
|
|
158
|
+
("Multiple Env params picks first", quote! { pub fn f(first_env: Env, second_env: Env) {} }, "&first_env"),
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
for (description, input, expected_env_ref) in test_cases {
|
|
162
|
+
assert_auth_check_inserted(input, expected_env_ref, description);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#[test]
|
|
167
|
+
fn test_only_auth_requires_env_param() {
|
|
168
|
+
// ============================================
|
|
169
|
+
// Error Cases: Missing/Invalid Env Argument Patterns
|
|
170
|
+
// ============================================
|
|
171
|
+
let cases = vec![
|
|
172
|
+
("no Env param", quote! { pub fn admin_action(value: u32) {} }),
|
|
173
|
+
// Tuple pattern destructuring is not supported - must use simple identifier
|
|
174
|
+
("tuple pattern", quote! { pub fn admin_action((env, _other): (&Env, u32)) {} }),
|
|
175
|
+
// Wildcard pattern (_) is not supported - must use named identifier
|
|
176
|
+
("wildcard pattern", quote! { pub fn admin_action(_: &Env) {} }),
|
|
177
|
+
// Struct destructuring pattern is not supported
|
|
178
|
+
("struct pattern", quote! { pub fn admin_action(Env { .. }: Env) {} }),
|
|
179
|
+
// Non-Env wrapper/container types are not recognized as Env params.
|
|
180
|
+
("Option<Env>", quote! { pub fn admin_action(env: Option<Env>) {} }),
|
|
181
|
+
("Option<&Env>", quote! { pub fn admin_action(env: Option<&Env>) {} }),
|
|
182
|
+
("Vec<Env>", quote! { pub fn admin_action(env: Vec<Env>) {} }),
|
|
183
|
+
("Box<Env>", quote! { pub fn admin_action(env: Box<Env>) {} }),
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
for (case, input) in cases {
|
|
187
|
+
assert_panics_contains(case, "function must have an Env argument", || {
|
|
188
|
+
crate::auth::prepend_only_auth_check(input.clone());
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ============================================
|
|
194
|
+
// Error Cases: only_auth macro non-function input
|
|
195
|
+
// ============================================
|
|
196
|
+
|
|
197
|
+
#[test]
|
|
198
|
+
fn test_only_auth_rejects_non_function_inputs() {
|
|
199
|
+
for (case, input) in filter_item_inputs_excluding_labels(&["function"]) {
|
|
200
|
+
assert_panics_contains(case, "failed to parse function", || {
|
|
201
|
+
crate::auth::prepend_only_auth_check(input.clone());
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============================================
|
|
207
|
+
// Error Cases: ownable macro non-struct input
|
|
208
|
+
// ============================================
|
|
209
|
+
|
|
210
|
+
#[test]
|
|
211
|
+
fn test_ownable_rejects_non_struct_inputs() {
|
|
212
|
+
for (case, input) in filter_item_inputs_excluding_labels(&["struct"]) {
|
|
213
|
+
assert_panics_contains(case, "failed to parse struct", || {
|
|
214
|
+
crate::auth::generate_ownable_impl(input.clone());
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============================================
|
|
220
|
+
// Error Cases: multisig macro non-struct input
|
|
221
|
+
// ============================================
|
|
222
|
+
|
|
223
|
+
#[test]
|
|
224
|
+
fn test_multisig_rejects_non_struct_inputs() {
|
|
225
|
+
for (case, input) in filter_item_inputs_excluding_labels(&["struct"]) {
|
|
226
|
+
assert_panics_contains(case, "failed to parse struct", || {
|
|
227
|
+
crate::auth::generate_multisig_impl(input.clone());
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|