blob: cc1020e60a5a141cd0f4889e1cab46c414f8d85a [file] [log] [blame]
Damien George929a6752014-04-02 15:31:39 +01001#! /usr/bin/env python3
Damien39977a52013-12-29 22:34:42 +00002
Markus Siemens19ccc6b2014-01-27 22:53:28 +01003import os
4import subprocess
5import sys
Damien George612045f2014-09-17 22:56:34 +01006import platform
Damien George41f768f2014-05-03 16:43:27 +01007import argparse
Markus Siemens19ccc6b2014-01-27 22:53:28 +01008from glob import glob
Damien39977a52013-12-29 22:34:42 +00009
Paul Sokolovskya7752a42014-04-04 17:28:34 +030010# Tests require at least CPython 3.3. If your default python3 executable
11# is of lower version, you can point MICROPY_CPYTHON3 environment var
12# to the correct executable.
Markus Siemens19ccc6b2014-01-27 22:53:28 +010013if os.name == 'nt':
Paul Sokolovskya7752a42014-04-04 17:28:34 +030014 CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe')
Andrew Scheller57094532014-04-17 01:22:45 +010015 MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../windows/micropython.exe')
Markus Siemens19ccc6b2014-01-27 22:53:28 +010016else:
Paul Sokolovsky34e11992014-04-03 22:06:35 +030017 CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
Andrew Scheller57094532014-04-17 01:22:45 +010018 MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../unix/micropython')
Damien39977a52013-12-29 22:34:42 +000019
Paul Sokolovskyfd232c32014-03-23 01:07:30 +020020def rm_f(fname):
21 if os.path.exists(fname):
22 os.remove(fname)
23
Paul Sokolovsky2cf38102014-07-12 16:34:51 +030024def run_tests(pyb, tests, args):
Damien George41f768f2014-05-03 16:43:27 +010025 test_count = 0
26 testcase_count = 0
27 passed_count = 0
28 failed_tests = []
Paul Sokolovsky43d4a6f2014-05-10 16:52:58 +030029 skipped_tests = []
Damien39977a52013-12-29 22:34:42 +000030
Chris Angelico047db222014-06-06 07:45:55 +100031 skip_tests = set()
Damien39977a52013-12-29 22:34:42 +000032
Chris Angelico047db222014-06-06 07:45:55 +100033 # Some tests shouldn't be run under Travis CI
34 if os.getenv('TRAVIS') == 'true':
35 skip_tests.add('basics/memoryerror.py')
Damien George23093692014-04-03 22:44:51 +010036
Damien George8594ce22014-09-13 18:43:09 +010037 # Some tests shouldn't be run on pyboard
38 if pyb is not None:
39 skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
40
Damien George612045f2014-09-17 22:56:34 +010041 # Some tests are known to fail on 64-bit machines
42 if pyb is None and platform.architecture()[0] == '64bit':
Damien George96e20c62014-09-23 12:09:26 +000043 pass
Damien George612045f2014-09-17 22:56:34 +010044
stijndc1ea112014-10-04 08:39:15 +020045 # Some tests use unsupported features on Windows
46 if os.name == 'nt':
47 skip_tests.add('extmod\\ujson_loads.py') #works but -2e-3 is printed as -0.002000000000000001 except for mingw-w64
48 skip_tests.add('import\\import_file.py') #works but CPython prints forward slashes
49 skip_tests.add('unix\\ffi_float.py')
50
Damien George15d2fe82014-08-29 19:47:10 +010051 # Some tests are known to fail with native emitter
52 # Remove them from the below when they work
53 if args.emit == 'native':
Damien Georged6230f62014-09-23 14:10:03 +000054 skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class class_super class_super_object closure1 closure2 closure_defargs del_deref del_local fun3 fun_calldblstar fun_callstar fun_callstardblstar fun_defargs fun_defargs2 fun_kwargs fun_kwonly fun_kwonlydef fun_kwvarargs fun_varargs gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send globals_del string_format string_join subclass_native2_list subclass_native2_tuple try2 try_finally1 try_finally_loops try_finally_return try_reraise try_reraise2 unboundlocal with1 with_break with_continue with_return'.split()})
Damien George15d2fe82014-08-29 19:47:10 +010055 skip_tests.add('float/string_format.py')
56 skip_tests.add('import/gen_context.py')
Damien George15d2fe82014-08-29 19:47:10 +010057 skip_tests.add('io/file_with.py')
58 skip_tests.add('micropython/heapalloc.py')
Damien George15d2fe82014-08-29 19:47:10 +010059 skip_tests.add('misc/features.py')
60 skip_tests.add('misc/recursion.py')
61 skip_tests.add('misc/rge_sm.py')
62
Damien George41f768f2014-05-03 16:43:27 +010063 for test_file in tests:
Chris Angelico88b11b52014-06-06 07:41:30 +100064 test_basename = os.path.basename(test_file)
65 test_name = os.path.splitext(test_basename)[0]
66
Chris Angelico047db222014-06-06 07:45:55 +100067 if test_file in skip_tests:
Damien George41f768f2014-05-03 16:43:27 +010068 print("skip ", test_file)
Paul Sokolovsky43d4a6f2014-05-10 16:52:58 +030069 skipped_tests.append(test_name)
Damien George41f768f2014-05-03 16:43:27 +010070 continue
Andrew Scheller1b997d52014-04-16 03:28:40 +010071
Damien George41f768f2014-05-03 16:43:27 +010072 # get expected output
73 test_file_expected = test_file + '.exp'
74 if os.path.isfile(test_file_expected):
75 # expected output given by a file, so read that in
76 with open(test_file_expected, 'rb') as f:
77 output_expected = f.read()
stijna4dbc732014-05-11 12:45:02 +020078 if os.name == 'nt':
79 output_expected = output_expected.replace(b'\n', b'\r\n')
Damien George41f768f2014-05-03 16:43:27 +010080 else:
stijna4dbc732014-05-11 12:45:02 +020081 # run CPython to work out expected output
Damien George41f768f2014-05-03 16:43:27 +010082 try:
83 output_expected = subprocess.check_output([CPYTHON3, '-B', test_file])
Paul Sokolovsky2cf38102014-07-12 16:34:51 +030084 if args.write_exp:
85 with open(test_file_expected, 'wb') as f:
86 f.write(output_expected)
Damien George41f768f2014-05-03 16:43:27 +010087 except subprocess.CalledProcessError:
88 output_expected = b'CPYTHON3 CRASH'
Damien39977a52013-12-29 22:34:42 +000089
Paul Sokolovsky2cf38102014-07-12 16:34:51 +030090 if args.write_exp:
91 continue
92
Damien George41f768f2014-05-03 16:43:27 +010093 # run Micro Python
94 if pyb is None:
95 # run on PC
96 try:
Damien George15d2fe82014-08-29 19:47:10 +010097 output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=' + args.emit, test_file])
Damien George41f768f2014-05-03 16:43:27 +010098 except subprocess.CalledProcessError:
99 output_mupy = b'CRASH'
100 else:
101 # run on pyboard
102 pyb.enter_raw_repl()
103 try:
104 output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n')
105 except pyboard.PyboardError:
106 output_mupy = b'CRASH'
Damien George4b34c762014-04-03 23:51:16 +0100107
Paul Sokolovsky43d4a6f2014-05-10 16:52:58 +0300108 if output_mupy == b'SKIP\n':
109 print("skip ", test_file)
110 skipped_tests.append(test_name)
111 continue
112
113 testcase_count += len(output_expected.splitlines())
114
Damien George41f768f2014-05-03 16:43:27 +0100115 filename_expected = test_basename + ".exp"
116 filename_mupy = test_basename + ".out"
117
118 if output_expected == output_mupy:
119 print("pass ", test_file)
120 passed_count += 1
121 rm_f(filename_expected)
122 rm_f(filename_mupy)
123 else:
Damien George41736f82014-06-28 10:29:12 +0100124 with open(filename_expected, "wb") as f:
125 f.write(output_expected)
126 with open(filename_mupy, "wb") as f:
127 f.write(output_mupy)
Damien George41f768f2014-05-03 16:43:27 +0100128 print("FAIL ", test_file)
129 failed_tests.append(test_name)
130
131 test_count += 1
132
133 print("{} tests performed ({} individual testcases)".format(test_count, testcase_count))
134 print("{} tests passed".format(passed_count))
135
Paul Sokolovsky43d4a6f2014-05-10 16:52:58 +0300136 if len(skipped_tests) > 0:
137 print("{} tests skipped: {}".format(len(skipped_tests), ' '.join(skipped_tests)))
Damien George41f768f2014-05-03 16:43:27 +0100138 if len(failed_tests) > 0:
139 print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests)))
140 return False
141
142 # all tests succeeded
143 return True
144
145def main():
146 cmd_parser = argparse.ArgumentParser(description='Run tests for Micro Python.')
147 cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard')
blmorris3b064372014-10-01 13:53:50 -0400148 cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device of the pyboard')
Damien Georgea053e372014-05-31 18:11:01 +0100149 cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)')
Paul Sokolovsky2cf38102014-07-12 16:34:51 +0300150 cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython')
Damien George15d2fe82014-08-29 19:47:10 +0100151 cmd_parser.add_argument('--emit', default='bytecode', help='Micro Python emitter to use (bytecode or native)')
Damien George41f768f2014-05-03 16:43:27 +0100152 cmd_parser.add_argument('files', nargs='*', help='input test files')
153 args = cmd_parser.parse_args()
154
155 if args.pyboard:
156 import pyboard
blmorris3b064372014-10-01 13:53:50 -0400157 pyb = pyboard.Pyboard(args.device)
Damien Georgeb636d022014-04-13 13:48:33 +0100158 pyb.enter_raw_repl()
Damien Georgeb636d022014-04-13 13:48:33 +0100159 else:
Damien George41f768f2014-05-03 16:43:27 +0100160 pyb = None
Damien39977a52013-12-29 22:34:42 +0000161
Damien George41f768f2014-05-03 16:43:27 +0100162 if len(args.files) == 0:
stijn8ac3b572014-05-28 14:27:54 +0200163 if args.test_dirs is None:
164 if pyb is None:
165 # run PC tests
Damien George612045f2014-09-17 22:56:34 +0100166 test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode', 'extmod', 'unix')
stijn8ac3b572014-05-28 14:27:54 +0200167 else:
168 # run pyboard tests
Damien George612045f2014-09-17 22:56:34 +0100169 test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod', 'pyb', 'pybnative', 'inlineasm')
Damien George41f768f2014-05-03 16:43:27 +0100170 else:
stijn8ac3b572014-05-28 14:27:54 +0200171 # run tests from these directories
172 test_dirs = args.test_dirs
Damien George41f768f2014-05-03 16:43:27 +0100173 tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files)
Markus Siemens19ccc6b2014-01-27 22:53:28 +0100174 else:
Damien George41f768f2014-05-03 16:43:27 +0100175 # tests explicitly given
176 tests = args.files
Markus Siemens19ccc6b2014-01-27 22:53:28 +0100177
Paul Sokolovsky2cf38102014-07-12 16:34:51 +0300178 if not run_tests(pyb, tests, args):
Damien George41f768f2014-05-03 16:43:27 +0100179 sys.exit(1)
Markus Siemens19ccc6b2014-01-27 22:53:28 +0100180
Damien George41f768f2014-05-03 16:43:27 +0100181if __name__ == "__main__":
182 main()