Repository: stretchr/testify (go)

Issue:
Feature request: assert.Never
Proposal for new assertion to the API: `assert.Never(*testing.T, func() bool, time.Duration, time.Duration)`. It would be a direct mirror of `assert.Eventually`, checking that the given condition wasn't met within a certain timeframe.

Copying a bunch of code from `assert.Eventually`, the implementation could look like this: 

```go
func Never(t *testing.T, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
	timer := time.NewTimer(waitFor)
	ticker := time.NewTicker(tick)
	checkPassed := make(chan bool)
	defer timer.Stop()
	defer ticker.Stop()
	defer close(checkPassed)
	for {
		select {
		case <-timer.C:
			return true
		case result := <-checkPassed:
			if result {
				return assert.Fail(t, "Condition satisfied", msgAndArgs...)
			}
		case <-ticker.C:
			go func() {
				checkPassed <- condition()
			}()
		}
	}
}
```

If this is something the maintainers would merge, I'd be happy to make a PR with tests and documentation for it. 

Pull request description:
Add Never assertion
Closes #870 

Never asserts that a conditon isn't met within a given timeframe.

Patch:
diff --git a/.travis.gofmt.sh b/.travis.gofmt.sh
index bfffdca..3f2e5d3 100755
--- a/.travis.gofmt.sh
+++ b/.travis.gofmt.sh
@@ -5,3 +5,10 @@ if [ -n "$(gofmt -l .)" ]; then
   gofmt -d .
   exit 1
 fi
+
+go generate ./...
+if [ -n "$(git status -s -uno)" ]; then
+  echo "Go generate output does not match commit."
+  echo "Did you forget to run go generate ./... ?"
+  exit 1
+fi
diff --git a/.travis.yml b/.travis.yml
index d6eead9..2d4a445 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,7 +19,7 @@ matrix:
       env: GO111MODULE=off
     - go: "1.13.x"
       env: GO111MODULE=on
-    - go: tip
+    - go: master
 script:
   - ./.travis.gogenerate.sh
   - ./.travis.gofmt.sh
diff --git a/Gopkg.lock b/Gopkg.lock
deleted file mode 100644
index 294cda0..0000000
--- a/Gopkg.lock
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
-
-
-[[projects]]
-  name = "github.com/davecgh/go-spew"
-  packages = ["spew"]
-  revision = "346938d642f2ec3594ed81d874461961cd0faa76"
-  version = "v1.1.0"
-
-[[projects]]
-  name = "github.com/pmezard/go-difflib"
-  packages = ["difflib"]
-  revision = "792786c7400a136282c1664665ae0a8db921c6c2"
-  version = "v1.0.0"
-
-[[projects]]
-  name = "github.com/stretchr/objx"
-  packages = ["."]
-  revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
-  version = "v0.1"
-
-[solve-meta]
-  analyzer-name = "dep"
-  analyzer-version = 1
-  inputs-digest = "448ddae4702c6aded2555faafd390c537789bb1c483f70b0431e6634f73f2090"
-  solver-name = "gps-cdcl"
-  solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
deleted file mode 100644
index a16374c..0000000
--- a/Gopkg.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[prune]
-  unused-packages = true
-  non-go = true
-  go-tests = true
-
-[[constraint]]
-  name = "github.com/davecgh/go-spew"
-  version = "~1.1.0"
-
-[[constraint]]
-  name = "github.com/pmezard/go-difflib"
-  version = "~1.0.0"
-
-[[constraint]]
-  name = "github.com/stretchr/objx"
-  version = "~0.1.0"
diff --git a/assert/assertion_format.go b/assert/assertion_format.go
index d3a4a74..bf89ecd 100644
--- a/assert/assertion_format.go
+++ b/assert/assertion_format.go
@@ -363,6 +363,17 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args .
 	return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
 }
 
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
 // Nilf asserts that the specified object is nil.
 //
 //    assert.Nilf(t, err, "error message %s", "formatted")
diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go
index 84dab78..75ecdca 100644
--- a/assert/assertion_forward.go
+++ b/assert/assertion_forward.go
@@ -715,6 +715,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
 	return Lessf(a.t, e1, e2, msg, args...)
 }
 
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Never(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Neverf(a.t, condition, waitFor, tick, msg, args...)
+}
+
 // Nil asserts that the specified object is nil.
 //
 //    a.Nil(err)
diff --git a/assert/assertions.go b/assert/assertions.go
index 2e48602..bdd8138 100644
--- a/assert/assertions.go
+++ b/assert/assertions.go
@@ -1579,7 +1579,7 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
 	for tick := ticker.C; ; {
 		select {
 		case <-timer.C:
-			return false
+			return Fail(t, "Condition never satisfied", msgAndArgs...)
 		case <-tick:
 			tick = nil
 			go func() { ch <- condition() }()
@@ -1591,3 +1591,36 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
 		}
 	}
 }
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
+func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	ch := make(chan bool, 1)
+
+	timer := time.NewTimer(waitFor)
+	defer timer.Stop()
+
+	ticker := time.NewTicker(tick)
+	defer ticker.Stop()
+
+	for tick := ticker.C; ; {
+		select {
+		case <-timer.C:
+			return true
+		case <-tick:
+			tick = nil
+			go func() { ch <- condition() }()
+		case v := <-ch:
+			if v {
+				return Fail(t, "Condition satisfied", msgAndArgs...)
+			}
+			tick = ticker.C
+		}
+	}
+}
diff --git a/require/require.go b/require/require.go
index 50ea1aa..cf6c7b5 100644
--- a/require/require.go
+++ b/require/require.go
@@ -914,6 +914,34 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter
 	t.FailNow()
 }
 
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
+func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
 // Nil asserts that the specified object is nil.
 //
 //    assert.Nil(t, err)
diff --git a/require/require_forward.go b/require/require_forward.go
index 0dd39ec..5aac226 100644
--- a/require/require_forward.go
+++ b/require/require_forward.go
@@ -716,6 +716,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
 	Lessf(a.t, e1, e2, msg, args...)
 }
 
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Never(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//    a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Neverf(a.t, condition, waitFor, tick, msg, args...)
+}
+
 // Nil asserts that the specified object is nil.
 //
 //    a.Nil(err)


Test patch:
diff --git a/assert/assertions_test.go b/assert/assertions_test.go
index 7c74a7c..35a643e 100644
--- a/assert/assertions_test.go
+++ b/assert/assertions_test.go
@@ -2167,6 +2167,27 @@ func TestEventuallyTrue(t *testing.T) {
 	True(t, Eventually(t, condition, 100*time.Millisecond, 20*time.Millisecond))
 }
 
+func TestNeverFalse(t *testing.T) {
+	condition := func() bool {
+		return false
+	}
+
+	True(t, Never(t, condition, 100*time.Millisecond, 20*time.Millisecond))
+}
+
+func TestNeverTrue(t *testing.T) {
+	mockT := new(testing.T)
+	state := 0
+	condition := func() bool {
+		defer func() {
+			state = state + 1
+		}()
+		return state == 2
+	}
+
+	False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
+}
+
 func TestEventuallyIssue805(t *testing.T) {
 	mockT := new(testing.T)
 
diff --git a/package_test.go b/package_test.go
index 7ac5d6d..f17ff15 100644
--- a/package_test.go
+++ b/package_test.go
@@ -1,8 +1,9 @@
 package testify
 
 import (
-	"github.com/stretchr/testify/assert"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestImports(t *testing.T) {