Add generated file
This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
2
vendor/golang.org/x/tools/cmd/cover/README
generated
vendored
Normal file
2
vendor/golang.org/x/tools/cmd/cover/README
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
NOTE: For Go releases 1.5 and later, this tool lives in the
|
||||
standard repository. The code here is not maintained.
|
722
vendor/golang.org/x/tools/cmd/cover/cover.go
generated
vendored
Normal file
722
vendor/golang.org/x/tools/cmd/cover/cover.go
generated
vendored
Normal file
@@ -0,0 +1,722 @@
|
||||
// Copyright 2013 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"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const usageMessage = "" +
|
||||
`Usage of 'go tool cover':
|
||||
Given a coverage profile produced by 'go test':
|
||||
go test -coverprofile=c.out
|
||||
|
||||
Open a web browser displaying annotated source code:
|
||||
go tool cover -html=c.out
|
||||
|
||||
Write out an HTML file instead of launching a web browser:
|
||||
go tool cover -html=c.out -o coverage.html
|
||||
|
||||
Display coverage percentages to stdout for each function:
|
||||
go tool cover -func=c.out
|
||||
|
||||
Finally, to generate modified source code with coverage annotations
|
||||
(what go test -cover does):
|
||||
go tool cover -mode=set -var=CoverageVariableName program.go
|
||||
`
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
fmt.Fprintln(os.Stderr, "Flags:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(os.Stderr, "\n Only one of -html, -func, or -mode may be set.")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var (
|
||||
mode = flag.String("mode", "", "coverage mode: set, count, atomic")
|
||||
varVar = flag.String("var", "GoCover", "name of coverage variable to generate")
|
||||
output = flag.String("o", "", "file for output; default: stdout")
|
||||
htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
|
||||
funcOut = flag.String("func", "", "output coverage profile information for each function")
|
||||
)
|
||||
|
||||
var profile string // The profile to read; the value of -html or -func
|
||||
|
||||
var counterStmt func(*File, ast.Expr) ast.Stmt
|
||||
|
||||
const (
|
||||
atomicPackagePath = "sync/atomic"
|
||||
atomicPackageName = "_cover_atomic_"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
// Usage information when no arguments.
|
||||
if flag.NFlag() == 0 && flag.NArg() == 0 {
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
err := parseFlags()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// Generate coverage-annotated source.
|
||||
if *mode != "" {
|
||||
annotate(flag.Arg(0))
|
||||
return
|
||||
}
|
||||
|
||||
// Output HTML or function coverage information.
|
||||
if *htmlOut != "" {
|
||||
err = htmlOutput(profile, *output)
|
||||
} else {
|
||||
err = funcOutput(profile, *output)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "cover: %v\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
// parseFlags sets the profile and counterStmt globals and performs validations.
|
||||
func parseFlags() error {
|
||||
profile = *htmlOut
|
||||
if *funcOut != "" {
|
||||
if profile != "" {
|
||||
return fmt.Errorf("too many options")
|
||||
}
|
||||
profile = *funcOut
|
||||
}
|
||||
|
||||
// Must either display a profile or rewrite Go source.
|
||||
if (profile == "") == (*mode == "") {
|
||||
return fmt.Errorf("too many options")
|
||||
}
|
||||
|
||||
if *mode != "" {
|
||||
switch *mode {
|
||||
case "set":
|
||||
counterStmt = setCounterStmt
|
||||
case "count":
|
||||
counterStmt = incCounterStmt
|
||||
case "atomic":
|
||||
counterStmt = atomicCounterStmt
|
||||
default:
|
||||
return fmt.Errorf("unknown -mode %v", *mode)
|
||||
}
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
return fmt.Errorf("missing source file")
|
||||
} else if flag.NArg() == 1 {
|
||||
return nil
|
||||
}
|
||||
} else if flag.NArg() == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
// Block represents the information about a basic block to be recorded in the analysis.
|
||||
// Note: Our definition of basic block is based on control structures; we don't break
|
||||
// apart && and ||. We could but it doesn't seem important enough to bother.
|
||||
type Block struct {
|
||||
startByte token.Pos
|
||||
endByte token.Pos
|
||||
numStmt int
|
||||
}
|
||||
|
||||
// File is a wrapper for the state of a file used in the parser.
|
||||
// The basic parse tree walker is a method of this type.
|
||||
type File struct {
|
||||
fset *token.FileSet
|
||||
name string // Name of file.
|
||||
astFile *ast.File
|
||||
blocks []Block
|
||||
atomicPkg string // Package name for "sync/atomic" in this file.
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
func (f *File) Visit(node ast.Node) ast.Visitor {
|
||||
switch n := node.(type) {
|
||||
case *ast.BlockStmt:
|
||||
// If it's a switch or select, the body is a list of case clauses; don't tag the block itself.
|
||||
if len(n.List) > 0 {
|
||||
switch n.List[0].(type) {
|
||||
case *ast.CaseClause: // switch
|
||||
for _, n := range n.List {
|
||||
clause := n.(*ast.CaseClause)
|
||||
clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
|
||||
}
|
||||
return f
|
||||
case *ast.CommClause: // select
|
||||
for _, n := range n.List {
|
||||
clause := n.(*ast.CommClause)
|
||||
clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
|
||||
}
|
||||
return f
|
||||
}
|
||||
}
|
||||
n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
|
||||
case *ast.IfStmt:
|
||||
ast.Walk(f, n.Body)
|
||||
if n.Else == nil {
|
||||
return nil
|
||||
}
|
||||
// The elses are special, because if we have
|
||||
// if x {
|
||||
// } else if y {
|
||||
// }
|
||||
// we want to cover the "if y". To do this, we need a place to drop the counter,
|
||||
// so we add a hidden block:
|
||||
// if x {
|
||||
// } else {
|
||||
// if y {
|
||||
// }
|
||||
// }
|
||||
switch stmt := n.Else.(type) {
|
||||
case *ast.IfStmt:
|
||||
block := &ast.BlockStmt{
|
||||
Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
List: []ast.Stmt{stmt},
|
||||
Rbrace: stmt.End(),
|
||||
}
|
||||
n.Else = block
|
||||
case *ast.BlockStmt:
|
||||
stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
|
||||
default:
|
||||
panic("unexpected node type in if")
|
||||
}
|
||||
ast.Walk(f, n.Else)
|
||||
return nil
|
||||
case *ast.SelectStmt:
|
||||
// Don't annotate an empty select - creates a syntax error.
|
||||
if n.Body == nil || len(n.Body.List) == 0 {
|
||||
return nil
|
||||
}
|
||||
case *ast.SwitchStmt:
|
||||
// Don't annotate an empty switch - creates a syntax error.
|
||||
if n.Body == nil || len(n.Body.List) == 0 {
|
||||
return nil
|
||||
}
|
||||
case *ast.TypeSwitchStmt:
|
||||
// Don't annotate an empty type switch - creates a syntax error.
|
||||
if n.Body == nil || len(n.Body.List) == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// unquote returns the unquoted string.
|
||||
func unquote(s string) string {
|
||||
t, err := strconv.Unquote(s)
|
||||
if err != nil {
|
||||
log.Fatalf("cover: improperly quoted string %q\n", s)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// addImport adds an import for the specified path, if one does not already exist, and returns
|
||||
// the local package name.
|
||||
func (f *File) addImport(path string) string {
|
||||
// Does the package already import it?
|
||||
for _, s := range f.astFile.Imports {
|
||||
if unquote(s.Path.Value) == path {
|
||||
if s.Name != nil {
|
||||
return s.Name.Name
|
||||
}
|
||||
return filepath.Base(path)
|
||||
}
|
||||
}
|
||||
newImport := &ast.ImportSpec{
|
||||
Name: ast.NewIdent(atomicPackageName),
|
||||
Path: &ast.BasicLit{
|
||||
Kind: token.STRING,
|
||||
Value: fmt.Sprintf("%q", path),
|
||||
},
|
||||
}
|
||||
impDecl := &ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
Specs: []ast.Spec{
|
||||
newImport,
|
||||
},
|
||||
}
|
||||
// Make the new import the first Decl in the file.
|
||||
astFile := f.astFile
|
||||
astFile.Decls = append(astFile.Decls, nil)
|
||||
copy(astFile.Decls[1:], astFile.Decls[0:])
|
||||
astFile.Decls[0] = impDecl
|
||||
astFile.Imports = append(astFile.Imports, newImport)
|
||||
|
||||
// Now refer to the package, just in case it ends up unused.
|
||||
// That is, append to the end of the file the declaration
|
||||
// var _ = _cover_atomic_.AddUint32
|
||||
reference := &ast.GenDecl{
|
||||
Tok: token.VAR,
|
||||
Specs: []ast.Spec{
|
||||
&ast.ValueSpec{
|
||||
Names: []*ast.Ident{
|
||||
ast.NewIdent("_"),
|
||||
},
|
||||
Values: []ast.Expr{
|
||||
&ast.SelectorExpr{
|
||||
X: ast.NewIdent(atomicPackageName),
|
||||
Sel: ast.NewIdent("AddUint32"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
astFile.Decls = append(astFile.Decls, reference)
|
||||
return atomicPackageName
|
||||
}
|
||||
|
||||
var slashslash = []byte("//")
|
||||
|
||||
// initialComments returns the prefix of content containing only
|
||||
// whitespace and line comments. Any +build directives must appear
|
||||
// within this region. This approach is more reliable than using
|
||||
// go/printer to print a modified AST containing comments.
|
||||
//
|
||||
func initialComments(content []byte) []byte {
|
||||
// Derived from go/build.Context.shouldBuild.
|
||||
end := 0
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 { // Blank line.
|
||||
end = len(content) - len(p)
|
||||
continue
|
||||
}
|
||||
if !bytes.HasPrefix(line, slashslash) { // Not comment line.
|
||||
break
|
||||
}
|
||||
}
|
||||
return content[:end]
|
||||
}
|
||||
|
||||
func annotate(name string) {
|
||||
fset := token.NewFileSet()
|
||||
content, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
log.Fatalf("cover: %s: %s", name, err)
|
||||
}
|
||||
parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments)
|
||||
if err != nil {
|
||||
log.Fatalf("cover: %s: %s", name, err)
|
||||
}
|
||||
parsedFile.Comments = trimComments(parsedFile, fset)
|
||||
|
||||
file := &File{
|
||||
fset: fset,
|
||||
name: name,
|
||||
astFile: parsedFile,
|
||||
}
|
||||
if *mode == "atomic" {
|
||||
file.atomicPkg = file.addImport(atomicPackagePath)
|
||||
}
|
||||
ast.Walk(file, file.astFile)
|
||||
fd := os.Stdout
|
||||
if *output != "" {
|
||||
var err error
|
||||
fd, err = os.Create(*output)
|
||||
if err != nil {
|
||||
log.Fatalf("cover: %s", err)
|
||||
}
|
||||
}
|
||||
fd.Write(initialComments(content)) // Retain '// +build' directives.
|
||||
file.print(fd)
|
||||
// After printing the source tree, add some declarations for the counters etc.
|
||||
// We could do this by adding to the tree, but it's easier just to print the text.
|
||||
file.addVariables(fd)
|
||||
}
|
||||
|
||||
// trimComments drops all but the //go: comments, some of which are semantically important.
|
||||
// We drop all others because they can appear in places that cause our counters
|
||||
// to appear in syntactically incorrect places. //go: appears at the beginning of
|
||||
// the line and is syntactically safe.
|
||||
func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
|
||||
var comments []*ast.CommentGroup
|
||||
for _, group := range file.Comments {
|
||||
var list []*ast.Comment
|
||||
for _, comment := range group.List {
|
||||
if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
|
||||
list = append(list, comment)
|
||||
}
|
||||
}
|
||||
if list != nil {
|
||||
comments = append(comments, &ast.CommentGroup{List: list})
|
||||
}
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
||||
func (f *File) print(w io.Writer) {
|
||||
printer.Fprint(w, f.fset, f.astFile)
|
||||
}
|
||||
|
||||
// intLiteral returns an ast.BasicLit representing the integer value.
|
||||
func (f *File) intLiteral(i int) *ast.BasicLit {
|
||||
node := &ast.BasicLit{
|
||||
Kind: token.INT,
|
||||
Value: fmt.Sprint(i),
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// index returns an ast.BasicLit representing the number of counters present.
|
||||
func (f *File) index() *ast.BasicLit {
|
||||
return f.intLiteral(len(f.blocks))
|
||||
}
|
||||
|
||||
// setCounterStmt returns the expression: __count[23] = 1.
|
||||
func setCounterStmt(f *File, counter ast.Expr) ast.Stmt {
|
||||
return &ast.AssignStmt{
|
||||
Lhs: []ast.Expr{counter},
|
||||
Tok: token.ASSIGN,
|
||||
Rhs: []ast.Expr{f.intLiteral(1)},
|
||||
}
|
||||
}
|
||||
|
||||
// incCounterStmt returns the expression: __count[23]++.
|
||||
func incCounterStmt(f *File, counter ast.Expr) ast.Stmt {
|
||||
return &ast.IncDecStmt{
|
||||
X: counter,
|
||||
Tok: token.INC,
|
||||
}
|
||||
}
|
||||
|
||||
// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1)
|
||||
func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt {
|
||||
return &ast.ExprStmt{
|
||||
X: &ast.CallExpr{
|
||||
Fun: &ast.SelectorExpr{
|
||||
X: ast.NewIdent(f.atomicPkg),
|
||||
Sel: ast.NewIdent("AddUint32"),
|
||||
},
|
||||
Args: []ast.Expr{&ast.UnaryExpr{
|
||||
Op: token.AND,
|
||||
X: counter,
|
||||
},
|
||||
f.intLiteral(1),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// newCounter creates a new counter expression of the appropriate form.
|
||||
func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt {
|
||||
counter := &ast.IndexExpr{
|
||||
X: &ast.SelectorExpr{
|
||||
X: ast.NewIdent(*varVar),
|
||||
Sel: ast.NewIdent("Count"),
|
||||
},
|
||||
Index: f.index(),
|
||||
}
|
||||
stmt := counterStmt(f, counter)
|
||||
f.blocks = append(f.blocks, Block{start, end, numStmt})
|
||||
return stmt
|
||||
}
|
||||
|
||||
// addCounters takes a list of statements and adds counters to the beginning of
|
||||
// each basic block at the top level of that list. For instance, given
|
||||
//
|
||||
// S1
|
||||
// if cond {
|
||||
// S2
|
||||
// }
|
||||
// S3
|
||||
//
|
||||
// counters will be added before S1 and before S3. The block containing S2
|
||||
// will be visited in a separate call.
|
||||
// TODO: Nested simple blocks get unnecessary (but correct) counters
|
||||
func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt {
|
||||
// Special case: make sure we add a counter to an empty block. Can't do this below
|
||||
// or we will add a counter to an empty statement list after, say, a return statement.
|
||||
if len(list) == 0 {
|
||||
return []ast.Stmt{f.newCounter(pos, blockEnd, 0)}
|
||||
}
|
||||
// We have a block (statement list), but it may have several basic blocks due to the
|
||||
// appearance of statements that affect the flow of control.
|
||||
var newList []ast.Stmt
|
||||
for {
|
||||
// Find first statement that affects flow of control (break, continue, if, etc.).
|
||||
// It will be the last statement of this basic block.
|
||||
var last int
|
||||
end := blockEnd
|
||||
for last = 0; last < len(list); last++ {
|
||||
end = f.statementBoundary(list[last])
|
||||
if f.endsBasicSourceBlock(list[last]) {
|
||||
extendToClosingBrace = false // Block is broken up now.
|
||||
last++
|
||||
break
|
||||
}
|
||||
}
|
||||
if extendToClosingBrace {
|
||||
end = blockEnd
|
||||
}
|
||||
if pos != end { // Can have no source to cover if e.g. blocks abut.
|
||||
newList = append(newList, f.newCounter(pos, end, last))
|
||||
}
|
||||
newList = append(newList, list[0:last]...)
|
||||
list = list[last:]
|
||||
if len(list) == 0 {
|
||||
break
|
||||
}
|
||||
pos = list[0].Pos()
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
// hasFuncLiteral reports the existence and position of the first func literal
|
||||
// in the node, if any. If a func literal appears, it usually marks the termination
|
||||
// of a basic block because the function body is itself a block.
|
||||
// Therefore we draw a line at the start of the body of the first function literal we find.
|
||||
// TODO: what if there's more than one? Probably doesn't matter much.
|
||||
func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
|
||||
if n == nil {
|
||||
return false, 0
|
||||
}
|
||||
var literal funcLitFinder
|
||||
ast.Walk(&literal, n)
|
||||
return literal.found(), token.Pos(literal)
|
||||
}
|
||||
|
||||
// statementBoundary finds the location in s that terminates the current basic
|
||||
// block in the source.
|
||||
func (f *File) statementBoundary(s ast.Stmt) token.Pos {
|
||||
// Control flow statements are easy.
|
||||
switch s := s.(type) {
|
||||
case *ast.BlockStmt:
|
||||
// Treat blocks like basic blocks to avoid overlapping counters.
|
||||
return s.Lbrace
|
||||
case *ast.IfStmt:
|
||||
found, pos := hasFuncLiteral(s.Init)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
found, pos = hasFuncLiteral(s.Cond)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.Body.Lbrace
|
||||
case *ast.ForStmt:
|
||||
found, pos := hasFuncLiteral(s.Init)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
found, pos = hasFuncLiteral(s.Cond)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
found, pos = hasFuncLiteral(s.Post)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.Body.Lbrace
|
||||
case *ast.LabeledStmt:
|
||||
return f.statementBoundary(s.Stmt)
|
||||
case *ast.RangeStmt:
|
||||
found, pos := hasFuncLiteral(s.X)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.Body.Lbrace
|
||||
case *ast.SwitchStmt:
|
||||
found, pos := hasFuncLiteral(s.Init)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
found, pos = hasFuncLiteral(s.Tag)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.Body.Lbrace
|
||||
case *ast.SelectStmt:
|
||||
return s.Body.Lbrace
|
||||
case *ast.TypeSwitchStmt:
|
||||
found, pos := hasFuncLiteral(s.Init)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.Body.Lbrace
|
||||
}
|
||||
// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
|
||||
// If it does, that's tricky because we want to exclude the body of the function from this block.
|
||||
// Draw a line at the start of the body of the first function literal we find.
|
||||
// TODO: what if there's more than one? Probably doesn't matter much.
|
||||
found, pos := hasFuncLiteral(s)
|
||||
if found {
|
||||
return pos
|
||||
}
|
||||
return s.End()
|
||||
}
|
||||
|
||||
// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc.,
|
||||
// or if it's just problematic, for instance contains a function literal, which will complicate
|
||||
// accounting due to the block-within-an expression.
|
||||
func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
|
||||
switch s := s.(type) {
|
||||
case *ast.BlockStmt:
|
||||
// Treat blocks like basic blocks to avoid overlapping counters.
|
||||
return true
|
||||
case *ast.BranchStmt:
|
||||
return true
|
||||
case *ast.ForStmt:
|
||||
return true
|
||||
case *ast.IfStmt:
|
||||
return true
|
||||
case *ast.LabeledStmt:
|
||||
return f.endsBasicSourceBlock(s.Stmt)
|
||||
case *ast.RangeStmt:
|
||||
return true
|
||||
case *ast.SwitchStmt:
|
||||
return true
|
||||
case *ast.SelectStmt:
|
||||
return true
|
||||
case *ast.TypeSwitchStmt:
|
||||
return true
|
||||
case *ast.ExprStmt:
|
||||
// Calls to panic change the flow.
|
||||
// We really should verify that "panic" is the predefined function,
|
||||
// but without type checking we can't and the likelihood of it being
|
||||
// an actual problem is vanishingly small.
|
||||
if call, ok := s.X.(*ast.CallExpr); ok {
|
||||
if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
found, _ := hasFuncLiteral(s)
|
||||
return found
|
||||
}
|
||||
|
||||
// funcLitFinder implements the ast.Visitor pattern to find the location of any
|
||||
// function literal in a subtree.
|
||||
type funcLitFinder token.Pos
|
||||
|
||||
func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) {
|
||||
if f.found() {
|
||||
return nil // Prune search.
|
||||
}
|
||||
switch n := node.(type) {
|
||||
case *ast.FuncLit:
|
||||
*f = funcLitFinder(n.Body.Lbrace)
|
||||
return nil // Prune search.
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *funcLitFinder) found() bool {
|
||||
return token.Pos(*f) != token.NoPos
|
||||
}
|
||||
|
||||
// Sort interface for []block1; used for self-check in addVariables.
|
||||
|
||||
type block1 struct {
|
||||
Block
|
||||
index int
|
||||
}
|
||||
|
||||
type blockSlice []block1
|
||||
|
||||
func (b blockSlice) Len() int { return len(b) }
|
||||
func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte }
|
||||
func (b blockSlice) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
|
||||
// offset translates a token position into a 0-indexed byte offset.
|
||||
func (f *File) offset(pos token.Pos) int {
|
||||
return f.fset.Position(pos).Offset
|
||||
}
|
||||
|
||||
// addVariables adds to the end of the file the declarations to set up the counter and position variables.
|
||||
func (f *File) addVariables(w io.Writer) {
|
||||
// Self-check: Verify that the instrumented basic blocks are disjoint.
|
||||
t := make([]block1, len(f.blocks))
|
||||
for i := range f.blocks {
|
||||
t[i].Block = f.blocks[i]
|
||||
t[i].index = i
|
||||
}
|
||||
sort.Sort(blockSlice(t))
|
||||
for i := 1; i < len(t); i++ {
|
||||
if t[i-1].endByte > t[i].startByte {
|
||||
fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index)
|
||||
// Note: error message is in byte positions, not token positions.
|
||||
fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n",
|
||||
f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte),
|
||||
f.name, f.offset(t[i].startByte), f.offset(t[i].endByte))
|
||||
}
|
||||
}
|
||||
|
||||
// Declare the coverage struct as a package-level variable.
|
||||
fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar)
|
||||
fmt.Fprintf(w, "\tCount [%d]uint32\n", len(f.blocks))
|
||||
fmt.Fprintf(w, "\tPos [3 * %d]uint32\n", len(f.blocks))
|
||||
fmt.Fprintf(w, "\tNumStmt [%d]uint16\n", len(f.blocks))
|
||||
fmt.Fprintf(w, "} {\n")
|
||||
|
||||
// Initialize the position array field.
|
||||
fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks))
|
||||
|
||||
// A nice long list of positions. Each position is encoded as follows to reduce size:
|
||||
// - 32-bit starting line number
|
||||
// - 32-bit ending line number
|
||||
// - (16 bit ending column number << 16) | (16-bit starting column number).
|
||||
for i, block := range f.blocks {
|
||||
start := f.fset.Position(block.startByte)
|
||||
end := f.fset.Position(block.endByte)
|
||||
fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
|
||||
}
|
||||
|
||||
// Close the position array.
|
||||
fmt.Fprintf(w, "\t},\n")
|
||||
|
||||
// Initialize the position array field.
|
||||
fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks))
|
||||
|
||||
// A nice long list of statements-per-block, so we can give a conventional
|
||||
// valuation of "percent covered". To save space, it's a 16-bit number, so we
|
||||
// clamp it if it overflows - won't matter in practice.
|
||||
for i, block := range f.blocks {
|
||||
n := block.numStmt
|
||||
if n > 1<<16-1 {
|
||||
n = 1<<16 - 1
|
||||
}
|
||||
fmt.Fprintf(w, "\t\t%d, // %d\n", n, i)
|
||||
}
|
||||
|
||||
// Close the statements-per-block array.
|
||||
fmt.Fprintf(w, "\t},\n")
|
||||
|
||||
// Close the struct initialization.
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
94
vendor/golang.org/x/tools/cmd/cover/cover_test.go
generated
vendored
Normal file
94
vendor/golang.org/x/tools/cmd/cover/cover_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// No testdata on Android.
|
||||
|
||||
// +build !android
|
||||
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
// Data directory, also the package directory for the test.
|
||||
testdata = "testdata"
|
||||
|
||||
// Binaries we compile.
|
||||
testcover = "./testcover.exe"
|
||||
)
|
||||
|
||||
var (
|
||||
// Files we use.
|
||||
testMain = filepath.Join(testdata, "main.go")
|
||||
testTest = filepath.Join(testdata, "test.go")
|
||||
coverInput = filepath.Join(testdata, "test_line.go")
|
||||
coverOutput = filepath.Join(testdata, "test_cover.go")
|
||||
)
|
||||
|
||||
var debug = false // Keeps the rewritten files around if set.
|
||||
|
||||
// Run this shell script, but do it in Go so it can be run by "go test".
|
||||
//
|
||||
// replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
|
||||
// go build -o ./testcover
|
||||
// ./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
// go run ./testdata/main.go ./testdata/test.go
|
||||
//
|
||||
func TestCover(t *testing.T) {
|
||||
// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
|
||||
file, err := ioutil.ReadFile(testTest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lines := bytes.Split(file, []byte("\n"))
|
||||
for i, line := range lines {
|
||||
lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
|
||||
}
|
||||
err = ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// defer removal of test_line.go
|
||||
if !debug {
|
||||
defer os.Remove(coverInput)
|
||||
}
|
||||
|
||||
// go build -o testcover
|
||||
cmd := exec.Command("go", "build", "-o", testcover)
|
||||
run(cmd, t)
|
||||
|
||||
// defer removal of testcover
|
||||
defer os.Remove(testcover)
|
||||
|
||||
// ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
|
||||
cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
|
||||
run(cmd, t)
|
||||
|
||||
// defer removal of ./testdata/test_cover.go
|
||||
if !debug {
|
||||
defer os.Remove(coverOutput)
|
||||
}
|
||||
|
||||
// go run ./testdata/main.go ./testdata/test.go
|
||||
cmd = exec.Command("go", "run", testMain, coverOutput)
|
||||
run(cmd, t)
|
||||
}
|
||||
|
||||
func run(c *exec.Cmd, t *testing.T) {
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
err := c.Run()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
27
vendor/golang.org/x/tools/cmd/cover/doc.go
generated
vendored
Normal file
27
vendor/golang.org/x/tools/cmd/cover/doc.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
/*
|
||||
Cover is a program for analyzing the coverage profiles generated by
|
||||
'go test -coverprofile=cover.out'.
|
||||
|
||||
Cover is also used by 'go test -cover' to rewrite the source code with
|
||||
annotations to track which parts of each function are executed.
|
||||
It operates on one Go source file at a time, computing approximate
|
||||
basic block information by studying the source. It is thus more portable
|
||||
than binary-rewriting coverage tools, but also a little less capable.
|
||||
For instance, it does not probe inside && and || expressions, and can
|
||||
be mildly confused by single statements with multiple function literals.
|
||||
|
||||
For usage information, please see:
|
||||
go help testflag
|
||||
go tool cover -help
|
||||
|
||||
No longer maintained:
|
||||
|
||||
For Go releases 1.5 and later, this tool lives in the
|
||||
standard repository. The code here is not maintained.
|
||||
|
||||
*/
|
||||
package main // import "golang.org/x/tools/cmd/cover"
|
166
vendor/golang.org/x/tools/cmd/cover/func.go
generated
vendored
Normal file
166
vendor/golang.org/x/tools/cmd/cover/func.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// This file implements the visitor that computes the (line, column)-(line-column) range for each function.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/tools/cover"
|
||||
)
|
||||
|
||||
// funcOutput takes two file names as arguments, a coverage profile to read as input and an output
|
||||
// file to write ("" means to write to standard output). The function reads the profile and produces
|
||||
// as output the coverage data broken down by function, like this:
|
||||
//
|
||||
// fmt/format.go:30: init 100.0%
|
||||
// fmt/format.go:57: clearflags 100.0%
|
||||
// ...
|
||||
// fmt/scan.go:1046: doScan 100.0%
|
||||
// fmt/scan.go:1075: advance 96.2%
|
||||
// fmt/scan.go:1119: doScanf 96.8%
|
||||
// total: (statements) 91.9%
|
||||
|
||||
func funcOutput(profile, outputFile string) error {
|
||||
profiles, err := cover.ParseProfiles(profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var out *bufio.Writer
|
||||
if outputFile == "" {
|
||||
out = bufio.NewWriter(os.Stdout)
|
||||
} else {
|
||||
fd, err := os.Create(outputFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
out = bufio.NewWriter(fd)
|
||||
}
|
||||
defer out.Flush()
|
||||
|
||||
tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0)
|
||||
defer tabber.Flush()
|
||||
|
||||
var total, covered int64
|
||||
for _, profile := range profiles {
|
||||
fn := profile.FileName
|
||||
file, err := findFile(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
funcs, err := findFuncs(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Now match up functions and profile blocks.
|
||||
for _, f := range funcs {
|
||||
c, t := f.coverage(profile)
|
||||
fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
|
||||
total += t
|
||||
covered += c
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findFuncs parses the file and returns a slice of FuncExtent descriptors.
|
||||
func findFuncs(name string) ([]*FuncExtent, error) {
|
||||
fset := token.NewFileSet()
|
||||
parsedFile, err := parser.ParseFile(fset, name, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
visitor := &FuncVisitor{
|
||||
fset: fset,
|
||||
name: name,
|
||||
astFile: parsedFile,
|
||||
}
|
||||
ast.Walk(visitor, visitor.astFile)
|
||||
return visitor.funcs, nil
|
||||
}
|
||||
|
||||
// FuncExtent describes a function's extent in the source by file and position.
|
||||
type FuncExtent struct {
|
||||
name string
|
||||
startLine int
|
||||
startCol int
|
||||
endLine int
|
||||
endCol int
|
||||
}
|
||||
|
||||
// FuncVisitor implements the visitor that builds the function position list for a file.
|
||||
type FuncVisitor struct {
|
||||
fset *token.FileSet
|
||||
name string // Name of file.
|
||||
astFile *ast.File
|
||||
funcs []*FuncExtent
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor {
|
||||
switch n := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
start := v.fset.Position(n.Pos())
|
||||
end := v.fset.Position(n.End())
|
||||
fe := &FuncExtent{
|
||||
name: n.Name.Name,
|
||||
startLine: start.Line,
|
||||
startCol: start.Column,
|
||||
endLine: end.Line,
|
||||
endCol: end.Column,
|
||||
}
|
||||
v.funcs = append(v.funcs, fe)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator.
|
||||
func (f *FuncExtent) coverage(profile *cover.Profile) (num, den int64) {
|
||||
// We could avoid making this n^2 overall by doing a single scan and annotating the functions,
|
||||
// but the sizes of the data structures is never very large and the scan is almost instantaneous.
|
||||
var covered, total int64
|
||||
// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
|
||||
for _, b := range profile.Blocks {
|
||||
if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) {
|
||||
// Past the end of the function.
|
||||
break
|
||||
}
|
||||
if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) {
|
||||
// Before the beginning of the function
|
||||
continue
|
||||
}
|
||||
total += int64(b.NumStmt)
|
||||
if b.Count > 0 {
|
||||
covered += int64(b.NumStmt)
|
||||
}
|
||||
}
|
||||
if total == 0 {
|
||||
total = 1 // Avoid zero denominator.
|
||||
}
|
||||
return covered, total
|
||||
}
|
||||
|
||||
// findFile finds the location of the named file in GOROOT, GOPATH etc.
|
||||
func findFile(file string) (string, error) {
|
||||
dir, file := filepath.Split(file)
|
||||
pkg, err := build.Import(dir, ".", build.FindOnly)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("can't find %q: %v", file, err)
|
||||
}
|
||||
return filepath.Join(pkg.Dir, file), nil
|
||||
}
|
284
vendor/golang.org/x/tools/cmd/cover/html.go
generated
vendored
Normal file
284
vendor/golang.org/x/tools/cmd/cover/html.go
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
// Copyright 2013 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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/tools/cover"
|
||||
)
|
||||
|
||||
// htmlOutput reads the profile data from profile and generates an HTML
|
||||
// coverage report, writing it to outfile. If outfile is empty,
|
||||
// it writes the report to a temporary file and opens it in a web browser.
|
||||
func htmlOutput(profile, outfile string) error {
|
||||
profiles, err := cover.ParseProfiles(profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var d templateData
|
||||
|
||||
for _, profile := range profiles {
|
||||
fn := profile.FileName
|
||||
if profile.Mode == "set" {
|
||||
d.Set = true
|
||||
}
|
||||
file, err := findFile(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't read %q: %v", fn, err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = htmlGen(&buf, src, profile.Boundaries(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Files = append(d.Files, &templateFile{
|
||||
Name: fn,
|
||||
Body: template.HTML(buf.String()),
|
||||
Coverage: percentCovered(profile),
|
||||
})
|
||||
}
|
||||
|
||||
var out *os.File
|
||||
if outfile == "" {
|
||||
var dir string
|
||||
dir, err = ioutil.TempDir("", "cover")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err = os.Create(filepath.Join(dir, "coverage.html"))
|
||||
} else {
|
||||
out, err = os.Create(outfile)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = htmlTemplate.Execute(out, d)
|
||||
if err == nil {
|
||||
err = out.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if outfile == "" {
|
||||
if !startBrowser("file://" + out.Name()) {
|
||||
fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// percentCovered returns, as a percentage, the fraction of the statements in
|
||||
// the profile covered by the test run.
|
||||
// In effect, it reports the coverage of a given source file.
|
||||
func percentCovered(p *cover.Profile) float64 {
|
||||
var total, covered int64
|
||||
for _, b := range p.Blocks {
|
||||
total += int64(b.NumStmt)
|
||||
if b.Count > 0 {
|
||||
covered += int64(b.NumStmt)
|
||||
}
|
||||
}
|
||||
if total == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(covered) / float64(total) * 100
|
||||
}
|
||||
|
||||
// htmlGen generates an HTML coverage report with the provided filename,
|
||||
// source code, and tokens, and writes it to the given Writer.
|
||||
func htmlGen(w io.Writer, src []byte, boundaries []cover.Boundary) error {
|
||||
dst := bufio.NewWriter(w)
|
||||
for i := range src {
|
||||
for len(boundaries) > 0 && boundaries[0].Offset == i {
|
||||
b := boundaries[0]
|
||||
if b.Start {
|
||||
n := 0
|
||||
if b.Count > 0 {
|
||||
n = int(math.Floor(b.Norm*9)) + 1
|
||||
}
|
||||
fmt.Fprintf(dst, `<span class="cov%v" title="%v">`, n, b.Count)
|
||||
} else {
|
||||
dst.WriteString("</span>")
|
||||
}
|
||||
boundaries = boundaries[1:]
|
||||
}
|
||||
switch b := src[i]; b {
|
||||
case '>':
|
||||
dst.WriteString(">")
|
||||
case '<':
|
||||
dst.WriteString("<")
|
||||
case '&':
|
||||
dst.WriteString("&")
|
||||
case '\t':
|
||||
dst.WriteString(" ")
|
||||
default:
|
||||
dst.WriteByte(b)
|
||||
}
|
||||
}
|
||||
return dst.Flush()
|
||||
}
|
||||
|
||||
// startBrowser tries to open the URL in a browser
|
||||
// and reports whether it succeeds.
|
||||
func startBrowser(url string) bool {
|
||||
// try to start the browser
|
||||
var args []string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
args = []string{"open"}
|
||||
case "windows":
|
||||
args = []string{"cmd", "/c", "start"}
|
||||
default:
|
||||
args = []string{"xdg-open"}
|
||||
}
|
||||
cmd := exec.Command(args[0], append(args[1:], url)...)
|
||||
return cmd.Start() == nil
|
||||
}
|
||||
|
||||
// rgb returns an rgb value for the specified coverage value
|
||||
// between 0 (no coverage) and 10 (max coverage).
|
||||
func rgb(n int) string {
|
||||
if n == 0 {
|
||||
return "rgb(192, 0, 0)" // Red
|
||||
}
|
||||
// Gradient from gray to green.
|
||||
r := 128 - 12*(n-1)
|
||||
g := 128 + 12*(n-1)
|
||||
b := 128 + 3*(n-1)
|
||||
return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
|
||||
}
|
||||
|
||||
// colors generates the CSS rules for coverage colors.
|
||||
func colors() template.CSS {
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < 11; i++ {
|
||||
fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i))
|
||||
}
|
||||
return template.CSS(buf.String())
|
||||
}
|
||||
|
||||
var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{
|
||||
"colors": colors,
|
||||
}).Parse(tmplHTML))
|
||||
|
||||
type templateData struct {
|
||||
Files []*templateFile
|
||||
Set bool
|
||||
}
|
||||
|
||||
type templateFile struct {
|
||||
Name string
|
||||
Body template.HTML
|
||||
Coverage float64
|
||||
}
|
||||
|
||||
const tmplHTML = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
body {
|
||||
background: black;
|
||||
color: rgb(80, 80, 80);
|
||||
}
|
||||
body, pre, #legend span {
|
||||
font-family: Menlo, monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
#topbar {
|
||||
background: black;
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 42px;
|
||||
border-bottom: 1px solid rgb(80, 80, 80);
|
||||
}
|
||||
#content {
|
||||
margin-top: 50px;
|
||||
}
|
||||
#nav, #legend {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
#legend {
|
||||
margin-top: 12px;
|
||||
}
|
||||
#nav {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#legend span {
|
||||
margin: 0 5px;
|
||||
}
|
||||
{{colors}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
<div id="nav">
|
||||
<select id="files">
|
||||
{{range $i, $f := .Files}}
|
||||
<option value="file{{$i}}">{{$f.Name}} ({{printf "%.1f" $f.Coverage}}%)</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div id="legend">
|
||||
<span>not tracked</span>
|
||||
{{if .Set}}
|
||||
<span class="cov0">not covered</span>
|
||||
<span class="cov8">covered</span>
|
||||
{{else}}
|
||||
<span class="cov0">no coverage</span>
|
||||
<span class="cov1">low coverage</span>
|
||||
<span class="cov2">*</span>
|
||||
<span class="cov3">*</span>
|
||||
<span class="cov4">*</span>
|
||||
<span class="cov5">*</span>
|
||||
<span class="cov6">*</span>
|
||||
<span class="cov7">*</span>
|
||||
<span class="cov8">*</span>
|
||||
<span class="cov9">*</span>
|
||||
<span class="cov10">high coverage</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
{{range $i, $f := .Files}}
|
||||
<pre class="file" id="file{{$i}}" {{if $i}}style="display: none"{{end}}>{{$f.Body}}</pre>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
(function() {
|
||||
var files = document.getElementById('files');
|
||||
var visible = document.getElementById('file0');
|
||||
files.addEventListener('change', onChange, false);
|
||||
function onChange() {
|
||||
visible.style.display = 'none';
|
||||
visible = document.getElementById(files.value);
|
||||
visible.style.display = 'block';
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</html>
|
||||
`
|
112
vendor/golang.org/x/tools/cmd/cover/testdata/main.go
generated
vendored
Normal file
112
vendor/golang.org/x/tools/cmd/cover/testdata/main.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// Test runner for coverage test. This file is not coverage-annotated; test.go is.
|
||||
// It knows the coverage counter is called "coverTest".
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
testAll()
|
||||
verify()
|
||||
}
|
||||
|
||||
type block struct {
|
||||
count uint32
|
||||
line uint32
|
||||
}
|
||||
|
||||
var counters = make(map[block]bool)
|
||||
|
||||
// check records the location and expected value for a counter.
|
||||
func check(line, count uint32) {
|
||||
b := block{
|
||||
count,
|
||||
line,
|
||||
}
|
||||
counters[b] = true
|
||||
}
|
||||
|
||||
// checkVal is a version of check that returns its extra argument,
|
||||
// so it can be used in conditionals.
|
||||
func checkVal(line, count uint32, val int) int {
|
||||
b := block{
|
||||
count,
|
||||
line,
|
||||
}
|
||||
counters[b] = true
|
||||
return val
|
||||
}
|
||||
|
||||
var PASS = true
|
||||
|
||||
// verify checks the expected counts against the actual. It runs after the test has completed.
|
||||
func verify() {
|
||||
for b := range counters {
|
||||
got, index := count(b.line)
|
||||
if b.count == anything && got != 0 {
|
||||
got = anything
|
||||
}
|
||||
if got != b.count {
|
||||
fmt.Fprintf(os.Stderr, "test_go:%d expected count %d got %d [counter %d]\n", b.line, b.count, got, index)
|
||||
PASS = false
|
||||
}
|
||||
}
|
||||
verifyPanic()
|
||||
if !PASS {
|
||||
fmt.Fprintf(os.Stderr, "FAIL\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
// verifyPanic is a special check for the known counter that should be
|
||||
// after the panic call in testPanic.
|
||||
func verifyPanic() {
|
||||
if coverTest.Count[panicIndex-1] != 1 {
|
||||
// Sanity check for test before panic.
|
||||
fmt.Fprintf(os.Stderr, "bad before panic")
|
||||
PASS = false
|
||||
}
|
||||
if coverTest.Count[panicIndex] != 0 {
|
||||
fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex])
|
||||
PASS = false
|
||||
}
|
||||
if coverTest.Count[panicIndex+1] != 1 {
|
||||
fmt.Fprintf(os.Stderr, "bad after panic")
|
||||
PASS = false
|
||||
}
|
||||
}
|
||||
|
||||
// count returns the count and index for the counter at the specified line.
|
||||
func count(line uint32) (uint32, int) {
|
||||
// Linear search is fine. Choose perfect fit over approximate.
|
||||
// We can have a closing brace for a range on the same line as a condition for an "else if"
|
||||
// and we don't want that brace to steal the count for the condition on the "if".
|
||||
// Therefore we test for a perfect (lo==line && hi==line) match, but if we can't
|
||||
// find that we take the first imperfect match.
|
||||
index := -1
|
||||
indexLo := uint32(1e9)
|
||||
for i := range coverTest.Count {
|
||||
lo, hi := coverTest.Pos[3*i], coverTest.Pos[3*i+1]
|
||||
if lo == line && line == hi {
|
||||
return coverTest.Count[i], i
|
||||
}
|
||||
// Choose the earliest match (the counters are in unpredictable order).
|
||||
if lo <= line && line <= hi && indexLo > lo {
|
||||
index = i
|
||||
indexLo = lo
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
fmt.Fprintln(os.Stderr, "cover_test: no counter for line", line)
|
||||
PASS = false
|
||||
return 0, 0
|
||||
}
|
||||
return coverTest.Count[index], index
|
||||
}
|
218
vendor/golang.org/x/tools/cmd/cover/testdata/test.go
generated
vendored
Normal file
218
vendor/golang.org/x/tools/cmd/cover/testdata/test.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// This program is processed by the cover command, and then testAll is called.
|
||||
// The test driver in main.go can then compare the coverage statistics with expectation.
|
||||
|
||||
// The word LINE is replaced by the line number in this file. When the file is executed,
|
||||
// the coverage processing has changed the line numbers, so we can't use runtime.Caller.
|
||||
|
||||
package main
|
||||
|
||||
const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
|
||||
|
||||
func testAll() {
|
||||
testSimple()
|
||||
testBlockRun()
|
||||
testIf()
|
||||
testFor()
|
||||
testRange()
|
||||
testSwitch()
|
||||
testTypeSwitch()
|
||||
testSelect1()
|
||||
testSelect2()
|
||||
testPanic()
|
||||
testEmptySwitches()
|
||||
}
|
||||
|
||||
// The indexes of the counters in testPanic are known to main.go
|
||||
const panicIndex = 3
|
||||
|
||||
// This test appears first because the index of its counters is known to main.go
|
||||
func testPanic() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
check(LINE, 1)
|
||||
panic("should not get next line")
|
||||
check(LINE, 0) // this is GoCover.Count[panicIndex]
|
||||
// The next counter is in testSimple and it will be non-zero.
|
||||
// If the panic above does not trigger a counter, the test will fail
|
||||
// because GoCover.Count[panicIndex] will be the one in testSimple.
|
||||
}
|
||||
|
||||
func testSimple() {
|
||||
check(LINE, 1)
|
||||
}
|
||||
|
||||
func testIf() {
|
||||
if true {
|
||||
check(LINE, 1)
|
||||
} else {
|
||||
check(LINE, 0)
|
||||
}
|
||||
if false {
|
||||
check(LINE, 0)
|
||||
} else {
|
||||
check(LINE, 1)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if checkVal(LINE, 3, i) <= 2 {
|
||||
check(LINE, 3)
|
||||
}
|
||||
if checkVal(LINE, 3, i) <= 1 {
|
||||
check(LINE, 2)
|
||||
}
|
||||
if checkVal(LINE, 3, i) <= 0 {
|
||||
check(LINE, 1)
|
||||
}
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if checkVal(LINE, 3, i) <= 1 {
|
||||
check(LINE, 2)
|
||||
} else {
|
||||
check(LINE, 1)
|
||||
}
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if checkVal(LINE, 3, i) <= 0 {
|
||||
check(LINE, 1)
|
||||
} else if checkVal(LINE, 2, i) <= 1 {
|
||||
check(LINE, 1)
|
||||
} else if checkVal(LINE, 1, i) <= 2 {
|
||||
check(LINE, 1)
|
||||
} else if checkVal(LINE, 0, i) <= 3 {
|
||||
check(LINE, 0)
|
||||
}
|
||||
}
|
||||
if func(a, b int) bool { return a < b }(3, 4) {
|
||||
check(LINE, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func testFor() {
|
||||
for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
|
||||
check(LINE, 10)
|
||||
}
|
||||
}
|
||||
|
||||
func testRange() {
|
||||
for _, f := range []func(){
|
||||
func() { check(LINE, 1) },
|
||||
} {
|
||||
f()
|
||||
check(LINE, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func testBlockRun() {
|
||||
check(LINE, 1)
|
||||
{
|
||||
check(LINE, 1)
|
||||
}
|
||||
{
|
||||
check(LINE, 1)
|
||||
}
|
||||
check(LINE, 1)
|
||||
{
|
||||
check(LINE, 1)
|
||||
}
|
||||
{
|
||||
check(LINE, 1)
|
||||
}
|
||||
check(LINE, 1)
|
||||
}
|
||||
|
||||
func testSwitch() {
|
||||
for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
|
||||
switch i {
|
||||
case 0:
|
||||
check(LINE, 1)
|
||||
case 1:
|
||||
check(LINE, 1)
|
||||
case 2:
|
||||
check(LINE, 1)
|
||||
default:
|
||||
check(LINE, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypeSwitch() {
|
||||
var x = []interface{}{1, 2.0, "hi"}
|
||||
for _, v := range x {
|
||||
switch func() { check(LINE, 3) }(); v.(type) {
|
||||
case int:
|
||||
check(LINE, 1)
|
||||
case float64:
|
||||
check(LINE, 1)
|
||||
case string:
|
||||
check(LINE, 1)
|
||||
case complex128:
|
||||
check(LINE, 0)
|
||||
default:
|
||||
check(LINE, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSelect1() {
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
c <- i
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
check(LINE, anything)
|
||||
case <-c:
|
||||
check(LINE, anything)
|
||||
default:
|
||||
check(LINE, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSelect2() {
|
||||
c1 := make(chan int, 1000)
|
||||
c2 := make(chan int, 1000)
|
||||
for i := 0; i < 1000; i++ {
|
||||
c1 <- i
|
||||
c2 <- i
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-c1:
|
||||
check(LINE, 1000)
|
||||
case <-c2:
|
||||
check(LINE, 1000)
|
||||
default:
|
||||
check(LINE, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty control statements created syntax errors. This function
|
||||
// is here just to be sure that those are handled correctly now.
|
||||
func testEmptySwitches() {
|
||||
check(LINE, 1)
|
||||
switch 3 {
|
||||
}
|
||||
check(LINE, 1)
|
||||
switch i := (interface{})(3).(int); i {
|
||||
}
|
||||
check(LINE, 1)
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
check(LINE, 1)
|
||||
c <- 1
|
||||
select {}
|
||||
}()
|
||||
<-c
|
||||
check(LINE, 1)
|
||||
}
|
Reference in New Issue
Block a user