Skip to content

Commit 5d5ad88

Browse files
committed
testing: implement testing.Cleanup
Also reorder and regroup common's fields slightly to match upstream. TODO: pull in more upstream tests once this package is goroutine-safe
1 parent 90592ba commit 5d5ad88

File tree

2 files changed

+117
-9
lines changed

2 files changed

+117
-9
lines changed

src/testing/sub_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package testing
6+
7+
import (
8+
"reflect"
9+
)
10+
11+
func TestCleanup(t *T) {
12+
var cleanups []int
13+
t.Run("test", func(t *T) {
14+
t.Cleanup(func() { cleanups = append(cleanups, 1) })
15+
t.Cleanup(func() { cleanups = append(cleanups, 2) })
16+
})
17+
if got, want := cleanups, []int{2, 1}; !reflect.DeepEqual(got, want) {
18+
t.Errorf("unexpected cleanup record; got %v want %v", got, want)
19+
}
20+
}
21+
22+
func TestRunCleanup(t *T) {
23+
outerCleanup := 0
24+
innerCleanup := 0
25+
t.Run("test", func(t *T) {
26+
t.Cleanup(func() { outerCleanup++ })
27+
t.Run("x", func(t *T) {
28+
t.Cleanup(func() { innerCleanup++ })
29+
})
30+
})
31+
if innerCleanup != 1 {
32+
t.Errorf("unexpected inner cleanup count; got %d want 1", innerCleanup)
33+
}
34+
if outerCleanup != 1 {
35+
t.Errorf("unexpected outer cleanup count; got %d want 0", outerCleanup)
36+
}
37+
}
38+
39+
func TestCleanupParallelSubtests(t *T) {
40+
ranCleanup := 0
41+
t.Run("test", func(t *T) {
42+
t.Cleanup(func() { ranCleanup++ })
43+
t.Run("x", func(t *T) {
44+
t.Parallel()
45+
if ranCleanup > 0 {
46+
t.Error("outer cleanup ran before parallel subtest")
47+
}
48+
})
49+
})
50+
if ranCleanup != 1 {
51+
t.Errorf("unexpected cleanup count; got %d want 1", ranCleanup)
52+
}
53+
}
54+
55+
func TestNestedCleanup(t *T) {
56+
ranCleanup := 0
57+
t.Run("test", func(t *T) {
58+
t.Cleanup(func() {
59+
if ranCleanup != 2 {
60+
t.Errorf("unexpected cleanup count in first cleanup: got %d want 2", ranCleanup)
61+
}
62+
ranCleanup++
63+
})
64+
t.Cleanup(func() {
65+
if ranCleanup != 0 {
66+
t.Errorf("unexpected cleanup count in second cleanup: got %d want 0", ranCleanup)
67+
}
68+
ranCleanup++
69+
t.Cleanup(func() {
70+
if ranCleanup != 1 {
71+
t.Errorf("unexpected cleanup count in nested cleanup: got %d want 1", ranCleanup)
72+
}
73+
ranCleanup++
74+
})
75+
})
76+
})
77+
if ranCleanup != 3 {
78+
t.Errorf("unexpected cleanup count: got %d want 3", ranCleanup)
79+
}
80+
}

src/testing/testing.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,17 @@ func Init() {
4343
// common holds the elements common between T and B and
4444
// captures common methods such as Errorf.
4545
type common struct {
46-
output bytes.Buffer
47-
w io.Writer // either &output, or at top level, os.Stdout
48-
indent string
46+
output bytes.Buffer
47+
w io.Writer // either &output, or at top level, os.Stdout
48+
indent string
49+
failed bool // Test or benchmark has failed.
50+
skipped bool // Test of benchmark has been skipped.
51+
cleanups []func() // optional functions to be called at the end of the test
52+
finished bool // Test function has completed.
4953

50-
failed bool // Test or benchmark has failed.
51-
skipped bool // Test of benchmark has been skipped.
52-
finished bool // Test function has completed.
53-
level int // Nesting depth of test or benchmark.
54-
name string // Name of test or benchmark.
55-
parent *common
54+
parent *common
55+
level int // Nesting depth of test or benchmark.
56+
name string // Name of test or benchmark.
5657
}
5758

5859
// TB is the interface common to T and B.
@@ -208,7 +209,34 @@ func (c *common) Parallel() {
208209
// Unimplemented.
209210
}
210211

212+
// Cleanup registers a function to be called when the test (or subtest) and all its
213+
// subtests complete. Cleanup functions will be called in last added,
214+
// first called order.
215+
func (c *common) Cleanup(f func()) {
216+
c.cleanups = append(c.cleanups, f)
217+
}
218+
219+
// runCleanup is called at the end of the test.
220+
func (c *common) runCleanup() {
221+
for {
222+
var cleanup func()
223+
if len(c.cleanups) > 0 {
224+
last := len(c.cleanups) - 1
225+
cleanup = c.cleanups[last]
226+
c.cleanups = c.cleanups[:last]
227+
}
228+
if cleanup == nil {
229+
return
230+
}
231+
cleanup()
232+
}
233+
}
234+
211235
func tRunner(t *T, fn func(t *T)) {
236+
defer func() {
237+
t.runCleanup()
238+
}()
239+
212240
// Run the test.
213241
if flagVerbose {
214242
fmt.Fprintf(t.w, "=== RUN %s\n", t.name)

0 commit comments

Comments
 (0)