55
66import argparse
77import os
8+ import plistlib
89import random
10+ import re
911import shlex
1012import shutil
1113import subprocess
2628from common import HttpServerThread , requires_dev_dependency
2729from tools import shared
2830from tools import ports
31+ from tools .feature_matrix import UNSUPPORTED
2932from tools .shared import EMCC , WINDOWS , FILE_PACKAGER , PIPE , DEBUG
30- from tools .utils import delete_dir
33+ from tools .utils import delete_dir , memoize
3134
3235
3336def make_test_chunked_synchronous_xhr_server (support_byte_ranges , data , port ):
@@ -141,6 +144,20 @@ def is_swiftshader(_):
141144 return is_chrome () and '--use-gl=swiftshader' in common .EMTEST_BROWSER
142145
143146
147+ @memoize
148+ def get_safari_version ():
149+ if not is_safari ():
150+ return UNSUPPORTED
151+ plist_path = os .path .join (common .EMTEST_BROWSER .strip (), 'Contents' , 'version.plist' )
152+ version_str = plistlib .load (open (plist_path , 'rb' )).get ('CFBundleShortVersionString' )
153+ # Split into parts (major.minor.patch)
154+ parts = (version_str .split ('.' ) + ['0' , '0' , '0' ])[:3 ]
155+ # Convert each part into integers, discarding any trailing string, e.g. '13a' -> 13.
156+ parts = [int (re .match (r"\d+" , s ).group ()) if re .match (r"\d+" , s ) else 0 for s in parts ]
157+ # Return version as XXYYZZ
158+ return parts [0 ] * 10000 + parts [1 ] * 100 + parts [2 ]
159+
160+
144161no_swiftshader = skip_if_simple ('not compatible with swiftshader' , is_swiftshader )
145162
146163no_chrome = skip_if ('no_chrome' , lambda _ : is_chrome (), 'chrome is not supported' )
@@ -150,6 +167,18 @@ def is_swiftshader(_):
150167no_safari = skip_if ('no_safari' , lambda _ : is_safari (), 'safari is not supported' )
151168
152169
170+ def requires_version (name , version_getter ):
171+ assert callable (version_getter )
172+
173+ def decorator (min_required_version , note = '' ):
174+ return skip_if_simple (name , lambda _ : version_getter () < min_required_version , f'{ name } v{ version_getter ()} is not supported (need v{ min_required_version } at minimum) { note } ' )
175+
176+ return decorator
177+
178+
179+ requires_safari_version = requires_version ('safari' , get_safari_version )
180+
181+
153182def is_jspi (args ):
154183 return '-sASYNCIFY=2' in args
155184
@@ -289,6 +318,7 @@ def test_sdl1(self):
289318 def test_sdl1_es6 (self ):
290319 self .reftest ('hello_world_sdl.c' , 'htmltest.png' , cflags = ['-sUSE_SDL' , '-lGL' , '-sEXPORT_ES6' ])
291320
321+ @no_safari ('TODO: Fails in NEW Safari 26.0.1 (21622.1.22.11.15), but not in OLD Safari 17.6 (17618.3.11.11.7, 17618) or Safari 18.5 (20621.2.5.11.8)' )
292322 def test_emscripten_log (self ):
293323 self .btest_exit ('test_emscripten_log.cpp' , cflags = ['-Wno-deprecated-pragma' , '-gsource-map' , '-g2' ])
294324
@@ -1443,6 +1473,7 @@ def test_separate_metadata_later(self):
14431473 self .run_process ([FILE_PACKAGER , 'more.data' , '--preload' , 'data.dat' , '--separate-metadata' , '--js-output=more.js' ])
14441474 self .btest (Path ('browser/separate_metadata_later.cpp' ), '1' , cflags = ['-sFORCE_FILESYSTEM' ])
14451475
1476+ @requires_safari_version (260001 , 'TODO: Fails with "Assertion failed: false"' ) # Fails in Safari 18.5 (20621.2.5.11.8) with Intel x64 CPU only. Passes on Safari 18.5 (20621.2.5.11.8) with ARM M1, Safari 17.6 (17618.3.11.11.7, 17618)/x64 and Safari 26.0.1 (21622.1.22.11.15)/M4
14461477 def test_idbstore (self ):
14471478 secret = str (time .time ())
14481479 for stage in (0 , 1 , 2 , 3 , 0 , 1 , 2 , 0 , 0 , 1 , 4 , 2 , 5 , 0 , 4 , 6 , 5 ):
@@ -2800,7 +2831,7 @@ def test_webgl2_pbo(self):
28002831 self .btest_exit ('webgl2_pbo.c' , cflags = ['-sMAX_WEBGL_VERSION=2' , '-lGL' ])
28012832
28022833 @no_firefox ('fails on CI likely due to GPU drivers there' )
2803- @no_safari ('TODO: Fails with report_result?5' ) # Safari 17.6 (17618.3.11.11.7, 17618)
2834+ @no_safari ('TODO: Fails with report_result?5' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
28042835 @requires_graphics_hardware
28052836 def test_webgl2_sokol_mipmap (self ):
28062837 self .reftest ('third_party/sokol/mipmap-emsc.c' , 'third_party/sokol/mipmap-emsc.png' ,
@@ -2959,7 +2990,7 @@ def test_sdl2_image_jpeg(self):
29592990 @also_with_wasmfs
29602991 @requires_graphics_hardware
29612992 @with_all_sjlj
2962- @no_safari ( ' Test enables Wasm exceptions, so will not run in Safari 17.6 (17618.3.11.11.7, 17618)' ) # Safari 17.6 (17618.3.11 .11.7, 17618 )
2993+ @requires_safari_version ( 170601 , 'TODO: Test enables Wasm exceptions' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), passes in Safari 18.5 (20621.2.5 .11.8) and Safari 26.0.1 (21622.1.22.11.15 )
29632994 def test_sdl2_image_formats (self ):
29642995 shutil .copy (test_file ('screenshot.png' ), '.' )
29652996 shutil .copy (test_file ('screenshot.jpg' ), '.' )
@@ -3361,7 +3392,7 @@ def test_async_returnvalue(self, args):
33613392 create_file ('filey.txt' , 'sync_tunnel\n sync_tunnel_bool\n ' )
33623393 self .btest ('test_async_returnvalue.c' , '0' , cflags = ['-sASSERTIONS' , '-sASYNCIFY' , '-sASYNCIFY_IGNORE_INDIRECT' , '--js-library' , test_file ('browser/test_async_returnvalue.js' )] + args )
33633394
3364- @no_safari ('TODO: Never reports a result, so times out' ) # Safari 17.6 (17618.3.11.11.7, 17618)
3395+ @no_safari ('TODO: Never reports a result, so times out' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
33653396 def test_async_bad_list (self ):
33663397 self .btest ('test_async_bad_list.c' , '0' , cflags = ['-sASYNCIFY' , '-sASYNCIFY_ONLY=waka' , '--profiling' ])
33673398
@@ -3414,7 +3445,7 @@ def test_modularize(self, args, code, opts):
34143445 self .run_browser ('a.html' , '/report_result?0' )
34153446
34163447 @no_firefox ('source phase imports not implemented yet in firefox' )
3417- @no_safari ('croaks on line "import source wasmModule from \' ./out.wasm\' ;"' ) # Safari 17.6 (17618.3.11.11.7, 17618)
3448+ @no_safari ('TODO: croaks on line "import source wasmModule from \' ./out.wasm\' ;"' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
34183449 def test_source_phase_imports (self ):
34193450 self .compile_btest ('browser_test_hello_world.c' , ['-sEXPORT_ES6' , '-sSOURCE_PHASE_IMPORTS' , '-Wno-experimental' , '-o' , 'out.mjs' ])
34203451 create_file ('a.html' , '''
@@ -3801,7 +3832,7 @@ def test_pthread_gcc_64bit_atomic_fetch_and_op(self):
38013832
38023833 # Test the old GCC atomic __sync_op_and_fetch builtin operations.
38033834 @also_with_wasm2js
3804- @no_safari ( 'TODO: browser.test_pthread_gcc_atomic_op_and_fetch_wasm2js fails with "abort:Assertion failed: nand_and_fetch_data == -1"' ) # Safari 17.6 (17618.3.11.11.7, 17618)
3835+ @requires_safari_version ( 170601 , 'TODO: browser.test_pthread_gcc_atomic_op_and_fetch_wasm2js fails with "abort:Assertion failed: nand_and_fetch_data == -1"' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), passes in Safari 18.5 (20621.2.5.11.8) and Safari 26.0.1 (21622.1.22.11.15 )
38053836 def test_pthread_gcc_atomic_op_and_fetch (self ):
38063837 self .cflags += ['-Wno-sync-fetch-and-nand-semantics-changed' ]
38073838 self .btest_exit ('pthread/test_pthread_gcc_atomic_op_and_fetch.c' , cflags = ['-O3' , '-pthread' , '-sPTHREAD_POOL_SIZE=8' ])
@@ -3899,7 +3930,7 @@ def test_pthread_cleanup(self):
38993930 '' : ([],),
39003931 'spinlock' : (['-DSPINLOCK_TEST' ],),
39013932 })
3902- @no_safari ( 'TODO: browser.test_pthread_mutex and browser.test_pthread_mutex_spinlock both hang Safari' ) # Safari 17.6 (17618.3.11.11.7, 17618)
3933+ @requires_safari_version ( 170601 , 'TODO: browser.test_pthread_mutex and browser.test_pthread_mutex_spinlock both hang Safari' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), passes in Safari 18.5 (20621.2.5.11.8) and Safari 26.0.1 (21622.1.22.11.15 )
39033934 def test_pthread_mutex (self , args ):
39043935 self .btest_exit ('pthread/test_pthread_mutex.c' , cflags = ['-O3' , '-pthread' , '-sPTHREAD_POOL_SIZE=8' ] + args )
39053936
@@ -4087,7 +4118,7 @@ def test_pthread_safe_stack(self):
40874118 'no_leak' : ['test_pthread_lsan_no_leak' , []],
40884119 })
40894120 @no_firefox ('https://github.com/emscripten-core/emscripten/issues/15978' )
4090- @no_safari ('TODO: browser.test_pthread_lsan_leak fails with /report_result?0' ) # Safari 17.6 (17618.3.11.11.7, 17618)
4121+ @no_safari ('TODO: browser.test_pthread_lsan_leak fails with /report_result?0' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
40914122 def test_pthread_lsan (self , name , args ):
40924123 self .btest (Path ('pthread' , name + '.cpp' ), expected = '1' , cflags = ['-fsanitize=leak' , '-pthread' , '-sPROXY_TO_PTHREAD' , '--pre-js' , test_file ('pthread' , name + '.js' )] + args )
40934124
@@ -4099,7 +4130,7 @@ def test_pthread_lsan(self, name, args):
40994130 'leak' : ['test_pthread_lsan_leak' , ['-gsource-map' ]],
41004131 'no_leak' : ['test_pthread_lsan_no_leak' , []],
41014132 })
4102- @no_safari ('TODO: browser.test_pthread_asan_leak fails with /report_result?0' ) # Safari 17.6 (17618.3.11.11.7, 17618)
4133+ @no_safari ('TODO: browser.test_pthread_asan_leak fails with /report_result?0' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
41034134 def test_pthread_asan (self , name , args ):
41044135 self .btest (Path ('pthread' , name + '.cpp' ), expected = '1' , cflags = ['-fsanitize=address' , '-pthread' , '-sPROXY_TO_PTHREAD' , '--pre-js' , test_file ('pthread' , name + '.js' )] + args )
41054136
@@ -4113,7 +4144,7 @@ def test_pthread_asan_use_after_free(self):
41134144 @no_2gb ('ASAN + GLOBAL_BASE' )
41144145 @no_4gb ('ASAN + GLOBAL_BASE' )
41154146 @no_firefox ('https://github.com/emscripten-core/emscripten/issues/20006' )
4116- @no_safari ('TODO: Hangs' ) # Safari Version 18.5 (20621.2.5 .11.8 )
4147+ @no_safari ('TODO: Hangs' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22 .11.15 )
41174148 @also_with_wasmfs
41184149 def test_pthread_asan_use_after_free_2 (self ):
41194150 # similiar to test_pthread_asan_use_after_free, but using a pool instead
@@ -4132,7 +4163,7 @@ def test_pthread_exit_process(self):
41324163 args += ['--pre-js' , test_file ('core/pthread/test_pthread_exit_runtime.pre.js' )]
41334164 self .btest ('core/pthread/test_pthread_exit_runtime.c' , expected = 'onExit status: 42' , cflags = args )
41344165
4135- @no_safari ('TODO: Fails with report_result?unexpected: [object ErrorEvent]' ) # Safari 17.6 (17618.3.11.11.7, 17618)
4166+ @no_safari ('TODO: Fails with report_result?unexpected: [object ErrorEvent]' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
41364167 def test_pthread_trap (self ):
41374168 create_file ('pre.js' , '''
41384169 if (typeof window === 'object' && window) {
@@ -5321,6 +5352,7 @@ def test_4gb(self):
53215352
53225353 # Tests that emmalloc supports up to 4GB Wasm heaps.
53235354 @no_firefox ('no 4GB support yet' )
5355+ @requires_safari_version (170601 , 'Assertion failed: emscripten_get_heap_size() == MAX_HEAP' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618)
53245356 @no_4gb ('uses MAXIMUM_MEMORY' )
53255357 def test_emmalloc_4gb (self ):
53265358 # For now, keep this in browser as this suite runs serially, which
@@ -5389,7 +5421,7 @@ def test_wasmfs_fetch_backend_threaded(self, args):
53895421 'jspi' : (['-Wno-experimental' , '-sASYNCIFY=2' ],),
53905422 'jspi_wasm_bigint' : (['-Wno-experimental' , '-sASYNCIFY=2' , '-sWASM_BIGINT' ],),
53915423 })
5392- @no_safari ('TODO: Fails with abort:Assertion failed: err == 0' ) # Safari 17.6 (17618.3.11.11.7, 17618)
5424+ @no_safari ('TODO: Fails with abort:Assertion failed: err == 0' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
53935425 def test_wasmfs_opfs (self , args ):
53945426 if '-sASYNCIFY=2' in args :
53955427 self .require_jspi ()
@@ -5399,7 +5431,7 @@ def test_wasmfs_opfs(self, args):
53995431 self .btest_exit (test , cflags = args + ['-DWASMFS_RESUME' ])
54005432
54015433 @no_firefox ('no OPFS support yet' )
5402- @no_safari ('TODO: Fails with exception:Did not get expected EIO when unlinking file' ) # Safari 17.6 (17618.3.11.11.7, 17618)
5434+ @no_safari ('TODO: Fails with exception:Did not get expected EIO when unlinking file' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618) and Safari 26.0.1 (21622.1.22.11.15 )
54035435 def test_wasmfs_opfs_errors (self ):
54045436 test = test_file ('wasmfs/wasmfs_opfs_errors.c' )
54055437 postjs = test_file ('wasmfs/wasmfs_opfs_errors_post.js' )
@@ -5474,7 +5506,7 @@ def test_manual_pthread_proxy_hammer(self, args):
54745506 def test_assert_failure (self ):
54755507 self .btest ('test_assert_failure.c' , 'abort:Assertion failed: false && "this is a test"' )
54765508
5477- @no_safari ('TODO: Fails with report_result?exception:rejected! / undefined ' ) # Safari 17.6 (17618.3.11.11.7, 17618)
5509+ @no_safari ('TODO: Fails with report_result?exception:rejected!' ) # Fails in Safari 17.6 (17618.3.11.11.7, 17618), Safari 26.0.1 (21622.1.22.11.15 )
54785510 def test_pthread_unhandledrejection (self ):
54795511 # Check that an unhandled promise rejection is propagated to the main thread
54805512 # as an error. This test is failing if it hangs!
0 commit comments