Skip to content

Commit a27808c

Browse files
committed
Implement tests to improve coverage:
* asts should be hashable/copyable/reprable. * lexer tokens, loc and source locations should be able to be repr. * visitors should properly inherit their enter/leave methods from parents.
1 parent 151841a commit a27808c

File tree

8 files changed

+87
-8
lines changed

8 files changed

+87
-8
lines changed

graphql/core/language/source.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ def __init__(self, body, name='GraphQL'):
99
self.name = name
1010

1111
def __eq__(self, other):
12-
if isinstance(other, Source):
13-
return self.body == other.body and self.name == other.name
14-
return False
12+
return (
13+
self is other or (
14+
isinstance(other, Source) and
15+
self.body == other.body and
16+
self.name == other.name
17+
)
18+
)

graphql/core/language/visitor_meta.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def __new__(cls, name, bases, attrs):
5353
for base in bases:
5454
if hasattr(base, '_enter_handlers'):
5555
enter_handlers.update(base._enter_handlers)
56+
5657
if hasattr(base, '_leave_handlers'):
5758
leave_handlers.update(base._leave_handlers)
5859

@@ -67,6 +68,8 @@ def __new__(cls, name, bases, attrs):
6768
ast_type = AST_KIND_TO_TYPE.get(ast_kind)
6869
leave_handlers[ast_type] = val
6970

71+
attrs['_enter_handlers'] = enter_handlers
72+
attrs['_leave_handlers'] = leave_handlers
7073
attrs['_get_enter_handler'] = enter_handlers.get
7174
attrs['_get_leave_handler'] = leave_handlers.get
7275
return super(VisitorMeta, cls).__new__(cls, name, bases, attrs)

graphql/core/pyutils/defer.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ def add_callbacks(self, callback, errback=None,
243243
>>> deferred.result
244244
'Got: catched'
245245
"""
246-
assert isinstance(callback, collections.Callable)
247-
assert errback is None or isinstance(errback, collections.Callable)
246+
assert callback is _passthrough or isinstance(callback, collections.Callable)
247+
assert errback is None or errback is _passthrough or isinstance(errback, collections.Callable)
248248
if errback is None:
249249
errback = _passthrough
250250
self.callbacks.append(((callback,
@@ -449,8 +449,7 @@ def defer(func, *args, **kwargs):
449449
return deferred
450450

451451

452-
def _passthrough(arg):
453-
return arg
452+
_passthrough = object()
454453

455454

456455
def succeed(result):

tests/core_language/test_ast.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import copy
2+
from graphql.core.language.visitor_meta import VisitorMeta, QUERY_DOCUMENT_KEYS
3+
4+
5+
def test_ast_is_hashable():
6+
for node_class in QUERY_DOCUMENT_KEYS:
7+
node = node_class(loc=None, **{k: k for k in node_class._fields})
8+
assert hash(node)
9+
10+
11+
def test_ast_is_copyable():
12+
for node_class in QUERY_DOCUMENT_KEYS:
13+
node = node_class(loc=None, **{k: k for k in node_class._fields})
14+
assert copy.copy(node) == node
15+
16+
17+
def test_ast_is_reprable():
18+
for node_class in QUERY_DOCUMENT_KEYS:
19+
node = node_class(loc=None, **{k: k for k in node_class._fields})
20+
assert repr(node)

tests/core_language/test_lexer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ def lex_one(s):
88
return Lexer(Source(s)).next_token()
99

1010

11+
def test_repr_token():
12+
token = lex_one('500')
13+
assert repr(token) == "<Token kind=Int at 0..3 value='500'>"
14+
15+
1116
def test_disallows_uncommon_control_characters():
1217
with raises(LanguageError) as excinfo:
1318
lex_one(u'\u0007')
@@ -213,4 +218,3 @@ def test_lex_reports_useful_information_for_dashes_in_names():
213218
lexer.next_token()
214219

215220
assert u'Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "b".' in excinfo.value.message
216-

tests/core_language/test_location.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from graphql.core.language.location import SourceLocation
2+
3+
4+
def test_repr_source_location():
5+
loc = SourceLocation(10, 25)
6+
assert repr(loc) == '<SourceLocation line=10 column=25>'

tests/core_language/test_parser.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
from .fixtures import KITCHEN_SINK
88

99

10+
def test_repr_loc():
11+
loc = Loc(start=10, end=25, source='foo')
12+
assert repr(loc) == '<Loc start=10 end=25 source=foo>'
13+
14+
1015
def test_parse_provides_useful_errors():
1116
with raises(LanguageError) as excinfo:
1217
parse("""{""")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from graphql.core.language import ast
2+
from graphql.core.language.visitor import Visitor
3+
4+
5+
def test_visitor_meta_creates_enter_and_leave_handlers():
6+
class MyVisitor(Visitor):
7+
def enter_OperationDefinition(self):
8+
pass
9+
10+
def leave_OperationDefinition(self):
11+
pass
12+
13+
assert MyVisitor._get_enter_handler(ast.OperationDefinition)
14+
assert MyVisitor._get_leave_handler(ast.OperationDefinition)
15+
16+
17+
def test_visitor_inherits_parent_definitions():
18+
class MyVisitor(Visitor):
19+
def enter_OperationDefinition(self):
20+
pass
21+
22+
def leave_OperationDefinition(self):
23+
pass
24+
25+
assert MyVisitor._get_enter_handler(ast.OperationDefinition)
26+
assert MyVisitor._get_leave_handler(ast.OperationDefinition)
27+
28+
class MyVisitorSubclassed(MyVisitor):
29+
def enter_FragmentDefinition(self):
30+
pass
31+
32+
def leave_FragmentDefinition(self):
33+
pass
34+
35+
assert MyVisitorSubclassed._get_enter_handler(ast.OperationDefinition)
36+
assert MyVisitorSubclassed._get_leave_handler(ast.OperationDefinition)
37+
assert MyVisitorSubclassed._get_enter_handler(ast.FragmentDefinition)
38+
assert MyVisitorSubclassed._get_leave_handler(ast.FragmentDefinition)

0 commit comments

Comments
 (0)