aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go')
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go669
1 files changed, 669 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go
new file mode 100644
index 000000000..a25ca8b9c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/terst/terst.go
@@ -0,0 +1,669 @@
+// This file was AUTOMATICALLY GENERATED by terst-import (smuggol) from github.com/robertkrimen/terst
+
+/*
+Package terst is a terse (terst = test + terse), easy-to-use testing library for Go.
+
+terst is compatible with (and works via) the standard testing package: http://golang.org/pkg/testing
+
+ var is = terst.Is
+
+ func Test(t *testing.T) {
+ terst.Terst(t, func() {
+ is("abc", "abc")
+
+ is(1, ">", 0)
+
+ var abc []int
+ is(abc, nil)
+ }
+ }
+
+Do not import terst directly, instead use `terst-import` to copy it into your testing environment:
+
+https://github.com/robertkrimen/terst/tree/master/terst-import
+
+ $ go get github.com/robertkrimen/terst/terst-import
+
+ $ terst-import
+
+*/
+package terst
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math/big"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+// Is compares two values (got & expect) and returns true if the comparison is true,
+// false otherwise. In addition, if the comparison is false, Is will report the error
+// in a manner similar to testing.T.Error(...). Is also takes an optional argument,
+// a comparator, that changes how the comparison is made. The following
+// comparators are available:
+//
+// == # got == expect (default)
+// != # got != expect
+//
+// > # got > expect (float32, uint, uint16, int, int64, ...)
+// >= # got >= expect
+// < # got < expect
+// <= # got <= expect
+//
+// =~ # regexp.MustCompile(expect).Match{String}(got)
+// !~ # !regexp.MustCompile(expect).Match{String}(got)
+//
+// Basic usage with the default comparator (==):
+//
+// Is(<got>, <expect>)
+//
+// Specifying a different comparator:
+//
+// Is(<got>, <comparator>, <expect>)
+//
+// A simple comparison:
+//
+// Is(2 + 2, 4)
+//
+// A bit trickier:
+//
+// Is(1, ">", 0)
+// Is(2 + 2, "!=", 5)
+// Is("Nothing happens.", "=~", `ing(\s+)happens\.$`)
+//
+// Is should only be called under a Terst(t, ...) call. For a standalone version,
+// use IsErr. If no scope is found and the comparison is false, then Is will panic the error.
+//
+func Is(arguments ...interface{}) bool {
+ err := IsErr(arguments...)
+ if err != nil {
+ call := Caller()
+ if call == nil {
+ panic(err)
+ }
+ call.Error(err)
+ return false
+ }
+ return true
+}
+
+type (
+ // ErrFail indicates a comparison failure (e.g. 0 > 1).
+ ErrFail error
+
+ // ErrInvalid indicates an invalid comparison (e.g. bool == string).
+ ErrInvalid error
+)
+
+var errInvalid = errors.New("invalid")
+
+var registry = struct {
+ table map[uintptr]*_scope
+ lock sync.RWMutex
+}{
+ table: map[uintptr]*_scope{},
+}
+
+func registerScope(pc uintptr, scope *_scope) {
+ registry.lock.Lock()
+ defer registry.lock.Unlock()
+ registry.table[pc] = scope
+}
+
+func scope() *_scope {
+ scope, _ := findScope()
+ return scope
+}
+
+func floatCompare(a float64, b float64) int {
+ if a > b {
+ return 1
+ } else if a < b {
+ return -1
+ }
+ // NaN == NaN
+ return 0
+}
+
+func bigIntCompare(a *big.Int, b *big.Int) int {
+ return a.Cmp(b)
+}
+
+func bigInt(value int64) *big.Int {
+ return big.NewInt(value)
+}
+
+func bigUint(value uint64) *big.Int {
+ return big.NewInt(0).SetUint64(value)
+}
+
+type _toString interface {
+ String() string
+}
+
+func toString(value interface{}) (string, error) {
+ switch value := value.(type) {
+ case string:
+ return value, nil
+ case _toString:
+ return value.String(), nil
+ case error:
+ return value.Error(), nil
+ }
+ return "", errInvalid
+}
+
+func matchString(got string, expect *regexp.Regexp) (int, error) {
+ if expect.MatchString(got) {
+ return 0, nil
+ }
+ return -1, nil
+}
+
+func match(got []byte, expect *regexp.Regexp) (int, error) {
+ if expect.Match(got) {
+ return 0, nil
+ }
+ return -1, nil
+}
+
+func compareMatch(got, expect interface{}) (int, error) {
+ switch got := got.(type) {
+ case []byte:
+ switch expect := expect.(type) {
+ case string:
+ matcher, err := regexp.Compile(expect)
+ if err != nil {
+ return 0, err
+ }
+ return match(got, matcher)
+ case *regexp.Regexp:
+ return match(got, expect)
+ }
+ default:
+ if got, err := toString(got); err == nil {
+ switch expect := expect.(type) {
+ case string:
+ matcher, err := regexp.Compile(expect)
+ if err != nil {
+ return 0, err
+ }
+ return matchString(got, matcher)
+ case *regexp.Regexp:
+ return matchString(got, expect)
+ }
+ } else {
+ return 0, err
+ }
+ }
+ return 0, errInvalid
+}
+
+func floatPromote(value reflect.Value) (float64, error) {
+ kind := value.Kind()
+ if reflect.Int <= kind && kind <= reflect.Int64 {
+ return float64(value.Int()), nil
+ }
+ if reflect.Uint <= kind && kind <= reflect.Uint64 {
+ return float64(value.Uint()), nil
+ }
+ if reflect.Float32 <= kind && kind <= reflect.Float64 {
+ return value.Float(), nil
+ }
+ return 0, errInvalid
+}
+
+func bigIntPromote(value reflect.Value) (*big.Int, error) {
+ kind := value.Kind()
+ if reflect.Int <= kind && kind <= reflect.Int64 {
+ return bigInt(value.Int()), nil
+ }
+ if reflect.Uint <= kind && kind <= reflect.Uint64 {
+ return bigUint(value.Uint()), nil
+ }
+ return nil, errInvalid
+}
+
+func compareOther(got, expect interface{}) (int, error) {
+ {
+ switch expect.(type) {
+ case float32, float64:
+ return compareNumber(got, expect)
+ case uint, uint8, uint16, uint32, uint64:
+ return compareNumber(got, expect)
+ case int, int8, int16, int32, int64:
+ return compareNumber(got, expect)
+ case string:
+ var err error
+ got, err = toString(got)
+ if err != nil {
+ return 0, err
+ }
+ case nil:
+ got := reflect.ValueOf(got)
+ switch got.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface:
+ if got.IsNil() {
+ return 0, nil
+ }
+ return -1, nil
+ case reflect.Invalid: // reflect.Invalid: var abc interface{} = nil
+ return 0, nil
+ }
+ return 0, errInvalid
+ }
+ }
+
+ if reflect.ValueOf(got).Type() != reflect.ValueOf(expect).Type() {
+ return 0, errInvalid
+ }
+
+ if reflect.DeepEqual(got, expect) {
+ return 0, nil
+ }
+ return -1, nil
+}
+
+func compareNumber(got, expect interface{}) (int, error) {
+ {
+ got := reflect.ValueOf(got)
+ k0 := got.Kind()
+ expect := reflect.ValueOf(expect)
+ k1 := expect.Kind()
+ if reflect.Float32 <= k0 && k0 <= reflect.Float64 ||
+ reflect.Float32 <= k1 && k1 <= reflect.Float64 {
+ got, err := floatPromote(got)
+ if err != nil {
+ return 0, err
+ }
+ expect, err := floatPromote(expect)
+ if err != nil {
+ return 0, err
+ }
+ return floatCompare(got, expect), nil
+ } else {
+ got, err := bigIntPromote(got)
+ if err != nil {
+ return 0, err
+ }
+ expect, err := bigIntPromote(expect)
+ if err != nil {
+ return 0, err
+ }
+ return got.Cmp(expect), nil
+ }
+ }
+
+ return 0, errInvalid
+}
+
+// IsErr compares two values (got & expect) and returns nil if the comparison is true, an ErrFail if
+// the comparison is false, or an ErrInvalid if the comparison is invalid. IsErr also
+// takes an optional argument, a comparator, that changes how the comparison is made.
+//
+// Is & IsErr are similar but different:
+//
+// Is(...) // Should only be called within a Terst(...) call
+// IsErr(...) // A standalone comparator, the same as Is, just without the automatic reporting
+//
+func IsErr(arguments ...interface{}) error {
+ var got, expect interface{}
+ comparator := "=="
+ switch len(arguments) {
+ case 0, 1:
+ return fmt.Errorf("invalid number of arguments to IsErr: %d", len(arguments))
+ case 2:
+ got, expect = arguments[0], arguments[1]
+ default:
+ if value, ok := arguments[1].(string); ok {
+ comparator = value
+ } else {
+ return fmt.Errorf("invalid comparator: %v", arguments[1])
+ }
+ got, expect = arguments[0], arguments[2]
+ }
+
+ var result int
+ var err error
+
+ switch comparator {
+ case "<", "<=", ">", ">=":
+ result, err = compareNumber(got, expect)
+ case "=~", "!~":
+ result, err = compareMatch(got, expect)
+ case "==", "!=":
+ result, err = compareOther(got, expect)
+ default:
+ return fmt.Errorf("invalid comparator: %s", comparator)
+ }
+
+ if err == errInvalid {
+ return ErrInvalid(fmt.Errorf(
+ "\nINVALID (%s):\n got: %v (%T)\n expected: %v (%T)",
+ comparator,
+ got, got,
+ expect, expect,
+ ))
+ } else if err != nil {
+ return err
+ }
+
+ equality, pass := false, false
+
+ switch comparator {
+ case "==", "=~":
+ equality = true
+ pass = result == 0
+ case "!=", "!~":
+ equality = true
+ pass = result != 0
+ case "<":
+ pass = result < 0
+ case "<=":
+ pass = result <= 0
+ case ">":
+ pass = result > 0
+ case ">=":
+ pass = result >= 0
+ }
+
+ if !pass {
+ if equality {
+ if comparator[1] == '~' {
+ if value, ok := got.([]byte); ok {
+ return ErrFail(fmt.Errorf(
+ "\nFAIL (%s)\n got: %s %v%s\nexpected: %v%s",
+ comparator,
+ value, got, typeKindString(got),
+ expect, typeKindString(expect),
+ ))
+ }
+ }
+ return ErrFail(fmt.Errorf(
+ "\nFAIL (%s)\n got: %v%s\nexpected: %v%s",
+ comparator,
+ got, typeKindString(got),
+ expect, typeKindString(expect),
+ ))
+ }
+ return ErrFail(fmt.Errorf(
+ "\nFAIL (%s)\n got: %v%s\nexpected: %s %v%s",
+ comparator,
+ got, typeKindString(got),
+ comparator, expect, typeKindString(expect),
+ ))
+ }
+
+ return nil
+}
+
+func typeKindString(value interface{}) string {
+ reflectValue := reflect.ValueOf(value)
+ kind := reflectValue.Kind().String()
+ result := fmt.Sprintf("%T", value)
+ if kind == result {
+ if kind == "string" {
+ return ""
+ }
+ return fmt.Sprintf(" (%T)", value)
+ }
+ return fmt.Sprintf(" (%T=%s)", value, kind)
+}
+
+func (scope *_scope) reset() {
+ scope.name = ""
+ scope.output = scope.output[:]
+ scope.start = time.Time{}
+ scope.duration = 0
+}
+
+// Terst creates a testing scope, where Is can be called and errors will be reported
+// according to the top-level location of the comparison, and not where the Is call
+// actually takes place. For example:
+//
+// func test(value int) {
+// Is(value, 5) // <--- This failure is reported below.
+// }
+//
+// Terst(t, func(){
+//
+// Is(2, ">", 3) // <--- An error is reported here.
+//
+// test(5) // <--- An error is reported here.
+//
+// })
+//
+func Terst(t *testing.T, arguments ...func()) {
+ scope := &_scope{
+ t: t,
+ }
+
+ pc, _, _, ok := runtime.Caller(1) // TODO Associate with the Test... func
+ if !ok {
+ panic("Here be dragons.")
+ }
+
+ _, scope.testFunc = findTestFunc()
+
+ registerScope(pc, scope)
+
+ for _, fn := range arguments {
+ func() {
+ scope.reset()
+ name := scope.testFunc.Name()
+ index := strings.LastIndex(scope.testFunc.Name(), ".")
+ if index >= 0 {
+ name = name[index+1:] + "(Terst)"
+ } else {
+ name = "(Terst)"
+ }
+ name = "(Terst)"
+ scope.name = name
+ scope.start = time.Now()
+ defer func() {
+ scope.duration = time.Now().Sub(scope.start)
+ if err := recover(); err != nil {
+ scope.t.Fail()
+ scope.report()
+ panic(err)
+ }
+ scope.report()
+ }()
+ fn()
+ }()
+ }
+}
+
+// From "testing"
+func (scope *_scope) report() {
+ format := "~~~ %s: (Terst)\n%s"
+ if scope.t.Failed() {
+ fmt.Printf(format, "FAIL", scope.output)
+ } else if testing.Verbose() && len(scope.output) > 0 {
+ fmt.Printf(format, "PASS", scope.output)
+ }
+}
+
+func (scope *_scope) log(call _entry, str string) {
+ scope.mu.Lock()
+ defer scope.mu.Unlock()
+ scope.output = append(scope.output, decorate(call, str)...)
+}
+
+// decorate prefixes the string with the file and line of the call site
+// and inserts the final newline if needed and indentation tabs for formascing.
+func decorate(call _entry, s string) string {
+
+ file, line := call.File, call.Line
+ if call.PC > 0 {
+ // Truncate file name at last file name separator.
+ if index := strings.LastIndex(file, "/"); index >= 0 {
+ file = file[index+1:]
+ } else if index = strings.LastIndex(file, "\\"); index >= 0 {
+ file = file[index+1:]
+ }
+ } else {
+ file = "???"
+ line = 1
+ }
+ buf := new(bytes.Buffer)
+ // Every line is indented at least one tab.
+ buf.WriteByte('\t')
+ fmt.Fprintf(buf, "%s:%d: ", file, line)
+ lines := strings.Split(s, "\n")
+ if l := len(lines); l > 1 && lines[l-1] == "" {
+ lines = lines[:l-1]
+ }
+ for i, line := range lines {
+ if i > 0 {
+ // Second and subsequent lines are indented an extra tab.
+ buf.WriteString("\n\t\t")
+ }
+ buf.WriteString(line)
+ }
+ buf.WriteByte('\n')
+ return buf.String()
+}
+
+func findScope() (*_scope, _entry) {
+ registry.lock.RLock()
+ defer registry.lock.RUnlock()
+ table := registry.table
+ depth := 2 // Starting depth
+ call := _entry{}
+ for {
+ pc, _, _, ok := runtime.Caller(depth)
+ if !ok {
+ break
+ }
+ if scope, exists := table[pc]; exists {
+ pc, file, line, _ := runtime.Caller(depth - 3) // Terst(...) + func(){}() + fn() => ???()
+ call.PC = pc
+ call.File = file
+ call.Line = line
+ return scope, call
+ }
+ depth++
+ }
+ return nil, _entry{}
+}
+
+// Call is a reference to a line immediately under a Terst testing scope.
+type Call struct {
+ scope *_scope
+ entry _entry
+}
+
+// Caller will search the stack, looking for a Terst testing scope. If a scope
+// is found, then Caller returns a Call for logging errors, accessing testing.T, etc.
+// If no scope is found, Caller returns nil.
+func Caller() *Call {
+ scope, entry := findScope()
+ if scope == nil {
+ return nil
+ }
+ return &Call{
+ scope: scope,
+ entry: entry,
+ }
+}
+
+// TestFunc returns the *runtime.Func entry for the top-level Test...(t testing.T)
+// function.
+func (cl *Call) TestFunc() *runtime.Func {
+ return cl.scope.testFunc
+}
+
+// T returns the original testing.T passed to Terst(...)
+func (cl *Call) T() *testing.T {
+ return cl.scope.t
+}
+
+// Log is the terst version of `testing.T.Log`
+func (cl *Call) Log(arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintln(arguments...))
+}
+
+// Logf is the terst version of `testing.T.Logf`
+func (cl *Call) Logf(format string, arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...))
+}
+
+// Error is the terst version of `testing.T.Error`
+func (cl *Call) Error(arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintln(arguments...))
+ cl.scope.t.Fail()
+}
+
+// Errorf is the terst version of `testing.T.Errorf`
+func (cl *Call) Errorf(format string, arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...))
+ cl.scope.t.Fail()
+}
+
+// Skip is the terst version of `testing.T.Skip`
+func (cl *Call) Skip(arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintln(arguments...))
+ cl.scope.t.SkipNow()
+}
+
+// Skipf is the terst version of `testing.T.Skipf`
+func (cl *Call) Skipf(format string, arguments ...interface{}) {
+ cl.scope.log(cl.entry, fmt.Sprintf(format, arguments...))
+ cl.scope.t.SkipNow()
+}
+
+type _scope struct {
+ t *testing.T
+ testFunc *runtime.Func
+ name string
+ mu sync.RWMutex
+ output []byte
+ start time.Time
+ duration time.Duration
+}
+
+type _entry struct {
+ PC uintptr
+ File string
+ Line int
+ Func *runtime.Func
+}
+
+func _findFunc(match string) (_entry, *runtime.Func) {
+ depth := 2 // Starting depth
+ for {
+ pc, file, line, ok := runtime.Caller(depth)
+ if !ok {
+ break
+ }
+ fn := runtime.FuncForPC(pc)
+ name := fn.Name()
+ if index := strings.LastIndex(name, match); index >= 0 {
+ // Assume we have an instance of TestXyzzy in a _test file
+ return _entry{
+ PC: pc,
+ File: file,
+ Line: line,
+ Func: fn,
+ }, fn
+ }
+ depth++
+ }
+ return _entry{}, nil
+}
+
+func findTestFunc() (_entry, *runtime.Func) {
+ return _findFunc(".Test")
+}
+
+func findTerstFunc() (_entry, *runtime.Func) {
+ return _findFunc(".Terst")
+}