1
2
3
4
5 package doc
6
7 import (
8 "bytes"
9 "flag"
10 "internal/testenv"
11 "log"
12 "os"
13 "path/filepath"
14 "regexp"
15 "runtime"
16 "strings"
17 "testing"
18
19 "cmd/go/internal/cfg"
20 )
21
22 func TestMain(m *testing.M) {
23
24 cfg.BuildContext.GOPATH = ""
25 testGOPATH = true
26
27
28
29
30 cfg.GOROOT = testenv.GOROOT(nil)
31
32
33
34
35 testdataDir, err := filepath.Abs("testdata")
36 if err != nil {
37 panic(err)
38 }
39 dirsInit(
40 Dir{importPath: "cmd/go/internal/doc/testdata", dir: testdataDir},
41 Dir{importPath: "cmd/go/internal/doc/testdata/nested", dir: filepath.Join(testdataDir, "nested")},
42 Dir{importPath: "cmd/go/internal/doc/testdata/nested/nested", dir: filepath.Join(testdataDir, "nested", "nested")})
43
44 os.Exit(m.Run())
45 }
46
47 func maybeSkip(t *testing.T) {
48 if runtime.GOOS == "ios" {
49 t.Skip("iOS does not have a full file tree")
50 }
51 }
52
53 type isDotSlashTest struct {
54 str string
55 result bool
56 }
57
58 var isDotSlashTests = []isDotSlashTest{
59 {``, false},
60 {`x`, false},
61 {`...`, false},
62 {`.../`, false},
63 {`...\`, false},
64
65 {`.`, true},
66 {`./`, true},
67 {`.\`, true},
68 {`./x`, true},
69 {`.\x`, true},
70
71 {`..`, true},
72 {`../`, true},
73 {`..\`, true},
74 {`../x`, true},
75 {`..\x`, true},
76 }
77
78 func TestIsDotSlashPath(t *testing.T) {
79 for _, test := range isDotSlashTests {
80 if result := isDotSlash(test.str); result != test.result {
81 t.Errorf("isDotSlash(%q) = %t; expected %t", test.str, result, test.result)
82 }
83 }
84 }
85
86 type test struct {
87 name string
88 args []string
89 yes []string
90 no []string
91 }
92
93 const p = "cmd/go/internal/doc/testdata"
94
95 var tests = []test{
96
97 {
98 "sanity check",
99 []string{p},
100 []string{`type ExportedType struct`},
101 nil,
102 },
103
104
105 {
106 "package clause",
107 []string{p},
108 []string{`package pkg.*cmd/go/internal/doc/testdata`},
109 nil,
110 },
111
112
113
114 {
115 "full package",
116 []string{p},
117 []string{
118 `Package comment`,
119 `const ExportedConstant = 1`,
120 `const ConstOne = 1`,
121 `const ConstFive ...`,
122 `var ExportedVariable = 1`,
123 `var VarOne = 1`,
124 `func ExportedFunc\(a int\) bool`,
125 `func ReturnUnexported\(\) unexportedType`,
126 `type ExportedType struct{ ... }`,
127 `const ExportedTypedConstant ExportedType = iota`,
128 `const ExportedTypedConstant_unexported unexportedType`,
129 `const ConstLeft2 uint64 ...`,
130 `const ConstGroup1 unexportedType = iota ...`,
131 `const ConstGroup4 ExportedType = ExportedType{}`,
132 `const MultiLineConst = ...`,
133 `var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`,
134 `func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`,
135 `var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`,
136 `type T1 = T2`,
137 `type SimpleConstraint interface{ ... }`,
138 `type TildeConstraint interface{ ... }`,
139 `type StructConstraint interface{ ... }`,
140 },
141 []string{
142 `const internalConstant = 2`,
143 `var internalVariable = 2`,
144 `func internalFunc(a int) bool`,
145 `Comment about exported constant`,
146 `Comment about exported variable`,
147 `Comment about block of constants`,
148 `Comment about block of variables`,
149 `Comment before ConstOne`,
150 `Comment before VarOne`,
151 `ConstTwo = 2`,
152 `VarTwo = 2`,
153 `VarFive = 5`,
154 `type unexportedType`,
155 `unexportedTypedConstant`,
156 `\bField`,
157 `Method`,
158 `someArgument[5-8]`,
159 `type T1 T2`,
160 `ignore:directive`,
161 },
162 },
163
164 {
165 "full package",
166 []string{"-all", p},
167 []string{
168 `package pkg .*import`,
169 `Package comment`,
170 `CONSTANTS`,
171 `Comment before ConstOne`,
172 `ConstOne = 1`,
173 `ConstTwo = 2 // Comment on line with ConstTwo`,
174 `ConstFive`,
175 `ConstSix`,
176 `Const block where first entry is unexported`,
177 `ConstLeft2, constRight2 uint64`,
178 `constLeft3, ConstRight3`,
179 `ConstLeft4, ConstRight4`,
180 `Duplicate = iota`,
181 `const CaseMatch = 1`,
182 `const Casematch = 2`,
183 `const ExportedConstant = 1`,
184 `const MultiLineConst = `,
185 `MultiLineString1`,
186 `VARIABLES`,
187 `Comment before VarOne`,
188 `VarOne = 1`,
189 `Comment about block of variables`,
190 `VarFive = 5`,
191 `var ExportedVariable = 1`,
192 `var ExportedVarOfUnExported unexportedType`,
193 `var LongLine = newLongLine\(`,
194 `var MultiLineVar = map\[struct {`,
195 `FUNCTIONS`,
196 `func ExportedFunc\(a int\) bool`,
197 `Comment about exported function`,
198 `func MultiLineFunc\(x interface`,
199 `func ReturnUnexported\(\) unexportedType`,
200 `TYPES`,
201 `type ExportedInterface interface`,
202 `type ExportedStructOneField struct`,
203 `type ExportedType struct`,
204 `Comment about exported type`,
205 `const ConstGroup4 ExportedType = ExportedType`,
206 `ExportedTypedConstant ExportedType = iota`,
207 `Constants tied to ExportedType`,
208 `func ExportedTypeConstructor\(\) \*ExportedType`,
209 `Comment about constructor for exported type`,
210 `func ReturnExported\(\) ExportedType`,
211 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
212 `Comment about exported method`,
213 `type T1 = T2`,
214 `type T2 int`,
215 `type SimpleConstraint interface {`,
216 `type TildeConstraint interface {`,
217 `type StructConstraint interface {`,
218 `BUG: function body note`,
219 },
220 []string{
221 `constThree`,
222 `_, _ uint64 = 2 \* iota, 1 << iota`,
223 `constLeft1, constRight1`,
224 `duplicate`,
225 `varFour`,
226 `func internalFunc`,
227 `unexportedField`,
228 `func \(unexportedType\)`,
229 `ignore:directive`,
230 },
231 },
232
233 {
234 "only package declaration",
235 []string{"-all", p + "/nested/empty"},
236 []string{`package empty .*import`},
237 nil,
238 },
239
240 {
241 "full package with -short",
242 []string{`-short`, p},
243 []string{
244 `const ExportedConstant = 1`,
245 `func ReturnUnexported\(\) unexportedType`,
246 },
247 []string{
248 `MultiLine(String|Method|Field)`,
249 },
250 },
251
252 {
253 "full package with u",
254 []string{`-u`, p},
255 []string{
256 `const ExportedConstant = 1`,
257 `const internalConstant = 2`,
258 `func internalFunc\(a int\) bool`,
259 `func ReturnUnexported\(\) unexportedType`,
260 },
261 []string{
262 `Comment about exported constant`,
263 `Comment about block of constants`,
264 `Comment about internal function`,
265 `MultiLine(String|Method|Field)`,
266 `ignore:directive`,
267 },
268 },
269
270 {
271 "full package",
272 []string{"-u", "-all", p},
273 []string{
274 `package pkg .*import`,
275 `Package comment`,
276 `CONSTANTS`,
277 `Comment before ConstOne`,
278 `ConstOne += 1`,
279 `ConstTwo += 2 // Comment on line with ConstTwo`,
280 `constThree = 3 // Comment on line with constThree`,
281 `ConstFive`,
282 `const internalConstant += 2`,
283 `Comment about internal constant`,
284 `VARIABLES`,
285 `Comment before VarOne`,
286 `VarOne += 1`,
287 `Comment about block of variables`,
288 `varFour += 4`,
289 `VarFive += 5`,
290 `varSix += 6`,
291 `var ExportedVariable = 1`,
292 `var LongLine = newLongLine\(`,
293 `var MultiLineVar = map\[struct {`,
294 `var internalVariable = 2`,
295 `Comment about internal variable`,
296 `FUNCTIONS`,
297 `func ExportedFunc\(a int\) bool`,
298 `Comment about exported function`,
299 `func MultiLineFunc\(x interface`,
300 `func internalFunc\(a int\) bool`,
301 `Comment about internal function`,
302 `func newLongLine\(ss .*string\)`,
303 `TYPES`,
304 `type ExportedType struct`,
305 `type T1 = T2`,
306 `type T2 int`,
307 `type unexportedType int`,
308 `Comment about unexported type`,
309 `ConstGroup1 unexportedType = iota`,
310 `ConstGroup2`,
311 `ConstGroup3`,
312 `ExportedTypedConstant_unexported unexportedType = iota`,
313 `Constants tied to unexportedType`,
314 `const unexportedTypedConstant unexportedType = 1`,
315 `func ReturnUnexported\(\) unexportedType`,
316 `func \(unexportedType\) ExportedMethod\(\) bool`,
317 `func \(unexportedType\) unexportedMethod\(\) bool`,
318 },
319 []string{
320 `ignore:directive`,
321 },
322 },
323
324
325 {
326 "single constant",
327 []string{p, `ExportedConstant`},
328 []string{
329 `Comment about exported constant`,
330 `const ExportedConstant = 1`,
331 },
332 nil,
333 },
334
335 {
336 "single constant with -u",
337 []string{`-u`, p, `internalConstant`},
338 []string{
339 `Comment about internal constant`,
340 `const internalConstant = 2`,
341 },
342 nil,
343 },
344
345 {
346 "block of constants",
347 []string{p, `ConstTwo`},
348 []string{
349 `Comment before ConstOne.\n.*ConstOne = 1`,
350 `ConstTwo = 2.*Comment on line with ConstTwo`,
351 `Comment about block of constants`,
352 },
353 []string{
354 `constThree`,
355 },
356 },
357
358 {
359 "block of constants with -u",
360 []string{"-u", p, `constThree`},
361 []string{
362 `constThree = 3.*Comment on line with constThree`,
363 },
364 nil,
365 },
366
367 {
368 "block of constants with -src",
369 []string{"-src", p, `ConstTwo`},
370 []string{
371 `Comment about block of constants`,
372 `ConstOne.*=.*1`,
373 `ConstTwo.*=.*2.*Comment on line with ConstTwo`,
374 `constThree`,
375 },
376 nil,
377 },
378
379 {
380 "block of constants with carryover type",
381 []string{p, `ConstLeft2`},
382 []string{
383 `ConstLeft2, constRight2 uint64`,
384 `constLeft3, ConstRight3`,
385 `ConstLeft4, ConstRight4`,
386 },
387 nil,
388 },
389
390 {
391 "block of constants with carryover type",
392 []string{"-u", p, `ConstLeft2`},
393 []string{
394 `_, _ uint64 = 2 \* iota, 1 << iota`,
395 `constLeft1, constRight1`,
396 `ConstLeft2, constRight2`,
397 `constLeft3, ConstRight3`,
398 `ConstLeft4, ConstRight4`,
399 },
400 nil,
401 },
402
403
404 {
405 "single variable",
406 []string{p, `ExportedVariable`},
407 []string{
408 `ExportedVariable`,
409 `var ExportedVariable = 1`,
410 },
411 nil,
412 },
413
414 {
415 "single variable with -u",
416 []string{`-u`, p, `internalVariable`},
417 []string{
418 `Comment about internal variable`,
419 `var internalVariable = 2`,
420 },
421 nil,
422 },
423
424 {
425 "block of variables",
426 []string{p, `VarTwo`},
427 []string{
428 `Comment before VarOne.\n.*VarOne = 1`,
429 `VarTwo = 2.*Comment on line with VarTwo`,
430 `Comment about block of variables`,
431 },
432 []string{
433 `varThree= 3`,
434 },
435 },
436
437 {
438 "block of variables with -u",
439 []string{"-u", p, `varThree`},
440 []string{
441 `varThree = 3.*Comment on line with varThree`,
442 },
443 nil,
444 },
445
446
447 {
448 "function",
449 []string{p, `ExportedFunc`},
450 []string{
451 `Comment about exported function`,
452 `func ExportedFunc\(a int\) bool`,
453 },
454 nil,
455 },
456
457 {
458 "function with -u",
459 []string{"-u", p, `internalFunc`},
460 []string{
461 `Comment about internal function`,
462 `func internalFunc\(a int\) bool`,
463 },
464 nil,
465 },
466
467 {
468 "function with -src",
469 []string{"-src", p, `ExportedFunc`},
470 []string{
471 `Comment about exported function`,
472 `func ExportedFunc\(a int\) bool`,
473 `return true != false`,
474 },
475 nil,
476 },
477
478
479 {
480 "type",
481 []string{p, `ExportedType`},
482 []string{
483 `Comment about exported type`,
484 `type ExportedType struct`,
485 `Comment before exported field.*\n.*ExportedField +int` +
486 `.*Comment on line with exported field`,
487 `ExportedEmbeddedType.*Comment on line with exported embedded field`,
488 `Has unexported fields`,
489 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
490 `const ExportedTypedConstant ExportedType = iota`,
491 `func ExportedTypeConstructor\(\) \*ExportedType`,
492 `io.Reader.*Comment on line with embedded Reader`,
493 },
494 []string{
495 `unexportedField`,
496 `int.*embedded`,
497 `Comment about exported method`,
498 `unexportedMethod`,
499 `unexportedTypedConstant`,
500 `error`,
501 },
502 },
503
504 {
505 "type",
506 []string{"-src", p, `ExportedType`},
507 []string{
508 `Comment about exported type`,
509 `type ExportedType struct`,
510 `Comment before exported field`,
511 `ExportedField.*Comment on line with exported field`,
512 `ExportedEmbeddedType.*Comment on line with exported embedded field`,
513 `unexportedType.*Comment on line with unexported embedded field`,
514 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
515 `const ExportedTypedConstant ExportedType = iota`,
516 `func ExportedTypeConstructor\(\) \*ExportedType`,
517 `io.Reader.*Comment on line with embedded Reader`,
518 },
519 []string{
520 `Comment about exported method`,
521 `unexportedMethod`,
522 `unexportedTypedConstant`,
523 },
524 },
525
526 {
527 "type",
528 []string{"-all", p, `ExportedType`},
529 []string{
530 `type ExportedType struct {`,
531 `Comment about exported type`,
532 `const ConstGroup4 ExportedType = ExportedType\{\}`,
533 `ExportedTypedConstant ExportedType = iota`,
534 `Constants tied to ExportedType`,
535 `func ExportedTypeConstructor\(\) \*ExportedType`,
536 `Comment about constructor for exported type.`,
537 `func ReturnExported\(\) ExportedType`,
538 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
539 `Comment about exported method.`,
540 `func \(ExportedType\) Uncommented\(a int\) bool\n\n`,
541 },
542 []string{
543 `unexportedType`,
544 },
545 },
546
547 {
548 "type T1",
549 []string{p + ".T1"},
550 []string{
551 `type T1 = T2`,
552 },
553 []string{
554 `type T1 T2`,
555 `type ExportedType`,
556 },
557 },
558
559 {
560 "type with unexported fields and -u",
561 []string{"-u", p, `ExportedType`},
562 []string{
563 `Comment about exported type`,
564 `type ExportedType struct`,
565 `Comment before exported field.*\n.*ExportedField +int`,
566 `unexportedField.*int.*Comment on line with unexported field`,
567 `ExportedEmbeddedType.*Comment on line with exported embedded field`,
568 `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`,
569 `\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`,
570 `unexportedType.*Comment on line with unexported embedded field`,
571 `\*unexportedType.*Comment on line with unexported embedded \*field`,
572 `io.Reader.*Comment on line with embedded Reader`,
573 `error.*Comment on line with embedded error`,
574 `func \(ExportedType\) unexportedMethod\(a int\) bool`,
575 `unexportedTypedConstant`,
576 },
577 []string{
578 `Has unexported fields`,
579 },
580 },
581
582 {
583 "unexported type with -u",
584 []string{"-u", p, `unexportedType`},
585 []string{
586 `Comment about unexported type`,
587 `type unexportedType int`,
588 `func \(unexportedType\) ExportedMethod\(\) bool`,
589 `func \(unexportedType\) unexportedMethod\(\) bool`,
590 `ExportedTypedConstant_unexported unexportedType = iota`,
591 `const unexportedTypedConstant unexportedType = 1`,
592 },
593 nil,
594 },
595
596
597 {
598 "interface type",
599 []string{p, `ExportedInterface`},
600 []string{
601 `Comment about exported interface`,
602 `type ExportedInterface interface`,
603 `Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` +
604 `.*Comment on line with exported method`,
605 `io.Reader.*Comment on line with embedded Reader`,
606 `error.*Comment on line with embedded error`,
607 `Has unexported methods`,
608 },
609 []string{
610 `unexportedField`,
611 `Comment about exported method`,
612 `unexportedMethod`,
613 `unexportedTypedConstant`,
614 },
615 },
616
617 {
618 "interface type with unexported methods and -u",
619 []string{"-u", p, `ExportedInterface`},
620 []string{
621 `Comment about exported interface`,
622 `type ExportedInterface interface`,
623 `Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` + `.*Comment on line with exported method`,
624 `unexportedMethod\(\).*Comment on line with unexported method`,
625 `io.Reader.*Comment on line with embedded Reader`,
626 `error.*Comment on line with embedded error`,
627 },
628 []string{
629 `Has unexported methods`,
630 },
631 },
632
633 {
634 "interface type with comparable",
635 []string{p, `ExportedComparableInterface`},
636 []string{
637 `Comment about exported interface with comparable`,
638 `type ExportedComparableInterface interface`,
639 `comparable.*Comment on line with comparable`,
640 `ExportedMethod\(\).*Comment on line with exported method`,
641 `Has unexported methods`,
642 },
643 []string{
644 `unexportedMethod`,
645 },
646 },
647
648 {
649 "interface type with comparable only",
650 []string{p, `ExportedComparableOnlyInterface`},
651 []string{
652 `ExportedComparableOnlyInterface has only comparable`,
653 `type ExportedComparableOnlyInterface interface`,
654 `comparable.*Comment on line with comparable`,
655 `ExportedMethod\(\).*Comment on line with exported method`,
656 },
657 []string{
658 `Has unexported methods`,
659 },
660 },
661
662
663 {
664 "interface method",
665 []string{p, `ExportedInterface.ExportedMethod`},
666 []string{
667 `Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` +
668 `.*Comment on line with exported method`,
669 },
670 []string{
671 `Comment about exported interface`,
672 },
673 },
674
675 {
676 "interface method at package level",
677 []string{p, `ExportedMethod`},
678 []string{
679 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
680 `Comment about exported method`,
681 },
682 []string{
683 `Comment before exported method.*\n.*ExportedMethod\(\)` +
684 `.*Comment on line with exported method`,
685 },
686 },
687
688
689 {
690 "method",
691 []string{p, `ExportedType.ExportedMethod`},
692 []string{
693 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
694 `Comment about exported method`,
695 },
696 nil,
697 },
698
699 {
700 "method with -u",
701 []string{"-u", p, `ExportedType.unexportedMethod`},
702 []string{
703 `func \(ExportedType\) unexportedMethod\(a int\) bool`,
704 `Comment about unexported method`,
705 },
706 nil,
707 },
708
709 {
710 "method with -src",
711 []string{"-src", p, `ExportedType.ExportedMethod`},
712 []string{
713 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
714 `Comment about exported method`,
715 `return true != true`,
716 },
717 nil,
718 },
719
720
721 {
722 "field",
723 []string{p, `ExportedType.ExportedField`},
724 []string{
725 `type ExportedType struct`,
726 `ExportedField int`,
727 `Comment before exported field`,
728 `Comment on line with exported field`,
729 `other fields elided`,
730 },
731 nil,
732 },
733
734
735 {
736 "method with -u",
737 []string{"-u", p, `ExportedType.unexportedField`},
738 []string{
739 `unexportedField int`,
740 `Comment on line with unexported field`,
741 },
742 nil,
743 },
744
745
746 {
747 "single-field struct",
748 []string{p, `ExportedStructOneField.OnlyField`},
749 []string{`the only field`},
750 []string{`other fields elided`},
751 },
752
753
754 {
755 "package with -ex",
756 []string{`-ex`, p},
757 []string{
758 `func ExampleExportedFunc\(\)`,
759 `func ExampleExportedType\(\)`,
760 `func Example\(\)`,
761 `func Example_multiline\(\)`,
762 `func Example_playable\(\)`,
763 },
764 nil,
765 },
766
767
768 {
769 "type with -ex",
770 []string{`-ex`, p, `ExportedType`},
771 []string{
772 `func ExampleExportedType\(\)`,
773 `func ExampleExportedType_ExportedMethod\(\)`,
774 },
775 nil,
776 },
777
778
779 {
780 "function with -ex",
781 []string{`-ex`, p, `ExportedFunc`},
782 []string{
783 `func ExampleExportedFunc\(\)`,
784 `Function example.`,
785 `func ExampleExportedFunc_two\(\)`,
786 `Function example two.`,
787 },
788 nil,
789 },
790
791
792 {
793 "method with -ex",
794 []string{`-ex`, p, `ExportedType.ExportedMethod`},
795 []string{
796 `func ExampleExportedType_ExportedMethod\(\)`,
797 `Method example.`,
798 },
799 nil,
800 },
801
802
803 {
804 "package example",
805 []string{p, `Example`},
806 []string{
807 `fmt.Println\("Package example output"\)`,
808 `Output: Package example output`,
809 },
810 []string{`func Example\(\)`},
811 },
812
813
814 {
815 "multiline output example",
816 []string{p, `Example_multiline`},
817 []string{
818 `fmt.Println\("Multiline\\nexample\\noutput"\)`,
819 "Output: \nMultiline\nexample\noutput",
820 },
821 []string{`Output: Multiline example output`},
822 },
823
824
825 {
826 "type example",
827 []string{p, `ExampleExportedType`},
828 []string{
829 `fmt.Println\("Type example output"\)`,
830 `Output: Type example output`,
831 },
832 []string{`func ExampleExportedType\(\)`},
833 },
834
835
836 {
837 "function example",
838 []string{p, `ExampleExportedFunc`},
839 []string{
840 `fmt.Println\("Function example output"\)`,
841 `Output: Function example output`,
842 },
843 []string{
844 `func ExampleExportedFunc\(\)`,
845 `fmt.Println\("Function example two output"\)`,
846 `Output: Function example two output`,
847 },
848 },
849
850
851 {
852 "function example",
853 []string{p, `ExampleExportedFunc_two`},
854 []string{
855 `fmt.Println\("Function example two output"\)`,
856 `Output: Function example two output`,
857 },
858 []string{
859 `func ExampleExportedFunc_two\(\)`,
860 `fmt.Println\("Function example output"\)`,
861 `Output: Function example output`,
862 },
863 },
864
865
866 {
867 "method example",
868 []string{p, `ExampleExportedType_ExportedMethod`},
869 []string{
870 `fmt.Println\("Method example output"\)`,
871 `Output: Method example output`,
872 },
873 []string{`func ExampleExportedType_ExportedMethod\(\)`},
874 },
875
876
877 {
878 "playable example",
879 []string{p, `Example_playable`},
880 []string{
881 `package main`,
882 `func main\(\) {`,
883 `fmt.Println\("Playable example output"\)`,
884 `}`,
885 `Output: Playable example output`,
886 },
887 []string{`func Example_playable\(\)`},
888 },
889
890
891 {
892 "case matching off",
893 []string{p, `casematch`},
894 []string{
895 `CaseMatch`,
896 `Casematch`,
897 },
898 nil,
899 },
900
901
902 {
903 "case matching on",
904 []string{"-c", p, `Casematch`},
905 []string{
906 `Casematch`,
907 },
908 []string{
909 `CaseMatch`,
910 },
911 },
912
913
914 {
915 "merge comments with -src A",
916 []string{"-src", p + "/merge", `A`},
917 []string{
918 `A doc`,
919 `func A`,
920 `A comment`,
921 },
922 []string{
923 `Package A doc`,
924 `Package B doc`,
925 `B doc`,
926 `B comment`,
927 `B doc`,
928 },
929 },
930 {
931 "merge comments with -src B",
932 []string{"-src", p + "/merge", `B`},
933 []string{
934 `B doc`,
935 `func B`,
936 `B comment`,
937 },
938 []string{
939 `Package A doc`,
940 `Package B doc`,
941 `A doc`,
942 `A comment`,
943 `A doc`,
944 },
945 },
946
947
948 {
949 "case matching on, no dups",
950 []string{"-u", p, `duplicate`},
951 []string{
952 `Duplicate`,
953 `duplicate`,
954 },
955 []string{
956 "\\)\n+const",
957 },
958 },
959 {
960 "non-imported: pkg.sym",
961 []string{"nested.Foo"},
962 []string{"Foo struct"},
963 nil,
964 },
965 {
966 "non-imported: pkg only",
967 []string{"nested"},
968 []string{"Foo struct"},
969 nil,
970 },
971 {
972 "non-imported: pkg sym",
973 []string{"nested", "Foo"},
974 []string{"Foo struct"},
975 nil,
976 },
977 {
978 "formatted doc on function",
979 []string{p, "ExportedFormattedDoc"},
980 []string{
981 `func ExportedFormattedDoc\(a int\) bool`,
982 ` Comment about exported function with formatting\.
983
984 Example
985
986 fmt\.Println\(FormattedDoc\(\)\)
987
988 Text after pre-formatted block\.`,
989 },
990 nil,
991 },
992 {
993 "formatted doc on type field",
994 []string{p, "ExportedFormattedType.ExportedField"},
995 []string{
996 `type ExportedFormattedType struct`,
997 ` // Comment before exported field with formatting\.
998 //[ ]
999 // Example
1000 //[ ]
1001 // a\.ExportedField = 123
1002 //[ ]
1003 // Text after pre-formatted block\.`,
1004 `ExportedField int`,
1005 },
1006 []string{"ignore:directive"},
1007 },
1008 {
1009 "formatted doc on entire type",
1010 []string{p, "ExportedFormattedType"},
1011 []string{
1012 `type ExportedFormattedType struct`,
1013 ` // Comment before exported field with formatting\.
1014 //
1015 // Example
1016 //
1017 // a\.ExportedField = 123
1018 //
1019 // Text after pre-formatted block\.`,
1020 `ExportedField int`,
1021 },
1022 []string{"ignore:directive"},
1023 },
1024 {
1025 "formatted doc on entire type with -all",
1026 []string{"-all", p, "ExportedFormattedType"},
1027 []string{
1028 `type ExportedFormattedType struct`,
1029 ` // Comment before exported field with formatting\.
1030 //
1031 // Example
1032 //
1033 // a\.ExportedField = 123
1034 //
1035 // Text after pre-formatted block\.`,
1036 `ExportedField int`,
1037 },
1038 []string{"ignore:directive"},
1039 },
1040 }
1041
1042 func TestDoc(t *testing.T) {
1043 maybeSkip(t)
1044 defer log.SetOutput(log.Writer())
1045 for _, test := range tests {
1046 var b bytes.Buffer
1047 var flagSet flag.FlagSet
1048 var logbuf bytes.Buffer
1049 log.SetOutput(&logbuf)
1050 err := do(t.Context(), &b, &flagSet, test.args)
1051 if err != nil {
1052 t.Fatalf("%s %v: %s\n", test.name, test.args, err)
1053 }
1054 if logbuf.Len() > 0 {
1055 t.Errorf("%s %v: unexpected log messages:\n%s", test.name, test.args, logbuf.Bytes())
1056 }
1057 output := b.Bytes()
1058 failed := false
1059 for j, yes := range test.yes {
1060 re, err := regexp.Compile(yes)
1061 if err != nil {
1062 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
1063 }
1064 if !re.Match(output) {
1065 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
1066 failed = true
1067 }
1068 }
1069 for j, no := range test.no {
1070 re, err := regexp.Compile(no)
1071 if err != nil {
1072 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
1073 }
1074 if re.Match(output) {
1075 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
1076 failed = true
1077 }
1078 }
1079 if bytes.Count(output, []byte("TYPES\n")) > 1 {
1080 t.Fatalf("%s: repeating headers", test.name)
1081 }
1082 if failed {
1083 t.Logf("\n%s", output)
1084 }
1085 }
1086 }
1087
1088
1089
1090
1091
1092
1093
1094 func TestMultiplePackages(t *testing.T) {
1095 if testing.Short() {
1096 t.Skip("scanning file system takes too long")
1097 }
1098 maybeSkip(t)
1099 var b bytes.Buffer
1100
1101 {
1102 var flagSet flag.FlagSet
1103 err := do(t.Context(), &b, &flagSet, []string{"crypto/rand.float64"})
1104 if err == nil {
1105 t.Errorf("expected error from crypto/rand.float64")
1106 } else if !strings.Contains(err.Error(), "no symbol float64") {
1107 t.Errorf("unexpected error %q from crypto/rand.float64", err)
1108 }
1109 }
1110
1111 {
1112 var flagSet flag.FlagSet
1113 err := do(t.Context(), &b, &flagSet, []string{"math/rand.float64"})
1114 if err != nil {
1115 t.Errorf("unexpected error %q from math/rand.float64", err)
1116 }
1117 }
1118
1119 {
1120 var flagSet flag.FlagSet
1121 err := do(t.Context(), &b, &flagSet, []string{"rand.float64"})
1122 if err != nil {
1123 t.Errorf("unexpected error %q from rand.float64", err)
1124 }
1125 }
1126
1127 {
1128 var flagSet flag.FlagSet
1129 err := do(t.Context(), &b, &flagSet, []string{"rand.doesnotexit"})
1130 if err == nil {
1131 t.Errorf("expected error from rand.doesnotexit")
1132 } else {
1133 errStr := err.Error()
1134 if !strings.Contains(errStr, "no symbol") {
1135 t.Errorf("error %q should contain 'no symbol", errStr)
1136 }
1137 if !strings.Contains(errStr, "crypto/rand") {
1138 t.Errorf("error %q should contain crypto/rand", errStr)
1139 }
1140 if !strings.Contains(errStr, "math/rand") {
1141 t.Errorf("error %q should contain math/rand", errStr)
1142 }
1143 }
1144 }
1145 }
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 func TestTwoArgLookup(t *testing.T) {
1160 if testing.Short() {
1161 t.Skip("scanning file system takes too long")
1162 }
1163 maybeSkip(t)
1164 var b bytes.Buffer
1165 {
1166 var flagSet flag.FlagSet
1167 err := do(t.Context(), &b, &flagSet, []string{"binary", "BigEndian"})
1168 if err != nil {
1169 t.Errorf("unexpected error %q from binary BigEndian", err)
1170 }
1171 }
1172 {
1173 var flagSet flag.FlagSet
1174 err := do(t.Context(), &b, &flagSet, []string{"rand", "Float64"})
1175 if err != nil {
1176 t.Errorf("unexpected error %q from rand Float64", err)
1177 }
1178 }
1179 {
1180 var flagSet flag.FlagSet
1181 err := do(t.Context(), &b, &flagSet, []string{"bytes", "Foo"})
1182 if err == nil {
1183 t.Errorf("expected error from bytes Foo")
1184 } else if !strings.Contains(err.Error(), "no symbol Foo") {
1185 t.Errorf("unexpected error %q from bytes Foo", err)
1186 }
1187 }
1188 {
1189 var flagSet flag.FlagSet
1190 err := do(t.Context(), &b, &flagSet, []string{"nosuchpackage", "Foo"})
1191 if err == nil {
1192
1193 } else if !strings.Contains(err.Error(), "no such package") {
1194 t.Errorf("unexpected error %q from nosuchpackage Foo", err)
1195 }
1196 }
1197 }
1198
1199
1200
1201
1202 func TestDotSlashLookup(t *testing.T) {
1203 if testing.Short() {
1204 t.Skip("scanning file system takes too long")
1205 }
1206 maybeSkip(t)
1207 t.Chdir(filepath.Join(cfg.GOROOT, "src", "text"))
1208
1209 var b strings.Builder
1210 var flagSet flag.FlagSet
1211 err := do(t.Context(), &b, &flagSet, []string{"./template"})
1212 if err != nil {
1213 t.Errorf("unexpected error %q from ./template", err)
1214 }
1215
1216 const want = `package template // import "text/template"`
1217 output := b.String()
1218 if !strings.HasPrefix(output, want) {
1219 t.Fatalf("wrong package: %.*q...", len(want), output)
1220 }
1221 }
1222
1223
1224
1225 func TestNoPackageClauseWhenNoMatch(t *testing.T) {
1226 maybeSkip(t)
1227 var b strings.Builder
1228 var flagSet flag.FlagSet
1229 err := do(t.Context(), &b, &flagSet, []string{"template.ZZZ"})
1230
1231 if err == nil {
1232 t.Error("expect an error for template.zzz")
1233 }
1234
1235 const dontWant = `package template // import `
1236 output := b.String()
1237 if strings.Contains(output, dontWant) {
1238 t.Fatalf("improper package clause printed:\n%s", output)
1239 }
1240 }
1241
1242 type trimTest struct {
1243 path string
1244 prefix string
1245 result string
1246 ok bool
1247 }
1248
1249 var trimTests = []trimTest{
1250 {"", "", "", true},
1251 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
1252 {"/usr/gopher/bar", "/usr/gopher", "bar", true},
1253 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
1254 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
1255 }
1256
1257 func TestTrim(t *testing.T) {
1258 for _, test := range trimTests {
1259 result, ok := trim(test.path, test.prefix)
1260 if ok != test.ok {
1261 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
1262 continue
1263 }
1264 if result != test.result {
1265 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
1266 continue
1267 }
1268 }
1269 }
1270
View as plain text