Skip to content

Commit 09365fd

Browse files
authored
[test] Re-implement the @all_engines decorator based on parameteraization. NFC (#25115)
This means that we can remove the loop over JS_ENGINES from few more tests. It also splits up these tests in to smaller units which is always good and means that it much more obvious what is going on when one of them fails.
1 parent ac9aa11 commit 09365fd

File tree

4 files changed

+85
-63
lines changed

4 files changed

+85
-63
lines changed

src/parseTools.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,12 @@ function ENVIRONMENT_IS_WORKER_THREAD() {
11081108
}
11091109

11101110
function nodeDetectionCode() {
1111-
if (ENVIRONMENT == 'node') {
1111+
if (ENVIRONMENT == 'node' && ASSERTIONS == 0) {
11121112
// The only environment where this code is intended to run is Node.js.
11131113
// Return unconditional true so that later Closure optimizer will be able to
11141114
// optimize code size.
1115+
// Note that when ASSERTIONS are enabled we still want to runtime detect
1116+
// node so that errors can be reported when run elsewhere.
11151117
return 'true';
11161118
}
11171119
return "typeof process == 'object' && process.versions?.node && process.type != 'renderer'";

test/common.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -450,19 +450,42 @@ def crossplatform(f):
450450
return f
451451

452452

453-
# without EMTEST_ALL_ENGINES set we only run tests in a single VM by
454-
# default. in some tests we know that cross-VM differences may happen and
455-
# so are worth testing, and they should be marked with this decorator
453+
# Without EMTEST_ALL_ENGINES set we only run tests in a single VM by default.
454+
# However, for some tests we know that cross-VM differences may happen and
455+
# so are worth testing, and they should be marked with this decorator which creates
456+
# N different variants of the test, one for each engine.
456457
def all_engines(f):
457458
assert callable(f)
458459

460+
if len(config.JS_ENGINES) == 1 or EMTEST_ALL_ENGINES:
461+
return f
462+
459463
@wraps(f)
460-
def decorated(self, *args, **kwargs):
461-
self.use_all_engines = True
464+
def metafunc(self, engine, *args, **kwargs):
462465
self.set_setting('ENVIRONMENT', 'web,node,shell')
466+
self.js_engines = [engine]
463467
f(self, *args, **kwargs)
464468

465-
return decorated
469+
engine_mapping = {}
470+
for engine in config.JS_ENGINES:
471+
if not engine_mapping:
472+
# For the first engine we use no suffix at all.
473+
# This uffnsures that one of the tests matches the original name, meaning that
474+
# you can still run just `test_foo` and always get the first engine without
475+
# needing to write, for example, `test_foo_node`.
476+
name = ''
477+
else:
478+
basename = os.path.basename(engine[0])
479+
name = basename
480+
suffix = 1
481+
while name in engine_mapping:
482+
name = f'{basename}_{suffix}'
483+
suffix += 1
484+
engine_mapping[name] = (engine,)
485+
486+
parameterize(metafunc, engine_mapping)
487+
488+
return metafunc
466489

467490

468491
@contextlib.contextmanager
@@ -1348,7 +1371,6 @@ def setUp(self):
13481371
self.temp_files_before_run = []
13491372
self.required_engine = None
13501373
self.wasm_engines = config.WASM_ENGINES.copy()
1351-
self.use_all_engines = EMTEST_ALL_ENGINES
13521374
if self.get_current_js_engine() != config.NODE_JS_TEST:
13531375
# If our primary JS engine is something other than node then enable
13541376
# shell support.
@@ -2103,11 +2125,11 @@ def _build_and_run(self, filename, expected_output, args=None,
21032125
self.assertExists(js_file)
21042126

21052127
engines = self.js_engines.copy()
2106-
if len(engines) > 1 and not self.use_all_engines:
2128+
if len(engines) > 1 and not EMTEST_ALL_ENGINES:
21072129
engines = engines[:1]
21082130
# In standalone mode, also add wasm vms as we should be able to run there too.
21092131
if self.get_setting('STANDALONE_WASM'):
2110-
# TODO once standalone wasm support is more stable, apply use_all_engines
2132+
# TODO once standalone wasm support is more stable, apply EMTEST_ALL_ENGINES
21112133
# like with js engines, but for now as we bring it up, test in all of them
21122134
if not self.wasm_engines:
21132135
if 'EMTEST_SKIP_WASM_ENGINE' in os.environ:

test/test_core.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8783,6 +8783,7 @@ def test_mallinfo(self):
87838783
def test_wrap_malloc(self, args):
87848784
self.do_runf('core/test_wrap_malloc.c', 'OK.', cflags=args)
87858785

8786+
@all_engines
87868787
def test_environment(self):
87878788
self.set_setting('ASSERTIONS')
87888789

@@ -8794,33 +8795,31 @@ def test(assert_returncode=0):
87948795
js = read_file(self.output_name('test_hello_world'))
87958796
assert ('require(' in js) == ('node' in self.get_setting('ENVIRONMENT')), 'we should have require() calls only if node js specified'
87968797

8797-
for engine in config.JS_ENGINES:
8798-
print(f'engine: {engine}')
8799-
# set us to test in just this engine
8800-
self.require_engine(engine)
8801-
# tell the compiler to build with just that engine
8802-
if engine == config.NODE_JS_TEST:
8803-
right = 'node'
8804-
wrong = 'shell'
8805-
else:
8806-
right = 'shell'
8807-
wrong = 'node'
8808-
# test with the right env
8809-
self.set_setting('ENVIRONMENT', right)
8810-
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8811-
test()
8812-
# test with the wrong env
8813-
self.set_setting('ENVIRONMENT', wrong)
8814-
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8815-
try:
8816-
test(assert_returncode=NON_ZERO)
8817-
raise Exception('unexpected success')
8818-
except Exception as e:
8819-
self.assertContained('not compiled for this environment', str(e))
8820-
# test with a combined env
8821-
self.set_setting('ENVIRONMENT', right + ',' + wrong)
8822-
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8823-
test()
8798+
engine = self.get_current_js_engine()
8799+
print(f'engine: {engine}')
8800+
# tell the compiler to build with just that engine
8801+
if engine == config.NODE_JS_TEST:
8802+
right = 'node'
8803+
wrong = 'shell'
8804+
else:
8805+
right = 'shell'
8806+
wrong = 'node'
8807+
# test with the right env
8808+
self.set_setting('ENVIRONMENT', right)
8809+
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8810+
test()
8811+
# test with the wrong env
8812+
self.set_setting('ENVIRONMENT', wrong)
8813+
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8814+
try:
8815+
test(assert_returncode=NON_ZERO)
8816+
raise Exception('unexpected success')
8817+
except Exception as e:
8818+
self.assertContained('not compiled for this environment', str(e))
8819+
# test with a combined env
8820+
self.set_setting('ENVIRONMENT', right + ',' + wrong)
8821+
print('ENVIRONMENT =', self.get_setting('ENVIRONMENT'))
8822+
test()
88248823

88258824
@requires_node
88268825
def test_postrun_exception(self):

test/test_other.py

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5953,11 +5953,12 @@ def test_argv0_node(self):
59535953
output = self.do_runf('code.c')
59545954
self.assertContained('I am ' + utils.normalize_path(os.path.realpath(self.get_dir())) + '/code.js', utils.normalize_path(output))
59555955

5956+
@all_engines
59565957
@parameterized({
5957-
'no_exit_runtime': [True],
5958-
'': [False],
5958+
'exit_runtime': (['-sEXIT_RUNTIME=1'],),
5959+
'': ([],),
59595960
})
5960-
def test_returncode(self, no_exit):
5961+
def test_returncode(self, args):
59615962
create_file('src.c', r'''
59625963
#include <stdio.h>
59635964
#include <stdlib.h>
@@ -5969,20 +5970,17 @@ def test_returncode(self, no_exit):
59695970
#endif
59705971
}
59715972
''')
5973+
msg = 'but keepRuntimeAlive() is set (counter=0) due to an async operation, so halting execution but not exiting the runtime'
59725974
for code in (0, 123):
59735975
for call_exit in (0, 1):
59745976
for async_compile in (0, 1):
5975-
self.run_process([EMCC, 'src.c', '-sENVIRONMENT=node,shell', '-DCODE=%d' % code, '-sEXIT_RUNTIME=%d' % (1 - no_exit), '-DCALL_EXIT=%d' % call_exit, '-sWASM_ASYNC_COMPILATION=%d' % async_compile])
5976-
for engine in config.JS_ENGINES:
5977-
print(code, call_exit, async_compile, engine)
5978-
proc = self.run_process(engine + ['a.out.js'], stderr=PIPE, check=False)
5979-
msg = 'but keepRuntimeAlive() is set (counter=0) due to an async operation, so halting execution but not exiting the runtime'
5980-
if no_exit and call_exit:
5981-
self.assertContained(msg, proc.stderr)
5982-
else:
5983-
self.assertNotContained(msg, proc.stderr)
5984-
# we always emit the right exit code, whether we exit the runtime or not
5985-
self.assertEqual(proc.returncode, code)
5977+
print('code', code, 'call_exit', call_exit, 'async_compile', async_compile)
5978+
cflags = args + [f'-DCODE={code}', f'-DCALL_EXIT={call_exit}', f'-sWASM_ASYNC_COMPILATION={async_compile}']
5979+
output = self.do_runf('src.c', cflags=cflags, assert_returncode=code)
5980+
if '-sEXIT_RUNTIME=1' not in args and call_exit:
5981+
self.assertContained(msg, output)
5982+
else:
5983+
self.assertNotContained(msg, output)
59865984

59875985
def test_emscripten_force_exit_NO_EXIT_RUNTIME(self):
59885986
create_file('src.c', r'''
@@ -8920,6 +8918,7 @@ def test_run_order(self):
89208918
]
89218919
self.do_runf('src.c', '\n'.join(expected_order))
89228920

8921+
@all_engines
89238922
def test_override_js_execution_environment(self):
89248923
create_file('main.c', r'''
89258924
#include <emscripten.h>
@@ -8934,19 +8933,19 @@ def test_override_js_execution_environment(self):
89348933
''')
89358934
self.run_process([EMCC, 'main.c', '-sENVIRONMENT=node,shell'])
89368935
src = read_file('a.out.js')
8936+
engine = self.get_current_js_engine()
89378937
for env in ['web', 'worker', 'node', 'shell']:
8938-
for engine in config.JS_ENGINES:
8939-
actual = 'NODE' if engine == config.NODE_JS_TEST else 'SHELL'
8940-
print(env, actual, engine)
8941-
module = {'ENVIRONMENT': env}
8942-
if env != actual:
8943-
# avoid problems with arguments detection, which may cause very odd failures with the wrong environment code
8944-
module['arguments'] = []
8945-
curr = 'var Module = %s;\n' % str(module)
8946-
print(' ' + curr)
8947-
create_file('test.js', curr + src)
8948-
seen = self.run_js('test.js', engine=engine, assert_returncode=NON_ZERO)
8949-
self.assertContained('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node', seen)
8938+
actual = 'NODE' if engine == config.NODE_JS_TEST else 'SHELL'
8939+
print('env', env, 'actual', actual, 'engine', engine)
8940+
module = {'ENVIRONMENT': env}
8941+
if env != actual:
8942+
# avoid problems with arguments detection, which may cause very odd failures with the wrong environment code
8943+
module['arguments'] = []
8944+
curr = 'var Module = %s;\n' % str(module)
8945+
print(' ' + curr)
8946+
create_file('test.js', curr + src)
8947+
seen = self.run_js('test.js', assert_returncode=NON_ZERO)
8948+
self.assertContained('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node', seen)
89508949

89518950
def test_override_c_environ(self):
89528951
create_file('pre.js', r'''

0 commit comments

Comments
 (0)