From 478c7b781942599a98dc3cd27de50c40105927f3 Mon Sep 17 00:00:00 2001 From: Magnus Hallin Date: Sat, 12 Nov 2016 10:24:23 +0100 Subject: [PATCH] Add enum input value tests and improve validation --- src/executor_tests/enums.rs | 146 ++++++++++++++++++++++++++++++++++ src/executor_tests/mod.rs | 1 + src/validation/input_value.rs | 12 ++- 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/executor_tests/enums.rs diff --git a/src/executor_tests/enums.rs b/src/executor_tests/enums.rs new file mode 100644 index 00000000..effca654 --- /dev/null +++ b/src/executor_tests/enums.rs @@ -0,0 +1,146 @@ +use std::collections::HashMap; + +use value::Value; +use ast::InputValue; +use schema::model::RootNode; +use ::GraphQLError::ValidationError; +use validation::RuleError; +use parser::SourcePosition; + +#[derive(Debug)] +enum Color { Red, Green, Blue } +struct TestType; + +graphql_enum!(Color { + Color::Red => "RED", + Color::Green => "GREEN", + Color::Blue => "BLUE", +}); + +graphql_object!(TestType: () |&self| { + field to_string(color: Color) -> String { + format!("Color::{:?}", color) + } + + field a_color() -> Color { + Color::Red + } +}); + +fn run_variable_query(query: &str, vars: HashMap, f: F) + where F: Fn(&HashMap) -> () +{ + let schema = RootNode::new(TestType, ()); + + let (result, errs) = ::execute(query, None, &schema, &vars, &()) + .expect("Execution failed"); + + assert_eq!(errs, []); + + println!("Result: {:?}", result); + + let obj = result.as_object_value().expect("Result is not an object"); + + f(obj); +} + +fn run_query(query: &str, f: F) + where F: Fn(&HashMap) -> () +{ + run_variable_query(query, HashMap::new(), f); +} + +#[test] +fn accepts_enum_literal() { + run_query( + "{ toString(color: RED) }", + |result| { + assert_eq!( + result.get("toString"), + Some(&Value::string("Color::Red"))); + }); +} + +#[test] +fn serializes_as_output() { + run_query( + "{ aColor }", + |result| { + assert_eq!( + result.get("aColor"), + Some(&Value::string("RED"))); + }); +} + +#[test] +fn does_not_accept_string_literals() { + let schema = RootNode::new(TestType, ()); + + let query = r#"{ toString(color: "RED") }"#; + let vars = vec![ + ].into_iter().collect(); + + let error = ::execute(query, None, &schema, &vars, &()) + .unwrap_err(); + + assert_eq!(error, ValidationError(vec![ + RuleError::new( + r#"Invalid value for argument "color", expected type "Color!""#, + &[SourcePosition::new(18, 0, 18)], + ), + ])); +} + +#[test] +fn accepts_strings_in_variables() { + run_variable_query( + "{ toString(color: RED) }", + vec![ + ("color".to_owned(), InputValue::string("RED")), + ].into_iter().collect(), + |result| { + assert_eq!( + result.get("toString"), + Some(&Value::string("Color::Red"))); + }); +} + +#[test] +fn does_not_accept_incorrect_enum_name_in_variables() { + let schema = RootNode::new(TestType, ()); + + let query = r#"query q($color: Color!) { toString(color: $color) }"#; + let vars = vec![ + ("color".to_owned(), InputValue::string("BLURPLE")), + ].into_iter().collect(); + + let error = ::execute(query, None, &schema, &vars, &()) + .unwrap_err(); + + assert_eq!(error, ValidationError(vec![ + RuleError::new( + r#"Variable "$color" got invalid value. Invalid value for enum "Color"."#, + &[SourcePosition::new(8, 0, 8)], + ), + ])); +} + +#[test] +fn does_not_accept_incorrect_type_in_variables() { + let schema = RootNode::new(TestType, ()); + + let query = r#"query q($color: Color!) { toString(color: $color) }"#; + let vars = vec![ + ("color".to_owned(), InputValue::int(123)), + ].into_iter().collect(); + + let error = ::execute(query, None, &schema, &vars, &()) + .unwrap_err(); + + assert_eq!(error, ValidationError(vec![ + RuleError::new( + r#"Variable "$color" got invalid value. Expected "Color", found not a string or enum."#, + &[SourcePosition::new(8, 0, 8)], + ), + ])); +} diff --git a/src/executor_tests/mod.rs b/src/executor_tests/mod.rs index 391693c2..c3a93d1f 100644 --- a/src/executor_tests/mod.rs +++ b/src/executor_tests/mod.rs @@ -1,2 +1,3 @@ mod introspection; mod variables; +mod enums; diff --git a/src/validation/input_value.rs b/src/validation/input_value.rs index 5413a9ab..456523f2 100644 --- a/src/validation/input_value.rs +++ b/src/validation/input_value.rs @@ -162,7 +162,17 @@ fn unify_enum<'a>( path: &Path<'a>, ) { match value { - &InputValue::String(_) | &InputValue::Enum(_) => (), + &InputValue::String(ref name) | &InputValue::Enum(ref name) => { + if !meta.values.iter().any(|ev| &ev.name == name) { + push_unification_error( + errors, + var_name, + var_pos, + path, + &format!(r#"Invalid value for enum "{}""#, meta.name), + ) + } + } _ => push_unification_error( errors, var_name,