@@ -308,7 +308,9 @@ def send_get(what):
308308
309309 else :
310310 # run via pyboard interface
311- had_crash , output_mupy = run_script_on_remote_target (pyb , args , test_file , is_special )
311+ had_crash , output_mupy = pyb .run_script_on_remote_target (
312+ args , test_file_abspath , is_special
313+ )
312314
313315 # canonical form for all ports/platforms is to use \n for end-of-line
314316 output_mupy = output_mupy .replace (b"\r \n " , b"\n " )
@@ -393,6 +395,51 @@ def value(self):
393395 return self ._value
394396
395397
398+ class PyboardNodeRunner :
399+ def __init__ (self ):
400+ mjs = os .getenv ("MICROPY_MICROPYTHON_MJS" )
401+ if mjs is None :
402+ mjs = base_path ("../ports/webassembly/build-standard/micropython.mjs" )
403+ else :
404+ mjs = os .path .abspath (mjs )
405+ self .micropython_mjs = mjs
406+
407+ def close (self ):
408+ pass
409+
410+ def run_script_on_remote_target (self , args , test_file , is_special ):
411+ cwd = os .path .dirname (test_file )
412+
413+ # Create system command list.
414+ cmdlist = ["node" ]
415+ if test_file .endswith (".py" ):
416+ # Run a Python script indirectly via "node micropython.mjs <script.py>".
417+ cmdlist .append (self .micropython_mjs )
418+ if args .heapsize is not None :
419+ cmdlist .extend (["-X" , "heapsize=" + args .heapsize ])
420+ cmdlist .append (test_file )
421+ else :
422+ # Run a js/mjs script directly with Node, passing in the path to micropython.mjs.
423+ cmdlist .append (test_file )
424+ cmdlist .append (self .micropython_mjs )
425+
426+ # Run the script.
427+ try :
428+ had_crash = False
429+ output_mupy = subprocess .check_output (
430+ cmdlist , stderr = subprocess .STDOUT , timeout = TEST_TIMEOUT , cwd = cwd
431+ )
432+ except subprocess .CalledProcessError as er :
433+ had_crash = True
434+ output_mupy = er .output + b"CRASH"
435+ except subprocess .TimeoutExpired as er :
436+ had_crash = True
437+ output_mupy = (er .output or b"" ) + b"TIMEOUT"
438+
439+ # Return the results.
440+ return had_crash , output_mupy
441+
442+
396443def run_tests (pyb , tests , args , result_dir , num_threads = 1 ):
397444 test_count = ThreadSafeCounter ()
398445 testcase_count = ThreadSafeCounter ()
@@ -631,6 +678,20 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
631678 ) # RA fsp rtc function doesn't support nano sec info
632679 elif args .target == "qemu-arm" :
633680 skip_tests .add ("misc/print_exception.py" ) # requires sys stdfiles
681+ elif args .target == "webassembly" :
682+ skip_tests .add ("basics/string_format_modulo.py" ) # can't print nulls to stdout
683+ skip_tests .add ("basics/string_strip.py" ) # can't print nulls to stdout
684+ skip_tests .add ("extmod/binascii_a2b_base64.py" )
685+ skip_tests .add ("extmod/re_stack_overflow.py" )
686+ skip_tests .add ("extmod/time_res.py" )
687+ skip_tests .add ("extmod/vfs_posix.py" )
688+ skip_tests .add ("extmod/vfs_posix_enoent.py" )
689+ skip_tests .add ("extmod/vfs_posix_paths.py" )
690+ skip_tests .add ("extmod/vfs_userfs.py" )
691+ skip_tests .add ("micropython/emg_exc.py" )
692+ skip_tests .add ("micropython/extreme_exc.py" )
693+ skip_tests .add ("micropython/heapalloc_exc_compressed_emg_exc.py" )
694+ skip_tests .add ("micropython/import_mpy_invalid.py" )
634695
635696 # Some tests are known to fail on 64-bit machines
636697 if pyb is None and platform .architecture ()[0 ] == "64bit" :
@@ -977,6 +1038,7 @@ def main():
9771038 LOCAL_TARGETS = (
9781039 "unix" ,
9791040 "qemu-arm" ,
1041+ "webassembly" ,
9801042 )
9811043 EXTERNAL_TARGETS = (
9821044 "pyboard" ,
@@ -997,6 +1059,8 @@ def main():
9971059 args .mpy_cross_flags = "-march=host"
9981060 elif args .target == "qemu-arm" :
9991061 args .mpy_cross_flags = "-march=armv7m"
1062+ if args .target == "webassembly" :
1063+ pyb = PyboardNodeRunner ()
10001064 elif args .target in EXTERNAL_TARGETS :
10011065 global pyboard
10021066 sys .path .append (base_path ("../tools" ))
@@ -1015,6 +1079,7 @@ def main():
10151079 args .mpy_cross_flags = "-march=armv7m"
10161080
10171081 pyb = pyboard .Pyboard (args .device , args .baudrate , args .user , args .password )
1082+ pyboard .Pyboard .run_script_on_remote_target = run_script_on_remote_target
10181083 pyb .enter_raw_repl ()
10191084 else :
10201085 raise ValueError ("target must be one of %s" % ", " .join (LOCAL_TARGETS + EXTERNAL_TARGETS ))
@@ -1032,6 +1097,10 @@ def main():
10321097 else :
10331098 tests = []
10341099 elif len (args .files ) == 0 :
1100+ test_extensions = ("*.py" ,)
1101+ if args .target == "webassembly" :
1102+ test_extensions += ("*.js" , "*.mjs" )
1103+
10351104 if args .test_dirs is None :
10361105 test_dirs = (
10371106 "basics" ,
@@ -1072,12 +1141,16 @@ def main():
10721141 "inlineasm" ,
10731142 "ports/qemu-arm" ,
10741143 )
1144+ elif args .target == "webassembly" :
1145+ test_dirs += ("float" ,)
10751146 else :
10761147 # run tests from these directories
10771148 test_dirs = args .test_dirs
10781149 tests = sorted (
10791150 test_file
1080- for test_files in (glob ("{}/*.py" .format (dir )) for dir in test_dirs )
1151+ for test_files in (
1152+ glob (os .path .join (dir , ext )) for dir in test_dirs for ext in test_extensions
1153+ )
10811154 for test_file in test_files
10821155 )
10831156 else :
0 commit comments