github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/doc/doc_test.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"runtime"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  func TestMain(m *testing.M) {
    19  	// Clear GOPATH so we don't access the user's own packages in the test.
    20  	buildCtx.GOPATH = ""
    21  	testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt
    22  
    23  	// Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test.
    24  	// Normally testdata directories are ignored, but sending it to dirs.scan directly is
    25  	// a hack that works around the check.
    26  	testdataDir, err := filepath.Abs("testdata")
    27  	if err != nil {
    28  		panic(err)
    29  	}
    30  	dirsInit(Dir{"testdata", testdataDir}, Dir{"testdata/nested", filepath.Join(testdataDir, "nested")}, Dir{"testdata/nested/nested", filepath.Join(testdataDir, "nested", "nested")})
    31  
    32  	os.Exit(m.Run())
    33  }
    34  
    35  func maybeSkip(t *testing.T) {
    36  	if strings.HasPrefix(runtime.GOOS, "nacl") {
    37  		t.Skip("nacl does not have a full file tree")
    38  	}
    39  	if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") {
    40  		t.Skip("darwin/arm does not have a full file tree")
    41  	}
    42  }
    43  
    44  type isDotSlashTest struct {
    45  	str    string
    46  	result bool
    47  }
    48  
    49  var isDotSlashTests = []isDotSlashTest{
    50  	{``, false},
    51  	{`x`, false},
    52  	{`...`, false},
    53  	{`.../`, false},
    54  	{`...\`, false},
    55  
    56  	{`.`, true},
    57  	{`./`, true},
    58  	{`.\`, true},
    59  	{`./x`, true},
    60  	{`.\x`, true},
    61  
    62  	{`..`, true},
    63  	{`../`, true},
    64  	{`..\`, true},
    65  	{`../x`, true},
    66  	{`..\x`, true},
    67  }
    68  
    69  func TestIsDotSlashPath(t *testing.T) {
    70  	for _, test := range isDotSlashTests {
    71  		if result := isDotSlash(test.str); result != test.result {
    72  			t.Errorf("isDotSlash(%q) = %t; expected %t", test.str, result, test.result)
    73  		}
    74  	}
    75  }
    76  
    77  type test struct {
    78  	name string
    79  	args []string // Arguments to "[go] doc".
    80  	yes  []string // Regular expressions that should match.
    81  	no   []string // Regular expressions that should not match.
    82  }
    83  
    84  const p = "cmd/doc/testdata"
    85  
    86  var tests = []test{
    87  	// Sanity check.
    88  	{
    89  		"sanity check",
    90  		[]string{p},
    91  		[]string{`type ExportedType struct`},
    92  		nil,
    93  	},
    94  
    95  	// Package dump includes import, package statement.
    96  	{
    97  		"package clause",
    98  		[]string{p},
    99  		[]string{`package pkg.*cmd/doc/testdata`},
   100  		nil,
   101  	},
   102  
   103  	// Constants.
   104  	// Package dump
   105  	{
   106  		"full package",
   107  		[]string{p},
   108  		[]string{
   109  			`Package comment`,
   110  			`const ExportedConstant = 1`,                                   // Simple constant.
   111  			`const ConstOne = 1`,                                           // First entry in constant block.
   112  			`const ConstFive ...`,                                          // From block starting with unexported constant.
   113  			`var ExportedVariable = 1`,                                     // Simple variable.
   114  			`var VarOne = 1`,                                               // First entry in variable block.
   115  			`func ExportedFunc\(a int\) bool`,                              // Function.
   116  			`func ReturnUnexported\(\) unexportedType`,                     // Function with unexported return type.
   117  			`type ExportedType struct{ ... }`,                              // Exported type.
   118  			`const ExportedTypedConstant ExportedType = iota`,              // Typed constant.
   119  			`const ExportedTypedConstant_unexported unexportedType`,        // Typed constant, exported for unexported type.
   120  			`const ConstLeft2 uint64 ...`,                                  // Typed constant using unexported iota.
   121  			`const ConstGroup1 unexportedType = iota ...`,                  // Typed constant using unexported type.
   122  			`const ConstGroup4 ExportedType = ExportedType{}`,              // Typed constant using exported type.
   123  			`const MultiLineConst = ...`,                                   // Multi line constant.
   124  			`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`,  // Multi line variable.
   125  			`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
   126  			`var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`,  // Long list of arguments.
   127  			`type T1 = T2`,                                                 // Type alias
   128  		},
   129  		[]string{
   130  			`const internalConstant = 2`,       // No internal constants.
   131  			`var internalVariable = 2`,         // No internal variables.
   132  			`func internalFunc(a int) bool`,    // No internal functions.
   133  			`Comment about exported constant`,  // No comment for single constant.
   134  			`Comment about exported variable`,  // No comment for single variable.
   135  			`Comment about block of constants`, // No comment for constant block.
   136  			`Comment about block of variables`, // No comment for variable block.
   137  			`Comment before ConstOne`,          // No comment for first entry in constant block.
   138  			`Comment before VarOne`,            // No comment for first entry in variable block.
   139  			`ConstTwo = 2`,                     // No second entry in constant block.
   140  			`VarTwo = 2`,                       // No second entry in variable block.
   141  			`VarFive = 5`,                      // From block starting with unexported variable.
   142  			`type unexportedType`,              // No unexported type.
   143  			`unexportedTypedConstant`,          // No unexported typed constant.
   144  			`\bField`,                          // No fields.
   145  			`Method`,                           // No methods.
   146  			`someArgument[5-8]`,                // No truncated arguments.
   147  			`type T1 T2`,                       // Type alias does not display as type declaration.
   148  		},
   149  	},
   150  	// Package dump -all
   151  	{
   152  		"full package",
   153  		[]string{"-all", p},
   154  		[]string{
   155  			`package pkg .*import`,
   156  			`Package comment`,
   157  			`CONSTANTS`,
   158  			`Comment before ConstOne`,
   159  			`ConstOne = 1`,
   160  			`ConstTwo = 2 // Comment on line with ConstTwo`,
   161  			`ConstFive`,
   162  			`ConstSix`,
   163  			`Const block where first entry is unexported`,
   164  			`ConstLeft2, constRight2 uint64`,
   165  			`constLeft3, ConstRight3`,
   166  			`ConstLeft4, ConstRight4`,
   167  			`Duplicate = iota`,
   168  			`const CaseMatch = 1`,
   169  			`const Casematch = 2`,
   170  			`const ExportedConstant = 1`,
   171  			`const MultiLineConst = `,
   172  			`MultiLineString1`,
   173  			`VARIABLES`,
   174  			`Comment before VarOne`,
   175  			`VarOne = 1`,
   176  			`Comment about block of variables`,
   177  			`VarFive = 5`,
   178  			`var ExportedVariable = 1`,
   179  			`var LongLine = newLongLine\(`,
   180  			`var MultiLineVar = map\[struct {`,
   181  			`FUNCTIONS`,
   182  			`func ExportedFunc\(a int\) bool`,
   183  			`Comment about exported function`,
   184  			`func MultiLineFunc\(x interface`,
   185  			`func ReturnUnexported\(\) unexportedType`,
   186  			`TYPES`,
   187  			`type ExportedInterface interface`,
   188  			`type ExportedStructOneField struct`,
   189  			`type ExportedType struct`,
   190  			`Comment about exported type`,
   191  			`const ConstGroup4 ExportedType = ExportedType`,
   192  			`ExportedTypedConstant ExportedType = iota`,
   193  			`Constants tied to ExportedType`,
   194  			`func ExportedTypeConstructor\(\) \*ExportedType`,
   195  			`Comment about constructor for exported type`,
   196  			`func ReturnExported\(\) ExportedType`,
   197  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   198  			`Comment about exported method`,
   199  			`type T1 = T2`,
   200  			`type T2 int`,
   201  		},
   202  		[]string{
   203  			`constThree`,
   204  			`_, _ uint64 = 2 \* iota, 1 << iota`,
   205  			`constLeft1, constRight1`,
   206  			`duplicate`,
   207  			`varFour`,
   208  			`func internalFunc`,
   209  			`unexportedField`,
   210  			`func \(unexportedType\)`,
   211  		},
   212  	},
   213  	// Package dump -u
   214  	{
   215  		"full package with u",
   216  		[]string{`-u`, p},
   217  		[]string{
   218  			`const ExportedConstant = 1`,               // Simple constant.
   219  			`const internalConstant = 2`,               // Internal constants.
   220  			`func internalFunc\(a int\) bool`,          // Internal functions.
   221  			`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
   222  		},
   223  		[]string{
   224  			`Comment about exported constant`,  // No comment for simple constant.
   225  			`Comment about block of constants`, // No comment for constant block.
   226  			`Comment about internal function`,  // No comment for internal function.
   227  			`MultiLine(String|Method|Field)`,   // No data from multi line portions.
   228  		},
   229  	},
   230  	// Package dump -u -all
   231  	{
   232  		"full package",
   233  		[]string{"-u", "-all", p},
   234  		[]string{
   235  			`package pkg .*import`,
   236  			`Package comment`,
   237  			`CONSTANTS`,
   238  			`Comment before ConstOne`,
   239  			`ConstOne += 1`,
   240  			`ConstTwo += 2 // Comment on line with ConstTwo`,
   241  			`constThree = 3 // Comment on line with constThree`,
   242  			`ConstFive`,
   243  			`const internalConstant += 2`,
   244  			`Comment about internal constant`,
   245  			`VARIABLES`,
   246  			`Comment before VarOne`,
   247  			`VarOne += 1`,
   248  			`Comment about block of variables`,
   249  			`varFour += 4`,
   250  			`VarFive += 5`,
   251  			`varSix += 6`,
   252  			`var ExportedVariable = 1`,
   253  			`var LongLine = newLongLine\(`,
   254  			`var MultiLineVar = map\[struct {`,
   255  			`var internalVariable = 2`,
   256  			`Comment about internal variable`,
   257  			`FUNCTIONS`,
   258  			`func ExportedFunc\(a int\) bool`,
   259  			`Comment about exported function`,
   260  			`func MultiLineFunc\(x interface`,
   261  			`func internalFunc\(a int\) bool`,
   262  			`Comment about internal function`,
   263  			`func newLongLine\(ss .*string\)`,
   264  			`TYPES`,
   265  			`type ExportedType struct`,
   266  			`type T1 = T2`,
   267  			`type T2 int`,
   268  			`type unexportedType int`,
   269  			`Comment about unexported type`,
   270  			`ConstGroup1 unexportedType = iota`,
   271  			`ConstGroup2`,
   272  			`ConstGroup3`,
   273  			`ExportedTypedConstant_unexported unexportedType = iota`,
   274  			`Constants tied to unexportedType`,
   275  			`const unexportedTypedConstant unexportedType = 1`,
   276  			`func ReturnUnexported\(\) unexportedType`,
   277  			`func \(unexportedType\) ExportedMethod\(\) bool`,
   278  			`func \(unexportedType\) unexportedMethod\(\) bool`,
   279  		},
   280  		nil,
   281  	},
   282  
   283  	// Single constant.
   284  	{
   285  		"single constant",
   286  		[]string{p, `ExportedConstant`},
   287  		[]string{
   288  			`Comment about exported constant`, // Include comment.
   289  			`const ExportedConstant = 1`,
   290  		},
   291  		nil,
   292  	},
   293  	// Single constant -u.
   294  	{
   295  		"single constant with -u",
   296  		[]string{`-u`, p, `internalConstant`},
   297  		[]string{
   298  			`Comment about internal constant`, // Include comment.
   299  			`const internalConstant = 2`,
   300  		},
   301  		nil,
   302  	},
   303  	// Block of constants.
   304  	{
   305  		"block of constants",
   306  		[]string{p, `ConstTwo`},
   307  		[]string{
   308  			`Comment before ConstOne.\n.*ConstOne = 1`,    // First...
   309  			`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
   310  			`Comment about block of constants`,            // Comment does too.
   311  		},
   312  		[]string{
   313  			`constThree`, // No unexported constant.
   314  		},
   315  	},
   316  	// Block of constants -u.
   317  	{
   318  		"block of constants with -u",
   319  		[]string{"-u", p, `constThree`},
   320  		[]string{
   321  			`constThree = 3.*Comment on line with constThree`,
   322  		},
   323  		nil,
   324  	},
   325  	// Block of constants -src.
   326  	{
   327  		"block of constants with -src",
   328  		[]string{"-src", p, `ConstTwo`},
   329  		[]string{
   330  			`Comment about block of constants`, // Top comment.
   331  			`ConstOne.*=.*1`,                   // Each constant seen.
   332  			`ConstTwo.*=.*2.*Comment on line with ConstTwo`,
   333  			`constThree`, // Even unexported constants.
   334  		},
   335  		nil,
   336  	},
   337  	// Block of constants with carryover type from unexported field.
   338  	{
   339  		"block of constants with carryover type",
   340  		[]string{p, `ConstLeft2`},
   341  		[]string{
   342  			`ConstLeft2, constRight2 uint64`,
   343  			`constLeft3, ConstRight3`,
   344  			`ConstLeft4, ConstRight4`,
   345  		},
   346  		nil,
   347  	},
   348  	// Block of constants -u with carryover type from unexported field.
   349  	{
   350  		"block of constants with carryover type",
   351  		[]string{"-u", p, `ConstLeft2`},
   352  		[]string{
   353  			`_, _ uint64 = 2 \* iota, 1 << iota`,
   354  			`constLeft1, constRight1`,
   355  			`ConstLeft2, constRight2`,
   356  			`constLeft3, ConstRight3`,
   357  			`ConstLeft4, ConstRight4`,
   358  		},
   359  		nil,
   360  	},
   361  
   362  	// Single variable.
   363  	{
   364  		"single variable",
   365  		[]string{p, `ExportedVariable`},
   366  		[]string{
   367  			`ExportedVariable`, // Include comment.
   368  			`var ExportedVariable = 1`,
   369  		},
   370  		nil,
   371  	},
   372  	// Single variable -u.
   373  	{
   374  		"single variable with -u",
   375  		[]string{`-u`, p, `internalVariable`},
   376  		[]string{
   377  			`Comment about internal variable`, // Include comment.
   378  			`var internalVariable = 2`,
   379  		},
   380  		nil,
   381  	},
   382  	// Block of variables.
   383  	{
   384  		"block of variables",
   385  		[]string{p, `VarTwo`},
   386  		[]string{
   387  			`Comment before VarOne.\n.*VarOne = 1`,    // First...
   388  			`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
   389  			`Comment about block of variables`,        // Comment does too.
   390  		},
   391  		[]string{
   392  			`varThree= 3`, // No unexported variable.
   393  		},
   394  	},
   395  	// Block of variables -u.
   396  	{
   397  		"block of variables with -u",
   398  		[]string{"-u", p, `varThree`},
   399  		[]string{
   400  			`varThree = 3.*Comment on line with varThree`,
   401  		},
   402  		nil,
   403  	},
   404  
   405  	// Function.
   406  	{
   407  		"function",
   408  		[]string{p, `ExportedFunc`},
   409  		[]string{
   410  			`Comment about exported function`, // Include comment.
   411  			`func ExportedFunc\(a int\) bool`,
   412  		},
   413  		nil,
   414  	},
   415  	// Function -u.
   416  	{
   417  		"function with -u",
   418  		[]string{"-u", p, `internalFunc`},
   419  		[]string{
   420  			`Comment about internal function`, // Include comment.
   421  			`func internalFunc\(a int\) bool`,
   422  		},
   423  		nil,
   424  	},
   425  	// Function with -src.
   426  	{
   427  		"function with -src",
   428  		[]string{"-src", p, `ExportedFunc`},
   429  		[]string{
   430  			`Comment about exported function`, // Include comment.
   431  			`func ExportedFunc\(a int\) bool`,
   432  			`return true != false`, // Include body.
   433  		},
   434  		nil,
   435  	},
   436  
   437  	// Type.
   438  	{
   439  		"type",
   440  		[]string{p, `ExportedType`},
   441  		[]string{
   442  			`Comment about exported type`, // Include comment.
   443  			`type ExportedType struct`,    // Type definition.
   444  			`Comment before exported field.*\n.*ExportedField +int` +
   445  				`.*Comment on line with exported field`,
   446  			`ExportedEmbeddedType.*Comment on line with exported embedded field`,
   447  			`Has unexported fields`,
   448  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   449  			`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
   450  			`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
   451  			`io.Reader.*Comment on line with embedded Reader`,
   452  		},
   453  		[]string{
   454  			`unexportedField`,               // No unexported field.
   455  			`int.*embedded`,                 // No unexported embedded field.
   456  			`Comment about exported method`, // No comment about exported method.
   457  			`unexportedMethod`,              // No unexported method.
   458  			`unexportedTypedConstant`,       // No unexported constant.
   459  			`error`,                         // No embedded error.
   460  		},
   461  	},
   462  	// Type with -src. Will see unexported fields.
   463  	{
   464  		"type",
   465  		[]string{"-src", p, `ExportedType`},
   466  		[]string{
   467  			`Comment about exported type`, // Include comment.
   468  			`type ExportedType struct`,    // Type definition.
   469  			`Comment before exported field`,
   470  			`ExportedField.*Comment on line with exported field`,
   471  			`ExportedEmbeddedType.*Comment on line with exported embedded field`,
   472  			`unexportedType.*Comment on line with unexported embedded field`,
   473  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   474  			`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
   475  			`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
   476  			`io.Reader.*Comment on line with embedded Reader`,
   477  		},
   478  		[]string{
   479  			`Comment about exported method`, // No comment about exported method.
   480  			`unexportedMethod`,              // No unexported method.
   481  			`unexportedTypedConstant`,       // No unexported constant.
   482  		},
   483  	},
   484  	// Type -all.
   485  	{
   486  		"type",
   487  		[]string{"-all", p, `ExportedType`},
   488  		[]string{
   489  			`type ExportedType struct {`,                        // Type definition as source.
   490  			`Comment about exported type`,                       // Include comment afterwards.
   491  			`const ConstGroup4 ExportedType = ExportedType\{\}`, // Related constants.
   492  			`ExportedTypedConstant ExportedType = iota`,
   493  			`Constants tied to ExportedType`,
   494  			`func ExportedTypeConstructor\(\) \*ExportedType`,
   495  			`Comment about constructor for exported type.`,
   496  			`func ReturnExported\(\) ExportedType`,
   497  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   498  			`Comment about exported method.`,
   499  		},
   500  		[]string{
   501  			`unexportedType`,
   502  		},
   503  	},
   504  	// Type T1 dump (alias).
   505  	{
   506  		"type T1",
   507  		[]string{p + ".T1"},
   508  		[]string{
   509  			`type T1 = T2`,
   510  		},
   511  		[]string{
   512  			`type T1 T2`,
   513  			`type ExportedType`,
   514  		},
   515  	},
   516  	// Type -u with unexported fields.
   517  	{
   518  		"type with unexported fields and -u",
   519  		[]string{"-u", p, `ExportedType`},
   520  		[]string{
   521  			`Comment about exported type`, // Include comment.
   522  			`type ExportedType struct`,    // Type definition.
   523  			`Comment before exported field.*\n.*ExportedField +int`,
   524  			`unexportedField.*int.*Comment on line with unexported field`,
   525  			`ExportedEmbeddedType.*Comment on line with exported embedded field`,
   526  			`\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`,
   527  			`\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`,
   528  			`unexportedType.*Comment on line with unexported embedded field`,
   529  			`\*unexportedType.*Comment on line with unexported embedded \*field`,
   530  			`io.Reader.*Comment on line with embedded Reader`,
   531  			`error.*Comment on line with embedded error`,
   532  			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
   533  			`unexportedTypedConstant`,
   534  		},
   535  		[]string{
   536  			`Has unexported fields`,
   537  		},
   538  	},
   539  	// Unexported type with -u.
   540  	{
   541  		"unexported type with -u",
   542  		[]string{"-u", p, `unexportedType`},
   543  		[]string{
   544  			`Comment about unexported type`, // Include comment.
   545  			`type unexportedType int`,       // Type definition.
   546  			`func \(unexportedType\) ExportedMethod\(\) bool`,
   547  			`func \(unexportedType\) unexportedMethod\(\) bool`,
   548  			`ExportedTypedConstant_unexported unexportedType = iota`,
   549  			`const unexportedTypedConstant unexportedType = 1`,
   550  		},
   551  		nil,
   552  	},
   553  
   554  	// Interface.
   555  	{
   556  		"interface type",
   557  		[]string{p, `ExportedInterface`},
   558  		[]string{
   559  			`Comment about exported interface`, // Include comment.
   560  			`type ExportedInterface interface`, // Interface definition.
   561  			`Comment before exported method.*\n.*ExportedMethod\(\)` +
   562  				`.*Comment on line with exported method`,
   563  			`io.Reader.*Comment on line with embedded Reader`,
   564  			`error.*Comment on line with embedded error`,
   565  			`Has unexported methods`,
   566  		},
   567  		[]string{
   568  			`unexportedField`,               // No unexported field.
   569  			`Comment about exported method`, // No comment about exported method.
   570  			`unexportedMethod`,              // No unexported method.
   571  			`unexportedTypedConstant`,       // No unexported constant.
   572  		},
   573  	},
   574  	// Interface -u with unexported methods.
   575  	{
   576  		"interface type with unexported methods and -u",
   577  		[]string{"-u", p, `ExportedInterface`},
   578  		[]string{
   579  			`Comment about exported interface`, // Include comment.
   580  			`type ExportedInterface interface`, // Interface definition.
   581  			`Comment before exported method.*\n.*ExportedMethod\(\)` +
   582  				`.*Comment on line with exported method`,
   583  			`unexportedMethod\(\).*Comment on line with unexported method`,
   584  			`io.Reader.*Comment on line with embedded Reader`,
   585  			`error.*Comment on line with embedded error`,
   586  		},
   587  		[]string{
   588  			`Has unexported methods`,
   589  		},
   590  	},
   591  
   592  	// Interface method.
   593  	{
   594  		"interface method",
   595  		[]string{p, `ExportedInterface.ExportedMethod`},
   596  		[]string{
   597  			`Comment before exported method.*\n.*ExportedMethod\(\)` +
   598  				`.*Comment on line with exported method`,
   599  		},
   600  		[]string{
   601  			`Comment about exported interface`,
   602  		},
   603  	},
   604  
   605  	// Method.
   606  	{
   607  		"method",
   608  		[]string{p, `ExportedType.ExportedMethod`},
   609  		[]string{
   610  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   611  			`Comment about exported method`,
   612  		},
   613  		nil,
   614  	},
   615  	// Method  with -u.
   616  	{
   617  		"method with -u",
   618  		[]string{"-u", p, `ExportedType.unexportedMethod`},
   619  		[]string{
   620  			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
   621  			`Comment about unexported method`,
   622  		},
   623  		nil,
   624  	},
   625  	// Method with -src.
   626  	{
   627  		"method with -src",
   628  		[]string{"-src", p, `ExportedType.ExportedMethod`},
   629  		[]string{
   630  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   631  			`Comment about exported method`,
   632  			`return true != true`,
   633  		},
   634  		nil,
   635  	},
   636  
   637  	// Field.
   638  	{
   639  		"field",
   640  		[]string{p, `ExportedType.ExportedField`},
   641  		[]string{
   642  			`type ExportedType struct`,
   643  			`ExportedField int`,
   644  			`Comment before exported field`,
   645  			`Comment on line with exported field`,
   646  			`other fields elided`,
   647  		},
   648  		nil,
   649  	},
   650  
   651  	// Field with -u.
   652  	{
   653  		"method with -u",
   654  		[]string{"-u", p, `ExportedType.unexportedField`},
   655  		[]string{
   656  			`unexportedField int`,
   657  			`Comment on line with unexported field`,
   658  		},
   659  		nil,
   660  	},
   661  
   662  	// Field of struct with only one field.
   663  	{
   664  		"single-field struct",
   665  		[]string{p, `ExportedStructOneField.OnlyField`},
   666  		[]string{`the only field`},
   667  		[]string{`other fields elided`},
   668  	},
   669  
   670  	// Case matching off.
   671  	{
   672  		"case matching off",
   673  		[]string{p, `casematch`},
   674  		[]string{
   675  			`CaseMatch`,
   676  			`Casematch`,
   677  		},
   678  		nil,
   679  	},
   680  
   681  	// Case matching on.
   682  	{
   683  		"case matching on",
   684  		[]string{"-c", p, `Casematch`},
   685  		[]string{
   686  			`Casematch`,
   687  		},
   688  		[]string{
   689  			`CaseMatch`,
   690  		},
   691  	},
   692  
   693  	// No dups with -u. Issue 21797.
   694  	{
   695  		"case matching on, no dups",
   696  		[]string{"-u", p, `duplicate`},
   697  		[]string{
   698  			`Duplicate`,
   699  			`duplicate`,
   700  		},
   701  		[]string{
   702  			"\\)\n+const", // This will appear if the const decl appears twice.
   703  		},
   704  	},
   705  	{
   706  		"non-imported: pkg.sym",
   707  		[]string{"nested.Foo"},
   708  		[]string{"Foo struct"},
   709  		nil,
   710  	},
   711  	{
   712  		"non-imported: pkg only",
   713  		[]string{"nested"},
   714  		[]string{"Foo struct"},
   715  		nil,
   716  	},
   717  	{
   718  		"non-imported: pkg sym",
   719  		[]string{"nested", "Foo"},
   720  		[]string{"Foo struct"},
   721  		nil,
   722  	},
   723  }
   724  
   725  func TestDoc(t *testing.T) {
   726  	maybeSkip(t)
   727  	for _, test := range tests {
   728  		var b bytes.Buffer
   729  		var flagSet flag.FlagSet
   730  		err := do(&b, &flagSet, test.args)
   731  		if err != nil {
   732  			t.Fatalf("%s %v: %s\n", test.name, test.args, err)
   733  		}
   734  		output := b.Bytes()
   735  		failed := false
   736  		for j, yes := range test.yes {
   737  			re, err := regexp.Compile(yes)
   738  			if err != nil {
   739  				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
   740  			}
   741  			if !re.Match(output) {
   742  				t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
   743  				failed = true
   744  			}
   745  		}
   746  		for j, no := range test.no {
   747  			re, err := regexp.Compile(no)
   748  			if err != nil {
   749  				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
   750  			}
   751  			if re.Match(output) {
   752  				t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
   753  				failed = true
   754  			}
   755  		}
   756  		if bytes.Count(output, []byte("TYPES\n")) > 1 {
   757  			t.Fatalf("%s: repeating headers", test.name)
   758  		}
   759  		if failed {
   760  			t.Logf("\n%s", output)
   761  		}
   762  	}
   763  }
   764  
   765  // Test the code to try multiple packages. Our test case is
   766  //	go doc rand.Float64
   767  // This needs to find math/rand.Float64; however crypto/rand, which doesn't
   768  // have the symbol, usually appears first in the directory listing.
   769  func TestMultiplePackages(t *testing.T) {
   770  	if testing.Short() {
   771  		t.Skip("scanning file system takes too long")
   772  	}
   773  	maybeSkip(t)
   774  	var b bytes.Buffer // We don't care about the output.
   775  	// Make sure crypto/rand does not have the symbol.
   776  	{
   777  		var flagSet flag.FlagSet
   778  		err := do(&b, &flagSet, []string{"crypto/rand.float64"})
   779  		if err == nil {
   780  			t.Errorf("expected error from crypto/rand.float64")
   781  		} else if !strings.Contains(err.Error(), "no symbol float64") {
   782  			t.Errorf("unexpected error %q from crypto/rand.float64", err)
   783  		}
   784  	}
   785  	// Make sure math/rand does have the symbol.
   786  	{
   787  		var flagSet flag.FlagSet
   788  		err := do(&b, &flagSet, []string{"math/rand.float64"})
   789  		if err != nil {
   790  			t.Errorf("unexpected error %q from math/rand.float64", err)
   791  		}
   792  	}
   793  	// Try the shorthand.
   794  	{
   795  		var flagSet flag.FlagSet
   796  		err := do(&b, &flagSet, []string{"rand.float64"})
   797  		if err != nil {
   798  			t.Errorf("unexpected error %q from rand.float64", err)
   799  		}
   800  	}
   801  	// Now try a missing symbol. We should see both packages in the error.
   802  	{
   803  		var flagSet flag.FlagSet
   804  		err := do(&b, &flagSet, []string{"rand.doesnotexit"})
   805  		if err == nil {
   806  			t.Errorf("expected error from rand.doesnotexit")
   807  		} else {
   808  			errStr := err.Error()
   809  			if !strings.Contains(errStr, "no symbol") {
   810  				t.Errorf("error %q should contain 'no symbol", errStr)
   811  			}
   812  			if !strings.Contains(errStr, "crypto/rand") {
   813  				t.Errorf("error %q should contain crypto/rand", errStr)
   814  			}
   815  			if !strings.Contains(errStr, "math/rand") {
   816  				t.Errorf("error %q should contain math/rand", errStr)
   817  			}
   818  		}
   819  	}
   820  }
   821  
   822  // Test the code to look up packages when given two args. First test case is
   823  //	go doc binary BigEndian
   824  // This needs to find encoding/binary.BigEndian, which means
   825  // finding the package encoding/binary given only "binary".
   826  // Second case is
   827  //	go doc rand Float64
   828  // which again needs to find math/rand and not give up after crypto/rand,
   829  // which has no such function.
   830  func TestTwoArgLookup(t *testing.T) {
   831  	if testing.Short() {
   832  		t.Skip("scanning file system takes too long")
   833  	}
   834  	maybeSkip(t)
   835  	var b bytes.Buffer // We don't care about the output.
   836  	{
   837  		var flagSet flag.FlagSet
   838  		err := do(&b, &flagSet, []string{"binary", "BigEndian"})
   839  		if err != nil {
   840  			t.Errorf("unexpected error %q from binary BigEndian", err)
   841  		}
   842  	}
   843  	{
   844  		var flagSet flag.FlagSet
   845  		err := do(&b, &flagSet, []string{"rand", "Float64"})
   846  		if err != nil {
   847  			t.Errorf("unexpected error %q from rand Float64", err)
   848  		}
   849  	}
   850  	{
   851  		var flagSet flag.FlagSet
   852  		err := do(&b, &flagSet, []string{"bytes", "Foo"})
   853  		if err == nil {
   854  			t.Errorf("expected error from bytes Foo")
   855  		} else if !strings.Contains(err.Error(), "no symbol Foo") {
   856  			t.Errorf("unexpected error %q from bytes Foo", err)
   857  		}
   858  	}
   859  	{
   860  		var flagSet flag.FlagSet
   861  		err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"})
   862  		if err == nil {
   863  			// actually present in the user's filesystem
   864  		} else if !strings.Contains(err.Error(), "no such package") {
   865  			t.Errorf("unexpected error %q from nosuchpackage Foo", err)
   866  		}
   867  	}
   868  }
   869  
   870  // Test the code to look up packages when the first argument starts with "./".
   871  // Our test case is in effect "cd src/text; doc ./template". This should get
   872  // text/template but before Issue 23383 was fixed would give html/template.
   873  func TestDotSlashLookup(t *testing.T) {
   874  	if testing.Short() {
   875  		t.Skip("scanning file system takes too long")
   876  	}
   877  	maybeSkip(t)
   878  	where := pwd()
   879  	defer func() {
   880  		if err := os.Chdir(where); err != nil {
   881  			t.Fatal(err)
   882  		}
   883  	}()
   884  	if err := os.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text")); err != nil {
   885  		t.Fatal(err)
   886  	}
   887  	var b bytes.Buffer
   888  	var flagSet flag.FlagSet
   889  	err := do(&b, &flagSet, []string{"./template"})
   890  	if err != nil {
   891  		t.Errorf("unexpected error %q from ./template", err)
   892  	}
   893  	// The output should contain information about the text/template package.
   894  	const want = `package template // import "text/template"`
   895  	output := b.String()
   896  	if !strings.HasPrefix(output, want) {
   897  		t.Fatalf("wrong package: %.*q...", len(want), output)
   898  	}
   899  }
   900  
   901  type trimTest struct {
   902  	path   string
   903  	prefix string
   904  	result string
   905  	ok     bool
   906  }
   907  
   908  var trimTests = []trimTest{
   909  	{"", "", "", true},
   910  	{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
   911  	{"/usr/gopher/bar", "/usr/gopher", "bar", true},
   912  	{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
   913  	{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
   914  }
   915  
   916  func TestTrim(t *testing.T) {
   917  	for _, test := range trimTests {
   918  		result, ok := trim(test.path, test.prefix)
   919  		if ok != test.ok {
   920  			t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
   921  			continue
   922  		}
   923  		if result != test.result {
   924  			t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
   925  			continue
   926  		}
   927  	}
   928  }