1#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
17#[darling(rename_all = "snake_case")]
18pub enum Backend {
19 Node(Node),
22
23 #[cfg(any(test, feature = "sandbox"))]
28 RuntimeOnly(RuntimeOnly),
29}
30
31impl Default for Backend {
32 fn default() -> Self {
33 Backend::Node(Node::Auto)
34 }
35}
36
37#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
40pub enum Node {
41 #[darling(word)]
43 #[darling(skip)]
44 Auto,
45 Url(String),
47}
48
49impl Node {
50 pub fn url(&self) -> Option<String> {
55 std::env::var("CONTRACTS_NODE_URL").ok().or_else(|| {
56 match self {
57 Node::Auto => None,
58 Node::Url(url) => Some(url.clone()),
59 }
60 })
61 }
62}
63
64#[cfg(any(test, feature = "sandbox"))]
66#[derive(Clone, Eq, PartialEq, Debug, darling::FromMeta)]
67pub enum RuntimeOnly {
68 #[darling(word)]
69 #[darling(skip)]
70 Default,
71 Sandbox(syn::Path),
72}
73
74#[cfg(any(test, feature = "sandbox"))]
75impl From<RuntimeOnly> for syn::Path {
76 fn from(value: RuntimeOnly) -> Self {
77 match value {
78 RuntimeOnly::Default => syn::parse_quote! { ::ink_e2e::DefaultSandbox },
79 RuntimeOnly::Sandbox(path) => path,
80 }
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}
103
104impl E2EConfig {
105 pub fn environment(&self) -> Option<syn::Path> {
107 self.environment.clone()
108 }
109
110 pub fn features(&self) -> Vec<String> {
112 self.features.iter().map(|ls| ls.value()).collect()
113 }
114
115 pub fn backend(&self) -> Backend {
117 self.backend.clone()
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use darling::{
125 ast::NestedMeta,
126 FromMeta,
127 };
128 use quote::quote;
129
130 #[test]
131 fn config_works_backend_runtime_only() {
132 let input = quote! {
133 environment = crate::CustomEnvironment,
134 backend(runtime_only),
135 };
136 let config =
137 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
138
139 assert_eq!(
140 config.environment(),
141 Some(syn::parse_quote! { crate::CustomEnvironment })
142 );
143
144 assert_eq!(config.backend(), Backend::RuntimeOnly(RuntimeOnly::Default));
145 }
146
147 #[test]
148 #[should_panic(expected = "ErrorUnknownField")]
149 fn config_backend_runtime_only_default_not_allowed() {
150 let input = quote! {
151 backend(runtime_only(default)),
152 };
153 let config =
154 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
155
156 assert_eq!(config.backend(), Backend::RuntimeOnly(RuntimeOnly::Default));
157 }
158
159 #[test]
160 fn config_works_runtime_only_with_custom_backend() {
161 let input = quote! {
162 backend(runtime_only(sandbox = ::ink_e2e::DefaultSandbox)),
163 };
164 let config =
165 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
166
167 assert_eq!(
168 config.backend(),
169 Backend::RuntimeOnly(RuntimeOnly::Sandbox(
170 syn::parse_quote! { ::ink_e2e::DefaultSandbox }
171 ))
172 );
173 }
174
175 #[test]
176 fn config_works_backend_node() {
177 let input = quote! {
178 backend(node),
179 };
180 let config =
181 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
182
183 assert_eq!(config.backend(), Backend::Node(Node::Auto));
184
185 match config.backend() {
186 Backend::Node(node_config) => {
187 assert_eq!(node_config, Node::Auto);
188
189 temp_env::with_vars([("CONTRACTS_NODE_URL", None::<&str>)], || {
190 assert_eq!(node_config.url(), None);
191 });
192
193 temp_env::with_vars(
194 [("CONTRACTS_NODE_URL", Some("ws://127.0.0.1:9000"))],
195 || {
196 assert_eq!(
197 node_config.url(),
198 Some(String::from("ws://127.0.0.1:9000"))
199 );
200 },
201 );
202 }
203 _ => panic!("Expected Backend::Node"),
204 }
205 }
206
207 #[test]
208 #[should_panic(expected = "ErrorUnknownField")]
209 fn config_backend_node_auto_not_allowed() {
210 let input = quote! {
211 backend(node(auto)),
212 };
213 let config =
214 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
215
216 assert_eq!(config.backend(), Backend::Node(Node::Auto));
217 }
218
219 #[test]
220 fn config_works_backend_node_url() {
221 let input = quote! {
222 backend(node(url = "ws://0.0.0.0:9999")),
223 };
224 let config =
225 E2EConfig::from_list(&NestedMeta::parse_meta_list(input).unwrap()).unwrap();
226
227 match config.backend() {
228 Backend::Node(node_config) => {
229 assert_eq!(node_config, Node::Url("ws://0.0.0.0:9999".to_owned()));
230
231 temp_env::with_vars([("CONTRACTS_NODE_URL", None::<&str>)], || {
232 assert_eq!(node_config.url(), Some("ws://0.0.0.0:9999".to_owned()));
233 });
234
235 temp_env::with_vars(
236 [("CONTRACTS_NODE_URL", Some("ws://127.0.0.1:9000"))],
237 || {
238 assert_eq!(
239 node_config.url(),
240 Some(String::from("ws://127.0.0.1:9000"))
241 );
242 },
243 );
244 }
245 _ => panic!("Expected Backend::Node"),
246 }
247 }
248}