Skip to content

Commit 9e7bc5f

Browse files
author
bayashi
authored
Merge pull request #181 from bayashi/guard-failnow
Guard FailNow
2 parents dd73688 + 5b0360a commit 9e7bc5f

File tree

6 files changed

+63
-79
lines changed

6 files changed

+63
-79
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func TestProtoMessages(t *testing.T) {
8989

9090
## Helper Methods
9191

92-
* **FailNow**, **FailNowOn**: Halt the test case immediately when the test fails
92+
* **FailNow**: Halt the test case immediately when the test fails
9393
* **Diff**: Get diff of 2 objects on anywhere
9494
* **Dump**: Get dumped string of objects on anywhere
9595
* **Debug**: Show debug info only on failure

actually_ctx.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package actually
2+
3+
import (
4+
"runtime"
5+
"strconv"
6+
"strings"
7+
"sync"
8+
)
9+
10+
// global context of actually
11+
var aCtx = &aContext{
12+
failNowStates: make(map[int64]bool),
13+
}
14+
15+
type aContext struct {
16+
mu sync.RWMutex
17+
failNowStates map[int64]bool // [goroutineID]bool
18+
}
19+
20+
func (ac *aContext) failNowOn() {
21+
ac.mu.Lock()
22+
defer ac.mu.Unlock()
23+
ac.failNowStates[goroutineID()] = true
24+
}
25+
26+
func (ac *aContext) failNotNow() {
27+
ac.mu.Lock()
28+
defer ac.mu.Unlock()
29+
delete(ac.failNowStates, goroutineID())
30+
}
31+
32+
func (ac *aContext) failNowState() bool {
33+
ac.mu.RLock()
34+
defer ac.mu.RUnlock()
35+
return ac.failNowStates[goroutineID()]
36+
}
37+
38+
func goroutineID() int64 {
39+
var buf [64]byte
40+
n := runtime.Stack(buf[:], false)
41+
idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
42+
id, err := strconv.ParseInt(idField, 10, 64)
43+
if err != nil {
44+
panic(err)
45+
}
46+
47+
return id
48+
}

actually_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestExpect(t *testing.T) {
4040
t.Errorf("`Expect()` was broken. Expected:%#v, but Actual:%#v", i, a.expect)
4141
}
4242
if a.failNow != nil && *a.failNow != false {
43-
t.Errorf("`FailNotNow()` was broken. Expected:%#v, but Actual:%#v", false, a.failNow)
43+
t.Errorf("Initial failNow value is wrong. Expected:%#v, but Actual:%#v", false, a.failNow)
4444
}
4545
}
4646

