1
2
3
4
5 package doc
6
7 import (
8 "bytes"
9 "flag"
10 "go/build"
11 "internal/testenv"
12 "log"
13 "os"
14 "path/filepath"
15 "regexp"
16 "runtime"
17 "strings"
18 "testing"
19 )
20
21 func TestMain(m *testing.M) {
22
23 buildCtx.GOPATH = ""
24 testGOPATH = true
25
26
27
28
29 buildCtx.GOROOT = testenv.GOROOT(nil)
30 build.Default.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: "testdata", dir: testdataDir},
41 Dir{importPath: "testdata/nested", dir: filepath.Join(testdataDir, "nested")},
42 Dir{importPath: "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 "case matching off",
756 []string{p, `casematch`},
757 []string{
758 `CaseMatch`,
759 `Casematch`,
760 },
761 nil,
762 },
763
764
765 {
766 "case matching on",
767 []string{"-c", p, `Casematch`},
768 []string{
769 `Casematch`,
770 },
771 []string{
772 `CaseMatch`,
773 },
774 },
775
776
777 {
778 "merge comments with -src A",
779 []string{"-src", p + "/merge", `A`},
780 []string{
781 `A doc`,
782 `func A`,
783 `A comment`,
784 },
785 []string{
786 `Package A doc`,
787 `Package B doc`,
788 `B doc`,
789 `B comment`,
790 `B doc`,
791 },
792 },
793 {
794 "merge comments with -src B",
795 []string{"-src", p + "/merge", `B`},
796 []string{
797 `B doc`,
798 `func B`,
799 `B comment`,
800 },
801 []string{
802 `Package A doc`,
803 `Package B doc`,
804 `A doc`,
805 `A comment`,
806 `A doc`,
807 },
808 },
809
810
811 {
812 "case matching on, no dups",
813 []string{"-u", p, `duplicate`},
814 []string{
815 `Duplicate`,
816 `duplicate`,
817 },
818 []string{
819 "\\)\n+const",
820 },
821 },
822 {
823 "non-imported: pkg.sym",
824 []string{"nested.Foo"},
825 []string{"Foo struct"},
826 nil,
827 },
828 {
829 "non-imported: pkg only",
830 []string{"nested"},
831 []string{"Foo struct"},
832 nil,
833 },
834 {
835 "non-imported: pkg sym",
836 []string{"nested", "Foo"},
837 []string{"Foo struct"},
838 nil,
839 },
840 {
841 "formatted doc on function",
842 []string{p, "ExportedFormattedDoc"},
843 []string{
844 `func ExportedFormattedDoc\(a int\) bool`,
845 ` Comment about exported function with formatting\.
846
847 Example
848
849 fmt\.Println\(FormattedDoc\(\)\)
850
851 Text after pre-formatted block\.`,
852 },
853 nil,
854 },
855 {
856 "formatted doc on type field",
857 []string{p, "ExportedFormattedType.ExportedField"},
858 []string{
859 `type ExportedFormattedType struct`,
860 ` // Comment before exported field with formatting\.
861 //[ ]
862 // Example
863 //[ ]
864 // a\.ExportedField = 123
865 //[ ]
866 // Text after pre-formatted block\.`,
867 `ExportedField int`,
868 },
869 []string{"ignore:directive"},
870 },
871 {
872 "formatted doc on entire type",
873 []string{p, "ExportedFormattedType"},
874 []string{
875 `type ExportedFormattedType struct`,
876 ` // Comment before exported field with formatting\.
877 //
878 // Example
879 //
880 // a\.ExportedField = 123
881 //
882 // Text after pre-formatted block\.`,
883 `ExportedField int`,
884 },
885 []string{"ignore:directive"},
886 },
887 {
888 "formatted doc on entire type with -all",
889 []string{"-all", p, "ExportedFormattedType"},
890 []string{
891 `type ExportedFormattedType struct`,
892 ` // Comment before exported field with formatting\.
893 //
894 // Example
895 //
896 // a\.ExportedField = 123
897 //
898 // Text after pre-formatted block\.`,
899 `ExportedField int`,
900 },
901 []string{"ignore:directive"},
902 },
903 }
904
905 func TestDoc(t *testing.T) {
906 maybeSkip(t)
907 defer log.SetOutput(log.Writer())
908 for _, test := range tests {
909 var b bytes.Buffer
910 var flagSet flag.FlagSet
911 var logbuf bytes.Buffer
912 log.SetOutput(&logbuf)
913 err := do(&b, &flagSet, test.args)
914 if err != nil {
915 t.Fatalf("%s %v: %s\n", test.name, test.args, err)
916 }
917 if logbuf.Len() > 0 {
918 t.Errorf("%s %v: unexpected log messages:\n%s", test.name, test.args, logbuf.Bytes())
919 }
920 output := b.Bytes()
921 failed := false
922 for j, yes := range test.yes {
923 re, err := regexp.Compile(yes)
924 if err != nil {
925 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
926 }
927 if !re.Match(output) {
928 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
929 failed = true
930 }
931 }
932 for j, no := range test.no {
933 re, err := regexp.Compile(no)
934 if err != nil {
935 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
936 }
937 if re.Match(output) {
938 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
939 failed = true
940 }
941 }
942 if bytes.Count(output, []byte("TYPES\n")) > 1 {
943 t.Fatalf("%s: repeating headers", test.name)
944 }
945 if failed {
946 t.Logf("\n%s", output)
947 }
948 }
949 }
950
951
952
953
954
955
956
957 func TestMultiplePackages(t *testing.T) {
958 if testing.Short() {
959 t.Skip("scanning file system takes too long")
960 }
961 maybeSkip(t)
962 var b bytes.Buffer
963
964 {
965 var flagSet flag.FlagSet
966 err := do(&b, &flagSet, []string{"crypto/rand.float64"})
967 if err == nil {
968 t.Errorf("expected error from crypto/rand.float64")
969 } else if !strings.Contains(err.Error(), "no symbol float64") {
970 t.Errorf("unexpected error %q from crypto/rand.float64", err)
971 }
972 }
973
974 {
975 var flagSet flag.FlagSet
976 err := do(&b, &flagSet, []string{"math/rand.float64"})
977 if err != nil {
978 t.Errorf("unexpected error %q from math/rand.float64", err)
979 }
980 }
981
982 {
983 var flagSet flag.FlagSet
984 err := do(&b, &flagSet, []string{"rand.float64"})
985 if err != nil {
986 t.Errorf("unexpected error %q from rand.float64", err)
987 }
988 }
989
990 {
991 var flagSet flag.FlagSet
992 err := do(&b, &flagSet, []string{"rand.doesnotexit"})
993 if err == nil {
994 t.Errorf("expected error from rand.doesnotexit")
995 } else {
996 errStr := err.Error()
997 if !strings.Contains(errStr, "no symbol") {
998 t.Errorf("error %q should contain 'no symbol", errStr)
999 }
1000 if !strings.Contains(errStr, "crypto/rand") {
1001 t.Errorf("error %q should contain crypto/rand", errStr)
1002 }
1003 if !strings.Contains(errStr, "math/rand") {
1004 t.Errorf("error %q should contain math/rand", errStr)
1005 }
1006 }
1007 }
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022 func TestTwoArgLookup(t *testing.T) {
1023 if testing.Short() {
1024 t.Skip("scanning file system takes too long")
1025 }
1026 maybeSkip(t)
1027 var b bytes.Buffer
1028 {
1029 var flagSet flag.FlagSet
1030 err := do(&b, &flagSet, []string{"binary", "BigEndian"})
1031 if err != nil {
1032 t.Errorf("unexpected error %q from binary BigEndian", err)
1033 }
1034 }
1035 {
1036 var flagSet flag.FlagSet
1037 err := do(&b, &flagSet, []string{"rand", "Float64"})
1038 if err != nil {
1039 t.Errorf("unexpected error %q from rand Float64", err)
1040 }
1041 }
1042 {
1043 var flagSet flag.FlagSet
1044 err := do(&b, &flagSet, []string{"bytes", "Foo"})
1045 if err == nil {
1046 t.Errorf("expected error from bytes Foo")
1047 } else if !strings.Contains(err.Error(), "no symbol Foo") {
1048 t.Errorf("unexpected error %q from bytes Foo", err)
1049 }
1050 }
1051 {
1052 var flagSet flag.FlagSet
1053 err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"})
1054 if err == nil {
1055
1056 } else if !strings.Contains(err.Error(), "no such package") {
1057 t.Errorf("unexpected error %q from nosuchpackage Foo", err)
1058 }
1059 }
1060 }
1061
1062
1063
1064
1065 func TestDotSlashLookup(t *testing.T) {
1066 if testing.Short() {
1067 t.Skip("scanning file system takes too long")
1068 }
1069 maybeSkip(t)
1070 t.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text"))
1071
1072 var b strings.Builder
1073 var flagSet flag.FlagSet
1074 err := do(&b, &flagSet, []string{"./template"})
1075 if err != nil {
1076 t.Errorf("unexpected error %q from ./template", err)
1077 }
1078
1079 const want = `package template // import "text/template"`
1080 output := b.String()
1081 if !strings.HasPrefix(output, want) {
1082 t.Fatalf("wrong package: %.*q...", len(want), output)
1083 }
1084 }
1085
1086
1087
1088 func TestNoPackageClauseWhenNoMatch(t *testing.T) {
1089 maybeSkip(t)
1090 var b strings.Builder
1091 var flagSet flag.FlagSet
1092 err := do(&b, &flagSet, []string{"template.ZZZ"})
1093
1094 if err == nil {
1095 t.Error("expect an error for template.zzz")
1096 }
1097
1098 const dontWant = `package template // import `
1099 output := b.String()
1100 if strings.Contains(output, dontWant) {
1101 t.Fatalf("improper package clause printed:\n%s", output)
1102 }
1103 }
1104
1105 type trimTest struct {
1106 path string
1107 prefix string
1108 result string
1109 ok bool
1110 }
1111
1112 var trimTests = []trimTest{
1113 {"", "", "", true},
1114 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
1115 {"/usr/gopher/bar", "/usr/gopher", "bar", true},
1116 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
1117 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
1118 }
1119
1120 func TestTrim(t *testing.T) {
1121 for _, test := range trimTests {
1122 result, ok := trim(test.path, test.prefix)
1123 if ok != test.ok {
1124 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
1125 continue
1126 }
1127 if result != test.result {
1128 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
1129 continue
1130 }
1131 }
1132 }
1133
View as plain text