Skip to content

Commit 8ac7ef7

Browse files
authored
Add assert_fail test helper. NFC (#25639)
I noticed that we were almost always following `expect_fail` with `assertContains` so I created a helper that does both. In many cases this collapses two lines of test code into a single one. In other cases I decided to keep the expectation string on its own line to avoid over-long lines, but it still simplifies the code I believe. I mostly used some crazy regex patterns to create this PR.
1 parent b8b8194 commit 8ac7ef7

File tree

5 files changed

+272
-363
lines changed

5 files changed

+272
-363
lines changed

test/common.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,12 +1319,12 @@ def emcc(self, filename, args=[], output_filename=None, **kwargs): # noqa
13191319

13201320
# Shared test code between main suite and others
13211321

1322-
def expect_fail(self, cmd, expect_traceback=False, **args):
1322+
def expect_fail(self, cmd, expect_traceback=False, **kwargs):
13231323
"""Run a subprocess and assert that it returns non-zero.
13241324
13251325
Return the stderr of the subprocess.
13261326
"""
1327-
proc = self.run_process(cmd, check=False, stderr=PIPE, **args)
1327+
proc = self.run_process(cmd, check=False, stderr=PIPE, **kwargs)
13281328
self.assertNotEqual(proc.returncode, 0, 'subprocess unexpectedly succeeded. stderr:\n' + proc.stderr)
13291329
# When we check for failure we expect a user-visible error, not a traceback.
13301330
# However, on windows a python traceback can happen randomly sometimes,
@@ -1337,6 +1337,13 @@ def expect_fail(self, cmd, expect_traceback=False, **args):
13371337
sys.stderr.write(proc.stderr)
13381338
return proc.stderr
13391339

1340+
def assert_fail(self, cmd, expected, **kwargs):
1341+
"""Just like expect_fail, but also check for expected message in stderr.
1342+
"""
1343+
err = self.expect_fail(cmd, **kwargs)
1344+
self.assertContained(expected, err)
1345+
return err
1346+
13401347
# excercise dynamic linker.
13411348
#
13421349
# test that linking to shared library B, which is linked to A, loads A as well.

test/test_browser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,8 +2552,8 @@ def test_worker_api_sleep(self):
25522552
@no_wasm64('TODO: wasm64 + BUILD_AS_WORKER')
25532553
def test_worker_api_with_pthread_compilation_fails(self):
25542554
self.run_process([EMCC, '-c', '-o', 'hello.o', test_file('hello_world.c')])
2555-
stderr = self.expect_fail([EMCC, 'hello.o', '-o', 'a.js', '-g', '--closure=1', '-pthread', '-sBUILD_AS_WORKER'])
2556-
self.assertContained("pthreads + BUILD_AS_WORKER require separate modes that don't work together, see https://github.com/emscripten-core/emscripten/issues/8854", stderr)
2555+
expected = "pthreads + BUILD_AS_WORKER require separate modes that don't work together, see https://github.com/emscripten-core/emscripten/issues/8854"
2556+
self.assert_fail([EMCC, 'hello.o', '-o', 'a.js', '-g', '--closure=1', '-pthread', '-sBUILD_AS_WORKER'], expected)
25572557

25582558
@also_with_wasmfs
25592559
def test_wget(self):

test/test_core.py

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,23 +1346,23 @@ def test_exceptions_allowed_misuse(self):
13461346

13471347
# Test old =2 setting for DISABLE_EXCEPTION_CATCHING
13481348
self.set_setting('DISABLE_EXCEPTION_CATCHING', 2)
1349-
err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_cflags())
1350-
self.assertContained('error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', err)
1349+
expected = 'error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]'
1350+
self.assert_fail([EMCC, test_file('hello_world.c')] + self.get_cflags(), expected)
13511351

13521352
# =0 should also be a warning
13531353
self.set_setting('DISABLE_EXCEPTION_CATCHING', 0)
1354-
err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_cflags())
1355-
self.assertContained('error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]', err)
1354+
expected = 'error: DISABLE_EXCEPTION_CATCHING=X is no longer needed when specifying EXCEPTION_CATCHING_ALLOWED [-Wdeprecated] [-Werror]'
1355+
self.assert_fail([EMCC, test_file('hello_world.c')] + self.get_cflags(), expected)
13561356

