updated goblin test lib

This commit is contained in:
Brad Rydzewski 2016-03-07 11:51:06 -08:00
parent b0500836f1
commit 9559192fb5
7 changed files with 80 additions and 88 deletions

View File

@ -120,6 +120,15 @@ func Test(t *testing.T) {
} }
``` ```
FAQ:
----
### How do I run specific tests?
If `-goblin.run=$REGES` is supplied to the `go test` command then only tests that match the supplied regex will run
TODO: TODO:
----- -----

View File

@ -3,6 +3,7 @@ package goblin
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
) )
type Assertion struct { type Assertion struct {
@ -19,10 +20,6 @@ func objectsAreEqual(a, b interface{}) bool {
return true return true
} }
if reflect.ValueOf(a) == reflect.ValueOf(b) {
return true
}
if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) { if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
return true return true
} }
@ -30,24 +27,33 @@ func objectsAreEqual(a, b interface{}) bool {
return false return false
} }
func formatMessages(messages ...string) string {
if len(messages) > 0 {
return ", " + strings.Join(messages, " ")
}
return ""
}
func (a *Assertion) Eql(dst interface{}) { func (a *Assertion) Eql(dst interface{}) {
a.Equal(dst) a.Equal(dst)
} }
func (a *Assertion) Equal(dst interface{}) { func (a *Assertion) Equal(dst interface{}) {
if !objectsAreEqual(a.src, dst) { if !objectsAreEqual(a.src, dst) {
a.fail(fmt.Sprintf("%v", a.src) + " does not equal " + fmt.Sprintf("%v", dst)) a.fail(fmt.Sprintf("%#v %s %#v", a.src, "does not equal", dst))
} }
} }
func (a *Assertion) IsTrue() { func (a *Assertion) IsTrue(messages ...string) {
if !objectsAreEqual(a.src, true) { if !objectsAreEqual(a.src, true) {
a.fail(fmt.Sprintf("%v", a.src) + " expected false to be truthy") message := fmt.Sprintf("%v %s%s", a.src, "expected false to be truthy", formatMessages(messages...))
a.fail(message)
} }
} }
func (a *Assertion) IsFalse() { func (a *Assertion) IsFalse(messages ...string) {
if !objectsAreEqual(a.src, false) { if !objectsAreEqual(a.src, false) {
a.fail(fmt.Sprintf("%v", a.src) + " expected true to be falsey") message := fmt.Sprintf("%v %s%s", a.src, "expected true to be falsey", formatMessages(messages...))
a.fail(message)
} }
} }

View File

