1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use darling:: {
16+ FromMeta ,
17+ ast:: NestedMeta ,
18+ } ;
19+ use proc_macro2:: TokenStream as TokenStream2 ;
20+ use syn:: {
21+ Meta ,
22+ punctuated:: Punctuated ,
23+ spanned:: Spanned ,
24+ } ;
25+
1526/// The type of the architecture that should be used to run test.
1627#[ derive( Clone , Eq , PartialEq , Debug , darling:: FromMeta ) ]
1728#[ darling( rename_all = "snake_case" ) ]
@@ -129,25 +140,123 @@ impl E2EConfig {
129140 pub fn replace_test_attr ( & self ) -> Option < String > {
130141 self . replace_test_attr . clone ( )
131142 }
143+
144+ /// Parses the attribute arguments passed to `ink_e2e::test`.
145+ pub fn from_attr_tokens ( attr : TokenStream2 ) -> Result < Self , syn:: Error > {
146+ let nested_meta = NestedMeta :: parse_meta_list ( attr) ?;
147+ Self :: from_nested_meta ( nested_meta)
148+ }
149+
150+ /// Builds the configuration from already parsed meta items.
151+ pub fn from_nested_meta ( nested_meta : Vec < NestedMeta > ) -> Result < Self , syn:: Error > {
152+ let normalized = normalize_runtime_meta ( nested_meta) ?;
153+ Self :: from_list ( & normalized) . map_err ( syn:: Error :: from)
154+ }
155+ }
156+
157+ fn normalize_runtime_meta (
158+ nested_meta : Vec < NestedMeta > ,
159+ ) -> Result < Vec < NestedMeta > , syn:: Error > {
160+ let mut args = Vec :: with_capacity ( nested_meta. len ( ) ) ;
161+ let mut runtime = None ;
162+
163+ for meta in nested_meta {
164+ if let Some ( found) = RuntimeBackendArg :: from_nested_meta ( & meta) ? {
165+ if runtime. replace ( found) . is_some ( ) {
166+ return Err ( syn:: Error :: new (
167+ meta. span ( ) ,
168+ "only a single `runtime` attribute is allowed" ,
169+ ) ) ;
170+ }
171+ continue ;
172+ }
173+ args. push ( meta) ;
174+ }
175+
176+ if let Some ( runtime) = runtime {
177+ args. push ( runtime. into_backend_meta ( ) ) ;
178+ }
179+
180+ Ok ( args)
181+ }
182+
183+ struct RuntimeBackendArg {
184+ runtime : Option < syn:: Path > ,
185+ }
186+
187+ impl RuntimeBackendArg {
188+ fn from_nested_meta ( meta : & NestedMeta ) -> Result < Option < Self > , syn:: Error > {
189+ let meta = match meta {
190+ NestedMeta :: Meta ( meta) if meta. path ( ) . is_ident ( "runtime" ) => meta,
191+ _ => return Ok ( None ) ,
192+ } ;
193+
194+ match meta {
195+ Meta :: Path ( _) => Ok ( Some ( Self { runtime : None } ) ) ,
196+ Meta :: List ( list) => {
197+ let nested: Punctuated < NestedMeta , syn:: Token ![ , ] > =
198+ list. parse_args_with ( Punctuated :: parse_terminated) ?;
199+ if nested. len ( ) != 1 {
200+ return Err ( syn:: Error :: new (
201+ list. span ( ) ,
202+ "`runtime` expects zero or one runtime type" ,
203+ ) ) ;
204+ }
205+ match nested. first ( ) . unwrap ( ) {
206+ NestedMeta :: Meta ( Meta :: Path ( path) ) => {
207+ Ok ( Some ( Self {
208+ runtime : Some ( path. clone ( ) ) ,
209+ } ) )
210+ }
211+ other => {
212+ Err ( syn:: Error :: new (
213+ other. span ( ) ,
214+ "`runtime` expects a runtime type path" ,
215+ ) )
216+ }
217+ }
218+ }
219+ Meta :: NameValue ( name_value) => {
220+ Err ( syn:: Error :: new (
221+ name_value. span ( ) ,
222+ "`runtime` does not support name-value pairs" ,
223+ ) )
224+ }
225+ }
226+ }
227+
228+ fn runtime ( & self ) -> syn:: Path {
229+ self . runtime
230+ . clone ( )
231+ . unwrap_or_else ( || syn:: parse_quote! { :: ink_runtime:: DefaultRuntime } )
232+ }
233+
234+ fn into_backend_meta ( self ) -> NestedMeta {
235+ let runtime = self . runtime ( ) ;
236+ syn:: parse_quote! {
237+ backend( runtime_only( sandbox = #runtime, client = :: ink_runtime:: RuntimeClient ) )
238+ }
239+ }
132240}
133241
134242#[ cfg( test) ]
135243mod tests {
136244 use super :: * ;
137- use darling:: {
138- FromMeta ,
139- ast:: NestedMeta ,
140- } ;
245+ use darling:: ast:: NestedMeta ;
141246 use quote:: quote;
142247
248+ fn parse_config ( input : TokenStream2 ) -> E2EConfig {
249+ let nested = NestedMeta :: parse_meta_list ( input) . unwrap ( ) ;
250+ E2EConfig :: from_nested_meta ( nested) . unwrap ( )
251+ }
252+
143253 #[ test]
144254 fn config_works_backend_runtime_only ( ) {
145255 let input = quote ! {
146256 environment = crate :: CustomEnvironment ,
147257 backend( runtime_only( sandbox = :: ink_runtime:: DefaultRuntime , client = :: ink_runtime:: RuntimeClient ) ) ,
148258 } ;
149- let config =
150- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
259+ let config = parse_config ( input) ;
151260
152261 assert_eq ! (
153262 config. environment( ) ,
@@ -169,8 +278,7 @@ mod tests {
169278 let input = quote ! {
170279 backend( runtime_only( default ) ) ,
171280 } ;
172- let config =
173- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
281+ let config = parse_config ( input) ;
174282
175283 assert_eq ! (
176284 config. backend( ) ,
@@ -186,8 +294,7 @@ mod tests {
186294 let input = quote ! {
187295 backend( runtime_only( sandbox = :: ink_runtime:: DefaultRuntime , client = :: ink_runtime:: RuntimeClient ) ) ,
188296 } ;
189- let config =
190- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
297+ let config = parse_config ( input) ;
191298
192299 assert_eq ! (
193300 config. backend( ) ,
@@ -198,13 +305,40 @@ mod tests {
198305 ) ;
199306 }
200307
308+ #[ test]
309+ fn runtime_keyword_defaults ( ) {
310+ let input = quote ! { runtime } ;
311+ let config = parse_config ( input) ;
312+
313+ assert_eq ! (
314+ config. backend( ) ,
315+ Backend :: RuntimeOnly ( RuntimeOnly {
316+ sandbox: syn:: parse_quote! { :: ink_runtime:: DefaultRuntime } ,
317+ client: syn:: parse_quote! { :: ink_runtime:: RuntimeClient } ,
318+ } )
319+ ) ;
320+ }
321+
322+ #[ test]
323+ fn runtime_keyword_custom_runtime ( ) {
324+ let input = quote ! { runtime( crate :: CustomRuntime ) } ;
325+ let config = parse_config ( input) ;
326+
327+ assert_eq ! (
328+ config. backend( ) ,
329+ Backend :: RuntimeOnly ( RuntimeOnly {
330+ sandbox: syn:: parse_quote! { crate :: CustomRuntime } ,
331+ client: syn:: parse_quote! { :: ink_runtime:: RuntimeClient } ,
332+ } )
333+ ) ;
334+ }
335+
201336 #[ test]
202337 fn config_works_backend_node ( ) {
203338 let input = quote ! {
204339 backend( node) ,
205340 } ;
206- let config =
207- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
341+ let config = parse_config ( input) ;
208342
209343 assert_eq ! ( config. backend( ) , Backend :: Node ( Node :: Auto ) ) ;
210344
@@ -236,8 +370,7 @@ mod tests {
236370 let input = quote ! {
237371 backend( node( auto) ) ,
238372 } ;
239- let config =
240- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
373+ let config = parse_config ( input) ;
241374
242375 assert_eq ! ( config. backend( ) , Backend :: Node ( Node :: Auto ) ) ;
243376 }
@@ -247,8 +380,7 @@ mod tests {
247380 let input = quote ! {
248381 backend( node( url = "ws://0.0.0.0:9999" ) ) ,
249382 } ;
250- let config =
251- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
383+ let config = parse_config ( input) ;
252384
253385 match config. backend ( ) {
254386 Backend :: Node ( node_config) => {
@@ -277,8 +409,7 @@ mod tests {
277409 let input = quote ! {
278410 replace_test_attr = "#[quickcheck]"
279411 } ;
280- let config =
281- E2EConfig :: from_list ( & NestedMeta :: parse_meta_list ( input) . unwrap ( ) ) . unwrap ( ) ;
412+ let config = parse_config ( input) ;
282413
283414 assert_eq ! ( config. replace_test_attr( ) , Some ( "#[quickcheck]" . to_owned( ) ) ) ;
284415 }
0 commit comments