mirror of
https://github.com/micropython/micropython.git
synced 2025-07-21 21:11:12 +02:00
Some tests are just too big for targets that don't have much heap memory, eg `tests/extmod/vfs_rom.py`. Other tests are too large because the target doesn't have enough IRAM for native code, eg esp8266 running `tests/micropython/viper_args.py`. Previously, such tests were explicitly skipped on targets known to have little memory, eg esp8266. But this doesn't scale to multiple targets, nor to more and more tests which are too large. This commit addresses that by adding logic to the test runner so it can automatically skip tests when they don't fit in the target's memory. It does this by prepending a `print('START TEST')` to every test, and if a `MemoryError` occurs before that line is printed then the test was too big. This works for standard tests, tests that go via .mpy files, and tests that run in native emitter mode via .mpy files. For tests that are too big, it prints `lrge <test name>` on the output, and at the end prints them on a separate line of skipped tests so they can be distinguished. They are also distinguished in the `_result.json` file as a skipped test with reason "too large". Signed-off-by: Damien George <damien@micropython.org>
100 lines
2.2 KiB
Python
100 lines
2.2 KiB
Python
# Test sys.print_exception (MicroPython) / traceback.print_exception (CPython).
|
|
|
|
try:
|
|
import io
|
|
import sys
|
|
except ImportError:
|
|
print("SKIP")
|
|
raise SystemExit
|
|
|
|
if hasattr(sys, "print_exception"):
|
|
print_exception = sys.print_exception
|
|
else:
|
|
import traceback
|
|
|
|
print_exception = lambda e, f: traceback.print_exception(None, e, sys.exc_info()[2], file=f)
|
|
|
|
|
|
def print_exc(e):
|
|
buf = io.StringIO()
|
|
print_exception(e, buf)
|
|
s = buf.getvalue()
|
|
for l in s.split("\n"):
|
|
# uPy on pyboard prints <stdin> as file, so remove filename.
|
|
if l.startswith(" File "):
|
|
l = l.split('"')
|
|
print(l[0], l[2])
|
|
# uPy and CPy tracebacks differ in that CPy prints a source line for
|
|
# each traceback entry. In this case, we know that offending line
|
|
# has 4-space indent, so filter it out.
|
|
elif not l.startswith(" "):
|
|
print(l)
|
|
|
|
|
|
# basic exception message
|
|
try:
|
|
raise Exception("msg")
|
|
except Exception as e:
|
|
print("caught")
|
|
print_exc(e)
|
|
|
|
|
|
# exception message with more than 1 source-code line
|
|
def f():
|
|
g()
|
|
|
|
|
|
def g():
|
|
raise Exception("fail")
|
|
|
|
|
|
try:
|
|
f()
|
|
except Exception as e:
|
|
print("caught")
|
|
print_exc(e)
|
|
|
|
# Test that an exception propagated through a finally doesn't have a traceback added there
|
|
try:
|
|
try:
|
|
f()
|
|
finally:
|
|
print("finally")
|
|
except Exception as e:
|
|
print("caught")
|
|
print_exc(e)
|
|
|
|
# Test that re-raising an exception doesn't add traceback info
|
|
try:
|
|
try:
|
|
f()
|
|
except Exception as e:
|
|
print("reraise")
|
|
print_exc(e)
|
|
raise
|
|
except Exception as e:
|
|
print("caught")
|
|
print_exc(e)
|
|
|
|
|
|
# Here we have a function with lots of bytecode generated for a single source-line, and
|
|
# there is an error right at the end of the bytecode. It should report the correct line.
|
|
def f():
|
|
f([1, 2], [1, 2], [1, 2], {1: 1, 1: 1, 1: 1, 1: 1, 1: 1, 1: 1, 1: f.X})
|
|
return 1
|
|
|
|
|
|
try:
|
|
f()
|
|
except Exception as e:
|
|
print_exc(e)
|
|
|
|
# Test non-stream object passed as output object, only valid for uPy
|
|
if hasattr(sys, "print_exception"):
|
|
try:
|
|
sys.print_exception(Exception, 1)
|
|
had_exception = False
|
|
except OSError:
|
|
had_exception = True
|
|
assert had_exception
|