Skip to content

Commit 8a48871

Browse files
committed
Fix tests to use proper AST node construction
Tests were using incomplete node construction that relied on default None values. This change makes tests more representative in preparation for non-nullable required fields.
1 parent c63ef1d commit 8a48871

File tree

6 files changed

+135
-73
lines changed

6 files changed

+135
-73
lines changed

tests/error/test_graphql_error.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from graphql.error import GraphQLError
66
from graphql.language import (
7-
Node,
7+
NameNode,
88
ObjectTypeDefinitionNode,
99
OperationDefinitionNode,
1010
Source,
@@ -352,7 +352,7 @@ def formats_graphql_error():
352352
extensions = {"ext": None}
353353
error = GraphQLError(
354354
"test message",
355-
Node(),
355+
NameNode(value="stub"),
356356
Source(
357357
"""
358358
query {

tests/language/test_ast.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@
1010
class SampleTestNode(Node):
1111
__slots__ = "alpha", "beta"
1212

13-
alpha: int
14-
beta: int
13+
alpha: int | Node # Union with Node to support copy tests with nested nodes
14+
beta: int | Node | None
1515

1616

1717
class SampleNamedNode(Node):
1818
__slots__ = "foo", "name"
1919

2020
foo: str
21-
name: str | None
21+
name: NameNode | None
22+
23+
24+
def make_loc(start: int = 1, end: int = 3) -> Location:
25+
"""Create a Location for testing with the given start/end offsets."""
26+
source = Source("test source")
27+
start_token = Token(TokenKind.NAME, start, end, 1, start, "test")
28+
return Location(start_token, start_token, source)
2229

2330

2431
def describe_token_class():
@@ -150,15 +157,21 @@ def can_hash():
150157

151158
def describe_node_class():
152159
def initializes_with_keywords():
153-
node = SampleTestNode(alpha=1, beta=2, loc=0)
160+
node = SampleTestNode(alpha=1, beta=2)
154161
assert node.alpha == 1
155162
assert node.beta == 2
156-
assert node.loc == 0
157-
node = SampleTestNode(alpha=1, loc=None)
158163
assert node.loc is None
164+
165+
def initializes_with_location():
166+
loc = make_loc()
167+
node = SampleTestNode(alpha=1, beta=2, loc=loc)
159168
assert node.alpha == 1
160-
assert node.beta is None
161-
node = SampleTestNode(alpha=1, beta=2, gamma=3)
169+
assert node.beta == 2
170+
assert node.loc is loc
171+
172+
def initializes_with_none_location():
173+
node = SampleTestNode(alpha=1, beta=2, loc=None)
174+
assert node.loc is None
162175
assert node.alpha == 1
163176
assert node.beta == 2
164177
assert not hasattr(node, "gamma")
@@ -174,27 +187,31 @@ def converts_list_to_tuple_on_init():
174187
def has_representation_with_loc():
175188
node = SampleTestNode(alpha=1, beta=2)
176189
assert repr(node) == "SampleTestNode"
177-
node = SampleTestNode(alpha=1, beta=2, loc=3)
178-
assert repr(node) == "SampleTestNode at 3"
190+
loc = make_loc(start=3, end=5)
191+
node = SampleTestNode(alpha=1, beta=2, loc=loc)
192+
assert repr(node) == "SampleTestNode at 3:5"
179193

180194
def has_representation_when_named():
181195
name_node = NameNode(value="baz")
182196
node = SampleNamedNode(foo="bar", name=name_node)
183197
assert repr(node) == "SampleNamedNode(name='baz')"
184-
node = SampleNamedNode(alpha=1, beta=2, name=name_node, loc=3)
185-
assert repr(node) == "SampleNamedNode(name='baz') at 3"
198+
loc = make_loc(start=3, end=5)
199+
node = SampleNamedNode(foo="bar", name=name_node, loc=loc)
200+
assert repr(node) == "SampleNamedNode(name='baz') at 3:5"
186201

187202
def has_representation_when_named_but_name_is_none():
188-
node = SampleNamedNode(alpha=1, beta=2, name=None)
203+
node = SampleNamedNode(foo="bar", name=None)
189204
assert repr(node) == "SampleNamedNode"
190-
node = SampleNamedNode(alpha=1, beta=2, name=None, loc=3)
191-
assert repr(node) == "SampleNamedNode at 3"
205+
loc = make_loc(start=3, end=5)
206+
node = SampleNamedNode(foo="bar", name=None, loc=loc)
207+
assert repr(node) == "SampleNamedNode at 3:5"
192208

193209
def has_special_representation_when_it_is_a_name_node():
194210
node = NameNode(value="foo")
195211
assert repr(node) == "NameNode('foo')"
196-
node = NameNode(value="foo", loc=3)
197-
assert repr(node) == "NameNode('foo') at 3"
212+
loc = make_loc(start=3, end=5)
213+
node = NameNode(value="foo", loc=loc)
214+
assert repr(node) == "NameNode('foo') at 3:5"
198215

199216
def can_check_equality():
200217
node = SampleTestNode(alpha=1, beta=2)

tests/language/test_schema_parser.py

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import pickle
44
from copy import deepcopy
55
from textwrap import dedent
6-
from typing import Optional, Tuple
76

87
import pytest
98

@@ -22,6 +21,7 @@
2221
InterfaceTypeDefinitionNode,
2322
InterfaceTypeExtensionNode,
2423
ListTypeNode,
24+
Location,
2525
NamedTypeNode,
2626
NameNode,
2727
NonNullTypeNode,
@@ -32,7 +32,10 @@
3232
ScalarTypeDefinitionNode,
3333
SchemaDefinitionNode,
3434
SchemaExtensionNode,
35+
Source,
3536
StringValueNode,
37+
Token,
38+
TokenKind,
3639
TypeNode,
3740
UnionTypeDefinitionNode,
3841
ValueNode,
@@ -41,16 +44,19 @@
4144

4245
from ..fixtures import kitchen_sink_sdl # noqa: F401
4346

44-
try:
45-
from typing import TypeAlias
46-
except ImportError: # Python < 3.10
47-
from typing_extensions import TypeAlias
4847

49-
50-
Location: TypeAlias = Optional[Tuple[int, int]]
48+
def make_loc(position: tuple[int, int]) -> Location:
49+
"""Create a Location for testing with the given (start, end) offsets."""
50+
source = Source(body="")
51+
token = Token(
52+
kind=TokenKind.NAME, start=position[0], end=position[1], line=1, column=1
53+
)
54+
return Location(start_token=token, end_token=token, source=source)
5155

5256

53-
def assert_syntax_error(text: str, message: str, location: Location) -> None:
57+
def assert_syntax_error(
58+
text: str, message: str, location: tuple[int, int] | None
59+
) -> None:
5460
with pytest.raises(GraphQLSyntaxError) as exc_info:
5561
parse(text)
5662
error = exc_info.value
@@ -59,85 +65,104 @@ def assert_syntax_error(text: str, message: str, location: Location) -> None:
5965
assert error.locations == [location]
6066

6167

62-
def assert_definitions(body: str, loc: Location, num=1):
68+
def assert_definitions(body: str, position: tuple[int, int] | None, num: int = 1):
6369
doc = parse(body)
6470
assert isinstance(doc, DocumentNode)
65-
assert doc.loc == loc
71+
assert doc.loc == position
6672
definitions = doc.definitions
6773
assert isinstance(definitions, tuple)
6874
assert len(definitions) == num
6975
return definitions[0] if num == 1 else definitions
7076

7177

72-
def type_node(name: str, loc: Location):
73-
return NamedTypeNode(name=name_node(name, loc), loc=loc)
78+
def type_node(name: str, position: tuple[int, int]):
79+
return NamedTypeNode(name=name_node(name, position), loc=make_loc(position))
7480

7581

76-
def name_node(name: str, loc: Location):
77-
return NameNode(value=name, loc=loc)
82+
def name_node(name: str, position: tuple[int, int]):
83+
return NameNode(value=name, loc=make_loc(position))
7884

7985

80-
def field_node(name: NameNode, type_: TypeNode, loc: Location):
81-
return field_node_with_args(name, type_, (), loc)
86+
def field_node(name: NameNode, type_: TypeNode, position: tuple[int, int]):
87+
return field_node_with_args(name, type_, (), position)
8288

8389

84-
def field_node_with_args(name: NameNode, type_: TypeNode, args: tuple, loc: Location):
90+
def field_node_with_args(
91+
name: NameNode, type_: TypeNode, args: tuple, position: tuple[int, int]
92+
):
8593
return FieldDefinitionNode(
86-
name=name, arguments=args, type=type_, directives=(), loc=loc, description=None
94+
name=name,
95+
arguments=args,
96+
type=type_,
97+
directives=(),
98+
loc=make_loc(position),
99+
description=None,
87100
)
88101

89102

90-
def non_null_type(type_: TypeNode, loc: Location):
91-
return NonNullTypeNode(type=type_, loc=loc)
103+
def non_null_type(type_: TypeNode, position: tuple[int, int]):
104+
return NonNullTypeNode(type=type_, loc=make_loc(position))
92105

93106

94-
def enum_value_node(name: str, loc: Location):
107+
def enum_value_node(name: str, position: tuple[int, int]):
95108
return EnumValueDefinitionNode(
96-
name=name_node(name, loc), directives=(), loc=loc, description=None
109+
name=name_node(name, position),
110+
directives=(),
111+
loc=make_loc(position),
112+
description=None,
97113
)
98114

99115

100116
def input_value_node(
101-
name: NameNode, type_: TypeNode, default_value: ValueNode | None, loc: Location
117+
name: NameNode,
118+
type_: TypeNode,
119+
default_value: ValueNode | None,
120+
position: tuple[int, int],
102121
):
103122
return InputValueDefinitionNode(
104123
name=name,
105124
type=type_,
106125
default_value=default_value,
107126
directives=(),
108-
loc=loc,
127+
loc=make_loc(position),
109128
description=None,
110129
)
111130

112131

113-
def boolean_value_node(value: bool, loc: Location):
114-
return BooleanValueNode(value=value, loc=loc)
132+
def boolean_value_node(value: bool, position: tuple[int, int]):
133+
return BooleanValueNode(value=value, loc=make_loc(position))
115134

116135

117-
def string_value_node(value: str, block: bool | None, loc: Location):
118-
return StringValueNode(value=value, block=block, loc=loc)
136+
def string_value_node(value: str, block: bool | None, position: tuple[int, int]):
137+
return StringValueNode(value=value, block=block, loc=make_loc(position))
119138

120139

121-
def list_type_node(type_: TypeNode, loc: Location):
122-
return ListTypeNode(type=type_, loc=loc)
140+
def list_type_node(type_: TypeNode, position: tuple[int, int]):
141+
return ListTypeNode(type=type_, loc=make_loc(position))
123142

124143

125144
def schema_extension_node(
126145
directives: tuple[DirectiveNode, ...],
127146
operation_types: tuple[OperationTypeDefinitionNode, ...],
128-
loc: Location,
147+
position: tuple[int, int],
129148
):
130149
return SchemaExtensionNode(
131-
directives=directives, operation_types=operation_types, loc=loc
150+
directives=directives, operation_types=operation_types, loc=make_loc(position)
132151
)
133152

134153

135-
def operation_type_definition(operation: OperationType, type_: TypeNode, loc: Location):
136-
return OperationTypeDefinitionNode(operation=operation, type=type_, loc=loc)
154+
def operation_type_definition(
155+
operation: OperationType, type_: TypeNode, position: tuple[int, int]
156+
):
157+
return OperationTypeDefinitionNode(
158+
operation=operation, type=type_, loc=make_loc(position)
159+
)
137160

138161

139-
def directive_node(name: NameNode, arguments: tuple[ArgumentNode, ...], loc: Location):
140-
return DirectiveNode(name=name, arguments=arguments, loc=loc)
162+
def directive_node(
163+
name: NameNode, arguments: tuple[ArgumentNode, ...], position: tuple[int, int]
164+
):
165+
return DirectiveNode(name=name, arguments=arguments, loc=make_loc(position))
141166

142167

143168
def describe_schema_parser():

0 commit comments

Comments
 (0)