From 9dd36404646f857c4f250537bac0d9a8ad041d25 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 4 Apr 2015 22:05:30 +0100 Subject: [PATCH] tests: Add missing tests for builtins, and many other things. --- tests/basics/builtin_chr.py | 9 +++++ tests/basics/builtin_compile.py | 25 +++++++++++-- tests/basics/builtin_dir.py | 9 +++++ tests/basics/builtin_divmod.py | 16 ++++++++ tests/basics/builtin_minmax.py | 6 +++ tests/basics/builtin_ord.py | 9 +++++ tests/basics/builtin_pow.py | 11 ++++++ .../{property.py => builtin_property.py} | 26 ++++++++++++- tests/basics/builtin_slice.py | 7 ++++ tests/basics/builtin_sorted.py | 10 +++++ tests/basics/class_descriptor.py | 7 ++++ tests/basics/fun_error.py | 31 ++++++++++++++++ tests/basics/int_big_mul.py | 15 ++++++++ tests/basics/module1.py | 13 +++++++ tests/basics/module2.py | 6 +++ tests/basics/module2.py.exp | 1 + tests/basics/object1.py | 7 ++++ tests/basics/op_error.py | 3 ++ tests/basics/sorted.py | 2 - tests/basics/string1.py | 8 ++-- tests/basics/sys1.py | 21 +++++++++++ tests/cmdline/repl_cont.py | 21 +++++++++++ tests/cmdline/repl_cont.py.exp | 32 ++++++++++++++++ tests/float/builtin_float_round.py | 4 ++ tests/float/complex1.py | 3 ++ tests/float/float1.py | 37 ++++++++++++++++++- tests/float/math_fun.py | 12 ++++-- tests/io/stringio1.py | 1 + tests/io/stringio_with.py | 6 +++ tests/micropython/meminfo.py | 12 ++++++ tests/micropython/meminfo.py.exp | 14 +++++++ tests/micropython/memstats.py | 17 +++++++++ tests/micropython/memstats.py.exp | 3 ++ tests/run-tests | 4 +- tests/unicode/unicode.py | 4 ++ tests/unicode/unicode_chr.py | 5 +++ tests/unicode/unicode_ord.py | 3 ++ 37 files changed, 406 insertions(+), 14 deletions(-) create mode 100644 tests/basics/builtin_chr.py create mode 100644 tests/basics/builtin_dir.py create mode 100644 tests/basics/builtin_divmod.py create mode 100644 tests/basics/builtin_ord.py create mode 100644 tests/basics/builtin_pow.py rename tests/basics/{property.py => builtin_property.py} (64%) create mode 100644 tests/basics/builtin_slice.py create mode 100644 tests/basics/builtin_sorted.py create mode 100644 tests/basics/fun_error.py create mode 100644 tests/basics/module1.py create mode 100644 tests/basics/module2.py create mode 100644 tests/basics/module2.py.exp create mode 100644 tests/basics/object1.py delete mode 100644 tests/basics/sorted.py create mode 100644 tests/basics/sys1.py create mode 100644 tests/cmdline/repl_cont.py create mode 100644 tests/cmdline/repl_cont.py.exp create mode 100644 tests/io/stringio_with.py create mode 100644 tests/micropython/meminfo.py create mode 100644 tests/micropython/meminfo.py.exp create mode 100644 tests/micropython/memstats.py create mode 100644 tests/micropython/memstats.py.exp create mode 100644 tests/unicode/unicode_chr.py create mode 100644 tests/unicode/unicode_ord.py diff --git a/tests/basics/builtin_chr.py b/tests/basics/builtin_chr.py new file mode 100644 index 0000000000..02d783ae66 --- /dev/null +++ b/tests/basics/builtin_chr.py @@ -0,0 +1,9 @@ +# test builtin chr (whether or not we support unicode) + +print(chr(65)) + +try: + chr(0x110000) +except ValueError: + print("ValueError") + diff --git a/tests/basics/builtin_compile.py b/tests/basics/builtin_compile.py index ef3ff014d4..32c6667d8b 100644 --- a/tests/basics/builtin_compile.py +++ b/tests/basics/builtin_compile.py @@ -7,10 +7,9 @@ def have_compile(): except NameError: return False -# global variable for compiled code to access -x = 1 - def test(): + global x + c = compile("print(x)", "file", "exec") try: @@ -18,11 +17,31 @@ def test(): except NameError: print("NameError") + # global variable for compiled code to access + x = 1 + exec(c) exec(c, {"x":2}) exec(c, {}, {"x":3}) + # single/eval mode + exec(compile('print(1 + 1)', 'file', 'single')) + print(eval(compile('1 + 1', 'file', 'eval'))) + + # bad mode + try: + compile('1', 'file', '') + except ValueError: + print("ValueError") + + # exception within compiled code + try: + exec(compile('noexist', 'file', 'exec')) + except NameError: + print("NameError") + print(x) # check 'x' still exists as a global + if have_compile(): test() else: diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py new file mode 100644 index 0000000000..c7064c8cab --- /dev/null +++ b/tests/basics/builtin_dir.py @@ -0,0 +1,9 @@ +# test builtin dir + +# dir of locals +print('__name__' in dir()) + +# dir of module +import sys +print('platform' in dir(sys)) + diff --git a/tests/basics/builtin_divmod.py b/tests/basics/builtin_divmod.py new file mode 100644 index 0000000000..f159691b7b --- /dev/null +++ b/tests/basics/builtin_divmod.py @@ -0,0 +1,16 @@ +# test builtin divmod + +print(divmod(0, 2)) +print(divmod(3, 4)) +print(divmod(20, 3)) + +try: + divmod(1, 0) +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + divmod('a', 'b') +except TypeError: + print("TypeError") + diff --git a/tests/basics/builtin_minmax.py b/tests/basics/builtin_minmax.py index a5f035b909..e2bb0ed7b0 100644 --- a/tests/basics/builtin_minmax.py +++ b/tests/basics/builtin_minmax.py @@ -23,3 +23,9 @@ print(max(lst, key=lambda x:x)) print(max(lst, key=lambda x:-x)) print(max(1, 2, 3, 4, key=lambda x:-x)) print(max(4, 3, 2, 1, key=lambda x:-x)) + +# need at least 1 item in the iterable +try: + min([]) +except ValueError: + print("ValueError") diff --git a/tests/basics/builtin_ord.py b/tests/basics/builtin_ord.py new file mode 100644 index 0000000000..6347aa4ec0 --- /dev/null +++ b/tests/basics/builtin_ord.py @@ -0,0 +1,9 @@ +# test builtin ord (whether or not we support unicode) + +print(ord('a')) + +try: + ord('') +except TypeError: + print("TypeError") + diff --git a/tests/basics/builtin_pow.py b/tests/basics/builtin_pow.py new file mode 100644 index 0000000000..a19ab8c843 --- /dev/null +++ b/tests/basics/builtin_pow.py @@ -0,0 +1,11 @@ +# test builtin pow() with integral values + +# 2 arg version +print(pow(0, 1)) +print(pow(1, 0)) +print(pow(-2, 3)) +print(pow(3, 8)) + +# 3 arg version +print(pow(3, 4, 7)) + diff --git a/tests/basics/property.py b/tests/basics/builtin_property.py similarity index 64% rename from tests/basics/property.py rename to tests/basics/builtin_property.py index 7f3c833ad3..4df9842a3e 100644 --- a/tests/basics/property.py +++ b/tests/basics/builtin_property.py @@ -1,3 +1,16 @@ +# test builtin property + +# create a property object explicitly +property() +property(1, 2, 3) + +# use its accessor methods +p = property() +p.getter(1) +p.setter(2) +p.deleter(3) + +# basic use as a decorator class A: def __init__(self, x): self._x = x @@ -15,6 +28,7 @@ try: except AttributeError: print("AttributeError") +# explicit use within a class class B: def __init__(self, x): self._x = x @@ -27,13 +41,18 @@ class B: print("x set") self._x = value - x = property(xget, xset) + def xdel(self): + print("x del") + + x = property(xget, xset, xdel) b = B(3) print(b.x) b.x = 4 print(b.x) +del b.x +# full use as a decorator class C: def __init__(self, x): self._x = x @@ -48,7 +67,12 @@ class C: print("x set") self._x = value + @x.deleter + def x(self): + print("x del") + c = C(5) print(c.x) c.x = 6 print(c.x) +del c.x diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py new file mode 100644 index 0000000000..4da1229fa0 --- /dev/null +++ b/tests/basics/builtin_slice.py @@ -0,0 +1,7 @@ +# test builtin slice + +# print slice +class A: + def __getitem__(self, idx): + print(idx) +A()[1:2:3] diff --git a/tests/basics/builtin_sorted.py b/tests/basics/builtin_sorted.py new file mode 100644 index 0000000000..a4f71a15eb --- /dev/null +++ b/tests/basics/builtin_sorted.py @@ -0,0 +1,10 @@ +# test builtin sorted + +print(sorted(set(range(100)))) +print(sorted(set(range(100)), key=lambda x: x + 100*(x % 2))) + +# need to use keyword argument +try: + sorted([], None) +except TypeError: + print("TypeError") diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index 27907411db..25b373e47e 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -1,13 +1,19 @@ class Descriptor: def __get__(self, obj, cls): + print('get') print(type(obj) is Main) print(cls is Main) return 'result' def __set__(self, obj, val): + print('set') print(type(obj) is Main) print(val) + def __delete__(self, obj): + print('delete') + print(type(obj) is Main) + class Main: Forward = Descriptor() @@ -18,4 +24,5 @@ if 'Descriptor' in repr(r.__class__): else: print(r) m.Forward = 'a' + del m.Forward diff --git a/tests/basics/fun_error.py b/tests/basics/fun_error.py new file mode 100644 index 0000000000..02af7b1bba --- /dev/null +++ b/tests/basics/fun_error.py @@ -0,0 +1,31 @@ +# test errors from bad function calls + +def test_exc(code, exc): + try: + exec(code) + print("no exception") + except exc: + print("right exception") + except: + print("wrong exception") + +# function doesn't take keyword args +test_exc("[].append(x=1)", TypeError) + +# function with variable number of positional args given too few +test_exc("round()", TypeError) + +# function with variable number of positional args given too many +test_exc("round(1, 2, 3)", TypeError) + +# function with fixed number of positional args given wrong number +test_exc("[].append(1, 2)", TypeError) + +# function with keyword args given extra positional args +test_exc("[].sort(1)", TypeError) + +# function with keyword args given extra keyword args +test_exc("[].sort(noexist=1)", TypeError) + +# function with keyword args not given a specific keyword arg +test_exc("enumerate()", TypeError) diff --git a/tests/basics/int_big_mul.py b/tests/basics/int_big_mul.py index f8d3dcd800..6010075c4e 100644 --- a/tests/basics/int_big_mul.py +++ b/tests/basics/int_big_mul.py @@ -6,3 +6,18 @@ for rhs in range(2, 11): print(lhs, '*', rhs, '=', res) lhs = res +# below tests pos/neg combinations that overflow small int + +# 31-bit overflow +i = 1 << 20 +print(i * i) +print(i * -i) +print(-i * i) +print(-i * -i) + +# 63-bit overflow +i = 1 << 40 +print(i * i) +print(i * -i) +print(-i * i) +print(-i * -i) diff --git a/tests/basics/module1.py b/tests/basics/module1.py new file mode 100644 index 0000000000..c158af52e2 --- /dev/null +++ b/tests/basics/module1.py @@ -0,0 +1,13 @@ +# test behaviour of module objects + +# this module should always exist +import __main__ + +# print module +print(repr(__main__).startswith(" '2') +print('1' + '2' < '2') -# Not implemented so far -# print('1' + '2' > '2') -# print('1' + '2' < '2') +# printing quote char in string +print(repr('\'\"')) diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py new file mode 100644 index 0000000000..fa81e14ecd --- /dev/null +++ b/tests/basics/sys1.py @@ -0,0 +1,21 @@ +# test sys module + +import sys + +print(sys.__name__) +print(type(sys.path)) +print(type(sys.argv)) +print(sys.version[:3]) +print(sys.version_info[0], sys.version_info[1]) +print(sys.byteorder in ('little', 'big')) +print(sys.maxsize > 100) + +try: + sys.exit() +except SystemExit as e: + print("SystemExit", e.args) + +try: + sys.exit(42) +except SystemExit as e: + print("SystemExit", e.args) diff --git a/tests/cmdline/repl_cont.py b/tests/cmdline/repl_cont.py new file mode 100644 index 0000000000..66a484ce3d --- /dev/null +++ b/tests/cmdline/repl_cont.py @@ -0,0 +1,21 @@ +# check REPL allows to continue input +1 \ ++ 2 +'abc' +"abc" +'''abc +def''' +"""ABC +DEF""" +print( +1 + 2) +l = [1, +2] +print(l) +d = {1:'one', +2:'two'} +print(d[2]) +def f(x): + print(x) + +f(3) diff --git a/tests/cmdline/repl_cont.py.exp b/tests/cmdline/repl_cont.py.exp new file mode 100644 index 0000000000..2405e601cb --- /dev/null +++ b/tests/cmdline/repl_cont.py.exp @@ -0,0 +1,32 @@ +Micro Python \.\+ linux version +>>> # check REPL allows to continue input +>>> 1 \ +... + 2 +3 +>>> 'abc' +'abc' +>>> "abc" +'abc' +>>> '''abc +... def''' +'abc\ndef' +>>> """ABC +... DEF""" +'ABC\nDEF' +>>> print( +... 1 + 2) +3 +>>> l = [1, +... 2] +>>> print(l) +[1, 2] +>>> d = {1:'one', +... 2:'two'} +>>> print(d[2]) +two +>>> def f(x): +... print(x) +... +>>> f(3) +3 +>>> diff --git a/tests/float/builtin_float_round.py b/tests/float/builtin_float_round.py index afde6ff16c..6759d0fd5a 100644 --- a/tests/float/builtin_float_round.py +++ b/tests/float/builtin_float_round.py @@ -10,3 +10,7 @@ for t in tests: # check .5 cases for i in range(11): print(round((i - 5) / 2)) + +# test second arg +# TODO uPy currently only supports second arg being 0 +print(round(1.4, 0)) diff --git a/tests/float/complex1.py b/tests/float/complex1.py index eafa53746a..2fb95c6908 100644 --- a/tests/float/complex1.py +++ b/tests/float/complex1.py @@ -33,6 +33,9 @@ ans = 1j ** 2.5j; print("%.5g %.5g" % (ans.real, ans.imag)) print(abs(1j)) print("%.5g" % abs(1j + 2)) +# float on lhs should delegate to complex +print(1.2 + 3j) + # convert bignum to complex on rhs ans = 1j + (1 << 70); print("%.5g %.5g" % (ans.real, ans.imag)) diff --git a/tests/float/float1.py b/tests/float/float1.py index 9e4bb85cd1..2539d89dc3 100644 --- a/tests/float/float1.py +++ b/tests/float/float1.py @@ -1,4 +1,15 @@ -# basic float +# test basic float capabilities + +# float construction +print(float(1.2)) + +# unary operators +print(bool(0.0)) +print(bool(1.2)) +print(+(1.2)) +print(-(1.2)) + +# division of integers x = 1 / 2 print(x) @@ -7,9 +18,16 @@ a = 1 a /= 2 print(a) +# floor division print(1.0 // 2) print(2.0 // 2) +# comparison +print(1.2 <= 3.4) +print(1.2 <= -3.4) +print(1.2 >= 3.4) +print(1.2 >= -3.4) + try: 1.0 / 0 except ZeroDivisionError: @@ -20,6 +38,23 @@ try: except ZeroDivisionError: print("ZeroDivisionError") +try: + 1.2 % 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +# unsupported unary ops + +try: + ~1.2 +except TypeError: + print("TypeError") + +try: + 1.2 in 3.4 +except TypeError: + print("TypeError") + # can't convert list to float try: float([]) diff --git a/tests/float/math_fun.py b/tests/float/math_fun.py index 03ee8e85d2..16aec76f92 100644 --- a/tests/float/math_fun.py +++ b/tests/float/math_fun.py @@ -33,7 +33,9 @@ functions = [('sqrt', sqrt, p_test_values), ('ceil', ceil, test_values), ('fabs', fabs, test_values), ('floor', floor, test_values), - ('trunc', trunc, test_values) + ('trunc', trunc, test_values), + ('radians', radians, test_values), + ('degrees', degrees, test_values), ] for function_name, function, test_vals in functions: @@ -52,10 +54,14 @@ for function_name, function, test_vals in tuple_functions: print("{:.5g} {:.5g}".format(x, y)) binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.), - (-23., -42.), (1., 0.0), (1., -0.0)]) + (-23., -42.), (1., 0.0), (1., -0.0)]), + ('pow', pow, ((1., 0.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)), + ('atan2', atan2, ((1., 0.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)), + ('fmod', fmod, ((1., 1.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)), + ('ldexp', ldexp, ((1., 0), (0., 1), (2., 2), (3., -2), (-3., -4),)), ] for function_name, function, test_vals in binary_functions: print(function_name) for value1, value2 in test_vals: - print("{:.7g}".format(function(value1, value2))) + print("{:.5g}".format(function(value1, value2))) diff --git a/tests/io/stringio1.py b/tests/io/stringio1.py index dae0187f88..22f561f299 100644 --- a/tests/io/stringio1.py +++ b/tests/io/stringio1.py @@ -1,6 +1,7 @@ import _io as io a = io.StringIO() +print('io.StringIO' in repr(a)) print(a.getvalue()) print(a.read()) diff --git a/tests/io/stringio_with.py b/tests/io/stringio_with.py new file mode 100644 index 0000000000..becb564dfd --- /dev/null +++ b/tests/io/stringio_with.py @@ -0,0 +1,6 @@ +import _io as io + +# test __enter__/__exit__ +with io.StringIO() as b: + b.write("foo") + print(b.getvalue()) diff --git a/tests/micropython/meminfo.py b/tests/micropython/meminfo.py new file mode 100644 index 0000000000..698bbbd21c --- /dev/null +++ b/tests/micropython/meminfo.py @@ -0,0 +1,12 @@ +# tests meminfo functions in micropython module + +import micropython + +# these functions are not always available +if not hasattr(micropython, 'mem_info'): + print('SKIP') +else: + micropython.mem_info() + micropython.mem_info(1) + micropython.qstr_info() + micropython.qstr_info(1) diff --git a/tests/micropython/meminfo.py.exp b/tests/micropython/meminfo.py.exp new file mode 100644 index 0000000000..31a97c3e43 --- /dev/null +++ b/tests/micropython/meminfo.py.exp @@ -0,0 +1,14 @@ +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+ +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+ +GC memory layout; from 0x\[0-9a-f\]\+: +######## +qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+ +qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+ +######## +Q(SKIP) diff --git a/tests/micropython/memstats.py b/tests/micropython/memstats.py new file mode 100644 index 0000000000..78e4d24736 --- /dev/null +++ b/tests/micropython/memstats.py @@ -0,0 +1,17 @@ +# tests meminfo functions in micropython module + +import micropython + +# these functions are not always available +if not hasattr(micropython, 'mem_total'): + print('SKIP') +else: + t = micropython.mem_total() + c = micropython.mem_current() + p = micropython.mem_peak() + + l = list(range(10000)) + + print(micropython.mem_total() > t) + print(micropython.mem_current() > c) + print(micropython.mem_peak() > p) diff --git a/tests/micropython/memstats.py.exp b/tests/micropython/memstats.py.exp new file mode 100644 index 0000000000..b8ca7e7ef0 --- /dev/null +++ b/tests/micropython/memstats.py.exp @@ -0,0 +1,3 @@ +True +True +True diff --git a/tests/run-tests b/tests/run-tests index 385c4e696d..03f149b9eb 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -29,7 +29,7 @@ def rm_f(fname): def run_micropython(pyb, args, test_file): if pyb is None: # run on PC - if test_file.startswith('cmdline/'): + if test_file.startswith('cmdline/') or test_file == 'micropython/meminfo.py': # special handling for tests of the unix cmdline program # check for any cmdline options needed for this test @@ -141,6 +141,7 @@ def run_tests(pyb, tests, args): if pyb is not None: skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead skip_tests.add('float/float2int_doubleprec.py') # requires double precision floating point to work + skip_tests.add('micropython/meminfo.py') # output is very different to PC output # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == '64bit': @@ -162,6 +163,7 @@ def run_tests(pyb, tests, args): skip_tests.add('float/cmath_fun.py') # requires f(*args) support skip_tests.add('import/gen_context.py') skip_tests.add('io/file_with.py') + skip_tests.add('io/stringio_with.py') skip_tests.add('micropython/heapalloc.py') skip_tests.add('misc/features.py') skip_tests.add('misc/recursion.py') diff --git a/tests/unicode/unicode.py b/tests/unicode/unicode.py index c7e523f06a..57075f7e3e 100644 --- a/tests/unicode/unicode.py +++ b/tests/unicode/unicode.py @@ -16,3 +16,7 @@ for i in range(-len(s), len(s)): # Test UTF-8 encode and decode enc = s.encode() print(enc, enc.decode() == s) + +# printing of unicode chars using repr +# TODO we don't do this correctly +#print(repr(s)) diff --git a/tests/unicode/unicode_chr.py b/tests/unicode/unicode_chr.py new file mode 100644 index 0000000000..248eb5892f --- /dev/null +++ b/tests/unicode/unicode_chr.py @@ -0,0 +1,5 @@ +# test builtin chr with unicode characters + +print(chr(945)) +print(chr(0x800)) +print(chr(0x10000)) diff --git a/tests/unicode/unicode_ord.py b/tests/unicode/unicode_ord.py new file mode 100644 index 0000000000..47cfa1c2d7 --- /dev/null +++ b/tests/unicode/unicode_ord.py @@ -0,0 +1,3 @@ +# test builtin ord with unicode characters + +print(ord('α'))