@ -3,8 +3,9 @@ package goblin
import ( import (
"flag" "flag"
"fmt" "fmt"
"os" "regexp"
"runtime" "runtime"
"sync"
"testing" "testing"
"time" "time"
) )
@ -28,7 +29,7 @@ func (g *G) Describe(name string, h func()) {
g.parent = d.parent g.parent = d.parent
if g.parent == nil { if g.parent == nil && d.hasTests {
g.reporter.begin() g.reporter.begin()
if d.run(g) { if d.run(g) {
g.t.Fail() g.t.Fail()
@ -71,31 +72,28 @@ func (d *Describe) runAfterEach() {
} }
func (d *Describe) run(g *G) bool { func (d *Describe) run(g *G) bool {
g.reporter.beginDescribe(d.name) failed := false
failed := ""
if d.hasTests { if d.hasTests {
g.reporter.beginDescribe(d.name)
for _, b := range d.befores { for _, b := range d.befores {
b() b()
} }
}
for _, r := range d.children { for _, r := range d.children {
if r.run(g) { if r.run(g) {
failed = "true" failed = true
}
} }
}
if d.hasTests {
for _, a := range d.afters { for _, a := range d.afters {
a() a()
} }
g.reporter.endDescribe()
} }
g.reporter.endDescribe() return failed
return failed != ""
} }
type Failure struct { type Failure struct {
@ -145,26 +143,29 @@ func (it *It) failed(msg string, stack []string) {
it.failure = &Failure{stack: stack, message: msg, testName: it.parent.name + " " + it.name} it.failure = &Failure{stack: stack, message: msg, testName: it.parent.name + " " + it.name}
} }
var timeout *time.Duration func parseFlags() {
//Flag parsing
flag.Parse()
if *regexParam != "" {
runRegex = regexp.MustCompile(*regexParam)
} else {
runRegex = nil
}
}
var timeout = flag.Duration("goblin.timeout", 5*time.Second, "Sets default timeouts for all tests")
var isTty = flag.Bool("goblin.tty", true, "Sets the default output format (color / monochrome)")
var regexParam = flag.String("goblin.run", "", "Runs only tests which match the supplied regex")
var runRegex *regexp.Regexp
func init() { func init() {
//Flag parsing parseFlags()
timeout = flag.Duration("goblin.timeout", 5*time.Second, "Sets default timeouts for all tests")
flag.Parse()
} }
func Goblin(t *testing.T, arguments ...string) *G { func Goblin(t *testing.T, arguments ...string) *G {
var gobtimeout = timeout g := &G{t: t, timeout: *timeout}
if arguments != nil {
//Programatic flags
var args = flag.NewFlagSet("Goblin arguments", flag.ContinueOnError)
gobtimeout = args.Duration("goblin.timeout", 5*time.Second, "Sets timeouts for tests")
args.Parse(arguments)
}
g := &G{t: t, timeout: *gobtimeout}
fd := os.Stdout.Fd()
var fancy TextFancier var fancy TextFancier
if IsTerminal(int(fd)) { if *isTty {
fancy = &TerminalFancier{} fancy = &TerminalFancier{}
} else { } else {
fancy = &Monochrome{} fancy = &Monochrome{}
@ -176,14 +177,16 @@ func Goblin(t *testing.T, arguments ...string) *G {
func runIt(g *G, h interface{}) { func runIt(g *G, h interface{}) {
defer timeTrack(time.Now(), g) defer timeTrack(time.Now(), g)
g.mutex.Lock()
g.timedOut = false g.timedOut = false
g.mutex.Unlock()
g.shouldContinue = make(chan bool) g.shouldContinue = make(chan bool)
if call, ok := h.(func()); ok { if call, ok := h.(func()); ok {
// the test is synchronous // the test is synchronous
go func() { call(); g.shouldContinue <- true }() go func(c chan bool) { call(); c <- true }(g.shouldContinue)
} else if call, ok := h.(func(Done)); ok { } else if call, ok := h.(func(Done)); ok {
doneCalled := 0 doneCalled := 0
go func() { go func(c chan bool) {
call(func(msg ...interface{}) { call(func(msg ...interface{}) {
if len(msg) > 0 { if len(msg) > 0 {
g.Fail(msg) g.Fail(msg)
@ -192,17 +195,16 @@ func runIt(g *G, h interface{}) {
if doneCalled > 1 { if doneCalled > 1 {
g.Fail("Done called multiple times") g.Fail("Done called multiple times")
} }
g.shouldContinue <- true c <- true
} }
}) })
}() }(g.shouldContinue)
} else { } else {
panic("Not implemented.") panic("Not implemented.")
} }
select { select {
case <-g.shouldContinue: case <-g.shouldContinue:
case <-time.After(g.timeout): case <-time.After(g.timeout):
fmt.Println("Timedout")
//Set to nil as it shouldn't continue //Set to nil as it shouldn't continue
g.shouldContinue = nil g.shouldContinue = nil
g.timedOut = true g.timedOut = true
@ -218,6 +220,7 @@ type G struct {
reporter Reporter reporter Reporter
timedOut bool timedOut bool
shouldContinue chan bool shouldContinue chan bool
mutex sync.Mutex
} }
func (g *G) SetReporter(r Reporter) { func (g *G) SetReporter(r Reporter) {
@ -225,12 +228,21 @@ func (g *G) SetReporter(r Reporter) {
} }
func (g *G) It(name string, h ...interface{}) { func (g *G) It(name string, h ...interface{}) {
it := &It{name: name, parent: g.parent, reporter: g.reporter} if matchesRegex(name) {
notifyParents(g.parent) it := &It{name: name, parent: g.parent, reporter: g.reporter}
if len(h) > 0 { notifyParents(g.parent)
it.h = h[0] if len(h) > 0 {
it.h = h[0]
}
g.parent.children = append(g.parent.children, Runnable(it))
} }
g.parent.children = append(g.parent.children, Runnable(it)) }
func matchesRegex(value string) bool {
if runRegex != nil {
return runRegex.MatchString(value)
}
return true
} }
func notifyParents(d *Describe) { func notifyParents(d *Describe) {
@ -272,9 +284,11 @@ func (g *G) Fail(error interface{}) {
if g.shouldContinue != nil { if g.shouldContinue != nil {
g.shouldContinue <- true g.shouldContinue <- true
} }
g.mutex.Lock()
defer g.mutex.Unlock()
if !g.timedOut { if !g.timedOut {
//Stop test function execution //Stop test function execution
runtime.Goexit() runtime.Goexit()
} }
} }

View File

@ -1,13 +0,0 @@
package goblin
import (
"syscall"
"unsafe"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

View File

@ -1,12 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package goblin
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
const ioctlWriteTermios = syscall.TIOCSETA

View File

@ -1,12 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package goblin
import "syscall"
const ioctlReadTermios = syscall.TCGETS
const ioctlWriteTermios = syscall.TCSETS

4
vendor/vendor.json vendored
View File

@ -50,8 +50,8 @@
}, },
{ {
"path": "github.com/franela/goblin", "path": "github.com/franela/goblin",
"revision": "a99b1e87ecb6884721c6586e8846ec368234fb9a", "revision": "889391d730237f8aca06ce3e62975112983f96b4",
"revisionTime": "2014-07-25T18:08:57-07:00" "revisionTime": "2016-01-23T18:11:54-03:00"
}, },
{ {
"path": "github.com/gin-gonic/gin", "path": "github.com/gin-gonic/gin",