use ast::{FromInputValue, InputValue};
use executor::Variables;
use parser::SourcePosition;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
use validation::RuleError;
use value::{Object, Value};
use GraphQLError::ValidationError;
#[derive(Debug)]
struct TestComplexScalar;
struct TestType;
graphql_scalar!(TestComplexScalar {
resolve(&self) -> Value {
Value::string("SerializedValue")
}
from_input_value(v: &InputValue) -> Option<TestComplexScalar> {
if let Some(s) = v.as_string_value() {
if s == "SerializedValue" {
return Some(TestComplexScalar);
}
}
None
}
});
#[derive(GraphQLInputObject, Debug)]
#[graphql(_internal)]
struct TestInputObject {
a: Option<String>,
b: Option<Vec<Option<String>>>,
c: String,
d: Option<TestComplexScalar>,
}
#[derive(GraphQLInputObject, Debug)]
#[graphql(_internal)]
struct TestNestedInputObject {
na: TestInputObject,
nb: String,
}
#[derive(GraphQLInputObject, Debug)]
#[graphql(_internal)]
struct ExampleInputObject {
a: Option<String>,
b: i32,
}
#[derive(GraphQLInputObject, Debug)]
#[graphql(_internal)]
struct InputWithDefaults {
#[graphql(default = "123")]
a: i32,
}
#[derive(Debug)]
enum CustomInput {
A(String),
B(String),
}
impl FromInputValue for CustomInput {
fn from_input_value(v: &InputValue) -> Option<Self> {
let obj = v.to_object_value()?;
match (obj.get("variant"), obj.get("value")) {
(Some(&&InputValue::String(ref variant)), Some(&&InputValue::String(ref value))) => {
match variant.as_str() {
"A" => Some(CustomInput::A(value.to_owned())),
"B" => Some(CustomInput::B(value.to_owned())),
_ => None,
}
}
_ => None,
}
}
}
impl ::GraphQLType for CustomInput {
type Context = ();
type TypeInfo = ();
fn name(_: &()) -> Option<&str> {
Some("CustomInput")
}
fn meta<'r>(_: &(), registry: &mut ::Registry<'r>) -> ::meta::MetaType<'r> {
let fields = &[
registry.arg::<String>("variant", &()),
registry.arg::<String>("value", &()),
];
registry
.build_input_object_type::<CustomInput>(&(), fields)
.into_meta()
}
}
graphql_object!(TestType: () |&self| {
field field_with_object_input(input: Option<TestInputObject>) -> String {
format!("{:?}", input)
}
field field_with_nullable_string_input(input: Option<String>) -> String {
format!("{:?}", input)
}
field field_with_non_nullable_string_input(input: String) -> String {
format!("{:?}", input)
}
field field_with_default_argument_value(input = ("Hello World".to_owned()): String) -> String {
format!("{:?}", input)
}
field field_with_nested_object_input(input: Option<TestNestedInputObject>) -> String {
format!("{:?}", input)
}
field list(input: Option<Vec<Option<String>>>) -> String {
format!("{:?}", input)
}
field nn_list(input: Vec<Option<String>>) -> String {
format!("{:?}", input)
}
field list_nn(input: Option<Vec<String>>) -> String {
format!("{:?}", input)
}
field nn_list_nn(input: Vec<String>) -> String {
format!("{:?}", input)
}
field example_input(arg: ExampleInputObject) -> String {
format!("a: {:?}, b: {:?}", arg.a, arg.b)
}
field input_with_defaults(arg: InputWithDefaults) -> String {
format!("a: {:?}", arg.a)
}
field input_with_custom(input: CustomInput) -> String {
format!("{:?}", input)
}
field integer_input(value: i32) -> String {
format!("value: {}", value)
}
field float_input(value: f64) -> String {
format!("value: {}", value)
}
});
fn run_variable_query<F>(query: &str, vars: Variables, f: F)
where
F: Fn(&Object) -> (),
{
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
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<F>(query: &str, f: F)
where
F: Fn(&Object) -> (),
{
run_variable_query(query, Variables::new(), f);
}
#[test]
fn inline_complex_input() {
run_query(
r#"{ fieldWithObjectInput(input: {a: "foo", b: ["bar"], c: "baz"}) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
},
);
}
#[test]
fn inline_parse_single_value_to_list() {
run_query(
r#"{ fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"}) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
},
);
}
#[test]
fn inline_runs_from_input_value_on_scalar() {
run_query(
r#"{ fieldWithObjectInput(input: {c: "baz", d: "SerializedValue"}) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#)));
},
);
}
#[test]
fn variable_valid_custom_input() {
run_variable_query(
r#"query q($input: CustomInput!) { inputWithCustom(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::object(
vec![
("variant", InputValue::string("B")),
("value", InputValue::string("whatever")),
].into_iter()
.collect(),
),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("inputWithCustom"),
Some(&Value::string(r#"B("whatever")"#))
);
},
);
}
#[test]
fn variable_invalid_custom_input() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: CustomInput!) { inputWithCustom(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::object(
vec![
("variant", InputValue::string("C")),
("value", InputValue::string("whatever")),
].into_iter()
.collect(),
),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" got invalid value. Expected input of type "CustomInput". Got: "{variant: "C", value: "whatever"}"."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn variable_complex_input() {
run_variable_query(
r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::object(
vec![
("a", InputValue::string("foo")),
("b", InputValue::list(vec![InputValue::string("bar")])),
("c", InputValue::string("baz")),
].into_iter()
.collect(),
),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
},
);
}
#[test]
fn variable_parse_single_value_to_list() {
run_variable_query(
r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::object(
vec![
("a", InputValue::string("foo")),
("b", InputValue::string("bar")),
("c", InputValue::string("baz")),
].into_iter()
.collect(),
),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
},
);
}
#[test]
fn variable_runs_from_input_value_on_scalar() {
run_variable_query(
r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::object(
vec![
("c", InputValue::string("baz")),
("d", InputValue::string("SerializedValue")),
].into_iter()
.collect(),
),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#)));
},
);
}
#[test]
fn variable_error_on_nested_non_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::object(
vec![
("a", InputValue::string("foo")),
("b", InputValue::string("bar")),
("c", InputValue::null()),
].into_iter()
.collect(),
),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" got invalid value. In field "c": Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn variable_error_on_incorrect_type() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![("input".to_owned(), InputValue::string("foo bar"))]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" got invalid value. Expected "TestInputObject", found not an object."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn variable_error_on_omit_non_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::object(
vec![
("a", InputValue::string("foo")),
("b", InputValue::string("bar")),
].into_iter()
.collect(),
),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" got invalid value. In field "c": Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn variable_multiple_errors_with_nesting() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query =
r#"query q($input: TestNestedInputObject) { fieldWithNestedObjectInput(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::object(
vec![(
"na",
InputValue::object(vec![("a", InputValue::string("foo"))].into_iter().collect()),
)].into_iter()
.collect(),
),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" got invalid value. In field "na": In field "c": Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
),
RuleError::new(
r#"Variable "$input" got invalid value. In field "nb": Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn variable_error_on_additional_field() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::object(
vec![
("a", InputValue::string("foo")),
("b", InputValue::string("bar")),
("c", InputValue::string("baz")),
("extra", InputValue::string("dog")),
].into_iter()
.collect(),
),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" got invalid value. In field "extra": Unknown field."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn allow_nullable_inputs_to_be_omitted() {
run_query(r#"{ fieldWithNullableStringInput }"#, |result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#))
);
});
}
#[test]
fn allow_nullable_inputs_to_be_omitted_in_variable() {
run_query(
r#"query q($value: String) { fieldWithNullableStringInput(input: $value) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#))
);
},
);
}
#[test]
fn allow_nullable_inputs_to_be_explicitly_null() {
run_query(
r#"{ fieldWithNullableStringInput(input: null) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#))
);
},
);
}
#[test]
fn allow_nullable_inputs_to_be_set_to_null_in_variable() {
run_variable_query(
r#"query q($value: String) { fieldWithNullableStringInput(input: $value) }"#,
vec![("value".to_owned(), InputValue::null())]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#))
);
},
);
}
#[test]
fn allow_nullable_inputs_to_be_set_to_value_in_variable() {
run_variable_query(
r#"query q($value: String) { fieldWithNullableStringInput(input: $value) }"#,
vec![("value".to_owned(), InputValue::string("a"))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"Some("a")"#))
);
},
);
}
#[test]
fn allow_nullable_inputs_to_be_set_to_value_directly() {
run_query(
r#"{ fieldWithNullableStringInput(input: "a") }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"Some("a")"#))
);
},
);
}
#[test]
fn does_not_allow_non_nullable_input_to_be_omitted_in_variable() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($value: String!) { fieldWithNonNullableStringInput(input: $value) }"#;
let vars = vec![].into_iter().collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$value" of required type "String!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn does_not_allow_non_nullable_input_to_be_set_to_null_in_variable() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($value: String!) { fieldWithNonNullableStringInput(input: $value) }"#;
let vars = vec![("value".to_owned(), InputValue::null())]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$value" of required type "String!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn allow_non_nullable_inputs_to_be_set_to_value_in_variable() {
run_variable_query(
r#"query q($value: String!) { fieldWithNonNullableStringInput(input: $value) }"#,
vec![("value".to_owned(), InputValue::string("a"))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithNonNullableStringInput"),
Some(&Value::string(r#""a""#))
);
},
);
}
#[test]
fn allow_non_nullable_inputs_to_be_set_to_value_directly() {
run_query(
r#"{ fieldWithNonNullableStringInput(input: "a") }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithNonNullableStringInput"),
Some(&Value::string(r#""a""#))
);
},
);
}
#[test]
fn allow_lists_to_be_null() {
run_variable_query(
r#"query q($input: [String]) { list(input: $input) }"#,
vec![("input".to_owned(), InputValue::null())]
.into_iter()
.collect(),
|result| {
assert_eq!(result.get_field_value("list"), Some(&Value::string(r#"None"#)));
},
);
}
#[test]
fn allow_lists_to_contain_values() {
run_variable_query(
r#"query q($input: [String]) { list(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![InputValue::string("A")]),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("list"),
Some(&Value::string(r#"Some([Some("A")])"#))
);
},
);
}
#[test]
fn allow_lists_to_contain_null() {
run_variable_query(
r#"query q($input: [String]) { list(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![
InputValue::string("A"),
InputValue::null(),
InputValue::string("B"),
]),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("list"),
Some(&Value::string(r#"Some([Some("A"), None, Some("B")])"#))
);
},
);
}
#[test]
fn does_not_allow_non_null_lists_to_be_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String]!) { nnList(input: $input) }"#;
let vars = vec![("input".to_owned(), InputValue::null())]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" of required type "[String]!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn allow_non_null_lists_to_contain_values() {
run_variable_query(
r#"query q($input: [String]!) { nnList(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![InputValue::string("A")]),
)].into_iter()
.collect(),
|result| {
assert_eq!(result.get_field_value("nnList"), Some(&Value::string(r#"[Some("A")]"#)));
},
);
}
#[test]
fn allow_non_null_lists_to_contain_null() {
run_variable_query(
r#"query q($input: [String]!) { nnList(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![
InputValue::string("A"),
InputValue::null(),
InputValue::string("B"),
]),
)].into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("nnList"),
Some(&Value::string(r#"[Some("A"), None, Some("B")]"#))
);
},
);
}
#[test]
fn allow_lists_of_non_null_to_be_null() {
run_variable_query(
r#"query q($input: [String!]) { listNn(input: $input) }"#,
vec![("input".to_owned(), InputValue::null())]
.into_iter()
.collect(),
|result| {
assert_eq!(result.get_field_value("listNn"), Some(&Value::string(r#"None"#)));
},
);
}
#[test]
fn allow_lists_of_non_null_to_contain_values() {
run_variable_query(
r#"query q($input: [String!]) { listNn(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![InputValue::string("A")]),
)].into_iter()
.collect(),
|result| {
assert_eq!(result.get_field_value("listNn"), Some(&Value::string(r#"Some(["A"])"#)));
},
);
}
#[test]
fn does_not_allow_lists_of_non_null_to_contain_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]) { listNn(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::list(vec![
InputValue::string("A"),
InputValue::null(),
InputValue::string("B"),
]),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" got invalid value. In element #1: Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn does_not_allow_non_null_lists_of_non_null_to_contain_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]!) { nnListNn(input: $input) }"#;
let vars = vec![(
"input".to_owned(),
InputValue::list(vec![
InputValue::string("A"),
InputValue::null(),
InputValue::string("B"),
]),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" got invalid value. In element #1: Expected "String!", found null."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn does_not_allow_non_null_lists_of_non_null_to_be_null() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]!) { nnListNn(input: $input) }"#;
let vars = vec![("value".to_owned(), InputValue::null())]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$input" of required type "[String!]!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn allow_non_null_lists_of_non_null_to_contain_values() {
run_variable_query(
r#"query q($input: [String!]!) { nnListNn(input: $input) }"#,
vec![(
"input".to_owned(),
InputValue::list(vec![InputValue::string("A")]),
)].into_iter()
.collect(),
|result| {
assert_eq!(result.get_field_value("nnListNn"), Some(&Value::string(r#"["A"]"#)));
},
);
}
#[test]
fn does_not_allow_invalid_types_to_be_used_as_values() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestType!) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![(
"value".to_owned(),
InputValue::list(vec![InputValue::string("A"), InputValue::string("B")]),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" expected value of type "TestType!" which cannot be used as an input type."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn does_not_allow_unknown_types_to_be_used_as_values() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: UnknownType!) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![(
"value".to_owned(),
InputValue::list(vec![InputValue::string("A"), InputValue::string("B")]),
)].into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(error, ValidationError(vec![
RuleError::new(
r#"Variable "$input" expected value of type "UnknownType!" which cannot be used as an input type."#,
&[SourcePosition::new(8, 0, 8)],
),
]));
}
#[test]
fn default_argument_when_not_provided() {
run_query(r#"{ fieldWithDefaultArgumentValue }"#, |result| {
assert_eq!(
result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#))
);
});
}
#[test]
fn default_argument_when_nullable_variable_not_provided() {
run_query(
r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#,
|result| {
assert_eq!(
result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#))
);
},
);
}
#[test]
fn default_argument_when_nullable_variable_set_to_null() {
run_variable_query(
r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#,
vec![("input".to_owned(), InputValue::null())]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#))
);
},
);
}
#[test]
fn nullable_input_object_arguments_successful_without_variables() {
run_query(r#"{ exampleInput(arg: {a: "abc", b: 123}) }"#, |result| {
assert_eq!(
result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: Some("abc"), b: 123"#))
);
});
run_query(r#"{ exampleInput(arg: {a: null, b: 1}) }"#, |result| {
assert_eq!(
result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#))
);
});
}
#[test]
fn nullable_input_object_arguments_successful_with_variables() {
run_variable_query(
r#"query q($var: Int!) { exampleInput(arg: {b: $var}) }"#,
vec![("var".to_owned(), InputValue::int(123))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 123"#))
);
},
);
run_variable_query(
r#"query q($var: String) { exampleInput(arg: {a: $var, b: 1}) }"#,
vec![("var".to_owned(), InputValue::null())]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#))
);
},
);
run_variable_query(
r#"query q($var: String) { exampleInput(arg: {a: $var, b: 1}) }"#,
vec![].into_iter().collect(),
|result| {
assert_eq!(
result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#))
);
},
);
}
#[test]
fn does_not_allow_missing_required_field() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"{ exampleInput(arg: {a: "abc"}) }"#;
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 "arg", expected type "ExampleInputObject!""#,
&[SourcePosition::new(20, 0, 20)],
)])
);
}
#[test]
fn does_not_allow_null_in_required_field() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"{ exampleInput(arg: {a: "abc", b: null}) }"#;
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 "arg", expected type "ExampleInputObject!""#,
&[SourcePosition::new(20, 0, 20)],
)])
);
}
#[test]
fn does_not_allow_missing_variable_for_required_field() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($var: Int!) { exampleInput(arg: {b: $var}) }"#;
let vars = vec![].into_iter().collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$var" of required type "Int!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn does_not_allow_null_variable_for_required_field() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($var: Int!) { exampleInput(arg: {b: $var}) }"#;
let vars = vec![("var".to_owned(), InputValue::null())]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$var" of required type "Int!" was not provided."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn input_object_with_default_values() {
run_query(r#"{ inputWithDefaults(arg: {a: 1}) }"#, |result| {
assert_eq!(
result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#))
);
});
run_variable_query(
r#"query q($var: Int!) { inputWithDefaults(arg: {a: $var}) }"#,
vec![("var".to_owned(), InputValue::int(1))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#))
);
},
);
run_variable_query(
r#"query q($var: Int = 1) { inputWithDefaults(arg: {a: $var}) }"#,
vec![].into_iter().collect(),
|result| {
assert_eq!(
result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#))
);
},
);
run_variable_query(
r#"query q($var: Int = 1) { inputWithDefaults(arg: {a: $var}) }"#,
vec![("var".to_owned(), InputValue::int(2))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 2"#))
);
},
);
}
mod integers {
use super::*;
#[test]
fn positive_and_negative_should_work() {
run_variable_query(
r#"query q($var: Int!) { integerInput(value: $var) }"#,
vec![("var".to_owned(), InputValue::int(1))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("integerInput"),
Some(&Value::string(r#"value: 1"#))
);
},
);
run_variable_query(
r#"query q($var: Int!) { integerInput(value: $var) }"#,
vec![("var".to_owned(), InputValue::int(-1))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("integerInput"),
Some(&Value::string(r#"value: -1"#))
);
},
);
}
#[test]
fn does_not_coerce_from_float() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($var: Int!) { integerInput(value: $var) }"#;
let vars = vec![("var".to_owned(), InputValue::float(10.0))]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$var" got invalid value. Expected "Int"."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
#[test]
fn does_not_coerce_from_string() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($var: Int!) { integerInput(value: $var) }"#;
let vars = vec![("var".to_owned(), InputValue::string("10"))]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$var" got invalid value. Expected "Int"."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
}
mod floats {
use super::*;
#[test]
fn float_values_should_work() {
run_variable_query(
r#"query q($var: Float!) { floatInput(value: $var) }"#,
vec![("var".to_owned(), InputValue::float(10.0))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("floatInput"),
Some(&Value::string(r#"value: 10"#))
);
},
);
}
#[test]
fn coercion_from_integers_should_work() {
run_variable_query(
r#"query q($var: Float!) { floatInput(value: $var) }"#,
vec![("var".to_owned(), InputValue::int(-1))]
.into_iter()
.collect(),
|result| {
assert_eq!(
result.get_field_value("floatInput"),
Some(&Value::string(r#"value: -1"#))
);
},
);
}
#[test]
fn does_not_coerce_from_string() {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($var: Float!) { floatInput(value: $var) }"#;
let vars = vec![("var".to_owned(), InputValue::string("10"))]
.into_iter()
.collect();
let error = ::execute(query, None, &schema, &vars, &()).unwrap_err();
assert_eq!(
error,
ValidationError(vec![RuleError::new(
r#"Variable "$var" got invalid value. Expected "Float"."#,
&[SourcePosition::new(8, 0, 8)],
)])
);
}
}