1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package parser
16
17 import (
18 "fmt"
19 "strings"
20 "testing"
21
22 "cuelang.org/go/cue/ast"
23 )
24
25 func TestParse(t *testing.T) {
26 testCases := []struct{ desc, in, out string }{{
27
28 "ellipsis in structs",
29 `#Def: {
30 b: "2"
31 ...
32 }
33 ...
34
35 #Def2: {
36 ...
37 b: "2"
38 }
39 #Def3: {...
40 _}
41 ...
42 `,
43 `#Def: {b: "2", ...}, ..., #Def2: {..., b: "2"}, #Def3: {..., _}, ...`,
44 }, {
45
46 "empty file", "", "",
47 }, {
48 "empty struct", "{}", "{}",
49 }, {
50 "empty structs", "{},{},", "{}, {}",
51 }, {
52 "empty structs; elided comma", "{}\n{}", "{}, {}",
53 }, {
54 "basic lits", `"a","b", 3,3.4,5,2_3`, `"a", "b", 3, 3.4, 5, 2_3`,
55 }, {
56 "keyword basic lits", `true,false,null,for,in,if,let,if`, `true, false, null, for, in, if, let, if`,
57 }, {
58 "keyword basic newline", `
59 true
60 false
61 null
62 for
63 in
64 if
65 let
66 if
67 `, `true, false, null, for, in, if, let, if`,
68 }, {
69 "keywords as labels",
70 `if: 0, for: 1, in: 2, where: 3, div: 4, quo: 5, func: 6
71 for: if: func: let: 3
72 `,
73 `if: 0, for: 1, in: 2, where: 3, div: 4, quo: 5, func: 6, for: {if: {func: {let: 3}}}`,
74 }, {
75 "keywords as alias",
76 `if=foo: 0
77 for=bar: 2
78 let=bar: 3
79 func=baz: 4
80 `,
81 `if=foo: 0, for=bar: 2, let=bar: 3, func=baz: 4`,
82 }, {
83 "json",
84 `{
85 "a": 1,
86 "b": "2",
87 "c": 3
88 }`,
89 `{"a": 1, "b": "2", "c": 3}`,
90 }, {
91 "json:extra comma",
92 `{
93 "a": 1,
94 "b": "2",
95 "c": 3,
96 }`,
97 `{"a": 1, "b": "2", "c": 3}`,
98 }, {
99 "json:simplified",
100 `{
101 a: 1
102 b: "2"
103 c: 3
104 }`,
105 `{a: 1, b: "2", c: 3}`,
106 }, {
107 "attributes",
108 `a: 1 @xml(,attr)
109 b: 2 @foo(a,b=4) @go(Foo)
110 c: {
111 d: "x" @go(D) @json(,omitempty)
112 e: "y" @ts(,type=string,"str")
113 }`,
114 `a: 1 @xml(,attr), b: 2 @foo(a,b=4) @go(Foo), c: {d: "x" @go(D) @json(,omitempty), e: "y" @ts(,type=string,"str")}`,
115 }, {
116 "not emitted",
117 `a: true
118 b?: "2"
119 c?: 3
120
121 d!: 2
122 e: f!: 3
123
124 "g\("en")"?: 4
125 "h\("en")"!: 4
126 `,
127 `a: true, b?: "2", c?: 3, d!: 2, e: {f!: 3}, "g\("en")"?: 4, "h\("en")"!: 4`,
128 }, {
129 "definition",
130 `#Def: {
131 b: "2"
132 c: 3
133
134 embedding
135 }
136 #Def: {}
137 `,
138 `#Def: {b: "2", c: 3, embedding}, #Def: {}`,
139 }, {
140 "one-line embedding",
141 `{ V1, V2 }`,
142 `{V1, V2}`,
143 }, {
144 "selectors",
145 `a.b. "str"`,
146 `a.b."str"`,
147 }, {
148 "selectors",
149 `a.b. "str"`,
150 `a.b."str"`,
151 }, {
152 "faulty bytes selector",
153 `a.b.'str'`,
154 "a.b._\nexpected selector, found 'STRING' 'str'",
155 }, {
156 "faulty multiline string selector",
157 `a.b."""
158 """`,
159 "a.b._\nexpected selector, found 'STRING' \"\"\"\n\t\t\t\"\"\"",
160 }, {
161 "expression embedding",
162 `#Def: {
163 a.b.c
164 a > b < c
165 -1<2
166
167 foo: 2
168 }`,
169 `#Def: {a.b.c, a>b<c, -1<2, foo: 2}`,
170 }, {
171 "ellipsis in structs",
172 `#Def: {
173 b: "2"
174 ...
175 }
176 ...
177
178 #Def2: {
179 ...
180 b: "2"
181 }
182 #Def3: {...
183 _}
184 ...
185 `,
186 `#Def: {b: "2", ...}, ..., #Def2: {..., b: "2"}, #Def3: {..., _}, ...`,
187 }, {
188 "emitted referencing non-emitted",
189 `a: 1
190 b: "2"
191 c: 3
192 { name: b, total: a + b }`,
193 `a: 1, b: "2", c: 3, {name: b, total: a+b}`,
194 }, {
195 "package file",
196 `package k8s
197 {}
198 `,
199 `package k8s, {}`,
200 }, {
201 "imports group",
202 `package k8s
203
204 import (
205 a "foo"
206 "bar/baz"
207 )
208 `,
209 `package k8s, import ( a "foo", "bar/baz" )`,
210 }, {
211 "imports single",
212 `package k8s
213
214 import a "foo"
215 import "bar/baz"
216 `,
217 `package k8s, import a "foo", import "bar/baz"`,
218 }, {
219 "collapsed fields",
220 `a: #b: c?: [Name=_]: d: 1
221 "g\("en")"?: 4
222 // job foo { bar: 1 } // TODO error after foo
223 job: "foo": [_]: { bar: 1 }
224 `,
225 `a: {#b: {c?: {[Name=_]: {d: 1}}}}, "g\("en")"?: 4, job: {"foo": {[_]: {bar: 1}}}`,
226 }, {
227 "identifiers",
228 `// $_: 1,
229 a: {b: {c: d}}
230 c: a
231 d: a.b
232 // e: a."b" // TODO: is an error
233 e: a.b.c
234 "f": f,
235 [X=_]: X
236 `,
237 "a: {b: {c: d}}, c: a, d: a.b, e: a.b.c, \"f\": f, [X=_]: X",
238 }, {
239 "empty fields",
240 `
241 "": 3
242 `,
243 `"": 3`,
244 }, {
245 "expressions",
246 ` a: (2 + 3) * 5
247 b: (2 + 3) + 4
248 c: 2 + 3 + 4
249 d: -1
250 e: !foo
251 f: _|_
252 `,
253 "a: (2+3)*5, b: (2+3)+4, c: 2+3+4, d: -1, e: !foo, f: _|_",
254 }, {
255 "pseudo keyword expressions",
256 ` a: (2 div 3) mod 5
257 b: (2 quo 3) rem 4
258 c: 2 div 3 div 4
259 `,
260 "a: (2 div 3) mod 5, b: (2 quo 3) rem 4, c: 2 div 3 div 4",
261 }, {
262 "ranges",
263 ` a: >=1 & <=2
264 b: >2.0 & <= 40.0
265 c: >"a" & <="b"
266 v: (>=1 & <=2) & <=(>=5 & <=10)
267 w: >1 & <=2 & <=3
268 d: >=3T & <=5M
269 `,
270 "a: >=1&<=2, b: >2.0&<=40.0, c: >\"a\"&<=\"b\", v: (>=1&<=2)&<=(>=5&<=10), w: >1&<=2&<=3, d: >=3T&<=5M",
271 }, {
272 "indices",
273 `{
274 a: b[2]
275 b: c[1:2]
276 c: "asdf"
277 d: c ["a"]
278 }`,
279 `{a: b[2], b: c[1:2], c: "asdf", d: c["a"]}`,
280 }, {
281 "calls",
282 `{
283 a: b(a.b, c.d)
284 b: a.b(c)
285 }`,
286 `{a: b(a.b, c.d), b: a.b(c)}`,
287 }, {
288 "lists",
289 `{
290 a: [ 1, 2, 3, b, c, ... ]
291 b: [ 1, 2, 3, ],
292 c: [ 1,
293 2,
294 3
295 ],
296 d: [ 1+2, 2, 4,]
297 }`,
298 `{a: [1, 2, 3, b, c, ...], b: [1, 2, 3], c: [1, 2, 3], d: [1+2, 2, 4]}`,
299 }, {
300 "list types",
301 `{
302 a: 4*[int]
303 b: <=5*[{a: 5}]
304 c1: [...int]
305 c2: [...]
306 c3: [1, 2, ...int,]
307 }`,
308 `{a: 4*[int], b: <=5*[{a: 5}], c1: [...int], c2: [...], c3: [1, 2, ...int]}`,
309 }, {
310 "list comprehensions",
311 `{
312 y: [1,2,3]
313 b: [for x in y if x == 1 { x }],
314 }`,
315 `{y: [1, 2, 3], b: [for x in y if x==1 {x}]}`,
316 }, {
317 "field comprehensions",
318 `{
319 y: { a: 1, b: 2}
320 a: {
321 for k, v in y if v > 2 {
322 "\(k)": v
323 }
324 }
325 }`,
326 `{y: {a: 1, b: 2}, a: {for k: v in y if v>2 {"\(k)": v}}}`,
327 }, {
328 "nested comprehensions",
329 `{
330 y: { a: 1, b: 2}
331 a: {
332 for k, v in y let x = v+2 if x > 2 {
333 "\(k)": v
334 }
335 }
336 }`,
337 `{y: {a: 1, b: 2}, a: {for k: v in y let x=v+2 if x>2 {"\(k)": v}}}`,
338 }, {
339 "let declaration",
340 `{
341 let X = 42
342 let Y = "42",
343 let Z = 10 + 12
344 }`,
345 `{let X=42, let Y="42", let Z=10+12}`,
346 }, {
347 "duplicates allowed",
348 `{
349 a: b: 3
350 a: { b: 3 }
351 }`,
352 "{a: {b: 3}, a: {b: 3}}",
353 }, {
354 "templates",
355 `{
356 [foo=_]: { a: int }
357 a: { a: 1 }
358 }`,
359 "{[foo=_]: {a: int}, a: {a: 1}}",
360 }, {
361 "value alias",
362 `
363 {
364 a: X=foo
365 b: Y={foo}
366 c: d: e: X=5
367 }
368 `,
369 `{a: X=foo, b: Y={foo}, c: {d: {e: X=5}}}`,
370 }, {
371 "dynamic labels",
372 `{
373 (x): a: int
374 x: "foo"
375 a: {
376 (a.b)
377 }
378
379 (x)?: 1
380 y: (x)!: 2
381 }`,
382 `{(x): {a: int}, x: "foo", a: {(a.b)}, (x)?: 1, y: {(x)!: 2}}`,
383 }, {
384 "foo",
385 `[
386 [1],
387 [1, 2],
388 [1, 2, 3],
389 ]`,
390 "[[1], [1, 2], [1, 2, 3]]",
391 }, {
392 "interpolation",
393 `a: "foo \(ident)"
394 b: "bar \(bar) $$$ "
395 c: "nest \( { a: "\( nest ) "}.a ) \(5)"
396 m1: """
397 multi \(bar)
398 """
399 m2: '''
400 \(bar) multi
401 '''`,
402 `a: "foo \(ident)", b: "bar \(bar) $$$ ", c: "nest \({a: "\(nest) "}.a) \(5)", ` + "m1: \"\"\"\n\t\t\t multi \\(bar)\n\t\t\t \"\"\", m2: '''\n\t\t\t \\(bar) multi\n\t\t\t '''",
403 }, {
404 "file comments",
405 `// foo
406
407 // uni
408 package foo // uniline
409
410 // file.1
411 // file.2
412
413 `,
414 "<[0// foo] <[d0// uni] [l3// uniline] [3// file.1 // file.2] package foo>>",
415 }, {
416 "line comments",
417 `// doc
418 a: 5 // line
419 b: 6 // lineb
420 // next
421 `,
422 "<[d0// doc] [l5// line] a: 5>, " +
423 "<[l5// lineb] [5// next] b: 6>",
424 }, {
425 "alt comments",
426 `// a ...
427 a: 5 // line a
428
429 // about a
430
431 // b ...
432 b: // lineb
433 6
434
435 // about b
436
437 c: 7
438
439 // about c
440
441 // about d
442 d:
443 // about e
444 e: 3
445 `,
446 "<[d0// a ...] [l5// line a] [5// about a] a: 5>, " +
447 "<[d0// b ...] [l2// lineb] [5// about b] b: 6>, " +
448 "<[5// about c] c: 7>, " +
449 "<[d0// about d] d: {<[d0// about e] e>: 3}>",
450 }, {
451 "expr comments",
452 `
453 a: 2 + // 2 +
454 3 + // 3 +
455 4 // 4
456 `,
457 "<[l5// 4] a: <[l2// 3 +] <[l2// 2 +] 2+3>+4>>",
458 }, {
459 "composit comments",
460 `a : {
461 a: 1, b: 2, c: 3, d: 4
462 // end
463 }
464 b: [
465 1, 2, 3, 4, 5,
466 // end
467 ]
468 c: [ 1, 2, 3, 4, // here
469 { a: 3 }, // here
470 5, 6, 7, 8 // and here
471 ]
472 d: {
473 a: 1 // Hello
474 // Doc
475 b: 2
476 }
477 e1: [
478 // comment in list body
479 ]
480 e2: {
481 // comment in struct body
482 }
483 `,
484 "a: {a: 1, b: 2, c: 3, <[d5// end] d: 4>}, " +
485 "b: [1, 2, 3, 4, <[d2// end] 5>], " +
486 "c: [1, 2, 3, <[l2// here] 4>, <[l4// here] {a: 3}>, 5, 6, 7, <[l2// and here] 8>], " +
487 "d: {<[l5// Hello] a: 1>, <[d0// Doc] b: 2>}, " +
488 "e1: <[d1// comment in list body] []>, " +
489 "e2: <[d1// comment in struct body] {}>",
490 }, {
491 "attribute comments",
492 `
493 a: 1 @a() @b() // d
494 `,
495 `<[l5// d] a: 1 @a() @b()>`,
496 }, {
497 "attribute declarations",
498 `
499 @foo()
500
501 package bar
502
503 @bar()
504
505 import "strings"
506
507 @baz()
508 `,
509 `@foo(), package bar, @bar(), import "strings", @baz()`,
510 }, {
511 "comprehension comments",
512 `
513 if X {
514 // Comment 1
515 Field: 2
516 // Comment 2
517 }
518 `,
519 `if X <[d2// Comment 2] {<[d0// Comment 1] Field: 2>}>`,
520 }, {
521 "let comments",
522 `let X = foo // Comment 1`,
523 `<[5// Comment 1] let X=foo>`,
524 }, {
525 "emit comments",
526 `// a comment at the beginning of the file
527
528 // a second comment
529
530 // comment
531 a: 5
532
533 {}
534
535 // a comment at the end of the file
536 `,
537 "<[0// a comment at the beginning of the file] [0// a second comment] <[d0// comment] a: 5>, <[2// a comment at the end of the file] {}>>",
538 }, {
539 "composite comments 2",
540 `
541 {
542 // foo
543
544 // fooo
545 foo: 1
546
547 bar: 2
548 }
549
550 [
551 {"name": "value"}, // each element has a long
552 {"name": "next"} // optional next element
553 ]
554 `,
555 `{<[0// foo] [d0// fooo] foo: 1>, bar: 2}, [<[l4// each element has a long] {"name": "value"}>, <[l4// optional next element] {"name": "next"}>]`,
556 }, {
557 desc: "field aliasing",
558 in: `
559 I="\(k)": v
560 S="foo-bar": w
561 L=foo: x
562 X=[0]: {
563 foo: X | null
564 }
565 [Y=string]: { name: Y }
566 X1=[X2=<"d"]: { name: X2 }
567 Y1=foo: Y2=bar: [Y1, Y2]
568 `,
569 out: `I="\(k)": v, ` +
570 `S="foo-bar": w, ` +
571 `L=foo: x, ` +
572 `X=[0]: {foo: X|null}, ` +
573 `[Y=string]: {name: Y}, ` +
574 `X1=[X2=<"d"]: {name: X2}, ` +
575 `Y1=foo: {Y2=bar: [Y1, Y2]}`,
576 }, {
577 desc: "allow keyword in expression",
578 in: `
579 foo: in & 2
580 `,
581 out: "foo: in&2",
582 }, {
583 desc: "dot import",
584 in: `
585 import . "foo"
586 `,
587 out: "import , \"foo\"\nexpected 'STRING', found '.'",
588 }, {
589 desc: "attributes",
590 in: `
591 package name
592
593 @t1(v1)
594
595 {
596 @t2(v2)
597 }
598 a: {
599 a: 1
600 @t3(v3)
601 @t4(v4)
602 c: 2
603 }
604 `,
605 out: "package name, @t1(v1), {@t2(v2)}, a: {a: 1, @t3(v3), @t4(v4), c: 2}",
606 }, {
607 desc: "Issue #276",
608 in: `
609 a: int=>2
610 `,
611 out: "a: int=>2",
612 }, {
613 desc: "struct comments",
614 in: `
615 struct: {
616 // This is a comment
617
618 // This is a comment
619
620 // Another comment
621 something: {
622 }
623
624 // extra comment
625 }`,
626 out: `struct: {<[0// This is a comment] [0// This is a comment] [d0// Another comment] [d5// extra comment] something: {}>}`,
627 }, {
628 desc: "list comments",
629 in: `
630 list: [
631 // Comment1
632
633 // Comment2
634
635 // Another comment
636 {
637 },
638
639 // Comment 3
640 ]`,
641 out: "list: [<[0// Comment1] [0// Comment2] [d0// Another comment] [d3// Comment 3] {}>]",
642 }, {
643 desc: "call comments",
644 in: `
645 funcArg1: foo(
646 {},
647
648 // Comment1
649
650 // Comment2
651 {}
652
653 // Comment3
654 )`,
655 out: "funcArg1: foo(<[1// Comment1] {}>, <[d0// Comment2] [d1// Comment3] {}>)",
656 }, {
657 desc: "front-style commas",
658 in: `
659 frontStyle: { "key": "value"
660 , "key2": "value2"
661 , "foo" : bar
662 }
663 `,
664 out: "frontStyle: {\"key\": \"value\", \"key2\": \"value2\", \"foo\": bar}",
665 }, {
666 desc: "function types",
667 in: `
668 f0: func(): int
669 f1: func(int): int
670 f2: func(int, string): int
671 f3: func({a: int, b: string}): bool
672 f4: func(bool, func(int, string): int): string
673 f5: func(int, int): func(bool, bool): bool
674 f6: func(func(bool, bool): bool, func(string, string): string): func(int, func(int, string): int): func(int, string): int
675 `,
676 out: "f0: func(): int, f1: func(int): int, f2: func(int, string): int, f3: func({a: int, b: string}): bool, f4: func(bool, func(int, string): int): string, f5: func(int, int): func(bool, bool): bool, f6: func(func(bool, bool): bool, func(string, string): string): func(int, func(int, string): int): func(int, string): int",
677 }}
678 for _, tc := range testCases {
679 t.Run(tc.desc, func(t *testing.T) {
680 mode := []Option{AllErrors}
681 if strings.Contains(tc.desc, "comments") {
682 mode = append(mode, ParseComments)
683 }
684 if strings.Contains(tc.desc, "function") {
685 mode = append(mode, ParseFuncs)
686 }
687 f, err := ParseFile("input", tc.in, mode...)
688 got := debugStr(f)
689 if err != nil {
690 got += "\n" + err.Error()
691 }
692 if got != tc.out {
693 t.Errorf("\ngot %q;\nwant %q", got, tc.out)
694 }
695 })
696 }
697 }
698
699 func TestStrict(t *testing.T) {
700 testCases := []struct{ desc, in string }{
701 {"block comments",
702 `a: 1 /* a */`},
703 {"space separator",
704 `a b c: 2`},
705 {"reserved identifiers",
706 `__foo: 3`},
707 {"old-style alias 1",
708 `X=3`},
709 {"old-style alias 2",
710 `X={}`},
711
712
713 {"additional typed not yet supported",
714 `{...int}`},
715 }
716 for _, tc := range testCases {
717 t.Run(tc.desc, func(t *testing.T) {
718 mode := []Option{AllErrors, ParseComments, FromVersion(Latest)}
719 _, err := ParseFile("input", tc.in, mode...)
720 if err == nil {
721 t.Errorf("unexpected success: %v", tc.in)
722 }
723 })
724 }
725 }
726
727 func TestParseExpr(t *testing.T) {
728
729
730 src := "a + b"
731 x, err := parseExprString(src)
732 if err != nil {
733 t.Errorf("ParseExpr(%q): %v", src, err)
734 }
735
736 if _, ok := x.(*ast.BinaryExpr); !ok {
737 t.Errorf("ParseExpr(%q): got %T, want *BinaryExpr", src, x)
738 }
739
740
741 src = "a + *"
742 if _, err := parseExprString(src); err == nil {
743 t.Errorf("ParseExpr(%q): got no error", src)
744 }
745
746
747 src = "a + b\n"
748 if _, err := parseExprString(src); err != nil {
749 t.Errorf("ParseExpr(%q): got error %s", src, err)
750 }
751 src = "a + b;"
752 if _, err := parseExprString(src); err == nil {
753 t.Errorf("ParseExpr(%q): got no error", src)
754 }
755
756
757 src = "{ foo: bar, bar: foo }"
758 x, err = parseExprString(src)
759 if err != nil {
760 t.Fatalf("ParseExpr(%q): %v", src, err)
761 }
762 for _, d := range x.(*ast.StructLit).Elts {
763 v := d.(*ast.Field).Value.(*ast.Ident)
764 if v.Scope == nil {
765 t.Errorf("ParseExpr(%q): scope of field %v not set", src, v.Name)
766 }
767 if v.Node == nil {
768 t.Errorf("ParseExpr(%q): scope of node %v not set", src, v.Name)
769 }
770 }
771
772
773 const validExpr = "a + b"
774 const anything = "dh3*#D)#_"
775 for _, c := range "!)]};," {
776 src := validExpr + string(c) + anything
777 if _, err := parseExprString(src); err == nil {
778 t.Errorf("ParseExpr(%q): got no error", src)
779 }
780 }
781
782
783 for _, src := range valids {
784 _, _ = parseExprString(src)
785 }
786 }
787
788 func TestImports(t *testing.T) {
789 var imports = map[string]bool{
790 `"a"`: true,
791 `"a/b"`: true,
792 `"a.b"`: true,
793 `'m\x61th'`: true,
794 `"greek/αβ"`: true,
795 `""`: false,
796
797
798
799
800
801
802 `#"a"#`: true,
803 `"\x00"`: false,
804 "'\x00'": false,
805 `"\x7f"`: false,
806 "`\x7f`": false,
807 `"a!"`: false,
808 "#'a!'#": false,
809 `"a b"`: false,
810 `#"a b"#`: false,
811 `"a\\b"`: false,
812 "#\"a\\b\"#": false,
813 "\"`a`\"": false,
814 "#'\"a\"'#": false,
815 `"\x80\x80"`: false,
816 "#'\x80\x80'#": false,
817 `"\xFFFD"`: false,
818 "#'\xFFFD'#": false,
819 }
820 for path, isValid := range imports {
821 t.Run(path, func(t *testing.T) {
822 src := fmt.Sprintf("package p, import %s", path)
823 _, err := ParseFile("", src)
824 switch {
825 case err != nil && isValid:
826 t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
827 case err == nil && !isValid:
828 t.Errorf("ParseFile(%s): got no error; expected one", src)
829 }
830 })
831 }
832 }
833
834
835
836
837 func TestIncompleteSelection(t *testing.T) {
838 for _, src := range []string{
839 "{ a: fmt. }",
840 "{ a: fmt.\n0.0: x }",
841 } {
842 t.Run("", func(t *testing.T) {
843 f, err := ParseFile("", src)
844 if err == nil {
845 t.Fatalf("ParseFile(%s) succeeded unexpectedly", src)
846 }
847
848 const wantErr = "expected selector"
849 if !strings.Contains(err.Error(), wantErr) {
850 t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
851 }
852
853 var sel *ast.SelectorExpr
854 ast.Walk(f, func(n ast.Node) bool {
855 if n, ok := n.(*ast.SelectorExpr); ok {
856 sel = n
857 }
858 return true
859 }, nil)
860 if sel == nil {
861 t.Fatalf("found no *SelectorExpr: %#v %s", f.Decls[0], debugStr(f))
862 }
863 const wantSel = "&{fmt _ {<nil>} {{}}}"
864 if fmt.Sprint(sel) != wantSel {
865 t.Fatalf("found selector %v, want %s", sel, wantSel)
866 }
867 })
868 }
869 }
870
871
872 func TestX(t *testing.T) {
873 t.Skip()
874
875 f, err := ParseFile("input", `
876 `, ParseComments)
877 if err != nil {
878 t.Errorf("unexpected error: %v", err)
879 }
880 t.Error(debugStr(f))
881 }
882
View as plain text