From 6cc124d075a7d3e9a3660bcdf596d19e2f9b0653 Mon Sep 17 00:00:00 2001 From: Magnus Hallin <mhallin@fastmail.com> Date: Sun, 16 Oct 2016 11:33:51 +0200 Subject: [PATCH] Add tests for the general args macro --- src/macros/args.rs | 79 +++---- src/macros/tests/args.rs | 464 +++++++++++++++++++++++++++++++++++++++ src/macros/tests/mod.rs | 1 + 3 files changed, 490 insertions(+), 54 deletions(-) create mode 100644 src/macros/tests/args.rs diff --git a/src/macros/args.rs b/src/macros/args.rs index b8afd927..a5ffcefe 100644 --- a/src/macros/args.rs +++ b/src/macros/args.rs @@ -5,16 +5,17 @@ macro_rules! __graphql__args { ( @as_expr, $e:expr) => { $e }; ( @as_pattern, $p:pat) => { $p }; - ( - @assign_arg_vars, - $args:ident, $executorvar:ident, &mut $exec:ident - ) => { - let __graphql__args!(@as_pattern, $exec) = &mut $executorvar; + ( @assign_arg_vars, $args:ident, $executorvar:ident, , $($rest:tt)* ) => { + __graphql__args!(@assign_arg_vars, $args, $executorvar, $($rest)*); + }; + + ( @assign_arg_vars, $args:ident, $executorvar:ident, ) => { + (); }; ( @assign_arg_vars, - $args:ident, $executorvar:ident, &mut $exec:ident, $($rest:tt)* + $args:ident, $executorvar:ident, &mut $exec:ident $($rest:tt)* ) => { let __graphql__args!(@as_pattern, $exec) = &mut $executorvar; __graphql__args!(@assign_arg_vars, $args, $executorvar, $($rest)*); @@ -23,7 +24,7 @@ macro_rules! __graphql__args { ( @assign_arg_vars, $args:ident, $executorvar:ident, - $name:ident : Option<$ty:ty> as $desc:expr, $($rest:tt)* + $name:ident : Option<$ty:ty> as $desc:tt $($rest:tt)* ) => { let $name: Option<$ty> = $args .get(&$crate::to_snake_case(stringify!($name))) @@ -31,16 +32,6 @@ macro_rules! __graphql__args { __graphql__args!(@assign_arg_vars, $args, $executorvar, $($rest)*); }; - ( - @assign_arg_vars, - $args:ident, $executorvar:ident, - $name:ident : Option<$ty:ty> as $desc:expr - ) => { - let $name: Option<$ty> = $args - .get(&$crate::to_snake_case(stringify!($name))) - .unwrap_or(None); - }; - ( @assign_arg_vars, $args:ident, $executorvar:ident, @@ -62,20 +53,24 @@ macro_rules! __graphql__args { .expect("Argument missing - validation must have failed"); }; - ( @assign_arg_vars, $args:ident, $executorvar:ident, ) => { - (); - }; - - ( - @apply_args, - $reg:expr, $base:expr, ( &mut executor ) - ) => { + ( @apply_args, $reg:expr, $base:expr, ( ) ) => { $base }; ( @apply_args, - $reg:expr, $base:expr, ( &mut executor , $( $rest:tt )* ) + $reg:expr, $base:expr, ( , $( $rest:tt )* ) + ) => { + __graphql__args!( + @apply_args, + $reg, + $base, + ( $($rest)* )) + }; + + ( + @apply_args, + $reg:expr, $base:expr, ( &mut executor $( $rest:tt )* ) ) => { __graphql__args!( @apply_args, @@ -102,24 +97,14 @@ macro_rules! __graphql__args { $reg, $base.argument($reg.arg_with_default::<$t>( &$crate::to_snake_case(stringify!($name)), - &__graphql__args!(@as_expr, $default))) - .description($desc), + &__graphql__args!(@as_expr, $default))), ( $($rest)* )) }; ( @apply_args, - $reg:expr, $base:expr, ( $name:ident = $default:tt : $t:ty as $desc:expr ) - ) => { - $base.argument($reg.arg_with_default::<$t>( - &$crate::to_snake_case(stringify!($name)), - &__graphql__args!(@as_expr, $default)) - .description($desc)) - }; - - ( - @apply_args, - $reg:expr, $base:expr, ( $name:ident = $default:tt : $t:ty as $desc:expr , $( $rest:tt )* ) + $reg:expr, $base:expr, + ( $name:ident = $default:tt : $t:ty as $desc:tt $( $rest:tt )* ) ) => { __graphql__args!( @apply_args, @@ -153,17 +138,7 @@ macro_rules! __graphql__args { ( @apply_args, - $reg:expr, $base:expr, ( $name:ident : $t:ty as $desc:expr ) - ) => { - $base.argument( - $reg.arg::<$t>( - &$crate::to_snake_case(stringify!($name))) - .description($desc)) - }; - - ( - @apply_args, - $reg:expr, $base:expr, ( $name:ident : $t:ty as $desc:expr , $( $rest:tt )* ) + $reg:expr, $base:expr, ( $name:ident : $t:ty as $desc:tt $( $rest:tt )* ) ) => { __graphql__args!( @apply_args, @@ -174,8 +149,4 @@ macro_rules! __graphql__args { .description($desc)), ( $($rest)* )) }; - - ( @apply_args, $reg:expr, $base:expr, ( ) ) => { - $base - }; } diff --git a/src/macros/tests/args.rs b/src/macros/tests/args.rs new file mode 100644 index 00000000..54741a95 --- /dev/null +++ b/src/macros/tests/args.rs @@ -0,0 +1,464 @@ +use std::collections::HashMap; + +use executor::FieldResult; +use value::Value; +use schema::model::RootNode; + +struct Root; + +/* + +Syntax to validate: + +* No args at all +* Executor arg vs. no executor arg +* Single arg vs. multi arg +* Trailing comma vs. no trailing comma +* Default value vs. no default value +* Description vs. no description + +*/ + +graphql_object!(Root: () as "Root" |&self| { + field simple() -> FieldResult<i64> { Ok(0) } + field exec_arg(&mut executor) -> FieldResult<i64> { Ok(0) } + field exec_arg_and_more(&mut executor, arg: i64) -> FieldResult<i64> { Ok(0) } + + field single_arg(arg: i64) -> FieldResult<i64> { Ok(0) } + field multi_args( + arg1: i64, + arg2: i64 + ) -> FieldResult<i64> { Ok(0) } + field multi_args_trailing_comma( + arg1: i64, + arg2: i64, + ) -> FieldResult<i64> { Ok(0) } + + field single_arg_descr(arg: i64 as "The arg") -> FieldResult<i64> { Ok(0) } + field multi_args_descr( + arg1: i64 as "The first arg", + arg2: i64 as "The second arg" + ) -> FieldResult<i64> { Ok(0) } + field multi_args_descr_trailing_comma( + arg1: i64 as "The first arg", + arg2: i64 as "The second arg", + ) -> FieldResult<i64> { Ok(0) } + + field arg_with_default(arg = 123: i64) -> FieldResult<i64> { Ok(0) } + field multi_args_with_default( + arg1 = 123: i64, + arg2 = 456: i64 + ) -> FieldResult<i64> { Ok(0) } + field multi_args_with_default_trailing_comma( + arg1 = 123: i64, + arg2 = 456: i64, + ) -> FieldResult<i64> { Ok(0) } + + field arg_with_default_descr(arg = 123: i64 as "The arg") -> FieldResult<i64> { Ok(0) } + field multi_args_with_default_descr( + arg1 = 123: i64 as "The first arg", + arg2 = 456: i64 as "The second arg" + ) -> FieldResult<i64> { Ok(0) } + field multi_args_with_default_trailing_comma_descr( + arg1 = 123: i64 as "The first arg", + arg2 = 456: i64 as "The second arg", + ) -> FieldResult<i64> { Ok(0) } +}); + +fn run_args_info_query<F>(field_name: &str, f: F) + where F: Fn(&Vec<Value>) -> () +{ + let doc = r#" + { + __type(name: "Root") { + fields { + name + args { + name + description + defaultValue + type { + name + ofType { + name + } + } + } + } + } + } + "#; + let schema = RootNode::new(Root {}, ()); + + let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + .expect("Execution failed"); + + assert_eq!(errs, []); + + println!("Result: {:?}", result); + + let type_info = result + .as_object_value().expect("Result is not an object") + .get("__type").expect("__type field missing") + .as_object_value().expect("__type field not an object value"); + + let fields = type_info + .get("fields").expect("fields field missing") + .as_list_value().expect("fields not a list"); + + let field = fields + .into_iter().filter( + |f| f.as_object_value().expect("Field not an object") + .get("name").expect("name field missing from field") + .as_string_value().expect("name is not a string") + == field_name) + .next().expect("Field not found") + .as_object_value().expect("Field is not an object"); + + println!("Field: {:?}", field); + + let args = field + .get("args").expect("args missing from field") + .as_list_value().expect("args is not a list"); + + println!("Args: {:?}", args); + + f(args); +} + +#[test] +fn introspect_field_simple() { + run_args_info_query("simple", |args| { + assert_eq!(args.len(), 0); + }); +} + +#[test] +fn introspect_field_exec_arg() { + run_args_info_query("execArg", |args| { + assert_eq!(args.len(), 0); + }); +} + +#[test] +fn introspect_field_exec_arg_and_more() { + run_args_info_query("execArgAndMore", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_single_arg() { + run_args_info_query("singleArg", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args() { + run_args_info_query("multiArgs", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_trailing_comma() { + run_args_info_query("multiArgsTrailingComma", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::null()), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_single_arg_descr() { + run_args_info_query("singleArgDescr", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg")), + ("description", Value::string("The arg")), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_descr() { + run_args_info_query("multiArgsDescr", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::string("The first arg")), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::string("The second arg")), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_descr_trailing_comma() { + run_args_info_query("multiArgsDescrTrailingComma", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::string("The first arg")), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::string("The second arg")), + ("defaultValue", Value::null()), + ("type", Value::object(vec![ + ("name", Value::null()), + ("ofType", Value::object(vec![ + ("name", Value::string("Int")), + ].into_iter().collect())), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_arg_with_default() { + run_args_info_query("argWithDefault", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg")), + ("description", Value::null()), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_with_default() { + run_args_info_query("multiArgsWithDefault", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::null()), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::null()), + ("defaultValue", Value::string("456")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_with_default_trailing_comma() { + run_args_info_query("multiArgsWithDefaultTrailingComma", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::null()), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::null()), + ("defaultValue", Value::string("456")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_arg_with_default_descr() { + run_args_info_query("argWithDefaultDescr", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg")), + ("description", Value::string("The arg")), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_with_default_descr() { + run_args_info_query("multiArgsWithDefaultDescr", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::string("The first arg")), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::string("The second arg")), + ("defaultValue", Value::string("456")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} + +#[test] +fn introspect_field_multi_args_with_default_trailing_comma_descr() { + run_args_info_query("multiArgsWithDefaultTrailingCommaDescr", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg1")), + ("description", Value::string("The first arg")), + ("defaultValue", Value::string("123")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + + assert!(args.contains(&Value::object(vec![ + ("name", Value::string("arg2")), + ("description", Value::string("The second arg")), + ("defaultValue", Value::string("456")), + ("type", Value::object(vec![ + ("name", Value::string("Int")), + ("ofType", Value::null()), + ].into_iter().collect())), + ].into_iter().collect()))); + }); +} diff --git a/src/macros/tests/mod.rs b/src/macros/tests/mod.rs index 96882a73..c22c674f 100644 --- a/src/macros/tests/mod.rs +++ b/src/macros/tests/mod.rs @@ -1,3 +1,4 @@ mod enums; mod scalar; #[allow(dead_code)] mod input_object; +mod args;