import unittest import textwrap from pygments.lexers import GraphQLLexer from pygments.token import ( Comment, Error, Keyword, Name, Number, Punctuation, String, Whitespace ) def assert_tokens_equal(self, text, expected, stack=("root",)): text = textwrap.dedent(text) lexer = GraphQLLexer() tokens_itr = lexer.get_tokens_unprocessed(text, stack=stack) self.assertEqual(list(tokens_itr), expected) def assert_value_equal(self, text, expected): if not isinstance(expected, list): expected = [expected] assert_tokens_equal(self, text, expected, stack=("value",)) def assert_string_equal(self, text, tokens): start = (0, String, '"') end = (len(text) - 1, String, '"') expected = [start, *tokens, end] assert_tokens_equal(self, text, expected, stack=("value",)) class TestValue(unittest.TestCase): maxDiff = None def test_float(self): assert_value_equal(self, "5.5", (0, Number.Float, "5.5")) assert_value_equal(self, "5e3", (0, Number.Float, "5e3")) assert_value_equal(self, "5E3", (0, Number.Float, "5E3")) assert_value_equal(self, "5e-3", (0, Number.Float, "5e-3")) assert_value_equal(self, "5E-3", (0, Number.Float, "5E-3")) assert_value_equal(self, "5e+3", (0, Number.Float, "5e+3")) assert_value_equal(self, "5E+3", (0, Number.Float, "5E+3")) assert_value_equal(self, "5.1e3", (0, Number.Float, "5.1e3")) assert_value_equal(self, "5.1E3", (0, Number.Float, "5.1E3")) assert_value_equal(self, "5.1e-3", (0, Number.Float, "5.1e-3")) assert_value_equal(self, "5.1E-3", (0, Number.Float, "5.1E-3")) assert_value_equal(self, "5.1e+3", (0, Number.Float, "5.1e+3")) assert_value_equal(self, "5.1E+3", (0, Number.Float, "5.1E+3")) def test_integer(self): assert_value_equal(self, "5", (0, Number.Integer, "5")) assert_value_equal(self, "-0", (0, Number.Integer, "-0")) # Not really following the specifications assert_value_equal(self, "-02", (0, Number.Integer, "-02")) def test_string(self): assert_string_equal(self, '"asdf"', [(1, String, "asdf")]) assert_string_equal( self, r'"asdf\""', [ (1, String, "asdf"), (5, String.Escape, r"\""), ], ) assert_string_equal( self, r'"asdf\m"', [(1, String, "asdf"), (5, Error, "\\"), (6, String, "m")] ) assert_string_equal( self, r'"asdf\u00E8"', [ (1, String, "asdf"), (5, String.Escape, r"\u00E8"), ], ) def test_boolean(self): assert_value_equal(self, "true", (0, Name.Builtin, "true")) assert_value_equal(self, "false", (0, Name.Builtin, "false")) def test_variable(self): assert_value_equal(self, "$hello", (0, Name.Variable, "$hello")) assert_value_equal( self, "$0hello", [ (0, Error, "$"), (1, Number.Integer, "0"), (2, Name.Constant, "hello"), ], ) def test_list_value(self): assert_value_equal( self, '[1, 1.1, "abc"]', [ (0, Punctuation, "["), (1, Number.Integer, "1"), (2, Punctuation, ","), (3, Whitespace, " "), (4, Number.Float, "1.1"), (7, Punctuation, ","), (8, Whitespace, " "), (9, String, '"'), (10, String, "abc"), (13, String, '"'), (14, Punctuation, "]"), ], ) assert_value_equal( self, '[1, 1.1, ["abc"]]', [ (0, Punctuation, "["), (1, Number.Integer, "1"), (2, Punctuation, ","), (3, Whitespace, " "), (4, Number.Float, "1.1"), (7, Punctuation, ","), (8, Whitespace, " "), (9, Punctuation, "["), (10, String, '"'), (11, String, "abc"), (14, String, '"'), (15, Punctuation, "]"), (16, Punctuation, "]"), ], ) class TestGraphqlLexer(unittest.TestCase): maxDiff = None def assert_builtin(self, text): assert_tokens_equal(self, text, [(0, Name.Builtin, text)], stack=("builtins",)) def test_keyworkd(self): assert_tokens_equal(self, "type", [(0, Keyword, "type")]) assert_tokens_equal(self, "schema", [(0, Keyword, "schema")]) assert_tokens_equal(self, "extend", [(0, Keyword, "extend")]) assert_tokens_equal(self, "enum", [(0, Keyword, "enum")]) assert_tokens_equal(self, "scalar", [(0, Keyword, "scalar")]) assert_tokens_equal(self, "implements", [(0, Keyword, "implements")]) assert_tokens_equal(self, "interface", [(0, Keyword, "interface")]) assert_tokens_equal(self, "union", [(0, Keyword, "union")]) assert_tokens_equal(self, "input", [(0, Keyword, "input")]) assert_tokens_equal(self, "directive", [(0, Keyword, "directive")]) def test_arguments_integer(self): text = """\ { field(arg: 24) field } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "field"), (9, Punctuation, "("), (10, Name, "arg"), # (10, Name.Attribute, 'arg'), (13, Punctuation, ":"), (14, Whitespace, " "), (15, Number.Integer, "24"), (17, Punctuation, ")"), (18, Whitespace, "\n "), (21, Name, "field"), (26, Whitespace, "\n"), (27, Punctuation, "}"), (28, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_arguments(self): text = """\ { human(id: "1000") { name height } } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "human"), (9, Punctuation, "("), # (10, Name.Attribute, 'id'), (10, Name, "id"), (12, Punctuation, ":"), (13, Whitespace, " "), (14, String, '"'), (15, String, "1000"), (19, String, '"'), (20, Punctuation, ")"), (21, Whitespace, " "), (22, Punctuation, "{"), (23, Whitespace, "\n "), (28, Name, "name"), (32, Whitespace, "\n "), (37, Name, "height"), (43, Whitespace, "\n "), (46, Punctuation, "}"), (47, Whitespace, "\n"), (48, Punctuation, "}"), (49, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_argument_scalar(self): text = """\ { human(id: "1000") { name height(unit: FOOT) } } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "human"), (9, Punctuation, "("), # (10, Name.Attribute, 'id'), (10, Name, "id"), (12, Punctuation, ":"), (13, Whitespace, " "), (14, String, '"'), (15, String, "1000"), (19, String, '"'), (20, Punctuation, ")"), (21, Whitespace, " "), (22, Punctuation, "{"), (23, Whitespace, "\n "), (28, Name, "name"), (32, Whitespace, "\n "), (37, Name, "height"), (43, Punctuation, "("), # (44, Name.Attribute, 'unit'), (44, Name, "unit"), (48, Punctuation, ":"), (49, Whitespace, " "), (50, Name.Constant, "FOOT"), (54, Punctuation, ")"), (55, Whitespace, "\n "), (58, Punctuation, "}"), (59, Whitespace, "\n"), (60, Punctuation, "}"), (61, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_alias(self): text = """\ { empireHero: hero(episode: EMPIRE) { name } jediHero: hero(episode: JEDI) { name } } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name.Label, "empireHero"), (14, Punctuation, ":"), (15, Whitespace, " "), (16, Name, "hero"), (20, Punctuation, "("), # (21, Name.Attribute, 'episode'), (21, Name, "episode"), (28, Punctuation, ":"), (29, Whitespace, " "), (30, Name.Constant, "EMPIRE"), (36, Punctuation, ")"), (37, Whitespace, " "), (38, Punctuation, "{"), (39, Whitespace, "\n "), (44, Name, "name"), (48, Whitespace, "\n "), (51, Punctuation, "}"), (52, Whitespace, "\n "), (55, Name.Label, "jediHero"), (63, Punctuation, ":"), (64, Whitespace, " "), (65, Name, "hero"), (69, Punctuation, "("), # (70, Name.Attribute, 'episode'), (70, Name, "episode"), (77, Punctuation, ":"), (78, Whitespace, " "), (79, Name.Constant, "JEDI"), (83, Punctuation, ")"), (84, Whitespace, " "), (85, Punctuation, "{"), (86, Whitespace, "\n "), (91, Name, "name"), (95, Whitespace, "\n "), (98, Punctuation, "}"), (99, Whitespace, "\n"), (100, Punctuation, "}"), (101, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_variables(self): text = """\ mutation testVar($int: Int, $myType: MyType, $required: String!, $list: [Int!]!) { doSomenthing(int: $int, myType: $myType, required: $required, list: $list) { response } } """ expected = [ (0, Keyword, "mutation"), (8, Whitespace, " "), (9, Name.Function, "testVar"), (16, Punctuation, "("), (17, Name.Variable, "$int"), (21, Punctuation, ":"), (22, Whitespace, " "), (23, Name.Builtin, "Int"), (26, Punctuation, ","), (27, Whitespace, " "), (28, Name.Variable, "$myType"), (35, Punctuation, ":"), (36, Whitespace, " "), (37, Name.Class, "MyType"), (43, Punctuation, ","), (44, Whitespace, "\n "), (49, Name.Variable, "$required"), (58, Punctuation, ":"), (59, Whitespace, " "), (60, Name.Builtin, "String"), (66, Punctuation, "!"), (67, Punctuation, ","), (68, Whitespace, " "), (69, Name.Variable, "$list"), (74, Punctuation, ":"), (75, Whitespace, " "), (76, Punctuation, "["), (77, Name.Builtin, "Int"), (80, Punctuation, "!"), (81, Punctuation, "]"), (82, Punctuation, "!"), (83, Punctuation, ")"), (84, Whitespace, "\n"), (85, Punctuation, "{"), (86, Whitespace, "\n "), (89, Name, "doSomenthing"), (101, Punctuation, "("), (102, Name, "int"), (105, Punctuation, ":"), (106, Whitespace, " "), (107, Name.Variable, "$int"), (111, Punctuation, ","), (112, Whitespace, " "), (113, Name, "myType"), (119, Punctuation, ":"), (120, Whitespace, " "), (121, Name.Variable, "$myType"), (128, Punctuation, ","), (129, Whitespace, "\n "), (136, Name, "required"), (144, Punctuation, ":"), (145, Whitespace, " "), (146, Name.Variable, "$required"), (155, Punctuation, ","), (156, Whitespace, " "), (157, Name, "list"), (161, Punctuation, ":"), (162, Whitespace, " "), (163, Name.Variable, "$list"), (168, Punctuation, ")"), (169, Whitespace, "\n "), (172, Punctuation, "{"), (173, Whitespace, "\n "), (178, Name, "response"), (186, Whitespace, "\n "), (189, Punctuation, "}"), (190, Whitespace, "\n"), (191, Punctuation, "}"), (192, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_operation_definition_directives(self): text = """\ query ($foo: Boolean = true, $bar: Boolean = false) { field @skip(if: $foo) { subfieldA } field @skip(if: $bar) { subfieldB } } """ expected = [ (0, Keyword, "query"), (5, Whitespace, " "), (6, Punctuation, "("), (7, Name.Variable, "$foo"), (11, Punctuation, ":"), (12, Whitespace, " "), (13, Name.Builtin, "Boolean"), (20, Whitespace, " "), (21, Punctuation, "="), (22, Whitespace, " "), (23, Name.Builtin, "true"), (27, Punctuation, ","), (28, Whitespace, " "), (29, Name.Variable, "$bar"), (33, Punctuation, ":"), (34, Whitespace, " "), (35, Name.Builtin, "Boolean"), (42, Whitespace, " "), (43, Punctuation, "="), (44, Whitespace, " "), (45, Name.Builtin, "false"), (50, Punctuation, ")"), (51, Whitespace, " "), (52, Punctuation, "{"), (53, Whitespace, "\n "), (56, Name, "field"), (61, Whitespace, " "), (62, Name.Decorator, "@skip"), (67, Punctuation, "("), (68, Name, "if"), (70, Punctuation, ":"), (71, Whitespace, " "), (72, Name.Variable, "$foo"), (76, Punctuation, ")"), (77, Whitespace, " "), (78, Punctuation, "{"), (79, Whitespace, "\n "), (84, Name, "subfieldA"), (93, Whitespace, "\n "), (96, Punctuation, "}"), (97, Whitespace, "\n "), (100, Name, "field"), (105, Whitespace, " "), (106, Name.Decorator, "@skip"), (111, Punctuation, "("), (112, Name, "if"), (114, Punctuation, ":"), (115, Whitespace, " "), (116, Name.Variable, "$bar"), (120, Punctuation, ")"), (121, Whitespace, " "), (122, Punctuation, "{"), (123, Whitespace, "\n "), (128, Name, "subfieldB"), (137, Whitespace, "\n "), (140, Punctuation, "}"), (141, Whitespace, "\n"), (142, Punctuation, "}"), (143, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_operation_definition_multi_directives(self): text = """\ query ($foo: Boolean = true, $bar: Boolean = false) { field @skip(if: $foo) @skip(if: $bar) } """ expected = [ (0, Keyword, "query"), (5, Whitespace, " "), (6, Punctuation, "("), (7, Name.Variable, "$foo"), (11, Punctuation, ":"), (12, Whitespace, " "), (13, Name.Builtin, "Boolean"), (20, Whitespace, " "), (21, Punctuation, "="), (22, Whitespace, " "), (23, Name.Builtin, "true"), (27, Punctuation, ","), (28, Whitespace, " "), (29, Name.Variable, "$bar"), (33, Punctuation, ":"), (34, Whitespace, " "), (35, Name.Builtin, "Boolean"), (42, Whitespace, " "), (43, Punctuation, "="), (44, Whitespace, " "), (45, Name.Builtin, "false"), (50, Punctuation, ")"), (51, Whitespace, " "), (52, Punctuation, "{"), (53, Whitespace, "\n "), (56, Name, "field"), (61, Whitespace, " "), (62, Name.Decorator, "@skip"), (67, Punctuation, "("), (68, Name, "if"), (70, Punctuation, ":"), (71, Whitespace, " "), (72, Name.Variable, "$foo"), (76, Punctuation, ")"), (77, Whitespace, " "), (78, Name.Decorator, "@skip"), (83, Punctuation, "("), (84, Name, "if"), (86, Punctuation, ":"), (87, Whitespace, " "), (88, Name.Variable, "$bar"), (92, Punctuation, ")"), (93, Whitespace, "\n"), (94, Punctuation, "}"), (95, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_fragment_spread(self): text = """\ query withNestedFragments { user(id: 4) { friends(first: 10) { ...friendFields } mutualFriends(first: 10) { ...friendFields @skip(if: true) } } } """ expected = [ (0, Keyword, "query"), (5, Whitespace, " "), (6, Name.Function, "withNestedFragments"), (25, Whitespace, " "), (26, Punctuation, "{"), (27, Whitespace, "\n "), (30, Name, "user"), (34, Punctuation, "("), (35, Name, "id"), (37, Punctuation, ":"), (38, Whitespace, " "), (39, Number.Integer, "4"), (40, Punctuation, ")"), (41, Whitespace, " "), (42, Punctuation, "{"), (43, Whitespace, "\n "), (48, Name, "friends"), (55, Punctuation, "("), (56, Name, "first"), (61, Punctuation, ":"), (62, Whitespace, " "), (63, Number.Integer, "10"), (65, Punctuation, ")"), (66, Whitespace, " "), (67, Punctuation, "{"), (68, Whitespace, "\n "), (75, Punctuation, "..."), (78, Name, "friendFields"), (90, Whitespace, "\n "), (95, Punctuation, "}"), (96, Whitespace, "\n "), (101, Name, "mutualFriends"), (114, Punctuation, "("), (115, Name, "first"), (120, Punctuation, ":"), (121, Whitespace, " "), (122, Number.Integer, "10"), (124, Punctuation, ")"), (125, Whitespace, " "), (126, Punctuation, "{"), (127, Whitespace, "\n "), (134, Punctuation, "..."), (137, Name, "friendFields"), (149, Whitespace, " "), (150, Name.Decorator, "@skip"), (155, Punctuation, "("), (156, Name, "if"), (158, Punctuation, ":"), (159, Whitespace, " "), (160, Name.Builtin, "true"), (164, Punctuation, ")"), (165, Whitespace, "\n "), (170, Punctuation, "}"), (171, Whitespace, "\n "), (174, Punctuation, "}"), (175, Whitespace, "\n"), (176, Punctuation, "}"), (177, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_inline_fragment(self): text = """\ query inlineFragmentTyping { profiles(handles: ["zuck", "cocacola"]) { handle ... on User { friends { count } } ... on Page { likers { count } } } } """ expected = [ (0, Keyword, "query"), (5, Whitespace, " "), (6, Name.Function, "inlineFragmentTyping"), (26, Whitespace, " "), (27, Punctuation, "{"), (28, Whitespace, "\n "), (31, Name, "profiles"), (39, Punctuation, "("), (40, Name, "handles"), (47, Punctuation, ":"), (48, Whitespace, " "), (49, Punctuation, "["), (50, String, '"'), (51, String, "zuck"), (55, String, '"'), (56, Punctuation, ","), (57, Whitespace, " "), (58, String, '"'), (59, String, "cocacola"), (67, String, '"'), (68, Punctuation, "]"), (69, Punctuation, ")"), (70, Whitespace, " "), (71, Punctuation, "{"), (72, Whitespace, "\n "), (77, Name, "handle"), (83, Whitespace, "\n "), (88, Punctuation, "..."), (91, Whitespace, " "), (92, Keyword, "on"), (94, Whitespace, " "), (95, Name.Class, "User"), (99, Whitespace, " "), (100, Punctuation, "{"), (101, Whitespace, "\n "), (108, Name, "friends"), (115, Whitespace, " "), (116, Punctuation, "{"), (117, Whitespace, "\n "), (126, Name, "count"), (131, Whitespace, "\n "), (138, Punctuation, "}"), (139, Whitespace, "\n "), (144, Punctuation, "}"), (145, Whitespace, "\n "), (150, Punctuation, "..."), (153, Whitespace, " "), (154, Keyword, "on"), (156, Whitespace, " "), (157, Name.Class, "Page"), (161, Whitespace, " "), (162, Punctuation, "{"), (163, Whitespace, "\n "), (170, Name, "likers"), (176, Whitespace, " "), (177, Punctuation, "{"), (178, Whitespace, "\n "), (187, Name, "count"), (192, Whitespace, "\n "), (199, Punctuation, "}"), (200, Whitespace, "\n "), (205, Punctuation, "}"), (206, Whitespace, "\n "), (209, Punctuation, "}"), (210, Whitespace, "\n"), (211, Punctuation, "}"), (212, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_input_value_nested_array(self): text = """\ { node(arg: [1, [2, 3]]) } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "node"), (8, Punctuation, "("), (9, Name, "arg"), (12, Punctuation, ":"), (13, Whitespace, " "), (14, Punctuation, "["), (15, Number.Integer, "1"), (16, Punctuation, ","), (17, Whitespace, " "), (18, Punctuation, "["), (19, Number.Integer, "2"), (20, Punctuation, ","), (21, Whitespace, " "), (22, Number.Integer, "3"), (23, Punctuation, "]"), (24, Punctuation, "]"), (25, Punctuation, ")"), (26, Whitespace, "\n"), (27, Punctuation, "}"), (28, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_input_value_object(self): text = """\ { node(arg: {a: "a", b: "b"}) } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "node"), (8, Punctuation, "("), (9, Name, "arg"), (12, Punctuation, ":"), (13, Whitespace, " "), (14, Punctuation, "{"), (15, Name, "a"), (16, Punctuation, ":"), (17, Whitespace, " "), (18, String, '"'), (19, String, "a"), (20, String, '"'), (21, Punctuation, ","), (22, Whitespace, " "), (23, Name, "b"), (24, Punctuation, ":"), (25, Whitespace, " "), (26, String, '"'), (27, String, "b"), (28, String, '"'), (29, Punctuation, "}"), (30, Punctuation, ")"), (31, Whitespace, "\n"), (32, Punctuation, "}"), (33, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_input_nested_value_object(self): text = """\ { node(arg: {a: "a", b: {c: "c", d: {e: "e"}}}) } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "node"), (8, Punctuation, "("), (9, Name, "arg"), (12, Punctuation, ":"), (13, Whitespace, " "), (14, Punctuation, "{"), (15, Name, "a"), (16, Punctuation, ":"), (17, Whitespace, " "), (18, String, '"'), (19, String, "a"), (20, String, '"'), (21, Punctuation, ","), (22, Whitespace, " "), (23, Name, "b"), (24, Punctuation, ":"), (25, Whitespace, " "), (26, Punctuation, "{"), (27, Name, "c"), (28, Punctuation, ":"), (29, Whitespace, " "), (30, String, '"'), (31, String, "c"), (32, String, '"'), (33, Punctuation, ","), (34, Whitespace, " "), (35, Name, "d"), (36, Punctuation, ":"), (37, Whitespace, " "), (38, Punctuation, "{"), (39, Name, "e"), (40, Punctuation, ":"), (41, Whitespace, " "), (42, String, '"'), (43, String, "e"), (44, String, '"'), (45, Punctuation, "}"), (46, Punctuation, "}"), (47, Punctuation, "}"), (48, Punctuation, ")"), (49, Whitespace, "\n"), (50, Punctuation, "}"), (51, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected) def test_input_value_mixed(self): text = """\ { node1(arg: {a: [1, 2]}) node2(arg: [1, {a: "a"}]) } """ expected = [ (0, Punctuation, "{"), (1, Whitespace, "\n "), (4, Name, "node1"), (9, Punctuation, "("), (10, Name, "arg"), (13, Punctuation, ":"), (14, Whitespace, " "), (15, Punctuation, "{"), (16, Name, "a"), (17, Punctuation, ":"), (18, Whitespace, " "), (19, Punctuation, "["), (20, Number.Integer, "1"), (21, Punctuation, ","), (22, Whitespace, " "), (23, Number.Integer, "2"), (24, Punctuation, "]"), (25, Punctuation, "}"), (26, Punctuation, ")"), (27, Whitespace, "\n "), (30, Name, "node2"), (35, Punctuation, "("), (36, Name, "arg"), (39, Punctuation, ":"), (40, Whitespace, " "), (41, Punctuation, "["), (42, Number.Integer, "1"), (43, Punctuation, ","), (44, Whitespace, " "), (45, Punctuation, "{"), (46, Name, "a"), (47, Punctuation, ":"), (48, Whitespace, " "), (49, String, '"'), (50, String, "a"), (51, String, '"'), (52, Punctuation, "}"), (53, Punctuation, "]"), (54, Punctuation, ")"), (55, Whitespace, "\n"), (56, Punctuation, "}"), (57, Whitespace, "\n"), ] assert_tokens_equal(self, text, expected)