mirror of
https://github.com/octoleo/restic.git
synced 2024-11-10 23:31:09 +00:00
Update dependencies
This, among others, updates the `go-flags` library, which includes a feature that closes #198.
This commit is contained in:
parent
d9a8dcfd67
commit
d9a90f7b89
22
Godeps/Godeps.json
generated
22
Godeps/Godeps.json
generated
@ -7,8 +7,8 @@
|
|||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/jessevdk/go-flags",
|
"ImportPath": "github.com/jessevdk/go-flags",
|
||||||
"Comment": "v1-293-g5e11878",
|
"Comment": "v1-297-g1b89bf7",
|
||||||
"Rev": "5e118789801496c93ba210d34ef1f2ce5a9173bd"
|
"Rev": "1b89bf73cd2c3a911d7b2a279ab085c4a18cf539"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/juju/errors",
|
"ImportPath": "github.com/juju/errors",
|
||||||
@ -26,17 +26,9 @@
|
|||||||
"ImportPath": "github.com/mitchellh/goamz/s3",
|
"ImportPath": "github.com/mitchellh/goamz/s3",
|
||||||
"Rev": "caaaea8b30ee15616494ee68abd5d8ebbbef05cf"
|
"Rev": "caaaea8b30ee15616494ee68abd5d8ebbbef05cf"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mitchellh/goamz/testutil",
|
|
||||||
"Rev": "caaaea8b30ee15616494ee68abd5d8ebbbef05cf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/motain/gocheck",
|
|
||||||
"Rev": "9beb271d26e640863a5bf4a3c5ea40ccdd466b84"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pkg/sftp",
|
"ImportPath": "github.com/pkg/sftp",
|
||||||
"Rev": "506297c9013d2893d5c5daaa9155e7333a1c58de"
|
"Rev": "518aed2757a65cfa64d4b1b2baf08410f8b7a6bc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vaughan0/go-ini",
|
"ImportPath": "github.com/vaughan0/go-ini",
|
||||||
@ -44,19 +36,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||||
"Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248"
|
"Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/poly1305",
|
"ImportPath": "golang.org/x/crypto/poly1305",
|
||||||
"Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248"
|
"Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/scrypt",
|
"ImportPath": "golang.org/x/crypto/scrypt",
|
||||||
"Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248"
|
"Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh",
|
"ImportPath": "golang.org/x/crypto/ssh",
|
||||||
"Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248"
|
"Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
25
Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go
generated
vendored
25
Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go
generated
vendored
@ -144,6 +144,25 @@ func (c *Command) makeLookup() lookup {
|
|||||||
commands: make(map[string]*Command),
|
commands: make(map[string]*Command),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent := c.parent
|
||||||
|
|
||||||
|
for parent != nil {
|
||||||
|
if cmd, ok := parent.(*Command); ok {
|
||||||
|
cmd.fillLookup(&ret, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if grp, ok := parent.(*Group); ok {
|
||||||
|
parent = grp
|
||||||
|
} else {
|
||||||
|
parent = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.fillLookup(&ret, false)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) fillLookup(ret *lookup, onlyOptions bool) {
|
||||||
c.eachGroup(func(g *Group) {
|
c.eachGroup(func(g *Group) {
|
||||||
for _, option := range g.options {
|
for _, option := range g.options {
|
||||||
if option.ShortName != 0 {
|
if option.ShortName != 0 {
|
||||||
@ -156,6 +175,10 @@ func (c *Command) makeLookup() lookup {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if onlyOptions {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, subcommand := range c.commands {
|
for _, subcommand := range c.commands {
|
||||||
ret.commands[subcommand.Name] = subcommand
|
ret.commands[subcommand.Name] = subcommand
|
||||||
|
|
||||||
@ -163,8 +186,6 @@ func (c *Command) makeLookup() lookup {
|
|||||||
ret.commands[a] = subcommand
|
ret.commands[a] = subcommand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) groupByName(name string) *Group {
|
func (c *Command) groupByName(name string) *Group {
|
||||||
|
50
Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go
generated
vendored
50
Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go
generated
vendored
@ -95,7 +95,55 @@ func TestCommandFlagOrder2(t *testing.T) {
|
|||||||
} `command:"cmd"`
|
} `command:"cmd"`
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
assertParseFail(t, ErrUnknownFlag, "unknown flag `v'", &opts, "cmd", "-v", "-g")
|
assertParseSuccess(t, &opts, "cmd", "-v", "-g")
|
||||||
|
|
||||||
|
if !opts.Value {
|
||||||
|
t.Errorf("Expected Value to be true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.Command.G {
|
||||||
|
t.Errorf("Expected Command.G to be true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandFlagOverride1(t *testing.T) {
|
||||||
|
var opts = struct {
|
||||||
|
Value bool `short:"v"`
|
||||||
|
|
||||||
|
Command struct {
|
||||||
|
Value bool `short:"v"`
|
||||||
|
} `command:"cmd"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
assertParseSuccess(t, &opts, "-v", "cmd")
|
||||||
|
|
||||||
|
if !opts.Value {
|
||||||
|
t.Errorf("Expected Value to be true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Command.Value {
|
||||||
|
t.Errorf("Expected Command.Value to be false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandFlagOverride2(t *testing.T) {
|
||||||
|
var opts = struct {
|
||||||
|
Value bool `short:"v"`
|
||||||
|
|
||||||
|
Command struct {
|
||||||
|
Value bool `short:"v"`
|
||||||
|
} `command:"cmd"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
assertParseSuccess(t, &opts, "cmd", "-v")
|
||||||
|
|
||||||
|
if opts.Value {
|
||||||
|
t.Errorf("Expected Value to be false")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.Command.Value {
|
||||||
|
t.Errorf("Expected Command.Value to be true")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommandEstimate(t *testing.T) {
|
func TestCommandEstimate(t *testing.T) {
|
||||||
|
20
Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go
generated
vendored
20
Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go
generated
vendored
@ -312,6 +312,26 @@ func quoteIfNeeded(s string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quoteIfNeededV(s []string) []string {
|
||||||
|
ret := make([]string, len(s))
|
||||||
|
|
||||||
|
for i, v := range s {
|
||||||
|
ret[i] = quoteIfNeeded(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteV(s []string) []string {
|
||||||
|
ret := make([]string, len(s))
|
||||||
|
|
||||||
|
for i, v := range s {
|
||||||
|
ret[i] = strconv.Quote(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func unquoteIfPossible(s string) (string, error) {
|
func unquoteIfPossible(s string) (string, error) {
|
||||||
if len(s) == 0 || s[0] != '"' {
|
if len(s) == 0 || s[0] != '"' {
|
||||||
return s, nil
|
return s, nil
|
||||||
|
14
Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go
generated
vendored
14
Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go
generated
vendored
@ -183,12 +183,16 @@ the Commander interface, then its Execute method will be run with the
|
|||||||
remaining command line arguments.
|
remaining command line arguments.
|
||||||
|
|
||||||
Command structs can have options which become valid to parse after the
|
Command structs can have options which become valid to parse after the
|
||||||
command has been specified on the command line. It is currently not valid
|
command has been specified on the command line, in addition to the options
|
||||||
to specify options from the parent level of the command after the command
|
of all the parent commands. I.e. considering a -v flag on the parser and an
|
||||||
name has occurred. Thus, given a top-level option "-v" and a command "add":
|
add command, the following are equivalent:
|
||||||
|
|
||||||
Valid: ./app -v add
|
./app -v add
|
||||||
Invalid: ./app add -v
|
./app add -v
|
||||||
|
|
||||||
|
However, if the -v flag is defined on the add command, then the first of
|
||||||
|
the two examples above would fail since the -v flag is not defined before
|
||||||
|
the add command.
|
||||||
|
|
||||||
|
|
||||||
Completion
|
Completion
|
||||||
|
40
Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go
generated
vendored
40
Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go
generated
vendored
@ -173,6 +173,14 @@ func TestMan(t *testing.T) {
|
|||||||
|
|
||||||
tt := time.Now()
|
tt := time.Now()
|
||||||
|
|
||||||
|
var envDefaultName string
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
envDefaultName = "%ENV_DEFAULT%"
|
||||||
|
} else {
|
||||||
|
envDefaultName = "$ENV_DEFAULT"
|
||||||
|
}
|
||||||
|
|
||||||
expected := fmt.Sprintf(`.TH TestMan 1 "%s"
|
expected := fmt.Sprintf(`.TH TestMan 1 "%s"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
TestMan \- Test manpage generation
|
TestMan \- Test manpage generation
|
||||||
@ -182,45 +190,45 @@ TestMan \- Test manpage generation
|
|||||||
This is a somewhat \fBlonger\fP description of what this does
|
This is a somewhat \fBlonger\fP description of what this does
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
\fB-v, --verbose\fP
|
\fB\fB\-v\fR, \fB\-\-verbose\fR\fP
|
||||||
Show verbose debug information
|
Show verbose debug information
|
||||||
.TP
|
.TP
|
||||||
\fB-c\fP
|
\fB\fB\-c\fR\fP
|
||||||
Call phone number
|
Call phone number
|
||||||
.TP
|
.TP
|
||||||
\fB--ptrslice\fP
|
\fB\fB\-\-ptrslice\fR\fP
|
||||||
A slice of pointers to string
|
A slice of pointers to string
|
||||||
.TP
|
.TP
|
||||||
\fB--empty-description\fP
|
\fB\fB\-\-empty-description\fR\fP
|
||||||
.TP
|
.TP
|
||||||
\fB--default\fP
|
\fB\fB\-\-default\fR <default: \fI"Some\\nvalue"\fR>\fP
|
||||||
Test default value
|
Test default value
|
||||||
.TP
|
.TP
|
||||||
\fB--default-array\fP
|
\fB\fB\-\-default-array\fR <default: \fI"Some value", "Other\\tvalue"\fR>\fP
|
||||||
Test default array value
|
Test default array value
|
||||||
.TP
|
.TP
|
||||||
\fB--default-map\fP
|
\fB\fB\-\-default-map\fR <default: \fI"some:value", "another:value"\fR>\fP
|
||||||
Testdefault map value
|
Testdefault map value
|
||||||
.TP
|
.TP
|
||||||
\fB--env-default1\fP
|
\fB\fB\-\-env-default1\fR <default: \fI"Some value"\fR>\fP
|
||||||
Test env-default1 value
|
Test env-default1 value
|
||||||
.TP
|
.TP
|
||||||
\fB--env-default2\fP
|
\fB\fB\-\-env-default2\fR <default: \fI%s\fR>\fP
|
||||||
Test env-default2 value
|
Test env-default2 value
|
||||||
.TP
|
.TP
|
||||||
\fB--opt-with-arg-name\fP
|
\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP
|
||||||
Option with named argument
|
Option with named argument
|
||||||
.TP
|
.TP
|
||||||
\fB-s\fP
|
\fB\fB\-s\fR <default: \fI"some", "value"\fR>\fP
|
||||||
A slice of strings
|
A slice of strings
|
||||||
.TP
|
.TP
|
||||||
\fB--intmap\fP
|
\fB\fB\-\-intmap\fR <default: \fI"a:1"\fR>\fP
|
||||||
A map from string to int
|
A map from string to int
|
||||||
.TP
|
.TP
|
||||||
\fB--sip.opt\fP
|
\fB\fB\-\-sip.opt\fR\fP
|
||||||
This is a subgroup option
|
This is a subgroup option
|
||||||
.TP
|
.TP
|
||||||
\fB--sip.sap.opt\fP
|
\fB\fB\-\-sip.sap.opt\fR\fP
|
||||||
This is a subsubgroup option
|
This is a subsubgroup option
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
.SS command
|
.SS command
|
||||||
@ -234,9 +242,9 @@ Longer \fBcommand\fP description
|
|||||||
\fBAliases\fP: cm, cmd
|
\fBAliases\fP: cm, cmd
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB--extra-verbose\fP
|
\fB\fB\-\-extra-verbose\fR\fP
|
||||||
Use for extra verbosity
|
Use for extra verbosity
|
||||||
`, tt.Format("2 January 2006"))
|
`, tt.Format("2 January 2006"), envDefaultName)
|
||||||
|
|
||||||
assertDiff(t, got, expected, "man page")
|
assertDiff(t, got, expected, "man page")
|
||||||
}
|
}
|
||||||
|
54
Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go
generated
vendored
54
Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go
generated
vendored
@ -3,30 +3,35 @@ package flags
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func manQuote(s string) string {
|
||||||
|
return strings.Replace(s, "\\", "\\\\", -1)
|
||||||
|
}
|
||||||
|
|
||||||
func formatForMan(wr io.Writer, s string) {
|
func formatForMan(wr io.Writer, s string) {
|
||||||
for {
|
for {
|
||||||
idx := strings.IndexRune(s, '`')
|
idx := strings.IndexRune(s, '`')
|
||||||
|
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
fmt.Fprintf(wr, "%s", s)
|
fmt.Fprintf(wr, "%s", manQuote(s))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(wr, "%s", s[:idx])
|
fmt.Fprintf(wr, "%s", manQuote(s[:idx]))
|
||||||
|
|
||||||
s = s[idx+1:]
|
s = s[idx+1:]
|
||||||
idx = strings.IndexRune(s, '\'')
|
idx = strings.IndexRune(s, '\'')
|
||||||
|
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
fmt.Fprintf(wr, "%s", s)
|
fmt.Fprintf(wr, "%s", manQuote(s))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(wr, "\\fB%s\\fP", s[:idx])
|
fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx]))
|
||||||
s = s[idx+1:]
|
s = s[idx+1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +47,7 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
|
|||||||
fmt.Fprintf(wr, "\\fB")
|
fmt.Fprintf(wr, "\\fB")
|
||||||
|
|
||||||
if opt.ShortName != 0 {
|
if opt.ShortName != 0 {
|
||||||
fmt.Fprintf(wr, "-%c", opt.ShortName)
|
fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opt.LongName) != 0 {
|
if len(opt.LongName) != 0 {
|
||||||
@ -50,10 +55,33 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
|
|||||||
fmt.Fprintf(wr, ", ")
|
fmt.Fprintf(wr, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(wr, "--%s", opt.LongNameWithNamespace())
|
fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.ValueName) != 0 || opt.OptionalArgument {
|
||||||
|
if opt.OptionalArgument {
|
||||||
|
fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.Default) != 0 {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
|
||||||
|
} else if len(opt.EnvDefaultKey) != 0 {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvDefaultKey))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvDefaultKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.Required {
|
||||||
|
fmt.Fprintf(wr, " (\\fIrequired\\fR)")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(wr, "\\fP")
|
fmt.Fprintln(wr, "\\fP")
|
||||||
|
|
||||||
if len(opt.Description) != 0 {
|
if len(opt.Description) != 0 {
|
||||||
formatForMan(wr, opt.Description)
|
formatForMan(wr, opt.Description)
|
||||||
fmt.Fprintln(wr, "")
|
fmt.Fprintln(wr, "")
|
||||||
@ -85,10 +113,10 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm
|
|||||||
if len(command.LongDescription) > 0 {
|
if len(command.LongDescription) > 0 {
|
||||||
fmt.Fprintln(wr, "")
|
fmt.Fprintln(wr, "")
|
||||||
|
|
||||||
cmdstart := fmt.Sprintf("The %s command", command.Name)
|
cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))
|
||||||
|
|
||||||
if strings.HasPrefix(command.LongDescription, cmdstart) {
|
if strings.HasPrefix(command.LongDescription, cmdstart) {
|
||||||
fmt.Fprintf(wr, "The \\fI%s\\fP command", command.Name)
|
fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))
|
||||||
|
|
||||||
formatForMan(wr, command.LongDescription[len(cmdstart):])
|
formatForMan(wr, command.LongDescription[len(cmdstart):])
|
||||||
fmt.Fprintln(wr, "")
|
fmt.Fprintln(wr, "")
|
||||||
@ -113,11 +141,11 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(usage) > 0 {
|
if len(usage) > 0 {
|
||||||
fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n\n", pre, usage)
|
fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n\n", manQuote(pre), manQuote(usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(command.Aliases) > 0 {
|
if len(command.Aliases) > 0 {
|
||||||
fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", strings.Join(command.Aliases, ", "))
|
fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
writeManPageOptions(wr, command.Group)
|
writeManPageOptions(wr, command.Group)
|
||||||
@ -129,9 +157,9 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm
|
|||||||
func (p *Parser) WriteManPage(wr io.Writer) {
|
func (p *Parser) WriteManPage(wr io.Writer) {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
|
|
||||||
fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", p.Name, t.Format("2 January 2006"))
|
fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
|
||||||
fmt.Fprintln(wr, ".SH NAME")
|
fmt.Fprintln(wr, ".SH NAME")
|
||||||
fmt.Fprintf(wr, "%s \\- %s\n", p.Name, p.ShortDescription)
|
fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription))
|
||||||
fmt.Fprintln(wr, ".SH SYNOPSIS")
|
fmt.Fprintln(wr, ".SH SYNOPSIS")
|
||||||
|
|
||||||
usage := p.Usage
|
usage := p.Usage
|
||||||
@ -140,7 +168,7 @@ func (p *Parser) WriteManPage(wr io.Writer) {
|
|||||||
usage = "[OPTIONS]"
|
usage = "[OPTIONS]"
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(wr, "\\fB%s\\fP %s\n", p.Name, usage)
|
fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
|
||||||
fmt.Fprintln(wr, ".SH DESCRIPTION")
|
fmt.Fprintln(wr, ".SH DESCRIPTION")
|
||||||
|
|
||||||
formatForMan(wr, p.LongDescription)
|
formatForMan(wr, p.LongDescription)
|
||||||
|
7
Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go
generated
vendored
7
Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go
generated
vendored
@ -35,7 +35,7 @@ type Option struct {
|
|||||||
|
|
||||||
// If true, specifies that the argument to an option flag is optional.
|
// If true, specifies that the argument to an option flag is optional.
|
||||||
// When no argument to the flag is specified on the command line, the
|
// When no argument to the flag is specified on the command line, the
|
||||||
// value of Default will be set in the field this option represents.
|
// value of OptionalValue will be set in the field this option represents.
|
||||||
// This is only valid for non-boolean options.
|
// This is only valid for non-boolean options.
|
||||||
OptionalArgument bool
|
OptionalArgument bool
|
||||||
|
|
||||||
@ -155,3 +155,8 @@ func (option *Option) String() string {
|
|||||||
func (option *Option) Value() interface{} {
|
func (option *Option) Value() interface{} {
|
||||||
return option.value.Interface()
|
return option.value.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSet returns true if option has been set
|
||||||
|
func (option *Option) IsSet() bool {
|
||||||
|
return option.isSet
|
||||||
|
}
|
||||||
|
180
Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go
generated
vendored
180
Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go
generated
vendored
@ -1,180 +0,0 @@
|
|||||||
package testutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HTTPServer struct {
|
|
||||||
URL string
|
|
||||||
Timeout time.Duration
|
|
||||||
started bool
|
|
||||||
request chan *http.Request
|
|
||||||
response chan ResponseFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
type Response struct {
|
|
||||||
Status int
|
|
||||||
Headers map[string]string
|
|
||||||
Body string
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultClient = &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPServer() *HTTPServer {
|
|
||||||
return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseFunc func(path string) Response
|
|
||||||
|
|
||||||
func (s *HTTPServer) Start() {
|
|
||||||
if s.started {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.started = true
|
|
||||||
s.request = make(chan *http.Request, 1024)
|
|
||||||
s.response = make(chan ResponseFunc, 1024)
|
|
||||||
u, err := url.Parse(s.URL)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
l, err := net.Listen("tcp", u.Host)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
go http.Serve(l, s)
|
|
||||||
|
|
||||||
s.Response(203, nil, "")
|
|
||||||
for {
|
|
||||||
// Wait for it to be up.
|
|
||||||
resp, err := http.Get(s.URL)
|
|
||||||
if err == nil && resp.StatusCode == 203 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(1e8)
|
|
||||||
}
|
|
||||||
s.WaitRequest() // Consume dummy request.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush discards all pending requests and responses.
|
|
||||||
func (s *HTTPServer) Flush() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-s.request:
|
|
||||||
case <-s.response:
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func body(req *http.Request) string {
|
|
||||||
data, err := ioutil.ReadAll(req.Body)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
||||||
req.ParseMultipartForm(1e6)
|
|
||||||
data, err := ioutil.ReadAll(req.Body)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
|
|
||||||
s.request <- req
|
|
||||||
var resp Response
|
|
||||||
select {
|
|
||||||
case respFunc := <-s.response:
|
|
||||||
resp = respFunc(req.URL.Path)
|
|
||||||
case <-time.After(s.Timeout):
|
|
||||||
const msg = "ERROR: Timeout waiting for test to prepare a response\n"
|
|
||||||
fmt.Fprintf(os.Stderr, msg)
|
|
||||||
resp = Response{500, nil, msg}
|
|
||||||
}
|
|
||||||
if resp.Headers != nil {
|
|
||||||
h := w.Header()
|
|
||||||
for k, v := range resp.Headers {
|
|
||||||
h.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if resp.Status != 0 {
|
|
||||||
w.WriteHeader(resp.Status)
|
|
||||||
}
|
|
||||||
w.Write([]byte(resp.Body))
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitRequests returns the next n requests made to the http server from
|
|
||||||
// the queue. If not enough requests were previously made, it waits until
|
|
||||||
// the timeout value for them to be made.
|
|
||||||
func (s *HTTPServer) WaitRequests(n int) []*http.Request {
|
|
||||||
reqs := make([]*http.Request, 0, n)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
select {
|
|
||||||
case req := <-s.request:
|
|
||||||
reqs = append(reqs, req)
|
|
||||||
case <-time.After(s.Timeout):
|
|
||||||
panic("Timeout waiting for request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return reqs
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitRequest returns the next request made to the http server from
|
|
||||||
// the queue. If no requests were previously made, it waits until the
|
|
||||||
// timeout value for one to be made.
|
|
||||||
func (s *HTTPServer) WaitRequest() *http.Request {
|
|
||||||
return s.WaitRequests(1)[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseFunc prepares the test server to respond the following n
|
|
||||||
// requests using f to build each response.
|
|
||||||
func (s *HTTPServer) ResponseFunc(n int, f ResponseFunc) {
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
s.response <- f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseMap maps request paths to responses.
|
|
||||||
type ResponseMap map[string]Response
|
|
||||||
|
|
||||||
// ResponseMap prepares the test server to respond the following n
|
|
||||||
// requests using the m to obtain the responses.
|
|
||||||
func (s *HTTPServer) ResponseMap(n int, m ResponseMap) {
|
|
||||||
f := func(path string) Response {
|
|
||||||
for rpath, resp := range m {
|
|
||||||
if rpath == path {
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
body := "Path not found in response map: " + path
|
|
||||||
return Response{Status: 500, Body: body}
|
|
||||||
}
|
|
||||||
s.ResponseFunc(n, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Responses prepares the test server to respond the following n requests
|
|
||||||
// using the provided response parameters.
|
|
||||||
func (s *HTTPServer) Responses(n int, status int, headers map[string]string, body string) {
|
|
||||||
f := func(path string) Response {
|
|
||||||
return Response{status, headers, body}
|
|
||||||
}
|
|
||||||
s.ResponseFunc(n, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response prepares the test server to respond the following request
|
|
||||||
// using the provided response parameters.
|
|
||||||
func (s *HTTPServer) Response(status int, headers map[string]string, body string) {
|
|
||||||
s.Responses(1, status, headers, body)
|
|
||||||
}
|
|
30
Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go
generated
vendored
30
Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
package testutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"github.com/mitchellh/goamz/aws"
|
|
||||||
. "github.com/motain/gocheck"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Amazon must be used by all tested packages to determine whether to
|
|
||||||
// run functional tests against the real AWS servers.
|
|
||||||
var Amazon bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&Amazon, "amazon", false, "Enable tests against amazon server")
|
|
||||||
}
|
|
||||||
|
|
||||||
type LiveSuite struct {
|
|
||||||
auth aws.Auth
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *LiveSuite) SetUpSuite(c *C) {
|
|
||||||
if !Amazon {
|
|
||||||
c.Skip("amazon tests not enabled (-amazon flag)")
|
|
||||||
}
|
|
||||||
auth, err := aws.EnvAuth()
|
|
||||||
if err != nil {
|
|
||||||
c.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
s.auth = auth
|
|
||||||
}
|
|
3
Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore
generated
vendored
3
Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
_*
|
|
||||||
[856].out
|
|
||||||
[856].out.exe
|
|
4
Godeps/_workspace/src/github.com/motain/gocheck/.gitignore
generated
vendored
4
Godeps/_workspace/src/github.com/motain/gocheck/.gitignore
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
_*
|
|
||||||
*.swp
|
|
||||||
*.[568]
|
|
||||||
[568].out
|
|
29
Godeps/_workspace/src/github.com/motain/gocheck/LICENSE
generated
vendored
29
Godeps/_workspace/src/github.com/motain/gocheck/LICENSE
generated
vendored
@ -1,29 +0,0 @@
|
|||||||
Gocheck - A rich testing framework for Go
|
|
||||||
|
|
||||||
Copyright (c) 2010, Gustavo Niemeyer <gustavo@niemeyer.net>
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
30
Godeps/_workspace/src/github.com/motain/gocheck/Makefile
generated
vendored
30
Godeps/_workspace/src/github.com/motain/gocheck/Makefile
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
include $(GOROOT)/src/Make.inc
|
|
||||||
|
|
||||||
TARG=launchpad.net/gocheck
|
|
||||||
|
|
||||||
GOFILES=\
|
|
||||||
gocheck.go\
|
|
||||||
helpers.go\
|
|
||||||
run.go\
|
|
||||||
checkers.go\
|
|
||||||
printer.go\
|
|
||||||
|
|
||||||
#TARGDIR=$(GOPATH)/pkg/$(GOOS)_$(GOARCH)
|
|
||||||
#GCIMPORTS=$(patsubst %,-I %/pkg/$(GOOS)_$(GOARCH),$(subst :, ,$(GOPATH)))
|
|
||||||
#LDIMPORTS=$(patsubst %,-L %/pkg/$(GOOS)_$(GOARCH),$(subst :, ,$(GOPATH)))
|
|
||||||
|
|
||||||
include $(GOROOT)/src/Make.pkg
|
|
||||||
|
|
||||||
GOFMT=gofmt
|
|
||||||
|
|
||||||
BADFMT=$(shell $(GOFMT) -l $(GOFILES) $(filter-out printer_test.go,$(wildcard *_test.go)))
|
|
||||||
|
|
||||||
gofmt: $(BADFMT)
|
|
||||||
@for F in $(BADFMT); do $(GOFMT) -w $$F && echo $$F; done
|
|
||||||
|
|
||||||
ifneq ($(BADFMT),)
|
|
||||||
ifneq ($(MAKECMDGOALS),gofmt)
|
|
||||||
#$(warning WARNING: make gofmt: $(BADFMT))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
2
Godeps/_workspace/src/github.com/motain/gocheck/TODO
generated
vendored
2
Godeps/_workspace/src/github.com/motain/gocheck/TODO
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
- Assert(slice, Contains, item)
|
|
||||||
- Parallel test support
|
|
136
Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go
generated
vendored
136
Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go
generated
vendored
@ -1,136 +0,0 @@
|
|||||||
// Copyright 2009 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 gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// testingB is a type passed to Benchmark functions to manage benchmark
|
|
||||||
// timing and to specify the number of iterations to run.
|
|
||||||
type timer struct {
|
|
||||||
start time.Time // Time test or benchmark started
|
|
||||||
duration time.Duration
|
|
||||||
N int
|
|
||||||
bytes int64
|
|
||||||
timerOn bool
|
|
||||||
benchTime time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartTimer starts timing a test. This function is called automatically
|
|
||||||
// before a benchmark starts, but it can also used to resume timing after
|
|
||||||
// a call to StopTimer.
|
|
||||||
func (c *C) StartTimer() {
|
|
||||||
if !c.timerOn {
|
|
||||||
c.start = time.Now()
|
|
||||||
c.timerOn = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopTimer stops timing a test. This can be used to pause the timer
|
|
||||||
// while performing complex initialization that you don't
|
|
||||||
// want to measure.
|
|
||||||
func (c *C) StopTimer() {
|
|
||||||
if c.timerOn {
|
|
||||||
c.duration += time.Now().Sub(c.start)
|
|
||||||
c.timerOn = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetTimer sets the elapsed benchmark time to zero.
|
|
||||||
// It does not affect whether the timer is running.
|
|
||||||
func (c *C) ResetTimer() {
|
|
||||||
if c.timerOn {
|
|
||||||
c.start = time.Now()
|
|
||||||
}
|
|
||||||
c.duration = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBytes informs the number of bytes that the benchmark processes
|
|
||||||
// on each iteration. If this is called in a benchmark it will also
|
|
||||||
// report MB/s.
|
|
||||||
func (c *C) SetBytes(n int64) {
|
|
||||||
c.bytes = n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) nsPerOp() int64 {
|
|
||||||
if c.N <= 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return c.duration.Nanoseconds() / int64(c.N)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) mbPerSec() float64 {
|
|
||||||
if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) timerString() string {
|
|
||||||
if c.N <= 0 {
|
|
||||||
return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
|
|
||||||
}
|
|
||||||
mbs := c.mbPerSec()
|
|
||||||
mb := ""
|
|
||||||
if mbs != 0 {
|
|
||||||
mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
|
|
||||||
}
|
|
||||||
nsop := c.nsPerOp()
|
|
||||||
ns := fmt.Sprintf("%10d ns/op", nsop)
|
|
||||||
if c.N > 0 && nsop < 100 {
|
|
||||||
// The format specifiers here make sure that
|
|
||||||
// the ones digits line up for all three possible formats.
|
|
||||||
if nsop < 10 {
|
|
||||||
ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
|
|
||||||
} else {
|
|
||||||
ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%8d\t%s%s", c.N, ns, mb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func min(x, y int) int {
|
|
||||||
if x > y {
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(x, y int) int {
|
|
||||||
if x < y {
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// roundDown10 rounds a number down to the nearest power of 10.
|
|
||||||
func roundDown10(n int) int {
|
|
||||||
var tens = 0
|
|
||||||
// tens = floor(log_10(n))
|
|
||||||
for n > 10 {
|
|
||||||
n = n / 10
|
|
||||||
tens++
|
|
||||||
}
|
|
||||||
// result = 10^tens
|
|
||||||
result := 1
|
|
||||||
for i := 0; i < tens; i++ {
|
|
||||||
result *= 10
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
|
|
||||||
func roundUp(n int) int {
|
|
||||||
base := roundDown10(n)
|
|
||||||
if n < (2 * base) {
|
|
||||||
return 2 * base
|
|
||||||
}
|
|
||||||
if n < (5 * base) {
|
|
||||||
return 5 * base
|
|
||||||
}
|
|
||||||
return 10 * base
|
|
||||||
}
|
|
75
Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go
generated
vendored
75
Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go
generated
vendored
@ -1,75 +0,0 @@
|
|||||||
// These tests verify the test running logic.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "launchpad.net/gocheck"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var benchmarkS = Suite(&BenchmarkS{})
|
|
||||||
|
|
||||||
type BenchmarkS struct{}
|
|
||||||
|
|
||||||
func (s *BenchmarkS) TestCountSuite(c *C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BenchmarkS) TestBasicTestTiming(c *C) {
|
|
||||||
helper := FixtureHelper{sleepOn: "Test1", sleep: 1000000 * time.Nanosecond}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Verbose: true}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
|
|
||||||
expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Test1\t0\\.001s\n" +
|
|
||||||
"PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Test2\t0\\.000s\n"
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BenchmarkS) TestStreamTestTiming(c *C) {
|
|
||||||
helper := FixtureHelper{sleepOn: "SetUpSuite", sleep: 1000000 * time.Nanosecond}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Stream: true}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
|
|
||||||
expected := "(?s).*\nPASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.SetUpSuite\t *0\\.001s\n.*"
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BenchmarkS) TestBenchmark(c *C) {
|
|
||||||
helper := FixtureHelper{sleep: 100000}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{
|
|
||||||
Output: &output,
|
|
||||||
Benchmark: true,
|
|
||||||
BenchmarkTime: 10000000,
|
|
||||||
Filter: "Benchmark1",
|
|
||||||
}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Benchmark1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Benchmark1")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
// ... and more.
|
|
||||||
|
|
||||||
expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n"
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BenchmarkS) TestBenchmarkBytes(c *C) {
|
|
||||||
helper := FixtureHelper{sleep: 100000}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{
|
|
||||||
Output: &output,
|
|
||||||
Benchmark: true,
|
|
||||||
BenchmarkTime: 10000000,
|
|
||||||
Filter: "Benchmark2",
|
|
||||||
}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
|
|
||||||
expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Benchmark2\t *100\t *[12][0-9]{5} ns/op\t *[4-9]\\.[0-9]{2} MB/s\n"
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
82
Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go
generated
vendored
82
Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go
generated
vendored
@ -1,82 +0,0 @@
|
|||||||
// These initial tests are for bootstrapping. They verify that we can
|
|
||||||
// basically use the testing infrastructure itself to check if the test
|
|
||||||
// system is working.
|
|
||||||
//
|
|
||||||
// These tests use will break down the test runner badly in case of
|
|
||||||
// errors because if they simply fail, we can't be sure the developer
|
|
||||||
// will ever see anything (because failing means the failing system
|
|
||||||
// somehow isn't working! :-)
|
|
||||||
//
|
|
||||||
// Do not assume *any* internal functionality works as expected besides
|
|
||||||
// what's actually tested here.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"launchpad.net/gocheck"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BootstrapS struct{}
|
|
||||||
|
|
||||||
var boostrapS = gocheck.Suite(&BootstrapS{})
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestCountSuite(c *gocheck.C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestFailedAndFail(c *gocheck.C) {
|
|
||||||
if c.Failed() {
|
|
||||||
critical("c.Failed() must be false first!")
|
|
||||||
}
|
|
||||||
c.Fail()
|
|
||||||
if !c.Failed() {
|
|
||||||
critical("c.Fail() didn't put the test in a failed state!")
|
|
||||||
}
|
|
||||||
c.Succeed()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestFailedAndSucceed(c *gocheck.C) {
|
|
||||||
c.Fail()
|
|
||||||
c.Succeed()
|
|
||||||
if c.Failed() {
|
|
||||||
critical("c.Succeed() didn't put the test back in a non-failed state")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestLogAndGetTestLog(c *gocheck.C) {
|
|
||||||
c.Log("Hello there!")
|
|
||||||
log := c.GetTestLog()
|
|
||||||
if log != "Hello there!\n" {
|
|
||||||
critical(fmt.Sprintf("Log() or GetTestLog() is not working! Got: %#v", log))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestLogfAndGetTestLog(c *gocheck.C) {
|
|
||||||
c.Logf("Hello %v", "there!")
|
|
||||||
log := c.GetTestLog()
|
|
||||||
if log != "Hello there!\n" {
|
|
||||||
critical(fmt.Sprintf("Logf() or GetTestLog() is not working! Got: %#v", log))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestRunShowsErrors(c *gocheck.C) {
|
|
||||||
output := String{}
|
|
||||||
gocheck.Run(&FailHelper{}, &gocheck.RunConf{Output: &output})
|
|
||||||
if strings.Index(output.value, "Expected failure!") == -1 {
|
|
||||||
critical(fmt.Sprintf("RunWithWriter() output did not contain the "+
|
|
||||||
"expected failure! Got: %#v",
|
|
||||||
output.value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestRunDoesntShowSuccesses(c *gocheck.C) {
|
|
||||||
output := String{}
|
|
||||||
gocheck.Run(&SuccessHelper{}, &gocheck.RunConf{Output: &output})
|
|
||||||
if strings.Index(output.value, "Expected success!") != -1 {
|
|
||||||
critical(fmt.Sprintf("RunWithWriter() output contained a successful "+
|
|
||||||
"test! Got: %#v",
|
|
||||||
output.value))
|
|
||||||
}
|
|
||||||
}
|
|
458
Godeps/_workspace/src/github.com/motain/gocheck/checkers.go
generated
vendored
458
Godeps/_workspace/src/github.com/motain/gocheck/checkers.go
generated
vendored
@ -1,458 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// CommentInterface and Commentf helper, to attach extra information to checks.
|
|
||||||
|
|
||||||
type comment struct {
|
|
||||||
format string
|
|
||||||
args []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commentf returns an infomational value to use with Assert or Check calls.
|
|
||||||
// If the checker test fails, the provided arguments will be passed to
|
|
||||||
// fmt.Sprintf, and will be presented next to the logged failure.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i))
|
|
||||||
//
|
|
||||||
// Note that if the comment is constant, a better option is to
|
|
||||||
// simply use a normal comment right above or next to the line, as
|
|
||||||
// it will also get printed with any errors:
|
|
||||||
//
|
|
||||||
// c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123)
|
|
||||||
//
|
|
||||||
func Commentf(format string, args ...interface{}) CommentInterface {
|
|
||||||
return &comment{format, args}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommentInterface must be implemented by types that attach extra
|
|
||||||
// information to failed checks. See the Commentf function for details.
|
|
||||||
type CommentInterface interface {
|
|
||||||
CheckCommentString() string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *comment) CheckCommentString() string {
|
|
||||||
return fmt.Sprintf(c.format, c.args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// The Checker interface.
|
|
||||||
|
|
||||||
// The Checker interface must be provided by checkers used with
|
|
||||||
// the Assert and Check verification methods.
|
|
||||||
type Checker interface {
|
|
||||||
Info() *CheckerInfo
|
|
||||||
Check(params []interface{}, names []string) (result bool, error string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// See the Checker interface.
|
|
||||||
type CheckerInfo struct {
|
|
||||||
Name string
|
|
||||||
Params []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (info *CheckerInfo) Info() *CheckerInfo {
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Not checker logic inverter.
|
|
||||||
|
|
||||||
// The Not checker inverts the logic of the provided checker. The
|
|
||||||
// resulting checker will succeed where the original one failed, and
|
|
||||||
// vice-versa.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(a, Not(Equals), b)
|
|
||||||
//
|
|
||||||
func Not(checker Checker) Checker {
|
|
||||||
return ¬Checker{checker}
|
|
||||||
}
|
|
||||||
|
|
||||||
type notChecker struct {
|
|
||||||
sub Checker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *notChecker) Info() *CheckerInfo {
|
|
||||||
info := *checker.sub.Info()
|
|
||||||
info.Name = "Not(" + info.Name + ")"
|
|
||||||
return &info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
result, error = checker.sub.Check(params, names)
|
|
||||||
result = !result
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// IsNil checker.
|
|
||||||
|
|
||||||
type isNilChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The IsNil checker tests whether the obtained value is nil.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(err, IsNil)
|
|
||||||
//
|
|
||||||
var IsNil Checker = &isNilChecker{
|
|
||||||
&CheckerInfo{Name: "IsNil", Params: []string{"value"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
return isNil(params[0]), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNil(obtained interface{}) (result bool) {
|
|
||||||
if obtained == nil {
|
|
||||||
result = true
|
|
||||||
} else {
|
|
||||||
switch v := reflect.ValueOf(obtained); v.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
||||||
return v.IsNil()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// NotNil checker. Alias for Not(IsNil), since it's so common.
|
|
||||||
|
|
||||||
type notNilChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The NotNil checker verifies that the obtained value is not nil.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(iface, NotNil)
|
|
||||||
//
|
|
||||||
// This is an alias for Not(IsNil), made available since it's a
|
|
||||||
// fairly common check.
|
|
||||||
//
|
|
||||||
var NotNil Checker = ¬NilChecker{
|
|
||||||
&CheckerInfo{Name: "NotNil", Params: []string{"value"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
return !isNil(params[0]), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Equals checker.
|
|
||||||
|
|
||||||
type equalsChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Equals checker verifies that the obtained value is equal to
|
|
||||||
// the expected value, according to usual Go semantics for ==.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(value, Equals, 42)
|
|
||||||
//
|
|
||||||
var Equals Checker = &equalsChecker{
|
|
||||||
&CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
defer func() {
|
|
||||||
if v := recover(); v != nil {
|
|
||||||
result = false
|
|
||||||
error = fmt.Sprint(v)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return params[0] == params[1], ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// DeepEquals checker.
|
|
||||||
|
|
||||||
type deepEqualsChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The DeepEquals checker verifies that the obtained value is deep-equal to
|
|
||||||
// the expected value. The check will work correctly even when facing
|
|
||||||
// slices, interfaces, and values of different types (which always fail
|
|
||||||
// the test).
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(value, DeepEquals, 42)
|
|
||||||
// c.Assert(array, DeepEquals, []string{"hi", "there"})
|
|
||||||
//
|
|
||||||
var DeepEquals Checker = &deepEqualsChecker{
|
|
||||||
&CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
return reflect.DeepEqual(params[0], params[1]), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// HasLen checker.
|
|
||||||
|
|
||||||
type hasLenChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The HasLen checker verifies that the obtained value has the
|
|
||||||
// provided length. In many cases this is superior to using Equals
|
|
||||||
// in conjuction with the len function because in case the check
|
|
||||||
// fails the value itself will be printed, instead of its length,
|
|
||||||
// providing more details for figuring the problem.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(list, HasLen, 5)
|
|
||||||
//
|
|
||||||
var HasLen Checker = &hasLenChecker{
|
|
||||||
&CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
n, ok := params[1].(int)
|
|
||||||
if !ok {
|
|
||||||
return false, "n must be an int"
|
|
||||||
}
|
|
||||||
value := reflect.ValueOf(params[0])
|
|
||||||
switch value.Kind() {
|
|
||||||
case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String:
|
|
||||||
default:
|
|
||||||
return false, "obtained value type has no length"
|
|
||||||
}
|
|
||||||
return value.Len() == n, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// ErrorMatches checker.
|
|
||||||
|
|
||||||
type errorMatchesChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ErrorMatches checker verifies that the error value
|
|
||||||
// is non nil and matches the regular expression provided.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(err, ErrorMatches, "perm.*denied")
|
|
||||||
//
|
|
||||||
var ErrorMatches Checker = errorMatchesChecker{
|
|
||||||
&CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) {
|
|
||||||
if params[0] == nil {
|
|
||||||
return false, "Error value is nil"
|
|
||||||
}
|
|
||||||
err, ok := params[0].(error)
|
|
||||||
if !ok {
|
|
||||||
return false, "Value is not an error"
|
|
||||||
}
|
|
||||||
params[0] = err.Error()
|
|
||||||
names[0] = "error"
|
|
||||||
return matches(params[0], params[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Matches checker.
|
|
||||||
|
|
||||||
type matchesChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Matches checker verifies that the string provided as the obtained
|
|
||||||
// value (or the string resulting from obtained.String()) matches the
|
|
||||||
// regular expression provided.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(err, Matches, "perm.*denied")
|
|
||||||
//
|
|
||||||
var Matches Checker = &matchesChecker{
|
|
||||||
&CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
return matches(params[0], params[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func matches(value, regex interface{}) (result bool, error string) {
|
|
||||||
reStr, ok := regex.(string)
|
|
||||||
if !ok {
|
|
||||||
return false, "Regex must be a string"
|
|
||||||
}
|
|
||||||
valueStr, valueIsStr := value.(string)
|
|
||||||
if !valueIsStr {
|
|
||||||
if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
|
|
||||||
valueStr, valueIsStr = valueWithStr.String(), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if valueIsStr {
|
|
||||||
matches, err := regexp.MatchString("^"+reStr+"$", valueStr)
|
|
||||||
if err != nil {
|
|
||||||
return false, "Can't compile regex: " + err.Error()
|
|
||||||
}
|
|
||||||
return matches, ""
|
|
||||||
}
|
|
||||||
return false, "Obtained value is not a string and has no .String()"
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Panics checker.
|
|
||||||
|
|
||||||
type panicsChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Panics checker verifies that calling the provided zero-argument
|
|
||||||
// function will cause a panic which is deep-equal to the provided value.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}).
|
|
||||||
//
|
|
||||||
//
|
|
||||||
var Panics Checker = &panicsChecker{
|
|
||||||
&CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
f := reflect.ValueOf(params[0])
|
|
||||||
if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
|
|
||||||
return false, "Function must take zero arguments"
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
// If the function has not panicked, then don't do the check.
|
|
||||||
if error != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
params[0] = recover()
|
|
||||||
names[0] = "panic"
|
|
||||||
result = reflect.DeepEqual(params[0], params[1])
|
|
||||||
}()
|
|
||||||
f.Call(nil)
|
|
||||||
return false, "Function has not panicked"
|
|
||||||
}
|
|
||||||
|
|
||||||
type panicMatchesChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The PanicMatches checker verifies that calling the provided zero-argument
|
|
||||||
// function will cause a panic with an error value matching
|
|
||||||
// the regular expression provided.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
|
|
||||||
//
|
|
||||||
//
|
|
||||||
var PanicMatches Checker = &panicMatchesChecker{
|
|
||||||
&CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
|
|
||||||
f := reflect.ValueOf(params[0])
|
|
||||||
if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
|
|
||||||
return false, "Function must take zero arguments"
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
// If the function has not panicked, then don't do the check.
|
|
||||||
if errmsg != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
obtained := recover()
|
|
||||||
names[0] = "panic"
|
|
||||||
if e, ok := obtained.(error); ok {
|
|
||||||
params[0] = e.Error()
|
|
||||||
} else if _, ok := obtained.(string); ok {
|
|
||||||
params[0] = obtained
|
|
||||||
} else {
|
|
||||||
errmsg = "Panic value is not a string or an error"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result, errmsg = matches(params[0], params[1])
|
|
||||||
}()
|
|
||||||
f.Call(nil)
|
|
||||||
return false, "Function has not panicked"
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// FitsTypeOf checker.
|
|
||||||
|
|
||||||
type fitsTypeChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The FitsTypeOf checker verifies that the obtained value is
|
|
||||||
// assignable to a variable with the same type as the provided
|
|
||||||
// sample value.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// c.Assert(value, FitsTypeOf, int64(0))
|
|
||||||
// c.Assert(value, FitsTypeOf, os.Error(nil))
|
|
||||||
//
|
|
||||||
var FitsTypeOf Checker = &fitsTypeChecker{
|
|
||||||
&CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
obtained := reflect.ValueOf(params[0])
|
|
||||||
sample := reflect.ValueOf(params[1])
|
|
||||||
if !obtained.IsValid() {
|
|
||||||
return false, ""
|
|
||||||
}
|
|
||||||
if !sample.IsValid() {
|
|
||||||
return false, "Invalid sample value"
|
|
||||||
}
|
|
||||||
return obtained.Type().AssignableTo(sample.Type()), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Implements checker.
|
|
||||||
|
|
||||||
type implementsChecker struct {
|
|
||||||
*CheckerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Implements checker verifies that the obtained value
|
|
||||||
// implements the interface specified via a pointer to an interface
|
|
||||||
// variable.
|
|
||||||
//
|
|
||||||
// For example:
|
|
||||||
//
|
|
||||||
// var e os.Error
|
|
||||||
// c.Assert(err, Implements, &e)
|
|
||||||
//
|
|
||||||
var Implements Checker = &implementsChecker{
|
|
||||||
&CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
|
||||||
obtained := reflect.ValueOf(params[0])
|
|
||||||
ifaceptr := reflect.ValueOf(params[1])
|
|
||||||
if !obtained.IsValid() {
|
|
||||||
return false, ""
|
|
||||||
}
|
|
||||||
if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface {
|
|
||||||
return false, "ifaceptr should be a pointer to an interface variable"
|
|
||||||
}
|
|
||||||
return obtained.Type().Implements(ifaceptr.Elem().Type()), ""
|
|
||||||
}
|
|
272
Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go
generated
vendored
272
Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go
generated
vendored
@ -1,272 +0,0 @@
|
|||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"launchpad.net/gocheck"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CheckersS struct{}
|
|
||||||
|
|
||||||
var _ = gocheck.Suite(&CheckersS{})
|
|
||||||
|
|
||||||
func testInfo(c *gocheck.C, checker gocheck.Checker, name string, paramNames []string) {
|
|
||||||
info := checker.Info()
|
|
||||||
if info.Name != name {
|
|
||||||
c.Fatalf("Got name %s, expected %s", info.Name, name)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(info.Params, paramNames) {
|
|
||||||
c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheck(c *gocheck.C, checker gocheck.Checker, result bool, error string, params ...interface{}) ([]interface{}, []string) {
|
|
||||||
info := checker.Info()
|
|
||||||
if len(params) != len(info.Params) {
|
|
||||||
c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params))
|
|
||||||
}
|
|
||||||
names := append([]string{}, info.Params...)
|
|
||||||
result_, error_ := checker.Check(params, names)
|
|
||||||
if result_ != result || error_ != error {
|
|
||||||
c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)",
|
|
||||||
info.Name, params, result_, error_, result, error)
|
|
||||||
}
|
|
||||||
return params, names
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestComment(c *gocheck.C) {
|
|
||||||
bug := gocheck.Commentf("a %d bc", 42)
|
|
||||||
comment := bug.CheckCommentString()
|
|
||||||
if comment != "a 42 bc" {
|
|
||||||
c.Fatalf("Commentf returned %#v", comment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestIsNil(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.IsNil, "IsNil", []string{"value"})
|
|
||||||
|
|
||||||
testCheck(c, gocheck.IsNil, true, "", nil)
|
|
||||||
testCheck(c, gocheck.IsNil, false, "", "a")
|
|
||||||
|
|
||||||
testCheck(c, gocheck.IsNil, true, "", (chan int)(nil))
|
|
||||||
testCheck(c, gocheck.IsNil, false, "", make(chan int))
|
|
||||||
testCheck(c, gocheck.IsNil, true, "", (error)(nil))
|
|
||||||
testCheck(c, gocheck.IsNil, false, "", errors.New(""))
|
|
||||||
testCheck(c, gocheck.IsNil, true, "", ([]int)(nil))
|
|
||||||
testCheck(c, gocheck.IsNil, false, "", make([]int, 1))
|
|
||||||
testCheck(c, gocheck.IsNil, false, "", int(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestNotNil(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.NotNil, "NotNil", []string{"value"})
|
|
||||||
|
|
||||||
testCheck(c, gocheck.NotNil, false, "", nil)
|
|
||||||
testCheck(c, gocheck.NotNil, true, "", "a")
|
|
||||||
|
|
||||||
testCheck(c, gocheck.NotNil, false, "", (chan int)(nil))
|
|
||||||
testCheck(c, gocheck.NotNil, true, "", make(chan int))
|
|
||||||
testCheck(c, gocheck.NotNil, false, "", (error)(nil))
|
|
||||||
testCheck(c, gocheck.NotNil, true, "", errors.New(""))
|
|
||||||
testCheck(c, gocheck.NotNil, false, "", ([]int)(nil))
|
|
||||||
testCheck(c, gocheck.NotNil, true, "", make([]int, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestNot(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.Not(gocheck.IsNil), "Not(IsNil)", []string{"value"})
|
|
||||||
|
|
||||||
testCheck(c, gocheck.Not(gocheck.IsNil), false, "", nil)
|
|
||||||
testCheck(c, gocheck.Not(gocheck.IsNil), true, "", "a")
|
|
||||||
}
|
|
||||||
|
|
||||||
type simpleStruct struct {
|
|
||||||
i int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestEquals(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.Equals, "Equals", []string{"obtained", "expected"})
|
|
||||||
|
|
||||||
// The simplest.
|
|
||||||
testCheck(c, gocheck.Equals, true, "", 42, 42)
|
|
||||||
testCheck(c, gocheck.Equals, false, "", 42, 43)
|
|
||||||
|
|
||||||
// Different native types.
|
|
||||||
testCheck(c, gocheck.Equals, false, "", int32(42), int64(42))
|
|
||||||
|
|
||||||
// With nil.
|
|
||||||
testCheck(c, gocheck.Equals, false, "", 42, nil)
|
|
||||||
|
|
||||||
// Slices
|
|
||||||
testCheck(c, gocheck.Equals, false, "runtime error: comparing uncomparable type []uint8", []byte{1, 2}, []byte{1, 2})
|
|
||||||
|
|
||||||
// Struct values
|
|
||||||
testCheck(c, gocheck.Equals, true, "", simpleStruct{1}, simpleStruct{1})
|
|
||||||
testCheck(c, gocheck.Equals, false, "", simpleStruct{1}, simpleStruct{2})
|
|
||||||
|
|
||||||
// Struct pointers
|
|
||||||
testCheck(c, gocheck.Equals, false, "", &simpleStruct{1}, &simpleStruct{1})
|
|
||||||
testCheck(c, gocheck.Equals, false, "", &simpleStruct{1}, &simpleStruct{2})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestDeepEquals(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.DeepEquals, "DeepEquals", []string{"obtained", "expected"})
|
|
||||||
|
|
||||||
// The simplest.
|
|
||||||
testCheck(c, gocheck.DeepEquals, true, "", 42, 42)
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", 42, 43)
|
|
||||||
|
|
||||||
// Different native types.
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", int32(42), int64(42))
|
|
||||||
|
|
||||||
// With nil.
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", 42, nil)
|
|
||||||
|
|
||||||
// Slices
|
|
||||||
testCheck(c, gocheck.DeepEquals, true, "", []byte{1, 2}, []byte{1, 2})
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", []byte{1, 2}, []byte{1, 3})
|
|
||||||
|
|
||||||
// Struct values
|
|
||||||
testCheck(c, gocheck.DeepEquals, true, "", simpleStruct{1}, simpleStruct{1})
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", simpleStruct{1}, simpleStruct{2})
|
|
||||||
|
|
||||||
// Struct pointers
|
|
||||||
testCheck(c, gocheck.DeepEquals, true, "", &simpleStruct{1}, &simpleStruct{1})
|
|
||||||
testCheck(c, gocheck.DeepEquals, false, "", &simpleStruct{1}, &simpleStruct{2})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestHasLen(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.HasLen, "HasLen", []string{"obtained", "n"})
|
|
||||||
|
|
||||||
testCheck(c, gocheck.HasLen, true, "", "abcd", 4)
|
|
||||||
testCheck(c, gocheck.HasLen, true, "", []int{1, 2}, 2)
|
|
||||||
testCheck(c, gocheck.HasLen, false, "", []int{1, 2}, 3)
|
|
||||||
|
|
||||||
testCheck(c, gocheck.HasLen, false, "n must be an int", []int{1, 2}, "2")
|
|
||||||
testCheck(c, gocheck.HasLen, false, "obtained value type has no length", nil, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestErrorMatches(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.ErrorMatches, "ErrorMatches", []string{"value", "regex"})
|
|
||||||
|
|
||||||
testCheck(c, gocheck.ErrorMatches, false, "Error value is nil", nil, "some error")
|
|
||||||
testCheck(c, gocheck.ErrorMatches, false, "Value is not an error", 1, "some error")
|
|
||||||
testCheck(c, gocheck.ErrorMatches, true, "", errors.New("some error"), "some error")
|
|
||||||
testCheck(c, gocheck.ErrorMatches, true, "", errors.New("some error"), "so.*or")
|
|
||||||
|
|
||||||
// Verify params mutation
|
|
||||||
params, names := testCheck(c, gocheck.ErrorMatches, false, "", errors.New("some error"), "other error")
|
|
||||||
c.Assert(params[0], gocheck.Equals, "some error")
|
|
||||||
c.Assert(names[0], gocheck.Equals, "error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestMatches(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.Matches, "Matches", []string{"value", "regex"})
|
|
||||||
|
|
||||||
// Simple matching
|
|
||||||
testCheck(c, gocheck.Matches, true, "", "abc", "abc")
|
|
||||||
testCheck(c, gocheck.Matches, true, "", "abc", "a.c")
|
|
||||||
|
|
||||||
// Must match fully
|
|
||||||
testCheck(c, gocheck.Matches, false, "", "abc", "ab")
|
|
||||||
testCheck(c, gocheck.Matches, false, "", "abc", "bc")
|
|
||||||
|
|
||||||
// String()-enabled values accepted
|
|
||||||
testCheck(c, gocheck.Matches, true, "", reflect.ValueOf("abc"), "a.c")
|
|
||||||
testCheck(c, gocheck.Matches, false, "", reflect.ValueOf("abc"), "a.d")
|
|
||||||
|
|
||||||
// Some error conditions.
|
|
||||||
testCheck(c, gocheck.Matches, false, "Obtained value is not a string and has no .String()", 1, "a.c")
|
|
||||||
testCheck(c, gocheck.Matches, false, "Can't compile regex: error parsing regexp: missing closing ]: `[c$`", "abc", "a[c")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestPanics(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.Panics, "Panics", []string{"function", "expected"})
|
|
||||||
|
|
||||||
// Some errors.
|
|
||||||
testCheck(c, gocheck.Panics, false, "Function has not panicked", func() bool { return false }, "BOOM")
|
|
||||||
testCheck(c, gocheck.Panics, false, "Function must take zero arguments", 1, "BOOM")
|
|
||||||
|
|
||||||
// Plain strings.
|
|
||||||
testCheck(c, gocheck.Panics, true, "", func() { panic("BOOM") }, "BOOM")
|
|
||||||
testCheck(c, gocheck.Panics, false, "", func() { panic("KABOOM") }, "BOOM")
|
|
||||||
testCheck(c, gocheck.Panics, true, "", func() bool { panic("BOOM") }, "BOOM")
|
|
||||||
|
|
||||||
// Error values.
|
|
||||||
testCheck(c, gocheck.Panics, true, "", func() { panic(errors.New("BOOM")) }, errors.New("BOOM"))
|
|
||||||
testCheck(c, gocheck.Panics, false, "", func() { panic(errors.New("KABOOM")) }, errors.New("BOOM"))
|
|
||||||
|
|
||||||
type deep struct{ i int }
|
|
||||||
// Deep value
|
|
||||||
testCheck(c, gocheck.Panics, true, "", func() { panic(&deep{99}) }, &deep{99})
|
|
||||||
|
|
||||||
// Verify params/names mutation
|
|
||||||
params, names := testCheck(c, gocheck.Panics, false, "", func() { panic(errors.New("KABOOM")) }, errors.New("BOOM"))
|
|
||||||
c.Assert(params[0], gocheck.ErrorMatches, "KABOOM")
|
|
||||||
c.Assert(names[0], gocheck.Equals, "panic")
|
|
||||||
|
|
||||||
// Verify a nil panic
|
|
||||||
testCheck(c, gocheck.Panics, true, "", func() { panic(nil) }, nil)
|
|
||||||
testCheck(c, gocheck.Panics, false, "", func() { panic(nil) }, "NOPE")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestPanicMatches(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.PanicMatches, "PanicMatches", []string{"function", "expected"})
|
|
||||||
|
|
||||||
// Error matching.
|
|
||||||
testCheck(c, gocheck.PanicMatches, true, "", func() { panic(errors.New("BOOM")) }, "BO.M")
|
|
||||||
testCheck(c, gocheck.PanicMatches, false, "", func() { panic(errors.New("KABOOM")) }, "BO.M")
|
|
||||||
|
|
||||||
// Some errors.
|
|
||||||
testCheck(c, gocheck.PanicMatches, false, "Function has not panicked", func() bool { return false }, "BOOM")
|
|
||||||
testCheck(c, gocheck.PanicMatches, false, "Function must take zero arguments", 1, "BOOM")
|
|
||||||
|
|
||||||
// Plain strings.
|
|
||||||
testCheck(c, gocheck.PanicMatches, true, "", func() { panic("BOOM") }, "BO.M")
|
|
||||||
testCheck(c, gocheck.PanicMatches, false, "", func() { panic("KABOOM") }, "BOOM")
|
|
||||||
testCheck(c, gocheck.PanicMatches, true, "", func() bool { panic("BOOM") }, "BO.M")
|
|
||||||
|
|
||||||
// Verify params/names mutation
|
|
||||||
params, names := testCheck(c, gocheck.PanicMatches, false, "", func() { panic(errors.New("KABOOM")) }, "BOOM")
|
|
||||||
c.Assert(params[0], gocheck.Equals, "KABOOM")
|
|
||||||
c.Assert(names[0], gocheck.Equals, "panic")
|
|
||||||
|
|
||||||
// Verify a nil panic
|
|
||||||
testCheck(c, gocheck.PanicMatches, false, "Panic value is not a string or an error", func() { panic(nil) }, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestFitsTypeOf(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.FitsTypeOf, "FitsTypeOf", []string{"obtained", "sample"})
|
|
||||||
|
|
||||||
// Basic types
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, true, "", 1, 0)
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", 1, int64(0))
|
|
||||||
|
|
||||||
// Aliases
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", 1, errors.New(""))
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", "error", errors.New(""))
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, true, "", errors.New("error"), errors.New(""))
|
|
||||||
|
|
||||||
// Structures
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", 1, simpleStruct{})
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", simpleStruct{42}, &simpleStruct{})
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, true, "", simpleStruct{42}, simpleStruct{})
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, true, "", &simpleStruct{42}, &simpleStruct{})
|
|
||||||
|
|
||||||
// Some bad values
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "Invalid sample value", 1, interface{}(nil))
|
|
||||||
testCheck(c, gocheck.FitsTypeOf, false, "", interface{}(nil), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CheckersS) TestImplements(c *gocheck.C) {
|
|
||||||
testInfo(c, gocheck.Implements, "Implements", []string{"obtained", "ifaceptr"})
|
|
||||||
|
|
||||||
var e error
|
|
||||||
var re runtime.Error
|
|
||||||
testCheck(c, gocheck.Implements, true, "", errors.New(""), &e)
|
|
||||||
testCheck(c, gocheck.Implements, false, "", errors.New(""), &re)
|
|
||||||
|
|
||||||
// Some bad values
|
|
||||||
testCheck(c, gocheck.Implements, false, "ifaceptr should be a pointer to an interface variable", 0, errors.New(""))
|
|
||||||
testCheck(c, gocheck.Implements, false, "ifaceptr should be a pointer to an interface variable", 0, interface{}(nil))
|
|
||||||
testCheck(c, gocheck.Implements, false, "", interface{}(nil), &e)
|
|
||||||
}
|
|
9
Godeps/_workspace/src/github.com/motain/gocheck/export_test.go
generated
vendored
9
Godeps/_workspace/src/github.com/motain/gocheck/export_test.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
func PrintLine(filename string, line int) (string, error) {
|
|
||||||
return printLine(filename, line)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Indent(s, with string) string {
|
|
||||||
return indent(s, with)
|
|
||||||
}
|
|
479
Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go
generated
vendored
479
Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go
generated
vendored
@ -1,479 +0,0 @@
|
|||||||
// Tests for the behavior of the test fixture system.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "launchpad.net/gocheck"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Fixture test suite.
|
|
||||||
|
|
||||||
type FixtureS struct{}
|
|
||||||
|
|
||||||
var fixtureS = Suite(&FixtureS{})
|
|
||||||
|
|
||||||
func (s *FixtureS) TestCountSuite(c *C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Basic fixture ordering verification.
|
|
||||||
|
|
||||||
func (s *FixtureS) TestOrder(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
Run(&helper, nil)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[7], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Check the behavior when panics occur within tests and fixtures.
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnTest(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "Test1"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[7], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: FixtureHelper.Test1\n\n" +
|
|
||||||
"\\.\\.\\. Panic: Test1 \\(PC=[xA-F0-9]+\\)\n\n" +
|
|
||||||
".+:[0-9]+\n" +
|
|
||||||
" in panic\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.trace\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.Test1\n$"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnSetUpTest(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "SetUpTest"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 4)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper\\.SetUpTest\n\n" +
|
|
||||||
"\\.\\.\\. Panic: SetUpTest \\(PC=[xA-F0-9]+\\)\n\n" +
|
|
||||||
".+:[0-9]+\n" +
|
|
||||||
" in panic\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.trace\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.SetUpTest\n" +
|
|
||||||
"\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper\\.Test1\n\n" +
|
|
||||||
"\\.\\.\\. Panic: Fixture has panicked " +
|
|
||||||
"\\(see related PANIC\\)\n$"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnTearDownTest(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "TearDownTest"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 5)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper.TearDownTest\n\n" +
|
|
||||||
"\\.\\.\\. Panic: TearDownTest \\(PC=[xA-F0-9]+\\)\n\n" +
|
|
||||||
".+:[0-9]+\n" +
|
|
||||||
" in panic\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.trace\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.TearDownTest\n" +
|
|
||||||
"\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper\\.Test1\n\n" +
|
|
||||||
"\\.\\.\\. Panic: Fixture has panicked " +
|
|
||||||
"\\(see related PANIC\\)\n$"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnSetUpSuite(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "SetUpSuite"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 2)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper.SetUpSuite\n\n" +
|
|
||||||
"\\.\\.\\. Panic: SetUpSuite \\(PC=[xA-F0-9]+\\)\n\n" +
|
|
||||||
".+:[0-9]+\n" +
|
|
||||||
" in panic\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.trace\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.SetUpSuite\n$"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnTearDownSuite(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "TearDownSuite"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[7], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: gocheck_test\\.go:[0-9]+: " +
|
|
||||||
"FixtureHelper.TearDownSuite\n\n" +
|
|
||||||
"\\.\\.\\. Panic: TearDownSuite \\(PC=[xA-F0-9]+\\)\n\n" +
|
|
||||||
".+:[0-9]+\n" +
|
|
||||||
" in panic\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.trace\n" +
|
|
||||||
".*gocheck_test.go:[0-9]+\n" +
|
|
||||||
" in FixtureHelper.TearDownSuite\n$"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// A wrong argument on a test or fixture will produce a nice error.
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongTestArg(c *C) {
|
|
||||||
helper := WrongTestArgHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[3], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[5], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 7)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongTestArgHelper\\.Test1\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongTestArgHelper\\.Test1 argument " +
|
|
||||||
"should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongSetUpTestArg(c *C) {
|
|
||||||
helper := WrongSetUpTestArgHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
|
|
||||||
expected :=
|
|
||||||
"^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongSetUpTestArgHelper\\.SetUpTest\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongSetUpTestArgHelper\\.SetUpTest argument " +
|
|
||||||
"should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongSetUpSuiteArg(c *C) {
|
|
||||||
helper := WrongSetUpSuiteArgHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
|
|
||||||
expected :=
|
|
||||||
"^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongSetUpSuiteArgHelper\\.SetUpSuite\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongSetUpSuiteArgHelper\\.SetUpSuite argument " +
|
|
||||||
"should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Nice errors also when tests or fixture have wrong arg count.
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongTestArgCount(c *C) {
|
|
||||||
helper := WrongTestArgCountHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[3], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[5], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 7)
|
|
||||||
|
|
||||||
expected := "^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongTestArgCountHelper\\.Test1\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongTestArgCountHelper\\.Test1 argument " +
|
|
||||||
"should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongSetUpTestArgCount(c *C) {
|
|
||||||
helper := WrongSetUpTestArgCountHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
|
|
||||||
expected :=
|
|
||||||
"^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongSetUpTestArgCountHelper\\.SetUpTest\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongSetUpTestArgCountHelper\\.SetUpTest argument " +
|
|
||||||
"should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestPanicOnWrongSetUpSuiteArgCount(c *C) {
|
|
||||||
helper := WrongSetUpSuiteArgCountHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
|
|
||||||
expected :=
|
|
||||||
"^\n-+\n" +
|
|
||||||
"PANIC: fixture_test\\.go:[0-9]+: " +
|
|
||||||
"WrongSetUpSuiteArgCountHelper\\.SetUpSuite\n\n" +
|
|
||||||
"\\.\\.\\. Panic: WrongSetUpSuiteArgCountHelper" +
|
|
||||||
"\\.SetUpSuite argument should be \\*gocheck\\.C\n"
|
|
||||||
|
|
||||||
c.Check(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper test suites with wrong function arguments.
|
|
||||||
|
|
||||||
type WrongTestArgHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongTestArgHelper) Test1(t int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrongSetUpTestArgHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongSetUpTestArgHelper) SetUpTest(t int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrongSetUpSuiteArgHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongSetUpSuiteArgHelper) SetUpSuite(t int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrongTestArgCountHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongTestArgCountHelper) Test1(c *C, i int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrongSetUpTestArgCountHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongSetUpTestArgCountHelper) SetUpTest(c *C, i int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrongSetUpSuiteArgCountHelper struct {
|
|
||||||
FixtureHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WrongSetUpSuiteArgCountHelper) SetUpSuite(c *C, i int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Ensure fixture doesn't run without tests.
|
|
||||||
|
|
||||||
type NoTestsHelper struct {
|
|
||||||
hasRun bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *NoTestsHelper) SetUpSuite(c *C) {
|
|
||||||
s.hasRun = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *NoTestsHelper) TearDownSuite(c *C) {
|
|
||||||
s.hasRun = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestFixtureDoesntRunWithoutTests(c *C) {
|
|
||||||
helper := NoTestsHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Check(helper.hasRun, Equals, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify that checks and assertions work correctly inside the fixture.
|
|
||||||
|
|
||||||
type FixtureCheckHelper struct {
|
|
||||||
fail string
|
|
||||||
completed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureCheckHelper) SetUpSuite(c *C) {
|
|
||||||
switch s.fail {
|
|
||||||
case "SetUpSuiteAssert":
|
|
||||||
c.Assert(false, Equals, true)
|
|
||||||
case "SetUpSuiteCheck":
|
|
||||||
c.Check(false, Equals, true)
|
|
||||||
}
|
|
||||||
s.completed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureCheckHelper) SetUpTest(c *C) {
|
|
||||||
switch s.fail {
|
|
||||||
case "SetUpTestAssert":
|
|
||||||
c.Assert(false, Equals, true)
|
|
||||||
case "SetUpTestCheck":
|
|
||||||
c.Check(false, Equals, true)
|
|
||||||
}
|
|
||||||
s.completed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureCheckHelper) Test(c *C) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestSetUpSuiteCheck(c *C) {
|
|
||||||
helper := FixtureCheckHelper{fail: "SetUpSuiteCheck"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Assert(output.value, Matches,
|
|
||||||
"\n---+\n"+
|
|
||||||
"FAIL: fixture_test\\.go:[0-9]+: "+
|
|
||||||
"FixtureCheckHelper\\.SetUpSuite\n\n"+
|
|
||||||
"fixture_test\\.go:[0-9]+:\n"+
|
|
||||||
" c\\.Check\\(false, Equals, true\\)\n"+
|
|
||||||
"\\.+ obtained bool = false\n"+
|
|
||||||
"\\.+ expected bool = true\n\n")
|
|
||||||
c.Assert(helper.completed, Equals, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestSetUpSuiteAssert(c *C) {
|
|
||||||
helper := FixtureCheckHelper{fail: "SetUpSuiteAssert"}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Assert(output.value, Matches,
|
|
||||||
"\n---+\n"+
|
|
||||||
"FAIL: fixture_test\\.go:[0-9]+: "+
|
|
||||||
"FixtureCheckHelper\\.SetUpSuite\n\n"+
|
|
||||||
"fixture_test\\.go:[0-9]+:\n"+
|
|
||||||
" c\\.Assert\\(false, Equals, true\\)\n"+
|
|
||||||
"\\.+ obtained bool = false\n"+
|
|
||||||
"\\.+ expected bool = true\n\n")
|
|
||||||
c.Assert(helper.completed, Equals, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify that logging within SetUpTest() persists within the test log itself.
|
|
||||||
|
|
||||||
type FixtureLogHelper struct {
|
|
||||||
c *C
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureLogHelper) SetUpTest(c *C) {
|
|
||||||
s.c = c
|
|
||||||
c.Log("1")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureLogHelper) Test(c *C) {
|
|
||||||
c.Log("2")
|
|
||||||
s.c.Log("3")
|
|
||||||
c.Log("4")
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureLogHelper) TearDownTest(c *C) {
|
|
||||||
s.c.Log("5")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestFixtureLogging(c *C) {
|
|
||||||
helper := FixtureLogHelper{}
|
|
||||||
output := String{}
|
|
||||||
Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Assert(output.value, Matches,
|
|
||||||
"\n---+\n"+
|
|
||||||
"FAIL: fixture_test\\.go:[0-9]+: "+
|
|
||||||
"FixtureLogHelper\\.Test\n\n"+
|
|
||||||
"1\n2\n3\n4\n5\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Skip() within fixture methods.
|
|
||||||
|
|
||||||
func (s *FixtureS) TestSkipSuite(c *C) {
|
|
||||||
helper := FixtureHelper{skip: true, skipOnN: 0}
|
|
||||||
output := String{}
|
|
||||||
result := Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Assert(output.value, Equals, "")
|
|
||||||
c.Assert(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Assert(helper.calls[1], Equals, "TearDownSuite")
|
|
||||||
c.Assert(len(helper.calls), Equals, 2)
|
|
||||||
c.Assert(result.Skipped, Equals, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureS) TestSkipTest(c *C) {
|
|
||||||
helper := FixtureHelper{skip: true, skipOnN: 1}
|
|
||||||
output := String{}
|
|
||||||
result := Run(&helper, &RunConf{Output: &output})
|
|
||||||
c.Assert(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Assert(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Assert(helper.calls[2], Equals, "SetUpTest")
|
|
||||||
c.Assert(helper.calls[3], Equals, "Test2")
|
|
||||||
c.Assert(helper.calls[4], Equals, "TearDownTest")
|
|
||||||
c.Assert(helper.calls[5], Equals, "TearDownSuite")
|
|
||||||
c.Assert(len(helper.calls), Equals, 6)
|
|
||||||
c.Assert(result.Skipped, Equals, 1)
|
|
||||||
}
|
|
340
Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go
generated
vendored
340
Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go
generated
vendored
@ -1,340 +0,0 @@
|
|||||||
// These tests check that the foundations of gocheck are working properly.
|
|
||||||
// They already assume that fundamental failing is working already, though,
|
|
||||||
// since this was tested in bootstrap_test.go. Even then, some care may
|
|
||||||
// still have to be taken when using external functions, since they should
|
|
||||||
// of course not rely on functionality tested here.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"launchpad.net/gocheck"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Foundation test suite.
|
|
||||||
|
|
||||||
type FoundationS struct{}
|
|
||||||
|
|
||||||
var foundationS = gocheck.Suite(&FoundationS{})
|
|
||||||
|
|
||||||
func (s *FoundationS) TestCountSuite(c *gocheck.C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestErrorf(c *gocheck.C) {
|
|
||||||
// Do not use checkState() here. It depends on Errorf() working.
|
|
||||||
expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
|
|
||||||
" c.Errorf(\"Error %%v!\", \"message\")\n"+
|
|
||||||
"... Error: Error message!\n\n",
|
|
||||||
getMyLine()+1)
|
|
||||||
c.Errorf("Error %v!", "message")
|
|
||||||
failed := c.Failed()
|
|
||||||
c.Succeed()
|
|
||||||
if log := c.GetTestLog(); log != expectedLog {
|
|
||||||
c.Logf("Errorf() logged %#v rather than %#v", log, expectedLog)
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
if !failed {
|
|
||||||
c.Logf("Errorf() didn't put the test in a failed state")
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestError(c *gocheck.C) {
|
|
||||||
expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
|
|
||||||
" c\\.Error\\(\"Error \", \"message!\"\\)\n"+
|
|
||||||
"\\.\\.\\. Error: Error message!\n\n",
|
|
||||||
getMyLine()+1)
|
|
||||||
c.Error("Error ", "message!")
|
|
||||||
checkState(c, nil,
|
|
||||||
&expectedState{
|
|
||||||
name: "Error(`Error `, `message!`)",
|
|
||||||
failed: true,
|
|
||||||
log: expectedLog,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestFailNow(c *gocheck.C) {
|
|
||||||
defer (func() {
|
|
||||||
if !c.Failed() {
|
|
||||||
c.Error("FailNow() didn't fail the test")
|
|
||||||
} else {
|
|
||||||
c.Succeed()
|
|
||||||
if c.GetTestLog() != "" {
|
|
||||||
c.Error("Something got logged:\n" + c.GetTestLog())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
c.FailNow()
|
|
||||||
c.Log("FailNow() didn't stop the test")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestSucceedNow(c *gocheck.C) {
|
|
||||||
defer (func() {
|
|
||||||
if c.Failed() {
|
|
||||||
c.Error("SucceedNow() didn't succeed the test")
|
|
||||||
}
|
|
||||||
if c.GetTestLog() != "" {
|
|
||||||
c.Error("Something got logged:\n" + c.GetTestLog())
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
c.Fail()
|
|
||||||
c.SucceedNow()
|
|
||||||
c.Log("SucceedNow() didn't stop the test")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestFailureHeader(c *gocheck.C) {
|
|
||||||
output := String{}
|
|
||||||
failHelper := FailHelper{}
|
|
||||||
gocheck.Run(&failHelper, &gocheck.RunConf{Output: &output})
|
|
||||||
header := fmt.Sprintf(""+
|
|
||||||
"\n-----------------------------------"+
|
|
||||||
"-----------------------------------\n"+
|
|
||||||
"FAIL: gocheck_test.go:%d: FailHelper.TestLogAndFail\n",
|
|
||||||
failHelper.testLine)
|
|
||||||
if strings.Index(output.value, header) == -1 {
|
|
||||||
c.Errorf(""+
|
|
||||||
"Failure didn't print a proper header.\n"+
|
|
||||||
"... Got:\n%s... Expected something with:\n%s",
|
|
||||||
output.value, header)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestFatal(c *gocheck.C) {
|
|
||||||
var line int
|
|
||||||
defer (func() {
|
|
||||||
if !c.Failed() {
|
|
||||||
c.Error("Fatal() didn't fail the test")
|
|
||||||
} else {
|
|
||||||
c.Succeed()
|
|
||||||
expected := fmt.Sprintf("foundation_test.go:%d:\n"+
|
|
||||||
" c.Fatal(\"Die \", \"now!\")\n"+
|
|
||||||
"... Error: Die now!\n\n",
|
|
||||||
line)
|
|
||||||
if c.GetTestLog() != expected {
|
|
||||||
c.Error("Incorrect log:", c.GetTestLog())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
line = getMyLine() + 1
|
|
||||||
c.Fatal("Die ", "now!")
|
|
||||||
c.Log("Fatal() didn't stop the test")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestFatalf(c *gocheck.C) {
|
|
||||||
var line int
|
|
||||||
defer (func() {
|
|
||||||
if !c.Failed() {
|
|
||||||
c.Error("Fatalf() didn't fail the test")
|
|
||||||
} else {
|
|
||||||
c.Succeed()
|
|
||||||
expected := fmt.Sprintf("foundation_test.go:%d:\n"+
|
|
||||||
" c.Fatalf(\"Die %%s!\", \"now\")\n"+
|
|
||||||
"... Error: Die now!\n\n",
|
|
||||||
line)
|
|
||||||
if c.GetTestLog() != expected {
|
|
||||||
c.Error("Incorrect log:", c.GetTestLog())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
line = getMyLine() + 1
|
|
||||||
c.Fatalf("Die %s!", "now")
|
|
||||||
c.Log("Fatalf() didn't stop the test")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestCallerLoggingInsideTest(c *gocheck.C) {
|
|
||||||
log := fmt.Sprintf(""+
|
|
||||||
"foundation_test.go:%d:\n"+
|
|
||||||
" result := c.Check\\(10, gocheck.Equals, 20\\)\n"+
|
|
||||||
"\\.\\.\\. obtained int = 10\n"+
|
|
||||||
"\\.\\.\\. expected int = 20\n\n",
|
|
||||||
getMyLine()+1)
|
|
||||||
result := c.Check(10, gocheck.Equals, 20)
|
|
||||||
checkState(c, result,
|
|
||||||
&expectedState{
|
|
||||||
name: "Check(10, Equals, 20)",
|
|
||||||
result: false,
|
|
||||||
failed: true,
|
|
||||||
log: log,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestCallerLoggingInDifferentFile(c *gocheck.C) {
|
|
||||||
result, line := checkEqualWrapper(c, 10, 20)
|
|
||||||
testLine := getMyLine() - 1
|
|
||||||
log := fmt.Sprintf(""+
|
|
||||||
"foundation_test.go:%d:\n"+
|
|
||||||
" result, line := checkEqualWrapper\\(c, 10, 20\\)\n"+
|
|
||||||
"gocheck_test.go:%d:\n"+
|
|
||||||
" return c.Check\\(obtained, gocheck.Equals, expected\\), getMyLine\\(\\)\n"+
|
|
||||||
"\\.\\.\\. obtained int = 10\n"+
|
|
||||||
"\\.\\.\\. expected int = 20\n\n",
|
|
||||||
testLine, line)
|
|
||||||
checkState(c, result,
|
|
||||||
&expectedState{
|
|
||||||
name: "Check(10, Equals, 20)",
|
|
||||||
result: false,
|
|
||||||
failed: true,
|
|
||||||
log: log,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// ExpectFailure() inverts the logic of failure.
|
|
||||||
|
|
||||||
type ExpectFailureSucceedHelper struct{}
|
|
||||||
|
|
||||||
func (s *ExpectFailureSucceedHelper) TestSucceed(c *gocheck.C) {
|
|
||||||
c.ExpectFailure("It booms!")
|
|
||||||
c.Error("Boom!")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExpectFailureFailHelper struct{}
|
|
||||||
|
|
||||||
func (s *ExpectFailureFailHelper) TestFail(c *gocheck.C) {
|
|
||||||
c.ExpectFailure("Bug #XYZ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestExpectFailureFail(c *gocheck.C) {
|
|
||||||
helper := ExpectFailureFailHelper{}
|
|
||||||
output := String{}
|
|
||||||
result := gocheck.Run(&helper, &gocheck.RunConf{Output: &output})
|
|
||||||
|
|
||||||
expected := "" +
|
|
||||||
"^\n-+\n" +
|
|
||||||
"FAIL: foundation_test\\.go:[0-9]+:" +
|
|
||||||
" ExpectFailureFailHelper\\.TestFail\n\n" +
|
|
||||||
"\\.\\.\\. Error: Test succeeded, but was expected to fail\n" +
|
|
||||||
"\\.\\.\\. Reason: Bug #XYZ\n$"
|
|
||||||
|
|
||||||
matched, err := regexp.MatchString(expected, output.value)
|
|
||||||
if err != nil {
|
|
||||||
c.Error("Bad expression: ", expected)
|
|
||||||
} else if !matched {
|
|
||||||
c.Error("ExpectFailure() didn't log properly:\n", output.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Assert(result.ExpectedFailures, gocheck.Equals, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestExpectFailureSucceed(c *gocheck.C) {
|
|
||||||
helper := ExpectFailureSucceedHelper{}
|
|
||||||
output := String{}
|
|
||||||
result := gocheck.Run(&helper, &gocheck.RunConf{Output: &output})
|
|
||||||
|
|
||||||
c.Assert(output.value, gocheck.Equals, "")
|
|
||||||
c.Assert(result.ExpectedFailures, gocheck.Equals, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestExpectFailureSucceedVerbose(c *gocheck.C) {
|
|
||||||
helper := ExpectFailureSucceedHelper{}
|
|
||||||
output := String{}
|
|
||||||
result := gocheck.Run(&helper, &gocheck.RunConf{Output: &output, Verbose: true})
|
|
||||||
|
|
||||||
expected := "" +
|
|
||||||
"FAIL EXPECTED: foundation_test\\.go:[0-9]+:" +
|
|
||||||
" ExpectFailureSucceedHelper\\.TestSucceed \\(It booms!\\)\t *[.0-9]+s\n"
|
|
||||||
|
|
||||||
matched, err := regexp.MatchString(expected, output.value)
|
|
||||||
if err != nil {
|
|
||||||
c.Error("Bad expression: ", expected)
|
|
||||||
} else if !matched {
|
|
||||||
c.Error("ExpectFailure() didn't log properly:\n", output.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Assert(result.ExpectedFailures, gocheck.Equals, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Skip() allows stopping a test without positive/negative results.
|
|
||||||
|
|
||||||
type SkipTestHelper struct{}
|
|
||||||
|
|
||||||
func (s *SkipTestHelper) TestFail(c *gocheck.C) {
|
|
||||||
c.Skip("Wrong platform or whatever")
|
|
||||||
c.Error("Boom!")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestSkip(c *gocheck.C) {
|
|
||||||
helper := SkipTestHelper{}
|
|
||||||
output := String{}
|
|
||||||
gocheck.Run(&helper, &gocheck.RunConf{Output: &output})
|
|
||||||
|
|
||||||
if output.value != "" {
|
|
||||||
c.Error("Skip() logged something:\n", output.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FoundationS) TestSkipVerbose(c *gocheck.C) {
|
|
||||||
helper := SkipTestHelper{}
|
|
||||||
output := String{}
|
|
||||||
gocheck.Run(&helper, &gocheck.RunConf{Output: &output, Verbose: true})
|
|
||||||
|
|
||||||
expected := "SKIP: foundation_test\\.go:[0-9]+: SkipTestHelper\\.TestFail" +
|
|
||||||
" \\(Wrong platform or whatever\\)"
|
|
||||||
matched, err := regexp.MatchString(expected, output.value)
|
|
||||||
if err != nil {
|
|
||||||
c.Error("Bad expression: ", expected)
|
|
||||||
} else if !matched {
|
|
||||||
c.Error("Skip() didn't log properly:\n", output.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Check minimum *log.Logger interface provided by *gocheck.C.
|
|
||||||
|
|
||||||
type minLogger interface {
|
|
||||||
Output(calldepth int, s string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BootstrapS) TestMinLogger(c *gocheck.C) {
|
|
||||||
var logger minLogger
|
|
||||||
logger = log.New(os.Stderr, "", 0)
|
|
||||||
logger = c
|
|
||||||
logger.Output(0, "Hello there")
|
|
||||||
expected := "\\[LOG\\] [.0-9]+ Hello there\n"
|
|
||||||
output := c.GetTestLog()
|
|
||||||
matched, err := regexp.MatchString(expected, output)
|
|
||||||
if err != nil {
|
|
||||||
c.Error("Bad expression: ", expected)
|
|
||||||
} else if !matched {
|
|
||||||
c.Error("Output() didn't log properly:\n", output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Ensure that suites with embedded types are working fine, including the
|
|
||||||
// the workaround for issue 906.
|
|
||||||
|
|
||||||
type EmbeddedInternalS struct {
|
|
||||||
called bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type EmbeddedS struct {
|
|
||||||
EmbeddedInternalS
|
|
||||||
}
|
|
||||||
|
|
||||||
var embeddedS = gocheck.Suite(&EmbeddedS{})
|
|
||||||
|
|
||||||
func (s *EmbeddedS) TestCountSuite(c *gocheck.C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EmbeddedInternalS) TestMethod(c *gocheck.C) {
|
|
||||||
c.Error("TestMethod() of the embedded type was called!?")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EmbeddedS) TestMethod(c *gocheck.C) {
|
|
||||||
// http://code.google.com/p/go/issues/detail?id=906
|
|
||||||
c.Check(s.called, gocheck.Equals, false) // Go issue 906 is affecting the runner?
|
|
||||||
s.called = true
|
|
||||||
}
|
|
915
Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go
generated
vendored
915
Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go
generated
vendored
@ -1,915 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Internal type which deals with suite method calling.
|
|
||||||
|
|
||||||
const (
|
|
||||||
fixtureKd = iota
|
|
||||||
testKd
|
|
||||||
)
|
|
||||||
|
|
||||||
type funcKind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
succeededSt = iota
|
|
||||||
failedSt
|
|
||||||
skippedSt
|
|
||||||
panickedSt
|
|
||||||
fixturePanickedSt
|
|
||||||
missedSt
|
|
||||||
)
|
|
||||||
|
|
||||||
type funcStatus int
|
|
||||||
|
|
||||||
// A method value can't reach its own Method structure.
|
|
||||||
type methodType struct {
|
|
||||||
reflect.Value
|
|
||||||
Info reflect.Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMethod(receiver reflect.Value, i int) *methodType {
|
|
||||||
return &methodType{receiver.Method(i), receiver.Type().Method(i)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (method *methodType) PC() uintptr {
|
|
||||||
return method.Info.Func.Pointer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (method *methodType) suiteName() string {
|
|
||||||
t := method.Info.Type.In(0)
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
return t.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (method *methodType) String() string {
|
|
||||||
return method.suiteName() + "." + method.Info.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (method *methodType) matches(re *regexp.Regexp) bool {
|
|
||||||
return (re.MatchString(method.Info.Name) ||
|
|
||||||
re.MatchString(method.suiteName()) ||
|
|
||||||
re.MatchString(method.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
type C struct {
|
|
||||||
method *methodType
|
|
||||||
kind funcKind
|
|
||||||
status funcStatus
|
|
||||||
logb *logger
|
|
||||||
logw io.Writer
|
|
||||||
done chan *C
|
|
||||||
reason string
|
|
||||||
mustFail bool
|
|
||||||
tempDir *tempDir
|
|
||||||
timer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) stopNow() {
|
|
||||||
runtime.Goexit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// logger is a concurrency safe byte.Buffer
|
|
||||||
type logger struct {
|
|
||||||
sync.Mutex
|
|
||||||
writer bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *logger) Write(buf []byte) (int, error) {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
return l.writer.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *logger) WriteTo(w io.Writer) (int64, error) {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
return l.writer.WriteTo(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *logger) String() string {
|
|
||||||
l.Lock()
|
|
||||||
defer l.Unlock()
|
|
||||||
return l.writer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Handling of temporary files and directories.
|
|
||||||
|
|
||||||
type tempDir struct {
|
|
||||||
sync.Mutex
|
|
||||||
_path string
|
|
||||||
_counter int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (td *tempDir) newPath() string {
|
|
||||||
td.Lock()
|
|
||||||
defer td.Unlock()
|
|
||||||
if td._path == "" {
|
|
||||||
var err error
|
|
||||||
for i := 0; i != 100; i++ {
|
|
||||||
path := fmt.Sprintf("%s/gocheck-%d", os.TempDir(), rand.Int())
|
|
||||||
if err = os.Mkdir(path, 0700); err == nil {
|
|
||||||
td._path = path
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if td._path == "" {
|
|
||||||
panic("Couldn't create temporary directory: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result := path.Join(td._path, strconv.Itoa(td._counter))
|
|
||||||
td._counter += 1
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (td *tempDir) removeAll() {
|
|
||||||
td.Lock()
|
|
||||||
defer td.Unlock()
|
|
||||||
if td._path != "" {
|
|
||||||
err := os.RemoveAll(td._path)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new temporary directory which is automatically removed after
|
|
||||||
// the suite finishes running.
|
|
||||||
func (c *C) MkDir() string {
|
|
||||||
path := c.tempDir.newPath()
|
|
||||||
if err := os.Mkdir(path, 0700); err != nil {
|
|
||||||
panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error()))
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Low-level logging functions.
|
|
||||||
|
|
||||||
func (c *C) log(args ...interface{}) {
|
|
||||||
c.writeLog([]byte(fmt.Sprint(args...) + "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logf(format string, args ...interface{}) {
|
|
||||||
c.writeLog([]byte(fmt.Sprintf(format+"\n", args...)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logNewLine() {
|
|
||||||
c.writeLog([]byte{'\n'})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) writeLog(buf []byte) {
|
|
||||||
c.logb.Write(buf)
|
|
||||||
if c.logw != nil {
|
|
||||||
c.logw.Write(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasStringOrError(x interface{}) (ok bool) {
|
|
||||||
_, ok = x.(fmt.Stringer)
|
|
||||||
if ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, ok = x.(error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logValue(label string, value interface{}) {
|
|
||||||
if label == "" {
|
|
||||||
if hasStringOrError(value) {
|
|
||||||
c.logf("... %#v (%q)", value, value)
|
|
||||||
} else {
|
|
||||||
c.logf("... %#v", value)
|
|
||||||
}
|
|
||||||
} else if value == nil {
|
|
||||||
c.logf("... %s = nil", label)
|
|
||||||
} else {
|
|
||||||
if hasStringOrError(value) {
|
|
||||||
fv := fmt.Sprintf("%#v", value)
|
|
||||||
qv := fmt.Sprintf("%q", value)
|
|
||||||
if fv != qv {
|
|
||||||
c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s, ok := value.(string); ok && isMultiLine(s) {
|
|
||||||
c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value))
|
|
||||||
c.logMultiLine(s)
|
|
||||||
} else {
|
|
||||||
c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logMultiLine(s string) {
|
|
||||||
b := make([]byte, 0, len(s)*2)
|
|
||||||
i := 0
|
|
||||||
n := len(s)
|
|
||||||
for i < n {
|
|
||||||
j := i + 1
|
|
||||||
for j < n && s[j-1] != '\n' {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
b = append(b, "... "...)
|
|
||||||
b = strconv.AppendQuote(b, s[i:j])
|
|
||||||
if j < n {
|
|
||||||
b = append(b, " +"...)
|
|
||||||
}
|
|
||||||
b = append(b, '\n')
|
|
||||||
i = j
|
|
||||||
}
|
|
||||||
c.writeLog(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMultiLine(s string) bool {
|
|
||||||
for i := 0; i+1 < len(s); i++ {
|
|
||||||
if s[i] == '\n' {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logString(issue string) {
|
|
||||||
c.log("... ", issue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logCaller(skip int) {
|
|
||||||
// This is a bit heavier than it ought to be.
|
|
||||||
skip += 1 // Our own frame.
|
|
||||||
pc, callerFile, callerLine, ok := runtime.Caller(skip)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var testFile string
|
|
||||||
var testLine int
|
|
||||||
testFunc := runtime.FuncForPC(c.method.PC())
|
|
||||||
if runtime.FuncForPC(pc) != testFunc {
|
|
||||||
for {
|
|
||||||
skip += 1
|
|
||||||
if pc, file, line, ok := runtime.Caller(skip); ok {
|
|
||||||
// Note that the test line may be different on
|
|
||||||
// distinct calls for the same test. Showing
|
|
||||||
// the "internal" line is helpful when debugging.
|
|
||||||
if runtime.FuncForPC(pc) == testFunc {
|
|
||||||
testFile, testLine = file, line
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if testFile != "" && (testFile != callerFile || testLine != callerLine) {
|
|
||||||
c.logCode(testFile, testLine)
|
|
||||||
}
|
|
||||||
c.logCode(callerFile, callerLine)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logCode(path string, line int) {
|
|
||||||
c.logf("%s:%d:", nicePath(path), line)
|
|
||||||
code, err := printLine(path, line)
|
|
||||||
if code == "" {
|
|
||||||
code = "..." // XXX Open the file and take the raw line.
|
|
||||||
if err != nil {
|
|
||||||
code += err.Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.log(indent(code, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
var valueGo = filepath.Join("reflect", "value.go")
|
|
||||||
|
|
||||||
func (c *C) logPanic(skip int, value interface{}) {
|
|
||||||
skip += 1 // Our own frame.
|
|
||||||
initialSkip := skip
|
|
||||||
for {
|
|
||||||
if pc, file, line, ok := runtime.Caller(skip); ok {
|
|
||||||
if skip == initialSkip {
|
|
||||||
c.logf("... Panic: %s (PC=0x%X)\n", value, pc)
|
|
||||||
}
|
|
||||||
name := niceFuncName(pc)
|
|
||||||
path := nicePath(file)
|
|
||||||
if name == "Value.call" && strings.HasSuffix(path, valueGo) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
c.logf("%s:%d\n in %s", nicePath(file), line, name)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
skip += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logSoftPanic(issue string) {
|
|
||||||
c.log("... Panic: ", issue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) logArgPanic(method *methodType, expectedType string) {
|
|
||||||
c.logf("... Panic: %s argument should be %s",
|
|
||||||
niceFuncName(method.PC()), expectedType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Some simple formatting helpers.
|
|
||||||
|
|
||||||
var initWD, initWDErr = os.Getwd()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if initWDErr == nil {
|
|
||||||
initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nicePath(path string) string {
|
|
||||||
if initWDErr == nil {
|
|
||||||
if strings.HasPrefix(path, initWD) {
|
|
||||||
return path[len(initWD):]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
func niceFuncPath(pc uintptr) string {
|
|
||||||
function := runtime.FuncForPC(pc)
|
|
||||||
if function != nil {
|
|
||||||
filename, line := function.FileLine(pc)
|
|
||||||
return fmt.Sprintf("%s:%d", nicePath(filename), line)
|
|
||||||
}
|
|
||||||
return "<unknown path>"
|
|
||||||
}
|
|
||||||
|
|
||||||
func niceFuncName(pc uintptr) string {
|
|
||||||
function := runtime.FuncForPC(pc)
|
|
||||||
if function != nil {
|
|
||||||
name := path.Base(function.Name())
|
|
||||||
if i := strings.Index(name, "."); i > 0 {
|
|
||||||
name = name[i+1:]
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(name, "(*") {
|
|
||||||
if i := strings.Index(name, ")"); i > 0 {
|
|
||||||
name = name[2:i] + name[i+1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i := strings.LastIndex(name, ".*"); i != -1 {
|
|
||||||
name = name[:i] + "." + name[i+2:]
|
|
||||||
}
|
|
||||||
if i := strings.LastIndex(name, "·"); i != -1 {
|
|
||||||
name = name[:i] + "." + name[i+2:]
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
return "<unknown function>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Result tracker to aggregate call results.
|
|
||||||
|
|
||||||
type Result struct {
|
|
||||||
Succeeded int
|
|
||||||
Failed int
|
|
||||||
Skipped int
|
|
||||||
Panicked int
|
|
||||||
FixturePanicked int
|
|
||||||
ExpectedFailures int
|
|
||||||
Missed int // Not even tried to run, related to a panic in the fixture.
|
|
||||||
RunError error // Houston, we've got a problem.
|
|
||||||
}
|
|
||||||
|
|
||||||
type resultTracker struct {
|
|
||||||
result Result
|
|
||||||
_lastWasProblem bool
|
|
||||||
_waiting int
|
|
||||||
_missed int
|
|
||||||
_expectChan chan *C
|
|
||||||
_doneChan chan *C
|
|
||||||
_stopChan chan bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newResultTracker() *resultTracker {
|
|
||||||
return &resultTracker{_expectChan: make(chan *C), // Synchronous
|
|
||||||
_doneChan: make(chan *C, 32), // Asynchronous
|
|
||||||
_stopChan: make(chan bool)} // Synchronous
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tracker *resultTracker) start() {
|
|
||||||
go tracker._loopRoutine()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tracker *resultTracker) waitAndStop() {
|
|
||||||
<-tracker._stopChan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tracker *resultTracker) expectCall(c *C) {
|
|
||||||
tracker._expectChan <- c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tracker *resultTracker) callDone(c *C) {
|
|
||||||
tracker._doneChan <- c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tracker *resultTracker) _loopRoutine() {
|
|
||||||
for {
|
|
||||||
var c *C
|
|
||||||
if tracker._waiting > 0 {
|
|
||||||
// Calls still running. Can't stop.
|
|
||||||
select {
|
|
||||||
// XXX Reindent this (not now to make diff clear)
|
|
||||||
case c = <-tracker._expectChan:
|
|
||||||
tracker._waiting += 1
|
|
||||||
case c = <-tracker._doneChan:
|
|
||||||
tracker._waiting -= 1
|
|
||||||
switch c.status {
|
|
||||||
case succeededSt:
|
|
||||||
if c.kind == testKd {
|
|
||||||
if c.mustFail {
|
|
||||||
tracker.result.ExpectedFailures++
|
|
||||||
} else {
|
|
||||||
tracker.result.Succeeded++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case failedSt:
|
|
||||||
tracker.result.Failed++
|
|
||||||
case panickedSt:
|
|
||||||
if c.kind == fixtureKd {
|
|
||||||
tracker.result.FixturePanicked++
|
|
||||||
} else {
|
|
||||||
tracker.result.Panicked++
|
|
||||||
}
|
|
||||||
case fixturePanickedSt:
|
|
||||||
// Track it as missed, since the panic
|
|
||||||
// was on the fixture, not on the test.
|
|
||||||
tracker.result.Missed++
|
|
||||||
case missedSt:
|
|
||||||
tracker.result.Missed++
|
|
||||||
case skippedSt:
|
|
||||||
if c.kind == testKd {
|
|
||||||
tracker.result.Skipped++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No calls. Can stop, but no done calls here.
|
|
||||||
select {
|
|
||||||
case tracker._stopChan <- true:
|
|
||||||
return
|
|
||||||
case c = <-tracker._expectChan:
|
|
||||||
tracker._waiting += 1
|
|
||||||
case c = <-tracker._doneChan:
|
|
||||||
panic("Tracker got an unexpected done call.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// The underlying suite runner.
|
|
||||||
|
|
||||||
type suiteRunner struct {
|
|
||||||
suite interface{}
|
|
||||||
setUpSuite, tearDownSuite *methodType
|
|
||||||
setUpTest, tearDownTest *methodType
|
|
||||||
tests []*methodType
|
|
||||||
tracker *resultTracker
|
|
||||||
tempDir *tempDir
|
|
||||||
output *outputWriter
|
|
||||||
reportedProblemLast bool
|
|
||||||
benchTime time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type RunConf struct {
|
|
||||||
Output io.Writer
|
|
||||||
Stream bool
|
|
||||||
Verbose bool
|
|
||||||
Filter string
|
|
||||||
Benchmark bool
|
|
||||||
BenchmarkTime time.Duration // Defaults to 1 second
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new suiteRunner able to run all methods in the given suite.
|
|
||||||
func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner {
|
|
||||||
var conf RunConf
|
|
||||||
if runConf != nil {
|
|
||||||
conf = *runConf
|
|
||||||
}
|
|
||||||
if conf.Output == nil {
|
|
||||||
conf.Output = os.Stdout
|
|
||||||
}
|
|
||||||
if conf.Benchmark {
|
|
||||||
conf.Verbose = true
|
|
||||||
}
|
|
||||||
|
|
||||||
suiteType := reflect.TypeOf(suite)
|
|
||||||
suiteNumMethods := suiteType.NumMethod()
|
|
||||||
suiteValue := reflect.ValueOf(suite)
|
|
||||||
|
|
||||||
runner := &suiteRunner{
|
|
||||||
suite: suite,
|
|
||||||
output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose),
|
|
||||||
tracker: newResultTracker(),
|
|
||||||
benchTime: conf.BenchmarkTime,
|
|
||||||
}
|
|
||||||
runner.tests = make([]*methodType, 0, suiteNumMethods)
|
|
||||||
runner.tempDir = new(tempDir)
|
|
||||||
if runner.benchTime == 0 {
|
|
||||||
runner.benchTime = 1 * time.Second
|
|
||||||
}
|
|
||||||
|
|
||||||
var filterRegexp *regexp.Regexp
|
|
||||||
if conf.Filter != "" {
|
|
||||||
if regexp, err := regexp.Compile(conf.Filter); err != nil {
|
|
||||||
msg := "Bad filter expression: " + err.Error()
|
|
||||||
runner.tracker.result.RunError = errors.New(msg)
|
|
||||||
return runner
|
|
||||||
} else {
|
|
||||||
filterRegexp = regexp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i != suiteNumMethods; i++ {
|
|
||||||
method := newMethod(suiteValue, i)
|
|
||||||
switch method.Info.Name {
|
|
||||||
case "SetUpSuite":
|
|
||||||
runner.setUpSuite = method
|
|
||||||
case "TearDownSuite":
|
|
||||||
runner.tearDownSuite = method
|
|
||||||
case "SetUpTest":
|
|
||||||
runner.setUpTest = method
|
|
||||||
case "TearDownTest":
|
|
||||||
runner.tearDownTest = method
|
|
||||||
default:
|
|
||||||
prefix := "Test"
|
|
||||||
if conf.Benchmark {
|
|
||||||
prefix = "Benchmark"
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(method.Info.Name, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if filterRegexp == nil || method.matches(filterRegexp) {
|
|
||||||
runner.tests = append(runner.tests, method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return runner
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run all methods in the given suite.
|
|
||||||
func (runner *suiteRunner) run() *Result {
|
|
||||||
if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
|
|
||||||
runner.tracker.start()
|
|
||||||
if runner.checkFixtureArgs() {
|
|
||||||
c := runner.runFixture(runner.setUpSuite, nil)
|
|
||||||
if c == nil || c.status == succeededSt {
|
|
||||||
for i := 0; i != len(runner.tests); i++ {
|
|
||||||
c := runner.runTest(runner.tests[i])
|
|
||||||
if c.status == fixturePanickedSt {
|
|
||||||
runner.skipTests(missedSt, runner.tests[i+1:])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if c != nil && c.status == skippedSt {
|
|
||||||
runner.skipTests(skippedSt, runner.tests)
|
|
||||||
} else {
|
|
||||||
runner.skipTests(missedSt, runner.tests)
|
|
||||||
}
|
|
||||||
runner.runFixture(runner.tearDownSuite, nil)
|
|
||||||
} else {
|
|
||||||
runner.skipTests(missedSt, runner.tests)
|
|
||||||
}
|
|
||||||
runner.tracker.waitAndStop()
|
|
||||||
runner.tempDir.removeAll()
|
|
||||||
}
|
|
||||||
return &runner.tracker.result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a call object with the given suite method, and fork a
|
|
||||||
// goroutine with the provided dispatcher for running it.
|
|
||||||
func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
|
|
||||||
var logw io.Writer
|
|
||||||
if runner.output.Stream {
|
|
||||||
logw = runner.output
|
|
||||||
}
|
|
||||||
if logb == nil {
|
|
||||||
logb = new(logger)
|
|
||||||
}
|
|
||||||
c := &C{
|
|
||||||
method: method,
|
|
||||||
kind: kind,
|
|
||||||
logb: logb,
|
|
||||||
logw: logw,
|
|
||||||
tempDir: runner.tempDir,
|
|
||||||
done: make(chan *C, 1),
|
|
||||||
timer: timer{benchTime: runner.benchTime},
|
|
||||||
}
|
|
||||||
runner.tracker.expectCall(c)
|
|
||||||
go (func() {
|
|
||||||
runner.reportCallStarted(c)
|
|
||||||
defer runner.callDone(c)
|
|
||||||
dispatcher(c)
|
|
||||||
})()
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same as forkCall(), but wait for call to finish before returning.
|
|
||||||
func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
|
|
||||||
c := runner.forkCall(method, kind, logb, dispatcher)
|
|
||||||
<-c.done
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a finished call. If there were any panics, update the call status
|
|
||||||
// accordingly. Then, mark the call as done and report to the tracker.
|
|
||||||
func (runner *suiteRunner) callDone(c *C) {
|
|
||||||
value := recover()
|
|
||||||
if value != nil {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case *fixturePanic:
|
|
||||||
if v.status == skippedSt {
|
|
||||||
c.status = skippedSt
|
|
||||||
} else {
|
|
||||||
c.logSoftPanic("Fixture has panicked (see related PANIC)")
|
|
||||||
c.status = fixturePanickedSt
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
c.logPanic(1, value)
|
|
||||||
c.status = panickedSt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.mustFail {
|
|
||||||
switch c.status {
|
|
||||||
case failedSt:
|
|
||||||
c.status = succeededSt
|
|
||||||
case succeededSt:
|
|
||||||
c.status = failedSt
|
|
||||||
c.logString("Error: Test succeeded, but was expected to fail")
|
|
||||||
c.logString("Reason: " + c.reason)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runner.reportCallDone(c)
|
|
||||||
c.done <- c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runs a fixture call synchronously. The fixture will still be run in a
|
|
||||||
// goroutine like all suite methods, but this method will not return
|
|
||||||
// while the fixture goroutine is not done, because the fixture must be
|
|
||||||
// run in a desired order.
|
|
||||||
func (runner *suiteRunner) runFixture(method *methodType, logb *logger) *C {
|
|
||||||
if method != nil {
|
|
||||||
c := runner.runFunc(method, fixtureKd, logb, func(c *C) {
|
|
||||||
c.ResetTimer()
|
|
||||||
c.StartTimer()
|
|
||||||
defer c.StopTimer()
|
|
||||||
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
|
|
||||||
})
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the fixture method with runFixture(), but panic with a fixturePanic{}
|
|
||||||
// in case the fixture method panics. This makes it easier to track the
|
|
||||||
// fixture panic together with other call panics within forkTest().
|
|
||||||
func (runner *suiteRunner) runFixtureWithPanic(method *methodType, logb *logger, skipped *bool) *C {
|
|
||||||
if skipped != nil && *skipped {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
c := runner.runFixture(method, logb)
|
|
||||||
if c != nil && c.status != succeededSt {
|
|
||||||
if skipped != nil {
|
|
||||||
*skipped = c.status == skippedSt
|
|
||||||
}
|
|
||||||
panic(&fixturePanic{c.status, method})
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
type fixturePanic struct {
|
|
||||||
status funcStatus
|
|
||||||
method *methodType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the suite test method, together with the test-specific fixture,
|
|
||||||
// asynchronously.
|
|
||||||
func (runner *suiteRunner) forkTest(method *methodType) *C {
|
|
||||||
return runner.forkCall(method, testKd, nil, func(c *C) {
|
|
||||||
var skipped bool
|
|
||||||
defer runner.runFixtureWithPanic(runner.tearDownTest, nil, &skipped)
|
|
||||||
defer c.StopTimer()
|
|
||||||
benchN := 1
|
|
||||||
for {
|
|
||||||
runner.runFixtureWithPanic(runner.setUpTest, c.logb, &skipped)
|
|
||||||
mt := c.method.Type()
|
|
||||||
if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
|
|
||||||
// Rather than a plain panic, provide a more helpful message when
|
|
||||||
// the argument type is incorrect.
|
|
||||||
c.status = panickedSt
|
|
||||||
c.logArgPanic(c.method, "*gocheck.C")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(c.method.Info.Name, "Test") {
|
|
||||||
c.ResetTimer()
|
|
||||||
c.StartTimer()
|
|
||||||
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
|
|
||||||
panic("unexpected method prefix: " + c.method.Info.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.GC()
|
|
||||||
c.N = benchN
|
|
||||||
c.ResetTimer()
|
|
||||||
c.StartTimer()
|
|
||||||
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
|
|
||||||
c.StopTimer()
|
|
||||||
if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
perOpN := int(1e9)
|
|
||||||
if c.nsPerOp() != 0 {
|
|
||||||
perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logic taken from the stock testing package:
|
|
||||||
// - Run more iterations than we think we'll need for a second (1.5x).
|
|
||||||
// - Don't grow too fast in case we had timing errors previously.
|
|
||||||
// - Be sure to run at least one more than last time.
|
|
||||||
benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
|
|
||||||
benchN = roundUp(benchN)
|
|
||||||
|
|
||||||
skipped = true // Don't run the deferred one if this panics.
|
|
||||||
runner.runFixtureWithPanic(runner.tearDownTest, nil, nil)
|
|
||||||
skipped = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same as forkTest(), but wait for the test to finish before returning.
|
|
||||||
func (runner *suiteRunner) runTest(method *methodType) *C {
|
|
||||||
c := runner.forkTest(method)
|
|
||||||
<-c.done
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to mark tests as skipped or missed. A bit heavy for what
|
|
||||||
// it does, but it enables homogeneous handling of tracking, including
|
|
||||||
// nice verbose output.
|
|
||||||
func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
|
|
||||||
for _, method := range methods {
|
|
||||||
runner.runFunc(method, testKd, nil, func(c *C) {
|
|
||||||
c.status = status
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if the fixture arguments are *gocheck.C. In case of errors,
|
|
||||||
// log the error as a panic in the fixture method call, and return false.
|
|
||||||
func (runner *suiteRunner) checkFixtureArgs() bool {
|
|
||||||
succeeded := true
|
|
||||||
argType := reflect.TypeOf(&C{})
|
|
||||||
for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest} {
|
|
||||||
if method != nil {
|
|
||||||
mt := method.Type()
|
|
||||||
if mt.NumIn() != 1 || mt.In(0) != argType {
|
|
||||||
succeeded = false
|
|
||||||
runner.runFunc(method, fixtureKd, nil, func(c *C) {
|
|
||||||
c.logArgPanic(method, "*gocheck.C")
|
|
||||||
c.status = panickedSt
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return succeeded
|
|
||||||
}
|
|
||||||
|
|
||||||
func (runner *suiteRunner) reportCallStarted(c *C) {
|
|
||||||
runner.output.WriteCallStarted("START", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (runner *suiteRunner) reportCallDone(c *C) {
|
|
||||||
runner.tracker.callDone(c)
|
|
||||||
switch c.status {
|
|
||||||
case succeededSt:
|
|
||||||
if c.mustFail {
|
|
||||||
runner.output.WriteCallSuccess("FAIL EXPECTED", c)
|
|
||||||
} else {
|
|
||||||
runner.output.WriteCallSuccess("PASS", c)
|
|
||||||
}
|
|
||||||
case skippedSt:
|
|
||||||
runner.output.WriteCallSuccess("SKIP", c)
|
|
||||||
case failedSt:
|
|
||||||
runner.output.WriteCallProblem("FAIL", c)
|
|
||||||
case panickedSt:
|
|
||||||
runner.output.WriteCallProblem("PANIC", c)
|
|
||||||
case fixturePanickedSt:
|
|
||||||
// That's a testKd call reporting that its fixture
|
|
||||||
// has panicked. The fixture call which caused the
|
|
||||||
// panic itself was tracked above. We'll report to
|
|
||||||
// aid debugging.
|
|
||||||
runner.output.WriteCallProblem("PANIC", c)
|
|
||||||
case missedSt:
|
|
||||||
runner.output.WriteCallSuccess("MISS", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Output writer manages atomic output writing according to settings.
|
|
||||||
|
|
||||||
type outputWriter struct {
|
|
||||||
m sync.Mutex
|
|
||||||
writer io.Writer
|
|
||||||
wroteCallProblemLast bool
|
|
||||||
Stream bool
|
|
||||||
Verbose bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter {
|
|
||||||
return &outputWriter{writer: writer, Stream: stream, Verbose: verbose}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ow *outputWriter) Write(content []byte) (n int, err error) {
|
|
||||||
ow.m.Lock()
|
|
||||||
n, err = ow.writer.Write(content)
|
|
||||||
ow.m.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ow *outputWriter) WriteCallStarted(label string, c *C) {
|
|
||||||
if ow.Stream {
|
|
||||||
header := renderCallHeader(label, c, "", "\n")
|
|
||||||
ow.m.Lock()
|
|
||||||
ow.writer.Write([]byte(header))
|
|
||||||
ow.m.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ow *outputWriter) WriteCallProblem(label string, c *C) {
|
|
||||||
var prefix string
|
|
||||||
if !ow.Stream {
|
|
||||||
prefix = "\n-----------------------------------" +
|
|
||||||
"-----------------------------------\n"
|
|
||||||
}
|
|
||||||
header := renderCallHeader(label, c, prefix, "\n\n")
|
|
||||||
ow.m.Lock()
|
|
||||||
ow.wroteCallProblemLast = true
|
|
||||||
ow.writer.Write([]byte(header))
|
|
||||||
if !ow.Stream {
|
|
||||||
c.logb.WriteTo(ow.writer)
|
|
||||||
}
|
|
||||||
ow.m.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
|
|
||||||
if ow.Stream || (ow.Verbose && c.kind == testKd) {
|
|
||||||
// TODO Use a buffer here.
|
|
||||||
var suffix string
|
|
||||||
if c.reason != "" {
|
|
||||||
suffix = " (" + c.reason + ")"
|
|
||||||
}
|
|
||||||
if c.status == succeededSt {
|
|
||||||
suffix += "\t" + c.timerString()
|
|
||||||
}
|
|
||||||
suffix += "\n"
|
|
||||||
if ow.Stream {
|
|
||||||
suffix += "\n"
|
|
||||||
}
|
|
||||||
header := renderCallHeader(label, c, "", suffix)
|
|
||||||
ow.m.Lock()
|
|
||||||
// Resist temptation of using line as prefix above due to race.
|
|
||||||
if !ow.Stream && ow.wroteCallProblemLast {
|
|
||||||
header = "\n-----------------------------------" +
|
|
||||||
"-----------------------------------\n" +
|
|
||||||
header
|
|
||||||
}
|
|
||||||
ow.wroteCallProblemLast = false
|
|
||||||
ow.writer.Write([]byte(header))
|
|
||||||
ow.m.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderCallHeader(label string, c *C, prefix, suffix string) string {
|
|
||||||
pc := c.method.PC()
|
|
||||||
return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
|
|
||||||
niceFuncName(pc), suffix)
|
|
||||||
}
|
|
196
Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go
generated
vendored
196
Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go
generated
vendored
@ -1,196 +0,0 @@
|
|||||||
// This file contains just a few generic helpers which are used by the
|
|
||||||
// other test files.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"launchpad.net/gocheck"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// We count the number of suites run at least to get a vague hint that the
|
|
||||||
// test suite is behaving as it should. Otherwise a bug introduced at the
|
|
||||||
// very core of the system could go unperceived.
|
|
||||||
const suitesRunExpected = 8
|
|
||||||
|
|
||||||
var suitesRun int = 0
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
gocheck.TestingT(t)
|
|
||||||
if suitesRun != suitesRunExpected && flag.Lookup("gocheck.f").Value.String() == "" {
|
|
||||||
critical(fmt.Sprintf("Expected %d suites to run rather than %d",
|
|
||||||
suitesRunExpected, suitesRun))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper functions.
|
|
||||||
|
|
||||||
// Break down badly. This is used in test cases which can't yet assume
|
|
||||||
// that the fundamental bits are working.
|
|
||||||
func critical(error string) {
|
|
||||||
fmt.Fprintln(os.Stderr, "CRITICAL: "+error)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the file line where it's called.
|
|
||||||
func getMyLine() int {
|
|
||||||
if _, _, line, ok := runtime.Caller(1); ok {
|
|
||||||
return line
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper type implementing a basic io.Writer for testing output.
|
|
||||||
|
|
||||||
// Type implementing the io.Writer interface for analyzing output.
|
|
||||||
type String struct {
|
|
||||||
value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// The only function required by the io.Writer interface. Will append
|
|
||||||
// written data to the String.value string.
|
|
||||||
func (s *String) Write(p []byte) (n int, err error) {
|
|
||||||
s.value += string(p)
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trivial wrapper to test errors happening on a different file
|
|
||||||
// than the test itself.
|
|
||||||
func checkEqualWrapper(c *gocheck.C, obtained, expected interface{}) (result bool, line int) {
|
|
||||||
return c.Check(obtained, gocheck.Equals, expected), getMyLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper suite for testing basic fail behavior.
|
|
||||||
|
|
||||||
type FailHelper struct {
|
|
||||||
testLine int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FailHelper) TestLogAndFail(c *gocheck.C) {
|
|
||||||
s.testLine = getMyLine() - 1
|
|
||||||
c.Log("Expected failure!")
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper suite for testing basic success behavior.
|
|
||||||
|
|
||||||
type SuccessHelper struct{}
|
|
||||||
|
|
||||||
func (s *SuccessHelper) TestLogAndSucceed(c *gocheck.C) {
|
|
||||||
c.Log("Expected success!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper suite for testing ordering and behavior of fixture.
|
|
||||||
|
|
||||||
type FixtureHelper struct {
|
|
||||||
calls []string
|
|
||||||
panicOn string
|
|
||||||
skip bool
|
|
||||||
skipOnN int
|
|
||||||
sleepOn string
|
|
||||||
sleep time.Duration
|
|
||||||
bytes int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) trace(name string, c *gocheck.C) {
|
|
||||||
s.calls = append(s.calls, name)
|
|
||||||
if name == s.panicOn {
|
|
||||||
panic(name)
|
|
||||||
}
|
|
||||||
if s.sleep > 0 && s.sleepOn == name {
|
|
||||||
time.Sleep(s.sleep)
|
|
||||||
}
|
|
||||||
if s.skip && s.skipOnN == len(s.calls)-1 {
|
|
||||||
c.Skip("skipOnN == n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) SetUpSuite(c *gocheck.C) {
|
|
||||||
s.trace("SetUpSuite", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) TearDownSuite(c *gocheck.C) {
|
|
||||||
s.trace("TearDownSuite", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) SetUpTest(c *gocheck.C) {
|
|
||||||
s.trace("SetUpTest", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) TearDownTest(c *gocheck.C) {
|
|
||||||
s.trace("TearDownTest", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) Test1(c *gocheck.C) {
|
|
||||||
s.trace("Test1", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) Test2(c *gocheck.C) {
|
|
||||||
s.trace("Test2", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) Benchmark1(c *gocheck.C) {
|
|
||||||
s.trace("Benchmark1", c)
|
|
||||||
for i := 0; i < c.N; i++ {
|
|
||||||
time.Sleep(s.sleep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FixtureHelper) Benchmark2(c *gocheck.C) {
|
|
||||||
s.trace("Benchmark2", c)
|
|
||||||
c.SetBytes(1024)
|
|
||||||
for i := 0; i < c.N; i++ {
|
|
||||||
time.Sleep(s.sleep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Helper which checks the state of the test and ensures that it matches
|
|
||||||
// the given expectations. Depends on c.Errorf() working, so shouldn't
|
|
||||||
// be used to test this one function.
|
|
||||||
|
|
||||||
type expectedState struct {
|
|
||||||
name string
|
|
||||||
result interface{}
|
|
||||||
failed bool
|
|
||||||
log string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the state of the test. Note that since this also verifies if
|
|
||||||
// the test is supposed to be in a failed state, no other checks should
|
|
||||||
// be done in addition to what is being tested.
|
|
||||||
func checkState(c *gocheck.C, result interface{}, expected *expectedState) {
|
|
||||||
failed := c.Failed()
|
|
||||||
c.Succeed()
|
|
||||||
log := c.GetTestLog()
|
|
||||||
matched, matchError := regexp.MatchString("^"+expected.log+"$", log)
|
|
||||||
if matchError != nil {
|
|
||||||
c.Errorf("Error in matching expression used in testing %s",
|
|
||||||
expected.name)
|
|
||||||
} else if !matched {
|
|
||||||
c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------",
|
|
||||||
expected.name, log, expected.log)
|
|
||||||
}
|
|
||||||
if result != expected.result {
|
|
||||||
c.Errorf("%s returned %#v rather than %#v",
|
|
||||||
expected.name, result, expected.result)
|
|
||||||
}
|
|
||||||
if failed != expected.failed {
|
|
||||||
if failed {
|
|
||||||
c.Errorf("%s has failed when it shouldn't", expected.name)
|
|
||||||
} else {
|
|
||||||
c.Errorf("%s has not failed when it should", expected.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
221
Godeps/_workspace/src/github.com/motain/gocheck/helpers.go
generated
vendored
221
Godeps/_workspace/src/github.com/motain/gocheck/helpers.go
generated
vendored
@ -1,221 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Basic succeeding/failing logic.
|
|
||||||
|
|
||||||
// Return true if the currently running test has already failed.
|
|
||||||
func (c *C) Failed() bool {
|
|
||||||
return c.status == failedSt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the currently running test as failed. Something ought to have been
|
|
||||||
// previously logged so that the developer knows what went wrong. The higher
|
|
||||||
// level helper functions will fail the test and do the logging properly.
|
|
||||||
func (c *C) Fail() {
|
|
||||||
c.status = failedSt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the currently running test as failed, and stop running the test.
|
|
||||||
// Something ought to have been previously logged so that the developer
|
|
||||||
// knows what went wrong. The higher level helper functions will fail the
|
|
||||||
// test and do the logging properly.
|
|
||||||
func (c *C) FailNow() {
|
|
||||||
c.Fail()
|
|
||||||
c.stopNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the currently running test as succeeded, undoing any previous
|
|
||||||
// failures.
|
|
||||||
func (c *C) Succeed() {
|
|
||||||
c.status = succeededSt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the currently running test as succeeded, undoing any previous
|
|
||||||
// failures, and stop running the test.
|
|
||||||
func (c *C) SucceedNow() {
|
|
||||||
c.Succeed()
|
|
||||||
c.stopNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expect the currently running test to fail, for the given reason. If the
|
|
||||||
// test does not fail, an error will be reported to raise the attention to
|
|
||||||
// this fact. The reason string is just a summary of why the given test is
|
|
||||||
// supposed to fail. This method is useful to temporarily disable tests
|
|
||||||
// which cover well known problems until a better time to fix the problem
|
|
||||||
// is found, without forgetting about the fact that a failure still exists.
|
|
||||||
func (c *C) ExpectFailure(reason string) {
|
|
||||||
if reason == "" {
|
|
||||||
panic("Missing reason why the test is expected to fail")
|
|
||||||
}
|
|
||||||
c.mustFail = true
|
|
||||||
c.reason = reason
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the running test, for the given reason. If used within SetUpTest,
|
|
||||||
// the individual test being set up will be skipped, and in SetUpSuite it
|
|
||||||
// will cause the whole suite to be skipped.
|
|
||||||
func (c *C) Skip(reason string) {
|
|
||||||
if reason == "" {
|
|
||||||
panic("Missing reason why the test is being skipped")
|
|
||||||
}
|
|
||||||
c.reason = reason
|
|
||||||
c.status = skippedSt
|
|
||||||
c.stopNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Basic logging.
|
|
||||||
|
|
||||||
// Return the current test error output.
|
|
||||||
func (c *C) GetTestLog() string {
|
|
||||||
return c.logb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log some information into the test error output. The provided arguments
|
|
||||||
// will be assembled together into a string using fmt.Sprint().
|
|
||||||
func (c *C) Log(args ...interface{}) {
|
|
||||||
c.log(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log some information into the test error output. The provided arguments
|
|
||||||
// will be assembled together into a string using fmt.Sprintf().
|
|
||||||
func (c *C) Logf(format string, args ...interface{}) {
|
|
||||||
c.logf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output enables *C to be used as a logger in functions that require only
|
|
||||||
// the minimum interface of *log.Logger.
|
|
||||||
func (c *C) Output(calldepth int, s string) error {
|
|
||||||
ns := time.Now().Sub(time.Time{}).Nanoseconds()
|
|
||||||
t := float64(ns%100e9) / 1e9
|
|
||||||
c.Logf("[LOG] %.05f %s", t, s)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log an error into the test error output, and mark the test as failed.
|
|
||||||
// The provided arguments will be assembled together into a string using
|
|
||||||
// fmt.Sprint().
|
|
||||||
func (c *C) Error(args ...interface{}) {
|
|
||||||
c.logCaller(1)
|
|
||||||
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
|
|
||||||
c.logNewLine()
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log an error into the test error output, and mark the test as failed.
|
|
||||||
// The provided arguments will be assembled together into a string using
|
|
||||||
// fmt.Sprintf().
|
|
||||||
func (c *C) Errorf(format string, args ...interface{}) {
|
|
||||||
c.logCaller(1)
|
|
||||||
c.logString(fmt.Sprintf("Error: "+format, args...))
|
|
||||||
c.logNewLine()
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log an error into the test error output, mark the test as failed, and
|
|
||||||
// stop the test execution. The provided arguments will be assembled
|
|
||||||
// together into a string using fmt.Sprint().
|
|
||||||
func (c *C) Fatal(args ...interface{}) {
|
|
||||||
c.logCaller(1)
|
|
||||||
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
|
|
||||||
c.logNewLine()
|
|
||||||
c.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log an error into the test error output, mark the test as failed, and
|
|
||||||
// stop the test execution. The provided arguments will be assembled
|
|
||||||
// together into a string using fmt.Sprintf().
|
|
||||||
func (c *C) Fatalf(format string, args ...interface{}) {
|
|
||||||
c.logCaller(1)
|
|
||||||
c.logString(fmt.Sprint("Error: ", fmt.Sprintf(format, args...)))
|
|
||||||
c.logNewLine()
|
|
||||||
c.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Generic checks and assertions based on checkers.
|
|
||||||
|
|
||||||
// Verify if the first value matches with the expected value. What
|
|
||||||
// matching means is defined by the provided checker. In case they do not
|
|
||||||
// match, an error will be logged, the test will be marked as failed, and
|
|
||||||
// the test execution will continue. Some checkers may not need the expected
|
|
||||||
// argument (e.g. IsNil). In either case, any extra arguments provided to
|
|
||||||
// the function will be logged next to the reported problem when the
|
|
||||||
// matching fails. This is a handy way to provide problem-specific hints.
|
|
||||||
func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool {
|
|
||||||
return c.internalCheck("Check", obtained, checker, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the first value matches with the expected value. What
|
|
||||||
// matching means is defined by the provided checker. In case they do not
|
|
||||||
// match, an error will be logged, the test will be marked as failed, and
|
|
||||||
// the test execution will stop. Some checkers may not need the expected
|
|
||||||
// argument (e.g. IsNil). In either case, any extra arguments provided to
|
|
||||||
// the function will be logged next to the reported problem when the
|
|
||||||
// matching fails. This is a handy way to provide problem-specific hints.
|
|
||||||
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
|
|
||||||
if !c.internalCheck("Assert", obtained, checker, args...) {
|
|
||||||
c.stopNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C) internalCheck(funcName string, obtained interface{}, checker Checker, args ...interface{}) bool {
|
|
||||||
if checker == nil {
|
|
||||||
c.logCaller(2)
|
|
||||||
c.logString(fmt.Sprintf("%s(obtained, nil!?, ...):", funcName))
|
|
||||||
c.logString("Oops.. you've provided a nil checker!")
|
|
||||||
c.logNewLine()
|
|
||||||
c.Fail()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the last argument is a bug info, extract it out.
|
|
||||||
var comment CommentInterface
|
|
||||||
if len(args) > 0 {
|
|
||||||
if c, ok := args[len(args)-1].(CommentInterface); ok {
|
|
||||||
comment = c
|
|
||||||
args = args[:len(args)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := append([]interface{}{obtained}, args...)
|
|
||||||
info := checker.Info()
|
|
||||||
|
|
||||||
if len(params) != len(info.Params) {
|
|
||||||
names := append([]string{info.Params[0], info.Name}, info.Params[1:]...)
|
|
||||||
c.logCaller(2)
|
|
||||||
c.logString(fmt.Sprintf("%s(%s):", funcName, strings.Join(names, ", ")))
|
|
||||||
c.logString(fmt.Sprintf("Wrong number of parameters for %s: want %d, got %d", info.Name, len(names), len(params)+1))
|
|
||||||
c.logNewLine()
|
|
||||||
c.Fail()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy since it may be mutated by Check.
|
|
||||||
names := append([]string{}, info.Params...)
|
|
||||||
|
|
||||||
// Do the actual check.
|
|
||||||
result, error := checker.Check(params, names)
|
|
||||||
if !result || error != "" {
|
|
||||||
c.logCaller(2)
|
|
||||||
for i := 0; i != len(params); i++ {
|
|
||||||
c.logValue(names[i], params[i])
|
|
||||||
}
|
|
||||||
if comment != nil {
|
|
||||||
c.logString(comment.CheckCommentString())
|
|
||||||
}
|
|
||||||
if error != "" {
|
|
||||||
c.logString(error)
|
|
||||||
}
|
|
||||||
c.logNewLine()
|
|
||||||
c.Fail()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
491
Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go
generated
vendored
491
Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go
generated
vendored
@ -1,491 +0,0 @@
|
|||||||
// These tests verify the inner workings of the helper methods associated
|
|
||||||
// with gocheck.T.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"launchpad.net/gocheck"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var helpersS = gocheck.Suite(&HelpersS{})
|
|
||||||
|
|
||||||
type HelpersS struct{}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCountSuite(c *gocheck.C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Fake checker and bug info to verify the behavior of Assert() and Check().
|
|
||||||
|
|
||||||
type MyChecker struct {
|
|
||||||
info *gocheck.CheckerInfo
|
|
||||||
params []interface{}
|
|
||||||
names []string
|
|
||||||
result bool
|
|
||||||
error string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *MyChecker) Info() *gocheck.CheckerInfo {
|
|
||||||
if checker.info == nil {
|
|
||||||
return &gocheck.CheckerInfo{Name: "MyChecker", Params: []string{"myobtained", "myexpected"}}
|
|
||||||
}
|
|
||||||
return checker.info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (checker *MyChecker) Check(params []interface{}, names []string) (bool, string) {
|
|
||||||
rparams := checker.params
|
|
||||||
rnames := checker.names
|
|
||||||
checker.params = append([]interface{}{}, params...)
|
|
||||||
checker.names = append([]string{}, names...)
|
|
||||||
if rparams != nil {
|
|
||||||
copy(params, rparams)
|
|
||||||
}
|
|
||||||
if rnames != nil {
|
|
||||||
copy(names, rnames)
|
|
||||||
}
|
|
||||||
return checker.result, checker.error
|
|
||||||
}
|
|
||||||
|
|
||||||
type myCommentType string
|
|
||||||
|
|
||||||
func (c myCommentType) CheckCommentString() string {
|
|
||||||
return string(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func myComment(s string) myCommentType {
|
|
||||||
return myCommentType(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Ensure a real checker actually works fine.
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckerInterface(c *gocheck.C) {
|
|
||||||
testHelperSuccess(c, "Check(1, Equals, 1)", true, func() interface{} {
|
|
||||||
return c.Check(1, gocheck.Equals, 1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Tests for Check(), mostly the same as for Assert() following these.
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckSucceedWithExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true}
|
|
||||||
testHelperSuccess(c, "Check(1, checker, 2)", true, func() interface{} {
|
|
||||||
return c.Check(1, checker, 2)
|
|
||||||
})
|
|
||||||
if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
|
|
||||||
c.Fatalf("Bad params for check: %#v", checker.params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckSucceedWithoutExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
testHelperSuccess(c, "Check(1, checker)", true, func() interface{} {
|
|
||||||
return c.Check(1, checker)
|
|
||||||
})
|
|
||||||
if !reflect.DeepEqual(checker.params, []interface{}{1}) {
|
|
||||||
c.Fatalf("Bad params for check: %#v", checker.params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckFailWithExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckFailWithExpectedAndComment(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n" +
|
|
||||||
"\\.+ Hello world!\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, 2, myComment("Hello world!"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckFailWithExpectedAndStaticComment(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" // Nice leading comment\\.\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2\\) // Hello there\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
// Nice leading comment.
|
|
||||||
return c.Check(1, checker, 2) // Hello there
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckFailWithoutExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker\\)\n" +
|
|
||||||
"\\.+ myvalue int = 1\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckFailWithoutExpectedAndMessage(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
|
|
||||||
"\\.+ myvalue int = 1\n" +
|
|
||||||
"\\.+ Hello world!\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, msg)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, myComment("Hello world!"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckWithMissingExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker\\)\n" +
|
|
||||||
"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
|
|
||||||
"\\.+ Wrong number of parameters for MyChecker: " +
|
|
||||||
"want 3, got 2\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, !?)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckWithTooManyExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2, 3\\)\n" +
|
|
||||||
"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
|
|
||||||
"\\.+ Wrong number of parameters for MyChecker: " +
|
|
||||||
"want 3, got 4\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2, 3)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, 2, 3)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckWithError(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n" +
|
|
||||||
"\\.+ Some not so cool data provided!\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckWithNilChecker(c *gocheck.C) {
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, nil\\)\n" +
|
|
||||||
"\\.+ Check\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
|
|
||||||
"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
|
|
||||||
testHelperFailure(c, "Check(obtained, nil)", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, nil)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestCheckWithParamsAndNamesMutation(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, params: []interface{}{3, 4}, names: []string{"newobtained", "newexpected"}}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(1, checker, 2\\)\n" +
|
|
||||||
"\\.+ newobtained int = 3\n" +
|
|
||||||
"\\.+ newexpected int = 4\n\n"
|
|
||||||
testHelperFailure(c, "Check(1, checker, 2) with mutation", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check(1, checker, 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Tests for Assert(), mostly the same as for Check() above.
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertSucceedWithExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true}
|
|
||||||
testHelperSuccess(c, "Assert(1, checker, 2)", nil, func() interface{} {
|
|
||||||
c.Assert(1, checker, 2)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
|
|
||||||
c.Fatalf("Bad params for check: %#v", checker.params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertSucceedWithoutExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
testHelperSuccess(c, "Assert(1, checker)", nil, func() interface{} {
|
|
||||||
c.Assert(1, checker)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if !reflect.DeepEqual(checker.params, []interface{}{1}) {
|
|
||||||
c.Fatalf("Bad params for check: %#v", checker.params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertFailWithExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker, 2\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker, 2)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertFailWithExpectedAndMessage(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n" +
|
|
||||||
"\\.+ Hello world!\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker, 2, msg)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker, 2, myComment("Hello world!"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertFailWithoutExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker\\)\n" +
|
|
||||||
"\\.+ myvalue int = 1\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertFailWithoutExpectedAndMessage(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, info: &gocheck.CheckerInfo{Params: []string{"myvalue"}}}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
|
|
||||||
"\\.+ myvalue int = 1\n" +
|
|
||||||
"\\.+ Hello world!\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker, msg)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker, myComment("Hello world!"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertWithMissingExpected(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: true}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker\\)\n" +
|
|
||||||
"\\.+ Assert\\(myobtained, MyChecker, myexpected\\):\n" +
|
|
||||||
"\\.+ Wrong number of parameters for MyChecker: " +
|
|
||||||
"want 3, got 2\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker, !?)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertWithError(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, checker, 2\\)\n" +
|
|
||||||
"\\.+ myobtained int = 1\n" +
|
|
||||||
"\\.+ myexpected int = 2\n" +
|
|
||||||
"\\.+ Some not so cool data provided!\n\n"
|
|
||||||
testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, checker, 2)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestAssertWithNilChecker(c *gocheck.C) {
|
|
||||||
log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
|
|
||||||
" c\\.Assert\\(1, nil\\)\n" +
|
|
||||||
"\\.+ Assert\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
|
|
||||||
"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
|
|
||||||
testHelperFailure(c, "Assert(obtained, nil)", nil, true, log,
|
|
||||||
func() interface{} {
|
|
||||||
c.Assert(1, nil)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Ensure that values logged work properly in some interesting cases.
|
|
||||||
|
|
||||||
func (s *HelpersS) TestValueLoggingWithArrays(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(\\[\\]byte{1, 2}, checker, \\[\\]byte{1, 3}\\)\n" +
|
|
||||||
"\\.+ myobtained \\[\\]uint8 = \\[\\]byte{0x1, 0x2}\n" +
|
|
||||||
"\\.+ myexpected \\[\\]uint8 = \\[\\]byte{0x1, 0x3}\n\n"
|
|
||||||
testHelperFailure(c, "Check([]byte{1}, chk, []byte{3})", false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check([]byte{1, 2}, checker, []byte{1, 3})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestValueLoggingWithMultiLine(c *gocheck.C) {
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(\"a\\\\nb\\\\n\", checker, \"a\\\\nb\\\\nc\"\\)\n" +
|
|
||||||
"\\.+ myobtained string = \"\" \\+\n" +
|
|
||||||
"\\.+ \"a\\\\n\" \\+\n" +
|
|
||||||
"\\.+ \"b\\\\n\"\n" +
|
|
||||||
"\\.+ myexpected string = \"\" \\+\n" +
|
|
||||||
"\\.+ \"a\\\\n\" \\+\n" +
|
|
||||||
"\\.+ \"b\\\\n\" \\+\n" +
|
|
||||||
"\\.+ \"c\"\n\n"
|
|
||||||
testHelperFailure(c, `Check("a\nb\n", chk, "a\nb\nc")`, false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check("a\nb\n", checker, "a\nb\nc")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestValueLoggingWithMultiLineException(c *gocheck.C) {
|
|
||||||
// If the newline is at the end of the string, don't log as multi-line.
|
|
||||||
checker := &MyChecker{result: false}
|
|
||||||
log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
|
|
||||||
" return c\\.Check\\(\"a b\\\\n\", checker, \"a\\\\nb\"\\)\n" +
|
|
||||||
"\\.+ myobtained string = \"a b\\\\n\"\n" +
|
|
||||||
"\\.+ myexpected string = \"\" \\+\n" +
|
|
||||||
"\\.+ \"a\\\\n\" \\+\n" +
|
|
||||||
"\\.+ \"b\"\n\n"
|
|
||||||
testHelperFailure(c, `Check("a b\n", chk, "a\nb")`, false, false, log,
|
|
||||||
func() interface{} {
|
|
||||||
return c.Check("a b\n", checker, "a\nb")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// MakeDir() tests.
|
|
||||||
|
|
||||||
type MkDirHelper struct {
|
|
||||||
path1 string
|
|
||||||
path2 string
|
|
||||||
isDir1 bool
|
|
||||||
isDir2 bool
|
|
||||||
isDir3 bool
|
|
||||||
isDir4 bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MkDirHelper) SetUpSuite(c *gocheck.C) {
|
|
||||||
s.path1 = c.MkDir()
|
|
||||||
s.isDir1 = isDir(s.path1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MkDirHelper) Test(c *gocheck.C) {
|
|
||||||
s.path2 = c.MkDir()
|
|
||||||
s.isDir2 = isDir(s.path2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MkDirHelper) TearDownSuite(c *gocheck.C) {
|
|
||||||
s.isDir3 = isDir(s.path1)
|
|
||||||
s.isDir4 = isDir(s.path2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HelpersS) TestMkDir(c *gocheck.C) {
|
|
||||||
helper := MkDirHelper{}
|
|
||||||
output := String{}
|
|
||||||
gocheck.Run(&helper, &gocheck.RunConf{Output: &output})
|
|
||||||
c.Assert(output.value, gocheck.Equals, "")
|
|
||||||
c.Check(helper.isDir1, gocheck.Equals, true)
|
|
||||||
c.Check(helper.isDir2, gocheck.Equals, true)
|
|
||||||
c.Check(helper.isDir3, gocheck.Equals, true)
|
|
||||||
c.Check(helper.isDir4, gocheck.Equals, true)
|
|
||||||
c.Check(helper.path1, gocheck.Not(gocheck.Equals),
|
|
||||||
helper.path2)
|
|
||||||
c.Check(isDir(helper.path1), gocheck.Equals, false)
|
|
||||||
c.Check(isDir(helper.path2), gocheck.Equals, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isDir(path string) bool {
|
|
||||||
if stat, err := os.Stat(path); err == nil {
|
|
||||||
return stat.IsDir()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concurrent logging should not corrupt the underling buffer.
|
|
||||||
// Use go test -race to detect the race in this test.
|
|
||||||
func (s *HelpersS) TestConcurrentLogging(c *gocheck.C) {
|
|
||||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
|
|
||||||
var start, stop sync.WaitGroup
|
|
||||||
start.Add(1)
|
|
||||||
for i, n := 0, runtime.NumCPU()*2; i < n; i++ {
|
|
||||||
stop.Add(1)
|
|
||||||
go func(i int) {
|
|
||||||
start.Wait()
|
|
||||||
for j := 0; j < 30; j++ {
|
|
||||||
c.Logf("Worker %d: line %d", i, j)
|
|
||||||
}
|
|
||||||
stop.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
start.Done()
|
|
||||||
stop.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// A couple of helper functions to test helper functions. :-)
|
|
||||||
|
|
||||||
func testHelperSuccess(c *gocheck.C, name string, expectedResult interface{}, closure func() interface{}) {
|
|
||||||
var result interface{}
|
|
||||||
defer (func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
checkState(c, result,
|
|
||||||
&expectedState{
|
|
||||||
name: name,
|
|
||||||
result: expectedResult,
|
|
||||||
failed: false,
|
|
||||||
log: "",
|
|
||||||
})
|
|
||||||
})()
|
|
||||||
result = closure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHelperFailure(c *gocheck.C, name string, expectedResult interface{}, shouldStop bool, log string, closure func() interface{}) {
|
|
||||||
var result interface{}
|
|
||||||
defer (func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
checkState(c, result,
|
|
||||||
&expectedState{
|
|
||||||
name: name,
|
|
||||||
result: expectedResult,
|
|
||||||
failed: true,
|
|
||||||
log: log,
|
|
||||||
})
|
|
||||||
})()
|
|
||||||
result = closure()
|
|
||||||
if shouldStop {
|
|
||||||
c.Logf("%s didn't stop when it should", name)
|
|
||||||
}
|
|
||||||
}
|
|
168
Godeps/_workspace/src/github.com/motain/gocheck/printer.go
generated
vendored
168
Godeps/_workspace/src/github.com/motain/gocheck/printer.go
generated
vendored
@ -1,168 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/printer"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func indent(s, with string) (r string) {
|
|
||||||
eol := true
|
|
||||||
for i := 0; i != len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
switch {
|
|
||||||
case eol && c == '\n' || c == '\r':
|
|
||||||
case c == '\n' || c == '\r':
|
|
||||||
eol = true
|
|
||||||
case eol:
|
|
||||||
eol = false
|
|
||||||
s = s[:i] + with + s[i:]
|
|
||||||
i += len(with)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func printLine(filename string, line int) (string, error) {
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
file, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
fnode, err := parser.ParseFile(fset, filename, file, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}
|
|
||||||
lp := &linePrinter{fset: fset, fnode: fnode, line: line, config: config}
|
|
||||||
ast.Walk(lp, fnode)
|
|
||||||
result := lp.output.Bytes()
|
|
||||||
// Comments leave \n at the end.
|
|
||||||
n := len(result)
|
|
||||||
for n > 0 && result[n-1] == '\n' {
|
|
||||||
n--
|
|
||||||
}
|
|
||||||
return string(result[:n]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type linePrinter struct {
|
|
||||||
config *printer.Config
|
|
||||||
fset *token.FileSet
|
|
||||||
fnode *ast.File
|
|
||||||
line int
|
|
||||||
output bytes.Buffer
|
|
||||||
stmt ast.Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) emit() bool {
|
|
||||||
if lp.stmt != nil {
|
|
||||||
lp.trim(lp.stmt)
|
|
||||||
lp.printWithComments(lp.stmt)
|
|
||||||
lp.stmt = nil
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) printWithComments(n ast.Node) {
|
|
||||||
nfirst := lp.fset.Position(n.Pos()).Line
|
|
||||||
nlast := lp.fset.Position(n.End()).Line
|
|
||||||
for _, g := range lp.fnode.Comments {
|
|
||||||
cfirst := lp.fset.Position(g.Pos()).Line
|
|
||||||
clast := lp.fset.Position(g.End()).Line
|
|
||||||
if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column {
|
|
||||||
for _, c := range g.List {
|
|
||||||
lp.output.WriteString(c.Text)
|
|
||||||
lp.output.WriteByte('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash {
|
|
||||||
// The printer will not include the comment if it starts past
|
|
||||||
// the node itself. Trick it into printing by overlapping the
|
|
||||||
// slash with the end of the statement.
|
|
||||||
g.List[0].Slash = n.End() - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node := &printer.CommentedNode{n, lp.fnode.Comments}
|
|
||||||
lp.config.Fprint(&lp.output, lp.fset, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) {
|
|
||||||
if n == nil {
|
|
||||||
if lp.output.Len() == 0 {
|
|
||||||
lp.emit()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
first := lp.fset.Position(n.Pos()).Line
|
|
||||||
last := lp.fset.Position(n.End()).Line
|
|
||||||
if first <= lp.line && last >= lp.line {
|
|
||||||
// Print the innermost statement containing the line.
|
|
||||||
if stmt, ok := n.(ast.Stmt); ok {
|
|
||||||
if _, ok := n.(*ast.BlockStmt); !ok {
|
|
||||||
lp.stmt = stmt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if first == lp.line && lp.emit() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return lp
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) trim(n ast.Node) bool {
|
|
||||||
stmt, ok := n.(ast.Stmt)
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
line := lp.fset.Position(n.Pos()).Line
|
|
||||||
if line != lp.line {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
switch stmt := stmt.(type) {
|
|
||||||
case *ast.IfStmt:
|
|
||||||
stmt.Body = lp.trimBlock(stmt.Body)
|
|
||||||
case *ast.SwitchStmt:
|
|
||||||
stmt.Body = lp.trimBlock(stmt.Body)
|
|
||||||
case *ast.TypeSwitchStmt:
|
|
||||||
stmt.Body = lp.trimBlock(stmt.Body)
|
|
||||||
case *ast.CaseClause:
|
|
||||||
stmt.Body = lp.trimList(stmt.Body)
|
|
||||||
case *ast.CommClause:
|
|
||||||
stmt.Body = lp.trimList(stmt.Body)
|
|
||||||
case *ast.BlockStmt:
|
|
||||||
stmt.List = lp.trimList(stmt.List)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) trimBlock(stmt *ast.BlockStmt) *ast.BlockStmt {
|
|
||||||
if !lp.trim(stmt) {
|
|
||||||
return lp.emptyBlock(stmt)
|
|
||||||
}
|
|
||||||
stmt.Rbrace = stmt.Lbrace
|
|
||||||
return stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) trimList(stmts []ast.Stmt) []ast.Stmt {
|
|
||||||
for i := 0; i != len(stmts); i++ {
|
|
||||||
if !lp.trim(stmts[i]) {
|
|
||||||
stmts[i] = lp.emptyStmt(stmts[i])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stmts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) emptyStmt(n ast.Node) *ast.ExprStmt {
|
|
||||||
return &ast.ExprStmt{&ast.Ellipsis{n.Pos(), nil}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lp *linePrinter) emptyBlock(n ast.Node) *ast.BlockStmt {
|
|
||||||
p := n.Pos()
|
|
||||||
return &ast.BlockStmt{p, []ast.Stmt{lp.emptyStmt(n)}, p}
|
|
||||||
}
|
|
109
Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go
generated
vendored
109
Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go
generated
vendored
@ -1,109 +0,0 @@
|
|||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "launchpad.net/gocheck"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Suite(&PrinterS{})
|
|
||||||
|
|
||||||
type PrinterS struct{}
|
|
||||||
|
|
||||||
func (s *PrinterS) TestCountSuite(c *C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
var printTestFuncLine int
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
printTestFuncLine = getMyLine() + 3
|
|
||||||
}
|
|
||||||
|
|
||||||
func printTestFunc() {
|
|
||||||
println(1) // Comment1
|
|
||||||
if 2 == 2 { // Comment2
|
|
||||||
println(3) // Comment3
|
|
||||||
}
|
|
||||||
switch 5 {
|
|
||||||
case 6:
|
|
||||||
println(6) // Comment6
|
|
||||||
println(7)
|
|
||||||
}
|
|
||||||
switch interface{}(9).(type) { // Comment9
|
|
||||||
case int:
|
|
||||||
println(10)
|
|
||||||
println(11)
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-(chan bool)(nil):
|
|
||||||
println(14)
|
|
||||||
println(15)
|
|
||||||
default:
|
|
||||||
println(16)
|
|
||||||
println(17)
|
|
||||||
}
|
|
||||||
println(19,
|
|
||||||
20)
|
|
||||||
_ = func() {
|
|
||||||
println(21)
|
|
||||||
println(22)
|
|
||||||
}
|
|
||||||
println(24, func() {
|
|
||||||
println(25)
|
|
||||||
})
|
|
||||||
// Leading comment
|
|
||||||
// with multiple lines.
|
|
||||||
println(29) // Comment29
|
|
||||||
}
|
|
||||||
|
|
||||||
var printLineTests = []struct {
|
|
||||||
line int
|
|
||||||
output string
|
|
||||||
}{
|
|
||||||
{1, "println(1) // Comment1"},
|
|
||||||
{2, "if 2 == 2 { // Comment2\n ...\n}"},
|
|
||||||
{3, "println(3) // Comment3"},
|
|
||||||
{5, "switch 5 {\n...\n}"},
|
|
||||||
{6, "case 6:\n println(6) // Comment6\n ..."},
|
|
||||||
{7, "println(7)"},
|
|
||||||
{9, "switch interface{}(9).(type) { // Comment9\n...\n}"},
|
|
||||||
{10, "case int:\n println(10)\n ..."},
|
|
||||||
{14, "case <-(chan bool)(nil):\n println(14)\n ..."},
|
|
||||||
{15, "println(15)"},
|
|
||||||
{16, "default:\n println(16)\n ..."},
|
|
||||||
{17, "println(17)"},
|
|
||||||
{19, "println(19,\n 20)"},
|
|
||||||
{20, "println(19,\n 20)"},
|
|
||||||
{21, "_ = func() {\n println(21)\n println(22)\n}"},
|
|
||||||
{22, "println(22)"},
|
|
||||||
{24, "println(24, func() {\n println(25)\n})"},
|
|
||||||
{25, "println(25)"},
|
|
||||||
{26, "println(24, func() {\n println(25)\n})"},
|
|
||||||
{29, "// Leading comment\n// with multiple lines.\nprintln(29) // Comment29"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PrinterS) TestPrintLine(c *C) {
|
|
||||||
for _, test := range printLineTests {
|
|
||||||
output, err := PrintLine("printer_test.go", printTestFuncLine+test.line)
|
|
||||||
c.Assert(err, IsNil)
|
|
||||||
c.Assert(output, Equals, test.output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var indentTests = []struct {
|
|
||||||
in, out string
|
|
||||||
}{
|
|
||||||
{"", ""},
|
|
||||||
{"\n", "\n"},
|
|
||||||
{"a", ">>>a"},
|
|
||||||
{"a\n", ">>>a\n"},
|
|
||||||
{"a\nb", ">>>a\n>>>b"},
|
|
||||||
{" ", ">>> "},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PrinterS) TestIndent(c *C) {
|
|
||||||
for _, test := range indentTests {
|
|
||||||
out := Indent(test.in, ">>>")
|
|
||||||
c.Assert(out, Equals, test.out)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
152
Godeps/_workspace/src/github.com/motain/gocheck/run.go
generated
vendored
152
Godeps/_workspace/src/github.com/motain/gocheck/run.go
generated
vendored
@ -1,152 +0,0 @@
|
|||||||
package gocheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Test suite registry.
|
|
||||||
|
|
||||||
var allSuites []interface{}
|
|
||||||
|
|
||||||
// Register the given value as a test suite to be run. Any methods starting
|
|
||||||
// with the Test prefix in the given value will be considered as a test to
|
|
||||||
// be run.
|
|
||||||
func Suite(suite interface{}) interface{} {
|
|
||||||
allSuites = append(allSuites, suite)
|
|
||||||
return suite
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Public running interface.
|
|
||||||
|
|
||||||
var (
|
|
||||||
filterFlag = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run")
|
|
||||||
verboseFlag = flag.Bool("gocheck.v", false, "Verbose mode")
|
|
||||||
streamFlag = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)")
|
|
||||||
benchFlag = flag.Bool("gocheck.b", false, "Run benchmarks")
|
|
||||||
benchTime = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark")
|
|
||||||
listFlag = flag.Bool("gocheck.list", false, "List the names of all tests that will be run")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Run all test suites registered with the Suite() function, printing
|
|
||||||
// results to stdout, and reporting any failures back to the 'testing'
|
|
||||||
// module.
|
|
||||||
func TestingT(testingT *testing.T) {
|
|
||||||
conf := &RunConf{
|
|
||||||
Filter: *filterFlag,
|
|
||||||
Verbose: *verboseFlag,
|
|
||||||
Stream: *streamFlag,
|
|
||||||
Benchmark: *benchFlag,
|
|
||||||
BenchmarkTime: *benchTime,
|
|
||||||
}
|
|
||||||
if *listFlag {
|
|
||||||
w := bufio.NewWriter(os.Stdout)
|
|
||||||
for _, name := range ListAll(conf) {
|
|
||||||
fmt.Fprintln(w, name)
|
|
||||||
}
|
|
||||||
w.Flush()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result := RunAll(conf)
|
|
||||||
println(result.String())
|
|
||||||
if !result.Passed() {
|
|
||||||
testingT.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunAll runs all test suites registered with the Suite() function, using the
|
|
||||||
// given run configuration.
|
|
||||||
func RunAll(runConf *RunConf) *Result {
|
|
||||||
result := Result{}
|
|
||||||
for _, suite := range allSuites {
|
|
||||||
result.Add(Run(suite, runConf))
|
|
||||||
}
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run runs the given test suite using the provided run configuration.
|
|
||||||
func Run(suite interface{}, runConf *RunConf) *Result {
|
|
||||||
runner := newSuiteRunner(suite, runConf)
|
|
||||||
return runner.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAll returns the names of all the test functions registered with the
|
|
||||||
// Suite function that will be run with the provided run configuration.
|
|
||||||
func ListAll(runConf *RunConf) []string {
|
|
||||||
var names []string
|
|
||||||
for _, suite := range allSuites {
|
|
||||||
names = append(names, List(suite, runConf)...)
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
// List prints the names of the test functions in the given
|
|
||||||
// suite that will be run with the provided run configuration
|
|
||||||
// to the given Writer.
|
|
||||||
func List(suite interface{}, runConf *RunConf) []string {
|
|
||||||
var names []string
|
|
||||||
runner := newSuiteRunner(suite, runConf)
|
|
||||||
for _, t := range runner.tests {
|
|
||||||
names = append(names, t.String())
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Result methods.
|
|
||||||
|
|
||||||
func (r *Result) Add(other *Result) {
|
|
||||||
r.Succeeded += other.Succeeded
|
|
||||||
r.Skipped += other.Skipped
|
|
||||||
r.Failed += other.Failed
|
|
||||||
r.Panicked += other.Panicked
|
|
||||||
r.FixturePanicked += other.FixturePanicked
|
|
||||||
r.ExpectedFailures += other.ExpectedFailures
|
|
||||||
r.Missed += other.Missed
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) Passed() bool {
|
|
||||||
return (r.Failed == 0 && r.Panicked == 0 &&
|
|
||||||
r.FixturePanicked == 0 && r.Missed == 0 &&
|
|
||||||
r.RunError == nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) String() string {
|
|
||||||
if r.RunError != nil {
|
|
||||||
return "ERROR: " + r.RunError.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
var value string
|
|
||||||
if r.Failed == 0 && r.Panicked == 0 && r.FixturePanicked == 0 &&
|
|
||||||
r.Missed == 0 {
|
|
||||||
value = "OK: "
|
|
||||||
} else {
|
|
||||||
value = "OOPS: "
|
|
||||||
}
|
|
||||||
value += fmt.Sprintf("%d passed", r.Succeeded)
|
|
||||||
if r.Skipped != 0 {
|
|
||||||
value += fmt.Sprintf(", %d skipped", r.Skipped)
|
|
||||||
}
|
|
||||||
if r.ExpectedFailures != 0 {
|
|
||||||
value += fmt.Sprintf(", %d expected failures", r.ExpectedFailures)
|
|
||||||
}
|
|
||||||
if r.Failed != 0 {
|
|
||||||
value += fmt.Sprintf(", %d FAILED", r.Failed)
|
|
||||||
}
|
|
||||||
if r.Panicked != 0 {
|
|
||||||
value += fmt.Sprintf(", %d PANICKED", r.Panicked)
|
|
||||||
}
|
|
||||||
if r.FixturePanicked != 0 {
|
|
||||||
value += fmt.Sprintf(", %d FIXTURE-PANICKED", r.FixturePanicked)
|
|
||||||
}
|
|
||||||
if r.Missed != 0 {
|
|
||||||
value += fmt.Sprintf(", %d MISSED", r.Missed)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
397
Godeps/_workspace/src/github.com/motain/gocheck/run_test.go
generated
vendored
397
Godeps/_workspace/src/github.com/motain/gocheck/run_test.go
generated
vendored
@ -1,397 +0,0 @@
|
|||||||
// These tests verify the test running logic.
|
|
||||||
|
|
||||||
package gocheck_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
. "launchpad.net/gocheck"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var runnerS = Suite(&RunS{})
|
|
||||||
|
|
||||||
type RunS struct{}
|
|
||||||
|
|
||||||
func (s *RunS) TestCountSuite(c *C) {
|
|
||||||
suitesRun += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Tests ensuring result counting works properly.
|
|
||||||
|
|
||||||
func (s *RunS) TestSuccess(c *C) {
|
|
||||||
output := String{}
|
|
||||||
result := Run(&SuccessHelper{}, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 1)
|
|
||||||
c.Check(result.Failed, Equals, 0)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 0)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 0)
|
|
||||||
c.Check(result.Missed, Equals, 0)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFailure(c *C) {
|
|
||||||
output := String{}
|
|
||||||
result := Run(&FailHelper{}, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 0)
|
|
||||||
c.Check(result.Failed, Equals, 1)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 0)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 0)
|
|
||||||
c.Check(result.Missed, Equals, 0)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFixture(c *C) {
|
|
||||||
output := String{}
|
|
||||||
result := Run(&FixtureHelper{}, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 2)
|
|
||||||
c.Check(result.Failed, Equals, 0)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 0)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 0)
|
|
||||||
c.Check(result.Missed, Equals, 0)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPanicOnTest(c *C) {
|
|
||||||
output := String{}
|
|
||||||
helper := &FixtureHelper{panicOn: "Test1"}
|
|
||||||
result := Run(helper, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 1)
|
|
||||||
c.Check(result.Failed, Equals, 0)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 1)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 0)
|
|
||||||
c.Check(result.Missed, Equals, 0)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPanicOnSetUpTest(c *C) {
|
|
||||||
output := String{}
|
|
||||||
helper := &FixtureHelper{panicOn: "SetUpTest"}
|
|
||||||
result := Run(helper, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 0)
|
|
||||||
c.Check(result.Failed, Equals, 0)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 0)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 1)
|
|
||||||
c.Check(result.Missed, Equals, 2)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPanicOnSetUpSuite(c *C) {
|
|
||||||
output := String{}
|
|
||||||
helper := &FixtureHelper{panicOn: "SetUpSuite"}
|
|
||||||
result := Run(helper, &RunConf{Output: &output})
|
|
||||||
c.Check(result.Succeeded, Equals, 0)
|
|
||||||
c.Check(result.Failed, Equals, 0)
|
|
||||||
c.Check(result.Skipped, Equals, 0)
|
|
||||||
c.Check(result.Panicked, Equals, 0)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 1)
|
|
||||||
c.Check(result.Missed, Equals, 2)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Check result aggregation.
|
|
||||||
|
|
||||||
func (s *RunS) TestAdd(c *C) {
|
|
||||||
result := &Result{
|
|
||||||
Succeeded: 1,
|
|
||||||
Skipped: 2,
|
|
||||||
Failed: 3,
|
|
||||||
Panicked: 4,
|
|
||||||
FixturePanicked: 5,
|
|
||||||
Missed: 6,
|
|
||||||
ExpectedFailures: 7,
|
|
||||||
}
|
|
||||||
result.Add(&Result{
|
|
||||||
Succeeded: 10,
|
|
||||||
Skipped: 20,
|
|
||||||
Failed: 30,
|
|
||||||
Panicked: 40,
|
|
||||||
FixturePanicked: 50,
|
|
||||||
Missed: 60,
|
|
||||||
ExpectedFailures: 70,
|
|
||||||
})
|
|
||||||
c.Check(result.Succeeded, Equals, 11)
|
|
||||||
c.Check(result.Skipped, Equals, 22)
|
|
||||||
c.Check(result.Failed, Equals, 33)
|
|
||||||
c.Check(result.Panicked, Equals, 44)
|
|
||||||
c.Check(result.FixturePanicked, Equals, 55)
|
|
||||||
c.Check(result.Missed, Equals, 66)
|
|
||||||
c.Check(result.ExpectedFailures, Equals, 77)
|
|
||||||
c.Check(result.RunError, IsNil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Check the Passed() method.
|
|
||||||
|
|
||||||
func (s *RunS) TestPassed(c *C) {
|
|
||||||
c.Assert((&Result{}).Passed(), Equals, true)
|
|
||||||
c.Assert((&Result{Succeeded: 1}).Passed(), Equals, true)
|
|
||||||
c.Assert((&Result{Skipped: 1}).Passed(), Equals, true)
|
|
||||||
c.Assert((&Result{Failed: 1}).Passed(), Equals, false)
|
|
||||||
c.Assert((&Result{Panicked: 1}).Passed(), Equals, false)
|
|
||||||
c.Assert((&Result{FixturePanicked: 1}).Passed(), Equals, false)
|
|
||||||
c.Assert((&Result{Missed: 1}).Passed(), Equals, false)
|
|
||||||
c.Assert((&Result{RunError: errors.New("!")}).Passed(), Equals, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Check that result printing is working correctly.
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintSuccess(c *C) {
|
|
||||||
result := &Result{Succeeded: 5}
|
|
||||||
c.Check(result.String(), Equals, "OK: 5 passed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintFailure(c *C) {
|
|
||||||
result := &Result{Failed: 5}
|
|
||||||
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 FAILED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintSkipped(c *C) {
|
|
||||||
result := &Result{Skipped: 5}
|
|
||||||
c.Check(result.String(), Equals, "OK: 0 passed, 5 skipped")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintExpectedFailures(c *C) {
|
|
||||||
result := &Result{ExpectedFailures: 5}
|
|
||||||
c.Check(result.String(), Equals, "OK: 0 passed, 5 expected failures")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintPanicked(c *C) {
|
|
||||||
result := &Result{Panicked: 5}
|
|
||||||
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 PANICKED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintFixturePanicked(c *C) {
|
|
||||||
result := &Result{FixturePanicked: 5}
|
|
||||||
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 FIXTURE-PANICKED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintMissed(c *C) {
|
|
||||||
result := &Result{Missed: 5}
|
|
||||||
c.Check(result.String(), Equals, "OOPS: 0 passed, 5 MISSED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintAll(c *C) {
|
|
||||||
result := &Result{Succeeded: 1, Skipped: 2, ExpectedFailures: 3,
|
|
||||||
Panicked: 4, FixturePanicked: 5, Missed: 6}
|
|
||||||
c.Check(result.String(), Equals,
|
|
||||||
"OOPS: 1 passed, 2 skipped, 3 expected failures, 4 PANICKED, "+
|
|
||||||
"5 FIXTURE-PANICKED, 6 MISSED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestPrintRunError(c *C) {
|
|
||||||
result := &Result{Succeeded: 1, Failed: 1,
|
|
||||||
RunError: errors.New("Kaboom!")}
|
|
||||||
c.Check(result.String(), Equals, "ERROR: Kaboom!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify that the method pattern flag works correctly.
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterTestName(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "Test[91]"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterTestNameWithAll(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: ".*"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[7], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterSuiteName(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "FixtureHelper"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test1")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[5], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[6], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[7], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterSuiteNameAndTestName(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "FixtureHelper\\.Test2"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(helper.calls[0], Equals, "SetUpSuite")
|
|
||||||
c.Check(helper.calls[1], Equals, "SetUpTest")
|
|
||||||
c.Check(helper.calls[2], Equals, "Test2")
|
|
||||||
c.Check(helper.calls[3], Equals, "TearDownTest")
|
|
||||||
c.Check(helper.calls[4], Equals, "TearDownSuite")
|
|
||||||
c.Check(len(helper.calls), Equals, 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterAllOut(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "NotFound"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestRequirePartialMatch(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "est"}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
c.Check(len(helper.calls), Equals, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestFilterError(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Filter: "]["}
|
|
||||||
result := Run(&helper, &runConf)
|
|
||||||
c.Check(result.String(), Equals,
|
|
||||||
"ERROR: Bad filter expression: error parsing regexp: missing closing ]: `[`")
|
|
||||||
c.Check(len(helper.calls), Equals, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify that List works correctly.
|
|
||||||
|
|
||||||
func (s *RunS) TestListFiltered(c *C) {
|
|
||||||
names := List(&FixtureHelper{}, &RunConf{Filter: "1"})
|
|
||||||
c.Assert(names, DeepEquals, []string{
|
|
||||||
"FixtureHelper.Test1",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestList(c *C) {
|
|
||||||
names := List(&FixtureHelper{}, &RunConf{})
|
|
||||||
c.Assert(names, DeepEquals, []string{
|
|
||||||
"FixtureHelper.Test1",
|
|
||||||
"FixtureHelper.Test2",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify that verbose mode prints tests which pass as well.
|
|
||||||
|
|
||||||
func (s *RunS) TestVerboseMode(c *C) {
|
|
||||||
helper := FixtureHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Verbose: true}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
|
|
||||||
expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Test1\t *[.0-9]+s\n" +
|
|
||||||
"PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Test2\t *[.0-9]+s\n"
|
|
||||||
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestVerboseModeWithFailBeforePass(c *C) {
|
|
||||||
helper := FixtureHelper{panicOn: "Test1"}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Verbose: true}
|
|
||||||
Run(&helper, &runConf)
|
|
||||||
|
|
||||||
expected := "(?s).*PANIC.*\n-+\n" + // Should have an extra line.
|
|
||||||
"PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Test2\t *[.0-9]+s\n"
|
|
||||||
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// Verify the stream output mode. In this mode there's no output caching.
|
|
||||||
|
|
||||||
type StreamHelper struct {
|
|
||||||
l2 sync.Mutex
|
|
||||||
l3 sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StreamHelper) SetUpSuite(c *C) {
|
|
||||||
c.Log("0")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StreamHelper) Test1(c *C) {
|
|
||||||
c.Log("1")
|
|
||||||
s.l2.Lock()
|
|
||||||
s.l3.Lock()
|
|
||||||
go func() {
|
|
||||||
s.l2.Lock() // Wait for "2".
|
|
||||||
c.Log("3")
|
|
||||||
s.l3.Unlock()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StreamHelper) Test2(c *C) {
|
|
||||||
c.Log("2")
|
|
||||||
s.l2.Unlock()
|
|
||||||
s.l3.Lock() // Wait for "3".
|
|
||||||
c.Fail()
|
|
||||||
c.Log("4")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestStreamMode(c *C) {
|
|
||||||
helper := &StreamHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Stream: true}
|
|
||||||
Run(helper, &runConf)
|
|
||||||
|
|
||||||
expected := "START: run_test\\.go:[0-9]+: StreamHelper\\.SetUpSuite\n0\n" +
|
|
||||||
"PASS: run_test\\.go:[0-9]+: StreamHelper\\.SetUpSuite\t *[.0-9]+s\n\n" +
|
|
||||||
"START: run_test\\.go:[0-9]+: StreamHelper\\.Test1\n1\n" +
|
|
||||||
"PASS: run_test\\.go:[0-9]+: StreamHelper\\.Test1\t *[.0-9]+s\n\n" +
|
|
||||||
"START: run_test\\.go:[0-9]+: StreamHelper\\.Test2\n2\n3\n4\n" +
|
|
||||||
"FAIL: run_test\\.go:[0-9]+: StreamHelper\\.Test2\n\n"
|
|
||||||
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
type StreamMissHelper struct{}
|
|
||||||
|
|
||||||
func (s *StreamMissHelper) SetUpSuite(c *C) {
|
|
||||||
c.Log("0")
|
|
||||||
c.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StreamMissHelper) Test1(c *C) {
|
|
||||||
c.Log("1")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RunS) TestStreamModeWithMiss(c *C) {
|
|
||||||
helper := &StreamMissHelper{}
|
|
||||||
output := String{}
|
|
||||||
runConf := RunConf{Output: &output, Stream: true}
|
|
||||||
Run(helper, &runConf)
|
|
||||||
|
|
||||||
expected := "START: run_test\\.go:[0-9]+: StreamMissHelper\\.SetUpSuite\n0\n" +
|
|
||||||
"FAIL: run_test\\.go:[0-9]+: StreamMissHelper\\.SetUpSuite\n\n" +
|
|
||||||
"START: run_test\\.go:[0-9]+: StreamMissHelper\\.Test1\n" +
|
|
||||||
"MISS: run_test\\.go:[0-9]+: StreamMissHelper\\.Test1\n\n"
|
|
||||||
|
|
||||||
c.Assert(output.value, Matches, expected)
|
|
||||||
}
|
|
627
Godeps/_workspace/src/github.com/pkg/sftp/client.go
generated
vendored
627
Godeps/_workspace/src/github.com/pkg/sftp/client.go
generated
vendored
@ -1,11 +1,16 @@
|
|||||||
package sftp
|
package sftp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding"
|
"encoding"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kr/fs"
|
"github.com/kr/fs"
|
||||||
@ -13,8 +18,19 @@ import (
|
|||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MaxPacket sets the maximum size of the payload.
|
||||||
|
func MaxPacket(size int) func(*Client) error {
|
||||||
|
return func(c *Client) error {
|
||||||
|
if size < 1<<15 {
|
||||||
|
return fmt.Errorf("size must be greater or equal to 32k")
|
||||||
|
}
|
||||||
|
c.maxPacket = size
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a new SFTP client on conn.
|
// New creates a new SFTP client on conn.
|
||||||
func NewClient(conn *ssh.Client) (*Client, error) {
|
func NewClient(conn *ssh.Client, opts ...func(*Client) error) (*Client, error) {
|
||||||
s, err := conn.NewSession()
|
s, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -31,21 +47,34 @@ func NewClient(conn *ssh.Client) (*Client, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewClientPipe(pr, pw)
|
return NewClientPipe(pr, pw, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientPipe creates a new SFTP client given a Reader and a WriteCloser.
|
// NewClientPipe creates a new SFTP client given a Reader and a WriteCloser.
|
||||||
// This can be used for connecting to an SFTP server over TCP/TLS or by using
|
// This can be used for connecting to an SFTP server over TCP/TLS or by using
|
||||||
// the system's ssh client program (e.g. via exec.Command).
|
// the system's ssh client program (e.g. via exec.Command).
|
||||||
func NewClientPipe(rd io.Reader, wr io.WriteCloser) (*Client, error) {
|
func NewClientPipe(rd io.Reader, wr io.WriteCloser, opts ...func(*Client) error) (*Client, error) {
|
||||||
sftp := &Client{
|
sftp := &Client{
|
||||||
w: wr,
|
w: wr,
|
||||||
r: rd,
|
r: rd,
|
||||||
|
maxPacket: 1 << 15,
|
||||||
|
inflight: make(map[uint32]chan<- result),
|
||||||
|
recvClosed: make(chan struct{}),
|
||||||
}
|
}
|
||||||
if err := sftp.sendInit(); err != nil {
|
if err := sftp.applyOptions(opts...); err != nil {
|
||||||
|
wr.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return sftp, sftp.recvVersion()
|
if err := sftp.sendInit(); err != nil {
|
||||||
|
wr.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := sftp.recvVersion(); err != nil {
|
||||||
|
wr.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
go sftp.recv()
|
||||||
|
return sftp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client represents an SFTP session on a *ssh.ClientConn SSH connection.
|
// Client represents an SFTP session on a *ssh.ClientConn SSH connection.
|
||||||
@ -54,14 +83,23 @@ func NewClientPipe(rd io.Reader, wr io.WriteCloser) (*Client, error) {
|
|||||||
//
|
//
|
||||||
// Client implements the github.com/kr/fs.FileSystem interface.
|
// Client implements the github.com/kr/fs.FileSystem interface.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
w io.WriteCloser
|
w io.WriteCloser
|
||||||
r io.Reader
|
r io.Reader
|
||||||
mu sync.Mutex // locks mu and seralises commands to the server
|
|
||||||
nextid uint32
|
maxPacket int // max packet size read or written.
|
||||||
|
nextid uint32
|
||||||
|
|
||||||
|
mu sync.Mutex // ensures only on request is in flight to the server at once
|
||||||
|
inflight map[uint32]chan<- result // outstanding requests
|
||||||
|
recvClosed chan struct{} // remote end has closed the connection
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the SFTP session.
|
// Close closes the SFTP session.
|
||||||
func (c *Client) Close() error { return c.w.Close() }
|
func (c *Client) Close() error {
|
||||||
|
err := c.w.Close()
|
||||||
|
<-c.recvClosed
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Create creates the named file mode 0666 (before umask), truncating it if
|
// Create creates the named file mode 0666 (before umask), truncating it if
|
||||||
// it already exists. If successful, methods on the returned File can be
|
// it already exists. If successful, methods on the returned File can be
|
||||||
@ -78,12 +116,9 @@ func (c *Client) sendInit() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the current value of c.nextid and increments it
|
// returns the next value of c.nextid
|
||||||
// callers is expected to hold c.mu
|
|
||||||
func (c *Client) nextId() uint32 {
|
func (c *Client) nextId() uint32 {
|
||||||
v := c.nextid
|
return atomic.AddUint32(&c.nextid, 1)
|
||||||
c.nextid++
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) recvVersion() error {
|
func (c *Client) recvVersion() error {
|
||||||
@ -103,6 +138,46 @@ func (c *Client) recvVersion() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// broadcastErr sends an error to all goroutines waiting for a response.
|
||||||
|
func (c *Client) broadcastErr(err error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
listeners := make([]chan<- result, 0, len(c.inflight))
|
||||||
|
for _, ch := range c.inflight {
|
||||||
|
listeners = append(listeners, ch)
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
for _, ch := range listeners {
|
||||||
|
ch <- result{err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recv continuously reads from the server and forwards responses to the
|
||||||
|
// appropriate channel.
|
||||||
|
func (c *Client) recv() {
|
||||||
|
defer close(c.recvClosed)
|
||||||
|
for {
|
||||||
|
typ, data, err := recvPacket(c.r)
|
||||||
|
if err != nil {
|
||||||
|
// Return the error to all listeners.
|
||||||
|
c.broadcastErr(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sid, _ := unmarshalUint32(data)
|
||||||
|
c.mu.Lock()
|
||||||
|
ch, ok := c.inflight[sid]
|
||||||
|
delete(c.inflight, sid)
|
||||||
|
c.mu.Unlock()
|
||||||
|
if !ok {
|
||||||
|
// This is an unexpected occurrence. Send the error
|
||||||
|
// back to all listeners so that they terminate
|
||||||
|
// gracefully.
|
||||||
|
c.broadcastErr(fmt.Errorf("sid: %v not fond", sid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch <- result{typ: typ, data: data}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Walk returns a new Walker rooted at root.
|
// Walk returns a new Walker rooted at root.
|
||||||
func (c *Client) Walk(root string) *fs.Walker {
|
func (c *Client) Walk(root string) *fs.Walker {
|
||||||
return fs.WalkFS(root, c)
|
return fs.WalkFS(root, c)
|
||||||
@ -117,8 +192,6 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
|
|||||||
}
|
}
|
||||||
defer c.close(handle) // this has to defer earlier than the lock below
|
defer c.close(handle) // this has to defer earlier than the lock below
|
||||||
var attrs []os.FileInfo
|
var attrs []os.FileInfo
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
var done = false
|
var done = false
|
||||||
for !done {
|
for !done {
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
@ -163,8 +236,6 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
|
|||||||
return attrs, err
|
return attrs, err
|
||||||
}
|
}
|
||||||
func (c *Client) opendir(path string) (string, error) {
|
func (c *Client) opendir(path string) (string, error) {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpOpendirPacket{
|
typ, data, err := c.sendRequest(sshFxpOpendirPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -189,8 +260,6 @@ func (c *Client) opendir(path string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Lstat(p string) (os.FileInfo, error) {
|
func (c *Client) Lstat(p string) (os.FileInfo, error) {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpLstatPacket{
|
typ, data, err := c.sendRequest(sshFxpLstatPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -216,8 +285,6 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) {
|
|||||||
|
|
||||||
// ReadLink reads the target of a symbolic link.
|
// ReadLink reads the target of a symbolic link.
|
||||||
func (c *Client) ReadLink(p string) (string, error) {
|
func (c *Client) ReadLink(p string) (string, error) {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpReadlinkPacket{
|
typ, data, err := c.sendRequest(sshFxpReadlinkPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -247,8 +314,6 @@ func (c *Client) ReadLink(p string) (string, error) {
|
|||||||
|
|
||||||
// setstat is a convience wrapper to allow for changing of various parts of the file descriptor.
|
// setstat is a convience wrapper to allow for changing of various parts of the file descriptor.
|
||||||
func (c *Client) setstat(path string, flags uint32, attrs interface{}) error {
|
func (c *Client) setstat(path string, flags uint32, attrs interface{}) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpSetstatPacket{
|
typ, data, err := c.sendRequest(sshFxpSetstatPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -315,8 +380,6 @@ func (c *Client) OpenFile(path string, f int) (*File, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) open(path string, pflags uint32) (*File, error) {
|
func (c *Client) open(path string, pflags uint32) (*File, error) {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpOpenPacket{
|
typ, data, err := c.sendRequest(sshFxpOpenPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -341,43 +404,10 @@ func (c *Client) open(path string, pflags uint32) (*File, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readAt reads len(buf) bytes from the remote file indicated by handle starting
|
|
||||||
// from offset.
|
|
||||||
func (c *Client) readAt(handle string, offset uint64, buf []byte) (uint32, error) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
|
||||||
typ, data, err := c.sendRequest(sshFxpReadPacket{
|
|
||||||
Id: id,
|
|
||||||
Handle: handle,
|
|
||||||
Offset: offset,
|
|
||||||
Len: uint32(len(buf)),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
switch typ {
|
|
||||||
case ssh_FXP_DATA:
|
|
||||||
sid, data := unmarshalUint32(data)
|
|
||||||
if sid != id {
|
|
||||||
return 0, &unexpectedIdErr{id, sid}
|
|
||||||
}
|
|
||||||
l, data := unmarshalUint32(data)
|
|
||||||
n := copy(buf, data[:l])
|
|
||||||
return uint32(n), nil
|
|
||||||
case ssh_FXP_STATUS:
|
|
||||||
return 0, eofOrErr(unmarshalStatus(id, data))
|
|
||||||
default:
|
|
||||||
return 0, unimplementedPacketErr(typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close closes a handle handle previously returned in the response
|
// close closes a handle handle previously returned in the response
|
||||||
// to SSH_FXP_OPEN or SSH_FXP_OPENDIR. The handle becomes invalid
|
// to SSH_FXP_OPEN or SSH_FXP_OPENDIR. The handle becomes invalid
|
||||||
// immediately after this request has been sent.
|
// immediately after this request has been sent.
|
||||||
func (c *Client) close(handle string) error {
|
func (c *Client) close(handle string) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpClosePacket{
|
typ, data, err := c.sendRequest(sshFxpClosePacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -395,8 +425,6 @@ func (c *Client) close(handle string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) fstat(handle string) (*FileStat, error) {
|
func (c *Client) fstat(handle string) (*FileStat, error) {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpFstatPacket{
|
typ, data, err := c.sendRequest(sshFxpFstatPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -420,6 +448,40 @@ func (c *Client) fstat(handle string) (*FileStat, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get vfs stats from remote host.
|
||||||
|
// Implementing statvfs@openssh.com SSH_FXP_EXTENDED feature
|
||||||
|
// from http://www.opensource.apple.com/source/OpenSSH/OpenSSH-175/openssh/PROTOCOL?txt
|
||||||
|
func (c *Client) StatVFS(path string) (*StatVFS, error) {
|
||||||
|
// send the StatVFS packet to the server
|
||||||
|
id := c.nextId()
|
||||||
|
typ, data, err := c.sendRequest(sshFxpStatvfsPacket{
|
||||||
|
Id: id,
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ {
|
||||||
|
// server responded with valid data
|
||||||
|
case ssh_FXP_EXTENDED_REPLY:
|
||||||
|
var response StatVFS
|
||||||
|
err = binary.Read(bytes.NewReader(data), binary.BigEndian, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("can not parse reply")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
|
||||||
|
// the resquest failed
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
return nil, errors.New(fxp(ssh_FXP_STATUS).String())
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, unimplementedPacketErr(typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Join joins any number of path elements into a single path, adding a
|
// Join joins any number of path elements into a single path, adding a
|
||||||
// separating slash if necessary. The result is Cleaned; in particular, all
|
// separating slash if necessary. The result is Cleaned; in particular, all
|
||||||
// empty strings are ignored.
|
// empty strings are ignored.
|
||||||
@ -437,8 +499,6 @@ func (c *Client) Remove(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) removeFile(path string) error {
|
func (c *Client) removeFile(path string) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpRemovePacket{
|
typ, data, err := c.sendRequest(sshFxpRemovePacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -456,8 +516,6 @@ func (c *Client) removeFile(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) removeDirectory(path string) error {
|
func (c *Client) removeDirectory(path string) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpRmdirPacket{
|
typ, data, err := c.sendRequest(sshFxpRmdirPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -476,8 +534,6 @@ func (c *Client) removeDirectory(path string) error {
|
|||||||
|
|
||||||
// Rename renames a file.
|
// Rename renames a file.
|
||||||
func (c *Client) Rename(oldname, newname string) error {
|
func (c *Client) Rename(oldname, newname string) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpRenamePacket{
|
typ, data, err := c.sendRequest(sshFxpRenamePacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -495,46 +551,41 @@ func (c *Client) Rename(oldname, newname string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) sendRequest(p encoding.BinaryMarshaler) (byte, []byte, error) {
|
// result captures the result of receiving the a packet from the server
|
||||||
if err := sendPacket(c.w, p); err != nil {
|
type result struct {
|
||||||
return 0, nil, err
|
typ byte
|
||||||
}
|
data []byte
|
||||||
return recvPacket(c.r)
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeAt writes len(buf) bytes from the remote file indicated by handle starting
|
type idmarshaler interface {
|
||||||
// from offset.
|
id() uint32
|
||||||
func (c *Client) writeAt(handle string, offset uint64, buf []byte) (uint32, error) {
|
encoding.BinaryMarshaler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) sendRequest(p idmarshaler) (byte, []byte, error) {
|
||||||
|
ch := make(chan result, 1)
|
||||||
|
c.dispatchRequest(ch, p)
|
||||||
|
s := <-ch
|
||||||
|
return s.typ, s.data, s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) dispatchRequest(ch chan<- result, p idmarshaler) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
c.inflight[p.id()] = ch
|
||||||
id := c.nextId()
|
if err := sendPacket(c.w, p); err != nil {
|
||||||
typ, data, err := c.sendRequest(sshFxpWritePacket{
|
delete(c.inflight, p.id())
|
||||||
Id: id,
|
c.mu.Unlock()
|
||||||
Handle: handle,
|
ch <- result{err: err}
|
||||||
Offset: offset,
|
return
|
||||||
Length: uint32(len(buf)),
|
|
||||||
Data: buf,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
switch typ {
|
|
||||||
case ssh_FXP_STATUS:
|
|
||||||
if err := okOrErr(unmarshalStatus(id, data)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint32(len(buf)), nil
|
|
||||||
default:
|
|
||||||
return 0, unimplementedPacketErr(typ)
|
|
||||||
}
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the specified directory. An error will be returned if a file or
|
// Creates the specified directory. An error will be returned if a file or
|
||||||
// directory with the specified path already exists, or if the directory's
|
// directory with the specified path already exists, or if the directory's
|
||||||
// parent folder does not exist (the method cannot create complete paths).
|
// parent folder does not exist (the method cannot create complete paths).
|
||||||
func (c *Client) Mkdir(path string) error {
|
func (c *Client) Mkdir(path string) error {
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
id := c.nextId()
|
id := c.nextId()
|
||||||
typ, data, err := c.sendRequest(sshFxpMkdirPacket{
|
typ, data, err := c.sendRequest(sshFxpMkdirPacket{
|
||||||
Id: id,
|
Id: id,
|
||||||
@ -551,6 +602,17 @@ func (c *Client) Mkdir(path string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyOptions applies options functions to the Client.
|
||||||
|
// If an error is encountered, option processing ceases.
|
||||||
|
func (c *Client) applyOptions(opts ...func(*Client) error) error {
|
||||||
|
for _, f := range opts {
|
||||||
|
if err := f(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// File represents a remote file.
|
// File represents a remote file.
|
||||||
type File struct {
|
type File struct {
|
||||||
c *Client
|
c *Client
|
||||||
@ -565,21 +627,226 @@ func (f *File) Close() error {
|
|||||||
return f.c.close(f.handle)
|
return f.c.close(f.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxConcurrentRequests = 64
|
||||||
|
|
||||||
// Read reads up to len(b) bytes from the File. It returns the number of
|
// Read reads up to len(b) bytes from the File. It returns the number of
|
||||||
// bytes read and an error, if any. EOF is signaled by a zero count with
|
// bytes read and an error, if any. EOF is signaled by a zero count with
|
||||||
// err set to io.EOF.
|
// err set to io.EOF.
|
||||||
func (f *File) Read(b []byte) (int, error) {
|
func (f *File) Read(b []byte) (int, error) {
|
||||||
var read int
|
// Split the read into multiple maxPacket sized concurrent reads
|
||||||
for len(b) > 0 {
|
// bounded by maxConcurrentRequests. This allows reads with a suitably
|
||||||
n, err := f.c.readAt(f.handle, f.offset, b[:min(len(b), maxWritePacket)])
|
// large buffer to transfer data at a much faster rate due to
|
||||||
f.offset += uint64(n)
|
// overlapping round trip times.
|
||||||
read += int(n)
|
inFlight := 0
|
||||||
if err != nil {
|
desiredInFlight := 1
|
||||||
return read, err
|
offset := f.offset
|
||||||
}
|
ch := make(chan result)
|
||||||
b = b[n:]
|
type inflightRead struct {
|
||||||
|
b []byte
|
||||||
|
offset uint64
|
||||||
}
|
}
|
||||||
return read, nil
|
reqs := map[uint32]inflightRead{}
|
||||||
|
type offsetErr struct {
|
||||||
|
offset uint64
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
var firstErr offsetErr
|
||||||
|
|
||||||
|
sendReq := func(b []byte, offset uint64) {
|
||||||
|
reqId := f.c.nextId()
|
||||||
|
f.c.dispatchRequest(ch, sshFxpReadPacket{
|
||||||
|
Id: reqId,
|
||||||
|
Handle: f.handle,
|
||||||
|
Offset: offset,
|
||||||
|
Len: uint32(len(b)),
|
||||||
|
})
|
||||||
|
inFlight++
|
||||||
|
reqs[reqId] = inflightRead{b: b, offset: offset}
|
||||||
|
}
|
||||||
|
|
||||||
|
var read int
|
||||||
|
for len(b) > 0 || inFlight > 0 {
|
||||||
|
for inFlight < desiredInFlight && len(b) > 0 && firstErr.err == nil {
|
||||||
|
l := min(len(b), f.c.maxPacket)
|
||||||
|
rb := b[:l]
|
||||||
|
sendReq(rb, offset)
|
||||||
|
offset += uint64(l)
|
||||||
|
b = b[l:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if inFlight == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case res := <-ch:
|
||||||
|
inFlight--
|
||||||
|
if res.err != nil {
|
||||||
|
firstErr = offsetErr{offset: 0, err: res.err}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
reqId, data := unmarshalUint32(res.data)
|
||||||
|
req, ok := reqs[reqId]
|
||||||
|
if !ok {
|
||||||
|
firstErr = offsetErr{offset: 0, err: fmt.Errorf("sid: %v not found", reqId)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
delete(reqs, reqId)
|
||||||
|
switch res.typ {
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
if firstErr.err == nil || req.offset < firstErr.offset {
|
||||||
|
firstErr = offsetErr{offset: req.offset, err: eofOrErr(unmarshalStatus(reqId, res.data))}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ssh_FXP_DATA:
|
||||||
|
l, data := unmarshalUint32(data)
|
||||||
|
n := copy(req.b, data[:l])
|
||||||
|
read += n
|
||||||
|
if n < len(req.b) {
|
||||||
|
sendReq(req.b[l:], req.offset+uint64(l))
|
||||||
|
}
|
||||||
|
if desiredInFlight < maxConcurrentRequests {
|
||||||
|
desiredInFlight++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
firstErr = offsetErr{offset: 0, err: unimplementedPacketErr(res.typ)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the error is anything other than EOF, then there
|
||||||
|
// may be gaps in the data copied to the buffer so it's
|
||||||
|
// best to return 0 so the caller can't make any
|
||||||
|
// incorrect assumptions about the state of the buffer.
|
||||||
|
if firstErr.err != nil && firstErr.err != io.EOF {
|
||||||
|
read = 0
|
||||||
|
}
|
||||||
|
f.offset += uint64(read)
|
||||||
|
return read, firstErr.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo writes the file to w. The return value is the number of bytes
|
||||||
|
// written. Any error encountered during the write is also returned.
|
||||||
|
func (f *File) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
inFlight := 0
|
||||||
|
desiredInFlight := 1
|
||||||
|
offset := f.offset
|
||||||
|
writeOffset := offset
|
||||||
|
fileSize := uint64(fi.Size())
|
||||||
|
ch := make(chan result)
|
||||||
|
type inflightRead struct {
|
||||||
|
b []byte
|
||||||
|
offset uint64
|
||||||
|
}
|
||||||
|
reqs := map[uint32]inflightRead{}
|
||||||
|
pendingWrites := map[uint64][]byte{}
|
||||||
|
type offsetErr struct {
|
||||||
|
offset uint64
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
var firstErr offsetErr
|
||||||
|
|
||||||
|
sendReq := func(b []byte, offset uint64) {
|
||||||
|
reqId := f.c.nextId()
|
||||||
|
f.c.dispatchRequest(ch, sshFxpReadPacket{
|
||||||
|
Id: reqId,
|
||||||
|
Handle: f.handle,
|
||||||
|
Offset: offset,
|
||||||
|
Len: uint32(len(b)),
|
||||||
|
})
|
||||||
|
inFlight++
|
||||||
|
reqs[reqId] = inflightRead{b: b, offset: offset}
|
||||||
|
}
|
||||||
|
|
||||||
|
var copied int64
|
||||||
|
for firstErr.err == nil || inFlight > 0 {
|
||||||
|
for inFlight < desiredInFlight && firstErr.err == nil {
|
||||||
|
b := make([]byte, f.c.maxPacket)
|
||||||
|
sendReq(b, offset)
|
||||||
|
offset += uint64(f.c.maxPacket)
|
||||||
|
if offset > fileSize {
|
||||||
|
desiredInFlight = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if inFlight == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case res := <-ch:
|
||||||
|
inFlight--
|
||||||
|
if res.err != nil {
|
||||||
|
firstErr = offsetErr{offset: 0, err: res.err}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
reqId, data := unmarshalUint32(res.data)
|
||||||
|
req, ok := reqs[reqId]
|
||||||
|
if !ok {
|
||||||
|
firstErr = offsetErr{offset: 0, err: fmt.Errorf("sid: %v not found", reqId)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
delete(reqs, reqId)
|
||||||
|
switch res.typ {
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
if firstErr.err == nil || req.offset < firstErr.offset {
|
||||||
|
firstErr = offsetErr{offset: req.offset, err: eofOrErr(unmarshalStatus(reqId, res.data))}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ssh_FXP_DATA:
|
||||||
|
l, data := unmarshalUint32(data)
|
||||||
|
if req.offset == writeOffset {
|
||||||
|
nbytes, err := w.Write(data)
|
||||||
|
copied += int64(nbytes)
|
||||||
|
if err != nil {
|
||||||
|
firstErr = offsetErr{offset: req.offset + uint64(nbytes), err: err}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nbytes < int(l) {
|
||||||
|
firstErr = offsetErr{offset: req.offset + uint64(nbytes), err: io.ErrShortWrite}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case offset > fileSize:
|
||||||
|
desiredInFlight = 1
|
||||||
|
case desiredInFlight < maxConcurrentRequests:
|
||||||
|
desiredInFlight++
|
||||||
|
}
|
||||||
|
writeOffset += uint64(nbytes)
|
||||||
|
for pendingData, ok := pendingWrites[writeOffset]; ok; pendingData, ok = pendingWrites[writeOffset] {
|
||||||
|
nbytes, err := w.Write(pendingData)
|
||||||
|
if err != nil {
|
||||||
|
firstErr = offsetErr{offset: writeOffset + uint64(nbytes), err: err}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nbytes < len(pendingData) {
|
||||||
|
firstErr = offsetErr{offset: writeOffset + uint64(nbytes), err: io.ErrShortWrite}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
writeOffset += uint64(nbytes)
|
||||||
|
inFlight--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Don't write the data yet because
|
||||||
|
// this response came in out of order
|
||||||
|
// and we need to wait for responses
|
||||||
|
// for earlier segments of the file.
|
||||||
|
inFlight++ // Pending writes should still be considered inFlight.
|
||||||
|
pendingWrites[req.offset] = data
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
firstErr = offsetErr{offset: 0, err: unimplementedPacketErr(res.typ)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if firstErr.err != io.EOF {
|
||||||
|
return copied, firstErr.err
|
||||||
|
}
|
||||||
|
return copied, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat returns the FileInfo structure describing file. If there is an
|
// Stat returns the FileInfo structure describing file. If there is an
|
||||||
@ -592,24 +859,140 @@ func (f *File) Stat() (os.FileInfo, error) {
|
|||||||
return fileInfoFromStat(fs, path.Base(f.path)), nil
|
return fileInfoFromStat(fs, path.Base(f.path)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// clamp writes to less than 32k
|
|
||||||
const maxWritePacket = 1 << 15
|
|
||||||
|
|
||||||
// Write writes len(b) bytes to the File. It returns the number of bytes
|
// Write writes len(b) bytes to the File. It returns the number of bytes
|
||||||
// written and an error, if any. Write returns a non-nil error when n !=
|
// written and an error, if any. Write returns a non-nil error when n !=
|
||||||
// len(b).
|
// len(b).
|
||||||
func (f *File) Write(b []byte) (int, error) {
|
func (f *File) Write(b []byte) (int, error) {
|
||||||
var written int
|
// Split the write into multiple maxPacket sized concurrent writes
|
||||||
for len(b) > 0 {
|
// bounded by maxConcurrentRequests. This allows writes with a suitably
|
||||||
n, err := f.c.writeAt(f.handle, f.offset, b[:min(len(b), maxWritePacket)])
|
// large buffer to transfer data at a much faster rate due to
|
||||||
f.offset += uint64(n)
|
// overlapping round trip times.
|
||||||
written += int(n)
|
inFlight := 0
|
||||||
if err != nil {
|
desiredInFlight := 1
|
||||||
return written, err
|
offset := f.offset
|
||||||
|
ch := make(chan result)
|
||||||
|
var firstErr error
|
||||||
|
written := len(b)
|
||||||
|
for len(b) > 0 || inFlight > 0 {
|
||||||
|
for inFlight < desiredInFlight && len(b) > 0 && firstErr == nil {
|
||||||
|
l := min(len(b), f.c.maxPacket)
|
||||||
|
rb := b[:l]
|
||||||
|
f.c.dispatchRequest(ch, sshFxpWritePacket{
|
||||||
|
Id: f.c.nextId(),
|
||||||
|
Handle: f.handle,
|
||||||
|
Offset: offset,
|
||||||
|
Length: uint32(len(rb)),
|
||||||
|
Data: rb,
|
||||||
|
})
|
||||||
|
inFlight++
|
||||||
|
offset += uint64(l)
|
||||||
|
b = b[l:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if inFlight == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case res := <-ch:
|
||||||
|
inFlight--
|
||||||
|
if res.err != nil {
|
||||||
|
firstErr = res.err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch res.typ {
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
id, _ := unmarshalUint32(res.data)
|
||||||
|
err := okOrErr(unmarshalStatus(id, res.data))
|
||||||
|
if err != nil && firstErr == nil {
|
||||||
|
firstErr = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if desiredInFlight < maxConcurrentRequests {
|
||||||
|
desiredInFlight++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
firstErr = unimplementedPacketErr(res.typ)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
b = b[n:]
|
|
||||||
}
|
}
|
||||||
return written, nil
|
// If error is non-nil, then there may be gaps in the data written to
|
||||||
|
// the file so it's best to return 0 so the caller can't make any
|
||||||
|
// incorrect assumptions about the state of the file.
|
||||||
|
if firstErr != nil {
|
||||||
|
written = 0
|
||||||
|
}
|
||||||
|
f.offset += uint64(written)
|
||||||
|
return written, firstErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFrom reads data from r until EOF and writes it to the file. The return
|
||||||
|
// value is the number of bytes read. Any error except io.EOF encountered
|
||||||
|
// during the read is also returned.
|
||||||
|
func (f *File) ReadFrom(r io.Reader) (int64, error) {
|
||||||
|
inFlight := 0
|
||||||
|
desiredInFlight := 1
|
||||||
|
offset := f.offset
|
||||||
|
ch := make(chan result)
|
||||||
|
var firstErr error
|
||||||
|
read := int64(0)
|
||||||
|
b := make([]byte, f.c.maxPacket)
|
||||||
|
for inFlight > 0 || firstErr == nil {
|
||||||
|
for inFlight < desiredInFlight && firstErr == nil {
|
||||||
|
n, err := r.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
firstErr = err
|
||||||
|
}
|
||||||
|
f.c.dispatchRequest(ch, sshFxpWritePacket{
|
||||||
|
Id: f.c.nextId(),
|
||||||
|
Handle: f.handle,
|
||||||
|
Offset: offset,
|
||||||
|
Length: uint32(n),
|
||||||
|
Data: b[:n],
|
||||||
|
})
|
||||||
|
inFlight++
|
||||||
|
offset += uint64(n)
|
||||||
|
read += int64(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inFlight == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case res := <-ch:
|
||||||
|
inFlight--
|
||||||
|
if res.err != nil {
|
||||||
|
firstErr = res.err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch res.typ {
|
||||||
|
case ssh_FXP_STATUS:
|
||||||
|
id, _ := unmarshalUint32(res.data)
|
||||||
|
err := okOrErr(unmarshalStatus(id, res.data))
|
||||||
|
if err != nil && firstErr == nil {
|
||||||
|
firstErr = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if desiredInFlight < maxConcurrentRequests {
|
||||||
|
desiredInFlight++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
firstErr = unimplementedPacketErr(res.typ)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if firstErr == io.EOF {
|
||||||
|
firstErr = nil
|
||||||
|
}
|
||||||
|
// If error is non-nil, then there may be gaps in the data written to
|
||||||
|
// the file so it's best to return 0 so the caller can't make any
|
||||||
|
// incorrect assumptions about the state of the file.
|
||||||
|
if firstErr != nil {
|
||||||
|
read = 0
|
||||||
|
}
|
||||||
|
f.offset += uint64(read)
|
||||||
|
return read, firstErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek implements io.Seeker by setting the client offset for the next Read or
|
// Seek implements io.Seeker by setting the client offset for the next Read or
|
||||||
|
371
Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go
generated
vendored
371
Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go
generated
vendored
@ -14,15 +14,18 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kr/fs"
|
"github.com/kr/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
READONLY = true
|
READONLY = true
|
||||||
READWRITE = false
|
READWRITE = false
|
||||||
|
NO_DELAY time.Duration = 0
|
||||||
|
|
||||||
debuglevel = "ERROR" // set to "DEBUG" for debugging
|
debuglevel = "ERROR" // set to "DEBUG" for debugging
|
||||||
)
|
)
|
||||||
@ -30,9 +33,57 @@ const (
|
|||||||
var testIntegration = flag.Bool("integration", false, "perform integration tests against sftp server process")
|
var testIntegration = flag.Bool("integration", false, "perform integration tests against sftp server process")
|
||||||
var testSftp = flag.String("sftp", "/usr/lib/openssh/sftp-server", "location of the sftp server binary")
|
var testSftp = flag.String("sftp", "/usr/lib/openssh/sftp-server", "location of the sftp server binary")
|
||||||
|
|
||||||
|
type delayedWrite struct {
|
||||||
|
t time.Time
|
||||||
|
b []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// delayedWriter wraps a writer and artificially delays the write. This is
|
||||||
|
// meant to mimic connections with various latencies. Error's returned from the
|
||||||
|
// underlying writer will panic so this should only be used over reliable
|
||||||
|
// connections.
|
||||||
|
type delayedWriter struct {
|
||||||
|
w io.WriteCloser
|
||||||
|
ch chan delayedWrite
|
||||||
|
closed chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDelayedWriter(w io.WriteCloser, delay time.Duration) io.WriteCloser {
|
||||||
|
ch := make(chan delayedWrite, 128)
|
||||||
|
closed := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
for writeMsg := range ch {
|
||||||
|
time.Sleep(writeMsg.t.Add(delay).Sub(time.Now()))
|
||||||
|
n, err := w.Write(writeMsg.b)
|
||||||
|
if err != nil {
|
||||||
|
panic("write error")
|
||||||
|
}
|
||||||
|
if n < len(writeMsg.b) {
|
||||||
|
panic("showrt write")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
close(closed)
|
||||||
|
}()
|
||||||
|
return delayedWriter{w: w, ch: ch, closed: closed}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w delayedWriter) Write(b []byte) (int, error) {
|
||||||
|
bcopy := make([]byte, len(b))
|
||||||
|
copy(bcopy, b)
|
||||||
|
w.ch <- delayedWrite{t: time.Now(), b: bcopy}
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w delayedWriter) Close() error {
|
||||||
|
close(w.ch)
|
||||||
|
<-w.closed
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// testClient returns a *Client connected to a localy running sftp-server
|
// testClient returns a *Client connected to a localy running sftp-server
|
||||||
// the *exec.Cmd returned must be defer Wait'd.
|
// the *exec.Cmd returned must be defer Wait'd.
|
||||||
func testClient(t testing.TB, readonly bool) (*Client, *exec.Cmd) {
|
func testClient(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) {
|
||||||
if !*testIntegration {
|
if !*testIntegration {
|
||||||
t.Skip("skipping intergration test")
|
t.Skip("skipping intergration test")
|
||||||
}
|
}
|
||||||
@ -45,6 +96,9 @@ func testClient(t testing.TB, readonly bool) (*Client, *exec.Cmd) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if delay > NO_DELAY {
|
||||||
|
pw = newDelayedWriter(pw, delay)
|
||||||
|
}
|
||||||
pr, err := cmd.StdoutPipe()
|
pr, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -58,19 +112,11 @@ func testClient(t testing.TB, readonly bool) (*Client, *exec.Cmd) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sftp.sendInit(); err != nil {
|
|
||||||
defer cmd.Wait()
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := sftp.recvVersion(); err != nil {
|
|
||||||
defer cmd.Wait()
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return sftp, cmd
|
return sftp, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
|
|
||||||
if err := sftp.Close(); err != nil {
|
if err := sftp.Close(); err != nil {
|
||||||
@ -79,7 +125,7 @@ func TestNewClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientLstat(t *testing.T) {
|
func TestClientLstat(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -105,7 +151,7 @@ func TestClientLstat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientLstatMissing(t *testing.T) {
|
func TestClientLstatMissing(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -122,7 +168,7 @@ func TestClientLstatMissing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientMkdir(t *testing.T) {
|
func TestClientMkdir(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -140,7 +186,7 @@ func TestClientMkdir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientOpen(t *testing.T) {
|
func TestClientOpen(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -199,7 +245,7 @@ func (s seek) end(t *testing.T, r io.ReadSeeker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientSeek(t *testing.T) {
|
func TestClientSeek(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -243,7 +289,7 @@ func TestClientSeek(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientCreate(t *testing.T) {
|
func TestClientCreate(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -262,7 +308,7 @@ func TestClientCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientAppend(t *testing.T) {
|
func TestClientAppend(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -281,7 +327,7 @@ func TestClientAppend(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientCreateFailed(t *testing.T) {
|
func TestClientCreateFailed(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -302,7 +348,7 @@ func TestClientCreateFailed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientFileStat(t *testing.T) {
|
func TestClientFileStat(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -333,7 +379,7 @@ func TestClientFileStat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientRemove(t *testing.T) {
|
func TestClientRemove(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -350,7 +396,7 @@ func TestClientRemove(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientRemoveDir(t *testing.T) {
|
func TestClientRemoveDir(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -367,7 +413,7 @@ func TestClientRemoveDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientRemoveFailed(t *testing.T) {
|
func TestClientRemoveFailed(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -384,7 +430,7 @@ func TestClientRemoveFailed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientRename(t *testing.T) {
|
func TestClientRename(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -405,7 +451,7 @@ func TestClientRename(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientReadLine(t *testing.T) {
|
func TestClientReadLine(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -449,7 +495,7 @@ var clientReadTests = []struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientRead(t *testing.T) {
|
func TestClientRead(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -537,7 +583,7 @@ var clientWriteTests = []struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientWrite(t *testing.T) {
|
func TestClientWrite(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READWRITE)
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -664,7 +710,7 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientWalk(t *testing.T) {
|
func TestClientWalk(t *testing.T) {
|
||||||
sftp, cmd := testClient(t, READONLY)
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -747,11 +793,29 @@ func TestClientWalk(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkRead(b *testing.B, bufsize int) {
|
// sftp/issue/42, abrupt server hangup would result in client hangs.
|
||||||
|
func TestServerRoughDisconnect(t *testing.T) {
|
||||||
|
sftp, cmd := testClient(t, READONLY, NO_DELAY)
|
||||||
|
|
||||||
|
f, err := sftp.Open("/dev/zero")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}()
|
||||||
|
|
||||||
|
io.Copy(ioutil.Discard, f)
|
||||||
|
sftp.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkRead(b *testing.B, bufsize int, delay time.Duration) {
|
||||||
size := 10*1024*1024 + 123 // ~10MiB
|
size := 10*1024*1024 + 123 // ~10MiB
|
||||||
|
|
||||||
// open sftp client
|
// open sftp client
|
||||||
sftp, cmd := testClient(b, READONLY)
|
sftp, cmd := testClient(b, READONLY, delay)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -786,38 +850,50 @@ func benchmarkRead(b *testing.B, bufsize int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead1k(b *testing.B) {
|
func BenchmarkRead1k(b *testing.B) {
|
||||||
benchmarkRead(b, 1*1024)
|
benchmarkRead(b, 1*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead16k(b *testing.B) {
|
func BenchmarkRead16k(b *testing.B) {
|
||||||
benchmarkRead(b, 16*1024)
|
benchmarkRead(b, 16*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead32k(b *testing.B) {
|
func BenchmarkRead32k(b *testing.B) {
|
||||||
benchmarkRead(b, 32*1024)
|
benchmarkRead(b, 32*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead128k(b *testing.B) {
|
func BenchmarkRead128k(b *testing.B) {
|
||||||
benchmarkRead(b, 128*1024)
|
benchmarkRead(b, 128*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead512k(b *testing.B) {
|
func BenchmarkRead512k(b *testing.B) {
|
||||||
benchmarkRead(b, 512*1024)
|
benchmarkRead(b, 512*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead1MiB(b *testing.B) {
|
func BenchmarkRead1MiB(b *testing.B) {
|
||||||
benchmarkRead(b, 1024*1024)
|
benchmarkRead(b, 1024*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRead4MiB(b *testing.B) {
|
func BenchmarkRead4MiB(b *testing.B) {
|
||||||
benchmarkRead(b, 4*1024*1024)
|
benchmarkRead(b, 4*1024*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkWrite(b *testing.B, bufsize int) {
|
func BenchmarkRead4MiBDelay10Msec(b *testing.B) {
|
||||||
|
benchmarkRead(b, 4*1024*1024, 10*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRead4MiBDelay50Msec(b *testing.B) {
|
||||||
|
benchmarkRead(b, 4*1024*1024, 50*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRead4MiBDelay150Msec(b *testing.B) {
|
||||||
|
benchmarkRead(b, 4*1024*1024, 150*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkWrite(b *testing.B, bufsize int, delay time.Duration) {
|
||||||
size := 10*1024*1024 + 123 // ~10MiB
|
size := 10*1024*1024 + 123 // ~10MiB
|
||||||
|
|
||||||
// open sftp client
|
// open sftp client
|
||||||
sftp, cmd := testClient(b, false)
|
sftp, cmd := testClient(b, false, delay)
|
||||||
defer cmd.Wait()
|
defer cmd.Wait()
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
@ -870,29 +946,230 @@ func benchmarkWrite(b *testing.B, bufsize int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite1k(b *testing.B) {
|
func BenchmarkWrite1k(b *testing.B) {
|
||||||
benchmarkWrite(b, 1*1024)
|
benchmarkWrite(b, 1*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite16k(b *testing.B) {
|
func BenchmarkWrite16k(b *testing.B) {
|
||||||
benchmarkWrite(b, 16*1024)
|
benchmarkWrite(b, 16*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite32k(b *testing.B) {
|
func BenchmarkWrite32k(b *testing.B) {
|
||||||
benchmarkWrite(b, 32*1024)
|
benchmarkWrite(b, 32*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite128k(b *testing.B) {
|
func BenchmarkWrite128k(b *testing.B) {
|
||||||
benchmarkWrite(b, 128*1024)
|
benchmarkWrite(b, 128*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite512k(b *testing.B) {
|
func BenchmarkWrite512k(b *testing.B) {
|
||||||
benchmarkWrite(b, 512*1024)
|
benchmarkWrite(b, 512*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite1MiB(b *testing.B) {
|
func BenchmarkWrite1MiB(b *testing.B) {
|
||||||
benchmarkWrite(b, 1024*1024)
|
benchmarkWrite(b, 1024*1024, NO_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrite4MiB(b *testing.B) {
|
func BenchmarkWrite4MiB(b *testing.B) {
|
||||||
benchmarkWrite(b, 4*1024*1024)
|
benchmarkWrite(b, 4*1024*1024, NO_DELAY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkWrite4MiBDelay10Msec(b *testing.B) {
|
||||||
|
benchmarkWrite(b, 4*1024*1024, 10*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkWrite4MiBDelay50Msec(b *testing.B) {
|
||||||
|
benchmarkWrite(b, 4*1024*1024, 50*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkWrite4MiBDelay150Msec(b *testing.B) {
|
||||||
|
benchmarkWrite(b, 4*1024*1024, 150*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientStatVFS(t *testing.T) {
|
||||||
|
sftp, cmd := testClient(t, READWRITE, NO_DELAY)
|
||||||
|
defer cmd.Wait()
|
||||||
|
defer sftp.Close()
|
||||||
|
|
||||||
|
vfs, err := sftp.StatVFS("/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get system stats
|
||||||
|
s := syscall.Statfs_t{}
|
||||||
|
err = syscall.Statfs("/", &s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check some stats
|
||||||
|
if vfs.Frsize != uint64(s.Frsize) {
|
||||||
|
t.Fatal("fr_size does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vfs.Bsize != uint64(s.Bsize) {
|
||||||
|
t.Fatal("f_bsize does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vfs.Namemax != uint64(s.Namelen) {
|
||||||
|
t.Fatal("f_namemax does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vfs.Bavail != s.Bavail {
|
||||||
|
t.Fatal("f_bavail does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkCopyDown(b *testing.B, fileSize int64, delay time.Duration) {
|
||||||
|
// Create a temp file and fill it with zero's.
|
||||||
|
src, err := ioutil.TempFile("", "sftptest")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
srcFilename := src.Name()
|
||||||
|
defer os.Remove(srcFilename)
|
||||||
|
zero, err := os.Open("/dev/zero")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
n, err := io.Copy(src, io.LimitReader(zero, fileSize))
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
if n < fileSize {
|
||||||
|
b.Fatal("short copy")
|
||||||
|
}
|
||||||
|
zero.Close()
|
||||||
|
src.Close()
|
||||||
|
|
||||||
|
sftp, cmd := testClient(b, READONLY, delay)
|
||||||
|
defer cmd.Wait()
|
||||||
|
defer sftp.Close()
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(fileSize)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
dst, err := ioutil.TempFile("", "sftptest")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(dst.Name())
|
||||||
|
|
||||||
|
src, err := sftp.Open(srcFilename)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
n, err := io.Copy(dst, src)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("copy error: %v", err)
|
||||||
|
}
|
||||||
|
if n < fileSize {
|
||||||
|
b.Fatal("unable to copy all bytes")
|
||||||
|
}
|
||||||
|
dst.Close()
|
||||||
|
fi, err := os.Stat(dst.Name())
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Size() != fileSize {
|
||||||
|
b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size())
|
||||||
|
}
|
||||||
|
os.Remove(dst.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyDown10MiBDelay10Msec(b *testing.B) {
|
||||||
|
benchmarkCopyDown(b, 10*1024*1024, 10*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyDown10MiBDelay50Msec(b *testing.B) {
|
||||||
|
benchmarkCopyDown(b, 10*1024*1024, 50*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyDown10MiBDelay150Msec(b *testing.B) {
|
||||||
|
benchmarkCopyDown(b, 10*1024*1024, 150*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkCopyUp(b *testing.B, fileSize int64, delay time.Duration) {
|
||||||
|
// Create a temp file and fill it with zero's.
|
||||||
|
src, err := ioutil.TempFile("", "sftptest")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
srcFilename := src.Name()
|
||||||
|
defer os.Remove(srcFilename)
|
||||||
|
zero, err := os.Open("/dev/zero")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
n, err := io.Copy(src, io.LimitReader(zero, fileSize))
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
if n < fileSize {
|
||||||
|
b.Fatal("short copy")
|
||||||
|
}
|
||||||
|
zero.Close()
|
||||||
|
src.Close()
|
||||||
|
|
||||||
|
sftp, cmd := testClient(b, false, delay)
|
||||||
|
defer cmd.Wait()
|
||||||
|
defer sftp.Close()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(fileSize)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
tmp, err := ioutil.TempFile("", "sftptest")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
tmp.Close()
|
||||||
|
defer os.Remove(tmp.Name())
|
||||||
|
|
||||||
|
dst, err := sftp.Create(tmp.Name())
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
src, err := os.Open(srcFilename)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
n, err := io.Copy(dst, src)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("copy error: %v", err)
|
||||||
|
}
|
||||||
|
if n < fileSize {
|
||||||
|
b.Fatal("unable to copy all bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(tmp.Name())
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Size() != fileSize {
|
||||||
|
b.Fatalf("wrong file size: want %d, got %d", fileSize, fi.Size())
|
||||||
|
}
|
||||||
|
os.Remove(tmp.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyUp10MiBDelay10Msec(b *testing.B) {
|
||||||
|
benchmarkCopyUp(b, 10*1024*1024, 10*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyUp10MiBDelay50Msec(b *testing.B) {
|
||||||
|
benchmarkCopyUp(b, 10*1024*1024, 50*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCopyUp10MiBDelay150Msec(b *testing.B) {
|
||||||
|
benchmarkCopyUp(b, 10*1024*1024, 150*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go
generated
vendored
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go
generated
vendored
@ -22,6 +22,7 @@ var (
|
|||||||
HOST = flag.String("host", "localhost", "ssh server hostname")
|
HOST = flag.String("host", "localhost", "ssh server hostname")
|
||||||
PORT = flag.Int("port", 22, "ssh server port")
|
PORT = flag.Int("port", 22, "ssh server port")
|
||||||
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
||||||
|
SIZE = flag.Int("s", 1<<15, "set max packet size")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -49,7 +50,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err := sftp.NewClient(conn)
|
c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to start sftp subsytem: %v", err)
|
log.Fatalf("unable to start sftp subsytem: %v", err)
|
||||||
}
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go
generated
vendored
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go
generated
vendored
@ -22,6 +22,7 @@ var (
|
|||||||
HOST = flag.String("host", "localhost", "ssh server hostname")
|
HOST = flag.String("host", "localhost", "ssh server hostname")
|
||||||
PORT = flag.Int("port", 22, "ssh server port")
|
PORT = flag.Int("port", 22, "ssh server port")
|
||||||
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
||||||
|
SIZE = flag.Int("s", 1<<15, "set max packet size")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -49,7 +50,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err := sftp.NewClient(conn)
|
c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to start sftp subsytem: %v", err)
|
log.Fatalf("unable to start sftp subsytem: %v", err)
|
||||||
}
|
}
|
||||||
|
147
Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go
generated
vendored
147
Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go
generated
vendored
@ -1,147 +0,0 @@
|
|||||||
// gsftp implements a simple sftp client.
|
|
||||||
//
|
|
||||||
// gsftp understands the following commands:
|
|
||||||
//
|
|
||||||
// List a directory (and its subdirectories)
|
|
||||||
// gsftp ls DIR
|
|
||||||
//
|
|
||||||
// Fetch a remote file
|
|
||||||
// gsftp fetch FILE
|
|
||||||
//
|
|
||||||
// Put the contents of stdin to a remote file
|
|
||||||
// cat LOCALFILE | gsftp put REMOTEFILE
|
|
||||||
//
|
|
||||||
// Print the details of a remote file
|
|
||||||
// gsftp stat FILE
|
|
||||||
//
|
|
||||||
// Remove a remote file
|
|
||||||
// gsftp rm FILE
|
|
||||||
//
|
|
||||||
// Rename a file
|
|
||||||
// gsftp mv OLD NEW
|
|
||||||
//
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
"golang.org/x/crypto/ssh/agent"
|
|
||||||
|
|
||||||
"github.com/pkg/sftp"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
USER = flag.String("user", os.Getenv("USER"), "ssh username")
|
|
||||||
HOST = flag.String("host", "localhost", "ssh server hostname")
|
|
||||||
PORT = flag.Int("port", 22, "ssh server port")
|
|
||||||
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.Parse()
|
|
||||||
if len(flag.Args()) < 1 {
|
|
||||||
log.Fatal("subcommand required")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var auths []ssh.AuthMethod
|
|
||||||
if aconn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
|
|
||||||
auths = append(auths, ssh.PublicKeysCallback(agent.NewClient(aconn).Signers))
|
|
||||||
|
|
||||||
}
|
|
||||||
if *PASS != "" {
|
|
||||||
auths = append(auths, ssh.Password(*PASS))
|
|
||||||
}
|
|
||||||
|
|
||||||
config := ssh.ClientConfig{
|
|
||||||
User: *USER,
|
|
||||||
Auth: auths,
|
|
||||||
}
|
|
||||||
addr := fmt.Sprintf("%s:%d", *HOST, *PORT)
|
|
||||||
conn, err := ssh.Dial("tcp", addr, &config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("unable to connect to [%s]: %v", addr, err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
client, err := sftp.NewClient(conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("unable to start sftp subsytem: %v", err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
switch cmd := flag.Args()[0]; cmd {
|
|
||||||
case "ls":
|
|
||||||
if len(flag.Args()) < 2 {
|
|
||||||
log.Fatalf("%s %s: remote path required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
walker := client.Walk(flag.Args()[1])
|
|
||||||
for walker.Step() {
|
|
||||||
if err := walker.Err(); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Println(walker.Path())
|
|
||||||
}
|
|
||||||
case "fetch":
|
|
||||||
if len(flag.Args()) < 2 {
|
|
||||||
log.Fatalf("%s %s: remote path required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
f, err := client.Open(flag.Args()[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if _, err := io.Copy(os.Stdout, f); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
case "put":
|
|
||||||
if len(flag.Args()) < 2 {
|
|
||||||
log.Fatalf("%s %s: remote path required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
f, err := client.Create(flag.Args()[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if _, err := io.Copy(f, os.Stdin); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
case "stat":
|
|
||||||
if len(flag.Args()) < 2 {
|
|
||||||
log.Fatalf("%s %s: remote path required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
f, err := client.Open(flag.Args()[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
fi, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("unable to stat file: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("%s %d %v\n", fi.Name(), fi.Size(), fi.Mode())
|
|
||||||
case "rm":
|
|
||||||
if len(flag.Args()) < 2 {
|
|
||||||
log.Fatalf("%s %s: remote path required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
if err := client.Remove(flag.Args()[1]); err != nil {
|
|
||||||
log.Fatalf("unable to remove file: %v", err)
|
|
||||||
}
|
|
||||||
case "mv":
|
|
||||||
if len(flag.Args()) < 3 {
|
|
||||||
log.Fatalf("%s %s: old and new name required", cmd, os.Args[0])
|
|
||||||
}
|
|
||||||
if err := client.Rename(flag.Args()[1], flag.Args()[2]); err != nil {
|
|
||||||
log.Fatalf("unable to rename file: %v", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatalf("unknown subcommand: %v", cmd)
|
|
||||||
}
|
|
||||||
}
|
|
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go
generated
vendored
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go
generated
vendored
@ -23,6 +23,7 @@ var (
|
|||||||
HOST = flag.String("host", "localhost", "ssh server hostname")
|
HOST = flag.String("host", "localhost", "ssh server hostname")
|
||||||
PORT = flag.Int("port", 22, "ssh server port")
|
PORT = flag.Int("port", 22, "ssh server port")
|
||||||
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
||||||
|
SIZE = flag.Int("s", 1<<15, "set max packet size")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -50,7 +51,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err := sftp.NewClient(conn)
|
c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to start sftp subsytem: %v", err)
|
log.Fatalf("unable to start sftp subsytem: %v", err)
|
||||||
}
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go
generated
vendored
3
Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go
generated
vendored
@ -23,6 +23,7 @@ var (
|
|||||||
HOST = flag.String("host", "localhost", "ssh server hostname")
|
HOST = flag.String("host", "localhost", "ssh server hostname")
|
||||||
PORT = flag.Int("port", 22, "ssh server port")
|
PORT = flag.Int("port", 22, "ssh server port")
|
||||||
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
PASS = flag.String("pass", os.Getenv("SOCKSIE_SSH_PASSWORD"), "ssh password")
|
||||||
|
SIZE = flag.Int("s", 1<<15, "set max packet size")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -50,7 +51,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err := sftp.NewClient(conn)
|
c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to start sftp subsytem: %v", err)
|
log.Fatalf("unable to start sftp subsytem: %v", err)
|
||||||
}
|
}
|
||||||
|
72
Godeps/_workspace/src/github.com/pkg/sftp/packet.go
generated
vendored
72
Godeps/_workspace/src/github.com/pkg/sftp/packet.go
generated
vendored
@ -64,7 +64,6 @@ func unmarshalString(b []byte) (string, []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sendPacket marshals p according to RFC 4234.
|
// sendPacket marshals p according to RFC 4234.
|
||||||
|
|
||||||
func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error {
|
func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error {
|
||||||
bb, err := m.MarshalBinary()
|
bb, err := m.MarshalBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -142,6 +141,8 @@ func (p sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
|
|||||||
return marshalIdString(ssh_FXP_READDIR, p.Id, p.Handle)
|
return marshalIdString(ssh_FXP_READDIR, p.Id, p.Handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpReaddirPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
type sshFxpOpendirPacket struct {
|
type sshFxpOpendirPacket struct {
|
||||||
Id uint32
|
Id uint32
|
||||||
Path string
|
Path string
|
||||||
@ -151,11 +152,15 @@ func (p sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
|
|||||||
return marshalIdString(ssh_FXP_OPENDIR, p.Id, p.Path)
|
return marshalIdString(ssh_FXP_OPENDIR, p.Id, p.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpOpendirPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
type sshFxpLstatPacket struct {
|
type sshFxpLstatPacket struct {
|
||||||
Id uint32
|
Id uint32
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpLstatPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
|
||||||
return marshalIdString(ssh_FXP_LSTAT, p.Id, p.Path)
|
return marshalIdString(ssh_FXP_LSTAT, p.Id, p.Path)
|
||||||
}
|
}
|
||||||
@ -165,6 +170,8 @@ type sshFxpFstatPacket struct {
|
|||||||
Handle string
|
Handle string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpFstatPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
|
||||||
return marshalIdString(ssh_FXP_FSTAT, p.Id, p.Handle)
|
return marshalIdString(ssh_FXP_FSTAT, p.Id, p.Handle)
|
||||||
}
|
}
|
||||||
@ -178,11 +185,15 @@ func (p sshFxpClosePacket) MarshalBinary() ([]byte, error) {
|
|||||||
return marshalIdString(ssh_FXP_CLOSE, p.Id, p.Handle)
|
return marshalIdString(ssh_FXP_CLOSE, p.Id, p.Handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpClosePacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
type sshFxpRemovePacket struct {
|
type sshFxpRemovePacket struct {
|
||||||
Id uint32
|
Id uint32
|
||||||
Filename string
|
Filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpRemovePacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
|
||||||
return marshalIdString(ssh_FXP_REMOVE, p.Id, p.Filename)
|
return marshalIdString(ssh_FXP_REMOVE, p.Id, p.Filename)
|
||||||
}
|
}
|
||||||
@ -192,6 +203,8 @@ type sshFxpRmdirPacket struct {
|
|||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpRmdirPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
|
||||||
return marshalIdString(ssh_FXP_RMDIR, p.Id, p.Path)
|
return marshalIdString(ssh_FXP_RMDIR, p.Id, p.Path)
|
||||||
}
|
}
|
||||||
@ -201,6 +214,8 @@ type sshFxpReadlinkPacket struct {
|
|||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpReadlinkPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
|
||||||
return marshalIdString(ssh_FXP_READLINK, p.Id, p.Path)
|
return marshalIdString(ssh_FXP_READLINK, p.Id, p.Path)
|
||||||
}
|
}
|
||||||
@ -212,6 +227,8 @@ type sshFxpOpenPacket struct {
|
|||||||
Flags uint32 // ignored
|
Flags uint32 // ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpOpenPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 +
|
l := 1 + 4 +
|
||||||
4 + len(p.Path) +
|
4 + len(p.Path) +
|
||||||
@ -233,6 +250,8 @@ type sshFxpReadPacket struct {
|
|||||||
Len uint32
|
Len uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpReadPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 + // type(byte) + uint32
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
4 + len(p.Handle) +
|
4 + len(p.Handle) +
|
||||||
@ -253,6 +272,8 @@ type sshFxpRenamePacket struct {
|
|||||||
Newpath string
|
Newpath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpRenamePacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 + // type(byte) + uint32
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
4 + len(p.Oldpath) +
|
4 + len(p.Oldpath) +
|
||||||
@ -274,6 +295,8 @@ type sshFxpWritePacket struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s sshFxpWritePacket) id() uint32 { return s.Id }
|
||||||
|
|
||||||
func (s sshFxpWritePacket) MarshalBinary() ([]byte, error) {
|
func (s sshFxpWritePacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 + // type(byte) + uint32
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
4 + len(s.Handle) +
|
4 + len(s.Handle) +
|
||||||
@ -296,6 +319,8 @@ type sshFxpMkdirPacket struct {
|
|||||||
Flags uint32 // ignored
|
Flags uint32 // ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpMkdirPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 + // type(byte) + uint32
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
4 + len(p.Path) +
|
4 + len(p.Path) +
|
||||||
@ -316,6 +341,8 @@ type sshFxpSetstatPacket struct {
|
|||||||
Attrs interface{}
|
Attrs interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p sshFxpSetstatPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
|
func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
|
||||||
l := 1 + 4 + // type(byte) + uint32
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
4 + len(p.Path) +
|
4 + len(p.Path) +
|
||||||
@ -329,3 +356,46 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
|
|||||||
b = marshal(b, p.Attrs)
|
b = marshal(b, p.Attrs)
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sshFxpStatvfsPacket struct {
|
||||||
|
Id uint32
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p sshFxpStatvfsPacket) id() uint32 { return p.Id }
|
||||||
|
|
||||||
|
func (p sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
|
||||||
|
l := 1 + 4 + // type(byte) + uint32
|
||||||
|
len(p.Path) +
|
||||||
|
len("statvfs@openssh.com")
|
||||||
|
|
||||||
|
b := make([]byte, 0, l)
|
||||||
|
b = append(b, ssh_FXP_EXTENDED)
|
||||||
|
b = marshalUint32(b, p.Id)
|
||||||
|
b = marshalString(b, "statvfs@openssh.com")
|
||||||
|
b = marshalString(b, p.Path)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatVFS struct {
|
||||||
|
Id uint32
|
||||||
|
Bsize uint64 /* file system block size */
|
||||||
|
Frsize uint64 /* fundamental fs block size */
|
||||||
|
Blocks uint64 /* number of blocks (unit f_frsize) */
|
||||||
|
Bfree uint64 /* free blocks in file system */
|
||||||
|
Bavail uint64 /* free blocks for non-root */
|
||||||
|
Files uint64 /* total file inodes */
|
||||||
|
Ffree uint64 /* free file inodes */
|
||||||
|
Favail uint64 /* free file inodes for to non-root */
|
||||||
|
Fsid uint64 /* file system id */
|
||||||
|
Flag uint64 /* bit mask of f_flag values */
|
||||||
|
Namemax uint64 /* maximum filename length */
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StatVFS) TotalSpace() uint64 {
|
||||||
|
return p.Frsize * p.Blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *StatVFS) FreeSpace() uint64 {
|
||||||
|
return p.Frsize * p.Bfree
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
@ -16,7 +16,7 @@ Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
|||||||
choose, you can pass the `New` functions from the different SHA packages to
|
choose, you can pass the `New` functions from the different SHA packages to
|
||||||
pbkdf2.Key.
|
pbkdf2.Key.
|
||||||
*/
|
*/
|
||||||
package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
|
package pbkdf2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go
generated
vendored
@ -16,7 +16,7 @@ used with a fixed key in order to generate one-time keys from an nonce.
|
|||||||
However, in this package AES isn't used and the one-time key is specified
|
However, in this package AES isn't used and the one-time key is specified
|
||||||
directly.
|
directly.
|
||||||
*/
|
*/
|
||||||
package poly1305 // import "golang.org/x/crypto/poly1305"
|
package poly1305
|
||||||
|
|
||||||
import "crypto/subtle"
|
import "crypto/subtle"
|
||||||
|
|
||||||
|
333
Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s
generated
vendored
Normal file
333
Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s
generated
vendored
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// This code was translated into a form compatible with 5a from the public
|
||||||
|
// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
|
||||||
|
|
||||||
|
// +build arm,!gccgo,!appengine
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
|
||||||
|
DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
|
||||||
|
DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
|
||||||
|
DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
|
||||||
|
DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
|
||||||
|
GLOBL poly1305_init_constants_armv6<>(SB), RODATA, $20
|
||||||
|
|
||||||
|
// Warning: the linker may use R11 to synthesize certain instructions. Please
|
||||||
|
// take care and verify that no synthetic instructions use it.
|
||||||
|
|
||||||
|
TEXT poly1305_init_ext_armv6<>(SB),NOSPLIT,$-4
|
||||||
|
MOVM.DB.W [R4-R11], (R13)
|
||||||
|
MOVM.IA.W (R1), [R2-R5]
|
||||||
|
MOVW $poly1305_init_constants_armv6<>(SB), R7
|
||||||
|
MOVW R2, R8
|
||||||
|
MOVW R2>>26, R9
|
||||||
|
MOVW R3>>20, g
|
||||||
|
MOVW R4>>14, R11
|
||||||
|
MOVW R5>>8, R12
|
||||||
|
ORR R3<<6, R9, R9
|
||||||
|
ORR R4<<12, g, g
|
||||||
|
ORR R5<<18, R11, R11
|
||||||
|
MOVM.IA (R7), [R2-R6]
|
||||||
|
AND R8, R2, R2
|
||||||
|
AND R9, R3, R3
|
||||||
|
AND g, R4, R4
|
||||||
|
AND R11, R5, R5
|
||||||
|
AND R12, R6, R6
|
||||||
|
MOVM.IA.W [R2-R6], (R0)
|
||||||
|
EOR R2, R2, R2
|
||||||
|
EOR R3, R3, R3
|
||||||
|
EOR R4, R4, R4
|
||||||
|
EOR R5, R5, R5
|
||||||
|
EOR R6, R6, R6
|
||||||
|
MOVM.IA.W [R2-R6], (R0)
|
||||||
|
MOVM.IA.W (R1), [R2-R5]
|
||||||
|
MOVM.IA [R2-R6], (R0)
|
||||||
|
MOVM.IA.W (R13), [R4-R11]
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT poly1305_blocks_armv6<>(SB),NOSPLIT,$-4
|
||||||
|
MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
|
||||||
|
SUB $128, R13
|
||||||
|
MOVW R0, 36(R13)
|
||||||
|
MOVW R1, 40(R13)
|
||||||
|
MOVW R2, 44(R13)
|
||||||
|
MOVW R1, R14
|
||||||
|
MOVW R2, R12
|
||||||
|
MOVW 56(R0), R8
|
||||||
|
WORD $0xe1180008 // TST R8, R8 not working see issue 5921
|
||||||
|
EOR R6, R6, R6
|
||||||
|
MOVW.EQ $(1<<24), R6
|
||||||
|
MOVW R6, 32(R13)
|
||||||
|
ADD $64, R13, g
|
||||||
|
MOVM.IA (R0), [R0-R9]
|
||||||
|
MOVM.IA [R0-R4], (g)
|
||||||
|
CMP $16, R12
|
||||||
|
BLO poly1305_blocks_armv6_done
|
||||||
|
poly1305_blocks_armv6_mainloop:
|
||||||
|
MOVM.IA.W (R14), [R0-R3]
|
||||||
|
MOVW R0>>26, g
|
||||||
|
MOVW R1>>20, R11
|
||||||
|
MOVW R2>>14, R12
|
||||||
|
MOVW R14, 40(R13)
|
||||||
|
MOVW R3>>8, R4
|
||||||
|
ORR R1<<6, g, g
|
||||||
|
ORR R2<<12, R11, R11
|
||||||
|
ORR R3<<18, R12, R12
|
||||||
|
BIC $0xfc000000, R0, R0
|
||||||
|
BIC $0xfc000000, g, g
|
||||||
|
MOVW 32(R13), R3
|
||||||
|
BIC $0xfc000000, R11, R11
|
||||||
|
BIC $0xfc000000, R12, R12
|
||||||
|
ADD R0, R5, R5
|
||||||
|
ADD g, R6, R6
|
||||||
|
ORR R3, R4, R4
|
||||||
|
ADD R11, R7, R7
|
||||||
|
ADD $64, R13, R14
|
||||||
|
ADD R12, R8, R8
|
||||||
|
ADD R4, R9, R9
|
||||||
|
MOVM.IA (R14), [R0-R4]
|
||||||
|
MULLU R4, R5, (R11, g)
|
||||||
|
MULLU R3, R5, (R14, R12)
|
||||||
|
MULALU R3, R6, (R11, g)
|
||||||
|
MULALU R2, R6, (R14, R12)
|
||||||
|
MULALU R2, R7, (R11, g)
|
||||||
|
MULALU R1, R7, (R14, R12)
|
||||||
|
ADD R4<<2, R4, R4
|
||||||
|
ADD R3<<2, R3, R3
|
||||||
|
MULALU R1, R8, (R11, g)
|
||||||
|
MULALU R0, R8, (R14, R12)
|
||||||
|
MULALU R0, R9, (R11, g)
|
||||||
|
MULALU R4, R9, (R14, R12)
|
||||||
|
MOVW g, 24(R13)
|
||||||
|
MOVW R11, 28(R13)
|
||||||
|
MOVW R12, 16(R13)
|
||||||
|
MOVW R14, 20(R13)
|
||||||
|
MULLU R2, R5, (R11, g)
|
||||||
|
MULLU R1, R5, (R14, R12)
|
||||||
|
MULALU R1, R6, (R11, g)
|
||||||
|
MULALU R0, R6, (R14, R12)
|
||||||
|
MULALU R0, R7, (R11, g)
|
||||||
|
MULALU R4, R7, (R14, R12)
|
||||||
|
ADD R2<<2, R2, R2
|
||||||
|
ADD R1<<2, R1, R1
|
||||||
|
MULALU R4, R8, (R11, g)
|
||||||
|
MULALU R3, R8, (R14, R12)
|
||||||
|
MULALU R3, R9, (R11, g)
|
||||||
|
MULALU R2, R9, (R14, R12)
|
||||||
|
MOVW g, 8(R13)
|
||||||
|
MOVW R11, 12(R13)
|
||||||
|
MOVW R12, 0(R13)
|
||||||
|
MOVW R14, w+4(SP)
|
||||||
|
MULLU R0, R5, (R11, g)
|
||||||
|
MULALU R4, R6, (R11, g)
|
||||||
|
MULALU R3, R7, (R11, g)
|
||||||
|
MULALU R2, R8, (R11, g)
|
||||||
|
MULALU R1, R9, (R11, g)
|
||||||
|
MOVM.IA (R13), [R0-R7]
|
||||||
|
MOVW g>>26, R12
|
||||||
|
MOVW R4>>26, R14
|
||||||
|
ORR R11<<6, R12, R12
|
||||||
|
ORR R5<<6, R14, R14
|
||||||
|
BIC $0xfc000000, g, g
|
||||||
|
BIC $0xfc000000, R4, R4
|
||||||
|
ADD.S R12, R0, R0
|
||||||
|
ADC $0, R1, R1
|
||||||
|
ADD.S R14, R6, R6
|
||||||
|
ADC $0, R7, R7
|
||||||
|
MOVW R0>>26, R12
|
||||||
|
MOVW R6>>26, R14
|
||||||
|
ORR R1<<6, R12, R12
|
||||||
|
ORR R7<<6, R14, R14
|
||||||
|
BIC $0xfc000000, R0, R0
|
||||||
|
BIC $0xfc000000, R6, R6
|
||||||
|
ADD R14<<2, R14, R14
|
||||||
|
ADD.S R12, R2, R2
|
||||||
|
ADC $0, R3, R3
|
||||||
|
ADD R14, g, g
|
||||||
|
MOVW R2>>26, R12
|
||||||
|
MOVW g>>26, R14
|
||||||
|
ORR R3<<6, R12, R12
|
||||||
|
BIC $0xfc000000, g, R5
|
||||||
|
BIC $0xfc000000, R2, R7
|
||||||
|
ADD R12, R4, R4
|
||||||
|
ADD R14, R0, R0
|
||||||
|
MOVW R4>>26, R12
|
||||||
|
BIC $0xfc000000, R4, R8
|
||||||
|
ADD R12, R6, R9
|
||||||
|
MOVW w+44(SP), R12
|
||||||
|
MOVW w+40(SP), R14
|
||||||
|
MOVW R0, R6
|
||||||
|
CMP $32, R12
|
||||||
|
SUB $16, R12, R12
|
||||||
|
MOVW R12, 44(R13)
|
||||||
|
BHS poly1305_blocks_armv6_mainloop
|
||||||
|
poly1305_blocks_armv6_done:
|
||||||
|
MOVW 36(R13), R12
|
||||||
|
MOVW R5, 20(R12)
|
||||||
|
MOVW R6, 24(R12)
|
||||||
|
MOVW R7, 28(R12)
|
||||||
|
MOVW R8, 32(R12)
|
||||||
|
MOVW R9, 36(R12)
|
||||||
|
ADD $128, R13, R13
|
||||||
|
MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT poly1305_finish_ext_armv6<>(SB),NOSPLIT,$-4
|
||||||
|
MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
|
||||||
|
SUB $16, R13, R13
|
||||||
|
MOVW R0, R5
|
||||||
|
MOVW R1, R6
|
||||||
|
MOVW R2, R7
|
||||||
|
MOVW R3, R8
|
||||||
|
AND.S R2, R2, R2
|
||||||
|
BEQ poly1305_finish_ext_armv6_noremaining
|
||||||
|
EOR R0, R0
|
||||||
|
MOVW R13, R9
|
||||||
|
MOVW R0, 0(R13)
|
||||||
|
MOVW R0, 4(R13)
|
||||||
|
MOVW R0, 8(R13)
|
||||||
|
MOVW R0, 12(R13)
|
||||||
|
WORD $0xe3120008 // TST R2, #8 not working see issue 5921
|
||||||
|
BEQ poly1305_finish_ext_armv6_skip8
|
||||||
|
MOVM.IA.W (R1), [g-R11]
|
||||||
|
MOVM.IA.W [g-R11], (R9)
|
||||||
|
poly1305_finish_ext_armv6_skip8:
|
||||||
|
WORD $0xe3120004 // TST $4, R2 not working see issue 5921
|
||||||
|
BEQ poly1305_finish_ext_armv6_skip4
|
||||||
|
MOVW.P 4(R1), g
|
||||||
|
MOVW.P g, 4(R9)
|
||||||
|
poly1305_finish_ext_armv6_skip4:
|
||||||
|
WORD $0xe3120002 // TST $2, R2 not working see issue 5921
|
||||||
|
BEQ poly1305_finish_ext_armv6_skip2
|
||||||
|
MOVHU.P 2(R1), g
|
||||||
|
MOVH.P g, 2(R9)
|
||||||
|
poly1305_finish_ext_armv6_skip2:
|
||||||
|
WORD $0xe3120001 // TST $1, R2 not working see issue 5921
|
||||||
|
BEQ poly1305_finish_ext_armv6_skip1
|
||||||
|
MOVBU.P 1(R1), g
|
||||||
|
MOVBU.P g, 1(R9)
|
||||||
|
poly1305_finish_ext_armv6_skip1:
|
||||||
|
MOVW $1, R11
|
||||||
|
MOVBU R11, 0(R9)
|
||||||
|
MOVW R11, 56(R5)
|
||||||
|
MOVW R5, R0
|
||||||
|
MOVW R13, R1
|
||||||
|
MOVW $16, R2
|
||||||
|
BL poly1305_blocks_armv6<>(SB)
|
||||||
|
poly1305_finish_ext_armv6_noremaining:
|
||||||
|
MOVW 20(R5), R0
|
||||||
|
MOVW 24(R5), R1
|
||||||
|
MOVW 28(R5), R2
|
||||||
|
MOVW 32(R5), R3
|
||||||
|
MOVW 36(R5), R4
|
||||||
|
MOVW R4>>26, R12
|
||||||
|
BIC $0xfc000000, R4, R4
|
||||||
|
ADD R12<<2, R12, R12
|
||||||
|
ADD R12, R0, R0
|
||||||
|
MOVW R0>>26, R12
|
||||||
|
BIC $0xfc000000, R0, R0
|
||||||
|
ADD R12, R1, R1
|
||||||
|
MOVW R1>>26, R12
|
||||||
|
BIC $0xfc000000, R1, R1
|
||||||
|
ADD R12, R2, R2
|
||||||
|
MOVW R2>>26, R12
|
||||||
|
BIC $0xfc000000, R2, R2
|
||||||
|
ADD R12, R3, R3
|
||||||
|
MOVW R3>>26, R12
|
||||||
|
BIC $0xfc000000, R3, R3
|
||||||
|
ADD R12, R4, R4
|
||||||
|
ADD $5, R0, R6
|
||||||
|
MOVW R6>>26, R12
|
||||||
|
BIC $0xfc000000, R6, R6
|
||||||
|
ADD R12, R1, R7
|
||||||
|
MOVW R7>>26, R12
|
||||||
|
BIC $0xfc000000, R7, R7
|
||||||
|
ADD R12, R2, g
|
||||||
|
MOVW g>>26, R12
|
||||||
|
BIC $0xfc000000, g, g
|
||||||
|
ADD R12, R3, R11
|
||||||
|
MOVW $-(1<<26), R12
|
||||||
|
ADD R11>>26, R12, R12
|
||||||
|
BIC $0xfc000000, R11, R11
|
||||||
|
ADD R12, R4, R14
|
||||||
|
MOVW R14>>31, R12
|
||||||
|
SUB $1, R12
|
||||||
|
AND R12, R6, R6
|
||||||
|
AND R12, R7, R7
|
||||||
|
AND R12, g, g
|
||||||
|
AND R12, R11, R11
|
||||||
|
AND R12, R14, R14
|
||||||
|
MVN R12, R12
|
||||||
|
AND R12, R0, R0
|
||||||
|
AND R12, R1, R1
|
||||||
|
AND R12, R2, R2
|
||||||
|
AND R12, R3, R3
|
||||||
|
AND R12, R4, R4
|
||||||
|
ORR R6, R0, R0
|
||||||
|
ORR R7, R1, R1
|
||||||
|
ORR g, R2, R2
|
||||||
|
ORR R11, R3, R3
|
||||||
|
ORR R14, R4, R4
|
||||||
|
ORR R1<<26, R0, R0
|
||||||
|
MOVW R1>>6, R1
|
||||||
|
ORR R2<<20, R1, R1
|
||||||
|
MOVW R2>>12, R2
|
||||||
|
ORR R3<<14, R2, R2
|
||||||
|
MOVW R3>>18, R3
|
||||||
|
ORR R4<<8, R3, R3
|
||||||
|
MOVW 40(R5), R6
|
||||||
|
MOVW 44(R5), R7
|
||||||
|
MOVW 48(R5), g
|
||||||
|
MOVW 52(R5), R11
|
||||||
|
ADD.S R6, R0, R0
|
||||||
|
ADC.S R7, R1, R1
|
||||||
|
ADC.S g, R2, R2
|
||||||
|
ADC.S R11, R3, R3
|
||||||
|
MOVM.IA [R0-R3], (R8)
|
||||||
|
MOVW R5, R12
|
||||||
|
EOR R0, R0, R0
|
||||||
|
EOR R1, R1, R1
|
||||||
|
EOR R2, R2, R2
|
||||||
|
EOR R3, R3, R3
|
||||||
|
EOR R4, R4, R4
|
||||||
|
EOR R5, R5, R5
|
||||||
|
EOR R6, R6, R6
|
||||||
|
EOR R7, R7, R7
|
||||||
|
MOVM.IA.W [R0-R7], (R12)
|
||||||
|
MOVM.IA [R0-R7], (R12)
|
||||||
|
ADD $16, R13, R13
|
||||||
|
MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
|
||||||
|
TEXT ·poly1305_auth_armv6(SB),0,$280-16
|
||||||
|
MOVW out+0(FP), R4
|
||||||
|
MOVW m+4(FP), R5
|
||||||
|
MOVW mlen+8(FP), R6
|
||||||
|
MOVW key+12(FP), R7
|
||||||
|
|
||||||
|
MOVW R13, R8
|
||||||
|
BIC $63, R13
|
||||||
|
SUB $64, R13, R13
|
||||||
|
MOVW R13, R0
|
||||||
|
MOVW R7, R1
|
||||||
|
BL poly1305_init_ext_armv6<>(SB)
|
||||||
|
BIC.S $15, R6, R2
|
||||||
|
BEQ poly1305_auth_armv6_noblocks
|
||||||
|
MOVW R13, R0
|
||||||
|
MOVW R5, R1
|
||||||
|
ADD R2, R5, R5
|
||||||
|
SUB R2, R6, R6
|
||||||
|
BL poly1305_blocks_armv6<>(SB)
|
||||||
|
poly1305_auth_armv6_noblocks:
|
||||||
|
MOVW R13, R0
|
||||||
|
MOVW R5, R1
|
||||||
|
MOVW R6, R2
|
||||||
|
MOVW R4, R3
|
||||||
|
BL poly1305_finish_ext_armv6<>(SB)
|
||||||
|
MOVW R8, R13
|
||||||
|
RET
|
24
Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
Normal file
24
Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build arm,!gccgo,!appengine
|
||||||
|
|
||||||
|
package poly1305
|
||||||
|
|
||||||
|
// This function is implemented in poly1305_arm.s
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
|
||||||
|
|
||||||
|
// Sum generates an authenticator for m using a one-time key and puts the
|
||||||
|
// 16-byte result into out. Authenticating two different messages with the same
|
||||||
|
// key allows an attacker to forge messages at will.
|
||||||
|
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
||||||
|
var mPtr *byte
|
||||||
|
if len(m) > 0 {
|
||||||
|
mPtr = &m[0]
|
||||||
|
}
|
||||||
|
poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
|
||||||
|
}
|
2
Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go
generated
vendored
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !amd64 gccgo appengine
|
// +build !amd64,!arm gccgo appengine
|
||||||
|
|
||||||
package poly1305
|
package poly1305
|
||||||
|
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go
generated
vendored
@ -5,7 +5,7 @@
|
|||||||
// Package scrypt implements the scrypt key derivation function as defined in
|
// Package scrypt implements the scrypt key derivation function as defined in
|
||||||
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
|
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
|
||||||
// Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf).
|
// Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf).
|
||||||
package scrypt // import "golang.org/x/crypto/scrypt"
|
package scrypt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go
generated
vendored
@ -8,7 +8,7 @@
|
|||||||
References:
|
References:
|
||||||
[PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
|
[PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
|
||||||
*/
|
*/
|
||||||
package agent // import "golang.org/x/crypto/ssh/agent"
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go
generated
vendored
@ -368,7 +368,7 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
|
|||||||
if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
|
if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
|
||||||
return fmt.Errorf("ssh: cert is not yet valid")
|
return fmt.Errorf("ssh: cert is not yet valid")
|
||||||
}
|
}
|
||||||
if before := int64(cert.ValidBefore); cert.ValidBefore != CertTimeInfinity && (unixNow >= before || before < 0) {
|
if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
|
||||||
return fmt.Errorf("ssh: cert has expired")
|
return fmt.Errorf("ssh: cert has expired")
|
||||||
}
|
}
|
||||||
if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
|
if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go
generated
vendored
@ -57,7 +57,7 @@ const exampleSSHCertWithOptions = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2Et
|
|||||||
func TestParseCertWithOptions(t *testing.T) {
|
func TestParseCertWithOptions(t *testing.T) {
|
||||||
opts := map[string]string{
|
opts := map[string]string{
|
||||||
"source-address": "192.168.1.0/24",
|
"source-address": "192.168.1.0/24",
|
||||||
"force-command": "/bin/sleep",
|
"force-command": "/bin/sleep",
|
||||||
}
|
}
|
||||||
exts := map[string]string{
|
exts := map[string]string{
|
||||||
"permit-X11-forwarding": "",
|
"permit-X11-forwarding": "",
|
||||||
|
66
Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go
generated
vendored
66
Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go
generated
vendored
@ -14,6 +14,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -350,6 +351,7 @@ func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|||||||
// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
|
// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
|
||||||
type cbcCipher struct {
|
type cbcCipher struct {
|
||||||
mac hash.Hash
|
mac hash.Hash
|
||||||
|
macSize uint32
|
||||||
decrypter cipher.BlockMode
|
decrypter cipher.BlockMode
|
||||||
encrypter cipher.BlockMode
|
encrypter cipher.BlockMode
|
||||||
|
|
||||||
@ -357,6 +359,10 @@ type cbcCipher struct {
|
|||||||
seqNumBytes [4]byte
|
seqNumBytes [4]byte
|
||||||
packetData []byte
|
packetData []byte
|
||||||
macResult []byte
|
macResult []byte
|
||||||
|
|
||||||
|
// Amount of data we should still read to hide which
|
||||||
|
// verification error triggered.
|
||||||
|
oracleCamouflage uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
|
||||||
@ -364,12 +370,18 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &cbcCipher{
|
|
||||||
|
cbc := &cbcCipher{
|
||||||
mac: macModes[algs.MAC].new(macKey),
|
mac: macModes[algs.MAC].new(macKey),
|
||||||
decrypter: cipher.NewCBCDecrypter(c, iv),
|
decrypter: cipher.NewCBCDecrypter(c, iv),
|
||||||
encrypter: cipher.NewCBCEncrypter(c, iv),
|
encrypter: cipher.NewCBCEncrypter(c, iv),
|
||||||
packetData: make([]byte, 1024),
|
packetData: make([]byte, 1024),
|
||||||
}, nil
|
}
|
||||||
|
if cbc.mac != nil {
|
||||||
|
cbc.macSize = uint32(cbc.mac.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func maxUInt32(a, b int) uint32 {
|
func maxUInt32(a, b int) uint32 {
|
||||||
@ -385,42 +397,58 @@ const (
|
|||||||
cbcMinPaddingSize = 4
|
cbcMinPaddingSize = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// cbcError represents a verification error that may leak information.
|
||||||
|
type cbcError string
|
||||||
|
|
||||||
|
func (e cbcError) Error() string { return string(e) }
|
||||||
|
|
||||||
func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
||||||
|
p, err := c.readPacketLeaky(seqNum, r)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(cbcError); ok {
|
||||||
|
// Verification error: read a fixed amount of
|
||||||
|
// data, to make distinguishing between
|
||||||
|
// failing MAC and failing length check more
|
||||||
|
// difficult.
|
||||||
|
io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
|
||||||
blockSize := c.decrypter.BlockSize()
|
blockSize := c.decrypter.BlockSize()
|
||||||
|
|
||||||
// Read the header, which will include some of the subsequent data in the
|
// Read the header, which will include some of the subsequent data in the
|
||||||
// case of block ciphers - this is copied back to the payload later.
|
// case of block ciphers - this is copied back to the payload later.
|
||||||
// How many bytes of payload/padding will be read with this first read.
|
// How many bytes of payload/padding will be read with this first read.
|
||||||
firstBlockLength := (prefixLen + blockSize - 1) / blockSize * blockSize
|
firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
|
||||||
firstBlock := c.packetData[:firstBlockLength]
|
firstBlock := c.packetData[:firstBlockLength]
|
||||||
if _, err := io.ReadFull(r, firstBlock); err != nil {
|
if _, err := io.ReadFull(r, firstBlock); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
|
||||||
|
|
||||||
c.decrypter.CryptBlocks(firstBlock, firstBlock)
|
c.decrypter.CryptBlocks(firstBlock, firstBlock)
|
||||||
length := binary.BigEndian.Uint32(firstBlock[:4])
|
length := binary.BigEndian.Uint32(firstBlock[:4])
|
||||||
if length > maxPacket {
|
if length > maxPacket {
|
||||||
return nil, errors.New("ssh: packet too large")
|
return nil, cbcError("ssh: packet too large")
|
||||||
}
|
}
|
||||||
if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
|
if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
|
||||||
// The minimum size of a packet is 16 (or the cipher block size, whichever
|
// The minimum size of a packet is 16 (or the cipher block size, whichever
|
||||||
// is larger) bytes.
|
// is larger) bytes.
|
||||||
return nil, errors.New("ssh: packet too small")
|
return nil, cbcError("ssh: packet too small")
|
||||||
}
|
}
|
||||||
// The length of the packet (including the length field but not the MAC) must
|
// The length of the packet (including the length field but not the MAC) must
|
||||||
// be a multiple of the block size or 8, whichever is larger.
|
// be a multiple of the block size or 8, whichever is larger.
|
||||||
if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
|
if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
|
||||||
return nil, errors.New("ssh: invalid packet length multiple")
|
return nil, cbcError("ssh: invalid packet length multiple")
|
||||||
}
|
}
|
||||||
|
|
||||||
paddingLength := uint32(firstBlock[4])
|
paddingLength := uint32(firstBlock[4])
|
||||||
if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
|
if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
|
||||||
return nil, errors.New("ssh: invalid packet length")
|
return nil, cbcError("ssh: invalid packet length")
|
||||||
}
|
|
||||||
|
|
||||||
var macSize uint32
|
|
||||||
if c.mac != nil {
|
|
||||||
macSize = uint32(c.mac.Size())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Positions within the c.packetData buffer:
|
// Positions within the c.packetData buffer:
|
||||||
@ -428,7 +456,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|||||||
paddingStart := macStart - paddingLength
|
paddingStart := macStart - paddingLength
|
||||||
|
|
||||||
// Entire packet size, starting before length, ending at end of mac.
|
// Entire packet size, starting before length, ending at end of mac.
|
||||||
entirePacketSize := macStart + macSize
|
entirePacketSize := macStart + c.macSize
|
||||||
|
|
||||||
// Ensure c.packetData is large enough for the entire packet data.
|
// Ensure c.packetData is large enough for the entire packet data.
|
||||||
if uint32(cap(c.packetData)) < entirePacketSize {
|
if uint32(cap(c.packetData)) < entirePacketSize {
|
||||||
@ -440,8 +468,10 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|||||||
c.packetData = c.packetData[:entirePacketSize]
|
c.packetData = c.packetData[:entirePacketSize]
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
|
if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
c.oracleCamouflage -= uint32(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingCrypted := c.packetData[firstBlockLength:macStart]
|
remainingCrypted := c.packetData[firstBlockLength:macStart]
|
||||||
@ -455,7 +485,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
|||||||
c.mac.Write(c.packetData[:macStart])
|
c.mac.Write(c.packetData[:macStart])
|
||||||
c.macResult = c.mac.Sum(c.macResult[:0])
|
c.macResult = c.mac.Sum(c.macResult[:0])
|
||||||
if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
|
if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
|
||||||
return nil, errors.New("ssh: MAC failure")
|
return nil, cbcError("ssh: MAC failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,13 +504,9 @@ func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, pack
|
|||||||
length := encLength - 4
|
length := encLength - 4
|
||||||
paddingLength := int(length) - (1 + len(packet))
|
paddingLength := int(length) - (1 + len(packet))
|
||||||
|
|
||||||
var macSize uint32
|
|
||||||
if c.mac != nil {
|
|
||||||
macSize = uint32(c.mac.Size())
|
|
||||||
}
|
|
||||||
// Overall buffer contains: header, payload, padding, mac.
|
// Overall buffer contains: header, payload, padding, mac.
|
||||||
// Space for the MAC is reserved in the capacity but not the slice length.
|
// Space for the MAC is reserved in the capacity but not the slice length.
|
||||||
bufferSize := encLength + macSize
|
bufferSize := encLength + c.macSize
|
||||||
if uint32(cap(c.packetData)) < bufferSize {
|
if uint32(cap(c.packetData)) < bufferSize {
|
||||||
c.packetData = make([]byte, encLength, bufferSize)
|
c.packetData = make([]byte, encLength, bufferSize)
|
||||||
} else {
|
} else {
|
||||||
|
63
Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go
generated
vendored
63
Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go
generated
vendored
@ -62,3 +62,66 @@ func TestPacketCiphers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCBCOracleCounterMeasure(t *testing.T) {
|
||||||
|
cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
|
||||||
|
defer delete(cipherModes, aes128cbcID)
|
||||||
|
|
||||||
|
kr := &kexResult{Hash: crypto.SHA1}
|
||||||
|
algs := directionAlgorithms{
|
||||||
|
Cipher: aes128cbcID,
|
||||||
|
MAC: "hmac-sha1",
|
||||||
|
Compression: "none",
|
||||||
|
}
|
||||||
|
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("newPacketCipher(client): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := "bla bla"
|
||||||
|
input := []byte(want)
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
|
||||||
|
t.Errorf("writePacket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
packetSize := buf.Len()
|
||||||
|
buf.Write(make([]byte, 2*maxPacket))
|
||||||
|
|
||||||
|
// We corrupt each byte, but this usually will only test the
|
||||||
|
// 'packet too large' or 'MAC failure' cases.
|
||||||
|
lastRead := -1
|
||||||
|
for i := 0; i < packetSize; i++ {
|
||||||
|
server, err := newPacketCipher(clientKeys, algs, kr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("newPacketCipher(client): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fresh := &bytes.Buffer{}
|
||||||
|
fresh.Write(buf.Bytes())
|
||||||
|
fresh.Bytes()[i] ^= 0x01
|
||||||
|
|
||||||
|
before := fresh.Len()
|
||||||
|
_, err = server.readPacket(0, fresh)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("corrupt byte %d: readPacket succeeded ", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := err.(cbcError); !ok {
|
||||||
|
t.Errorf("corrupt byte %d: got %v (%T), want cbcError", i, err, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
after := fresh.Len()
|
||||||
|
bytesRead := before - after
|
||||||
|
if bytesRead < maxPacket {
|
||||||
|
t.Errorf("corrupt byte %d: read %d bytes, want more than %d", i, bytesRead, maxPacket)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 && bytesRead != lastRead {
|
||||||
|
t.Errorf("corrupt byte %d: read %d bytes, want %d bytes read", i, bytesRead, lastRead)
|
||||||
|
}
|
||||||
|
lastRead = bytesRead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go
generated
vendored
@ -53,7 +53,7 @@ var supportedHostKeyAlgos = []string{
|
|||||||
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
||||||
// because they have reached the end of their useful life.
|
// because they have reached the end of their useful life.
|
||||||
var supportedMACs = []string{
|
var supportedMACs = []string{
|
||||||
"hmac-sha1", "hmac-sha1-96",
|
"hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
|
||||||
}
|
}
|
||||||
|
|
||||||
var supportedCompressions = []string{compressionNone}
|
var supportedCompressions = []string{compressionNone}
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go
generated
vendored
@ -15,4 +15,4 @@ References:
|
|||||||
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
|
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
|
||||||
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
|
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
|
||||||
*/
|
*/
|
||||||
package ssh // import "golang.org/x/crypto/ssh"
|
package ssh
|
||||||
|
4
Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go
generated
vendored
4
Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go
generated
vendored
@ -9,6 +9,7 @@ package ssh
|
|||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
"hash"
|
"hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,6 +45,9 @@ func (t truncatingMAC) Size() int {
|
|||||||
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
|
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
|
||||||
|
|
||||||
var macModes = map[string]*macMode{
|
var macModes = map[string]*macMode{
|
||||||
|
"hmac-sha2-256": {32, func(key []byte) hash.Hash {
|
||||||
|
return hmac.New(sha256.New, key)
|
||||||
|
}},
|
||||||
"hmac-sha1": {20, func(key []byte) hash.Hash {
|
"hmac-sha1": {20, func(key []byte) hash.Hash {
|
||||||
return hmac.New(sha1.New, key)
|
return hmac.New(sha1.New, key)
|
||||||
}},
|
}},
|
||||||
|
7
Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go
generated
vendored
7
Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go
generated
vendored
@ -484,11 +484,12 @@ func parseString(in []byte) (out, rest []byte, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
length := binary.BigEndian.Uint32(in)
|
length := binary.BigEndian.Uint32(in)
|
||||||
if uint32(len(in)) < 4+length {
|
in = in[4:]
|
||||||
|
if uint32(len(in)) < length {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
out = in[4 : 4+length]
|
out = in[:length]
|
||||||
rest = in[4+length:]
|
rest = in[length:]
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
10
Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go
generated
vendored
10
Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go
generated
vendored
@ -162,6 +162,16 @@ func TestBareMarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalShortKexInitPacket(t *testing.T) {
|
||||||
|
// This used to panic.
|
||||||
|
// Issue 11348
|
||||||
|
packet := []byte{0x14, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xff, 0xff, 0xff}
|
||||||
|
kim := &kexInitMsg{}
|
||||||
|
if err := Unmarshal(packet, kim); err == nil {
|
||||||
|
t.Error("truncated packet unmarshaled without error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func randomBytes(out []byte, rand *rand.Rand) {
|
func randomBytes(out []byte, rand *rand.Rand) {
|
||||||
for i := 0; i < len(out); i++ {
|
for i := 0; i < len(out); i++ {
|
||||||
out[i] = byte(rand.Int31())
|
out[i] = byte(rand.Int31())
|
||||||
|
4
Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go
generated
vendored
4
Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go
generated
vendored
@ -168,6 +168,10 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
|
|||||||
return nil, errors.New("ssh: server has no host keys")
|
return nil, errors.New("ssh: server has no host keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil {
|
||||||
|
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
|
||||||
|
}
|
||||||
|
|
||||||
if config.ServerVersion != "" {
|
if config.ServerVersion != "" {
|
||||||
s.serverVersion = []byte(config.ServerVersion)
|
s.serverVersion = []byte(config.ServerVersion)
|
||||||
} else {
|
} else {
|
||||||
|
40
Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go
generated
vendored
40
Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go
generated
vendored
@ -9,9 +9,11 @@ package ssh
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
crypto_rand "crypto/rand"
|
crypto_rand "crypto/rand"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
@ -678,3 +680,41 @@ func TestSessionID(t *testing.T) {
|
|||||||
t.Errorf("client and server SessionID were empty.")
|
t.Errorf("client and server SessionID were empty.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type noReadConn struct {
|
||||||
|
readSeen bool
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *noReadConn) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *noReadConn) Read(b []byte) (int, error) {
|
||||||
|
c.readSeen = true
|
||||||
|
return 0, errors.New("noReadConn error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidServerConfiguration(t *testing.T) {
|
||||||
|
c1, c2, err := netPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
defer c2.Close()
|
||||||
|
|
||||||
|
serveConn := noReadConn{Conn: c1}
|
||||||
|
serverConf := &ServerConfig{}
|
||||||
|
|
||||||
|
NewServerConn(&serveConn, serverConf)
|
||||||
|
if serveConn.readSeen {
|
||||||
|
t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing host key")
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConf.AddHostKey(testSigners["ecdsa"])
|
||||||
|
|
||||||
|
NewServerConn(&serveConn, serverConf)
|
||||||
|
if serveConn.readSeen {
|
||||||
|
t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing authentication method")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
@ -14,7 +14,7 @@
|
|||||||
// panic(err)
|
// panic(err)
|
||||||
// }
|
// }
|
||||||
// defer terminal.Restore(0, oldState)
|
// defer terminal.Restore(0, oldState)
|
||||||
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
package terminal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go
generated
vendored
@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
// This package contains integration tests for the
|
// This package contains integration tests for the
|
||||||
// golang.org/x/crypto/ssh package.
|
// golang.org/x/crypto/ssh package.
|
||||||
package test // import "golang.org/x/crypto/ssh/test"
|
package test
|
||||||
|
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go
generated
vendored
@ -5,4 +5,4 @@
|
|||||||
// This package contains test data shared between the various subpackages of
|
// This package contains test data shared between the various subpackages of
|
||||||
// the golang.org/x/crypto/ssh package. Under no circumstance should
|
// the golang.org/x/crypto/ssh package. Under no circumstance should
|
||||||
// this data be used for production code.
|
// this data be used for production code.
|
||||||
package testdata // import "golang.org/x/crypto/ssh/testdata"
|
package testdata
|
||||||
|
Loading…
Reference in New Issue
Block a user