Skip to content

Commit

Permalink
cmd/doc: add test
Browse files Browse the repository at this point in the history
Refactor main a bit to make it possible to run tests without an exec every time.
(Makes a huge difference in run time.)

Add a silver test. Not quite golden, since it looks for pieces rather than the
full output, and also includes tests for what should not appear.

Fixes golang#10920.

Change-Id: I6a4951cc14e61763379754a10b0cc3484d30c267
Reviewed-on: https://go-review.googlesource.com/11272
Reviewed-by: Russ Cox <[email protected]>
Run-TryBot: Rob Pike <[email protected]>
  • Loading branch information
robpike committed Jun 19, 2015
1 parent 5ac5a98 commit d0652e7
Show file tree
Hide file tree
Showing 5 changed files with 514 additions and 28 deletions.
6 changes: 6 additions & 0 deletions misc/nacl/testzip.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ go src=..
asm
testdata
+
doc
main.go
pkg.go
doc_test.go
testdata
+
internal
objfile
objfile.go
Expand Down
343 changes: 343 additions & 0 deletions src/cmd/doc/doc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"bytes"
"flag"
"os"
"os/exec"
"regexp"
"testing"
)

const (
dataDir = "testdata"
binary = "testdoc"
)

type test struct {
name string
args []string // Arguments to "[go] doc".
yes []string // Regular expressions that should match.
no []string // Regular expressions that should not match.
}

const p = "cmd/doc/testdata"

