From d9a90f7b8972b8d4a4ffb36005c9411ba1ad4ac8 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 28 Jun 2015 16:36:50 +0200 Subject: [PATCH] Update dependencies This, among others, updates the `go-flags` library, which includes a feature that closes #198. --- Godeps/Godeps.json | 22 +- .../jessevdk/go-flags/command_private.go | 25 +- .../jessevdk/go-flags/command_test.go | 50 +- .../github.com/jessevdk/go-flags/convert.go | 20 + .../src/github.com/jessevdk/go-flags/flags.go | 14 +- .../github.com/jessevdk/go-flags/help_test.go | 40 +- .../src/github.com/jessevdk/go-flags/man.go | 54 +- .../github.com/jessevdk/go-flags/option.go | 7 +- .../mitchellh/goamz/testutil/http.go | 180 ---- .../mitchellh/goamz/testutil/suite.go | 30 - .../src/github.com/motain/gocheck/.bzrignore | 3 - .../src/github.com/motain/gocheck/.gitignore | 4 - .../src/github.com/motain/gocheck/LICENSE | 29 - .../src/github.com/motain/gocheck/Makefile | 30 - .../src/github.com/motain/gocheck/TODO | 2 - .../github.com/motain/gocheck/benchmark.go | 136 --- .../motain/gocheck/benchmark_test.go | 75 -- .../motain/gocheck/bootstrap_test.go | 82 -- .../src/github.com/motain/gocheck/checkers.go | 458 --------- .../motain/gocheck/checkers_test.go | 272 ------ .../github.com/motain/gocheck/export_test.go | 9 - .../github.com/motain/gocheck/fixture_test.go | 479 --------- .../motain/gocheck/foundation_test.go | 340 ------- .../src/github.com/motain/gocheck/gocheck.go | 915 ------------------ .../github.com/motain/gocheck/gocheck_test.go | 196 ---- .../src/github.com/motain/gocheck/helpers.go | 221 ----- .../github.com/motain/gocheck/helpers_test.go | 491 ---------- .../src/github.com/motain/gocheck/printer.go | 168 ---- .../github.com/motain/gocheck/printer_test.go | 109 --- .../src/github.com/motain/gocheck/run.go | 152 --- .../src/github.com/motain/gocheck/run_test.go | 397 -------- .../src/github.com/pkg/sftp/client.go | 627 +++++++++--- .../pkg/sftp/client_integration_test.go | 371 ++++++- .../examples/buffered-read-benchmark/main.go | 3 +- .../examples/buffered-write-benchmark/main.go | 3 +- .../pkg/sftp/examples/gsftp/main.go | 147 --- .../examples/streaming-read-benchmark/main.go | 3 +- .../streaming-write-benchmark/main.go | 3 +- .../src/github.com/pkg/sftp/packet.go | 72 +- .../src/golang.org/x/crypto/pbkdf2/pbkdf2.go | 2 +- .../golang.org/x/crypto/poly1305/poly1305.go | 2 +- .../x/crypto/poly1305/poly1305_arm.s | 333 +++++++ .../golang.org/x/crypto/poly1305/sum_arm.go | 24 + .../golang.org/x/crypto/poly1305/sum_ref.go | 2 +- .../src/golang.org/x/crypto/scrypt/scrypt.go | 2 +- .../golang.org/x/crypto/ssh/agent/client.go | 2 +- .../src/golang.org/x/crypto/ssh/certs.go | 2 +- .../src/golang.org/x/crypto/ssh/certs_test.go | 2 +- .../src/golang.org/x/crypto/ssh/cipher.go | 66 +- .../golang.org/x/crypto/ssh/cipher_test.go | 63 ++ .../src/golang.org/x/crypto/ssh/common.go | 2 +- .../src/golang.org/x/crypto/ssh/doc.go | 2 +- .../src/golang.org/x/crypto/ssh/mac.go | 4 + .../src/golang.org/x/crypto/ssh/messages.go | 7 +- .../golang.org/x/crypto/ssh/messages_test.go | 10 + .../src/golang.org/x/crypto/ssh/server.go | 4 + .../golang.org/x/crypto/ssh/session_test.go | 40 + .../golang.org/x/crypto/ssh/terminal/util.go | 2 +- .../src/golang.org/x/crypto/ssh/test/doc.go | 2 +- .../golang.org/x/crypto/ssh/testdata/doc.go | 2 +- 60 files changed, 1627 insertions(+), 5187 deletions(-) delete mode 100644 Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go delete mode 100644 Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/.gitignore delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/LICENSE delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/Makefile delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/TODO delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/checkers.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/export_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/helpers.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/printer.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/run.go delete mode 100644 Godeps/_workspace/src/github.com/motain/gocheck/run_test.go delete mode 100644 Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s create mode 100644 Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index aeeb0b3bb..8a33bddca 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -7,8 +7,8 @@ "Deps": [ { "ImportPath": "github.com/jessevdk/go-flags", - "Comment": "v1-293-g5e11878", - "Rev": "5e118789801496c93ba210d34ef1f2ce5a9173bd" + "Comment": "v1-297-g1b89bf7", + "Rev": "1b89bf73cd2c3a911d7b2a279ab085c4a18cf539" }, { "ImportPath": "github.com/juju/errors", @@ -26,17 +26,9 @@ "ImportPath": "github.com/mitchellh/goamz/s3", "Rev": "caaaea8b30ee15616494ee68abd5d8ebbbef05cf" }, - { - "ImportPath": "github.com/mitchellh/goamz/testutil", - "Rev": "caaaea8b30ee15616494ee68abd5d8ebbbef05cf" - }, - { - "ImportPath": "github.com/motain/gocheck", - "Rev": "9beb271d26e640863a5bf4a3c5ea40ccdd466b84" - }, { "ImportPath": "github.com/pkg/sftp", - "Rev": "506297c9013d2893d5c5daaa9155e7333a1c58de" + "Rev": "518aed2757a65cfa64d4b1b2baf08410f8b7a6bc" }, { "ImportPath": "github.com/vaughan0/go-ini", @@ -44,19 +36,19 @@ }, { "ImportPath": "golang.org/x/crypto/pbkdf2", - "Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248" + "Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e" }, { "ImportPath": "golang.org/x/crypto/poly1305", - "Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248" + "Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e" }, { "ImportPath": "golang.org/x/crypto/scrypt", - "Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248" + "Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e" }, { "ImportPath": "golang.org/x/crypto/ssh", - "Rev": "24ffb5feb3312a39054178a4b0a4554fc2201248" + "Rev": "cc04154d65fb9296747569b107cfd05380b1ea3e" } ] } diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go index 5d30a8afe..82ce7930e 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_private.go @@ -144,6 +144,25 @@ func (c *Command) makeLookup() lookup { 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) { for _, option := range g.options { if option.ShortName != 0 { @@ -156,6 +175,10 @@ func (c *Command) makeLookup() lookup { } }) + if onlyOptions { + return + } + for _, subcommand := range c.commands { ret.commands[subcommand.Name] = subcommand @@ -163,8 +186,6 @@ func (c *Command) makeLookup() lookup { ret.commands[a] = subcommand } } - - return ret } func (c *Command) groupByName(name string) *Group { diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go index a093e1588..1d904ae74 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/command_test.go @@ -95,7 +95,55 @@ func TestCommandFlagOrder2(t *testing.T) { } `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) { diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go index 191b5f4cd..118573736 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/convert.go @@ -312,6 +312,26 @@ func quoteIfNeeded(s string) string { 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) { if len(s) == 0 || s[0] != '"' { return s, nil diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go index 37d331d0a..4ac67931a 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/flags.go @@ -183,12 +183,16 @@ the Commander interface, then its Execute method will be run with the remaining command line arguments. 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 -to specify options from the parent level of the command after the command -name has occurred. Thus, given a top-level option "-v" and a command "add": +command has been specified on the command line, in addition to the options +of all the parent commands. I.e. considering a -v flag on the parser and an +add command, the following are equivalent: - Valid: ./app -v add - Invalid: ./app add -v + ./app -v add + ./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 diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go index c80288301..e10f4b6ba 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/help_test.go @@ -173,6 +173,14 @@ func TestMan(t *testing.T) { tt := time.Now() + var envDefaultName string + + if runtime.GOOS == "windows" { + envDefaultName = "%ENV_DEFAULT%" + } else { + envDefaultName = "$ENV_DEFAULT" + } + expected := fmt.Sprintf(`.TH TestMan 1 "%s" .SH NAME TestMan \- Test manpage generation @@ -182,45 +190,45 @@ TestMan \- Test manpage generation This is a somewhat \fBlonger\fP description of what this does .SH OPTIONS .TP -\fB-v, --verbose\fP +\fB\fB\-v\fR, \fB\-\-verbose\fR\fP Show verbose debug information .TP -\fB-c\fP +\fB\fB\-c\fR\fP Call phone number .TP -\fB--ptrslice\fP +\fB\fB\-\-ptrslice\fR\fP A slice of pointers to string .TP -\fB--empty-description\fP +\fB\fB\-\-empty-description\fR\fP .TP -\fB--default\fP +\fB\fB\-\-default\fR \fP Test default value .TP -\fB--default-array\fP +\fB\fB\-\-default-array\fR \fP Test default array value .TP -\fB--default-map\fP +\fB\fB\-\-default-map\fR \fP Testdefault map value .TP -\fB--env-default1\fP +\fB\fB\-\-env-default1\fR \fP Test env-default1 value .TP -\fB--env-default2\fP +\fB\fB\-\-env-default2\fR \fP Test env-default2 value .TP -\fB--opt-with-arg-name\fP +\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP Option with named argument .TP -\fB-s\fP +\fB\fB\-s\fR \fP A slice of strings .TP -\fB--intmap\fP +\fB\fB\-\-intmap\fR \fP A map from string to int .TP -\fB--sip.opt\fP +\fB\fB\-\-sip.opt\fR\fP This is a subgroup option .TP -\fB--sip.sap.opt\fP +\fB\fB\-\-sip.sap.opt\fR\fP This is a subsubgroup option .SH COMMANDS .SS command @@ -234,9 +242,9 @@ Longer \fBcommand\fP description \fBAliases\fP: cm, cmd .TP -\fB--extra-verbose\fP +\fB\fB\-\-extra-verbose\fR\fP Use for extra verbosity -`, tt.Format("2 January 2006")) +`, tt.Format("2 January 2006"), envDefaultName) assertDiff(t, got, expected, "man page") } diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go index e8e5916c0..95347d07f 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/man.go @@ -3,30 +3,35 @@ package flags import ( "fmt" "io" + "runtime" "strings" "time" ) +func manQuote(s string) string { + return strings.Replace(s, "\\", "\\\\", -1) +} + func formatForMan(wr io.Writer, s string) { for { idx := strings.IndexRune(s, '`') if idx < 0 { - fmt.Fprintf(wr, "%s", s) + fmt.Fprintf(wr, "%s", manQuote(s)) break } - fmt.Fprintf(wr, "%s", s[:idx]) + fmt.Fprintf(wr, "%s", manQuote(s[:idx])) s = s[idx+1:] idx = strings.IndexRune(s, '\'') if idx < 0 { - fmt.Fprintf(wr, "%s", s) + fmt.Fprintf(wr, "%s", manQuote(s)) break } - fmt.Fprintf(wr, "\\fB%s\\fP", s[:idx]) + fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx])) s = s[idx+1:] } } @@ -42,7 +47,7 @@ func writeManPageOptions(wr io.Writer, grp *Group) { fmt.Fprintf(wr, "\\fB") if opt.ShortName != 0 { - fmt.Fprintf(wr, "-%c", opt.ShortName) + fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName) } if len(opt.LongName) != 0 { @@ -50,10 +55,33 @@ func writeManPageOptions(wr io.Writer, grp *Group) { 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, " ", manQuote(strings.Join(quoteV(opt.Default), ", "))) + } else if len(opt.EnvDefaultKey) != 0 { + if runtime.GOOS == "windows" { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } else { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } + } + + if opt.Required { + fmt.Fprintf(wr, " (\\fIrequired\\fR)") } fmt.Fprintln(wr, "\\fP") + if len(opt.Description) != 0 { formatForMan(wr, opt.Description) fmt.Fprintln(wr, "") @@ -85,10 +113,10 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm if len(command.LongDescription) > 0 { 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) { - 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):]) fmt.Fprintln(wr, "") @@ -113,11 +141,11 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm } 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 { - 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) @@ -129,9 +157,9 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm func (p *Parser) WriteManPage(wr io.Writer) { 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.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") usage := p.Usage @@ -140,7 +168,7 @@ func (p *Parser) WriteManPage(wr io.Writer) { 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") formatForMan(wr, p.LongDescription) diff --git a/Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go b/Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go index 29e702c19..42c105921 100644 --- a/Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go +++ b/Godeps/_workspace/src/github.com/jessevdk/go-flags/option.go @@ -35,7 +35,7 @@ type Option struct { // 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 - // 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. OptionalArgument bool @@ -155,3 +155,8 @@ func (option *Option) String() string { func (option *Option) Value() interface{} { return option.value.Interface() } + +// IsSet returns true if option has been set +func (option *Option) IsSet() bool { + return option.isSet +} diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go deleted file mode 100644 index ccc570cdd..000000000 --- a/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/http.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go deleted file mode 100644 index 2d432a00d..000000000 --- a/Godeps/_workspace/src/github.com/mitchellh/goamz/testutil/suite.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore b/Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore deleted file mode 100644 index e39772eb9..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/.bzrignore +++ /dev/null @@ -1,3 +0,0 @@ -_* -[856].out -[856].out.exe diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/.gitignore b/Godeps/_workspace/src/github.com/motain/gocheck/.gitignore deleted file mode 100644 index 191a5360b..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -_* -*.swp -*.[568] -[568].out diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/LICENSE b/Godeps/_workspace/src/github.com/motain/gocheck/LICENSE deleted file mode 100644 index d106fac0e..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Gocheck - A rich testing framework for Go - -Copyright (c) 2010, Gustavo Niemeyer - -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. diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/Makefile b/Godeps/_workspace/src/github.com/motain/gocheck/Makefile deleted file mode 100644 index 333e56cc1..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/Makefile +++ /dev/null @@ -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 - diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/TODO b/Godeps/_workspace/src/github.com/motain/gocheck/TODO deleted file mode 100644 index 33498270e..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- Assert(slice, Contains, item) -- Parallel test support diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go b/Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go deleted file mode 100644 index dcd426f22..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/benchmark.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go deleted file mode 100644 index 336243f2c..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/benchmark_test.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go deleted file mode 100644 index a3bc28cd4..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/bootstrap_test.go +++ /dev/null @@ -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)) - } -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/checkers.go b/Godeps/_workspace/src/github.com/motain/gocheck/checkers.go deleted file mode 100644 index 5c91200f0..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/checkers.go +++ /dev/null @@ -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()), "" -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go deleted file mode 100644 index 0945491b9..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/checkers_test.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/export_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/export_test.go deleted file mode 100644 index ad2962199..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/export_test.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go deleted file mode 100644 index 63f392e49..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/fixture_test.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go deleted file mode 100644 index 9f8915006..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/foundation_test.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go b/Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go deleted file mode 100644 index 631170967..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/gocheck.go +++ /dev/null @@ -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 "" -} - -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 "" -} - -// ----------------------------------------------------------------------- -// 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) -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go deleted file mode 100644 index e4acda996..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/gocheck_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/helpers.go b/Godeps/_workspace/src/github.com/motain/gocheck/helpers.go deleted file mode 100644 index fe4ca5169..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/helpers.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go deleted file mode 100644 index fb9ef8e18..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/helpers_test.go +++ /dev/null @@ -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) - } -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/printer.go b/Godeps/_workspace/src/github.com/motain/gocheck/printer.go deleted file mode 100644 index 103ab14a0..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/printer.go +++ /dev/null @@ -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} -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go deleted file mode 100644 index 552bdf79e..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/printer_test.go +++ /dev/null @@ -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) - } - -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/run.go b/Godeps/_workspace/src/github.com/motain/gocheck/run.go deleted file mode 100644 index 8400355a9..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/run.go +++ /dev/null @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/motain/gocheck/run_test.go b/Godeps/_workspace/src/github.com/motain/gocheck/run_test.go deleted file mode 100644 index cdcddc080..000000000 --- a/Godeps/_workspace/src/github.com/motain/gocheck/run_test.go +++ /dev/null @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/client.go b/Godeps/_workspace/src/github.com/pkg/sftp/client.go index f48b0be7b..9bb26c65d 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/client.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/client.go @@ -1,11 +1,16 @@ package sftp import ( + "bytes" "encoding" + "encoding/binary" + "errors" + "fmt" "io" "os" "path" "sync" + "sync/atomic" "time" "github.com/kr/fs" @@ -13,8 +18,19 @@ import ( "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. -func NewClient(conn *ssh.Client) (*Client, error) { +func NewClient(conn *ssh.Client, opts ...func(*Client) error) (*Client, error) { s, err := conn.NewSession() if err != nil { return nil, err @@ -31,21 +47,34 @@ func NewClient(conn *ssh.Client) (*Client, error) { return nil, err } - return NewClientPipe(pr, pw) + return NewClientPipe(pr, pw, opts...) } // 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 // 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{ - w: wr, - r: rd, + w: wr, + 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 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. @@ -54,14 +83,23 @@ func NewClientPipe(rd io.Reader, wr io.WriteCloser) (*Client, error) { // // Client implements the github.com/kr/fs.FileSystem interface. type Client struct { - w io.WriteCloser - r io.Reader - mu sync.Mutex // locks mu and seralises commands to the server - nextid uint32 + w io.WriteCloser + r io.Reader + + 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. -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 // 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 -// callers is expected to hold c.mu +// returns the next value of c.nextid func (c *Client) nextId() uint32 { - v := c.nextid - c.nextid++ - return v + return atomic.AddUint32(&c.nextid, 1) } func (c *Client) recvVersion() error { @@ -103,6 +138,46 @@ func (c *Client) recvVersion() error { 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. func (c *Client) Walk(root string) *fs.Walker { 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 var attrs []os.FileInfo - c.mu.Lock() - defer c.mu.Unlock() var done = false for !done { id := c.nextId() @@ -163,8 +236,6 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) { return attrs, err } func (c *Client) opendir(path string) (string, error) { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpOpendirPacket{ Id: id, @@ -189,8 +260,6 @@ func (c *Client) opendir(path string) (string, error) { } func (c *Client) Lstat(p string) (os.FileInfo, error) { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpLstatPacket{ Id: id, @@ -216,8 +285,6 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) { // ReadLink reads the target of a symbolic link. func (c *Client) ReadLink(p string) (string, error) { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpReadlinkPacket{ 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. func (c *Client) setstat(path string, flags uint32, attrs interface{}) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpSetstatPacket{ 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) { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpOpenPacket{ 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 // to SSH_FXP_OPEN or SSH_FXP_OPENDIR. The handle becomes invalid // immediately after this request has been sent. func (c *Client) close(handle string) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpClosePacket{ Id: id, @@ -395,8 +425,6 @@ func (c *Client) close(handle string) error { } func (c *Client) fstat(handle string) (*FileStat, error) { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpFstatPacket{ 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 // separating slash if necessary. The result is Cleaned; in particular, all // empty strings are ignored. @@ -437,8 +499,6 @@ func (c *Client) Remove(path string) error { } func (c *Client) removeFile(path string) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpRemovePacket{ Id: id, @@ -456,8 +516,6 @@ func (c *Client) removeFile(path string) error { } func (c *Client) removeDirectory(path string) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpRmdirPacket{ Id: id, @@ -476,8 +534,6 @@ func (c *Client) removeDirectory(path string) error { // Rename renames a file. func (c *Client) Rename(oldname, newname string) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpRenamePacket{ Id: id, @@ -495,46 +551,41 @@ func (c *Client) Rename(oldname, newname string) error { } } -func (c *Client) sendRequest(p encoding.BinaryMarshaler) (byte, []byte, error) { - if err := sendPacket(c.w, p); err != nil { - return 0, nil, err - } - return recvPacket(c.r) +// result captures the result of receiving the a packet from the server +type result struct { + typ byte + data []byte + err error } -// writeAt writes len(buf) bytes from the remote file indicated by handle starting -// from offset. -func (c *Client) writeAt(handle string, offset uint64, buf []byte) (uint32, error) { +type idmarshaler interface { + id() uint32 + 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() - defer c.mu.Unlock() - id := c.nextId() - typ, data, err := c.sendRequest(sshFxpWritePacket{ - Id: id, - Handle: handle, - Offset: offset, - 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.inflight[p.id()] = ch + if err := sendPacket(c.w, p); err != nil { + delete(c.inflight, p.id()) + c.mu.Unlock() + ch <- result{err: err} + return } + c.mu.Unlock() } // 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 // parent folder does not exist (the method cannot create complete paths). func (c *Client) Mkdir(path string) error { - c.mu.Lock() - defer c.mu.Unlock() id := c.nextId() typ, data, err := c.sendRequest(sshFxpMkdirPacket{ 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. type File struct { c *Client @@ -565,21 +627,226 @@ func (f *File) Close() error { return f.c.close(f.handle) } +const maxConcurrentRequests = 64 + // 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 // err set to io.EOF. func (f *File) Read(b []byte) (int, error) { - var read int - for len(b) > 0 { - n, err := f.c.readAt(f.handle, f.offset, b[:min(len(b), maxWritePacket)]) - f.offset += uint64(n) - read += int(n) - if err != nil { - return read, err - } - b = b[n:] + // Split the read into multiple maxPacket sized concurrent reads + // bounded by maxConcurrentRequests. This allows reads with a suitably + // large buffer to transfer data at a much faster rate due to + // overlapping round trip times. + inFlight := 0 + desiredInFlight := 1 + offset := f.offset + ch := make(chan result) + 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 @@ -592,24 +859,140 @@ func (f *File) Stat() (os.FileInfo, error) { 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 // written and an error, if any. Write returns a non-nil error when n != // len(b). func (f *File) Write(b []byte) (int, error) { - var written int - for len(b) > 0 { - n, err := f.c.writeAt(f.handle, f.offset, b[:min(len(b), maxWritePacket)]) - f.offset += uint64(n) - written += int(n) - if err != nil { - return written, err + // Split the write into multiple maxPacket sized concurrent writes + // bounded by maxConcurrentRequests. This allows writes with a suitably + // large buffer to transfer data at a much faster rate due to + // overlapping round trip times. + inFlight := 0 + desiredInFlight := 1 + 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 diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go b/Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go index 828deea35..ff8cc8de0 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/client_integration_test.go @@ -14,15 +14,18 @@ import ( "path" "path/filepath" "reflect" + "syscall" "testing" "testing/quick" + "time" "github.com/kr/fs" ) const ( - READONLY = true - READWRITE = false + READONLY = true + READWRITE = false + NO_DELAY time.Duration = 0 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 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 // 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 { t.Skip("skipping intergration test") } @@ -45,6 +96,9 @@ func testClient(t testing.TB, readonly bool) (*Client, *exec.Cmd) { if err != nil { t.Fatal(err) } + if delay > NO_DELAY { + pw = newDelayedWriter(pw, delay) + } pr, err := cmd.StdoutPipe() if err != nil { t.Fatal(err) @@ -58,19 +112,11 @@ func testClient(t testing.TB, readonly bool) (*Client, *exec.Cmd) { 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 } func TestNewClient(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() if err := sftp.Close(); err != nil { @@ -79,7 +125,7 @@ func TestNewClient(t *testing.T) { } func TestClientLstat(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -105,7 +151,7 @@ func TestClientLstat(t *testing.T) { } func TestClientLstatMissing(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -122,7 +168,7 @@ func TestClientLstatMissing(t *testing.T) { } func TestClientMkdir(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -140,7 +186,7 @@ func TestClientMkdir(t *testing.T) { } func TestClientOpen(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -199,7 +245,7 @@ func (s seek) end(t *testing.T, r io.ReadSeeker) { } func TestClientSeek(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -243,7 +289,7 @@ func TestClientSeek(t *testing.T) { } func TestClientCreate(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -262,7 +308,7 @@ func TestClientCreate(t *testing.T) { } func TestClientAppend(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -281,7 +327,7 @@ func TestClientAppend(t *testing.T) { } func TestClientCreateFailed(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -302,7 +348,7 @@ func TestClientCreateFailed(t *testing.T) { } func TestClientFileStat(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -333,7 +379,7 @@ func TestClientFileStat(t *testing.T) { } func TestClientRemove(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -350,7 +396,7 @@ func TestClientRemove(t *testing.T) { } func TestClientRemoveDir(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -367,7 +413,7 @@ func TestClientRemoveDir(t *testing.T) { } func TestClientRemoveFailed(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -384,7 +430,7 @@ func TestClientRemoveFailed(t *testing.T) { } func TestClientRename(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -405,7 +451,7 @@ func TestClientRename(t *testing.T) { } func TestClientReadLine(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -449,7 +495,7 @@ var clientReadTests = []struct { } func TestClientRead(t *testing.T) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() defer sftp.Close() @@ -537,7 +583,7 @@ var clientWriteTests = []struct { } func TestClientWrite(t *testing.T) { - sftp, cmd := testClient(t, READWRITE) + sftp, cmd := testClient(t, READWRITE, NO_DELAY) defer cmd.Wait() 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) { - sftp, cmd := testClient(t, READONLY) + sftp, cmd := testClient(t, READONLY, NO_DELAY) defer cmd.Wait() 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 // open sftp client - sftp, cmd := testClient(b, READONLY) + sftp, cmd := testClient(b, READONLY, delay) defer cmd.Wait() defer sftp.Close() @@ -786,38 +850,50 @@ func benchmarkRead(b *testing.B, bufsize int) { } func BenchmarkRead1k(b *testing.B) { - benchmarkRead(b, 1*1024) + benchmarkRead(b, 1*1024, NO_DELAY) } func BenchmarkRead16k(b *testing.B) { - benchmarkRead(b, 16*1024) + benchmarkRead(b, 16*1024, NO_DELAY) } func BenchmarkRead32k(b *testing.B) { - benchmarkRead(b, 32*1024) + benchmarkRead(b, 32*1024, NO_DELAY) } func BenchmarkRead128k(b *testing.B) { - benchmarkRead(b, 128*1024) + benchmarkRead(b, 128*1024, NO_DELAY) } func BenchmarkRead512k(b *testing.B) { - benchmarkRead(b, 512*1024) + benchmarkRead(b, 512*1024, NO_DELAY) } func BenchmarkRead1MiB(b *testing.B) { - benchmarkRead(b, 1024*1024) + benchmarkRead(b, 1024*1024, NO_DELAY) } 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 // open sftp client - sftp, cmd := testClient(b, false) + sftp, cmd := testClient(b, false, delay) defer cmd.Wait() defer sftp.Close() @@ -870,29 +946,230 @@ func benchmarkWrite(b *testing.B, bufsize int) { } func BenchmarkWrite1k(b *testing.B) { - benchmarkWrite(b, 1*1024) + benchmarkWrite(b, 1*1024, NO_DELAY) } func BenchmarkWrite16k(b *testing.B) { - benchmarkWrite(b, 16*1024) + benchmarkWrite(b, 16*1024, NO_DELAY) } func BenchmarkWrite32k(b *testing.B) { - benchmarkWrite(b, 32*1024) + benchmarkWrite(b, 32*1024, NO_DELAY) } func BenchmarkWrite128k(b *testing.B) { - benchmarkWrite(b, 128*1024) + benchmarkWrite(b, 128*1024, NO_DELAY) } func BenchmarkWrite512k(b *testing.B) { - benchmarkWrite(b, 512*1024) + benchmarkWrite(b, 512*1024, NO_DELAY) } func BenchmarkWrite1MiB(b *testing.B) { - benchmarkWrite(b, 1024*1024) + benchmarkWrite(b, 1024*1024, NO_DELAY) } 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) } diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go b/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go index 5d63f18c9..32c4d1f3b 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-read-benchmark/main.go @@ -22,6 +22,7 @@ var ( 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") + SIZE = flag.Int("s", 1<<15, "set max packet size") ) func init() { @@ -49,7 +50,7 @@ func main() { } defer conn.Close() - c, err := sftp.NewClient(conn) + c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE)) if err != nil { log.Fatalf("unable to start sftp subsytem: %v", err) } diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go b/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go index c0ea133a8..0c38db68c 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/examples/buffered-write-benchmark/main.go @@ -22,6 +22,7 @@ var ( 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") + SIZE = flag.Int("s", 1<<15, "set max packet size") ) func init() { @@ -49,7 +50,7 @@ func main() { } defer conn.Close() - c, err := sftp.NewClient(conn) + c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE)) if err != nil { log.Fatalf("unable to start sftp subsytem: %v", err) } diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go b/Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go deleted file mode 100644 index a1a8824b5..000000000 --- a/Godeps/_workspace/src/github.com/pkg/sftp/examples/gsftp/main.go +++ /dev/null @@ -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) - } -} diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go b/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go index 7ebdbd46e..dc901e976 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-read-benchmark/main.go @@ -23,6 +23,7 @@ var ( 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") + SIZE = flag.Int("s", 1<<15, "set max packet size") ) func init() { @@ -50,7 +51,7 @@ func main() { } defer conn.Close() - c, err := sftp.NewClient(conn) + c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE)) if err != nil { log.Fatalf("unable to start sftp subsytem: %v", err) } diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go b/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go index 63b27b55f..07a9ddb7c 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/examples/streaming-write-benchmark/main.go @@ -23,6 +23,7 @@ var ( 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") + SIZE = flag.Int("s", 1<<15, "set max packet size") ) func init() { @@ -50,7 +51,7 @@ func main() { } defer conn.Close() - c, err := sftp.NewClient(conn) + c, err := sftp.NewClient(conn, sftp.MaxPacket(*SIZE)) if err != nil { log.Fatalf("unable to start sftp subsytem: %v", err) } diff --git a/Godeps/_workspace/src/github.com/pkg/sftp/packet.go b/Godeps/_workspace/src/github.com/pkg/sftp/packet.go index f2c2b671f..45c9d7bdc 100644 --- a/Godeps/_workspace/src/github.com/pkg/sftp/packet.go +++ b/Godeps/_workspace/src/github.com/pkg/sftp/packet.go @@ -64,7 +64,6 @@ func unmarshalString(b []byte) (string, []byte) { } // sendPacket marshals p according to RFC 4234. - func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error { bb, err := m.MarshalBinary() if err != nil { @@ -142,6 +141,8 @@ func (p sshFxpReaddirPacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_READDIR, p.Id, p.Handle) } +func (p sshFxpReaddirPacket) id() uint32 { return p.Id } + type sshFxpOpendirPacket struct { Id uint32 Path string @@ -151,11 +152,15 @@ func (p sshFxpOpendirPacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_OPENDIR, p.Id, p.Path) } +func (p sshFxpOpendirPacket) id() uint32 { return p.Id } + type sshFxpLstatPacket struct { Id uint32 Path string } +func (p sshFxpLstatPacket) id() uint32 { return p.Id } + func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_LSTAT, p.Id, p.Path) } @@ -165,6 +170,8 @@ type sshFxpFstatPacket struct { Handle string } +func (p sshFxpFstatPacket) id() uint32 { return p.Id } + func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) { 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) } +func (p sshFxpClosePacket) id() uint32 { return p.Id } + type sshFxpRemovePacket struct { Id uint32 Filename string } +func (p sshFxpRemovePacket) id() uint32 { return p.Id } + func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_REMOVE, p.Id, p.Filename) } @@ -192,6 +203,8 @@ type sshFxpRmdirPacket struct { Path string } +func (p sshFxpRmdirPacket) id() uint32 { return p.Id } + func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_RMDIR, p.Id, p.Path) } @@ -201,6 +214,8 @@ type sshFxpReadlinkPacket struct { Path string } +func (p sshFxpReadlinkPacket) id() uint32 { return p.Id } + func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) { return marshalIdString(ssh_FXP_READLINK, p.Id, p.Path) } @@ -212,6 +227,8 @@ type sshFxpOpenPacket struct { Flags uint32 // ignored } +func (p sshFxpOpenPacket) id() uint32 { return p.Id } + func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + 4 + len(p.Path) + @@ -233,6 +250,8 @@ type sshFxpReadPacket struct { Len uint32 } +func (p sshFxpReadPacket) id() uint32 { return p.Id } + func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + // type(byte) + uint32 4 + len(p.Handle) + @@ -253,6 +272,8 @@ type sshFxpRenamePacket struct { Newpath string } +func (p sshFxpRenamePacket) id() uint32 { return p.Id } + func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + // type(byte) + uint32 4 + len(p.Oldpath) + @@ -274,6 +295,8 @@ type sshFxpWritePacket struct { Data []byte } +func (s sshFxpWritePacket) id() uint32 { return s.Id } + func (s sshFxpWritePacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + // type(byte) + uint32 4 + len(s.Handle) + @@ -296,6 +319,8 @@ type sshFxpMkdirPacket struct { Flags uint32 // ignored } +func (p sshFxpMkdirPacket) id() uint32 { return p.Id } + func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + // type(byte) + uint32 4 + len(p.Path) + @@ -316,6 +341,8 @@ type sshFxpSetstatPacket struct { Attrs interface{} } +func (p sshFxpSetstatPacket) id() uint32 { return p.Id } + func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { l := 1 + 4 + // type(byte) + uint32 4 + len(p.Path) + @@ -329,3 +356,46 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { b = marshal(b, p.Attrs) 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 +} diff --git a/Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go b/Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go index 593f65300..c02b4d5a7 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -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 pbkdf2.Key. */ -package pbkdf2 // import "golang.org/x/crypto/pbkdf2" +package pbkdf2 import ( "crypto/hmac" diff --git a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go index 4a5f826f7..2270d2b38 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305.go @@ -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 directly. */ -package poly1305 // import "golang.org/x/crypto/poly1305" +package poly1305 import "crypto/subtle" diff --git a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s new file mode 100644 index 000000000..c83784b0e --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/poly1305_arm.s @@ -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 diff --git a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go new file mode 100644 index 000000000..50b979c24 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_arm.go @@ -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) +} diff --git a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go index 92d38018d..0b24fc78b 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/poly1305/sum_ref.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 gccgo appengine +// +build !amd64,!arm gccgo appengine package poly1305 diff --git a/Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go b/Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go index dc0124b1f..30737b0a6 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/scrypt/scrypt.go @@ -5,7 +5,7 @@ // Package scrypt implements the scrypt key derivation function as defined in // Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard // Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf). -package scrypt // import "golang.org/x/crypto/scrypt" +package scrypt import ( "crypto/sha256" diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go index 31a0120c9..c98cb16b2 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client.go @@ -8,7 +8,7 @@ References: [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 ( "bytes" diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go index a7426b602..385770036 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs.go @@ -368,7 +368,7 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { 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") } if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go index 33236f5e8..d6c4a3371 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/certs_test.go @@ -57,7 +57,7 @@ const exampleSSHCertWithOptions = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2Et func TestParseCertWithOptions(t *testing.T) { opts := map[string]string{ "source-address": "192.168.1.0/24", - "force-command": "/bin/sleep", + "force-command": "/bin/sleep", } exts := map[string]string{ "permit-X11-forwarding": "", diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go index b17318385..3e06da0de 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher.go @@ -14,6 +14,7 @@ import ( "fmt" "hash" "io" + "io/ioutil" ) 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 type cbcCipher struct { mac hash.Hash + macSize uint32 decrypter cipher.BlockMode encrypter cipher.BlockMode @@ -357,6 +359,10 @@ type cbcCipher struct { seqNumBytes [4]byte packetData []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) { @@ -364,12 +370,18 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi if err != nil { return nil, err } - return &cbcCipher{ + + cbc := &cbcCipher{ mac: macModes[algs.MAC].new(macKey), decrypter: cipher.NewCBCDecrypter(c, iv), encrypter: cipher.NewCBCEncrypter(c, iv), packetData: make([]byte, 1024), - }, nil + } + if cbc.mac != nil { + cbc.macSize = uint32(cbc.mac.Size()) + } + + return cbc, nil } func maxUInt32(a, b int) uint32 { @@ -385,42 +397,58 @@ const ( 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) { + 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() // 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. // 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] if _, err := io.ReadFull(r, firstBlock); err != nil { return nil, err } + c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength + c.decrypter.CryptBlocks(firstBlock, firstBlock) length := binary.BigEndian.Uint32(firstBlock[:4]) if length > maxPacket { - return nil, errors.New("ssh: packet too large") + return nil, cbcError("ssh: packet too large") } if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { // The minimum size of a packet is 16 (or the cipher block size, whichever // 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 // be a multiple of the block size or 8, whichever is larger. 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]) if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { - return nil, errors.New("ssh: invalid packet length") - } - - var macSize uint32 - if c.mac != nil { - macSize = uint32(c.mac.Size()) + return nil, cbcError("ssh: invalid packet length") } // Positions within the c.packetData buffer: @@ -428,7 +456,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { paddingStart := macStart - paddingLength // 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. 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] } - if _, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { + if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { return nil, err + } else { + c.oracleCamouflage -= uint32(n) } 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.macResult = c.mac.Sum(c.macResult[:0]) 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 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. // 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 { c.packetData = make([]byte, encLength, bufferSize) } else { diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go index 2fb75d0d7..54b92b6ed 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/cipher_test.go @@ -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 + } +} diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go index b03a3dfd8..0a9df1f95 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/common.go @@ -53,7 +53,7 @@ var supportedHostKeyAlgos = []string{ // 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. var supportedMACs = []string{ - "hmac-sha1", "hmac-sha1-96", + "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", } var supportedCompressions = []string{compressionNone} diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go index d6be89466..a5ff8af6b 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/doc.go @@ -15,4 +15,4 @@ References: [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 */ -package ssh // import "golang.org/x/crypto/ssh" +package ssh diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go index aff404291..07744ad67 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/mac.go @@ -9,6 +9,7 @@ package ssh import ( "crypto/hmac" "crypto/sha1" + "crypto/sha256" "hash" ) @@ -44,6 +45,9 @@ func (t truncatingMAC) Size() int { func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } 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 { return hmac.New(sha1.New, key) }}, diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go index f9e44bb1e..eaf610669 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages.go @@ -484,11 +484,12 @@ func parseString(in []byte) (out, rest []byte, ok bool) { return } length := binary.BigEndian.Uint32(in) - if uint32(len(in)) < 4+length { + in = in[4:] + if uint32(len(in)) < length { return } - out = in[4 : 4+length] - rest = in[4+length:] + out = in[:length] + rest = in[length:] ok = true return } diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go index 21d52daf2..955b5127f 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/messages_test.go @@ -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) { for i := 0; i < len(out); i++ { out[i] = byte(rand.Int31()) diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go index 52aee11e3..baedf5bbe 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/server.go @@ -168,6 +168,10 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) 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 != "" { s.serverVersion = []byte(config.ServerVersion) } else { diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go index 88e66bf48..7ce44f59c 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/session_test.go @@ -9,9 +9,11 @@ package ssh import ( "bytes" crypto_rand "crypto/rand" + "errors" "io" "io/ioutil" "math/rand" + "net" "testing" "golang.org/x/crypto/ssh/terminal" @@ -678,3 +680,41 @@ func TestSessionID(t *testing.T) { 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") + } +} diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go index 598e3df77..0763c9a97 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/util.go @@ -14,7 +14,7 @@ // panic(err) // } // defer terminal.Restore(0, oldState) -package terminal // import "golang.org/x/crypto/ssh/terminal" +package terminal import ( "io" diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go index 3f9b3346d..29ad65e96 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/test/doc.go @@ -4,4 +4,4 @@ // This package contains integration tests for the // golang.org/x/crypto/ssh package. -package test // import "golang.org/x/crypto/ssh/test" +package test diff --git a/Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go b/Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go index fcae47ca6..ae7bd8b89 100644 --- a/Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go +++ b/Godeps/_workspace/src/golang.org/x/crypto/ssh/testdata/doc.go @@ -5,4 +5,4 @@ // This package contains test data shared between the various subpackages of // the golang.org/x/crypto/ssh package. Under no circumstance should // this data be used for production code. -package testdata // import "golang.org/x/crypto/ssh/testdata" +package testdata