@@ -12,6 +12,7 @@ import (
12
12
"os"
13
13
"os/exec"
14
14
"path/filepath"
15
+ "strconv"
15
16
"strings"
16
17
"testing"
17
18
"time"
@@ -32,10 +33,12 @@ import (
32
33
//
33
34
// The test will save the smallest reproduction found and print out the relevant
34
35
// information.
35
- func tryToReduce (t * testing.T , testStateDir string , runDir string , reduceAttempts int ) {
36
+ func tryToReduce (
37
+ t * testing.T , testStateDir string , runDir string , initialStatePath string , reduceAttempts int ,
38
+ ) {
36
39
testRootDir := filepath .Dir (runDir )
37
40
runSubdir := filepath .Base (runDir )
38
- r := makeReducer (t , testStateDir , testRootDir , []string {runSubdir }, reduceAttempts )
41
+ r := makeReducer (t , testStateDir , testRootDir , []string {runSubdir }, initialStatePath , reduceAttempts )
39
42
r .Run (t )
40
43
}
41
44
@@ -52,19 +55,26 @@ func tryToReduce(t *testing.T, testStateDir string, runDir string, reduceAttempt
52
55
// The test will save the smallest reproduction found and print out the relevant
53
56
// information.
54
57
func tryToReduceCompare (
55
- t * testing.T , testStateDir string , testRootDir string , runSubdirs []string , reduceAttempts int ,
58
+ t * testing.T ,
59
+ testStateDir string ,
60
+ testRootDir string ,
61
+ runSubdirs []string ,
62
+ initialStatePath string ,
63
+ reduceAttempts int ,
56
64
) {
57
- r := makeReducer (t , testStateDir , testRootDir , runSubdirs , reduceAttempts )
65
+ r := makeReducer (t , testStateDir , testRootDir , runSubdirs , initialStatePath , reduceAttempts )
58
66
r .Run (t )
59
67
}
60
68
61
69
// reducer is a helper that starts with a reproduction of a RunOnce failure and
62
70
// tries to reduce the number of operations.
63
71
type reducer struct {
64
72
// testRootDir is the directory of the test, which contains the "ops" file.
65
- testRootDir string
66
- configs []testConfig
67
- reduceAttempts int
73
+ testRootDir string
74
+ configs []testConfig
75
+ // initialStatePath stores the --initial-state value, if set.
76
+ initialStatePath string
77
+ reduceAttempts int
68
78
69
79
ops []string
70
80
@@ -84,7 +94,12 @@ type testConfig struct {
84
94
}
85
95
86
96
func makeReducer (
87
- t * testing.T , testStateDir string , testRootDir string , runSubdirs []string , reduceAttempts int ,
97
+ t * testing.T ,
98
+ testStateDir string ,
99
+ testRootDir string ,
100
+ runSubdirs []string ,
101
+ initialStatePath string ,
102
+ reduceAttempts int ,
88
103
) * reducer {
89
104
// All run dirs should have the same parent path.
90
105
opsData , err := os .ReadFile (filepath .Join (testRootDir , "ops" ))
@@ -105,11 +120,12 @@ func makeReducer(
105
120
t .Logf ("Starting with %d operations" , len (ops ))
106
121
107
122
return & reducer {
108
- testRootDir : testRootDir ,
109
- configs : tc ,
110
- ops : ops ,
111
- reduceAttempts : reduceAttempts ,
112
- testStateDir : testStateDir ,
123
+ testRootDir : testRootDir ,
124
+ configs : tc ,
125
+ initialStatePath : initialStatePath ,
126
+ ops : ops ,
127
+ reduceAttempts : reduceAttempts ,
128
+ testStateDir : testStateDir ,
113
129
}
114
130
}
115
131
@@ -144,15 +160,16 @@ func (r *reducer) try(t *testing.T, ops []string) bool {
144
160
"--keep" ,
145
161
}
146
162
147
- var runFlags []string
148
163
if len (runSubdirs ) == 1 {
149
164
// RunOnce mode.
150
- runFlags = [] string { "--run-dir" , filepath .Join (testRootDir , runSubdirs [0 ])}
165
+ args = append ( args , "--run-dir" , filepath .Join (testRootDir , runSubdirs [0 ]))
151
166
} else {
152
167
// Compare mode.
153
- runFlags = []string {"--compare" , filepath .Join (testRootDir , fmt .Sprintf ("{%s}" , strings .Join (runSubdirs , "," )))}
168
+ args = append (args , "--compare" , filepath .Join (testRootDir , fmt .Sprintf ("{%s}" , strings .Join (runSubdirs , "," ))))
169
+ }
170
+ if r .initialStatePath != "" {
171
+ args = append (args , "--initial-state" , r .initialStatePath )
154
172
}
155
- args = append (args , runFlags ... )
156
173
157
174
var output bytes.Buffer
158
175
cmd := exec .CommandContext (context .Background (), os .Args [0 ], args ... )
@@ -188,7 +205,7 @@ func (r *reducer) try(t *testing.T, ops []string) bool {
188
205
t .Logf (" Diagram: %s" , diagramPath )
189
206
}
190
207
191
- t .Logf (` go test ./internal/metamorphic -tags invariants -run "%s$" -v %s %q` , t . Name (), runFlags [ 0 ], runFlags [ 1 ] )
208
+ t .Logf (" go test ./internal/metamorphic -tags invariants %s" , shellJoin ( cmd . Args [ 1 :]) )
192
209
if r .lastSavedDir != "" {
193
210
require .NoError (t , os .RemoveAll (r .lastSavedDir ))
194
211
}
@@ -238,3 +255,16 @@ func randomSubset(t *testing.T, ops []string, removeProbability float64) []strin
238
255
}
239
256
return res
240
257
}
258
+
259
+ func shellJoin (args []string ) string {
260
+ quoted := make ([]string , len (args ))
261
+ for i , a := range args {
262
+ // Quote if the word has bytes that the shell would interpret.
263
+ if strings .ContainsAny (a , " \t \n \" '\\ $`*?[]{}<>|&;()" ) {
264
+ quoted [i ] = strconv .Quote (a )
265
+ } else {
266
+ quoted [i ] = a
267
+ }
268
+ }
269
+ return strings .Join (quoted , " " )
270
+ }
0 commit comments