13571357
# =1 should be a hard error
13581358
self.set_setting('DISABLE_EXCEPTION_CATCHING', 1)
1359-
err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_cflags())
1360-
self.assertContained('error: DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED are mutually exclusive', err)
1359+
expected = 'error: DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED are mutually exclusive'
1360+
self.assert_fail([EMCC, test_file('hello_world.c')] + self.get_cflags(), expected)
13611361

13621362
# even setting an empty list should trigger the error;
13631363
self.set_setting('EXCEPTION_CATCHING_ALLOWED', [])
1364-
err = self.expect_fail([EMCC, test_file('hello_world.c')] + self.get_cflags())
1365-
self.assertContained('error: DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED are mutually exclusive', err)
1364+
expected = 'error: DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED are mutually exclusive'
1365+
self.assert_fail([EMCC, test_file('hello_world.c')] + self.get_cflags(), expected)
13661366

13671367
@with_all_eh_sjlj
13681368
def test_exceptions_uncaught(self):
@@ -1659,20 +1659,20 @@ def clear_all_relevant_settings(self):
16591659

16601660
# Emscripten EH and Wasm EH cannot be enabled at the same time
16611661
self.set_setting('DISABLE_EXCEPTION_CATCHING', 0)
1662-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1663-
self.assertContained('error: DISABLE_EXCEPTION_CATCHING=0 is not compatible with -fwasm-exceptions', err)
1662+
expected = 'error: DISABLE_EXCEPTION_CATCHING=0 is not compatible with -fwasm-exceptions'
1663+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
16641664
clear_all_relevant_settings(self)
16651665

16661666
self.set_setting('DISABLE_EXCEPTION_THROWING', 0)
1667-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1668-
self.assertContained('error: DISABLE_EXCEPTION_THROWING=0 is not compatible with -fwasm-exceptions', err)
1667+
expected = 'error: DISABLE_EXCEPTION_THROWING=0 is not compatible with -fwasm-exceptions'
1668+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
16691669
clear_all_relevant_settings(self)
16701670

16711671
# Emscripten EH: You can't enable catching and disable throwing
16721672
self.set_setting('DISABLE_EXCEPTION_THROWING', 1)
16731673
self.set_setting('DISABLE_EXCEPTION_CATCHING', 0)
1674-
err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags())
1675-
self.assertContained("error: DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions", err)
1674+
expected = "error: DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions"
1675+
self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected)
16761676
clear_all_relevant_settings(self)
16771677

16781678
# When using Wasm EH, users are not supposed to explicitly pass
@@ -1681,50 +1681,50 @@ def clear_all_relevant_settings(self):
16811681
# We only warn on these cases, but the tests here error out because the
16821682
# test setting includes -Werror.
16831683
self.set_setting('DISABLE_EXCEPTION_THROWING', 1)
1684-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1685-
self.assertContained('error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', err)
1684+
expected = 'error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions'
1685+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
16861686
clear_all_relevant_settings(self)
16871687

16881688
self.set_setting('DISABLE_EXCEPTION_CATCHING', 1)
1689-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1690-
self.assertContained('error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions', err)
1689+
expected = 'error: you no longer need to pass DISABLE_EXCEPTION_CATCHING or DISABLE_EXCEPTION_THROWING when using Wasm exceptions'
1690+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
16911691
clear_all_relevant_settings(self)
16921692

16931693
# Emscripten SjLj and Wasm EH cannot mix
16941694
self.set_setting('SUPPORT_LONGJMP', 'emscripten')
1695-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1696-
self.assertContained('error: SUPPORT_LONGJMP=emscripten is not compatible with -fwasm-exceptions', err)
1695+
expected = 'error: SUPPORT_LONGJMP=emscripten is not compatible with -fwasm-exceptions'
1696+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
16971697
clear_all_relevant_settings(self)
16981698

