|
21 | 21 | import sys |
22 | 22 | import unittest |
23 | 23 | from collections import OrderedDict |
| 24 | +from contextlib import contextmanager |
24 | 25 | from multiprocessing.pool import ThreadPool |
25 | 26 | from pathlib import Path |
26 | 27 |
|
@@ -219,6 +220,7 @@ def run_one_spec_test(wast: Path, stdout=None): |
219 | 220 | return # don't try all the binary format stuff TODO |
220 | 221 | else: |
221 | 222 | shared.fail_with_error(str(e)) |
| 223 | + raise |
222 | 224 |
|
223 | 225 | check_expected(actual, expected, stdout=stdout) |
224 | 226 |
|
@@ -248,32 +250,63 @@ def run_one_spec_test(wast: Path, stdout=None): |
248 | 250 |
|
249 | 251 |
|
250 | 252 | def run_spec_test_with_wrapped_stdout(wast: Path): |
| 253 | + ''' |
| 254 | + Returns (bool, str) where the first element is whether the test was |
| 255 | + successful and the second is the combined stdout and stderr of the test. |
| 256 | + ''' |
251 | 257 | out = io.StringIO() |
252 | 258 | try: |
253 | 259 | run_one_spec_test(wast, stdout=out) |
254 | 260 | except Exception as e: |
255 | 261 | # Serialize exceptions into the output string buffer |
256 | 262 | # so they can be reported on the main thread. |
257 | 263 | print(e, file=out) |
258 | | - raise |
259 | | - return out.getvalue() |
| 264 | + return False, out.getvalue() |
| 265 | + return True, out.getvalue() |
| 266 | + |
| 267 | + |
| 268 | +@contextmanager |
| 269 | +def red_stdout(): |
| 270 | + try: |
| 271 | + print("\033[31m", end="") |
| 272 | + yield |
| 273 | + finally: |
| 274 | + print("\033[0m", end="") |
260 | 275 |
|
261 | 276 |
|
262 | 277 | def run_spec_tests(): |
263 | 278 | print('\n[ checking wasm-shell spec testcases... ]\n') |
264 | 279 |
|
265 | 280 | worker_count = os.cpu_count() |
266 | 281 | print("Running with", worker_count, "workers") |
267 | | - test_paths = [Path(x) for x in shared.options.spec_tests] |
| 282 | + test_paths = (Path(x) for x in shared.options.spec_tests) |
| 283 | + |
| 284 | + failed_stdouts = [] |
268 | 285 | with ThreadPool(processes=worker_count) as pool: |
269 | 286 | try: |
270 | | - for result in pool.imap_unordered(run_spec_test_with_wrapped_stdout, test_paths): |
271 | | - print(result, end="") |
| 287 | + for success, stdout in pool.imap_unordered(run_spec_test_with_wrapped_stdout, test_paths): |
| 288 | + if success: |
| 289 | + print(stdout, end="") |
| 290 | + continue |
| 291 | + |
| 292 | + failed_stdouts.append(stdout) |
| 293 | + if shared.options.abort_on_first_failure: |
| 294 | + with red_stdout(): |
| 295 | + print("Aborted tests execution after first failure. Set --no-fail-fast to disable this.") |
| 296 | + break |
272 | 297 | except KeyboardInterrupt: |
273 | 298 | # Hard exit to avoid threads continuing to run after Ctrl-C. |
274 | 299 | # There's no concern of deadlocking during shutdown here. |
275 | 300 | os._exit(1) |
276 | 301 |
|
| 302 | + if not failed_stdouts: |
| 303 | + return |
| 304 | + |
| 305 | + with red_stdout(): |
| 306 | + print("Failed tests:") |
| 307 | + for failed in failed_stdouts: |
| 308 | + print(failed, end="") |
| 309 | + |
277 | 310 |
|
278 | 311 | def run_validator_tests(): |
279 | 312 | print('\n[ running validation tests... ]\n') |
|
0 commit comments