Skip to content

Commit d4f4c8d

Browse files
committed
Merge remote-tracking branch 'dittos/master'
2 parents 37f266b + 1f0c725 commit d4f4c8d

File tree

3 files changed

+246
-2
lines changed

3 files changed

+246
-2
lines changed

graphql/core/validation/rules.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,22 @@ def message(field_name, type):
148148

149149

150150
class UniqueFragmentNames(ValidationRule):
151-
pass
151+
def __init__(self, context):
152+
super(UniqueFragmentNames, self).__init__(context)
153+
self.known_fragment_names = {}
154+
155+
def enter_FragmentDefinition(self, node, *args):
156+
fragment_name = node.name.value
157+
if fragment_name in self.known_fragment_names:
158+
return GraphQLError(
159+
self.duplicate_fragment_name_message(fragment_name),
160+
[self.known_fragment_names[fragment_name], node.name]
161+
)
162+
self.known_fragment_names[fragment_name] = node.name
163+
164+
@staticmethod
165+
def duplicate_fragment_name_message(field):
166+
return 'There can only be one fragment named {}'.format(field)
152167

153168

154169
class KnownFragmentNames(ValidationRule):
@@ -256,7 +271,28 @@ def directive_message(arg_name, directive_name):
256271

257272

258273
class UniqueArgumentNames(ValidationRule):
259-
pass
274+
def __init__(self, context):
275+
super(UniqueArgumentNames, self).__init__(context)
276+
self.known_arg_names = {}
277+
278+
def enter_Field(self, node, *args):
279+
self.known_arg_names = {}
280+
281+
def enter_Directive(self, node, key, parent, path, ancestors):
282+
self.known_arg_names = {}
283+
284+
def enter_Argument(self, node, *args):
285+
arg_name = node.name.value
286+
if arg_name in self.known_arg_names:
287+
return GraphQLError(
288+
self.duplicate_arg_message(arg_name),
289+
[self.known_arg_names[arg_name], node.name]
290+
)
291+
self.known_arg_names[arg_name] = node.name
292+
293+
@staticmethod
294+
def duplicate_arg_message(field):
295+
return 'There can only be one argument named {}'.format(field)
260296

261297