16991699
# Wasm SjLj and Emscripten EH cannot mix
17001700
self.set_setting('SUPPORT_LONGJMP', 'wasm')
17011701
self.set_setting('DISABLE_EXCEPTION_THROWING', 0)
1702-
err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags())
1703-
self.assertContained('error: SUPPORT_LONGJMP=wasm cannot be used with DISABLE_EXCEPTION_THROWING=0', err)
1702+
expected = 'error: SUPPORT_LONGJMP=wasm cannot be used with DISABLE_EXCEPTION_THROWING=0'
1703+
self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected)
17041704
clear_all_relevant_settings(self)
17051705

17061706
self.set_setting('SUPPORT_LONGJMP', 'wasm')
17071707
self.set_setting('DISABLE_EXCEPTION_CATCHING', 0)
1708-
err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags())
1709-
self.assertContained('error: SUPPORT_LONGJMP=wasm cannot be used with DISABLE_EXCEPTION_CATCHING=0', err)
1708+
expected = 'error: SUPPORT_LONGJMP=wasm cannot be used with DISABLE_EXCEPTION_CATCHING=0'
1709+
self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected)
17101710
clear_all_relevant_settings(self)
17111711

17121712
# Wasm EH does not support ASYNCIFY=1
17131713
self.set_setting('ASYNCIFY', 1)
1714-
err = self.expect_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags())
1715-
self.assertContained('error: ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.', err)
1714+
expected = 'error: ASYNCIFY=1 is not compatible with -fwasm-exceptions. Parts of the program that mix ASYNCIFY and exceptions will not compile.'
1715+
self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected)
17161716
clear_all_relevant_settings(self)
17171717

17181718
# EXPORT_EXCEPTION_HANDLING_HELPERS and EXCEPTION_STACK_TRACES requires
17191719
# either Emscripten EH or Wasm EH
17201720
self.set_setting('EXPORT_EXCEPTION_HANDLING_HELPERS')
1721-
err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags())
1722-
self.assertContained('error: EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions', err)
1721+
expected = 'error: EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions'
1722+
self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected)
17231723
clear_all_relevant_settings(self)
17241724

17251725
self.set_setting('EXCEPTION_STACK_TRACES')
1726-
err = self.expect_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags())
1727-
self.assertContained('error: EXCEPTION_STACK_TRACES requires either of -fexceptions or -fwasm-exceptions', err)
1726+
expected = 'error: EXCEPTION_STACK_TRACES requires either of -fexceptions or -fwasm-exceptions'
1727+
self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected)
17281728
clear_all_relevant_settings(self)
17291729

17301730
# Marked as impure since the WASI reactor modules (modules without main)
@@ -2082,8 +2082,8 @@ def test_em_js(self, args, force_c):
20822082

20832083
@no_wasm2js('test depends on WASM_BIGINT which is not compatible with wasm2js')
20842084
def test_em_js_i64(self):
2085-
err = self.expect_fail([EMCC, '-Werror', '-sWASM_BIGINT=0', test_file('core/test_em_js_i64.c')])
2086-
self.assertContained('emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`', err)
2085+
expected = 'emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`'
2086+
self.assert_fail([EMCC, '-Werror', '-sWASM_BIGINT=0', test_file('core/test_em_js_i64.c')], expected)
20872087
self.do_core_test('test_em_js_i64.c')
20882088

20892089
def test_em_js_address_taken(self):
@@ -6432,8 +6432,7 @@ def test_unicode_js_library(self):
64326432
# On Windows when Unicode support is enabled, this test code does not fail.
64336433
if not (WINDOWS and self.run_process(['chcp'], stdout=PIPE, shell=True).stdout.strip() == 'Active code page: 65001'):
64346434
create_file('expect_fail.py', 'print(len(open(r"%s").read()))' % test_file('unicode_library.js'))
6435-
err = self.expect_fail([PYTHON, 'expect_fail.py'], expect_traceback=True)
6436-
self.assertContained('UnicodeDecodeError', err)
6435+
self.assert_fail([PYTHON, 'expect_fail.py'], 'UnicodeDecodeError', expect_traceback=True)
64376436

