graphql_tools/validation/rules/
unique_argument_names.rs1use std::collections::HashMap;
2
3use crate::parser::Pos;
4
5use super::ValidationRule;
6use crate::ast::{visit_document, 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<'a> OperationVisitor<'a, 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<'a>(&self) -> &'a str {
88 "UniqueArgumentNames"
89 }
90
91 fn validate(
92 &self,
93 ctx: &mut OperationVisitorContext,
94 error_collector: &mut ValidationErrorContext,
95 ) {
96 visit_document(
97 &mut UniqueArgumentNames::new(),
98 ctx.operation,
99 ctx,
100 error_collector,
101 );
102 }
103}
104
105#[test]
106fn no_arguments_on_field() {
107 use crate::validation::test_utils::*;
108
109 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
110 let errors = test_operation_with_schema(
111 "{
112 field
113 }",
114 TEST_SCHEMA,
115 &mut plan,
116 );
117
118 assert_eq!(get_messages(&errors).len(), 0);
119}
120
121#[test]
122fn no_arguments_on_directive() {
123 use crate::validation::test_utils::*;
124
125 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
126 let errors = test_operation_with_schema(
127 "{
128 field @directive
129 }",
130 TEST_SCHEMA,
131 &mut plan,
132 );
133
134 assert_eq!(get_messages(&errors).len(), 0);
135}
136
137#[test]
138fn argument_on_field() {
139 use crate::validation::test_utils::*;
140
141 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
142 let errors = test_operation_with_schema(
143 "{
144 field(arg: \"value\")
145 }",
146 TEST_SCHEMA,
147 &mut plan,
148 );
149
150 assert_eq!(get_messages(&errors).len(), 0);
151}
152
153#[test]
154fn argument_on_directive() {
155 use crate::validation::test_utils::*;
156
157 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
158 let errors = test_operation_with_schema(
159 "{
160 field @directive(arg: \"value\")
161 }",
162 TEST_SCHEMA,
163 &mut plan,
164 );
165
166 assert_eq!(get_messages(&errors).len(), 0);
167}
168
169#[test]
170fn same_argument_on_two_fields() {
171 use crate::validation::test_utils::*;
172
173 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
174 let errors = test_operation_with_schema(
175 "{
176 one: field(arg: \"value\")
177 two: field(arg: \"value\")
178 }",
179 TEST_SCHEMA,
180 &mut plan,
181 );
182
183 assert_eq!(get_messages(&errors).len(), 0);
184}
185
186#[test]
187fn same_argument_on_field_and_directive() {
188 use crate::validation::test_utils::*;
189
190 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
191 let errors = test_operation_with_schema(
192 "{
193 field(arg: \"value\") @directive(arg: \"value\")
194 }",
195 TEST_SCHEMA,
196 &mut plan,
197 );
198
199 assert_eq!(get_messages(&errors).len(), 0);
200}
201
202#[test]
203fn same_argument_on_two_directives() {
204 use crate::validation::test_utils::*;
205
206 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
207 let errors = test_operation_with_schema(
208 "{
209 field @directive1(arg: \"value\") @directive2(arg: \"value\")
210 }",
211 TEST_SCHEMA,
212 &mut plan,
213 );
214
215 assert_eq!(get_messages(&errors).len(), 0);
216}
217
218#[test]
219fn multiple_field_arguments() {
220 use crate::validation::test_utils::*;
221
222 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
223 let errors = test_operation_with_schema(
224 "{
225 field(arg1: \"value\", arg2: \"value\", arg3: \"value\")
226 }",
227 TEST_SCHEMA,
228 &mut plan,
229 );
230
231 assert_eq!(get_messages(&errors).len(), 0);
232}
233
234#[test]
235fn multiple_directive_argument() {
236 use crate::validation::test_utils::*;
237
238 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
239 let errors = test_operation_with_schema(
240 "{
241 field @directive(arg1: \"value\", arg2: \"value\", arg3: \"value\")
242 }",
243 TEST_SCHEMA,
244 &mut plan,
245 );
246
247 assert_eq!(get_messages(&errors).len(), 0);
248}
249
250#[test]
251fn duplicate_field_arguments() {
252 use crate::validation::test_utils::*;
253
254 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
255 let errors = test_operation_with_schema(
256 "{
257 field(arg1: \"value\", arg1: \"value\")
258 }",
259 TEST_SCHEMA,
260 &mut plan,
261 );
262
263 let messages = get_messages(&errors);
264 assert_eq!(messages.len(), 1);
265 assert_eq!(
266 messages,
267 vec!["There can be only one argument named \"arg1\"."]
268 );
269}
270
271#[test]
272fn many_duplicate_field_arguments() {
273 use crate::validation::test_utils::*;
274
275 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
276 let errors = test_operation_with_schema(
277 "{
278 field(arg1: \"value\", arg1: \"value\", arg1: \"value\")
279 }",
280 TEST_SCHEMA,
281 &mut plan,
282 );
283
284 let messages = get_messages(&errors);
285 assert_eq!(messages.len(), 1);
286 assert_eq!(
287 messages,
288 vec!["There can be only one argument named \"arg1\"."]
289 );
290}
291
292#[test]
293fn duplicate_directive_arguments() {
294 use crate::validation::test_utils::*;
295
296 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
297 let errors = test_operation_with_schema(
298 "{
299 field @directive(arg1: \"value\", arg1: \"value\")
300 }",
301 TEST_SCHEMA,
302 &mut plan,
303 );
304
305 let messages = get_messages(&errors);
306 assert_eq!(messages.len(), 1);
307 assert_eq!(
308 messages,
309 vec!["There can be only one argument named \"arg1\"."]
310 );
311}
312
313#[test]
314fn many_duplicate_directive_arguments() {
315 use crate::validation::test_utils::*;
316
317 let mut plan = create_plan_from_rule(Box::new(UniqueArgumentNames {}));
318 let errors = test_operation_with_schema(
319 "{
320 field @directive(arg1: \"value\", arg1: \"value\", arg1: \"value\")
321 }",
322 TEST_SCHEMA,
323 &mut plan,
324 );
325
326 let messages = get_messages(&errors);
327 assert_eq!(messages.len(), 1);
328 assert_eq!(
329 messages,
330 vec!["There can be only one argument named \"arg1\"."]
331 );
332}