async_graphql/validation/rules/
unique_argument_names.rs

1use 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}