@@ -136,15 +136,17 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
136
136
})
137
137
}
138
138
139
- // Test runs the tests in the given package.
140
- func Test (pkgName string , options * compileopts.Options , testCompileOnly bool , outpath string ) error {
139
+ // Test runs the tests in the given package. Returns whether the test passed and
140
+ // possibly an error if the test failed to run.
141
+ func Test (pkgName string , options * compileopts.Options , testCompileOnly bool , outpath string ) (bool , error ) {
141
142
options .TestConfig .CompileTestBinary = true
142
143
config , err := builder .NewConfig (options )
143
144
if err != nil {
144
- return err
145
+ return false , err
145
146
}
146
147
147
- return builder .Build (pkgName , outpath , config , func (result builder.BuildResult ) error {
148
+ var passed bool
149
+ err = builder .Build (pkgName , outpath , config , func (result builder.BuildResult ) error {
148
150
if testCompileOnly || outpath != "" {
149
151
// Write test binary to the specified file name.
150
152
if outpath == "" {
@@ -158,48 +160,78 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, ou
158
160
// Do not run the test.
159
161
return nil
160
162
}
161
- if len (config .Target .Emulator ) == 0 {
162
- // Run directly.
163
- cmd := executeCommand (config .Options , result .Binary )
164
- cmd .Stdout = os .Stdout
165
- cmd .Stderr = os .Stderr
166
- cmd .Dir = result .MainDir
167
- err := cmd .Run ()
168
- if err != nil {
169
- // Propagate the exit code
170
- if err , ok := err .(* exec.ExitError ); ok {
171
- os .Exit (err .ExitCode ())
172
- }
173
- return & commandError {"failed to run compiled binary" , result .Binary , err }
174
- }
175
- return nil
163
+
164
+ // Run the test.
165
+ start := time .Now ()
166
+ var err error
167
+ passed , err = runPackageTest (config , result )
168
+ if err != nil {
169
+ return err
170
+ }
171
+ duration := time .Since (start )
172
+
173
+ // Print the result.
174
+ importPath := strings .TrimSuffix (result .ImportPath , ".test" )
175
+ if passed {
176
+ fmt .Printf ("ok \t %s\t %.3fs\n " , importPath , duration .Seconds ())
176
177
} else {
177
- // Run in an emulator.
178
- args := append (config .Target .Emulator [1 :], result .Binary )
179
- cmd := executeCommand (config .Options , config .Target .Emulator [0 ], args ... )
180
- buf := & bytes.Buffer {}
181
- w := io .MultiWriter (os .Stdout , buf )
182
- cmd .Stdout = w
183
- cmd .Stderr = os .Stderr
184
- err := cmd .Run ()
185
- if err != nil {
186
- if err , ok := err .(* exec.ExitError ); ! ok || ! err .Exited () {
187
- // Workaround for QEMU which always exits with an error.
188
- return & commandError {"failed to run emulator with" , result .Binary , err }
189
- }
178
+ fmt .Printf ("FAIL\t %s\t %.3fs\n " , importPath , duration .Seconds ())
179
+ }
180
+ return nil
181
+ })
182
+ if err , ok := err .(loader.NoTestFilesError ); ok {
183
+ fmt .Printf ("? \t %s\t [no test files]\n " , err .ImportPath )
184
+ // Pretend the test passed - it at least didn't fail.
185
+ return true , nil
186
+ }
187
+ return passed , err
188
+ }
189
+
190
+ // runPackageTest runs a test binary that was previously built. The return
191
+ // values are whether the test passed and any errors encountered while trying to
192
+ // run the binary.
193
+ func runPackageTest (config * compileopts.Config , result builder.BuildResult ) (bool , error ) {
194
+ if len (config .Target .Emulator ) == 0 {
195
+ // Run directly.
196
+ cmd := executeCommand (config .Options , result .Binary )
197
+ cmd .Stdout = os .Stdout
198
+ cmd .Stderr = os .Stderr
199
+ cmd .Dir = result .MainDir
200
+ err := cmd .Run ()
201
+ if err != nil {
202
+ if _ , ok := err .(* exec.ExitError ); ok {
203
+ // Binary exited with a non-zero exit code, which means the test
204
+ // failed.
205
+ return false , nil
190
206
}
191
- testOutput := string (buf .Bytes ())
192
- if testOutput == "PASS\n " || strings .HasSuffix (testOutput , "\n PASS\n " ) {
193
- // Test passed.
194
- return nil
195
- } else {
196
- // Test failed, either by ending with the word "FAIL" or with a
197
- // panic of some sort.
198
- os .Exit (1 )
199
- return nil // unreachable
207
+ return false , & commandError {"failed to run compiled binary" , result .Binary , err }
208
+ }
209
+ return true , nil
210
+ } else {
211
+ // Run in an emulator.
212
+ args := append (config .Target .Emulator [1 :], result .Binary )
213
+ cmd := executeCommand (config .Options , config .Target .Emulator [0 ], args ... )
214
+ buf := & bytes.Buffer {}
215
+ w := io .MultiWriter (os .Stdout , buf )
216
+ cmd .Stdout = w
217
+ cmd .Stderr = os .Stderr
218
+ err := cmd .Run ()
219
+ if err != nil {
220
+ if err , ok := err .(* exec.ExitError ); ! ok || ! err .Exited () {
221
+ // Workaround for QEMU which always exits with an error.
222
+ return false , & commandError {"failed to run emulator with" , result .Binary , err }
200
223
}
201
224
}
202
- })
225
+ testOutput := string (buf .Bytes ())
226
+ if testOutput == "PASS\n " || strings .HasSuffix (testOutput , "\n PASS\n " ) {
227
+ // Test passed.
228
+ return true , nil
229
+ } else {
230
+ // Test failed, either by ending with the word "FAIL" or with a
231
+ // panic of some sort.
232
+ return false , nil
233
+ }
234
+ }
203
235
}
204
236
205
237
// Flash builds and flashes the built binary to the given serial port.
@@ -1072,16 +1104,26 @@ func main() {
1072
1104
err := Run (pkgName , options )
1073
1105
handleCompilerError (err )
1074
1106
case "test" :
1075
- pkgName := "."
1076
- if flag .NArg () == 1 {
1077
- pkgName = filepath .ToSlash (flag .Arg (0 ))
1078
- } else if flag .NArg () > 1 {
1079
- fmt .Fprintln (os .Stderr , "test only accepts a single positional argument: package name, but multiple were specified" )
1080
- usage ()
1107
+ var pkgNames []string
1108
+ for i := 0 ; i < flag .NArg (); i ++ {
1109
+ pkgNames = append (pkgNames , filepath .ToSlash (flag .Arg (i )))
1110
+ }
1111
+ if len (pkgNames ) == 0 {
1112
+ pkgNames = []string {"." }
1113
+ }
1114
+ allTestsPassed := true
1115
+ for _ , pkgName := range pkgNames {
1116
+ // TODO: parallelize building the test binaries
1117
+ passed , err := Test (pkgName , options , * testCompileOnlyFlag , outpath )
1118
+ handleCompilerError (err )
1119
+ if ! passed {
1120
+ allTestsPassed = false
1121
+ }
1122
+ }
1123
+ if ! allTestsPassed {
1124
+ fmt .Println ("FAIL" )
1081
1125
os .Exit (1 )
1082
1126
}
1083
- err := Test (pkgName , options , * testCompileOnlyFlag , outpath )
1084
- handleCompilerError (err )
1085
1127
case "targets" :
1086
1128
dir := filepath .Join (goenv .Get ("TINYGOROOT" ), "targets" )
1087
1129
entries , err := ioutil .ReadDir (dir )
0 commit comments