-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatrix.go
101 lines (93 loc) · 3.18 KB
/
matrix.go
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
91
92
93
94
95
96
97
98
99
100
101
package ntest
import (
"testing"
"github.com/muir/nject"
)
// RunParallelMatrix uses t.Run() to fork into multiple threads of execution for each
// sub-test before any chains are evaluated. This forces the chains to share
// nothing between them. RunParallelMatrix does not provide any default injectors
// other than a *testing.T that comes from a named provider (named "testing.T")
//
// A matrix is a specific type: map[string]nject.Provider. Add those to the
// chain to trigger matrix testing.
//
// t.Parallel() is used for each t.Run()
//
// A warning about t.Parallel(): inner tests wait until outer tests finish.
// See https://go.dev/play/p/ZDaw054HeIN
//
// Matrix values must be direct arguments to RunMatrix -- they will not be extracted
// from nject.Sequences. RunParallelMatrix will fail if there is no matrix provided.
func RunParallelMatrix(t *testing.T, chain ...any) {
t.Parallel()
runMatrixTest(t, true, chain)
}
// RunMatrix uses t.Run() separate execution for each
// sub-test before any chains are evaluated. This forces the chains to share
// nothing between them. RunMatrix does not provide any default injectors
// other than a *testing.T that comes from a named provider (named "testing.T")
//
// A matrix is a specific type: map[string]nject.Provider. Add those to the
// chain to trigger matrix testing.
//
// Matrix values must be direct arguments to RunMatrix -- they will not be extracted
// from nject.Sequences. RunMatrix will fail if there is no matrix provided.
func RunMatrix(t *testing.T, chain ...any) {
runMatrixTest(t, false, chain)
}
func runMatrixTest(t *testing.T, parallel bool, chain []any) {
breakChain := func(t *testing.T, chain []any) (matrix map[string]nject.Provider, before []any, after []any) {
for i, injector := range chain {
matrix, ok := injector.(map[string]nject.Provider)
if ok {
return matrix, chain[:i], chain[i+1:]
}
}
return nil, nil, chain
}
testingT := func(t *testing.T) []any {
return []any{nject.Provide("testing.T", func() *testing.T { return t })}
}
matrix, before, after := breakChain(t, chain)
if matrix == nil {
t.Log("No matrix found in matrix testing, perhaps the specifier is in a Sequence? (not allowed)")
t.Fail()
return
}
var startTest func(t *testing.T, matrix map[string]nject.Provider, before []any, after []any)
startTest = func(t *testing.T, matrix map[string]nject.Provider, before []any, after []any) {
for name, subChain := range matrix {
subChain := subChain
t.Run(name, func(t *testing.T) {
if parallel {
t.Parallel()
}
matrix, newBefore, newAfter := breakChain(t, after)
if matrix == nil {
RunTest(t, combineSlices(testingT(t), before, []any{subChain}, after)...)
} else {
startTest(t, matrix, combineSlices(before, newBefore, []any{subChain}), newAfter)
}
})
}
}
startTest(t, matrix, before, after)
}
func combineSlices[T any](first []T, more ...[]T) []T {
if len(more) == 0 {
return first
}
total := len(first)
for _, m := range more {
total += len(m)
}
if total == len(first) {
return first
}
combined := make([]T, len(first), total)
copy(combined, first)
for _, m := range more {
combined = append(combined, m...)
}
return combined
}