graphql_tools/validation/rules/
unique_argument_names.rs1use std::collections::HashMap;
2
3use crate::parser::Pos;
4
5use super::ValidationRule;
6use crate::ast::{OperationVisitor, OperationVisitorContext};
7use crate::static_graphql::query::Value;
8use crate::validation::utils::{ValidationError, ValidationErrorContext};
9
10pub struct UniqueArgumentNames;
17
18impl Default for UniqueArgumentNames {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl UniqueArgumentNames {
25 pub fn new() -> Self {
26 UniqueArgumentNames
27 }
28}
29
30impl<'doc> OperationVisitor<'doc, ValidationErrorContext> for UniqueArgumentNames {
31 fn enter_field(
32 &mut self,
33 _: &mut OperationVisitorContext,
34 user_context: &mut ValidationErrorContext,
35 field: &crate::static_graphql::query::Field,
36 ) {
37 let found_args = collect_from_arguments(field.position, &field.arguments);
38
39 found_args.iter().for_each(|(arg_name, positions)| {
40 if positions.len() > 1 {
41 user_context.report_error(ValidationError {
42 error_code: self.error_code(),
43 message: format!("There can be only one argument named \"{}\".", arg_name),
44 locations: positions.clone(),
45 })
46 }
47 });
48 }
49
50 fn enter_directive(
51 &mut self,
52 _: &mut OperationVisitorContext,
53 user_context: &mut ValidationErrorContext,
54 directive: &crate::static_graphql::query::Directive,
55 ) {
56 let found_args = collect_from_arguments(directive.position, &directive.arguments);
57
58 found_args.iter().for_each(|(arg_name, positions)| {
59 if positions.len() > 1 {
60 user_context.report_error(ValidationError {
61 error_code: self.error_code(),
62 message: format!("There can be only one argument named \"{}\".", arg_name),
63 locations: positions.clone(),
64 })
65 }
66 });
67 }
68}
69
70fn collect_from_arguments(
71 reported_position: Pos,
72 arguments: &Vec<(String, Value)>,
73) -> HashMap<String, Vec<Pos>> {
74 let mut found_args = HashMap::<String, Vec<Pos>>::new();
75
76 for (arg_name, _arg_value) in arguments {
77 found_args
78 .entry(arg_name.clone())
79 .or_default()
80 .push(reported_position);
81 }
82
83 found_args
84}
85
86impl ValidationRule for UniqueArgumentNames {
87 fn error_code(&self) -> &'static str {
88 "UniqueArgumentNames"
89 }
90
91 fn visitor<'doc>(&self) -> super::ValidationVisitor<'doc> {
92 Box::new(UniqueArgumentNames::new())
93 }
94}
95
96#[test]
97fn no_arguments_on_field() {
98 use crate::validation::test_utils::*;
99
100 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
101 let errors = test_operation_with_schema(
102 "{
103 field
104 }",
105 TEST_SCHEMA,
106 &mut plan,
107 );
108
109 assert_eq!(get_messages(&errors).len(), 0);
110}
111
112#[test]
113fn no_arguments_on_directive() {
114 use crate::validation::test_utils::*;
115
116 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
117 let errors = test_operation_with_schema(
118 "{
119 field @directive
120 }",
121 TEST_SCHEMA,
122 &mut plan,
123 );
124
125 assert_eq!(get_messages(&errors).len(), 0);
126}
127
128#[test]
129fn argument_on_field() {
130 use crate::validation::test_utils::*;
131
132 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
133 let errors = test_operation_with_schema(
134 "{
135 field(arg: \"value\")
136 }",
137 TEST_SCHEMA,
138 &mut plan,
139 );
140
141 assert_eq!(get_messages(&errors).len(), 0);
142}
143
144#[test]
145fn argument_on_directive() {
146 use crate::validation::test_utils::*;
147
148 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
149 let errors = test_operation_with_schema(
150 "{
151 field @directive(arg: \"value\")
152 }",
153 TEST_SCHEMA,
154 &mut plan,
155 );
156
157 assert_eq!(get_messages(&errors).len(), 0);
158}
159
160#[test]
161fn same_argument_on_two_fields() {
162 use crate::validation::test_utils::*;
163
164 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
165 let errors = test_operation_with_schema(
166 "{
167 one: field(arg: \"value\")
168 two: field(arg: \"value\")
169 }",
170 TEST_SCHEMA,
171 &mut plan,
172 );
173
174 assert_eq!(get_messages(&errors).len(), 0);
175}
176
177#[test]
178fn same_argument_on_field_and_directive() {
179 use crate::validation::test_utils::*;
180
181 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
182 let errors = test_operation_with_schema(
183 "{
184 field(arg: \"value\") @directive(arg: \"value\")
185 }",
186 TEST_SCHEMA,
187 &mut plan,
188 );
189
190 assert_eq!(get_messages(&errors).len(), 0);
191}
192
193#[test]
194fn same_argument_on_two_directives() {
195 use crate::validation::test_utils::*;
196
197 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
198 let errors = test_operation_with_schema(
199 "{
200 field @directive1(arg: \"value\") @directive2(arg: \"value\")
201 }",
202 TEST_SCHEMA,
203 &mut plan,
204 );
205
206 assert_eq!(get_messages(&errors).len(), 0);
207}
208
209#[test]
210fn multiple_field_arguments() {
211 use crate::validation::test_utils::*;
212
213 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
214 let errors = test_operation_with_schema(
215 "{
216 field(arg1: \"value\", arg2: \"value\", arg3: \"value\")
217 }",
218 TEST_SCHEMA,
219 &mut plan,
220 );
221
222 assert_eq!(get_messages(&errors).len(), 0);
223}
224
225#[test]
226fn multiple_directive_argument() {
227 use crate::validation::test_utils::*;
228
229 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
230 let errors = test_operation_with_schema(
231 "{
232 field @directive(arg1: \"value\", arg2: \"value\", arg3: \"value\")
233 }",
234 TEST_SCHEMA,
235 &mut plan,
236 );
237
238 assert_eq!(get_messages(&errors).len(), 0);
239}
240
241#[test]
242fn duplicate_field_arguments() {
243 use crate::validation::test_utils::*;
244
245 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
246 let errors = test_operation_with_schema(
247 "{
248 field(arg1: \"value\", arg1: \"value\")
249 }",
250 TEST_SCHEMA,
251 &mut plan,
252 );
253
254 let messages = get_messages(&errors);
255 assert_eq!(messages.len(), 1);
256 assert_eq!(
257 messages,
258 vec!["There can be only one argument named \"arg1\"."]
259 );
260}
261
262#[test]
263fn many_duplicate_field_arguments() {
264 use crate::validation::test_utils::*;
265
266 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
267 let errors = test_operation_with_schema(
268 "{
269 field(arg1: \"value\", arg1: \"value\", arg1: \"value\")
270 }",
271 TEST_SCHEMA,
272 &mut plan,
273 );
274
275 let messages = get_messages(&errors);
276 assert_eq!(messages.len(), 1);
277 assert_eq!(
278 messages,
279 vec!["There can be only one argument named \"arg1\"."]
280 );
281}
282
283#[test]
284fn duplicate_directive_arguments() {
285 use crate::validation::test_utils::*;
286
287 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
288 let errors = test_operation_with_schema(
289 "{
290 field @directive(arg1: \"value\", arg1: \"value\")
291 }",
292 TEST_SCHEMA,
293 &mut plan,
294 );
295
296 let messages = get_messages(&errors);
297 assert_eq!(messages.len(), 1);
298 assert_eq!(
299 messages,
300 vec!["There can be only one argument named \"arg1\"."]
301 );
302}
303
304#[test]
305fn many_duplicate_directive_arguments() {
306 use crate::validation::test_utils::*;
307
308 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
309 let errors = test_operation_with_schema(
310 "{
311 field @directive(arg1: \"value\", arg1: \"value\", arg1: \"value\")
312 }",
313 TEST_SCHEMA,
314 &mut plan,
315 );
316
317 let messages = get_messages(&errors);
318 assert_eq!(messages.len(), 1);
319 assert_eq!(
320 messages,
321 vec!["There can be only one argument named \"arg1\"."]
322 );
323}