graphql 0.18.5 → 0.18.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d69978a50350e058883fa1f9fdfc5c6e5dcc80b
4
- data.tar.gz: 97cc2fdfc3778f6b75cf34a2b9d5dcf6354a1a28
3
+ metadata.gz: 097a1f2ab62a05d6617d2445c0771066c1d547a3
4
+ data.tar.gz: c65cc3378d3a1e525881abfde3c520b2f2eac71a
5
5
  SHA512:
6
- metadata.gz: c6177a5c17291fc6f95f0f2d8e14f3831ebc9af7f46addd15bc3283a63310151c8fc7fbfc1acc332a181ab808060afb399fd87ce83db6e0088c093adabd8b35b
7
- data.tar.gz: b0464b86095e2aafa933d4dc5b6e5491ef2354df6025943967a78d36d63d7f7c2111e6bfaefe3b11abd5d8937c1ba14e160b5fe9d255cc7b5501d56b0f8e92a1
6
+ metadata.gz: 913f57d14573f3fef716bd604e1dc62827d1fb62361bde854e42fe32f357a3e88ee382f1f1605a1bb11a16fcc80f2a9e7ff5e223a408c83bf5b224b8e9d76913
7
+ data.tar.gz: cfd8abc3faad374f484e97ef7b3505486c60067fefb6c1295f3eb55f0478f750dd344c3da9a876c87179a8f3772597245a05e561430df4a4c4f685f055e17a4b
data/lib/graphql.rb CHANGED
@@ -58,6 +58,7 @@ require "graphql/introspection"
58
58
  require "graphql/language"
59
59
  require "graphql/analysis"
60
60
  require "graphql/schema"
61
+ require "graphql/schema/loader"
61
62
  require "graphql/schema/printer"
62
63
 
63
64
  # Order does not matter for these:
@@ -26,5 +26,19 @@ module GraphQL
26
26
  end
27
27
 
28
28
  attr_writer :name
29
+
30
+ def type=(new_return_type)
31
+ ensure_defined
32
+ @clean_type = nil
33
+ @dirty_type = new_return_type
34
+ end
35
+
36
+ # Get the return type for this field.
37
+ def type
38
+ @clean_type ||= begin
39
+ ensure_defined
40
+ GraphQL::BaseType.resolve_related_type(@dirty_type)
41
+ end
42
+ end
29
43
  end
30
44
  end
@@ -56,7 +56,7 @@ module GraphQL
56
56
  # }
57
57
  #
58
58
  class EnumType < GraphQL::BaseType
59
- accepts_definitions value: GraphQL::Define::AssignEnumValue
59
+ accepts_definitions :values, value: GraphQL::Define::AssignEnumValue
60
60
 
61
61
  def initialize
62
62
  @values_by_name = {}
@@ -124,6 +124,10 @@ module GraphQL
124
124
  #
125
125
  # Created with the `value` helper
126
126
  class EnumValue
127
+ def self.define(name:, description: nil, deprecation_reason: nil, value: nil)
128
+ new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
129
+ end
130
+
127
131
  attr_accessor :name, :description, :deprecation_reason, :value
128
132
  def initialize(name:, description:, deprecation_reason:, value:)
129
133
  @name = name
data/lib/graphql/field.rb CHANGED
@@ -120,7 +120,7 @@ module GraphQL
120
120
  #
121
121
  class Field
122
122
  include GraphQL::Define::InstanceDefinable
123
- accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, :hash_key, argument: GraphQL::Define::AssignArgument
123
+ accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, :hash_key, :arguments, argument: GraphQL::Define::AssignArgument
124
124
 
125
125
  lazy_defined_attr_accessor :deprecation_reason, :description, :property, :hash_key
126
126
 
@@ -24,6 +24,7 @@ module GraphQL
24
24
  #
25
25
  class InputObjectType < GraphQL::BaseType
26
26
  accepts_definitions(
27
+ :arguments,
27
28
  input_field: GraphQL::Define::AssignArgument,
28
29
  argument: GraphQL::Define::AssignArgument
29
30
  )
@@ -23,7 +23,7 @@ module GraphQL
23
23
  #