262298
class ArgumentsOfCorrectType(ValidationRule):
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from graphql.core.language.location import SourceLocation
2+
from graphql.core.validation.rules import UniqueArgumentNames
3+
from utils import expect_passes_rule, expect_fails_rule
4+
5+
6+
def duplicate_arg(arg_name, l1, c1, l2, c2):
7+
return {
8+
'message': UniqueArgumentNames.duplicate_arg_message(arg_name),
9+
'locations': [SourceLocation(l1, c1), SourceLocation(l2, c2)]
10+
}
11+
12+
13+
def test_no_arguments_on_field():
14+
expect_passes_rule(UniqueArgumentNames, '''
15+
{
16+
field
17+
}
18+
''')
19+
20+
21+
def test_no_arguments_on_directive():
22+
expect_passes_rule(UniqueArgumentNames, '''
23+
{
24+
field
25+
}
26+
''')
27+
28+
29+
def test_argument_on_field():
30+
expect_passes_rule(UniqueArgumentNames, '''
31+
{
32+
field(arg: "value")
33+
}
34+
''')
35+
36+
37+
def test_argument_on_directive():
38+
expect_passes_rule(UniqueArgumentNames, '''
39+
{
40+
field @directive(arg: "value")
41+
}
42+
''')
43+
44+
def test_same_field_two_arguments():
45+
expect_passes_rule(UniqueArgumentNames, '''
46+
{
47+
one: field(arg: "value")
48+
two: field(arg: "value")
49+
}
50+
''')
51+
52+
def test_same_argument_on_field_and_directive():
53+
expect_passes_rule(UniqueArgumentNames, '''
54+
{
55+
field(arg: "value") @directive(arg: "value")
56+
}
57+
''')
58+
def test_same_argument_two_directives():
59+
expect_passes_rule(UniqueArgumentNames, '''
60+
{
61+
field @directive1(arg: "value") @directive2(arg: "value")
62+
}
63+
''')
64+
65+
def test_multiple_field_arguments():
66+
expect_passes_rule(UniqueArgumentNames, '''
67+
{
68+
field(arg1: "value", arg2: "value", arg3: "value")
69+
}
70+
''')
71+
72+
def test_multiple_directive_arguments():
73+
expect_passes_rule(UniqueArgumentNames, '''
74+
{
75+
field @directive(arg1: "value", arg2: "value", arg3: "value")
76+
}
77+
''')
78+
79+
def test_duplicate_field_arguments():
80+
expect_fails_rule(UniqueArgumentNames, '''
81+
{
82+
field(arg1: "value", arg1: "value")
83+
}
84+
''', [duplicate_arg('arg1', 3, 13, 3, 28)]
85+
)
86+
87+
def test_many_duplicate_field_arguments():
88+
expect_fails_rule(UniqueArgumentNames, '''
89+
{
90+
field(arg1: "value", arg1: "value", arg1: "value")
91+
}
92+
''', [
93+
duplicate_arg('arg1', 3, 13, 3, 28),
94+
duplicate_arg('arg1', 3, 13, 3, 43)
95+
])
96+
97+
def test_duplicate_directive_arguments():
98+
expect_fails_rule(UniqueArgumentNames, '''
99+
{
100+
field @directive(arg1: "value", arg1: "value")
101+
}
102+
''', [duplicate_arg('arg1', 3, 24, 3, 39)]
103+
)
104+
105+
def test_many_duplicate_directive_arguments():
106+
expect_fails_rule(UniqueArgumentNames, '''
107+
{
108+
field @directive(arg1: "value", arg1: "value", arg1: "value")
109+
}
110+
''',[
111+
duplicate_arg('arg1', 3, 24, 3, 39),
112+
duplicate_arg('arg1', 3, 24, 3, 54)
113+
])
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from graphql.core.language.location import SourceLocation
2+
from graphql.core.validation.rules import UniqueFragmentNames
3+
from utils import expect_passes_rule, expect_fails_rule
4+
5+
6+
def duplicate_fragment(fragment_name, l1, c1, l2, c2):
7+
return {
8+
'message': UniqueFragmentNames.duplicate_fragment_name_message(fragment_name),
9+
'locations': [SourceLocation(l1, c1), SourceLocation(l2, c2)]
10+
}
11+
12+
13+
def test_no_fragments():
14+
expect_passes_rule(UniqueFragmentNames, '''
15+
{
16+
field
17+
}
18+
''')
19+
20+
def test_one_fragment():
21+
expect_passes_rule(UniqueFragmentNames, '''
22+
{
23+
...fragA
24+
}
25+
fragment fragA on Type {
26+
field
27+
}
28+
''')
29+
30+
def test_many_fragments():
31+
expect_passes_rule(UniqueFragmentNames, '''
32+
{
33+
...fragA
34+
...fragB
35+
...fragC
36+
}
37+
fragment fragA on Type {
38+
fieldA
39+
}
40+
fragment fragB on Type {
41+
fieldB
42+
}
43+
fragment fragC on Type {
44+
fieldC
45+
}
46+
''')
47+
48+
def test_inline_fragments():
49+
expect_passes_rule(UniqueFragmentNames, '''
50+
{
51+
...on Type {
52+
fieldA
53+
}
54+
...on Type {
55+
fieldB
56+
}
57+
}
58+
''')
59+
60+
def test_fragment_operation_same_name():
61+
expect_passes_rule(UniqueFragmentNames, '''
62+
query Foo {
63+
...Foo
64+
}
65+
fragment Foo on Type {
66+
field
67+
}
68+
''')
69+
70+
def test_fragments_same_name():
71+
expect_fails_rule(UniqueFragmentNames, '''
72+
{
73+
...fragA
74+
}
75+
fragment fragA on Type {
76+
fieldA
77+
}
78+
fragment fragA on Type {
79+
fieldB
80+
}
81+
''', [duplicate_fragment('fragA', 5, 18, 8, 18)]
82+
)
83+
84+
def test_fragments_same_name_no_ref():
85+
expect_fails_rule(UniqueFragmentNames, '''
86+
fragment fragA on Type {
87+
fieldA
88+
}
89+
fragment fragA on Type {
90+
fieldB
91+
}
92+
''', [
93+
duplicate_fragment('fragA', 2, 18, 5, 18)
94+
]
95+
)

0 commit comments

Comments
 (0)