Skip to content

Commit 05321fe

Browse files
committed
Merge pull request #20 from rawls238/guy_unique_frag_names
Add UniqueFragmentNames validation + tests
2 parents 060315c + 463d662 commit 05321fe

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

graphql/core/validation/rules.py

Lines changed: 16 additions & 1 deletion
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):
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)