64386437
self.cflags += ['-sMODULARIZE', '--js-library', test_file('unicode_library.js'), '--extern-post-js', test_file('modularize_post_js.js'), '--post-js', test_file('unicode_postjs.js')]
64396438
self.do_run_in_out_file_test('test_unicode_js_library.c')
@@ -7679,8 +7678,7 @@ def test_embind_val_read_pointer(self):
76797678
self.do_runf('embind/test_val_read_pointer.cpp', cflags=['-lembind'])
76807679

76817680
def test_embind_val_assignment(self):
7682-
err = self.expect_fail([EMCC, test_file('embind/test_val_assignment.cpp'), '-lembind', '-c'])
7683-
self.assertContained('candidate function not viable: expects an lvalue for object argument', err)
7681+
self.assert_fail([EMCC, test_file('embind/test_val_assignment.cpp'), '-lembind', '-c'], 'candidate function not viable: expects an lvalue for object argument')
76847682

76857683
@node_pthreads
76867684
def test_embind_val_cross_thread(self):
@@ -9550,8 +9548,7 @@ def test_undefined_main(self):
95509548
if self.get_setting('STANDALONE_WASM'):
95519549
# In standalone we don't support implicitly building without main. The user has to explicitly
95529550
# opt out (see below).
9553-
err = self.expect_fail([EMCC, test_file('core/test_ctors_no_main.cpp')] + self.get_cflags())
9554-
self.assertContained('undefined symbol: main', err)
9551+
self.assert_fail([EMCC, test_file('core/test_ctors_no_main.cpp')] + self.get_cflags(), 'undefined symbol: main')
95559552
elif not self.get_setting('STRICT'):
95569553
# Traditionally in emscripten we allow main to be implicitly undefined. This allows programs
95579554
# with a main and libraries without a main to be compiled identically.
@@ -9561,8 +9558,8 @@ def test_undefined_main(self):
95619558

95629559
# Disabling IGNORE_MISSING_MAIN should cause link to fail due to missing main
95639560
self.set_setting('IGNORE_MISSING_MAIN', 0)
9564-
err = self.expect_fail([EMCC, test_file('core/test_ctors_no_main.cpp')] + self.get_cflags())
9565-
self.assertContained('error: entry symbol not defined (pass --no-entry to suppress): main', err)
9561+
expected = 'error: entry symbol not defined (pass --no-entry to suppress): main'
9562+
self.assert_fail([EMCC, test_file('core/test_ctors_no_main.cpp')] + self.get_cflags(), expected)
95669563

95679564
# In non-standalone mode exporting an empty list of functions signal that we don't
95689565
# have a main and so should not generate an error.
@@ -9581,8 +9578,7 @@ def test_undefined_main_explicit(self):
95819578
def test_undefined_main_wasm_output(self):
95829579
if not can_do_standalone(self):
95839580
self.skipTest('standalone mode only')
9584-
err = self.expect_fail([EMCC, '-o', 'out.wasm', test_file('core/test_ctors_no_main.cpp')] + self.get_cflags())
9585-
self.assertContained('undefined symbol: main', err)
9581+
self.assert_fail([EMCC, '-o', 'out.wasm', test_file('core/test_ctors_no_main.cpp')] + self.get_cflags(), 'undefined symbol: main')
95869582

95879583
@no_2gb('crashed wasmtime')
95889584
def test_export_start(self):
@@ -9741,8 +9737,8 @@ def test_main_reads_args(self):
97419737
def test_promise(self):
97429738
# This test depends on Promise.any, which in turn requires a modern target. Check that it
97439739
# fails to even build on old targets.
9744-
err = self.expect_fail([EMCC, test_file('core/test_promise.c'), '-sMIN_CHROME_VERSION=75'])
9745-
self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err)
9740+
expected = 'error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration'
9741+
self.assert_fail([EMCC, test_file('core/test_promise.c'), '-sMIN_CHROME_VERSION=75'], expected)
97469742
self.do_core_test('test_promise.c')
97479743

97489744
@with_asyncify_and_jspi

0 commit comments

Comments
 (0)