var tests = []test{
// Sanity check.
{
"fmt",
[]string{`fmt`},
[]string{`type Formatter interface`},
nil,
},

// Package dump includes import, package statement.
{
"package clause",
[]string{p},
[]string{`package pkg.*cmd/doc/testdata`},
nil,
},

// Constants.
// Package dump
{
"full package",
[]string{p},
[]string{
`Package comment`,
`const ExportedConstant = 1`, // Simple constant.
`ConstOne = 1`, // First entry in constant block.
`const ExportedVariable = 1`, // Simple variable.
`VarOne = 1`, // First entry in variable block.
`func ExportedFunc\(a int\) bool`, // Function.
`type ExportedType struct { ... }`, // Exported type.
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
},
[]string{
`const internalConstant = 2`, // No internal constants.
`const internalVariable = 2`, // No internal variables.
`func internalFunc(a int) bool`, // No internal functions.
`Comment about exported constant`, // No comment for single constant.
`Comment about exported variable`, // No comment for single variable.
`Comment about block of constants.`, // No comment for constant block.
`Comment about block of variables.`, // No comment for variable block.
`Comment before ConstOne`, // No comment for first entry in constant block.
`Comment before VarOne`, // No comment for first entry in variable block.
`ConstTwo = 2`, // No second entry in constant block.
`VarTwo = 2`, // No second entry in variable block.
`type unexportedType`, // No unexported type.
`unexportedTypedConstant`, // No unexported typed constant.
`Field`, // No fields.
`Method`, // No methods.
},
},
// Package dump -u
{
"full package with u",
[]string{`-u`, p},
[]string{
`const ExportedConstant = 1`, // Simple constant.
`const internalConstant = 2`, // Internal constants.
`func internalFunc\(a int\) bool`, // Internal functions.
},
[]string{
`Comment about exported constant`, // No comment for simple constant.
`Comment about block of constants`, // No comment for constant block.
`Comment about internal function`, // No comment for internal function.
},
},

// Single constant.
{
"single constant",
[]string{p, `ExportedConstant`},
[]string{
`Comment about exported constant`, // Include comment.
`const ExportedConstant = 1`,
},
nil,
},
// Single constant -u.
{
"single constant with -u",
[]string{`-u`, p, `internalConstant`},
[]string{
`Comment about internal constant`, // Include comment.
`const internalConstant = 2`,
},
nil,
},
// Block of constants.
{
"block of constants",
[]string{p, `ConstTwo`},
[]string{
`Comment before ConstOne.\n.*ConstOne = 1`, // First...
`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
`Comment about block of constants`, // Comment does too.
},
[]string{
`constThree`, // No unexported constant.
},
},
// Block of constants -u.
{
"block of constants with -u",
[]string{"-u", p, `constThree`},
[]string{
`constThree = 3.*Comment on line with constThree`,
},
nil,
},

// Single variable.
{
"single variable",
[]string{p, `ExportedVariable`},
[]string{
`ExportedVariable`, // Include comment.
`const ExportedVariable = 1`,
},
nil,
},
// Single variable -u.
{
"single variable with -u",
[]string{`-u`, p, `internalVariable`},
[]string{
`Comment about internal variable`, // Include comment.
`const internalVariable = 2`,
},
nil,
},
// Block of variables.
{
"block of variables",
[]string{p, `VarTwo`},
[]string{
`Comment before VarOne.\n.*VarOne = 1`, // First...
`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
`Comment about block of variables`, // Comment does too.
},
[]string{
`varThree= 3`, // No unexported variable.
},
},
// Block of variables -u.
{
"block of variables with -u",
[]string{"-u", p, `varThree`},
[]string{
`varThree = 3.*Comment on line with varThree`,
},
nil,
},

// Function.
{
"function",
[]string{p, `ExportedFunc`},
[]string{
`Comment about exported function`, // Include comment.
`func ExportedFunc\(a int\) bool`,
},
nil,
},
// Function -u.
{
"function with -u",
[]string{"-u", p, `internalFunc`},
[]string{
`Comment about internal function`, // Include comment.
`func internalFunc\(a int\) bool`,
},
nil,
},

// Type.
{
"type",
[]string{p, `ExportedType`},
[]string{
`Comment about exported type`, // Include comment.
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int`,
`Has unexported fields`,
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
},
[]string{
`unexportedField`, // No unexported field.
`Comment about exported method.`, // No comment about exported method.
`unexportedMethod`, // No unexported method.
`unexportedTypedConstant`, // No unexported constant.
},
},
// Type -u with unexported fields.
{
"type with unexported fields and -u",
[]string{"-u", p, `ExportedType`},
[]string{
`Comment about exported type`, // Include comment.
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int`,
`unexportedField int.*Comment on line with unexported field.`,
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
`unexportedTypedConstant`,
},
[]string{
`Has unexported fields`,
},
},
// Unexported type with -u.
{
"unexported type with -u",
[]string{"-u", p, `unexportedType`},
[]string{
`Comment about unexported type`, // Include comment.
`type unexportedType int`, // Type definition.
`func \(unexportedType\) ExportedMethod\(\) bool`,
`func \(unexportedType\) unexportedMethod\(\) bool`,
`ExportedTypedConstant_unexported unexportedType = iota`,
`const unexportedTypedConstant unexportedType = 1`,
},
nil,
},

// Method.
{
"method",
[]string{p, `ExportedType.ExportedMethod`},
[]string{
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
`Comment about exported method.`,
},
nil,
},
// Method with -u.
{
"method with -u",
[]string{"-u", p, `ExportedType.unexportedMethod`},
[]string{
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
`Comment about unexported method.`,
},
nil,
},

// Case matching off.
{
"case matching off",
[]string{p, `casematch`},
[]string{
`CaseMatch`,
`Casematch`,
},
nil,
},

// Case matching on.
{
"case matching on",
[]string{"-c", p, `Casematch`},
[]string{
`Casematch`,
},
[]string{
`CaseMatch`,
},
},
}

func TestDoc(t *testing.T) {
for _, test := range tests {
var b bytes.Buffer
var flagSet flag.FlagSet
err := do(&b, &flagSet, test.args)
if err != nil {
t.Fatalf("%s: %s\n", test.name, err)
}
output := b.Bytes()
failed := false
for j, yes := range test.yes {
re, err := regexp.Compile(yes)
if err != nil {
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
}
if !re.Match(output) {
t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
failed = true
}
}
for j, no := range test.no {
re, err := regexp.Compile(no)
if err != nil {
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
}
if re.Match(output) {
t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
failed = true
}
}
if failed {
t.Logf("\n%s", output)
}
}
}

// run runs the command, but calls t.Fatal if there is an error.
func run(c *exec.Cmd, t *testing.T) []byte {
output, err := c.CombinedOutput()
if err != nil {
os.Stdout.Write(output)
t.Fatal(err)
}
return output
}
Loading

0 comments on commit d0652e7

Please sign in to comment.