File: race_test.go

package info (click to toggle)
golang-github-frankban-quicktest 1.14.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 332 kB
  • sloc: makefile: 2
file content (90 lines) | stat: -rw-r--r-- 1,943 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Licensed under the MIT license, see LICENSE file for details.

package quicktest_test

import (
	"sync"
	"sync/atomic"
	"testing"

	qt "github.com/frankban/quicktest"
)

func TestConcurrentMethods(t *testing.T) {
	// This test is designed to be run with the race
	// detector enabled. It checks that C methods
	// are safe to call concurrently.

	// N holds the number of iterations to run any given
	// operation concurrently with the others.
	const N = 100

	var x, y int32
	c := qt.New(dummyT{t})
	c.Run("subtest", func(c *qt.C) {
		var wg sync.WaitGroup
		// start calls f in two goroutines, each
		// running it N times.
		// All the goroutines get started before we actually
		// start them running, so that the race detector
		// has a better chance of catching issues.
		gogogo := make(chan struct{})
		start := func(f func()) {
			repeat := func() {
				defer wg.Done()
				<-gogogo
				for i := 0; i < N; i++ {
					f()
				}
			}
			wg.Add(2)
			go repeat()
			go repeat()
		}
		start(func() {
			c.Defer(func() {
				atomic.AddInt32(&x, 1)
			})
			c.Defer(func() {
				atomic.AddInt32(&y, 1)
			})
		})
		start(func() {
			c.Done()
		})
		start(func() {
			c.SetFormat(func(v interface{}) string {
				return "x"
			})
		})
		start(func() {
			// Do an assert to exercise the formatter.
			c.Check(true, qt.Equals, false)
		})
		start(func() {
			c.Run("", func(c *qt.C) {})
		})
		close(gogogo)
		wg.Wait()
	})
	// Check that all the defer functions ran OK.
	if x != N*2 || y != N*2 {
		t.Fatalf("unexpected x, y counts; got %d, %d; want %d, %d", x, y, N*2, N*2)
	}
}

// dummyT wraps a *testing.T value suitable
// for TestConcurrentMethods so that calling Error
// won't fail the test and that it implements
// Run correctly.
type dummyT struct {
	*testing.T
}

func (dummyT) Error(...interface{}) {}

func (t dummyT) Run(name string, f func(t dummyT)) bool {
	return t.T.Run(name, func(t *testing.T) {
		f(dummyT{t})
	})
}