24
24
  class InterfaceType < GraphQL::BaseType
25
25
  include GraphQL::BaseType::HasPossibleTypes
26
- accepts_definitions :resolve_type, field: GraphQL::Define::AssignObjectField
26
+ accepts_definitions :resolve_type, :fields, field: GraphQL::Define::AssignObjectField
27
27
 
28
28
  lazy_defined_attr_accessor :fields
29
29
 
@@ -0,0 +1,577 @@
1
+ module GraphQL
2
+ module Language
3
+ # If you create your own GraphQL parser, can verify it using these tests.
4
+ #
5
+ # @example Include these tests in a Minitest suite
6
+ # require 'graphql/language/parser_tests'
7
+ #
8
+ # describe MyParser do
9
+ # include GraphQL::Language::ParserTests
10
+ # subject { MyParser }
11
+ # end
12
+ module ParserTests
13
+ def self.included(test)
14
+ test.send(:describe, "Parser Tests") do
15
+ let(:document) { subject.parse(query_string) }
16
+ let(:query_string) {%|
17
+ query getStuff($someVar: Int = 1, $anotherVar: [String!] ) @skip(if: false) {
18
+ myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
19
+
20
+ anotherField(someArg: [1,2,3]) {
21
+ nestedField
22
+ ... moreNestedFields @skip(if: true)
23
+ }
24
+
25
+ ... on OtherType @include(unless: false){
26
+ field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
27
+ anotherField
28
+ }
29
+
30
+ ... {
31
+ id
32
+ }
33
+ }
34
+
35
+ fragment moreNestedFields on NestedType @or(something: "ok") {
36
+ anotherNestedField
37
+ }
38
+ |}
39
+
40
+ describe ".parse" do
41
+ it "parses queries" do
42
+ assert document
43
+ end
44
+
45
+ describe "visited nodes" do
46
+ let(:query) { document.definitions.first }
47
+ let(:fragment_def) { document.definitions.last }
48
+
49
+ it "creates a valid document" do
50
+ assert document.is_a?(GraphQL::Language::Nodes::Document)
51
+ assert_equal 2, document.definitions.length
52
+ end
53
+
54
+ it "creates a valid operation" do
55
+ assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
56
+ assert_equal "getStuff", query.name
57
+ assert_equal "query", query.operation_type
58
+ assert_equal 2, query.variables.length
59
+ assert_equal 4, query.selections.length
60
+ assert_equal 1, query.directives.length
61
+ assert_equal [2, 13], [query.line, query.col]
62
+ end
63
+
64
+ it "creates a valid fragment definition" do
65
+ assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
66
+ assert_equal "moreNestedFields", fragment_def.name
67
+ assert_equal 1, fragment_def.selections.length
68
+ assert_equal "NestedType", fragment_def.type
69
+ assert_equal 1, fragment_def.directives.length
70
+ assert_equal [20, 13], fragment_def.position
71
+ end
72
+
73
+ describe "variable definitions" do
74
+ let(:optional_var) { query.variables.first }
75
+ it "gets name and type" do
76
+ assert_equal "someVar", optional_var.name
77
+ assert_equal "Int", optional_var.type.name
78
+ end
79
+
80
+ it "gets default value" do
81
+ assert_equal 1, optional_var.default_value
82
+ end
83
+
84
+ it "gets position info" do
85
+ assert_equal [2, 28], optional_var.position
86
+ end
87
+ end
88
+
89
+ describe "fields" do
90
+ let(:leaf_field) { query.selections.first }
91
+ let(:parent_field) { query.selections[1] }
92
+
93
+ it "gets name, alias, arguments and directives" do
94
+ assert_equal "someField", leaf_field.name
95
+ assert_equal "myField", leaf_field.alias
96
+ assert_equal 2, leaf_field.directives.length
97
+ assert_equal 2, leaf_field.arguments.length
98
+ end
99
+
100
+ it "gets nested fields" do
101
+ assert_equal 2, parent_field.selections.length
102
+ end
103
+
104
+ it "gets location info" do
105
+ assert_equal [3 ,15], leaf_field.position
106
+ end
107
+
108
+ describe "when the arguments list is empty" do
109
+ let(:query_string) { "{ field() }"}
110
+ let(:field) { query.selections.first }
111
+ it "has zero arguments" do
112
+ assert_equal 0, field.arguments.length
113
+ end
114
+ end
115
+
116
+ describe "when selections are empty" do
117
+ let(:query_string) { "{ field { } }"}
118
+ let(:field) { query.selections.first }
119
+ it "has zero selections" do
120
+ assert_equal 0, field.selections.length
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "arguments" do
126
+ let(:literal_argument) { query.selections.first.arguments.last }
127
+ let(:variable_argument) { query.selections.first.arguments.first }
128
+
129
+ it "gets name and literal value" do
130
+ assert_equal "ok", literal_argument.name
131
+ assert_equal 1.4, literal_argument.value
132
+ end
133
+
134
+ it "gets name and variable value" do
135
+ assert_equal "someArg", variable_argument.name
136
+ assert_equal "someVar", variable_argument.value.name
137
+ end
138
+
139
+
140
+ it "gets position info" do
141
+ assert_equal [3, 34], variable_argument.position
142
+ end
143
+ end
144
+
145
+ describe "fragment spreads" do
146
+ let(:fragment_spread) { query.selections[1].selections.last }
147
+ it "gets the name and directives" do
148
+ assert_equal "moreNestedFields", fragment_spread.name
149
+ assert_equal 1, fragment_spread.directives.length
150
+ end
151
+
152
+ it "gets position info" do
153
+ assert_equal [7, 17], fragment_spread.position
154
+ end
155
+ end
156
+
157
+ describe "directives" do
158
+ let(:variable_directive) { query.selections.first.directives.first }
159
+
160
+ it "gets the name and arguments" do
161
+ assert_equal "skip", variable_directive.name
162
+ assert_equal "if", variable_directive.arguments.first.name
163
+ assert_equal 1, variable_directive.arguments.length
164
+ end
165
+
166
+ it "gets position info" do
167
+ assert_equal [3, 62], variable_directive.position
168
+ end
169
+ end
170
+
171
+ describe "inline fragments" do
172
+ let(:inline_fragment) { query.selections[2] }
173
+ let(:typeless_inline_fragment) { query.selections[3] }
174
+
175
+ it "gets the type and directives" do
176
+ assert_equal "OtherType", inline_fragment.type
177
+ assert_equal 2, inline_fragment.selections.length
178
+ assert_equal 1, inline_fragment.directives.length
179
+ end
180
+
181
+ it "gets inline fragments without type conditions" do
182
+ assert_equal nil, typeless_inline_fragment.type
183
+ assert_equal 1, typeless_inline_fragment.selections.length
184
+ assert_equal 0, typeless_inline_fragment.directives.length
185
+ end
186
+
187
+ it "gets position info" do
188
+ assert_equal [10, 15], inline_fragment.position
189
+ end
190
+ end
191
+
192
+ describe "inputs" do
193
+ let(:query_string) {%|
194
+ {
195
+ field(
196
+ int: 3,
197
+ float: 4.7e-24,
198
+ bool: false,
199
+ string: "☀︎🏆\\n escaped \\" unicode \\u00b6 /",
200
+ enum: ENUM_NAME,
201
+ array: [7, 8, 9]
202
+ object: {a: [1,2,3], b: {c: "4"}}
203
+ unicode_bom: "\xef\xbb\xbfquery"
204
+ keywordEnum: on
205
+ )
206
+ }
207
+ |}
208
+
209
+ let(:inputs) { document.definitions.first.selections.first.arguments }
210
+
211
+ it "parses ints" do
212
+ assert_equal 3, inputs[0].value
213
+ end
214
+
215
+ it "parses floats" do
216
+ assert_equal 0.47e-23, inputs[1].value
217
+ end
218
+
219
+ it "parses booleans" do
220
+ assert_equal false, inputs[2].value
221
+ end
222
+
223
+ it "parses UTF-8 strings" do
224
+ assert_equal %|☀︎🏆\n escaped " unicode ¶ /|, inputs[3].value
225
+ end
226
+
227
+ it "parses enums" do
228
+ assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
229
+ assert_equal "ENUM_NAME", inputs[4].value.name
230
+ end
231
+
232
+ it "parses arrays" do
233
+ assert_equal [7,8,9], inputs[5].value
234
+ end
235
+
236
+ it "parses objects" do
237
+ obj = inputs[6].value
238
+ assert_equal "a", obj.arguments[0].name
239
+ assert_equal [1,2,3], obj.arguments[0].value
240
+ assert_equal "b", obj.arguments[1].name
241
+ assert_equal "c", obj.arguments[1].value.arguments[0].name
242
+ assert_equal "4", obj.arguments[1].value.arguments[0].value
243
+ end
244
+
245
+ it "parses unicode bom" do
246
+ obj = inputs[7].value
247
+ assert_equal %|\xef\xbb\xbfquery|, inputs[7].value
248
+ end
249
+
250
+ it "parses enum 'on''" do
251
+ assert_equal "on", inputs[8].value.name
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "unnamed queries" do
257
+ let(:query_string) {%|
258
+ { name, age, height }
259
+ |}
260
+ let(:operation) { document.definitions.first }
261
+
262
+ it "parses unnamed queries" do
263
+ assert_equal 1, document.definitions.length
264
+ assert_equal "query", operation.operation_type
265
+ assert_equal nil, operation.name
266
+ assert_equal 3, operation.selections.length
267
+ end
268
+ end
269
+
270
+ describe "introspection query" do
271
+ let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
272
+
273
+ it "parses a big ol' query" do
274
+ assert(document)
275
+ end
276
+ end
277
+
278
+ describe "schema" do
279
+ it "parses the test schema" do
280
+ schema = DummySchema
281
+ schema_string = GraphQL::Schema::Printer.print_schema(schema)
282
+ document = subject.parse(schema_string)
283
+
284
+ assert_equal schema_string, document.to_query_string
285
+ end
286
+
287
+ it "parses mimal schema definition" do
288
+ document = subject.parse('schema { query: QueryRoot }')
289
+
290
+ schema = document.definitions.first
291
+ assert_equal 'QueryRoot', schema.query
292
+ assert_equal nil, schema.mutation
293
+ assert_equal nil, schema.subscription
294
+ end
295
+
296
+ it "parses full schema definitions" do
297
+ document = subject.parse('
298
+ schema {
299
+ query: QueryRoot
300
+ mutation: MutationRoot
301
+ subscription: SubscriptionRoot
302
+ }
303
+ ')
304
+
305
+ schema = document.definitions.first
306
+ assert_equal 'QueryRoot', schema.query
307
+ assert_equal 'MutationRoot', schema.mutation
308
+ assert_equal 'SubscriptionRoot', schema.subscription
309
+ end
310
+
311
+ it "parses object types" do
312
+ document = subject.parse('
313
+ type Comment implements Node {
314
+ id: ID!
315
+ }
316
+ ')
317
+
318
+ type = document.definitions.first
319
+ assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
320
+ assert_equal 'Comment', type.name
321
+ assert_equal ['Node'], type.interfaces
322
+ assert_equal ['id'], type.fields.map(&:name)
323
+ assert_equal [], type.fields[0].arguments
324
+ assert_equal 'ID', type.fields[0].type.of_type.name
325
+ end
326
+
327
+ it "parses field arguments" do
328
+ document = subject.parse('
329
+ type Mutation {
330
+ post(id: ID!, data: PostData = { message: "First!1!", type: BLOG, tags: ["Test", "Annoying"] }): Post
331
+ }
332
+ ')
333
+
334
+ field = document.definitions.first.fields.first
335
+ assert_equal ['id', 'data'], field.arguments.map(&:name)
336
+ data_arg = field.arguments[1]
337
+ assert_equal 'PostData', data_arg.type.name
338
+ assert_equal ['message', 'type', 'tags'], data_arg.default_value.arguments.map(&:name)
339
+ tags_arg = data_arg.default_value.arguments[2]
340
+ assert_equal ['Test', 'Annoying'], tags_arg.value
341
+ end
342
+
343
+ it "parses scalar types" do
344
+ document = subject.parse('scalar DateTime')
345
+
346
+ type = document.definitions.first
347
+ assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
348
+ assert_equal 'DateTime', type.name
349
+ end
350
+
351
+ it "parses interface types" do
352
+ document = subject.parse('
353
+ interface Node {
354
+ id: ID!
355
+ }
356
+ ')
357
+
358
+ type = document.definitions.first
359
+ assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
360
+ assert_equal 'Node', type.name
361
+ assert_equal ['id'], type.fields.map(&:name)
362
+ assert_equal [], type.fields[0].arguments
363
+ assert_equal 'ID', type.fields[0].type.of_type.name
364
+ end
365
+
366
+ it "parses enum types" do
367
+ document = subject.parse('
368
+ enum DogCommand { SIT, DOWN, HEEL }
369
+ ')
370
+
371
+ type = document.definitions.first
372
+ assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
373
+ assert_equal 'DogCommand', type.name
374
+ assert_equal ['SIT', 'DOWN', 'HEEL'], type.values
375
+ end
376
+
377
+ it "parses input object types" do
378
+ document = subject.parse('
379
+ input EmptyMutationInput {
380
+ clientMutationId: String
381
+ }
382
+ ')
383
+
384
+ type = document.definitions.first
385
+ assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
386
+ assert_equal 'EmptyMutationInput', type.name
387
+ assert_equal ['clientMutationId'], type.fields.map(&:name)
388
+ assert_equal 'String', type.fields[0].type.name
389
+ assert_equal nil, type.fields[0].default_value
390
+ end
391
+ end
392
+ end
393
+
394
+ describe "errors" do
395
+ let(:query_string) {%| query doSomething { bogus { } |}
396
+ it "raises a parse error" do
397
+ err = assert_raises(GraphQL::ParseError) { document }
398
+ end
399
+
400
+ it "correctly identifies parse error location and content" do
401
+ e = assert_raises(GraphQL::ParseError) do
402
+ GraphQL.parse("
403
+ query getCoupons {
404
+ allCoupons: {data{id}}
405
+ }
406
+ ")
407
+ end
408
+ assert_includes(e.message, '"{"')
409
+ assert_includes(e.message, "RCURLY")
410
+ assert_equal(3, e.line)
411
+ assert_equal(33, e.col)
412
+ end
413
+
414
+ it "handles unexpected ends" do
415
+ err = assert_raises(GraphQL::ParseError) { GraphQL.parse("{ ") }
416
+ assert_equal "Unexpected end of document", err.message
417
+ end
418
+
419
+ it "rejects unsupported characters" do
420
+ e = assert_raises(GraphQL::ParseError) do
421
+ GraphQL.parse("{ field; }")
422
+ end
423
+
424
+ assert_includes(e.message, "Parse error on \";\"")
425
+ end
426
+
427
+ it "rejects control characters" do
428
+ e = assert_raises(GraphQL::ParseError) do
429
+ GraphQL.parse("{ \afield }")
430
+ end
431
+
432
+ assert_includes(e.message, "Parse error on \"\\a\"")
433
+ end
434
+
435
+ it "rejects partial BOM" do
436
+ e = assert_raises(GraphQL::ParseError) do
437
+ GraphQL.parse("{ \xeffield }")
438
+ end
439
+
440
+ assert_includes(e.message, "Parse error on \"\\xEF\"")
441
+ end
442
+
443
+ it "rejects vertical tabs" do
444
+ e = assert_raises(GraphQL::ParseError) do
445
+ GraphQL.parse("{ \vfield }")
446
+ end
447
+
448
+ assert_includes(e.message, "Parse error on \"\\v\"")
449
+ end
450
+
451
+ it "rejects form feed" do
452
+ e = assert_raises(GraphQL::ParseError) do
453
+ GraphQL.parse("{ \ffield }")
454
+ end
455
+
456
+ assert_includes(e.message, "Parse error on \"\\f\"")
457
+ end
458
+
459
+ it "rejects no break space" do
460
+ e = assert_raises(GraphQL::ParseError) do
461
+ GraphQL.parse("{ \xa0field }")
462
+ end
463
+
464
+ assert_includes(e.message, "Parse error on \"\\xA0\"")
465
+ end
466
+
467
+ it "rejects unterminated strings" do
468
+ e = assert_raises(GraphQL::ParseError) do
469
+ GraphQL.parse("\"")
470
+ end
471
+
472
+ assert_includes(e.message, "Parse error on \"\\\"\"")
473
+
474
+ e = assert_raises(GraphQL::ParseError) do
475
+ GraphQL.parse("\"\n\"")
476
+ end
477
+
478
+ assert_includes(e.message, "Parse error on \"\\n\"")
479
+ end
480
+
481
+ it "rejects bad escape sequence in strings" do
482
+ e = assert_raises(GraphQL::ParseError) do
483
+ GraphQL.parse("{ field(arg:\"\\x\") }")
484
+ end
485
+
486
+ assert_includes(e.message, "Parse error on bad Unicode escape sequence")
487
+ end
488
+
489
+ it "rejects incomplete escape sequence in strings" do
490
+ e = assert_raises(GraphQL::ParseError) do
491
+ GraphQL.parse("{ field(arg:\"\\u1\") }")
492
+ end
493
+
494
+ assert_includes(e.message, "bad Unicode escape sequence")
495
+ end
496
+
497
+ it "rejects unicode escape with bad chars" do
498
+ e = assert_raises(GraphQL::ParseError) do
499
+ GraphQL.parse("{ field(arg:\"\\u0XX1\") }")
500
+ end
501
+
502
+ assert_includes(e.message, "bad Unicode escape sequence")
503
+
504
+ e = assert_raises(GraphQL::ParseError) do
505
+ GraphQL.parse("{ field(arg:\"\\uXXXX\") }")
506
+ end
507
+
508
+ assert_includes(e.message, "bad Unicode escape sequence")
509
+
510
+
511
+ e = assert_raises(GraphQL::ParseError) do
512
+ GraphQL.parse("{ field(arg:\"\\uFXXX\") }")
513
+ end
514
+
515
+ assert_includes(e.message, "bad Unicode escape sequence")
516
+
517
+
518
+ e = assert_raises(GraphQL::ParseError) do
519
+ GraphQL.parse("{ field(arg:\"\\uXXXF\") }")
520
+ end
521
+
522
+ assert_includes(e.message, "bad Unicode escape sequence")
523
+ end
524
+
525
+ it "rejects fragments named 'on'" do
526
+ e = assert_raises(GraphQL::ParseError) do
527
+ GraphQL.parse("fragment on on on { on }")
528
+ end
529
+
530
+ assert_includes(e.message, "Parse error on \"on\"")
531
+ end
532
+
533
+ it "rejects fragment spread of 'on'" do
534
+ e = assert_raises(GraphQL::ParseError) do
535
+ GraphQL.parse("{ ...on }")
536
+ end
537
+
538
+ assert_includes(e.message, "Parse error on \"}\"")
539
+ end
540
+
541
+ it "rejects null value" do
542
+ e = assert_raises(GraphQL::ParseError) do
543
+ GraphQL.parse("{ fieldWithNullableStringInput(input: null) }")
544
+ end
545
+
546
+ assert_includes(e.message, "Parse error on \"null\"")
547
+ end
548
+ end
549
+
550
+
551
+ describe "whitespace" do
552
+ describe "whitespace-only queries" do
553
+ let(:query_string) { " " }
554
+ it "doesn't blow up" do
555
+ assert_equal [], document.definitions
556
+ end
557
+ end
558
+
559
+ describe "empty string queries" do
560
+ let(:query_string) { "" }
561
+ it "doesn't blow up" do
562
+ assert_equal [], document.definitions
563
+ end
564
+ end
565
+
566
+ describe "using tabs as whitespace" do
567
+ let(:query_string) { "\t{\t\tid, \tname}"}
568
+ it "parses the query" do
569
+ assert_equal 1, document.definitions.length
570
+ end
571
+ end
572
+ end
573
+ end
574
+ end
575
+ end
576
+ end
577
+ end