async_graphql/validation/rules/
unique_argument_names.rs1use std::collections::HashSet;
2
3use async_graphql_value::Value;
4
5use crate::{
6 parser::types::{Directive, Field},
7 validation::visitor::{Visitor, VisitorContext},
8 Name, Positioned,
9};
10
11#[derive(Default)]
12pub struct UniqueArgumentNames<'a> {
13 names: HashSet<&'a str>,
14}
15
16impl<'a> Visitor<'a> for UniqueArgumentNames<'a> {
17 fn enter_directive(
18 &mut self,
19 _ctx: &mut VisitorContext<'a>,
20 _directive: &'a Positioned<Directive>,
21 ) {
22 self.names.clear();
23 }
24
25 fn enter_argument(
26 &mut self,
27 ctx: &mut VisitorContext<'a>,
28 name: &'a Positioned<Name>,
29 _value: &'a Positioned<Value>,
30 ) {
31 if !self.names.insert(name.node.as_str()) {
32 ctx.report_error(
33 vec![name.pos],
34 format!("There can only be one argument named \"{}\"", name),
35 )
36 }
37 }
38
39 fn enter_field(&mut self, _ctx: &mut VisitorContext<'a>, _field: &'a Positioned<Field>) {
40 self.names.clear();
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 pub fn factory<'a>() -> UniqueArgumentNames<'a> {
49 UniqueArgumentNames::default()
50 }
51
52 #[test]
53 fn no_arguments_on_field() {
54 expect_passes_rule!(
55 factory,
56 r#"
57 {
58 field
59 }
60 "#,
61 );
62 }
63
64 #[test]
65 fn no_arguments_on_directive() {
66 expect_passes_rule!(
67 factory,
68 r#"
69 {
70 dog @directive
71 }
72 "#,
73 );
74 }
75
76 #[test]
77 fn argument_on_field() {
78 expect_passes_rule!(
79 factory,
80 r#"
81 {
82 field(arg: "value")
83 }
84 "#,
85 );
86 }
87
88 #[test]
89 fn argument_on_directive() {
90 expect_passes_rule!(
91 factory,
92 r#"
93 {
94 dog @directive(arg: "value")
95 }
96 "#,
97 );
98 }
99
100 #[test]
101 fn same_argument_on_two_fields() {
102 expect_passes_rule!(
103 factory,
104 r#"
105 {
106 one: field(arg: "value")
107 two: field(arg: "value")
108 }
109 "#,
110 );
111 }
112
113 #[test]
114 fn same_argument_on_field_and_directive() {
115 expect_passes_rule!(
116 factory,
117 r#"
118 {
119 field(arg: "value") @directive(arg: "value")
120 }
121 "#,
122 );
123 }
124
125 #[test]
126 fn same_argument_on_two_directives() {
127 expect_passes_rule!(
128 factory,
129 r#"
130 {
131 field @directive1(arg: "value") @directive2(arg: "value")
132 }
133 "#,
134 );
135 }
136
137 #[test]
138 fn multiple_field_arguments() {
139 expect_passes_rule!(
140 factory,
141 r#"
142 {
143 field(arg1: "value", arg2: "value", arg3: "value")
144 }
145 "#,
146 );
147 }
148
149 #[test]
150 fn multiple_directive_arguments() {
151 expect_passes_rule!(
152 factory,
153 r#"
154 {
155 field @directive(arg1: "value", arg2: "value", arg3: "value")
156 }
157 "#,
158 );
159 }
160
161 #[test]
162 fn duplicate_field_arguments() {
163 expect_fails_rule!(
164 factory,
165 r#"
166 {
167 field(arg1: "value", arg1: "value")
168 }
169 "#,
170 );
171 }
172
173 #[test]
174 fn many_duplicate_field_arguments() {
175 expect_fails_rule!(
176 factory,
177 r#"
178 {
179 field(arg1: "value", arg1: "value", arg1: "value")
180 }
181 "#,
182 );
183 }
184
185 #[test]
186 fn duplicate_directive_arguments() {
187 expect_fails_rule!(
188 factory,
189 r#"
190 {
191 field @directive(arg1: "value", arg1: "value")
192 }
193 "#,
194 );
195 }
196
197 #[test]
198 fn many_duplicate_directive_arguments() {
199 expect_fails_rule!(
200 factory,
201 r#"
202 {
203 field @directive(arg1: "value", arg1: "value", arg1: "value")
204 }
205 "#,
206 );
207 }
208}