Source file
src/cmd/doc/doc_test.go
Documentation: cmd/doc
1
2
3
4
5 package main
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/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/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 {
635 "interface method",
636 []string{p, `ExportedInterface.ExportedMethod`},
637 []string{
638 `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\(\)` +
639 `.*Comment on line with exported method`,
640 },
641 []string{
642 `Comment about exported interface`,
643 },
644 },
645
646 {
647 "interface method at package level",
648 []string{p, `ExportedMethod`},
649 []string{
650 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
651 `Comment about exported method`,
652 },
653 []string{
654 `Comment before exported method.*\n.*ExportedMethod\(\)` +
655 `.*Comment on line with exported method`,
656 },
657 },
658
659
660 {
661 "method",
662 []string{p, `ExportedType.ExportedMethod`},
663 []string{
664 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
665 `Comment about exported method`,
666 },
667 nil,
668 },
669
670 {
671 "method with -u",
672 []string{"-u", p, `ExportedType.unexportedMethod`},
673 []string{
674 `func \(ExportedType\) unexportedMethod\(a int\) bool`,
675 `Comment about unexported method`,
676 },
677 nil,
678 },
679
680 {
681 "method with -src",
682 []string{"-src", p, `ExportedType.ExportedMethod`},
683 []string{
684 `func \(ExportedType\) ExportedMethod\(a int\) bool`,
685 `Comment about exported method`,
686 `return true != true`,
687 },
688 nil,
689 },
690
691
692 {
693 "field",
694 []string{p, `ExportedType.ExportedField`},
695 []string{
696 `type ExportedType struct`,
697 `ExportedField int`,
698 `Comment before exported field`,
699 `Comment on line with exported field`,
700 `other fields elided`,
701 },
702 nil,
703 },
704
705
706 {
707 "method with -u",
708 []string{"-u", p, `ExportedType.unexportedField`},
709 []string{
710 `unexportedField int`,
711 `Comment on line with unexported field`,
712 },
713 nil,
714 },
715
716
717 {
718 "single-field struct",
719 []string{p, `ExportedStructOneField.OnlyField`},
720 []string{`the only field`},
721 []string{`other fields elided`},
722 },
723
724
725 {
726 "case matching off",
727 []string{p, `casematch`},
728 []string{
729 `CaseMatch`,
730 `Casematch`,
731 },
732 nil,
733 },
734
735
736 {
737 "case matching on",
738 []string{"-c", p, `Casematch`},
739 []string{
740 `Casematch`,
741 },
742 []string{
743 `CaseMatch`,
744 },
745 },
746
747
748 {
749 "merge comments with -src A",
750 []string{"-src", p + "/merge", `A`},
751 []string{
752 `A doc`,
753 `func A`,
754 `A comment`,
755 },
756 []string{
757 `Package A doc`,
758 `Package B doc`,
759 `B doc`,
760 `B comment`,
761 `B doc`,
762 },
763 },
764 {
765 "merge comments with -src B",
766 []string{"-src", p + "/merge", `B`},
767 []string{
768 `B doc`,
769 `func B`,
770 `B comment`,
771 },
772 []string{
773 `Package A doc`,
774 `Package B doc`,
775 `A doc`,
776 `A comment`,
777 `A doc`,
778 },
779 },
780
781
782 {
783 "case matching on, no dups",
784 []string{"-u", p, `duplicate`},
785 []string{
786 `Duplicate`,
787 `duplicate`,
788 },
789 []string{
790 "\\)\n+const",
791 },
792 },
793 {
794 "non-imported: pkg.sym",
795 []string{"nested.Foo"},
796 []string{"Foo struct"},
797 nil,
798 },
799 {
800 "non-imported: pkg only",
801 []string{"nested"},
802 []string{"Foo struct"},
803 nil,
804 },
805 {
806 "non-imported: pkg sym",
807 []string{"nested", "Foo"},
808 []string{"Foo struct"},
809 nil,
810 },
811 {
812 "formatted doc on function",
813 []string{p, "ExportedFormattedDoc"},
814 []string{
815 `func ExportedFormattedDoc\(a int\) bool`,
816 ` Comment about exported function with formatting\.
817
818 Example
819
820 fmt\.Println\(FormattedDoc\(\)\)
821
822 Text after pre-formatted block\.`,
823 },
824 nil,
825 },
826 {
827 "formatted doc on type field",
828 []string{p, "ExportedFormattedType.ExportedField"},
829 []string{
830 `type ExportedFormattedType struct`,
831 ` // Comment before exported field with formatting\.
832 //[ ]
833 // Example
834 //[ ]
835 // a\.ExportedField = 123
836 //[ ]
837 // Text after pre-formatted block\.`,
838 `ExportedField int`,
839 },
840 []string{"ignore:directive"},
841 },
842 {
843 "formatted doc on entire type",
844 []string{p, "ExportedFormattedType"},
845 []string{
846 `type ExportedFormattedType struct`,
847 ` // Comment before exported field with formatting\.
848 //
849 // Example
850 //
851 // a\.ExportedField = 123
852 //
853 // Text after pre-formatted block\.`,
854 `ExportedField int`,
855 },
856 []string{"ignore:directive"},
857 },
858 {
859 "formatted doc on entire type with -all",
860 []string{"-all", p, "ExportedFormattedType"},
861 []string{
862 `type ExportedFormattedType struct`,
863 ` // Comment before exported field with formatting\.
864 //
865 // Example
866 //
867 // a\.ExportedField = 123
868 //
869 // Text after pre-formatted block\.`,
870 `ExportedField int`,
871 },
872 []string{"ignore:directive"},
873 },
874 }
875
876 func TestDoc(t *testing.T) {
877 maybeSkip(t)
878 defer log.SetOutput(log.Writer())
879 for _, test := range tests {
880 var b bytes.Buffer
881 var flagSet flag.FlagSet
882 var logbuf bytes.Buffer
883 log.SetOutput(&logbuf)
884 err := do(&b, &flagSet, test.args)
885 if err != nil {
886 t.Fatalf("%s %v: %s\n", test.name, test.args, err)
887 }
888 if logbuf.Len() > 0 {
889 t.Errorf("%s %v: unexpected log messages:\n%s", test.name, test.args, logbuf.Bytes())
890 }
891 output := b.Bytes()
892 failed := false
893 for j, yes := range test.yes {
894 re, err := regexp.Compile(yes)
895 if err != nil {
896 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
897 }
898 if !re.Match(output) {
899 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
900 failed = true
901 }
902 }
903 for j, no := range test.no {
904 re, err := regexp.Compile(no)
905 if err != nil {
906 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
907 }
908 if re.Match(output) {
909 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
910 failed = true
911 }
912 }
913 if bytes.Count(output, []byte("TYPES\n")) > 1 {
914 t.Fatalf("%s: repeating headers", test.name)
915 }
916 if failed {
917 t.Logf("\n%s", output)
918 }
919 }
920 }
921
922
923
924
925
926
927
928 func TestMultiplePackages(t *testing.T) {
929 if testing.Short() {
930 t.Skip("scanning file system takes too long")
931 }
932 maybeSkip(t)
933 var b bytes.Buffer
934
935 {
936 var flagSet flag.FlagSet
937 err := do(&b, &flagSet, []string{"crypto/rand.float64"})
938 if err == nil {
939 t.Errorf("expected error from crypto/rand.float64")
940 } else if !strings.Contains(err.Error(), "no symbol float64") {
941 t.Errorf("unexpected error %q from crypto/rand.float64", err)
942 }
943 }
944
945 {
946 var flagSet flag.FlagSet
947 err := do(&b, &flagSet, []string{"math/rand.float64"})
948 if err != nil {
949 t.Errorf("unexpected error %q from math/rand.float64", err)
950 }
951 }
952
953 {
954 var flagSet flag.FlagSet
955 err := do(&b, &flagSet, []string{"rand.float64"})
956 if err != nil {
957 t.Errorf("unexpected error %q from rand.float64", err)
958 }
959 }
960
961 {
962 var flagSet flag.FlagSet
963 err := do(&b, &flagSet, []string{"rand.doesnotexit"})
964 if err == nil {
965 t.Errorf("expected error from rand.doesnotexit")
966 } else {
967 errStr := err.Error()
968 if !strings.Contains(errStr, "no symbol") {
969 t.Errorf("error %q should contain 'no symbol", errStr)
970 }
971 if !strings.Contains(errStr, "crypto/rand") {
972 t.Errorf("error %q should contain crypto/rand", errStr)
973 }
974 if !strings.Contains(errStr, "math/rand") {
975 t.Errorf("error %q should contain math/rand", errStr)
976 }
977 }
978 }
979 }
980
981
982
983
984
985
986
987
988
989
990
991
992
993 func TestTwoArgLookup(t *testing.T) {
994 if testing.Short() {
995 t.Skip("scanning file system takes too long")
996 }
997 maybeSkip(t)
998 var b bytes.Buffer
999 {
1000 var flagSet flag.FlagSet
1001 err := do(&b, &flagSet, []string{"binary", "BigEndian"})
1002 if err != nil {
1003 t.Errorf("unexpected error %q from binary BigEndian", err)
1004 }
1005 }
1006 {
1007 var flagSet flag.FlagSet
1008 err := do(&b, &flagSet, []string{"rand", "Float64"})
1009 if err != nil {
1010 t.Errorf("unexpected error %q from rand Float64", err)
1011 }
1012 }
1013 {
1014 var flagSet flag.FlagSet
1015 err := do(&b, &flagSet, []string{"bytes", "Foo"})
1016 if err == nil {
1017 t.Errorf("expected error from bytes Foo")
1018 } else if !strings.Contains(err.Error(), "no symbol Foo") {
1019 t.Errorf("unexpected error %q from bytes Foo", err)
1020 }
1021 }
1022 {
1023 var flagSet flag.FlagSet
1024 err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"})
1025 if err == nil {
1026
1027 } else if !strings.Contains(err.Error(), "no such package") {
1028 t.Errorf("unexpected error %q from nosuchpackage Foo", err)
1029 }
1030 }
1031 }
1032
1033
1034
1035
1036 func TestDotSlashLookup(t *testing.T) {
1037 if testing.Short() {
1038 t.Skip("scanning file system takes too long")
1039 }
1040 maybeSkip(t)
1041 where, err := os.Getwd()
1042 if err != nil {
1043 t.Fatal(err)
1044 }
1045 defer func() {
1046 if err := os.Chdir(where); err != nil {
1047 t.Fatal(err)
1048 }
1049 }()
1050 if err := os.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text")); err != nil {
1051 t.Fatal(err)
1052 }
1053 var b strings.Builder
1054 var flagSet flag.FlagSet
1055 err = do(&b, &flagSet, []string{"./template"})
1056 if err != nil {
1057 t.Errorf("unexpected error %q from ./template", err)
1058 }
1059
1060 const want = `package template // import "text/template"`
1061 output := b.String()
1062 if !strings.HasPrefix(output, want) {
1063 t.Fatalf("wrong package: %.*q...", len(want), output)
1064 }
1065 }
1066
1067
1068
1069 func TestNoPackageClauseWhenNoMatch(t *testing.T) {
1070 maybeSkip(t)
1071 var b strings.Builder
1072 var flagSet flag.FlagSet
1073 err := do(&b, &flagSet, []string{"template.ZZZ"})
1074
1075 if err == nil {
1076 t.Error("expect an error for template.zzz")
1077 }
1078
1079 const dontWant = `package template // import `
1080 output := b.String()
1081 if strings.Contains(output, dontWant) {
1082 t.Fatalf("improper package clause printed:\n%s", output)
1083 }
1084 }
1085
1086 type trimTest struct {
1087 path string
1088 prefix string
1089 result string
1090 ok bool
1091 }
1092
1093 var trimTests = []trimTest{
1094 {"", "", "", true},
1095 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
1096 {"/usr/gopher/bar", "/usr/gopher", "bar", true},
1097 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
1098 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
1099 }
1100
1101 func TestTrim(t *testing.T) {
1102 for _, test := range trimTests {
1103 result, ok := trim(test.path, test.prefix)
1104 if ok != test.ok {
1105 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
1106 continue
1107 }
1108 if result != test.result {
1109 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
1110 continue
1111 }
1112 }
1113 }
1114
View as plain text