github.com/aloncn/graphics-go@v0.0.1/src/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  	"regexp"
    11  	"runtime"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func maybeSkip(t *testing.T) {
    17  	if strings.HasPrefix(runtime.GOOS, "nacl") {
    18  		t.Skip("nacl does not have a full file tree")
    19  	}
    20  	if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") {
    21  		t.Skip("darwin/arm does not have a full file tree")
    22  	}
    23  }
    24  
    25  const (
    26  	dataDir = "testdata"
    27  	binary  = "testdoc"
    28  )
    29  
    30  type test struct {
    31  	name string
    32  	args []string // Arguments to "[go] doc".
    33  	yes  []string // Regular expressions that should match.
    34  	no   []string // Regular expressions that should not match.
    35  }
    36  
    37  const p = "cmd/doc/testdata"
    38  
    39  var tests = []test{
    40  	// Sanity check.
    41  	{
    42  		"sanity check",
    43  		[]string{p},
    44  		[]string{`type ExportedType struct`},
    45  		nil,
    46  	},
    47  
    48  	// Package dump includes import, package statement.
    49  	{
    50  		"package clause",
    51  		[]string{p},
    52  		[]string{`package pkg.*cmd/doc/testdata`},
    53  		nil,
    54  	},
    55  
    56  	// Constants.
    57  	// Package dump
    58  	{
    59  		"full package",
    60  		[]string{p},
    61  		[]string{
    62  			`Package comment`,
    63  			`const ExportedConstant = 1`,                            // Simple constant.
    64  			`const ConstOne = 1`,                                    // First entry in constant block.
    65  			`const ConstFive ...`,                                   // From block starting with unexported constant.
    66  			`var ExportedVariable = 1`,                              // Simple variable.
    67  			`var VarOne = 1`,                                        // First entry in variable block.
    68  			`func ExportedFunc\(a int\) bool`,                       // Function.
    69  			`type ExportedType struct { ... }`,                      // Exported type.
    70  			`const ExportedTypedConstant ExportedType = iota`,       // Typed constant.
    71  			`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
    72  		},
    73  		[]string{
    74  			`const internalConstant = 2`,        // No internal constants.
    75  			`var internalVariable = 2`,          // No internal variables.
    76  			`func internalFunc(a int) bool`,     // No internal functions.
    77  			`Comment about exported constant`,   // No comment for single constant.
    78  			`Comment about exported variable`,   // No comment for single variable.
    79  			`Comment about block of constants.`, // No comment for constant block.
    80  			`Comment about block of variables.`, // No comment for variable block.
    81  			`Comment before ConstOne`,           // No comment for first entry in constant block.
    82  			`Comment before VarOne`,             // No comment for first entry in variable block.
    83  			`ConstTwo = 2`,                      // No second entry in constant block.
    84  			`VarTwo = 2`,                        // No second entry in variable block.
    85  			`VarFive = 5`,                       // From block starting with unexported variable.
    86  			`type unexportedType`,               // No unexported type.
    87  			`unexportedTypedConstant`,           // No unexported typed constant.
    88  			`Field`,                             // No fields.
    89  			`Method`,                            // No methods.
    90  		},
    91  	},
    92  	// Package dump -u
    93  	{
    94  		"full package with u",
    95  		[]string{`-u`, p},
    96  		[]string{
    97  			`const ExportedConstant = 1`,      // Simple constant.
    98  			`const internalConstant = 2`,      // Internal constants.
    99  			`func internalFunc\(a int\) bool`, // Internal functions.
   100  		},
   101  		[]string{
   102  			`Comment about exported constant`,  // No comment for simple constant.
   103  			`Comment about block of constants`, // No comment for constant block.
   104  			`Comment about internal function`,  // No comment for internal function.
   105  		},
   106  	},
   107  
   108  	// Single constant.
   109  	{
   110  		"single constant",
   111  		[]string{p, `ExportedConstant`},
   112  		[]string{
   113  			`Comment about exported constant`, // Include comment.
   114  			`const ExportedConstant = 1`,
   115  		},
   116  		nil,
   117  	},
   118  	// Single constant -u.
   119  	{
   120  		"single constant with -u",
   121  		[]string{`-u`, p, `internalConstant`},
   122  		[]string{
   123  			`Comment about internal constant`, // Include comment.
   124  			`const internalConstant = 2`,
   125  		},
   126  		nil,
   127  	},
   128  	// Block of constants.
   129  	{
   130  		"block of constants",
   131  		[]string{p, `ConstTwo`},
   132  		[]string{
   133  			`Comment before ConstOne.\n.*ConstOne = 1`,    // First...
   134  			`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
   135  			`Comment about block of constants`,            // Comment does too.
   136  		},
   137  		[]string{
   138  			`constThree`, // No unexported constant.
   139  		},
   140  	},
   141  	// Block of constants -u.
   142  	{
   143  		"block of constants with -u",
   144  		[]string{"-u", p, `constThree`},
   145  		[]string{
   146  			`constThree = 3.*Comment on line with constThree`,
   147  		},
   148  		nil,
   149  	},
   150  
   151  	// Single variable.
   152  	{
   153  		"single variable",
   154  		[]string{p, `ExportedVariable`},
   155  		[]string{
   156  			`ExportedVariable`, // Include comment.
   157  			`var ExportedVariable = 1`,
   158  		},
   159  		nil,
   160  	},
   161  	// Single variable -u.
   162  	{
   163  		"single variable with -u",
   164  		[]string{`-u`, p, `internalVariable`},
   165  		[]string{
   166  			`Comment about internal variable`, // Include comment.
   167  			`var internalVariable = 2`,
   168  		},
   169  		nil,
   170  	},
   171  	// Block of variables.
   172  	{
   173  		"block of variables",
   174  		[]string{p, `VarTwo`},
   175  		[]string{
   176  			`Comment before VarOne.\n.*VarOne = 1`,    // First...
   177  			`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
   178  			`Comment about block of variables`,        // Comment does too.
   179  		},
   180  		[]string{
   181  			`varThree= 3`, // No unexported variable.
   182  		},
   183  	},
   184  	// Block of variables -u.
   185  	{
   186  		"block of variables with -u",
   187  		[]string{"-u", p, `varThree`},
   188  		[]string{
   189  			`varThree = 3.*Comment on line with varThree`,
   190  		},
   191  		nil,
   192  	},
   193  
   194  	// Function.
   195  	{
   196  		"function",
   197  		[]string{p, `ExportedFunc`},
   198  		[]string{
   199  			`Comment about exported function`, // Include comment.
   200  			`func ExportedFunc\(a int\) bool`,
   201  		},
   202  		nil,
   203  	},
   204  	// Function -u.
   205  	{
   206  		"function with -u",
   207  		[]string{"-u", p, `internalFunc`},
   208  		[]string{
   209  			`Comment about internal function`, // Include comment.
   210  			`func internalFunc\(a int\) bool`,
   211  		},
   212  		nil,
   213  	},
   214  
   215  	// Type.
   216  	{
   217  		"type",
   218  		[]string{p, `ExportedType`},
   219  		[]string{
   220  			`Comment about exported type`, // Include comment.
   221  			`type ExportedType struct`,    // Type definition.
   222  			`Comment before exported field.*\n.*ExportedField +int` +
   223  				`.*Comment on line with exported field.`,
   224  			`Has unexported fields`,
   225  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   226  			`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
   227  			`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
   228  		},
   229  		[]string{
   230  			`unexportedField`,                // No unexported field.
   231  			`Comment about exported method.`, // No comment about exported method.
   232  			`unexportedMethod`,               // No unexported method.
   233  			`unexportedTypedConstant`,        // No unexported constant.
   234  		},
   235  	},
   236  	// Type -u with unexported fields.
   237  	{
   238  		"type with unexported fields and -u",
   239  		[]string{"-u", p, `ExportedType`},
   240  		[]string{
   241  			`Comment about exported type`, // Include comment.
   242  			`type ExportedType struct`,    // Type definition.
   243  			`Comment before exported field.*\n.*ExportedField +int`,
   244  			`unexportedField int.*Comment on line with unexported field.`,
   245  			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
   246  			`unexportedTypedConstant`,
   247  		},
   248  		[]string{
   249  			`Has unexported fields`,
   250  		},
   251  	},
   252  	// Unexported type with -u.
   253  	{
   254  		"unexported type with -u",
   255  		[]string{"-u", p, `unexportedType`},
   256  		[]string{
   257  			`Comment about unexported type`, // Include comment.
   258  			`type unexportedType int`,       // Type definition.
   259  			`func \(unexportedType\) ExportedMethod\(\) bool`,
   260  			`func \(unexportedType\) unexportedMethod\(\) bool`,
   261  			`ExportedTypedConstant_unexported unexportedType = iota`,
   262  			`const unexportedTypedConstant unexportedType = 1`,
   263  		},
   264  		nil,
   265  	},
   266  
   267  	// Interface.
   268  	{
   269  		"type",
   270  		[]string{p, `ExportedInterface`},
   271  		[]string{
   272  			`Comment about exported interface`, // Include comment.
   273  			`type ExportedInterface interface`, // Interface definition.
   274  			`Comment before exported method.*\n.*ExportedMethod\(\)` +
   275  				`.*Comment on line with exported method`,
   276  			`Has unexported methods`,
   277  		},
   278  		[]string{
   279  			`unexportedField`,               // No unexported field.
   280  			`Comment about exported method`, // No comment about exported method.
   281  			`unexportedMethod`,              // No unexported method.
   282  			`unexportedTypedConstant`,       // No unexported constant.
   283  		},
   284  	},
   285  	// Interface -u with unexported methods.
   286  	{
   287  		"type with unexported methods and -u",
   288  		[]string{"-u", p, `ExportedInterface`},
   289  		[]string{
   290  			`Comment about exported interface`, // Include comment.
   291  			`type ExportedInterface interface`, // Interface definition.
   292  			`Comment before exported method.*\n.*ExportedMethod\(\)` +
   293  				`.*Comment on line with exported method`,
   294  			`unexportedMethod\(\).*Comment on line with unexported method.`,
   295  		},
   296  		[]string{
   297  			`Has unexported methods`,
   298  		},
   299  	},
   300  
   301  	// Method.
   302  	{
   303  		"method",
   304  		[]string{p, `ExportedType.ExportedMethod`},
   305  		[]string{
   306  			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
   307  			`Comment about exported method.`,
   308  		},
   309  		nil,
   310  	},
   311  	// Method  with -u.
   312  	{
   313  		"method with -u",
   314  		[]string{"-u", p, `ExportedType.unexportedMethod`},
   315  		[]string{
   316  			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
   317  			`Comment about unexported method.`,
   318  		},
   319  		nil,
   320  	},
   321  
   322  	// Case matching off.
   323  	{
   324  		"case matching off",
   325  		[]string{p, `casematch`},
   326  		[]string{
   327  			`CaseMatch`,
   328  			`Casematch`,
   329  		},
   330  		nil,
   331  	},
   332  
   333  	// Case matching on.
   334  	{
   335  		"case matching on",
   336  		[]string{"-c", p, `Casematch`},
   337  		[]string{
   338  			`Casematch`,
   339  		},
   340  		[]string{
   341  			`CaseMatch`,
   342  		},
   343  	},
   344  }
   345  
   346  func TestDoc(t *testing.T) {
   347  	maybeSkip(t)
   348  	for _, test := range tests {
   349  		var b bytes.Buffer
   350  		var flagSet flag.FlagSet
   351  		err := do(&b, &flagSet, test.args)
   352  		if err != nil {
   353  			t.Fatalf("%s: %s\n", test.name, err)
   354  		}
   355  		output := b.Bytes()
   356  		failed := false
   357  		for j, yes := range test.yes {
   358  			re, err := regexp.Compile(yes)
   359  			if err != nil {
   360  				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
   361  			}
   362  			if !re.Match(output) {
   363  				t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
   364  				failed = true
   365  			}
   366  		}
   367  		for j, no := range test.no {
   368  			re, err := regexp.Compile(no)
   369  			if err != nil {
   370  				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
   371  			}
   372  			if re.Match(output) {
   373  				t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
   374  				failed = true
   375  			}
   376  		}
   377  		if failed {
   378  			t.Logf("\n%s", output)
   379  		}
   380  	}
   381  }
   382  
   383  // Test the code to try multiple packages. Our test case is
   384  //	go doc rand.Float64
   385  // This needs to find math/rand.Float64; however crypto/rand, which doesn't
   386  // have the symbol, usually appears first in the directory listing.
   387  func TestMultiplePackages(t *testing.T) {
   388  	if testing.Short() {
   389  		t.Skip("scanning file system takes too long")
   390  	}
   391  	maybeSkip(t)
   392  	var b bytes.Buffer // We don't care about the output.
   393  	// Make sure crypto/rand does not have the symbol.
   394  	{
   395  		var flagSet flag.FlagSet
   396  		err := do(&b, &flagSet, []string{"crypto/rand.float64"})
   397  		if err == nil {
   398  			t.Errorf("expected error from crypto/rand.float64")
   399  		} else if !strings.Contains(err.Error(), "no symbol float64") {
   400  			t.Errorf("unexpected error %q from crypto/rand.float64", err)
   401  		}
   402  	}
   403  	// Make sure math/rand does have the symbol.
   404  	{
   405  		var flagSet flag.FlagSet
   406  		err := do(&b, &flagSet, []string{"math/rand.float64"})
   407  		if err != nil {
   408  			t.Errorf("unexpected error %q from math/rand.float64", err)
   409  		}
   410  	}
   411  	// Try the shorthand.
   412  	{
   413  		var flagSet flag.FlagSet
   414  		err := do(&b, &flagSet, []string{"rand.float64"})
   415  		if err != nil {
   416  			t.Errorf("unexpected error %q from rand.float64", err)
   417  		}
   418  	}
   419  	// Now try a missing symbol. We should see both packages in the error.
   420  	{
   421  		var flagSet flag.FlagSet
   422  		err := do(&b, &flagSet, []string{"rand.doesnotexit"})
   423  		if err == nil {
   424  			t.Errorf("expected error from rand.doesnotexit")
   425  		} else {
   426  			errStr := err.Error()
   427  			if !strings.Contains(errStr, "no symbol") {
   428  				t.Errorf("error %q should contain 'no symbol", errStr)
   429  			}
   430  			if !strings.Contains(errStr, "crypto/rand") {
   431  				t.Errorf("error %q should contain crypto/rand", errStr)
   432  			}
   433  			if !strings.Contains(errStr, "math/rand") {
   434  				t.Errorf("error %q should contain math/rand", errStr)
   435  			}
   436  		}
   437  	}
   438  }
   439  
   440  type trimTest struct {
   441  	path   string
   442  	prefix string
   443  	result string
   444  	ok     bool
   445  }
   446  
   447  var trimTests = []trimTest{
   448  	{"", "", "", true},
   449  	{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
   450  	{"/usr/gopher/bar", "/usr/gopher", "bar", true},
   451  	{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
   452  	{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
   453  	{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
   454  }
   455  
   456  func TestTrim(t *testing.T) {
   457  	for _, test := range trimTests {
   458  		result, ok := trim(test.path, test.prefix)
   459  		if ok != test.ok {
   460  			t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
   461  			continue
   462  		}
   463  		if result != test.result {
   464  			t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
   465  			continue
   466  		}
   467  	}
   468  }