1#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
17#[darling(rename_all = "snake_case")]
18pub enum Backend {
19 Node(Node),
22
23 RuntimeOnly(RuntimeOnly),
28}
29
30impl Default for Backend {
31 fn default() -> Self {
32 Backend::Node(Node::Auto)
33 }
34}
35
36#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
39pub enum Node {
40 #[darling(word)]
42 #[darling(skip)]
43 Auto,
44 Url(String),
46}
47
48impl Node {
49 pub fn url(&self) -> Option<String> {
54 let url = std::env::var("CONTRACTS_NODE_URL").ok().or_else(|| {
55 match self {
56 Node::Auto => None,
57 Node::Url(url) => Some(url.clone()),
58 }
59 });
60 tracing::debug!("[E2E] Using node url {:?}", url);
61 url
62 }
63}
64
65#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
67pub struct RuntimeOnly {
68 pub sandbox: syn::Path,
70 pub client: syn::Path,
73}
74
75impl RuntimeOnly {
76 pub fn runtime_path(&self) -> syn::Path {
77 self.sandbox.clone()
78 }
79 pub fn client_path(&self) -> syn::Path {
80 self.client.clone()
81 }
82}
83
84#[derive(Debug, Default, PartialEq, Eq, darling::FromMeta)]
86pub struct E2EConfig {
87 #[darling(default)]
94 environment: Option<syn::Path>,
95 #[darling(default)]
97 backend: Backend,
98 #[darling(default)]
101 features: Vec<syn::LitStr>,
102 #[darling(default)]
108 replace_test_attr: Option<String>,
109}
110
111impl E2EConfig {
112 pub fn environment(&self) -> Option<syn::Path> {
114 self.environment.clone()
115 }
116
117 pub fn features(&self) -> Vec<String> {
119 self.features.iter().map(|ls| ls.value()).collect()
120 }
121
122 pub fn backend(&self) -> Backend {
124 self.backend.clone()
125 }
126
127 pub fn replace_test_attr(&self) -> Option<String> {
130 self.replace_test_attr.clone()
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use darling::{
138 FromMeta,
139 ast::NestedMeta,
140 };
141 use quote::quote;
142
143 #[test]
144 fn config_works_backend_runtime_only() {
145 let input = quote! {
146 environment = crate::CustomEnvironment,
147 backend(runtime_only(sandbox = ::ink_sandbox::DefaultSandbox, client = ::ink_sandbox::SandboxClient)),
148 };
149 let config =
150 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
151
152 assert_eq!(
153 config.environment(),
154 Some(syn::parse_quote! { crate::CustomEnvironment })
155 );
156
157 assert_eq!(
158 config.backend(),
159 Backend::RuntimeOnly(RuntimeOnly {
160 sandbox: syn::parse_quote! { ::ink_sandbox::DefaultSandbox },
161 client: syn::parse_quote! { ::ink_sandbox::SandboxClient },
162 })
163 );
164 }
165
166 #[test]
167 #[should_panic(expected = "ErrorUnknownField")]
168 fn config_backend_runtime_only_default_not_allowed() {
169 let input = quote! {
170 backend(runtime_only(default)),
171 };
172 let config =
173 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
174
175 assert_eq!(
176 config.backend(),
177 Backend::RuntimeOnly(RuntimeOnly {
178 sandbox: syn::parse_quote! { ::ink_sandbox::DefaultSandbox },
179 client: syn::parse_quote! { ::ink_sandbox::SandboxClient },
180 })
181 );
182 }
183
184 #[test]
185 fn config_works_runtime_only_with_custom_backend() {
186 let input = quote! {
187 backend(runtime_only(sandbox = ::ink_sandbox::DefaultSandbox, client = ::ink_sandbox::SandboxClient)),
188 };
189 let config =
190 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
191
192 assert_eq!(
193 config.backend(),
194 Backend::RuntimeOnly(RuntimeOnly {
195 sandbox: syn::parse_quote! { ::ink_sandbox::DefaultSandbox },
196 client: syn::parse_quote! { ::ink_sandbox::SandboxClient },
197 })
198 );
199 }
200
201 #[test]
202 fn config_works_backend_node() {
203 let input = quote! {
204 backend(node),
205 };
206 let config =
207 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
208
209 assert_eq!(config.backend(), Backend::Node(Node::Auto));
210
211 match config.backend() {
212 Backend::Node(node_config) => {
213 assert_eq!(node_config, Node::Auto);
214
215 temp_env::with_vars([("CONTRACTS_NODE_URL", None::<&str>)], || {
216 assert_eq!(node_config.url(), None);
217 });
218
219 temp_env::with_vars(
220 [("CONTRACTS_NODE_URL", Some("ws://127.0.0.1:9000"))],
221 || {
222 assert_eq!(
223 node_config.url(),
224 Some(String::from("ws://127.0.0.1:9000"))
225 );
226 },
227 );
228 }
229 _ => panic!("Expected Backend::Node"),
230 }
231 }
232
233 #[test]
234 #[should_panic(expected = "ErrorUnknownField")]
235 fn config_backend_node_auto_not_allowed() {
236 let input = quote! {
237 backend(node(auto)),
238 };
239 let config =
240 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
241
242 assert_eq!(config.backend(), Backend::Node(Node::Auto));
243 }
244
245 #[test]
246 fn config_works_backend_node_url() {
247 let input = quote! {
248 backend(node(url = "ws://0.0.0.0:9999")),
249 };
250 let config =
251 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
252
253 match config.backend() {
254 Backend::Node(node_config) => {
255 assert_eq!(node_config, Node::Url("ws://0.0.0.0:9999".to_owned()));
256
257 temp_env::with_vars([("CONTRACTS_NODE_URL", None::<&str>)], || {
258 assert_eq!(node_config.url(), Some("ws://0.0.0.0:9999".to_owned()));
259 });
260
261 temp_env::with_vars(
262 [("CONTRACTS_NODE_URL", Some("ws://127.0.0.1:9000"))],
263 || {
264 assert_eq!(
265 node_config.url(),
266 Some(String::from("ws://127.0.0.1:9000"))
267 );
268 },
269 );
270 }
271 _ => panic!("Expected Backend::Node"),
272 }
273 }
274
275 #[test]
276 fn config_works_test_attr_replacement() {
277 let input = quote! {
278 replace_test_attr = "#[quickcheck]"
279 };
280 let config =
281 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
282
283 assert_eq!(config.replace_test_attr(), Some("#[quickcheck]".to_owned()));
284 }
285}