actually_util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var funcFail = func(a *testingA, w *w.Witness, reason string) {
3535
a.t.Helper()
3636
if a.failNow != nil && !*a.failNow {
3737
w.Fail(a.t, reason, skipMine)
38-
} else if (a.failNow != nil && *a.failNow) || len(os.Getenv(envKey_FailNow)) > 0 {
38+
} else if (a.failNow != nil && *a.failNow) || aCtx.failNowState() || len(os.Getenv(envKey_FailNow)) > 0 {
3939
w.FailNow(a.t, reason, skipMine)
4040
} else {
4141
w.Fail(a.t, reason, skipMine)

actually_util_test.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ import (
77
)
88

99
func TestFail(t *testing.T) {
10-
{
11-
a := FailNow()
12-
if *a.failNow != true {
13-
t.Errorf("`FailNow()` was broken. Expected:%#v, but Actual:%#v", true, a.failNow)
14-
}
15-
16-
a = FailNotNow()
17-
if *a.failNow != false {
18-
t.Errorf("`FailNotNow()` was broken. Expected:%#v, but Actual:%#v", false, a.failNow)
19-
}
20-
}
21-
2210
a := Got(nil)
2311
if a.failNow != nil && *a.failNow != false {
2412
t.Errorf("Default failNow is false, but Actual:%#v", a.failNow)
@@ -29,11 +17,6 @@ func TestFail(t *testing.T) {
2917
t.Errorf("`FailNow()` was broken. Expected:%#v, but Actual:%#v", true, a.failNow)
3018
}
3119

32-
a.FailNotNow()
33-
if *a.failNow != false {
34-
t.Errorf("`FailNotNow()` was broken. Expected:%#v, but Actual:%#v", false, a.failNow)
35-
}
36-
3720
a.t = t
3821

3922
stub()

helpers.go

Lines changed: 12 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,76 +16,29 @@ func failNowPtr(v bool) *bool {
1616
return &v
1717
}
1818

19-
// `FailNow` turns a flag on to stop further test execution immediately if one test fails.
19+
// The method `FailNow` turns a flag on to stop further test execution immediately if one test fails.
2020
/*
2121
actually.Got(something).FailNow().Nil(t) // Fail now for only this test
2222
*/
23-
func FailNow() *testingA {
24-
return &testingA{
25-
failNow: failNowPtr(true),
26-
}
27-
}
2823
func (a *testingA) FailNow() *testingA {
2924
a.failNow = failNowPtr(true)
3025

3126
return a
3227
}
3328

34-
// FailNowOn function turns an ENV flag on to stop further test execution immediately if one test fails.
35-
// This switch is enabled within the test. Not only during function.
36-
/*
37-
func Test(t *testing.T) {
38-
actually.FailNowOn(t)
39-
actually.Got(something).Nil(t) // Fail Now
40-
actually.Got(something).Expect(something).Same(t) // Fail Now
41-
}
42-
*/
43-
// Warning: Do not use FailNowOn along with t.Parallel.
44-
func FailNowOn(t *testing.T) {
45-
t.Setenv(envKey_FailNow, envKey_FailNow)
46-
}
47-
48-
// FailNotNowOn function turns an ENV flag off to stop further test execution immediately if one test fails.
49-
// If you want to turn the ENV flag on, then you should call `FailNowOn`.
50-
/*
51-
func Test(t *testing.T) {
52-
// turn on to fail right now
53-
actually.FailNowOn(t)
54-
actually.Got(something).Nil(t) // Fail Now
55-
actually.Got(something).Expect(something).Same(t) // Fail Now
56-
57-
// turn off
58-
actually.FailNotNowOn(t)
59-
actually.Got(something).Nil(t) // NOT Fail Now
60-
actually.Got(something).Expect(something).Same(t) // NOT Fail Now
61-
62-
// Fail Now by FailNow() in the chain
63-
actually.Got(something).FailNow().Nil(t) // Fail Now
64-
65-
// Again, turn on to fail right now
66-
actually.FailNowOn(t)
67-
actually.Got(something).Nil(t) // Fail Now
68-
}
69-
*/
70-
// This switch is enabled within the test. Not only during function.
71-
func FailNotNowOn(t *testing.T) {
72-
t.Setenv(envKey_FailNow, "")
73-
}
74-
75-
// FailNotNow turns a flag off, so that even if the test fails, execution does not stop immediately.
29+
// The function `FailNow` receives a func that is including tests of `actually`.
30+
// The included tests inside `FailNow` will stop execution immediately upon failure,
31+
// even without explicitly calling `FailNow` individually.
7632
/*
77-
It behaves this way by default. If you want the opposite behavior, call `FailNow` method.
33+
actually.FailNow(func() {
34+
actually.Got(false).True(t) // stop this failuer
35+
actually.Got(true).True(t) // not executed
36+
})
7837
*/
79-
// Deprecated: Anyone uses? This method will be removed in the near future.
80-
func FailNotNow() *testingA {
81-
return &testingA{
82-
failNow: failNowPtr(false),
83-
}
84-
}
85-
func (a *testingA) FailNotNow() *testingA {
86-
a.failNow = failNowPtr(false)
87-
88-
return a
38+
func FailNow(fn func()) {
39+
aCtx.failNowOn()
40+
defer aCtx.failNotNow()
41+
fn()
8942
}
9043

9144
// X turns on a flag to show test values as raw in a fail report.

0 commit comments

Comments
 (0)