2015-06-19 12:39:02 +10:00
|
|
|
// 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"
|
|
|
|
|
"regexp"
|
2015-06-20 20:28:46 +10:00
|
|
|
"runtime"
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
"strings"
|
2015-06-19 12:39:02 +10:00
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
func maybeSkip(t *testing.T) {
|
|
|
|
|
if strings.HasPrefix(runtime.GOOS, "nacl") {
|
|
|
|
|
t.Skip("nacl does not have a full file tree")
|
|
|
|
|
}
|
|
|
|
|
if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") {
|
|
|
|
|
t.Skip("darwin/arm does not have a full file tree")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 12:39:02 +10:00
|
|
|
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.
|
|
|
|
|
{
|
2015-06-20 08:12:10 +10:00
|
|
|
"sanity check",
|
|
|
|
|
[]string{p},
|
|
|
|
|
[]string{`type ExportedType struct`},
|
2015-06-19 12:39:02 +10:00
|
|
|
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.
|
2015-06-21 05:10:05 +10:00
|
|
|
`const ConstOne = 1`, // First entry in constant block.
|
2015-09-18 14:53:33 -07:00
|
|
|
`const ConstFive ...`, // From block starting with unexported constant.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var ExportedVariable = 1`, // Simple variable.
|
|
|
|
|
`var VarOne = 1`, // First entry in variable block.
|
2015-06-19 12:39:02 +10:00
|
|
|
`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.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var internalVariable = 2`, // No internal variables.
|
2015-06-19 12:39:02 +10:00
|
|
|
`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.
|
2015-09-18 14:53:33 -07:00
|
|
|
`VarFive = 5`, // From block starting with unexported variable.
|
2015-06-19 12:39:02 +10:00
|
|
|
`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.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var ExportedVariable = 1`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Single variable -u.
|
|
|
|
|
{
|
|
|
|
|
"single variable with -u",
|
|
|
|
|
[]string{`-u`, p, `internalVariable`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about internal variable`, // Include comment.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var internalVariable = 2`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
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.
|
2015-06-20 20:28:46 +10:00
|
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
[]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) {
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
maybeSkip(t)
|
2015-06-19 12:39:02 +10:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
// Test the code to try multiple packages. Our test case is
|
|
|
|
|
// go doc rand.Float64
|
|
|
|
|
// This needs to find math/rand.Float64; however crypto/rand, which doesn't
|
|
|
|
|
// have the symbol, usually appears first in the directory listing.
|
|
|
|
|
func TestMultiplePackages(t *testing.T) {
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
t.Skip("scanning file system takes too long")
|
|
|
|
|
}
|
|
|
|
|
maybeSkip(t)
|
|
|
|
|
var b bytes.Buffer // We don't care about the output.
|
|
|
|
|
// Make sure crypto/rand does not have the symbol.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"crypto/rand.float64"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf("expected error from crypto/rand.float64")
|
|
|
|
|
} else if !strings.Contains(err.Error(), "no symbol float64") {
|
|
|
|
|
t.Errorf("unexpected error %q from crypto/rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Make sure math/rand does have the symbol.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"math/rand.float64"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from math/rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Try the shorthand.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"rand.float64"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Now try a missing symbol. We should see both packages in the error.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"rand.doesnotexit"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf("expected error from rand.doesnotexit")
|
|
|
|
|
} else {
|
|
|
|
|
errStr := err.Error()
|
|
|
|
|
if !strings.Contains(errStr, "no symbol") {
|
|
|
|
|
t.Errorf("error %q should contain 'no symbol", errStr)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(errStr, "crypto/rand") {
|
|
|
|
|
t.Errorf("error %q should contain crypto/rand", errStr)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(errStr, "math/rand") {
|
|
|
|
|
t.Errorf("error %q should contain math/rand", errStr)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-19 12:39:02 +10:00
|
|
|
}
|
|
|
|
|
}
|
2015-09-28 13:45:57 -07:00
|
|
|
|
|
|
|
|
type trimTest struct {
|
|
|
|
|
path string
|
|
|
|
|
prefix string
|
|
|
|
|
result string
|
|
|
|
|
ok bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var trimTests = []trimTest{
|
|
|
|
|
{"", "", "", true},
|
|
|
|
|
{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
|
|
|
|
|
{"/usr/gopher/bar", "/usr/gopher", "bar", true},
|
|
|
|
|
{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
|
|
|
|
|
{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
|
|
|
|
|
{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestTrim(t *testing.T) {
|
|
|
|
|
for _, test := range trimTests {
|
|
|
|
|
result, ok := trim(test.path, test.prefix)
|
|
|
|
|
if ok != test.ok {
|
|
|
|
|
t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if result != test.result {
|
|
|
|
|
t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|