Repository: stretchr/testify (go)

Issue:
`suite.Require` deadlock 
If `require` object hasn't been initialized before calling `suite.Require` method, it will be created on the base of  `*testing.T` returned from  `suite.T()` ([code](https://github.com/stretchr/testify/blame/v1.8.4/suite/suite.go#L61)):

```go
// Require returns a require context for suite.
func (suite *Suite) Require() *require.Assertions {
	suite.mu.Lock()
	defer suite.mu.Unlock()
	if suite.require == nil {
		suite.require = require.New(suite.T())
	}
	return suite.require
}
```

This will result in a deadlock because `suite.T()` wants to acquire the lock that has been already acquired:

```go
// T retrieves the current *testing.T context.
func (suite *Suite) T() *testing.T {
	suite.mu.RLock()
	defer suite.mu.RUnlock()
	return suite.t
}
```

Pull request:
suite: fix deadlock in suite.Require()/Assert()
As pointed out in issue #1520, if the suite is not initialised properly (by calling the `Run` function), then calling `suite.Require()` or `suite.Assert()` will result in a deadlock.

## Changes

This commit fixes that by panicking if the suite is not initialised properly. This is justified because the suite is intended to be triggered in the right way. If the user does not do that, this panic will nudge them in the right direction.

It has to be a panic because, at this point, we don't have access to any `testing.T` context to gracefully call a `t.Fail()`. Also, these two functions are not expected to return an error.

## Related issues

Fixes #1520

Patch:
diff --git a/mock/mock.go b/mock/mock.go
index 213bde2..5e35861 100644
--- a/mock/mock.go
+++ b/mock/mock.go
@@ -594,9 +594,6 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
 // AssertExpectations asserts that everything specified with On and Return was
 // in fact called as expected.  Calls may have occurred in any order.
 func (m *Mock) AssertExpectations(t TestingT) bool {
-	if s, ok := t.(interface{ Skipped() bool }); ok && s.Skipped() {
-		return true
-	}
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
diff --git a/suite/suite.go b/suite/suite.go
index eac6909..18443a9 100644
--- a/suite/suite.go
+++ b/suite/suite.go
@@ -58,7 +58,7 @@ func (suite *Suite) Require() *require.Assertions {
 	suite.mu.Lock()
 	defer suite.mu.Unlock()
 	if suite.require == nil {
-		suite.require = require.New(suite.T())
+		panic("'Require' must not be called before 'Run' or 'SetT'")
 	}
 	return suite.require
 }
@@ -72,7 +72,7 @@ func (suite *Suite) Assert() *assert.Assertions {
 	suite.mu.Lock()
 	defer suite.mu.Unlock()
 	if suite.Assertions == nil {
-		suite.Assertions = assert.New(suite.T())
+		panic("'Assert' must not be called before 'Run' or 'SetT'")
 	}
 	return suite.Assertions
 }


Test patch:
diff --git a/mock/mock_test.go b/mock/mock_test.go
index b80a8a7..52d20be 100644
--- a/mock/mock_test.go
+++ b/mock/mock_test.go
@@ -1493,16 +1493,6 @@ func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
 
 }
 
-func Test_Mock_AssertExpectations_Skipped_Test(t *testing.T) {
-
-	var mockedService = new(TestExampleImplementation)
-
-	mockedService.On("Test_Mock_AssertExpectations_Skipped_Test", 1, 2, 3).Return(5, 6, 7)
-	defer mockedService.AssertExpectations(t)
-
-	t.Skip("skipping test to ensure AssertExpectations does not fail")
-}
-
 func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
 
 	var mockedService = new(TestExampleImplementation)
diff --git a/suite/suite_test.go b/suite/suite_test.go
index 292dc29..b31eb35 100644
--- a/suite/suite_test.go
+++ b/suite/suite_test.go
@@ -692,3 +692,27 @@ func TestSubtestPanic(t *testing.T) {
 	assert.True(t, suite.inTearDownTest)
 	assert.True(t, suite.inTearDownSuite)
 }
+
+type unInitialisedSuite struct {
+	Suite
+}
+
+// TestUnInitialisedSuites asserts the behaviour of the suite methods when the
+// suite is not initialised
+func TestUnInitialisedSuites(t *testing.T) {
+	t.Run("should panic on Require", func(t *testing.T) {
+		suite := new(unInitialisedSuite)
+
+		assert.Panics(t, func() {
+			suite.Require().True(true)
+		})
+	})
+
+	t.Run("should panic on Assert", func(t *testing.T) {
+		suite := new(unInitialisedSuite)
+
+		assert.Panics(t, func() {
+			suite.Assert().True(true)
+		})
+	})
+}