New Upstream Snapshot - golang-github-karlseguin-expect

Ready changes

Summary

Merged new upstream version: 1.0.8 (was: 1.0.1+git20160716.12.5c2eadb).

Resulting package

Built on 2022-11-19T03:34 (took 3m51s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots golang-github-karlseguin-expect-dev

Lintian Result

Diff

diff --git a/debian/changelog b/debian/changelog
index 3bfd27d..a2e57b6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-karlseguin-expect (1.0.8-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 19 Nov 2022 03:31:33 -0000
+
 golang-github-karlseguin-expect (1.0.1+git20160716.12.5c2eadb-2) unstable; urgency=medium
 
   * Team Upload.
diff --git a/debian/patches/0001-fix-parsing-flags.patch b/debian/patches/0001-fix-parsing-flags.patch
index efed141..c5aee59 100644
--- a/debian/patches/0001-fix-parsing-flags.patch
+++ b/debian/patches/0001-fix-parsing-flags.patch
@@ -1,7 +1,9 @@
 Description: Initialize test so that test flags can be parsed during execution.
---- a/runner.go
-+++ b/runner.go
-@@ -30,6 +30,11 @@
+Index: golang-github-karlseguin-expect.git/runner.go
+===================================================================
+--- golang-github-karlseguin-expect.git.orig/runner.go
++++ golang-github-karlseguin-expect.git/runner.go
+@@ -34,6 +34,11 @@ var (
  	summaryPattern = regexp.MustCompile(`(?s)(\d+) passed.*?(\d+) failed`)
  )
  
@@ -12,4 +14,4 @@ Description: Initialize test so that test flags can be parsed during execution.
 +
  func init() {
  	os.Setenv("GO_TEST", "true")
- 
+ }
diff --git a/expect.go b/expect.go
index 8e6683b..1ff2ee9 100644
--- a/expect.go
+++ b/expect.go
@@ -110,7 +110,7 @@ func (e *ToExpectation) Equal(expected interface{}, others ...interface{}) PostH
 	assertion.invert = e.invert
 	failed := !equal(assertion, e.actual, expected)
 
-	if len(others) != len(e.others) {
+	if len(others) > len(e.others) {
 		Errorf("mismatch number of values and expectations %d != %d", len(e.others)+1, len(others)+1)
 		failed = true
 	} else {
@@ -128,10 +128,10 @@ func (e *ToExpectation) Equal(expected interface{}, others ...interface{}) PostH
 }
 
 func (e *ToExpectation) Eql(expected interface{}, others ...interface{}) PostHandler {
-	if len(others) == len(e.others) {
-		expected = coerce(e.actual, expected)
+	if len(others) <= len(e.others) {
+		e.actual, expected = coerce(e.actual, expected)
 		for i := 0; i < len(others); i++ {
-			others[i] = coerce(e.others[i], others[i])
+			e.others[i], others[i] = coerce(e.others[i], others[i])
 		}
 	}
 
@@ -328,11 +328,26 @@ func convertFromJson(value interface{}) string {
 	return string(bytes)
 }
 
-func coerce(actual interface{}, expected interface{}) interface{} {
+func coerce(actual interface{}, expected interface{}) (interface{}, interface{}) {
 	at := reflect.TypeOf(actual)
 	et := reflect.TypeOf(expected)
+
+	if et == nil || at == nil {
+		return actual, expected
+	}
+
 	if et.ConvertibleTo(at) {
-		return reflect.ValueOf(expected).Convert(at).Interface()
+		return actual, reflect.ValueOf(expected).Convert(at).Interface()
+	}
+
+	if et.String() == "string" {
+		if error, ok := actual.(interface{ Error() string }); ok {
+			return error.Error(), expected
+		}
+		if stringer, ok := actual.(interface{ String() string }); ok {
+			return stringer.String(), expected
+		}
 	}
-	return expected
+
+	return actual, expected
 }
diff --git a/expect_test.go b/expect_test.go
index c60a7d4..42169ce 100644
--- a/expect_test.go
+++ b/expect_test.go
@@ -1,6 +1,7 @@
 package expect
 
 import (
+	"errors"
 	"fmt"
 	"testing"
 )
@@ -113,12 +114,11 @@ func (_ ExpectTests) Contain_Failures() {
 
 func (_ ExpectTests) ExpectMulipleValues_Success() {
 	Expect(1, true, "over 9000").To.Equal(1, true, "over 9000")
+	Expect([]byte("123"), nil).To.Equal([]byte("123"))
+	Expect([]byte("123"), nil).To.Eql("123")
 }
 
 func (_ ExpectTests) ExpectMulipleValues_Failure() {
-	failing("mismatch number of values and expectations 3 != 2", 1, func() {
-		Expect(1, true, "over 9000").To.Equal(1, true)
-	})
 	failing("mismatch number of values and expectations 2 != 3", 1, func() {
 		Expect(1, true).To.Equal(1, true, "a")
 	})
@@ -219,6 +219,18 @@ func (_ ExpectTests) EqlForStringAndBytes() {
 	Expect("CD").To.Eql([]byte{67, 68})
 }
 
+func (_ ExpectTests) EqlForStringAndError() {
+	Expect(errors.New("an error")).To.Eql("an error")
+
+	failing("expected \"an error\" to be equal to \"123\"", 1, func() {
+		Expect(errors.New("an error")).To.Eql("123")
+	})
+
+	failing("expected <nil> to be equal to 123", 1, func() {
+		Expect(nil).To.Eql("123")
+	})
+}
+
 func failing(expected string, count int, f func()) {
 	actuals := make([]string, 0, 5)
 	Errorf = func(format string, args ...interface{}) {
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..b8fd454
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module github.com/karlseguin/expect
+
+go 1.14
+
+require github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a766ef9
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ=
+github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
diff --git a/posthandler.go b/posthandler.go
index 6caeb7e..4adf1a4 100644
--- a/posthandler.go
+++ b/posthandler.go
@@ -6,7 +6,10 @@ import (
 )
 
 var (
-	SuccessHandler = &SuccessPostHandler{}
+	SuccessHandler        = &SuccessPostHandler{}
+	FailureHandlerFactory = func(expected, actual interface{}) PostHandler {
+		return &FailurePostHandler{expected, actual}
+	}
 )
 
 type PostHandler interface {
@@ -19,7 +22,7 @@ type FailurePostHandler struct {
 }
 
 func NewFailureHandler(expected, actual interface{}) PostHandler {
-	return &FailurePostHandler{expected, actual}
+	return FailureHandlerFactory(expected, actual)
 }
 
 func (h *FailurePostHandler) Message(format string, args ...interface{}) {
diff --git a/readme.md b/readme.md
index bc03b34..f519ebc 100644
--- a/readme.md
+++ b/readme.md
@@ -44,6 +44,9 @@ Run tests as you normally would via `go test`. However, to run specific tests, u
 
     go test -m AddsTwo
 
+### Exit On Error
+Use the -e flag to exit on a failed assertion.
+
 ## Expectations
 
 Two similar syntaxes of expectations are supported
@@ -61,7 +64,7 @@ All expectations can be reversed by starting the chain with `Not.`:
 * `Not.GreaterOrEqual.To(x)` or `Not.GreaterOrEqualTo(x)`
 * `Not.Less.Than(x)` or `Not.LessThan(x)`
 * `Not.LessOrEqual.To(x)` or `Not.LessOrEqualTo(x)`
-
+verbose
 ### Eql
 
 The `Equal` method is strict. This will fail:
@@ -123,21 +126,24 @@ Expect(res.Code).To.Equal(404).Message("Expected %d got %d")
 
 ## Multiple Values
 
-`Expect` throws away all but the first value. This is convenient when a method returns an error which you don't care to test:
+`Expect` will only compare the number of values expected. This is useful for ignoring nil errors:
 
 ```go
 Expect(ioutil.ReadFile("blah")).To.Equal([]byte{1, 2, 3, 4})
 ```
 
-However, using `To.Equal` multiple values can be provided:
+Multiple expected values can be provided and they'll be compared to the corresponding value:
 
 ```go
+Expect(1, true, "a").To.Equal(1, true)
 Expect(1, true, "a").To.Equal(1, true, "a")
+
+Expect(1, true, "a").To.Equal(1, true, "a", "NOPE") // will fail
 ```
 
 ## stdout
 
-Go's testing package has no hooks into its reporting. `Expect` takes the drastic step of occasionally silencing `os.Stdout`, which many packages uses (such as `fmt.Print`). However, within your test, `os.Stdout` **will** work.
+Go's testing package has no hooks into its reporting. `Expect` takes the drastic step of occasionally silencing `os.Stdout`, which many packages use (such as `fmt.Print`). However, within your test, `os.Stdout` **will** work.
 
 If you print anything outside of your test, say during `init`, it'll likely be silenced by `Expect`. You can disable this behavior with the `-vv` flag (use `-v` and `-vv` in combination to change the behavior of both `Expect` and Go's library)
 
@@ -162,7 +168,7 @@ func (ct *CalculatorTests) n() *Calculator {
 }
 ```
 
-Futhermore, when you setup the runner, you can setup code to before or after running tests (once for all tests, not once per test):
+Furthermore, when you setup the runner, you can setup code to before or after running tests (once for all tests, not once per test):
 
 ```go
 func Test_Caculator(t *testing.T) {
@@ -203,14 +209,16 @@ a brief summary beyond what Go's test runner provides (I always worry that every
 What we can do is use the `-summary <PATH>` flag and provide a path where summary data will be stored / updated. Therefore, even if multiple processes are launched, and even if we can't output to stdout, with a bit of work invoking the tests, we can get a summary. For example, I recommend a simple Makefile:
 
 ```Makefile
-    TEMPFILE := $(shell mktemp -u -t testsummary)
-
-    test:
-      go test ./... -summary $(TEMPFILE)
-      @if [ -a $(TEMPFILE) ] ; \
-      then \
-        awk '{s+=$$1} END {print "\033[1;32m", s, "passed"}' $(TEMPFILE); rm $(TEMPFILE) ;\
-      fi;
+TMPDIR := $(shell dirname $(shell mktemp -u))
+TEST_SUMMARY := $(TMPDIR)/$$(go list).go.summary
+
+test:
+  go test ./... -summary $(TEST_SUMMARY)
+  @if [ -a $(TEST_SUMMARY) ] ; \
+  then \
+    awk '{s+=$$1} END {print "\033[1;32m", s, "passed"}' $(TEST_SUMMARY); rm $(TEST_SUMMARY) ;\
+  fi;
+```
 
 # Mocks
 
diff --git a/runner.go b/runner.go
index 742c9b6..50d1be4 100644
--- a/runner.go
+++ b/runner.go
@@ -9,6 +9,7 @@ import (
 	"runtime"
 	"strconv"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 
@@ -16,7 +17,10 @@ import (
 )
 
 var (
+	loaded         = false
+	loadLock       = new(sync.Mutex)
 	showStdout     = flag.Bool("vv", false, "turn on stdout")
+	exitOnFailure  = flag.Bool("e", false, "exit on failures")
 	matchFlag      = flag.String("m", "", "Regular expression selecting which tests to run")
 	notMatchFlag   = flag.String("M", "", "Regular expression selecting which tests not to run")
 	summaryPath    = flag.String("summary", "", "Path to write a summary file to")
@@ -32,21 +36,38 @@ var (
 
 func init() {
 	os.Setenv("GO_TEST", "true")
-
-	flag.Parse()
-	if len(*matchFlag) != 0 {
-		pattern = regexp.MustCompile("(?i)" + *matchFlag)
-	}
-	if len(*notMatchFlag) != 0 {
-		notPattern = regexp.MustCompile("(?i)" + *notMatchFlag)
-	}
-	if *showStdout == true {
-		silentOut = stdout
-	}
-	os.Stdout = silentOut
 }
 
 func Expectify(suite interface{}, t *testing.T) {
+	loadLock.Lock()
+	if !loaded {
+		flag.Parse()
+		if len(*matchFlag) != 0 {
+			pattern = regexp.MustCompile("(?i)" + *matchFlag)
+		}
+		if len(*notMatchFlag) != 0 {
+			notPattern = regexp.MustCompile("(?i)" + *notMatchFlag)
+		}
+		if *showStdout == true {
+			silentOut = stdout
+		}
+		os.Stdout = silentOut
+		loaded = true
+
+		if *exitOnFailure {
+			FailureHandlerFactory = func(actual, expected interface{}) PostHandler {
+				for _, res := range runner.results {
+					if !res.Passed() || testing.Verbose() {
+						res.Report()
+					}
+				}
+				os.Exit(1)
+				return nil
+			}
+		}
+	}
+	loadLock.Unlock()
+
 	var name string
 	var res *result
 	defer func() {
@@ -192,27 +213,32 @@ func (r *Runner) Skip(format string, args ...interface{}) {
 }
 
 func (r *Runner) Errorf(format string, args ...interface{}) {
-	file := "???"
-	line := 1
-	ok := false
-	for i := 3; i < 10; i++ {
-		_, file, line, ok = runtime.Caller(i)
-		if ok == false || strings.HasSuffix(file, "_test.go") {
+	collecting := false
+	stacks := make([]string, 0, 5)
+
+	for i := 0; i < 20; i++ {
+		_, file, line, ok := runtime.Caller(i)
+		if ok == false {
 			break
 		}
-	}
 
-	if ok {
-		if index := strings.LastIndex(file, "/"); index >= 0 {
-			file = file[index+1:]
-		} else if index = strings.LastIndex(file, "\\"); index >= 0 {
-			file = file[index+1:]
+		isTest := strings.HasSuffix(file, "_test.go")
+		if collecting == false && isTest {
+			collecting = true
+		}
+
+		// we're no longer in the _test.go stack, stop collecting
+		if collecting == true && !isTest {
+			break
+		}
+		if collecting {
+			stacks = append(stacks, fmt.Sprintf("       %s:%d", file, line))
 		}
 	}
 
 	failure := &Failure{
 		message:  fmt.Sprintf(format, args...),
-		location: fmt.Sprintf("%s:%d", file, line),
+		location: strings.Join(stacks, "\n") + "\n",
 	}
 	r.current.failures = append(r.current.failures, failure)
 }
@@ -266,8 +292,8 @@ func (r *result) Report() {
 		color.Println(" @g✓", info)
 	} else {
 		color.Println(" @r×", info)
-		for _, failure := range r.failures {
-			color.Printf("    @.%-40s%s\n", failure.location, failure.message)
+		for i, failure := range r.failures {
+			color.Printf("    %d. %s\n@.%-40s\n", i+1, failure.message, failure.location)
 		}
 	}
 }

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/gocode/src/github.com/karlseguin/expect/go.mod
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/karlseguin/expect/go.sum

No differences were encountered in the control files

More details

Full run details