juniper/validation/rules/
default_values_of_correct_type.rs1use std::fmt;
2
3use crate::{
4 ast::VariableDefinition,
5 parser::Spanning,
6 types::utilities::validate_literal_value,
7 validation::{ValidatorContext, Visitor},
8 value::ScalarValue,
9};
10
11pub struct DefaultValuesOfCorrectType;
12
13pub fn factory() -> DefaultValuesOfCorrectType {
14 DefaultValuesOfCorrectType
15}
16
17impl<'a, S> Visitor<'a, S> for DefaultValuesOfCorrectType
18where
19 S: ScalarValue,
20{
21 fn enter_variable_definition(
22 &mut self,
23 ctx: &mut ValidatorContext<'a, S>,
24 (var_name, var_def): &'a (Spanning<&'a str>, VariableDefinition<S>),
25 ) {
26 if let Some(Spanning {
27 item: ref var_value,
28 ref span,
29 }) = var_def.default_value
30 {
31 if var_def.var_type.item.is_non_null() {
32 ctx.report_error(
33 &non_null_error_message(var_name.item, &var_def.var_type.item),
34 &[span.start],
35 )
36 } else {
37 let meta_type = ctx.schema.make_type(&var_def.var_type.item);
38
39 if let Some(err) = validate_literal_value(ctx.schema, &meta_type, var_value) {
40 ctx.report_error(
41 &type_error_message(var_name.item, &var_def.var_type.item, err),
42 &[span.start],
43 );
44 }
45 }
46 }
47 }
48}
49
50fn type_error_message(
51 arg_name: impl fmt::Display,
52 type_name: impl fmt::Display,
53 reason: impl fmt::Display,
54) -> String {
55 format!(
56 "Invalid default value for argument \"{arg_name}\", expected type \"{type_name}\", \
57 reason: {reason}",
58 )
59}
60
61fn non_null_error_message(arg_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
62 format!(
63 "Argument \"{arg_name}\" has type \"{type_name}\" and is not nullable, \
64 so it can't have a default value",
65 )
66}
67
68#[cfg(test)]
69mod tests {
70 use super::{factory, non_null_error_message, type_error_message};
71
72 use crate::{
73 parser::SourcePosition,
74 types::utilities::error,
75 validation::{RuleError, expect_fails_rule, expect_passes_rule},
76 value::DefaultScalarValue,
77 };
78
79 #[test]
80 fn variables_with_no_default_values() {
81 expect_passes_rule::<_, _, DefaultScalarValue>(
82 factory,
83 r#"
84 query NullableValues($a: Int, $b: String, $c: ComplexInput) {
85 dog { name }
86 }
87 "#,
88 );
89 }
90
91 #[test]
92 fn required_variables_without_default_values() {
93 expect_passes_rule::<_, _, DefaultScalarValue>(
94 factory,
95 r#"
96 query RequiredValues($a: Int!, $b: String!) {
97 dog { name }
98 }
99 "#,
100 );
101 }
102
103 #[test]
104 fn variables_with_valid_default_values() {
105 expect_passes_rule::<_, _, DefaultScalarValue>(
106 factory,
107 r#"
108 query WithDefaultValues(
109 $a: Int = 1,
110 $b: String = "ok",
111 $c: ComplexInput = { requiredField: true, intField: 3 }
112 ) {
113 dog { name }
114 }
115 "#,
116 );
117 }
118
119 #[test]
120 fn no_required_variables_with_default_values() {
121 expect_fails_rule::<_, _, DefaultScalarValue>(
122 factory,
123 r#"
124 query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") {
125 dog { name }
126 }
127 "#,
128 &[
129 RuleError::new(
130 &non_null_error_message("a", "Int!"),
131 &[SourcePosition::new(55, 1, 54)],
132 ),
133 RuleError::new(
134 &non_null_error_message("b", "String!"),
135 &[SourcePosition::new(72, 1, 71)],
136 ),
137 ],
138 );
139 }
140
141 #[test]
142 fn variables_with_invalid_default_values() {
143 expect_fails_rule::<_, _, DefaultScalarValue>(
144 factory,
145 r#"
146 query InvalidDefaultValues(
147 $a: Int = "one",
148 $b: String = 4,
149 $c: ComplexInput = "notverycomplex"
150 ) {
151 dog { name }
152 }
153 "#,
154 &[
155 RuleError::new(
156 &type_error_message("a", "Int", error::type_value("\"one\"", "Int")),
157 &[SourcePosition::new(67, 2, 26)],
158 ),
159 RuleError::new(
160 &type_error_message("b", "String", error::type_value("4", "String")),
161 &[SourcePosition::new(103, 3, 29)],
162 ),
163 RuleError::new(
164 &type_error_message(
165 "c",
166 "ComplexInput",
167 error::type_value("\"notverycomplex\"", "ComplexInput"),
168 ),
169 &[SourcePosition::new(141, 4, 35)],
170 ),
171 ],
172 );
173 }
174
175 #[test]
176 fn complex_variables_missing_required_field() {
177 expect_fails_rule::<_, _, DefaultScalarValue>(
178 factory,
179 r#"
180 query MissingRequiredField($a: ComplexInput = {intField: 3}) {
181 dog { name }
182 }
183 "#,
184 &[RuleError::new(
185 &type_error_message(
186 "a",
187 "ComplexInput",
188 error::missing_fields("ComplexInput", "\"requiredField\""),
189 ),
190 &[SourcePosition::new(59, 1, 58)],
191 )],
192 );
193 }
194
195 #[test]
196 fn list_variables_with_invalid_item() {
197 expect_fails_rule::<_, _, DefaultScalarValue>(
198 factory,
199 r#"
200 query InvalidItem($a: [String] = ["one", 2]) {
201 dog { name }
202 }
203 "#,
204 &[RuleError::new(
205 &type_error_message("a", "[String]", error::type_value("2", "String")),
206 &[SourcePosition::new(46, 1, 45)],
207 )],
208 );
209 }
210}