Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-09-22 14:54:24 -03:00
parent 55ccaf4be3
commit 2882fb5ebe
457 changed files with 54614 additions and 19833 deletions

View file

@ -3,4 +3,5 @@ TODO
tmp/**/*
*.coverprofile
.vscode
.idea/
.idea/
*.log

View file

@ -1,3 +1,18 @@
## 1.6.0
### New Features
- add --debug flag to emit node output to files (#499) [39febac]
### Fixes
- fix: for `go vet` to pass [69338ec]
- docs: fix for contributing instructions [7004cb1]
- consolidate and streamline contribution docs (#494) [d848015]
- Make generated Junit file compatable with "Maven Surefire" (#488) [e51bee6]
- all: gofmt [000d317]
- Increase eventually timeout to 30s [c73579c]
- Clarify asynchronous test behaviour [294d8f4]
- Travis badge should only show master [26d2143]
## 1.5.0 5/10/2018
### New Features

View file

@ -1,13 +1,33 @@
# Contributing to Ginkgo
Your contributions to Ginkgo are essential for its long-term maintenance and improvement. To make a contribution:
Your contributions to Ginkgo are essential for its long-term maintenance and improvement.
- Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code!
- Ensure adequate test coverage:
- If you're adding functionality to the Ginkgo library, make sure to add appropriate unit and/or integration tests (under the `integration` folder).
- If you're adding functionality to the Ginkgo CLI note that there are very few unit tests. Please add an integration test.
- Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR
- Please run following linter locally `go vet ./...` and make sure output does not contain any warnings
- Update the documentation. In addition to standard `godoc` comments Ginkgo has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR.
- When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder).
- When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test.
- Update the documentation. Ginko uses `godoc` comments and documentation on the `gh-pages` branch.
If relevant, please submit a docs PR to that branch alongside your code PR.
Thanks for supporting Ginkgo!
## Setup
Fork the repo, then:
```
go get github.com/onsi/ginkgo
go get github.com/onsi/gomega/...
cd $GOPATH/src/github.com/onsi/ginkgo
git remote add fork git@github.com:<NAME>/ginkgo.git
ginkgo -r -p # ensure tests are green
go vet ./... # ensure linter is happy
```
## Making the PR
- go to a new branch `git checkout -b my-feature`
- make your changes
- run tests and linter again (see above)
- `git push fork`
- open PR 🎉

View file

@ -1,6 +1,6 @@
![Ginkgo: A Go BDD Testing Framework](http://onsi.github.io/ginkgo/images/ginkgo.png)
[![Build Status](https://travis-ci.org/onsi/ginkgo.svg)](https://travis-ci.org/onsi/ginkgo)
[![Build Status](https://travis-ci.org/onsi/ginkgo.svg?branch=master)](https://travis-ci.org/onsi/ginkgo)
Jump to the [docs](http://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
@ -118,6 +118,4 @@ Ginkgo is MIT-Licensed
## Contributing
Since Ginkgo tests also internal packages, when you fork, you'll have to replace imports with your repository.<br />
Use `before_pr.sh` for that<br />
After you finished your changes and before you push your pull request, use `after_pr.sh` to revert those changes
See [CONTRIBUTING.md](CONTRIBUTING.md)

View file

@ -1,13 +0,0 @@
# Take current path
path=$(pwd)
# Split it
IFS='\/'; arrIN=($path); unset IFS;
# Find directory before ginkgo
len=${#arrIN[@]}
userDir=${arrIN[$len-2]}
# Replace onsi with userdir
find . -type f -name '*.go' -exec sed -i '' s/github.com\\/onsi\\/ginkgo\\/internal/github.com\\/$userDir\\/ginkgo\\/internal/ {} +

View file

@ -20,7 +20,7 @@ import (
"fmt"
)
const VERSION = "1.5.0"
const VERSION = "1.6.0"
type GinkgoConfigType struct {
RandomSeed int64
@ -34,6 +34,7 @@ type GinkgoConfigType struct {
FlakeAttempts int
EmitSpecProgress bool
DryRun bool
DebugParallel bool
ParallelNode int
ParallelTotal int
@ -81,6 +82,8 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
flagSet.BoolVar(&(GinkgoConfig.EmitSpecProgress), prefix+"progress", false, "If set, ginkgo will emit progress information as each spec runs to the GinkgoWriter.")
flagSet.BoolVar(&(GinkgoConfig.DebugParallel), prefix+"debug", false, "If set, ginkgo will emit node output to files when running in parallel.")
if includeParallelFlags {
flagSet.IntVar(&(GinkgoConfig.ParallelNode), prefix+"parallel.node", 1, "This worker node's (one-indexed) node number. For running specs in parallel.")
flagSet.IntVar(&(GinkgoConfig.ParallelTotal), prefix+"parallel.total", 1, "The total number of worker nodes. For running specs in parallel.")
@ -141,6 +144,10 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
result = append(result, fmt.Sprintf("--%sprogress", prefix))
}
if ginkgo.DebugParallel {
result = append(result, fmt.Sprintf("--%sdebug", prefix))
}
if ginkgo.ParallelNode != 0 {
result = append(result, fmt.Sprintf("--%sparallel.node=%d", prefix, ginkgo.ParallelNode))
}

View file

@ -29,6 +29,7 @@ import (
"github.com/onsi/ginkgo/internal/writer"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/ginkgo/reporters/stenographer"
colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
"github.com/onsi/ginkgo/types"
)
@ -228,10 +229,14 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor
func buildDefaultReporter() Reporter {
remoteReportingServer := config.GinkgoConfig.StreamHost
if remoteReportingServer == "" {
stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1)
stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout())
return reporters.NewDefaultReporter(config.DefaultReporterConfig, stenographer)
} else {
return remote.NewForwardingReporter(remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor())
debugFile := ""
if config.GinkgoConfig.DebugParallel {
debugFile = fmt.Sprintf("ginkgo-node-%d.log", config.GinkgoConfig.ParallelNode)
}
return remote.NewForwardingReporter(config.DefaultReporterConfig, remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor(), GinkgoWriter.(*writer.Writer), debugFile)
}
}

View file

@ -87,6 +87,9 @@ func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure)
finished = true
}()
// If this goroutine gets no CPU time before the select block,
// the <-done case may complete even if the test took longer than the timeoutThreshold.
// This can cause flaky behaviour, but we haven't seen it in the wild.
select {
case <-done:
case <-time.After(r.timeoutThreshold):

View file

@ -3,8 +3,14 @@ package remote
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"github.com/onsi/ginkgo/internal/writer"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/ginkgo/reporters/stenographer"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
@ -30,14 +36,41 @@ type ForwardingReporter struct {
serverHost string
poster Poster
outputInterceptor OutputInterceptor
debugMode bool
debugFile *os.File
nestedReporter *reporters.DefaultReporter
}
func NewForwardingReporter(serverHost string, poster Poster, outputInterceptor OutputInterceptor) *ForwardingReporter {
return &ForwardingReporter{
func NewForwardingReporter(config config.DefaultReporterConfigType, serverHost string, poster Poster, outputInterceptor OutputInterceptor, ginkgoWriter *writer.Writer, debugFile string) *ForwardingReporter {
reporter := &ForwardingReporter{
serverHost: serverHost,
poster: poster,
outputInterceptor: outputInterceptor,
}
if debugFile != "" {
var err error
reporter.debugMode = true
reporter.debugFile, err = os.Create(debugFile)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
if !config.Verbose {
//if verbose is true then the GinkgoWriter emits to stdout. Don't _also_ redirect GinkgoWriter output as that will result in duplication.
ginkgoWriter.AndRedirectTo(reporter.debugFile)
}
outputInterceptor.StreamTo(reporter.debugFile) //This is not working
stenographer := stenographer.New(false, true, reporter.debugFile)
config.Succinct = false
config.Verbose = true
config.FullTrace = true
reporter.nestedReporter = reporters.NewDefaultReporter(config, stenographer)
}
return reporter
}
func (reporter *ForwardingReporter) post(path string, data interface{}) {
@ -56,6 +89,10 @@ func (reporter *ForwardingReporter) SpecSuiteWillBegin(conf config.GinkgoConfigT
}
reporter.outputInterceptor.StartInterceptingOutput()
if reporter.debugMode {
reporter.nestedReporter.SpecSuiteWillBegin(conf, summary)
reporter.debugFile.Sync()
}
reporter.post("/SpecSuiteWillBegin", data)
}
@ -63,10 +100,18 @@ func (reporter *ForwardingReporter) BeforeSuiteDidRun(setupSummary *types.SetupS
output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput()
reporter.outputInterceptor.StartInterceptingOutput()
setupSummary.CapturedOutput = output
if reporter.debugMode {
reporter.nestedReporter.BeforeSuiteDidRun(setupSummary)
reporter.debugFile.Sync()
}
reporter.post("/BeforeSuiteDidRun", setupSummary)
}
func (reporter *ForwardingReporter) SpecWillRun(specSummary *types.SpecSummary) {
if reporter.debugMode {
reporter.nestedReporter.SpecWillRun(specSummary)
reporter.debugFile.Sync()
}
reporter.post("/SpecWillRun", specSummary)
}
@ -74,6 +119,10 @@ func (reporter *ForwardingReporter) SpecDidComplete(specSummary *types.SpecSumma
output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput()
reporter.outputInterceptor.StartInterceptingOutput()
specSummary.CapturedOutput = output
if reporter.debugMode {
reporter.nestedReporter.SpecDidComplete(specSummary)
reporter.debugFile.Sync()
}
reporter.post("/SpecDidComplete", specSummary)
}
@ -81,10 +130,18 @@ func (reporter *ForwardingReporter) AfterSuiteDidRun(setupSummary *types.SetupSu
output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput()
reporter.outputInterceptor.StartInterceptingOutput()
setupSummary.CapturedOutput = output
if reporter.debugMode {
reporter.nestedReporter.AfterSuiteDidRun(setupSummary)
reporter.debugFile.Sync()
}
reporter.post("/AfterSuiteDidRun", setupSummary)
}
func (reporter *ForwardingReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
reporter.outputInterceptor.StopInterceptingAndReturnOutput()
if reporter.debugMode {
reporter.nestedReporter.SpecSuiteDidEnd(summary)
reporter.debugFile.Sync()
}
reporter.post("/SpecSuiteDidEnd", summary)
}

View file

@ -1,5 +1,7 @@
package remote
import "os"
/*
The OutputInterceptor is used by the ForwardingReporter to
intercept and capture all stdin and stderr output during a test run.
@ -7,4 +9,5 @@ intercept and capture all stdin and stderr output during a test run.
type OutputInterceptor interface {
StartInterceptingOutput() error
StopInterceptingAndReturnOutput() (string, error)
StreamTo(*os.File)
}

View file

@ -6,6 +6,8 @@ import (
"errors"
"io/ioutil"
"os"
"github.com/hpcloud/tail"
)
func NewOutputInterceptor() OutputInterceptor {
@ -14,7 +16,10 @@ func NewOutputInterceptor() OutputInterceptor {
type outputInterceptor struct {
redirectFile *os.File
streamTarget *os.File
intercepting bool
tailer *tail.Tail
doneTailing chan bool
}
func (interceptor *outputInterceptor) StartInterceptingOutput() error {
@ -37,6 +42,18 @@ func (interceptor *outputInterceptor) StartInterceptingOutput() error {
syscallDup(int(interceptor.redirectFile.Fd()), 1)
syscallDup(int(interceptor.redirectFile.Fd()), 2)
if interceptor.streamTarget != nil {
interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true})
interceptor.doneTailing = make(chan bool)
go func() {
for line := range interceptor.tailer.Lines {
interceptor.streamTarget.Write([]byte(line.Text + "\n"))
}
close(interceptor.doneTailing)
}()
}
return nil
}
@ -51,5 +68,16 @@ func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string,
interceptor.intercepting = false
if interceptor.streamTarget != nil {
interceptor.tailer.Stop()
interceptor.tailer.Cleanup()
<-interceptor.doneTailing
interceptor.streamTarget.Sync()
}
return string(output), err
}
func (interceptor *outputInterceptor) StreamTo(out *os.File) {
interceptor.streamTarget = out
}

View file

@ -4,6 +4,7 @@ package remote
import (
"errors"
"os"
)
func NewOutputInterceptor() OutputInterceptor {
@ -31,3 +32,5 @@ func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string,
return "", nil
}
func (interceptor *outputInterceptor) StreamTo(*os.File) {}

View file

@ -16,10 +16,11 @@ type WriterInterface interface {
}
type Writer struct {
buffer *bytes.Buffer
outWriter io.Writer
lock *sync.Mutex
stream bool
buffer *bytes.Buffer
outWriter io.Writer
lock *sync.Mutex
stream bool
redirector io.Writer
}
func New(outWriter io.Writer) *Writer {
@ -31,6 +32,10 @@ func New(outWriter io.Writer) *Writer {
}
}
func (w *Writer) AndRedirectTo(writer io.Writer) {
w.redirector = writer
}
func (w *Writer) SetStream(stream bool) {
w.lock.Lock()
defer w.lock.Unlock()
@ -42,6 +47,9 @@ func (w *Writer) Write(b []byte) (n int, err error) {
defer w.lock.Unlock()
n, err = w.buffer.Write(b)
if w.redirector != nil {
w.redirector.Write(b)
}
if w.stream {
return w.outWriter.Write(b)
}

View file

@ -11,6 +11,7 @@ package reporters
import (
"encoding/xml"
"fmt"
"math"
"os"
"strings"
@ -24,6 +25,7 @@ type JUnitTestSuite struct {
Name string `xml:"name,attr"`
Tests int `xml:"tests,attr"`
Failures int `xml:"failures,attr"`
Errors int `xml:"errors,attr"`
Time float64 `xml:"time,attr"`
}
@ -119,8 +121,9 @@ func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun
reporter.suite.Time = summary.RunTime.Seconds()
reporter.suite.Time = math.Trunc(summary.RunTime.Seconds() * 1000 / 1000)
reporter.suite.Failures = summary.NumberOfFailedSpecs
reporter.suite.Errors = 0
file, err := os.Create(reporter.filename)
if err != nil {
fmt.Printf("Failed to create JUnit report file: %s\n\t%s", reporter.filename, err.Error())

View file

@ -12,7 +12,6 @@ import (
"runtime"
"strings"
"github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
"github.com/onsi/ginkgo/types"
)
@ -62,7 +61,7 @@ type Stenographer interface {
SummarizeFailures(summaries []*types.SpecSummary)
}
func New(color bool, enableFlakes bool) Stenographer {
func New(color bool, enableFlakes bool, writer io.Writer) Stenographer {
denoter := "•"
if runtime.GOOS == "windows" {
denoter = "+"
@ -72,7 +71,7 @@ func New(color bool, enableFlakes bool) Stenographer {
denoter: denoter,
cursorState: cursorStateTop,
enableFlakes: enableFlakes,
w: colorable.NewColorableStdout(),
w: writer,
}
}

View file

@ -5,10 +5,12 @@ go:
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
install:
- go get -v ./...
- env GO111MODULE=on go get -v ./...
- env GO111MODULE=on go build ./...
- go get github.com/onsi/ginkgo
- go install github.com/onsi/ginkgo/ginkgo
script: $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race && go vet
script: env GO111MODULE=on $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race && env GO111MODULE=on go vet

View file

@ -1,4 +1,23 @@
## HEAD
## 1.4.2
### Fixes:
- Add go.mod and go.sum files to define the gomega go module [f3de367, a085d30]
- Work around go vet issue with Go v1.11 (#300) [40dd6ad]
- Better output when using with go XUnit-style tests, fixes #255 (#297) [29a4b97]
- Fix MatchJSON fail to parse json.RawMessage (#298) [ae19f1b]
- show threshold in failure message of BeNumericallyMatcher (#293) [4bbecc8]
## 1.4.1
### Fixes:
- Update documentation formatting and examples (#289) [9be8410]
- allow 'Receive' matcher to be used with concrete types (#286) [41673fd]
- Fix data race in ghttp server (#283) [7ac6b01]
- Travis badge should only show master [cc102ab]
## 1.4.0
### Features
- Make string pretty diff user configurable (#273) [eb112ce, 649b44d]

View file

@ -1,6 +1,6 @@
![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png)
[![Build Status](https://travis-ci.org/onsi/gomega.svg)](https://travis-ci.org/onsi/gomega)
[![Build Status](https://travis-ci.org/onsi/gomega.svg?branch=master)](https://travis-ci.org/onsi/gomega)
Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers).

15
vendor/github.com/onsi/gomega/go.mod generated vendored Normal file
View file

@ -0,0 +1,15 @@
module github.com/onsi/gomega
require (
github.com/fsnotify/fsnotify v1.4.7 // indirect
github.com/golang/protobuf v1.2.0
github.com/hpcloud/tail v1.0.0 // indirect
github.com/onsi/ginkgo v1.6.0
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect
golang.org/x/text v0.3.0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.2.1
)

24
vendor/github.com/onsi/gomega/go.sum generated vendored Normal file
View file

@ -0,0 +1,24 @@
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types"
)
const GOMEGA_VERSION = "1.4.0"
const GOMEGA_VERSION = "1.4.2"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
@ -32,7 +32,7 @@ Alternatively, you may have forgotten to register a fail handler with RegisterFa
Depending on your vendoring solution you may be inadvertently importing gomega and subpackages (e.g. ghhtp, gexec,...) from different locations.
`
var globalFailHandler types.GomegaFailHandler
var globalFailWrapper *types.GomegaFailWrapper
var defaultEventuallyTimeout = time.Second
var defaultEventuallyPollingInterval = 10 * time.Millisecond
@ -42,7 +42,14 @@ var defaultConsistentlyPollingInterval = 10 * time.Millisecond
//RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails
//the fail handler passed into RegisterFailHandler is called.
func RegisterFailHandler(handler types.GomegaFailHandler) {
globalFailHandler = handler
if handler == nil {
globalFailWrapper = nil
return
}
globalFailWrapper = &types.GomegaFailWrapper{
Fail: handler,
TWithHelper: testingtsupport.EmptyTWithHelper{},
}
}
//RegisterTestingT connects Gomega to Golang's XUnit style
@ -52,12 +59,12 @@ func RegisterFailHandler(handler types.GomegaFailHandler) {
//
//You'll need to call this at the top of each XUnit style test:
//
// func TestFarmHasCow(t *testing.T) {
// RegisterTestingT(t)
// func TestFarmHasCow(t *testing.T) {
// RegisterTestingT(t)
//
// f := farm.New([]string{"Cow", "Horse"})
// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
// }
// f := farm.New([]string{"Cow", "Horse"})
// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
// }
//
// Note that this *testing.T is registered *globally* by Gomega (this is why you don't have to
// pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests
@ -67,7 +74,7 @@ func RegisterFailHandler(handler types.GomegaFailHandler) {
//
// (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*).
func RegisterTestingT(t types.GomegaTestingT) {
RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t))
RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
}
//InterceptGomegaHandlers runs a given callback and returns an array of
@ -80,7 +87,7 @@ func RegisterTestingT(t types.GomegaTestingT) {
//This is most useful when testing custom matchers, but can also be used to check
//on a value using a Gomega assertion without causing a test failure.
func InterceptGomegaFailures(f func()) []string {
originalHandler := globalFailHandler
originalHandler := globalFailWrapper.Fail
failures := []string{}
RegisterFailHandler(func(message string, callerSkip ...int) {
failures = append(failures, message)
@ -91,7 +98,7 @@ func InterceptGomegaFailures(f func()) []string {
}
//Ω wraps an actual value allowing assertions to be made on it:
// Ω("foo").Should(Equal("foo"))
// Ω("foo").Should(Equal("foo"))
//
//If Ω is passed more than one argument it will pass the *first* argument to the matcher.
//All subsequent arguments will be required to be nil/zero.
@ -112,7 +119,7 @@ func Ω(actual interface{}, extra ...interface{}) GomegaAssertion {
}
//Expect wraps an actual value allowing assertions to be made on it:
// Expect("foo").To(Equal("foo"))
// Expect("foo").To(Equal("foo"))
//
//If Expect is passed more than one argument it will pass the *first* argument to the matcher.
//All subsequent arguments will be required to be nil/zero.
@ -142,10 +149,10 @@ func Expect(actual interface{}, extra ...interface{}) GomegaAssertion {
//error message to refer to the calling line in the test (as opposed to the line in the helper function)
//set the first argument of `ExpectWithOffset` appropriately.
func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) GomegaAssertion {
if globalFailHandler == nil {
if globalFailWrapper == nil {
panic(nilFailHandlerPanic)
}
return assertion.New(actual, globalFailHandler, offset, extra...)
return assertion.New(actual, globalFailWrapper, offset, extra...)
}
//Eventually wraps an actual value allowing assertions to be made on it.
@ -192,7 +199,7 @@ func Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAsserti
//initial argument to indicate an offset in the call stack. This is useful when building helper
//functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
if globalFailHandler == nil {
if globalFailWrapper == nil {
panic(nilFailHandlerPanic)
}
timeoutInterval := defaultEventuallyTimeout
@ -203,7 +210,7 @@ func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailHandler, timeoutInterval, pollingInterval, offset)
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
}
//Consistently wraps an actual value allowing assertions to be made on it.
@ -237,7 +244,7 @@ func Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAsser
//initial argument to indicate an offset in the call stack. This is useful when building helper
//functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
if globalFailHandler == nil {
if globalFailWrapper == nil {
panic(nilFailHandlerPanic)
}
timeoutInterval := defaultConsistentlyDuration
@ -248,7 +255,7 @@ func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interfa
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailHandler, timeoutInterval, pollingInterval, offset)
return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
}
//Set the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses.
@ -326,12 +333,12 @@ type GomegaWithT struct {
//NewGomegaWithT takes a *testing.T and returngs a `GomegaWithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with
//Gomega's rich ecosystem of matchers in standard `testing` test suits.
//
// func TestFarmHasCow(t *testing.T) {
// g := GomegaWithT(t)
// func TestFarmHasCow(t *testing.T) {
// g := GomegaWithT(t)
//
// f := farm.New([]string{"Cow", "Horse"})
// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
// }
// f := farm.New([]string{"Cow", "Horse"})
// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
// }
func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
return &GomegaWithT{
t: t,
@ -340,7 +347,7 @@ func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
//See documentation for Expect
func (g *GomegaWithT) Expect(actual interface{}, extra ...interface{}) GomegaAssertion {
return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailHandler(g.t), 0, extra...)
return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...)
}
//See documentation for Eventually
@ -353,7 +360,7 @@ func (g *GomegaWithT) Eventually(actual interface{}, intervals ...interface{}) G
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailHandler(g.t), timeoutInterval, pollingInterval, 0)
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
}
//See documentation for Consistently
@ -366,7 +373,7 @@ func (g *GomegaWithT) Consistently(actual interface{}, intervals ...interface{})
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailHandler(g.t), timeoutInterval, pollingInterval, 0)
return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
}
func toDuration(input interface{}) time.Duration {

View file

@ -9,37 +9,42 @@ import (
type Assertion struct {
actualInput interface{}
fail types.GomegaFailHandler
failWrapper *types.GomegaFailWrapper
offset int
extra []interface{}
}
func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion {
func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion {
return &Assertion{
actualInput: actualInput,
fail: fail,
failWrapper: failWrapper,
offset: offset,
extra: extra,
}
}
func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
@ -55,8 +60,9 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{})
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
matches, err := matcher.Match(assertion.actualInput)
description := assertion.buildDescription(optionalDescription...)
assertion.failWrapper.TWithHelper.Helper()
if err != nil {
assertion.fail(description+err.Error(), 2+assertion.offset)
assertion.failWrapper.Fail(description+err.Error(), 2+assertion.offset)
return false
}
if matches != desiredMatch {
@ -66,7 +72,7 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool
} else {
message = matcher.NegatedFailureMessage(assertion.actualInput)
}
assertion.fail(description+message, 2+assertion.offset)
assertion.failWrapper.Fail(description+message, 2+assertion.offset)
return false
}
@ -80,7 +86,8 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
}
description := assertion.buildDescription(optionalDescription...)
assertion.fail(description+message, 2+assertion.offset)
assertion.failWrapper.TWithHelper.Helper()
assertion.failWrapper.Fail(description+message, 2+assertion.offset)
return false
}

View file

@ -22,11 +22,11 @@ type AsyncAssertion struct {
actualInput interface{}
timeoutInterval time.Duration
pollingInterval time.Duration
fail types.GomegaFailHandler
failWrapper *types.GomegaFailWrapper
offset int
}
func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
func New(asyncType AsyncAssertionType, actualInput interface{}, failWrapper *types.GomegaFailWrapper, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
actualType := reflect.TypeOf(actualInput)
if actualType.Kind() == reflect.Func {
if actualType.NumIn() != 0 || actualType.NumOut() == 0 {
@ -37,7 +37,7 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg
return &AsyncAssertion{
asyncType: asyncType,
actualInput: actualInput,
fail: fail,
failWrapper: failWrapper,
timeoutInterval: timeoutInterval,
pollingInterval: pollingInterval,
offset: offset,
@ -45,10 +45,12 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg
}
func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.match(matcher, true, optionalDescription...)
}
func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.match(matcher, false, optionalDescription...)
}
@ -110,6 +112,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
matches, err = matcher.Match(value)
}
assertion.failWrapper.TWithHelper.Helper()
fail := func(preamble string) {
errMsg := ""
message := ""
@ -122,7 +126,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
message = matcher.NegatedFailureMessage(value)
}
}
assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
assertion.failWrapper.TWithHelper.Helper()
assertion.failWrapper.Fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
}
if assertion.asyncType == AsyncAssertionTypeEventually {

View file

@ -8,30 +8,50 @@ import (
"github.com/onsi/gomega/types"
)
var StackTracePruneRE = regexp.MustCompile(`\/gomega\/|\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
type EmptyTWithHelper struct{}
func (e EmptyTWithHelper) Helper() {}
type gomegaTestingT interface {
Fatalf(format string, args ...interface{})
}
func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler {
return func(message string, callerSkip ...int) {
skip := 1
if len(callerSkip) > 0 {
skip = callerSkip[0]
func BuildTestingTGomegaFailWrapper(t gomegaTestingT) *types.GomegaFailWrapper {
tWithHelper, hasHelper := t.(types.TWithHelper)
if !hasHelper {
tWithHelper = EmptyTWithHelper{}
}
fail := func(message string, callerSkip ...int) {
if hasHelper {
tWithHelper.Helper()
t.Fatalf("\n%s", message)
} else {
skip := 2
if len(callerSkip) > 0 {
skip += callerSkip[0]
}
stackTrace := pruneStack(string(debug.Stack()), skip)
t.Fatalf("\n%s\n%s\n", stackTrace, message)
}
stackTrace := pruneStack(string(debug.Stack()), skip)
t.Fatalf("\n%s\n%s", stackTrace, message)
}
return &types.GomegaFailWrapper{
Fail: fail,
TWithHelper: tWithHelper,
}
}
func pruneStack(fullStackTrace string, skip int) string {
stack := strings.Split(fullStackTrace, "\n")
if len(stack) > 2*(skip+1) {
stack = stack[2*(skip+1):]
stack := strings.Split(fullStackTrace, "\n")[1:]
if len(stack) > 2*skip {
stack = stack[2*skip:]
}
prunedStack := []string{}
re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
for i := 0; i < len(stack)/2; i++ {
if !re.Match([]byte(stack[i*2])) {
if !StackTracePruneRE.Match([]byte(stack[i*2])) {
prunedStack = append(prunedStack, stack[i*2])
prunedStack = append(prunedStack, stack[i*2+1])
}

View file

@ -344,9 +344,9 @@ func BeTemporally(comparator string, compareTo time.Time, threshold ...time.Dura
//BeAssignableToTypeOf succeeds if actual is assignable to the type of expected.
//It will return an error when one of the values is nil.
// Expect(0).Should(BeAssignableToTypeOf(0)) // Same values
// Expect(5).Should(BeAssignableToTypeOf(-1)) // different values same type
// Expect("foo").Should(BeAssignableToTypeOf("bar")) // different values same type
// Expect(0).Should(BeAssignableToTypeOf(0)) // Same values
// Expect(5).Should(BeAssignableToTypeOf(-1)) // different values same type
// Expect("foo").Should(BeAssignableToTypeOf("bar")) // different values same type
// Expect(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{}))
func BeAssignableToTypeOf(expected interface{}) types.GomegaMatcher {
return &matchers.AssignableToTypeOfMatcher{

View file

@ -13,11 +13,23 @@ type BeNumericallyMatcher struct {
}
func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo[0])
return matcher.FormatFailureMessage(actual, false)
}
func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo[0])
return matcher.FormatFailureMessage(actual, true)
}
func (matcher *BeNumericallyMatcher) FormatFailureMessage(actual interface{}, negated bool) (message string) {
if len(matcher.CompareTo) == 1 {
message = fmt.Sprintf("to be %s", matcher.Comparator)
} else {
message = fmt.Sprintf("to be within %v of %s", matcher.CompareTo[1], matcher.Comparator)
}
if negated {
message = "not " + message
}
return format.Message(actual, message, matcher.CompareTo[0])
}
func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) {

View file

@ -4,8 +4,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"strings"
"github.com/onsi/gomega/format"
)
@ -42,32 +40,6 @@ func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (mess
return formattedMessage(format.Message(actualString, "not to match JSON of", expectedString), matcher.firstFailurePath)
}
func formattedMessage(comparisonMessage string, failurePath []interface{}) string {
var diffMessage string
if len(failurePath) == 0 {
diffMessage = ""
} else {
diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath))
}
return fmt.Sprintf("%s%s", comparisonMessage, diffMessage)
}
func formattedFailurePath(failurePath []interface{}) string {
formattedPaths := []string{}
for i := len(failurePath) - 1; i >= 0; i-- {
switch p := failurePath[i].(type) {
case int:
formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p))
default:
if i != len(failurePath)-1 {
formattedPaths = append(formattedPaths, ".")
}
formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p))
}
}
return strings.Join(formattedPaths, "")
}
func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
actualString, ok := toString(actual)
if !ok {
@ -91,45 +63,3 @@ func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatte
return abuf.String(), ebuf.String(), nil
}
func deepEqual(a interface{}, b interface{}) (bool, []interface{}) {
var errorPath []interface{}
if reflect.TypeOf(a) != reflect.TypeOf(b) {
return false, errorPath
}
switch a.(type) {
case []interface{}:
if len(a.([]interface{})) != len(b.([]interface{})) {
return false, errorPath
}
for i, v := range a.([]interface{}) {
elementEqual, keyPath := deepEqual(v, b.([]interface{})[i])
if !elementEqual {
return false, append(keyPath, i)
}
}
return true, errorPath
case map[string]interface{}:
if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) {
return false, errorPath
}
for k, v1 := range a.(map[string]interface{}) {
v2, ok := b.(map[string]interface{})[k]
if !ok {
return false, errorPath
}
elementEqual, keyPath := deepEqual(v1, v2)
if !elementEqual {
return false, append(keyPath, k)
}
}
return true, errorPath
default:
return a == b, errorPath
}
}

View file

@ -2,7 +2,6 @@ package matchers
import (
"fmt"
"reflect"
"strings"
"github.com/onsi/gomega/format"
@ -10,7 +9,8 @@ import (
)
type MatchYAMLMatcher struct {
YAMLToMatch interface{}
YAMLToMatch interface{}
firstFailurePath []interface{}
}
func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) {
@ -29,17 +29,19 @@ func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err er
return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err)
}
return reflect.DeepEqual(aval, eval), nil
var equal bool
equal, matcher.firstFailurePath = deepEqual(aval, eval)
return equal, nil
}
func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
return format.Message(actualString, "to match YAML of", expectedString)
return formattedMessage(format.Message(actualString, "to match YAML of", expectedString), matcher.firstFailurePath)
}
func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
return format.Message(actualString, "not to match YAML of", expectedString)
return formattedMessage(format.Message(actualString, "not to match YAML of", expectedString), matcher.firstFailurePath)
}
func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) {

View file

@ -35,11 +35,6 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro
if argType.Kind() != reflect.Ptr {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1))
}
assignable := channelType.Elem().AssignableTo(argType.Elem())
if !assignable {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(matcher.Arg, 1))
}
}
}
@ -71,7 +66,18 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro
if didReceive {
if matcher.Arg != nil {
outValue := reflect.ValueOf(matcher.Arg)
reflect.Indirect(outValue).Set(value)
if value.Type().AssignableTo(outValue.Elem().Type()) {
outValue.Elem().Set(value)
return true, nil
}
if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
outValue.Elem().Set(value.Elem())
return true, nil
} else {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1))
}
}
return true, nil

View file

@ -0,0 +1,92 @@
package matchers
import (
"fmt"
"reflect"
"strings"
)
func formattedMessage(comparisonMessage string, failurePath []interface{}) string {
var diffMessage string
if len(failurePath) == 0 {
diffMessage = ""
} else {
diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath))
}
return fmt.Sprintf("%s%s", comparisonMessage, diffMessage)
}
func formattedFailurePath(failurePath []interface{}) string {
formattedPaths := []string{}
for i := len(failurePath) - 1; i >= 0; i-- {
switch p := failurePath[i].(type) {
case int:
formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p))
default:
if i != len(failurePath)-1 {
formattedPaths = append(formattedPaths, ".")
}
formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p))
}
}
return strings.Join(formattedPaths, "")
}
func deepEqual(a interface{}, b interface{}) (bool, []interface{}) {
var errorPath []interface{}
if reflect.TypeOf(a) != reflect.TypeOf(b) {
return false, errorPath
}
switch a.(type) {
case []interface{}:
if len(a.([]interface{})) != len(b.([]interface{})) {
return false, errorPath
}
for i, v := range a.([]interface{}) {
elementEqual, keyPath := deepEqual(v, b.([]interface{})[i])
if !elementEqual {
return false, append(keyPath, i)
}
}
return true, errorPath
case map[interface{}]interface{}:
if len(a.(map[interface{}]interface{})) != len(b.(map[interface{}]interface{})) {
return false, errorPath
}
for k, v1 := range a.(map[interface{}]interface{}) {
v2, ok := b.(map[interface{}]interface{})[k]
if !ok {
return false, errorPath
}
elementEqual, keyPath := deepEqual(v1, v2)
if !elementEqual {
return false, append(keyPath, k)
}
}
return true, errorPath
case map[string]interface{}:
if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) {
return false, errorPath
}
for k, v1 := range a.(map[string]interface{}) {
v2, ok := b.(map[string]interface{})[k]
if !ok {
return false, errorPath
}
elementEqual, keyPath := deepEqual(v1, v2)
if !elementEqual {
return false, append(keyPath, k)
}
}
return true, errorPath
default:
return a == b, errorPath
}
}

View file

@ -9,6 +9,7 @@ http://onsi.github.io/gomega/
package matchers
import (
"encoding/json"
"fmt"
"reflect"
)
@ -133,6 +134,11 @@ func toString(a interface{}) (string, bool) {
return aStringer.String(), true
}
aJSONRawMessage, isJSONRawMessage := a.(json.RawMessage)
if isJSONRawMessage {
return string(aJSONRawMessage), true
}
return "", false
}

View file

@ -1,7 +1,16 @@
package types
type TWithHelper interface {
Helper()
}
type GomegaFailHandler func(message string, callerSkip ...int)
type GomegaFailWrapper struct {
Fail GomegaFailHandler
TWithHelper TWithHelper
}
//A simple *testing.T interface wrapper
type GomegaTestingT interface {
Fatalf(format string, args ...interface{})