summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Kerr <skerr@aggies.ncat.edu>2020-12-16 10:25:20 -0500
committerSeth Kerr <skerr@aggies.ncat.edu>2020-12-16 10:25:20 -0500
commitca757f2ead6e84ad52b6030281b666792fb12b43 (patch)
treee6669e7242beaa050aca96d62faa021cb5c6d446
parentc16b8f1ee5eb4cea1131ba7db4938c65fb1045d0 (diff)
removed comments on 64MiB SPI flash causing build test issues
-rw-r--r--.gitattributes 232
-rw-r--r--.gitignore 288
-rw-r--r--.gitmodules 2155
-rw-r--r--.mailmap 2112
-rw-r--r--mpy-cross/.gitignore 211
-rw-r--r--ports/atmel-samd/.gitattributes 22
-rw-r--r--ports/atmel-samd/.gitignore 21
-rw-r--r--ports/atmel-samd/boards/board.h47
-rw-r--r--supervisor/shared/external_flash/devices.h50
-rw-r--r--tests/README 218
-rw-r--r--tests/extmod 2/btree1.py89
-rw-r--r--tests/extmod 2/framebuf1.py109
-rw-r--r--tests/extmod 2/framebuf16.py59
-rw-r--r--tests/extmod 2/framebuf2.py.exp57
-rw-r--r--tests/extmod 2/framebuf4.py53
-rw-r--r--tests/extmod 2/framebuf_subclass.py20
-rw-r--r--tests/extmod 2/machine1.py28
-rw-r--r--tests/extmod 2/machine_pinbase.py30
-rw-r--r--tests/extmod 2/machine_pinbase.py.exp9
-rw-r--r--tests/extmod 2/ticks_diff.py33
-rw-r--r--tests/extmod 2/time_ms_us.py22
-rw-r--r--tests/extmod 2/time_ms_us.py.exp3
-rw-r--r--tests/extmod 2/ubinascii_a2b_base64.py49
-rw-r--r--tests/extmod 2/ubinascii_hexlify.py17
-rw-r--r--tests/extmod 2/uctypes_32bit_intbig.py.exp11
-rw-r--r--tests/extmod 2/uctypes_array_assign_native_le.py89
-rw-r--r--tests/extmod 2/uctypes_array_assign_native_le.py.exp11
-rw-r--r--tests/extmod 2/uctypes_array_assign_native_le_intbig.py43
-rw-r--r--tests/extmod 2/uctypes_bytearray.py22
-rw-r--r--tests/extmod 2/uctypes_byteat.py10
-rw-r--r--tests/extmod 2/uctypes_byteat.py.exp2
-rw-r--r--tests/extmod 2/uctypes_error.py37
-rw-r--r--tests/extmod 2/uctypes_error.py.exp4
-rw-r--r--tests/extmod 2/uctypes_le_float.py24
-rw-r--r--tests/extmod 2/uctypes_native_float.py20
-rw-r--r--tests/extmod 2/uctypes_ptr_le.py34
-rw-r--r--tests/extmod 2/uctypes_ptr_native_le.py.exp6
-rw-r--r--tests/extmod 2/uctypes_sizeof.py.exp7
-rw-r--r--tests/extmod 2/uhashlib_sha1.py28
-rw-r--r--tests/extmod 2/ujson_dump.py30
-rw-r--r--tests/extmod 2/ujson_dumps_extra.py9
-rw-r--r--tests/extmod 2/ujson_dumps_float.py10
-rw-r--r--tests/extmod 2/ujson_load_readinto.py.exp4
-rw-r--r--tests/extmod 2/ujson_loads.py74
-rw-r--r--tests/extmod 2/ujson_loads_float.py17
-rw-r--r--tests/extmod 2/urandom_basic.py29
-rw-r--r--tests/extmod 2/ure1.py103
-rw-r--r--tests/extmod 2/ure_debug.py.exp15
-rw-r--r--tests/extmod 2/ure_error.py25
-rw-r--r--tests/extmod 2/ure_namedclass.py32
-rw-r--r--tests/extmod 2/ure_stack_overflow.py.exp1
-rw-r--r--tests/extmod 2/ure_sub_unmatched.py.exp1
-rw-r--r--tests/extmod 2/ussl_basic.py59
-rw-r--r--tests/extmod 2/utimeq1.py137
-rw-r--r--tests/extmod 2/utimeq_stable.py.exp1
-rw-r--r--tests/extmod 2/uzlib_decompio.py33
-rw-r--r--tests/extmod 2/uzlib_decompio_gz.py.exp13
-rw-r--r--tests/extmod 2/vfs_fat_fileio1.py139
-rw-r--r--tests/extmod 2/vfs_fat_fileio1.py.exp18
-rw-r--r--tests/extmod 2/vfs_fat_more.py.exp29
-rw-r--r--tests/extmod 2/vfs_fat_oldproto.py.exp3
-rw-r--r--tests/extmod 2/vfs_fat_ramdisk.py.exp17
-rw-r--r--tests/extmod 2/websocket_basic.py.exp14
-rw-r--r--tests/feature_check 2/README4
-rw-r--r--tests/feature_check 2/async_check.py3
-rw-r--r--tests/feature_check 2/async_check.py.exp0
-rw-r--r--tests/feature_check 2/byteorder.py2
-rw-r--r--tests/feature_check 2/byteorder.py.exp0
-rw-r--r--tests/feature_check 2/complex.py5
-rw-r--r--tests/feature_check 2/complex.py.exp0
-rw-r--r--tests/feature_check 2/const.py1
-rw-r--r--tests/feature_check 2/const.py.exp0
-rw-r--r--tests/feature_check 2/coverage.py5
-rw-r--r--tests/feature_check 2/coverage.py.exp0
-rw-r--r--tests/feature_check 2/float.py13
-rw-r--r--tests/feature_check 2/float.py.exp1
-rw-r--r--tests/feature_check 2/int_big.py2
-rw-r--r--tests/feature_check 2/int_big.py.exp1
-rw-r--r--tests/feature_check 2/native_check.py4
-rw-r--r--tests/feature_check 2/native_check.py.exp0
-rw-r--r--tests/feature_check 2/repl_emacs_check.py3
-rw-r--r--tests/feature_check 2/repl_emacs_check.py.exp7
-rw-r--r--tests/feature_check 2/reverse_ops.py9
-rw-r--r--tests/feature_check 2/reverse_ops.py.exp0
-rw-r--r--tests/feature_check 2/set_check.py2
-rw-r--r--tests/feature_check 2/set_check.py.exp0
-rw-r--r--tests/float 2/array_construct.py10
-rw-r--r--tests/float 2/builtin_float_hash.py25
-rw-r--r--tests/float 2/builtin_float_minmax.py31
-rw-r--r--tests/float 2/builtin_float_pow.py11
-rw-r--r--tests/float 2/builtin_float_round.py24
-rw-r--r--tests/float 2/builtin_float_round_intbig.py4
-rw-r--r--tests/float 2/bytearray_construct.py9
-rw-r--r--tests/float 2/bytes_construct.py9
-rw-r--r--tests/float 2/cmath_fun.py55
-rw-r--r--tests/float 2/cmath_fun_special.py31
-rw-r--r--tests/float 2/complex1.py116
-rw-r--r--tests/float 2/complex1_intbig.py4
-rw-r--r--tests/float 2/float1.py119
-rw-r--r--tests/float 2/float2int_doubleprec_intbig.py100
-rw-r--r--tests/float 2/float2int_fp30_intbig.py97
-rw-r--r--tests/float 2/float2int_intbig.py99
-rw-r--r--tests/float 2/float_array.py20
-rw-r--r--tests/float 2/float_compare.py22
-rw-r--r--tests/float 2/float_divmod.py25
-rw-r--r--tests/float 2/float_divmod_relaxed.py33
-rw-r--r--tests/float 2/float_format.py19
-rw-r--r--tests/float 2/float_parse.py32
-rw-r--r--tests/float 2/float_parse_doubleprec.py21
-rw-r--r--tests/float 2/float_struct.py17
-rw-r--r--tests/float 2/int_big_float.py28
-rw-r--r--tests/float 2/int_divzero.py9
-rw-r--r--tests/float 2/int_power.py8
-rw-r--r--tests/float 2/list_index.py8
-rw-r--r--tests/float 2/math_domain.py51
-rw-r--r--tests/float 2/math_domain_special.py36
-rw-r--r--tests/float 2/math_fun.py63
-rw-r--r--tests/float 2/math_fun_bool.py16
-rw-r--r--tests/float 2/math_fun_int.py14
-rw-r--r--tests/float 2/math_fun_intbig.py11
-rw-r--r--tests/float 2/math_fun_special.py35
-rw-r--r--tests/float 2/python36.py10
-rw-r--r--tests/float 2/python36.py.exp5
-rw-r--r--tests/float 2/string_format.py41
-rw-r--r--tests/float 2/string_format2.py106
-rw-r--r--tests/float 2/string_format_fp30.py41
-rw-r--r--tests/float 2/string_format_modulo.py49
-rw-r--r--tests/float 2/string_format_modulo2.py24
-rw-r--r--tests/float 2/string_format_modulo2_intbig.py21
-rw-r--r--tests/float 2/string_format_modulo3.py3
-rw-r--r--tests/float 2/string_format_modulo3.py.exp2
-rw-r--r--tests/float 2/true_value.py7
-rw-r--r--tests/float 2/types.py17
-rw-r--r--tests/inlineasm 2/asmargs.py29
-rw-r--r--tests/inlineasm 2/asmargs.py.exp5
-rw-r--r--tests/inlineasm 2/asmbcc.py27
-rw-r--r--tests/inlineasm 2/asmbcc.py.exp4
-rw-r--r--tests/inlineasm 2/asmbitops.py13
-rw-r--r--tests/inlineasm 2/asmbitops.py.exp4
-rw-r--r--tests/inlineasm 2/asmblbx.py21
-rw-r--r--tests/inlineasm 2/asmblbx.py.exp2
-rw-r--r--tests/inlineasm 2/asmconst.py8
-rw-r--r--tests/inlineasm 2/asmconst.py.exp1
-rw-r--r--tests/inlineasm 2/asmdiv.py16
-rw-r--r--tests/inlineasm 2/asmdiv.py.exp7
-rw-r--r--tests/inlineasm 2/asmfpaddsub.py14
-rw-r--r--tests/inlineasm 2/asmfpaddsub.py.exp1
-rw-r--r--tests/inlineasm 2/asmfpcmp.py14
-rw-r--r--tests/inlineasm 2/asmfpcmp.py.exp3
-rw-r--r--tests/inlineasm 2/asmfpldrstr.py11
-rw-r--r--tests/inlineasm 2/asmfpldrstr.py.exp1
-rw-r--r--tests/inlineasm 2/asmfpmuldiv.py14
-rw-r--r--tests/inlineasm 2/asmfpmuldiv.py.exp1
-rw-r--r--tests/inlineasm 2/asmfpsqrt.py14
-rw-r--r--tests/inlineasm 2/asmfpsqrt.py.exp1
-rw-r--r--tests/inlineasm 2/asmit.py16
-rw-r--r--tests/inlineasm 2/asmit.py.exp2
-rw-r--r--tests/inlineasm 2/asmpushpop.py8
-rw-r--r--tests/inlineasm 2/asmpushpop.py.exp1
-rw-r--r--tests/inlineasm 2/asmrettype.py21
-rw-r--r--tests/inlineasm 2/asmrettype.py.exp4
-rw-r--r--tests/inlineasm 2/asmshift.py29
-rw-r--r--tests/inlineasm 2/asmshift.py.exp6
-rw-r--r--tests/inlineasm 2/asmspecialregs.py10
-rw-r--r--tests/inlineasm 2/asmspecialregs.py.exp2
-rw-r--r--tests/inlineasm 2/asmsum.py57
-rw-r--r--tests/inlineasm 2/asmsum.py.exp2
-rw-r--r--tests/io/data/file1 23
-rw-r--r--tests/jni 2/README11
-rw-r--r--tests/jni 2/list.py15
-rw-r--r--tests/jni 2/list.py.exp4
-rw-r--r--tests/jni 2/object.py15
-rw-r--r--tests/jni 2/object.py.exp3
-rw-r--r--tests/jni 2/system_out.py8
-rw-r--r--tests/jni 2/system_out.py.exp1
-rw-r--r--tests/net_hosted 2/README11
-rw-r--r--tests/net_hosted 2/accept_nonblock.py16
-rw-r--r--tests/net_hosted 2/accept_nonblock.py.exp1
-rw-r--r--tests/net_hosted 2/accept_timeout.py22
-rw-r--r--tests/net_hosted 2/accept_timeout.py.exp1
-rw-r--r--tests/net_hosted 2/connect_nonblock.py20
-rw-r--r--tests/net_hosted 2/connect_nonblock.py.exp1
-rw-r--r--tests/net_hosted 2/connect_poll.py32
-rw-r--r--tests/net_hosted 2/connect_poll.py.exp3
-rw-r--r--tests/net_hosted 2/ssl_getpeercert.py21
-rw-r--r--tests/net_hosted 2/ssl_getpeercert.py.exp1
-rw-r--r--tests/net_inet 2/README5
-rw-r--r--tests/net_inet 2/test_tls_sites.py59
-rw-r--r--tests/net_inet 2/test_tls_sites.py.exp5
-rwxr-xr-xtests/run-bench-tests 297
-rwxr-xr-xtests/run-tests 2615
-rw-r--r--tests/stress 2/dict_copy.py7
-rw-r--r--tests/stress 2/dict_create.py8
-rw-r--r--tests/stress 2/dict_create_max.py13
-rw-r--r--tests/stress 2/gc_trace.py17
-rw-r--r--tests/stress 2/list_sort.py6
-rw-r--r--tests/stress 2/recursion.py7
-rw-r--r--tests/stress 2/recursive_data.py13
-rw-r--r--tests/stress 2/recursive_data.py.exp1
-rw-r--r--tests/stress 2/recursive_gen.py18
-rw-r--r--tests/stress 2/recursive_iternext.py57
-rw-r--r--tests/stress 2/recursive_iternext.py.exp4
-rw-r--r--tests/thread 2/mutate_bytearray.py46
-rw-r--r--tests/thread 2/mutate_dict.py44
-rw-r--r--tests/thread 2/mutate_instance.py45
-rw-r--r--tests/thread 2/mutate_list.py46
-rw-r--r--tests/thread 2/mutate_set.py39
-rw-r--r--tests/thread 2/stress_aes.py257
-rw-r--r--tests/thread 2/stress_create.py22
-rw-r--r--tests/thread 2/stress_heap.py48
-rw-r--r--tests/thread 2/stress_recurse.py27
-rw-r--r--tests/thread 2/thread_exc1.py32
-rw-r--r--tests/thread 2/thread_exc2.py10
-rw-r--r--tests/thread 2/thread_exc2.py.exp5
-rw-r--r--tests/thread 2/thread_exit1.py21
-rw-r--r--tests/thread 2/thread_exit2.py21
-rw-r--r--tests/thread 2/thread_gc1.py36
-rw-r--r--tests/thread 2/thread_ident1.py23
-rw-r--r--tests/thread 2/thread_lock1.py48
-rw-r--r--tests/thread 2/thread_lock2.py26
-rw-r--r--tests/thread 2/thread_lock3.py29
-rw-r--r--tests/thread 2/thread_lock4.py53
-rw-r--r--tests/thread 2/thread_qstr1.py41
-rw-r--r--tests/thread 2/thread_shared1.py33
-rw-r--r--tests/thread 2/thread_shared2.py34
-rw-r--r--tests/thread 2/thread_sleep1.py33
-rw-r--r--tests/thread 2/thread_stacksize1.py49
-rw-r--r--tests/thread 2/thread_start1.py25
-rw-r--r--tests/thread 2/thread_start2.py28
-rw-r--r--tests/unix 2/extra_coverage.py74
-rw-r--r--tests/unix 2/extra_coverage.py.exp106
-rw-r--r--tests/unix 2/ffi_callback.py33
-rw-r--r--tests/unix 2/ffi_callback.py.exp2
-rw-r--r--tests/unix 2/ffi_float.py32
-rw-r--r--tests/unix 2/ffi_float.py.exp8
-rw-r--r--tests/unix 2/ffi_float2.py31
-rw-r--r--tests/unix 2/ffi_float2.py.exp6
-rw-r--r--tools/.gitattributes 21
-rw-r--r--tools/.gitignore 28
239 files changed, 6751 insertions, 16 deletions
diff --git a/.gitattributes 2 b/.gitattributes 2
new file mode 100644
index 000000000..5ebde95f0
--- /dev/null
+++ b/.gitattributes 2
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
+#
+# SPDX-License-Identifier: MIT
+
+# Per default everything gets normalized and gets LF line endings on checkout.
+* text eol=lf
+
+# These will always have CRLF line endings on checkout.
+*.vcxproj text eol=crlf
+*.props text eol=crlf
+*.bat text eol=crlf
+
+# These are binary so should never be modified by git.
+*.png binary
+*.jpg binary
+*.dxf binary
+*.mpy binary
+*.deb binary
+*.zip binary
+*.pdf binary
+
+# These should also not be modified by git.
+tests/basics/string_cr_conversion.py -text
+tests/basics/string_crlf_conversion.py -text
+ports/stm32/pybcdc.inf_template -text
+ports/stm32/usbhost/** -text
+ports/cc3200/hal/aes.c -text
+ports/cc3200/hal/aes.h -text
+ports/cc3200/hal/des.c -text
+ports/cc3200/hal/i2s.c -text
+ports/cc3200/hal/i2s.h -text
+ports/cc3200/version.h -text
diff --git a/.gitignore 2 b/.gitignore 2
new file mode 100644
index 000000000..a8814be45
--- /dev/null
+++ b/.gitignore 2
@@ -0,0 +1,88 @@
+# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
+#
+# SPDX-License-Identifier: MIT
+
+# Compiled Sources
+###################
+*.o
+*.a
+!atmel-samd/asf/**/*.a
+*.elf
+*.bin
+*.map
+*.hex
+*.dis
+*.exe
+
+# Packages
+############
+dist/
+*.egg-info
+.eggs
+
+# Logs and Databases
+######################
+*.log
+
+# VIM Swap Files
+######################
+*.swp
+
+# Build directory
+######################
+build/
+bin/
+circuitpython-stubs/
+
+# Test failure outputs
+######################
+tests/*.exp
+tests/*.out
+
+# Python cache files
+######################
+__pycache__/
+*.pyc
+
+# Customized Makefile/project overrides
+######################
+GNUmakefile
+user.props
+
+# Sphinx output
+###############
+_build
+
+# Generated rst files
+######################
+genrst/
+/autoapi/
+/shared-bindings/*/**/*.rst
+
+# ctags and similar
+###################
+TAGS
+
+# Merge leftovers
+#################
+*.orig
+
+# Emacs backup files
+####################
+*~
+
+*.DS_Store
+**/*.DS_Store
+*.icloud
+
+# POEdit mo files
+####################
+*.mo
+
+.vscode
+.idea
+
+# Python Virtual Environments
+####################
+.venv
+.env
diff --git a/.gitmodules 2 b/.gitmodules 2
new file mode 100644
index 000000000..aaa66caf7
--- /dev/null
+++ b/.gitmodules 2
@@ -0,0 +1,155 @@
+# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
+#
+# SPDX-License-Identifier: MIT
+
+[submodule "lib/axtls"]
+ path = lib/axtls
+ url = https://github.com/pfalcon/axtls
+ branch = micropython
+[submodule "lib/libffi"]
+ path = lib/libffi
+ url = https://github.com/atgreen/libffi
+[submodule "lib/berkeley-db-1.xx"]
+ path = lib/berkeley-db-1.xx
+ url = https://github.com/pfalcon/berkeley-db-1.xx
+[submodule "lib/uzlib"]
+ path = lib/uzlib
+ url = https://github.com/pfalcon/uzlib
+[submodule "tools/uf2"]
+ path = tools/uf2
+ url = https://github.com/Microsoft/uf2.git
+[submodule "atmel-samd/frozen/Adafruit_CircuitPython_NeoPixel"]
+ path = frozen/Adafruit_CircuitPython_NeoPixel
+ url = https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel
+[submodule "frozen/Adafruit_CircuitPython_Thermistor"]
+ path = frozen/Adafruit_CircuitPython_Thermistor
+ url = https://github.com/adafruit/Adafruit_CircuitPython_Thermistor.git
+[submodule "frozen/Adafruit_CircuitPython_LIS3DH"]
+ path = frozen/Adafruit_CircuitPython_LIS3DH
+ url = https://github.com/adafruit/Adafruit_CircuitPython_LIS3DH.git
+[submodule "frozen/Adafruit_CircuitPython_BusDevice"]
+ path = frozen/Adafruit_CircuitPython_BusDevice
+ url = https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git
+[submodule "tools/python-semver"]
+ path = tools/python-semver
+ url = https://github.com/k-bx/python-semver.git
+[submodule "atmel-samd/asf4"]
+ path = ports/atmel-samd/asf4
+ url = https://github.com/adafruit/asf4.git
+ branch = circuitpython
+[submodule "tools/usb_descriptor"]
+ path = tools/usb_descriptor
+ url = https://github.com/adafruit/usb_descriptor.git
+[submodule "lib/nrfutil"]
+ path = lib/nrfutil
+ url = https://github.com/adafruit/nRF52_nrfutil
+[submodule "ports/atmel-samd/freetouch"]
+ path = ports/atmel-samd/freetouch
+ url = https://github.com/adafruit/Adafruit_FreeTouch.git
+[submodule "frozen/Adafruit_CircuitPython_CircuitPlayground"]
+ path = frozen/Adafruit_CircuitPython_CircuitPlayground
+ url = https://github.com/adafruit/Adafruit_CircuitPython_CircuitPlayground.git
+[submodule "frozen/Adafruit_CircuitPython_HID"]
+ path = frozen/Adafruit_CircuitPython_HID
+ url = https://github.com/adafruit/Adafruit_CircuitPython_HID.git
+[submodule "ports/atmel-samd/Adafruit_CircuitPython_Motor"]
+ path = frozen/Adafruit_CircuitPython_Motor
+ url = https://github.com/adafruit/Adafruit_CircuitPython_Motor.git
+[submodule "ports/atmel-samd/Adafruit_CircuitPython_seesaw"]
+ path = frozen/Adafruit_CircuitPython_seesaw
+ url = https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git
+[submodule "frozen/Adafruit_CircuitPython_IRRemote"]
+ path = frozen/Adafruit_CircuitPython_IRRemote
+ url = https://github.com/adafruit/Adafruit_CircuitPython_IRRemote.git
+[submodule "frozen/Adafruit_CircuitPython_DotStar"]
+ path = frozen/Adafruit_CircuitPython_DotStar
+ url = https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git
+[submodule "ports/atmel-samd/peripherals"]
+ path = ports/atmel-samd/peripherals
+ url = https://github.com/adafruit/samd-peripherals.git
+[submodule "frozen/Adafruit_CircuitPython_Crickit"]
+ path = frozen/Adafruit_CircuitPython_Crickit
+ url = https://github.com/adafruit/Adafruit_CircuitPython_Crickit
+[submodule "ports/nrf/nrfx"]
+ path = ports/nrf/nrfx
+ url = https://github.com/adafruit/nrfx.git
+[submodule "lib/tinyusb"]
+ path = lib/tinyusb
+ url = https://github.com/hathach/tinyusb.git
+ branch = master
+ fetchRecurseSubmodules = false
+[submodule "tools/huffman"]
+ path = tools/huffman
+ url = https://github.com/tannewt/huffman.git
+[submodule "tools/adabot"]
+ path = tools/adabot
+ url = https://github.com/adafruit/adabot.git
+[submodule "tools/bitmap_font"]
+ path = tools/bitmap_font
+ url = https://github.com/adafruit/Adafruit_CircuitPython_BitmapFont.git
+[submodule "tools/Tecate-bitmap-fonts"]
+ path = tools/Tecate-bitmap-fonts
+ url = https://github.com/Tecate/bitmap-fonts.git
+[submodule "frozen/pew-pewpew-standalone-10.x"]
+ path = frozen/pew-pewpew-standalone-10.x
+ url = https://github.com/pewpew-game/pew-pewpew-standalone-10.x.git
+[submodule "frozen/circuitpython-stage"]
+ path = frozen/circuitpython-stage
+ url = https://github.com/python-ugame/circuitpython-stage.git
+[submodule "ports/cxd56/spresense-exported-sdk"]
+ path = ports/cxd56/spresense-exported-sdk
+ url = https://github.com/sonydevworld/spresense-exported-sdk.git
+[submodule "frozen/Adafruit_CircuitPython_SD"]
+ path = frozen/Adafruit_CircuitPython_SD
+ url = https://github.com/adafruit/Adafruit_CircuitPython_SD.git
+[submodule "lib/mp3"]
+ path = lib/mp3
+ url = https://github.com/adafruit/Adafruit_MP3
+[submodule "ports/mimxrt10xx/sdk"]
+ path = ports/mimxrt10xx/sdk
+ url = https://github.com/adafruit/MIMXRT10xx_SDK
+[submodule "frozen/Adafruit_CircuitPython_Register"]
+ path = frozen/Adafruit_CircuitPython_Register
+ url = https://github.com/adafruit/Adafruit_CircuitPython_Register.git
+[submodule "extmod/ulab"]
+ path = extmod/ulab
+ url = https://github.com/v923z/micropython-ulab
+[submodule "frozen/Adafruit_CircuitPython_ESP32SPI"]
+ path = frozen/Adafruit_CircuitPython_ESP32SPI
+ url = https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI
+[submodule "frozen/Adafruit_CircuitPython_Requests"]
+ path = frozen/Adafruit_CircuitPython_Requests
+ url = https://github.com/adafruit/Adafruit_CircuitPython_Requests
+[submodule "ports/stm/st_driver"]
+ path = ports/stm/st_driver
+ url = https://github.com/hathach/st_driver.git
+[submodule "lib/protomatter"]
+ path = lib/protomatter
+ url = https://github.com/adafruit/Adafruit_Protomatter
+[submodule "frozen/Adafruit_CircuitPython_LSM6DS"]
+ path = frozen/Adafruit_CircuitPython_LSM6DS
+ url = https://github.com/adafruit/Adafruit_CircuitPython_LSM6DS
+[submodule "frozen/Adafruit_CircuitPython_FocalTouch"]
+ path = frozen/Adafruit_CircuitPython_FocalTouch
+ url = https://github.com/adafruit/Adafruit_CircuitPython_FocalTouch
+[submodule "frozen/Adafruit_CircuitPython_DS3231"]
+ path = frozen/Adafruit_CircuitPython_DS3231
+ url = https://github.com/adafruit/Adafruit_CircuitPython_DS3231
+[submodule "frozen/Adafruit_CircuitPython_DRV2605"]
+ path = frozen/Adafruit_CircuitPython_DRV2605
+ url = https://github.com/adafruit/Adafruit_CircuitPython_DRV2605
+[submodule "frozen/Adafruit_CircuitPython_BLE"]
+ path = frozen/Adafruit_CircuitPython_BLE
+ url = https://github.com/adafruit/Adafruit_CircuitPython_BLE
+[submodule "frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center"]
+ path = frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center
+ url = https://github.com/adafruit/Adafruit_CircuitPython_BLE_Apple_Notification_Center
+[submodule "frozen/Adafruit_CircuitPython_RFM9x"]
+ path = frozen/Adafruit_CircuitPython_RFM9x
+ url = https://github.com/adafruit/Adafruit_CircuitPython_RFM9x.git
+[submodule "frozen/Adafruit_CircuitPython_RFM69"]
+ path = frozen/Adafruit_CircuitPython_RFM69
+ url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git
+[submodule "ports/esp32s2/esp-idf"]
+ path = ports/esp32s2/esp-idf
+ url = https://github.com/jepler/esp-idf.git
diff --git a/.mailmap 2 b/.mailmap 2
new file mode 100644
index 000000000..f9d7f47a1
--- /dev/null
+++ b/.mailmap 2
@@ -0,0 +1,112 @@
+# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
+#
+# SPDX-License-Identifier: Unlicense
+
+Alexander Steffen <devel.20.webmeister@spamgourmet.com>
+Alexander Steffen <devel.20.webmeister@spamgourmet.com> <Alexander.Steffen@infineon.com>
+Alexander Steffen <devel.20.webmeister@spamgourmet.com> <webmeister@users.noreply.github.com>
+Benjamin Vernoux <bvernoux@gmail.com>
+Brent Rubell <robots199@me.com>
+Brent Rubell <robots199@me.com> <brent@xn.home>
+Brent Rubell <robots199@me.com> <brentru@users.noreply.github.com>
+Carlos <carlos.santiago.diaz@gmail.com>
+Chris Packham <judge.packham@gmail.com>
+Chris Packham <judge.packham@gmail.com> <chris.packham@alliedtelesis.co.nz>
+Damiano Mazzella <damianomazzella@gmail.com>
+Damien George <damien.p.george@gmail.com>
+Dan Halbert <halbert@adafruit.com>
+Dan Halbert <halbert@adafruit.com> <halbert@halwitz.org>
+Daniel Pollard <daniel@learnweaver.com>
+Daniel Pollard <daniel@learnweaver.com> <daniel.pollard@learnweaver.com>
+Daniel Tralamazza <daniel@tralamazza.com>
+Daniel Tralamazza <daniel@tralamazza.com> <tralamazza@users.noreply.github.com>
+David Glaude <david.glaude@gmail.com>
+David Glaude <david.glaude@gmail.com> <dglaude@users.noreply.github.com>
+George Waters <gwatersdev@gmail.com>
+George Waters <gwatersdev@gmail.com> <george@georgeh2os.com>
+Ha Thach <thach@tinyusb.org>
+Henrik Sölver <henrik.solver@gmail.com>
+Ilya Dmitrichenko <errordeveloper@gmail.com>
+Ilya Dmitrichenko <errordeveloper@gmail.com> <ilya@xively.com>
+Jason Pecor <14111408+jpecor@users.noreply.github.com>
+Jeff Epler <jepler@gmail.com>
+Jeff Epler <jepler@gmail.com> <jeff@adafruit.com>
+Jeff Epler <jepler@gmail.com> <jepler@de11.u>
+Jeff Epler <jepler@gmail.com> <jepler@unpythonic.net>
+Jerry Needell <jerryneedell@gmail.com>
+Joe Bakalor <jmbakalor@gmail.com>
+Josh Klar <josh@klar.sh>
+Josh Klar <josh@klar.sh> <j@iv597.com>
+Juan Biondi <juanernestobiondi@gmail.com>
+Juan Biondi <juanernestobiondi@gmail.com> <juanernestobiondi@hotmail.com>
+KalbeAbbas <kalbeabbas142@gmail.com>
+KalbeAbbas <kalbeabbas142@gmail.com> <kalbeabbas@142@gmail.com>
+Kamil Tomaszewski <kamil.tomaszewski@sony.com>
+Kamil Tomaszewski <kamil.tomaszewski@sony.com> <46525824+kamtom480@users.noreply.github.com>
+Kattni <kattni@adafruit.com> <kattni@kittyfish.org>
+Kattni Rembor <kattni@adafruit.com>
+Kenny <WarriorOfWire@users.noreply.github.com>
+Kenny <WarriorOfWire@users.noreply.github.com> <3454741+WarriorOfWire@users.noreply.github.com>
+Kevin Townsend <contact@microbuilder.eu>
+Kevin Townsend <contact@microbuilder.eu> <microbuilder@users.noreply.github.com>
+Krzysztof Blazewicz <blazewicz.krzysztof@gmail.com>
+Krzysztof Blazewicz <blazewicz.krzysztof@gmail.com> <krzysztof.blazewicz@uxeon.com>
+Li Weiwei <liweiwei@yeweitech.org>
+Li Weiwei <liweiwei@yeweitech.org> <liweiwei@yeweitech.com>
+Limor "Ladyada" Fried <limor@ladyada.net>
+Limor "Ladyada" Fried <limor@ladyada.net> <ladyada>
+Lucian Copeland <hierophect@gmail.com>
+Lucian Copeland <hierophect@gmail.com> <hierophect@Lucians-MacBook-Air-2.local>
+Mark Olsson <post@markolsson.se>
+Mark Olsson <post@markolsson.se> <mark@markolsson.se>
+Matt Land <matt-land@users.noreply.github.com>
+Matt Land <matt-land@users.noreply.github.com> <mland@sparefoot.com>
+Matt Wozniski <godlygeek+git@gmail.com>
+Matt Wozniski <godlygeek+git@gmail.com> <mwozniski@bloomberg.net>
+Melissa LeBlanc-Williams <melissa@adafruit.com>
+Melissa LeBlanc-Williams <melissa@adafruit.com> <melissa@melissagirl.com>
+Metallicow <metaliobovinus@gmail.com>
+Metallicow <metaliobovinus@gmail.com> <edg62702@yahoo.com>
+Peter Hinch <peter@hinch.me.uk>
+Peter Hinch <peter@hinch.me.uk> <peterhinch@users.noreply.github.com>
+Radomir Dopieralski <openstack@sheep.art.pl>
+Radomir Dopieralski <openstack@sheep.art.pl> <deshipu@users.noreply.github.com>
+Rafa Gould <rafagoulds@gmail.com>
+Rafa Gould <rafagoulds@gmail.com> <50337143+rafa-gould@users.noreply.github.com>
+Ryan Shaw <ryan.shaw@wisetechglobal.com>
+Ryan Shaw <ryan.shaw@wisetechglobal.com> <ryannathans@hotmail.com>
+Sabas <s@electroniccats.com>
+Sabas <s@electroniccats.com> <s@theinventorhouse.org>
+Sabas <s@electroniccats.com> <sabasjimenez@gmail.com>
+Scott Shawcroft <scott@adafruit.com>
+Scott Shawcroft <scott@adafruit.com> <devnull@unpythonic.net>
+Scott Shawcroft <scott@adafruit.com> <scott.shawcroft@gmail.com>
+Scott Shawcroft <scott@adafruit.com> <scott@chickadee.tech>
+Scott Shawcroft <scott@adafruit.com> <scott@tannewt.org>
+Sebastian Plamauer <oeplse@gmail.com>
+Sebastian Plamauer <oeplse@gmail.com> <oepse@gmail.com>
+Senuros <Senuros@users.noreply.github.com>
+Senuros <Senuros@users.noreply.github.com> <senuros@noreply.github.com>
+Stewart Colborne <tscolborne@outlook.com>
+Stewart Colborne <tscolborne@outlook.com> <tscolborne@hotmail.com>
+TG-Techie <TGTechie01@gmail.com>
+TG-Techie <TGTechie01@gmail.com> <39284876+TG-Techie@users.noreply.github.com>
+Thea Flowers <me@thea.codes>
+Thea Flowers <me@thea.codes> <theaflowers@google.com>
+Tobias Badertscher <badi@baerospace.ch>
+Tobias Badertscher <badi@baerospace.ch> <python@baerospace.ch>
+danicampora <danicampora@gmail.com>
+danicampora <danicampora@gmail.com> <daniel@wipy.io>
+dherrada <dylan.herrada@gmail.com>
+dherrada <dylan.herrada@gmail.com> <33632497+dherrada@users.noreply.github.com>
+dherrada <dylan.herrada@gmail.com> <=>
+glennrub <glennbakke@gmail.com>
+retoc <retoc@users.noreply.github.com>
+retoc <retoc@users.noreply.github.com> <Retoc@noreply.github.com>
+siddacious <nospam187+github@gmail.com>
+siddacious <nospam187+github@gmail.com> <bsiepert@gmail.com>
+siddacious <nospam187+github@gmail.com> <bsiepert@lbl.gov>
+sommersoft <sommersoft@gmail.com>
+sommersoft <sommersoft@gmail.com> <sommersoft@users.noreply.github.com>
+stijn <stijn@ignitron.net>
+stijn <stijn@ignitron.net> <stinos@zoho.com>
diff --git a/mpy-cross/.gitignore 2 b/mpy-cross/.gitignore 2
new file mode 100644
index 000000000..6daeea504
--- /dev/null
+++ b/mpy-cross/.gitignore 2
@@ -0,0 +1,11 @@
+# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
+#
+# SPDX-License-Identifier: MIT
+
+/build-*
+/mpy-cross
+/mpy-cross.static
+/mpy-cross.static.exe
+/mpy-cross.static-raspbian
+/mpy-cross.fuzz
+/pitools
diff --git a/ports/atmel-samd/.gitattributes 2 b/ports/atmel-samd/.gitattributes 2
new file mode 100644
index 000000000..09bba615b
--- /dev/null
+++ b/ports/atmel-samd/.gitattributes 2
@@ -0,0 +1,2 @@
+tools/bossac* binary
+asf/**/*.a binary
diff --git a/ports/atmel-samd/.gitignore 2 b/ports/atmel-samd/.gitignore 2
new file mode 100644
index 000000000..414487d53
--- /dev/null
+++ b/ports/atmel-samd/.gitignore 2
@@ -0,0 +1 @@
+build-*/
diff --git a/ports/atmel-samd/boards/board.h b/ports/atmel-samd/boards/board.h
new file mode 100644
index 000000000..4f0ae9d72
--- /dev/null
+++ b/ports/atmel-samd/boards/board.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file defines board specific functions.
+
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_BOARD_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_BOARD_H
+
+#include <stdbool.h>
+
+#include "py/mpconfig.h"
+
+// Initializes board related state once on start up.
+void board_init(void);
+
+// Returns true if the user initiates safe mode in a board specific way.
+// Also add BOARD_USER_SAFE_MODE in mpconfigboard.h to explain the board specific
+// way.
+bool board_requests_safe_mode(void);
+
+// Reset the state of off MCU components such as neopixels.
+void reset_board(void);
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_BOARD_H
diff --git a/supervisor/shared/external_flash/devices.h b/supervisor/shared/external_flash/devices.h
index fafb68ef0..d632dd96e 100644
--- a/supervisor/shared/external_flash/devices.h
+++ b/supervisor/shared/external_flash/devices.h
@@ -589,22 +589,40 @@ typedef struct {
// Settings for the Macronix MX25L51245G 64MiB SPI flash.
// Datasheet: https://www.macronix.com/Lists/Datasheet/Attachments/7437/MX25L51245G,%203V,%20512Mb,%20v1.6.pdf
-// Will finish this addition in a future PR. All the stuff is there, just need to test in the wild.
-//#define MX25L25645G {\
-// .total_size = (1 << 25), /* 32 MiB */ \
-// .start_up_time_us = 5000, \
-// .manufacturer_id = 0x9f, \
-// .memory_type = 0xab, \
-// .capacity = 0x90, \
-// .max_clock_speed_mhz = 133, \
-// .quad_enable_bit_mask = 0xaf, \
-// .has_sector_protection = false, \
-// .supports_fast_read = true, \
-// .supports_qspi = true, \
-// .supports_qspi_writes = true, \
-// .write_status_register_split = false, \
-// .single_status_byte = true, \
-//}
+#define MX25L25645G {\
+ .total_size = (1 << 25), /* 32 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0x9f, \
+ .memory_type = 0xab, \
+ .capacity = 0x90, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0xaf, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+}
+
+// Settings for the Macronix MX25L12833F 16MiB SPI flash
+// Datasheet: https://www.macronix.com/Lists/Datasheet/Attachments/7447/MX25L12833F,%203V,%20128Mb,%20v1.0.pdf
+
+#define MX25L12833F {\
+ .total_size = (1UL << 24), /* 16 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc2, \
+ .memory_type = 0x20, \
+ .capacity = 0x18, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x40, \
+ .has_sector_protection = true, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+ }
// Settings for the Winbond W25Q128JV-PM 16MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
// Datasheet: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
diff --git a/tests/README 2 b/tests/README 2
new file mode 100644
index 000000000..3458f36a8
--- /dev/null
+++ b/tests/README 2
@@ -0,0 +1,18 @@
+This directory contains tests for various functionality areas of MicroPython.
+To run all stable tests, run "run-tests" script in this directory.
+
+Tests of capabilities not supported on all platforms should be written
+to check for the capability being present. If it is not, the test
+should merely output 'SKIP' followed by the line terminator, and call
+sys.exit() to raise SystemExit, instead of attempting to test the
+missing capability. The testing framework (run-tests in this
+directory, test_main.c in qemu_arm) recognizes this as a skipped test.
+
+There are a few features for which this mechanism cannot be used to
+condition a test. The run-tests script uses small scripts in the
+feature_check directory to check whether each such feature is present,
+and skips the relevant tests if not.
+
+When creating new tests, anything that relies on float support should go in the
+float/ subdirectory. Anything that relies on import x, where x is not a built-in
+module, should go in the import/ subdirectory.
diff --git a/tests/extmod 2/btree1.py b/tests/extmod 2/btree1.py
new file mode 100644
index 000000000..59638ef0a
--- /dev/null
+++ b/tests/extmod 2/btree1.py
@@ -0,0 +1,89 @@
+try:
+ import btree
+ import uio
+ import uerrno
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+#f = open("_test.db", "w+b")
+f = uio.BytesIO()
+db = btree.open(f, pagesize=512)
+
+db[b"foo3"] = b"bar3"
+db[b"foo1"] = b"bar1"
+db[b"foo2"] = b"bar2"
+db[b"bar1"] = b"foo1"
+
+dbstr = str(db)
+print(dbstr[:7], dbstr[-1:])
+
+print(db[b"foo2"])
+try:
+ print(db[b"foo"])
+except KeyError:
+ print("KeyError")
+print(db.get(b"foo"))
+print(db.get(b"foo", b"dflt"))
+
+del db[b"foo2"]
+try:
+ del db[b"foo"]
+except KeyError:
+ print("KeyError")
+
+for k, v in db.items():
+ print((k, v))
+
+print("---")
+for k, v in db.items(None, None):
+ print((k, v))
+
+print("---")
+for k, v in db.items(b"f"):
+ print((k, v))
+
+print("---")
+for k, v in db.items(b"f", b"foo3"):
+ print((k, v))
+
+print("---")
+for k, v in db.items(None, b"foo3"):
+ print((k, v))
+
+print("---")
+for k, v in db.items(b"f", b"foo3", btree.INCL):
+ print((k, v))
+
+print("---")
+for k, v in db.items(None, None, btree.DESC):
+ print((k, v))
+
+print(db.seq(1, b"foo1"))
+print(db.seq(1, b"qux"))
+
+try:
+ db.seq(b"foo1")
+except OSError as e:
+ print(e.args[0] == uerrno.EINVAL)
+
+print(list(db.keys()))
+print(list(db.values()))
+
+for k in db:
+ print(k)
+
+db.put(b"baz1", b"qux1")
+
+print("foo1", "foo1" in db)
+print("foo2", "foo2" in db)
+print("baz1", "baz1" in db)
+
+try:
+ print(db + db[b"foo1"])
+except TypeError:
+ print("TypeError")
+
+db.flush()
+db.close()
+f.close()
diff --git a/tests/extmod 2/framebuf1.py b/tests/extmod 2/framebuf1.py
new file mode 100644
index 000000000..2c1366522
--- /dev/null
+++ b/tests/extmod 2/framebuf1.py
@@ -0,0 +1,109 @@
+try:
+ import framebuf
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+w = 5
+h = 16
+size = w * h // 8
+buf = bytearray(size)
+maps = {framebuf.MONO_VLSB : 'MONO_VLSB',
+ framebuf.MONO_HLSB : 'MONO_HLSB',
+ framebuf.MONO_HMSB : 'MONO_HMSB'}
+
+for mapping in maps.keys():
+ for x in range(size):
+ buf[x] = 0
+ fbuf = framebuf.FrameBuffer(buf, w, h, mapping)
+ print(maps[mapping])
+ # access as buffer
+ print(memoryview(fbuf)[0])
+
+ # fill
+ fbuf.fill(1)
+ print(buf)
+ fbuf.fill(0)
+ print(buf)
+
+ # put pixel
+ fbuf.pixel(0, 0, 1)
+ fbuf.pixel(4, 0, 1)
+ fbuf.pixel(0, 15, 1)
+ fbuf.pixel(4, 15, 1)
+ print(buf)
+
+ # clear pixel
+ fbuf.pixel(4, 15, 0)
+ print(buf)
+
+ # get pixel
+ print(fbuf.pixel(0, 0), fbuf.pixel(1, 1))
+
+ # hline
+ fbuf.fill(0)
+ fbuf.hline(0, 1, w, 1)
+ print('hline', buf)
+
+ # vline
+ fbuf.fill(0)
+ fbuf.vline(1, 0, h, 1)
+ print('vline', buf)
+
+ # rect
+ fbuf.fill(0)
+ fbuf.rect(1, 1, 3, 3, 1)
+ print('rect', buf)
+
+ #fill rect
+ fbuf.fill(0)
+ fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation
+ fbuf.fill_rect(1, 1, 3, 3, 1)
+ print('fill_rect', buf)
+
+ # line
+ fbuf.fill(0)
+ fbuf.line(1, 1, 3, 3, 1)
+ print('line', buf)
+
+ # line steep negative gradient
+ fbuf.fill(0)
+ fbuf.line(3, 3, 2, 1, 1)
+ print('line', buf)
+
+ # scroll
+ fbuf.fill(0)
+ fbuf.pixel(2, 7, 1)
+ fbuf.scroll(0, 1)
+ print(buf)
+ fbuf.scroll(0, -2)
+ print(buf)
+ fbuf.scroll(1, 0)
+ print(buf)
+ fbuf.scroll(-1, 0)
+ print(buf)
+ fbuf.scroll(2, 2)
+ print(buf)
+
+ # print text
+ fbuf.fill(0)
+ fbuf.text("hello", 0, 0, 1)
+ print(buf)
+ fbuf.text("hello", 0, 0, 0) # clear
+ print(buf)
+
+ # char out of font range set to chr(127)
+ fbuf.text(str(chr(31)), 0, 0)
+ print(buf)
+ print()
+
+# test invalid constructor, and stride argument
+try:
+ fbuf = framebuf.FrameBuffer(buf, w, h, -1, w)
+except ValueError:
+ print("ValueError")
+
+# test legacy constructor
+fbuf = framebuf.FrameBuffer1(buf, w, h)
+fbuf = framebuf.FrameBuffer1(buf, w, h, w)
+print(framebuf.MVLSB == framebuf.MONO_VLSB)
diff --git a/tests/extmod 2/framebuf16.py b/tests/extmod 2/framebuf16.py
new file mode 100644
index 000000000..fe81f7f93
--- /dev/null
+++ b/tests/extmod 2/framebuf16.py
@@ -0,0 +1,59 @@
+try:
+ import framebuf
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def printbuf():
+ print("--8<--")
+ for y in range(h):
+ print(buf[y * w * 2:(y + 1) * w * 2])
+ print("-->8--")
+
+w = 4
+h = 5
+buf = bytearray(w * h * 2)
+fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.RGB565)
+
+# fill
+fbuf.fill(0xffff)
+printbuf()
+fbuf.fill(0x0000)
+printbuf()
+
+# put pixel
+fbuf.pixel(0, 0, 0xeeee)
+fbuf.pixel(3, 0, 0xee00)
+fbuf.pixel(0, 4, 0x00ee)
+fbuf.pixel(3, 4, 0x0ee0)
+printbuf()
+
+# get pixel
+print(fbuf.pixel(0, 4), fbuf.pixel(1, 1))
+
+# scroll
+fbuf.fill(0x0000)
+fbuf.pixel(2, 2, 0xffff)
+printbuf()
+fbuf.scroll(0, 1)
+printbuf()
+fbuf.scroll(1, 0)
+printbuf()
+fbuf.scroll(-1, -2)
+printbuf()
+
+w2 = 2
+h2 = 3
+buf2 = bytearray(w2 * h2 * 2)
+fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.RGB565)
+
+fbuf2.fill(0x0000)
+fbuf2.pixel(0, 0, 0x0ee0)
+fbuf2.pixel(0, 2, 0xee00)
+fbuf2.pixel(1, 0, 0x00ee)
+fbuf2.pixel(1, 2, 0xe00e)
+fbuf.fill(0xffff)
+fbuf.blit(fbuf2, 3, 3, 0x0000)
+fbuf.blit(fbuf2, -1, -1, 0x0000)
+fbuf.blit(fbuf2, 16, 16, 0x0000)
+printbuf()
diff --git a/tests/extmod 2/framebuf2.py.exp b/tests/extmod 2/framebuf2.py.exp
new file mode 100644
index 000000000..c53e518a6
--- /dev/null
+++ b/tests/extmod 2/framebuf2.py.exp
@@ -0,0 +1,57 @@
+--8<--
+33333333
+33333333
+33333333
+33333333
+33333333
+-->8--
+--8<--
+00000000
+00000000
+00000000
+00000000
+00000000
+-->8--
+--8<--
+10020000
+00000000
+00000000
+00000000
+30020000
+-->8--
+3 0
+--8<--
+00000000
+00000000
+00300000
+00000000
+00000000
+-->8--
+--8<--
+00000000
+00000000
+00000000
+00300000
+00000000
+-->8--
+--8<--
+00000000
+00000000
+00000000
+00030000
+00000000
+-->8--
+--8<--
+00000000
+00300000
+00000000
+00030000
+00000000
+-->8--
+--8<--
+33333333
+23333333
+33333333
+33311333
+33333333
+-->8--
diff --git a/tests/extmod 2/framebuf4.py b/tests/extmod 2/framebuf4.py
new file mode 100644
index 000000000..8358fa55b
--- /dev/null
+++ b/tests/extmod 2/framebuf4.py
@@ -0,0 +1,53 @@
+try:
+ import framebuf
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def printbuf():
+ print("--8<--")
+ for y in range(h):
+ print(buf[y * w // 2:(y + 1) * w // 2])
+ print("-->8--")
+
+w = 16
+h = 8
+buf = bytearray(w * h // 2)
+fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS4_HMSB)
+
+# fill
+fbuf.fill(0x0f)
+printbuf()
+fbuf.fill(0xa0)
+printbuf()
+
+# put pixel
+fbuf.pixel(0, 0, 0x01)
+printbuf()
+fbuf.pixel(w-1, 0, 0x02)
+printbuf()
+fbuf.pixel(w-1, h-1, 0x03)
+printbuf()
+fbuf.pixel(0, h-1, 0x04)
+printbuf()
+
+# get pixel
+print(fbuf.pixel(0, 0), fbuf.pixel(w-1, 0), fbuf.pixel(w-1, h-1), fbuf.pixel(0, h-1))
+print(fbuf.pixel(1, 0), fbuf.pixel(w-2, 0), fbuf.pixel(w-2, h-1), fbuf.pixel(1, h-1))
+
+# fill rect
+fbuf.fill_rect(0, 0, w, h, 0x0f)
+printbuf()
+fbuf.fill_rect(0, 0, w, h, 0xf0)
+fbuf.fill_rect(1, 0, w//2+1, 1, 0xf1)
+printbuf()
+fbuf.fill_rect(1, 0, w//2+1, 1, 0x10)
+fbuf.fill_rect(1, 0, w//2, 1, 0xf1)
+printbuf()
+fbuf.fill_rect(1, 0, w//2, 1, 0x10)
+fbuf.fill_rect(0, h-4, w//2+1, 4, 0xaf)
+printbuf()
+fbuf.fill_rect(0, h-4, w//2+1, 4, 0xb0)
+fbuf.fill_rect(0, h-4, w//2, 4, 0xaf)
+printbuf()
+fbuf.fill_rect(0, h-4, w//2, 4, 0xb0)
diff --git a/tests/extmod 2/framebuf_subclass.py b/tests/extmod 2/framebuf_subclass.py
new file mode 100644
index 000000000..6363c224f
--- /dev/null
+++ b/tests/extmod 2/framebuf_subclass.py
@@ -0,0 +1,20 @@
+# test subclassing framebuf.FrameBuffer
+
+try:
+ import framebuf
+except ImportError:
+ print('SKIP')
+ raise SystemExit
+
+class FB(framebuf.FrameBuffer):
+ def __init__(self, n):
+ self.n = n
+ super().__init__(bytearray(2 * n * n), n, n, framebuf.RGB565)
+
+ def foo(self):
+ self.hline(0, 2, self.n, 0x0304)
+
+fb = FB(n=3)
+fb.pixel(0, 0, 0x0102)
+fb.foo()
+print(bytes(fb))
diff --git a/tests/extmod 2/machine1.py b/tests/extmod 2/machine1.py
new file mode 100644
index 000000000..6ff38cc05
--- /dev/null
+++ b/tests/extmod 2/machine1.py
@@ -0,0 +1,28 @@
+# test machine module
+
+try:
+ try:
+ import umachine as machine
+ except ImportError:
+ import machine
+ machine.mem8
+except:
+ print("SKIP")
+ raise SystemExit
+
+print(machine.mem8)
+
+try:
+ machine.mem16[1]
+except ValueError:
+ print("ValueError")
+
+try:
+ machine.mem16[1] = 1
+except ValueError:
+ print("ValueError")
+
+try:
+ del machine.mem8[0]
+except TypeError:
+ print("TypeError")
diff --git a/tests/extmod 2/machine_pinbase.py b/tests/extmod 2/machine_pinbase.py
new file mode 100644
index 000000000..e91775504
--- /dev/null
+++ b/tests/extmod 2/machine_pinbase.py
@@ -0,0 +1,30 @@
+try:
+ import umachine as machine
+except ImportError:
+ import machine
+try:
+ machine.PinBase
+except AttributeError:
+ print("SKIP")
+ raise SystemExit
+
+
+class MyPin(machine.PinBase):
+
+ def __init__(self):
+ print("__init__")
+ self.v = False
+
+ def value(self, v=None):
+ print("value:", v)
+ if v is None:
+ self.v = not self.v
+ return int(self.v)
+
+p = MyPin()
+
+print(p.value())
+print(p.value())
+print(p.value())
+p.value(1)
+p.value(0)
diff --git a/tests/extmod 2/machine_pinbase.py.exp b/tests/extmod 2/machine_pinbase.py.exp
new file mode 100644
index 000000000..b31cd9830
--- /dev/null
+++ b/tests/extmod 2/machine_pinbase.py.exp
@@ -0,0 +1,9 @@
+__init__
+value: None
+1
+value: None
+0
+value: None
+1
+value: 1
+value: 0
diff --git a/tests/extmod 2/ticks_diff.py b/tests/extmod 2/ticks_diff.py
new file mode 100644
index 000000000..4d8df83cf
--- /dev/null
+++ b/tests/extmod 2/ticks_diff.py
@@ -0,0 +1,33 @@
+from utime import ticks_diff, ticks_add
+
+MAX = ticks_add(0, -1)
+# Should be done like this to avoid small int overflow
+MODULO_HALF = MAX // 2 + 1
+
+# Invariants:
+# if ticks_diff(a, b) = c,
+# then ticks_diff(b, a) = -c
+
+assert ticks_diff(1, 0) == 1, ticks_diff(1, 0)
+assert ticks_diff(0, 1) == -1
+
+assert ticks_diff(0, MAX) == 1
+assert ticks_diff(MAX, 0) == -1
+
+assert ticks_diff(0, MAX - 1) == 2
+
+# Maximum "positive" distance
+assert ticks_diff(MODULO_HALF, 1) == MODULO_HALF - 1, ticks_diff(MODULO_HALF, 1)
+# Step further, and it becomes a negative distance
+assert ticks_diff(MODULO_HALF, 0) == -MODULO_HALF
+
+# Offsetting that in either direction doesn't affect the result
+off = 100
+# Cheating and skipping to use ticks_add() when we know there's no wraparound
+# Real apps should use always it.
+assert ticks_diff(MODULO_HALF + off, 1 + off) == MODULO_HALF - 1
+assert ticks_diff(MODULO_HALF + off, 0 + off) == -MODULO_HALF
+assert ticks_diff(MODULO_HALF - off, ticks_add(1, -off)) == MODULO_HALF - 1
+assert ticks_diff(MODULO_HALF - off, ticks_add(0, -off)) == -MODULO_HALF
+
+print("OK")
diff --git a/tests/extmod 2/time_ms_us.py b/tests/extmod 2/time_ms_us.py
new file mode 100644
index 000000000..135cf1e09
--- /dev/null
+++ b/tests/extmod 2/time_ms_us.py
@@ -0,0 +1,22 @@
+import utime
+try:
+ utime.sleep_ms
+except AttributeError:
+ print("SKIP")
+ raise SystemExit
+
+utime.sleep_ms(1)
+utime.sleep_us(1)
+
+t0 = utime.ticks_ms()
+t1 = utime.ticks_ms()
+print(0 <= utime.ticks_diff(t1, t0) <= 1)
+
+t0 = utime.ticks_us()
+t1 = utime.ticks_us()
+print(0 <= utime.ticks_diff(t1, t0) <= 500)
+
+# ticks_cpu may not be implemented, at least make sure it doesn't decrease
+t0 = utime.ticks_cpu()
+t1 = utime.ticks_cpu()
+print(utime.ticks_diff(t1, t0) >= 0)
diff --git a/tests/extmod 2/time_ms_us.py.exp b/tests/extmod 2/time_ms_us.py.exp
new file mode 100644
index 000000000..b8ca7e7ef
--- /dev/null
+++ b/tests/extmod 2/time_ms_us.py.exp
@@ -0,0 +1,3 @@
+True
+True
+True
diff --git a/tests/extmod 2/ubinascii_a2b_base64.py b/tests/extmod 2/ubinascii_a2b_base64.py
new file mode 100644
index 000000000..5e642ec51
--- /dev/null
+++ b/tests/extmod 2/ubinascii_a2b_base64.py
@@ -0,0 +1,49 @@
+try:
+ try:
+ import ubinascii as binascii
+ except ImportError:
+ import binascii
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(binascii.a2b_base64(b''))
+print(binascii.a2b_base64(b'Zg=='))
+print(binascii.a2b_base64(b'Zm8='))
+print(binascii.a2b_base64(b'Zm9v'))
+print(binascii.a2b_base64(b'Zm9vYg=='))
+print(binascii.a2b_base64(b'Zm9vYmE='))
+print(binascii.a2b_base64(b'Zm9vYmFy'))
+
+print(binascii.a2b_base64(b'AAECAwQFBgc='))
+print(binascii.a2b_base64(b'CAkKCwwNDg8='))
+print(binascii.a2b_base64(b'f4D/'))
+print(binascii.a2b_base64(b'f4D+')) # convert '+'
+print(binascii.a2b_base64(b'MTIzNEFCQ0RhYmNk'))
+
+# Ignore invalid characters and pad sequences
+print(binascii.a2b_base64(b'Zm9v\n'))
+print(binascii.a2b_base64(b'Zm\x009v\n'))
+print(binascii.a2b_base64(b'Zm9v=='))
+print(binascii.a2b_base64(b'Zm9v==='))
+print(binascii.a2b_base64(b'Zm9v===YmFy'))
+
+# Unicode strings can be decoded
+print(binascii.a2b_base64(u'Zm9v===YmFy'))
+
+try:
+ print(binascii.a2b_base64(b'abc'))
+except ValueError:
+ print("ValueError")
+try:
+ print(binascii.a2b_base64(b'abcde='))
+except ValueError:
+ print("ValueError")
+try:
+ print(binascii.a2b_base64(b'ab*d'))
+except ValueError:
+ print("ValueError")
+try:
+ print(binascii.a2b_base64(b'ab=cdef='))
+except ValueError:
+ print("ValueError")
diff --git a/tests/extmod 2/ubinascii_hexlify.py b/tests/extmod 2/ubinascii_hexlify.py
new file mode 100644
index 000000000..dabc3c7e4
--- /dev/null
+++ b/tests/extmod 2/ubinascii_hexlify.py
@@ -0,0 +1,17 @@
+try:
+ try:
+ import ubinascii as binascii
+ except ImportError:
+ import binascii
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(binascii.hexlify(b'\x00\x01\x02\x03\x04\x05\x06\x07'))
+print(binascii.hexlify(b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'))
+print(binascii.hexlify(b'\x7f\x80\xff'))
+print(binascii.hexlify(b'1234ABCDabcd'))
+try:
+ binascii.hexlify('')
+except TypeError:
+ print("TypeError")
diff --git a/tests/extmod 2/uctypes_32bit_intbig.py.exp b/tests/extmod 2/uctypes_32bit_intbig.py.exp
new file mode 100644
index 000000000..d1fc1fe35
--- /dev/null
+++ b/tests/extmod 2/uctypes_32bit_intbig.py.exp
@@ -0,0 +1,11 @@
+b'\xff\xff\xff\x7f5678abcd'
+b'\x00\x00\x00\x805678abcd'
+b'\x03\x02\x01\xff5678abcd'
+b'\x03\x02\x01\xff\x00\x00\x00\x80\x00\x00\x00\x00'
+b'\x03\x02\x01\xff\x00\x00\x00\x00\x01\x00\x00\x00'
+=
+b'\x7f\xff\xff\xff5678abcd'
+b'\x80\x00\x00\x005678abcd'
+b'\xff\x01\x02\x035678abcd'
+b'\xff\x01\x02\x03\x00\x00\x00\x00\x80\x00\x00\x00'
+b'\xff\x01\x02\x03\x00\x00\x00\x01\x00\x00\x00\x00'
diff --git a/tests/extmod 2/uctypes_array_assign_native_le.py b/tests/extmod 2/uctypes_array_assign_native_le.py
new file mode 100644
index 000000000..a538bf9ad
--- /dev/null
+++ b/tests/extmod 2/uctypes_array_assign_native_le.py
@@ -0,0 +1,89 @@
+import sys
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+if sys.byteorder != "little":
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ # arr is array at offset 0, of UINT8 elements, array size is 2
+ "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
+ # arr2 is array at offset 0, size 2, of structures defined recursively
+ "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
+ "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2),
+
+ # aligned
+ "arr5": (uctypes.ARRAY | 0, uctypes.UINT32 | 1),
+ "arr7": (uctypes.ARRAY | 0, 1, {"l": uctypes.UINT32 | 0}),
+
+ "arr8": (uctypes.ARRAY | 0, uctypes.INT8 | 1),
+ "arr9": (uctypes.ARRAY | 0, uctypes.INT16 | 1),
+ "arr10": (uctypes.ARRAY | 0, uctypes.INT32 | 1),
+ "arr11": (uctypes.ARRAY | 0, uctypes.INT64 | 1),
+ "arr12": (uctypes.ARRAY | 0, uctypes.UINT64| 1),
+ "arr13": (uctypes.ARRAY | 1, 1, {"l": {}}),
+}
+
+data = bytearray(8)
+
+S = uctypes.struct(uctypes.addressof(data), desc)
+
+# assign byte
+S.arr[0] = 0x11
+print(hex(S.arr[0]))
+assert hex(S.arr[0]) == "0x11"
+
+# assign word
+S.arr3[0] = 0x2233
+print(hex(S.arr3[0]))
+assert hex(S.arr3[0]) == "0x2233"
+
+# assign word, with index
+S.arr3[1] = 0x4455
+print(hex(S.arr3[1]))
+assert hex(S.arr3[1]) == "0x4455"
+
+# assign long, aligned
+S.arr5[0] = 0x66778899
+print(hex(S.arr5[0]))
+assert hex(S.arr5[0]) == "0x66778899"
+
+print(S.arr5[0] == S.arr7[0].l)
+assert S.arr5[0] == S.arr7[0].l
+
+# assign int8
+S.arr8[0] = 0x11
+print(hex(S.arr8[0]))
+assert hex(S.arr8[0]) == "0x11"
+
+# assign int16
+S.arr9[0] = 0x1122
+print(hex(S.arr9[0]))
+assert hex(S.arr9[0]) == "0x1122"
+
+# assign int32
+S.arr10[0] = 0x11223344
+print(hex(S.arr10[0]))
+assert hex(S.arr10[0]) == "0x11223344"
+
+# index out of range
+try:
+ print(S.arr8[2])
+except IndexError:
+ print("IndexError")
+
+# syntax error in descriptor
+try:
+ S.arr13[0].l = 0x11
+except TypeError:
+ print("TypeError")
+
+# operation not supported
+try:
+ S.arr13[0] = 0x11
+except TypeError:
+ print("TypeError")
diff --git a/tests/extmod 2/uctypes_array_assign_native_le.py.exp b/tests/extmod 2/uctypes_array_assign_native_le.py.exp
new file mode 100644
index 000000000..9d67b1c77
--- /dev/null
+++ b/tests/extmod 2/uctypes_array_assign_native_le.py.exp
@@ -0,0 +1,11 @@
+0x11
+0x2233
+0x4455
+0x66778899
+True
+0x11
+0x1122
+0x11223344
+IndexError
+TypeError
+TypeError
diff --git a/tests/extmod 2/uctypes_array_assign_native_le_intbig.py b/tests/extmod 2/uctypes_array_assign_native_le_intbig.py
new file mode 100644
index 000000000..84dfba0e2
--- /dev/null
+++ b/tests/extmod 2/uctypes_array_assign_native_le_intbig.py
@@ -0,0 +1,43 @@
+import sys
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+if sys.byteorder != "little":
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ # arr is array at offset 0, of UINT8 elements, array size is 2
+ "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
+ # arr2 is array at offset 0, size 2, of structures defined recursively
+ "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
+ "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2),
+
+ # aligned
+ "arr5": (uctypes.ARRAY | 0, uctypes.UINT32 | 1),
+ "arr7": (uctypes.ARRAY | 0, 1, {"l": uctypes.UINT32 | 0}),
+
+ "arr8": (uctypes.ARRAY | 0, uctypes.INT8 | 1),
+ "arr9": (uctypes.ARRAY | 0, uctypes.INT16 | 1),
+ "arr10": (uctypes.ARRAY | 0, uctypes.INT32 | 1),
+ "arr11": (uctypes.ARRAY | 0, uctypes.INT64 | 1),
+ "arr12": (uctypes.ARRAY | 0, uctypes.UINT64| 1),
+ "arr13": (uctypes.ARRAY | 1, 1, {"l": {}}),
+}
+
+data = bytearray(8)
+
+S = uctypes.struct(uctypes.addressof(data), desc)
+
+# assign int64
+S.arr11[0] = 0x11223344
+print(hex(S.arr11[0]))
+assert hex(S.arr11[0]) == "0x11223344"
+
+# assign uint64
+S.arr12[0] = 0x11223344
+print(hex(S.arr12[0]))
+assert hex(S.arr12[0]) == "0x11223344"
diff --git a/tests/extmod 2/uctypes_bytearray.py b/tests/extmod 2/uctypes_bytearray.py
new file mode 100644
index 000000000..77c93c376
--- /dev/null
+++ b/tests/extmod 2/uctypes_bytearray.py
@@ -0,0 +1,22 @@
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
+ "arr2": (uctypes.ARRAY | 2, uctypes.INT8 | 2),
+}
+
+data = bytearray(b"01234567")
+
+S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN)
+
+# Arrays of UINT8 are accessed as bytearrays
+print(S.arr)
+# But not INT8, because value range is different
+print(type(S.arr2))
+
+# convert to buffer
+print(bytearray(S))
diff --git a/tests/extmod 2/uctypes_byteat.py b/tests/extmod 2/uctypes_byteat.py
new file mode 100644
index 000000000..784209f80
--- /dev/null
+++ b/tests/extmod 2/uctypes_byteat.py
@@ -0,0 +1,10 @@
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+data = bytearray(b'01234567')
+
+print(uctypes.bytes_at(uctypes.addressof(data), 4))
+print(uctypes.bytearray_at(uctypes.addressof(data), 4))
diff --git a/tests/extmod 2/uctypes_byteat.py.exp b/tests/extmod 2/uctypes_byteat.py.exp
new file mode 100644
index 000000000..e1ae4d053
--- /dev/null
+++ b/tests/extmod 2/uctypes_byteat.py.exp
@@ -0,0 +1,2 @@
+b'0123'
+bytearray(b'0123')
diff --git a/tests/extmod 2/uctypes_error.py b/tests/extmod 2/uctypes_error.py
new file mode 100644
index 000000000..2500e2927
--- /dev/null
+++ b/tests/extmod 2/uctypes_error.py
@@ -0,0 +1,37 @@
+# test general errors with uctypes
+
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+data = bytearray(b"01234567")
+
+# del subscr not supported
+S = uctypes.struct(uctypes.addressof(data), {})
+try:
+ del S[0]
+except TypeError:
+ print('TypeError')
+
+# list is an invalid descriptor
+S = uctypes.struct(uctypes.addressof(data), [])
+try:
+ S.x
+except TypeError:
+ print('TypeError')
+
+# can't access attribute with invalid descriptor
+S = uctypes.struct(uctypes.addressof(data), {'x':[]})
+try:
+ S.x
+except TypeError:
+ print('TypeError')
+
+# can't assign to aggregate
+S = uctypes.struct(uctypes.addressof(data), {'x':(uctypes.ARRAY | 0, uctypes.INT8 | 2)})
+try:
+ S.x = 1
+except TypeError:
+ print('TypeError')
diff --git a/tests/extmod 2/uctypes_error.py.exp b/tests/extmod 2/uctypes_error.py.exp
new file mode 100644
index 000000000..802c260d2
--- /dev/null
+++ b/tests/extmod 2/uctypes_error.py.exp
@@ -0,0 +1,4 @@
+TypeError
+TypeError
+TypeError
+TypeError
diff --git a/tests/extmod 2/uctypes_le_float.py b/tests/extmod 2/uctypes_le_float.py
new file mode 100644
index 000000000..84ff2b84c
--- /dev/null
+++ b/tests/extmod 2/uctypes_le_float.py
@@ -0,0 +1,24 @@
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ "f32": uctypes.FLOAT32 | 0,
+ "f64": uctypes.FLOAT64 | 0,
+ "uf64": uctypes.FLOAT64 | 2, # unaligned
+}
+
+data = bytearray(10)
+
+S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN)
+
+S.f32 = 12.34
+print('%.4f' % S.f32)
+
+S.f64 = 12.34
+print('%.4f' % S.f64)
+
+S.uf64 = 12.34
+print('%.4f' % S.uf64)
diff --git a/tests/extmod 2/uctypes_native_float.py b/tests/extmod 2/uctypes_native_float.py
new file mode 100644
index 000000000..acef47036
--- /dev/null
+++ b/tests/extmod 2/uctypes_native_float.py
@@ -0,0 +1,20 @@
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ "f32": uctypes.FLOAT32 | 0,
+ "f64": uctypes.FLOAT64 | 0,
+}
+
+data = bytearray(8)
+
+S = uctypes.struct(uctypes.addressof(data), desc, uctypes.NATIVE)
+
+S.f32 = 12.34
+print('%.4f' % S.f32)
+
+S.f64 = 12.34
+print('%.4f' % S.f64)
diff --git a/tests/extmod 2/uctypes_ptr_le.py b/tests/extmod 2/uctypes_ptr_le.py
new file mode 100644
index 000000000..056e45650
--- /dev/null
+++ b/tests/extmod 2/uctypes_ptr_le.py
@@ -0,0 +1,34 @@
+import sys
+try:
+ import uctypes
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+if sys.byteorder != "little":
+ print("SKIP")
+ raise SystemExit
+
+desc = {
+ "ptr": (uctypes.PTR | 0, uctypes.UINT8),
+ "ptr16": (uctypes.PTR | 0, uctypes.UINT16),
+ "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}),
+}
+
+bytes = b"01"
+
+addr = uctypes.addressof(bytes)
+buf = addr.to_bytes(uctypes.sizeof(desc), "little")
+
+S = uctypes.struct(uctypes.addressof(buf), desc, uctypes.LITTLE_ENDIAN)
+
+print(S.ptr[0])
+assert S.ptr[0] == ord("0")
+print(S.ptr[1])
+assert S.ptr[1] == ord("1")
+print(hex(S.ptr16[0]))
+assert hex(S.ptr16[0]) == "0x3130"
+print(S.ptr2[0].b, S.ptr2[1].b)
+print (S.ptr2[0].b, S.ptr2[1].b)
+print(hex(S.ptr16[0]))
+assert (S.ptr2[0].b, S.ptr2[1].b) == (48, 49)
diff --git a/tests/extmod 2/uctypes_ptr_native_le.py.exp b/tests/extmod 2/uctypes_ptr_native_le.py.exp
new file mode 100644
index 000000000..30d159edd
--- /dev/null
+++ b/tests/extmod 2/uctypes_ptr_native_le.py.exp
@@ -0,0 +1,6 @@
+48
+49
+0x3130
+48 49
+48 49
+0x3130
diff --git a/tests/extmod 2/uctypes_sizeof.py.exp b/tests/extmod 2/uctypes_sizeof.py.exp
new file mode 100644
index 000000000..b35b11aa0
--- /dev/null
+++ b/tests/extmod 2/uctypes_sizeof.py.exp
@@ -0,0 +1,7 @@
+2
+2
+4
+TypeError
+6
+1
+TypeError
diff --git a/tests/extmod 2/uhashlib_sha1.py b/tests/extmod 2/uhashlib_sha1.py
new file mode 100644
index 000000000..9d6427b33
--- /dev/null
+++ b/tests/extmod 2/uhashlib_sha1.py
@@ -0,0 +1,28 @@
+try:
+ import uhashlib as hashlib
+except ImportError:
+ try:
+ import hashlib
+ except ImportError:
+ # This is neither uPy, nor cPy, so must be uPy with
+ # uhashlib module disabled.
+ print("SKIP")
+ raise SystemExit
+
+try:
+ hashlib.sha1
+except AttributeError:
+ # SHA1 is only available on some ports
+ print("SKIP")
+ raise SystemExit
+
+sha1 = hashlib.sha1(b'hello')
+sha1.update(b'world')
+print(sha1.digest())
+
+sha1 = hashlib.sha1(b'hello')
+try:
+ sha1.update(u'world')
+except TypeError as e:
+ print("TypeError")
+print(sha1.digest())
diff --git a/tests/extmod 2/ujson_dump.py b/tests/extmod 2/ujson_dump.py
new file mode 100644
index 000000000..b1cb4a9cb
--- /dev/null
+++ b/tests/extmod 2/ujson_dump.py
@@ -0,0 +1,30 @@
+try:
+ from uio import StringIO
+ import ujson as json
+except:
+ try:
+ from io import StringIO
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+s = StringIO()
+json.dump(False, s)
+print(s.getvalue())
+
+s = StringIO()
+json.dump({"a": (2, [3, None])}, s)
+print(s.getvalue())
+
+# dump to a small-int not allowed
+try:
+ json.dump(123, 1)
+except (AttributeError, OSError): # CPython and uPy have different errors
+ print('Exception')
+
+# dump to an object not allowed
+try:
+ json.dump(123, {})
+except (AttributeError, OSError): # CPython and uPy have different errors
+ print('Exception')
diff --git a/tests/extmod 2/ujson_dumps_extra.py b/tests/extmod 2/ujson_dumps_extra.py
new file mode 100644
index 000000000..21a388c32
--- /dev/null
+++ b/tests/extmod 2/ujson_dumps_extra.py
@@ -0,0 +1,9 @@
+# test uPy ujson behaviour that's not valid in CPy
+
+try:
+ import ujson
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(ujson.dumps(b'1234'))
diff --git a/tests/extmod 2/ujson_dumps_float.py b/tests/extmod 2/ujson_dumps_float.py
new file mode 100644
index 000000000..e8cceb6f1
--- /dev/null
+++ b/tests/extmod 2/ujson_dumps_float.py
@@ -0,0 +1,10 @@
+try:
+ import ujson as json
+except ImportError:
+ try:
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(json.dumps(1.2))
diff --git a/tests/extmod 2/ujson_load_readinto.py.exp b/tests/extmod 2/ujson_load_readinto.py.exp
new file mode 100644
index 000000000..f8c3c693b
--- /dev/null
+++ b/tests/extmod 2/ujson_load_readinto.py.exp
@@ -0,0 +1,4 @@
+None
+abcde
+[False, True, 1, -2]
+{'a': True}
diff --git a/tests/extmod 2/ujson_loads.py b/tests/extmod 2/ujson_loads.py
new file mode 100644
index 000000000..adba3c068
--- /dev/null
+++ b/tests/extmod 2/ujson_loads.py
@@ -0,0 +1,74 @@
+try:
+ import ujson as json
+except ImportError:
+ try:
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def my_print(o):
+ if isinstance(o, dict):
+ print('sorted dict', sorted(o.items()))
+ else:
+ print(o)
+
+my_print(json.loads('null'))
+my_print(json.loads('false'))
+my_print(json.loads('true'))
+my_print(json.loads('1'))
+my_print(json.loads('-2'))
+my_print(json.loads('"abc\\u0064e"'))
+my_print(json.loads('[]'))
+my_print(json.loads('[null]'))
+my_print(json.loads('[null,false,true]'))
+my_print(json.loads(' [ null , false , true ] '))
+my_print(json.loads('{}'))
+my_print(json.loads('{"a":true}'))
+my_print(json.loads('{"a":null, "b":false, "c":true}'))
+my_print(json.loads('{"a":[], "b":[1], "c":{"3":4}}'))
+my_print(json.loads('"abc\\bdef"'))
+my_print(json.loads('"abc\\fdef"'))
+my_print(json.loads('"abc\\ndef"'))
+my_print(json.loads('"abc\\rdef"'))
+my_print(json.loads('"abc\\tdef"'))
+my_print(json.loads('"abc\\uabcd"'))
+
+# whitespace handling
+my_print(json.loads('{\n\t"a":[]\r\n, "b":[1], "c":{"3":4} \n\r\t\r\r\r\n}'))
+
+# loading nothing should raise exception
+try:
+ json.loads('')
+except ValueError:
+ print('ValueError')
+
+# string which is not closed
+try:
+ my_print(json.loads('"abc'))
+except ValueError:
+ print('ValueError')
+
+# unaccompanied closing brace
+try:
+ my_print(json.loads(']'))
+except ValueError:
+ print('ValueError')
+
+# unspecified object type
+try:
+ my_print(json.loads('a'))
+except ValueError:
+ print('ValueError')
+
+# bad property name
+try:
+ my_print(json.loads('{{}:"abc"}'))
+except ValueError:
+ print('ValueError')
+
+# unexpected characters after white space
+try:
+ my_print(json.loads('[null] a'))
+except ValueError:
+ print('ValueError')
diff --git a/tests/extmod 2/ujson_loads_float.py b/tests/extmod 2/ujson_loads_float.py
new file mode 100644
index 000000000..f1b8cc364
--- /dev/null
+++ b/tests/extmod 2/ujson_loads_float.py
@@ -0,0 +1,17 @@
+try:
+ import ujson as json
+except ImportError:
+ try:
+ import json
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def my_print(o):
+ print('%.3f' % o)
+
+my_print(json.loads('1.2'))
+my_print(json.loads('1e2'))
+my_print(json.loads('-2.3'))
+my_print(json.loads('-2e3'))
+my_print(json.loads('-2e-3'))
diff --git a/tests/extmod 2/urandom_basic.py b/tests/extmod 2/urandom_basic.py
new file mode 100644
index 000000000..57e6b26cb
--- /dev/null
+++ b/tests/extmod 2/urandom_basic.py
@@ -0,0 +1,29 @@
+try:
+ import urandom as random
+except ImportError:
+ try:
+ import random
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# check getrandbits returns a value within the bit range
+for b in (1, 2, 3, 4, 16, 32):
+ for i in range(50):
+ assert random.getrandbits(b) < (1 << b)
+
+# check that seed(0) gives a non-zero value
+random.seed(0)
+print(random.getrandbits(16) != 0)
+
+# check that PRNG is repeatable
+random.seed(1)
+r = random.getrandbits(16)
+random.seed(1)
+print(random.getrandbits(16) == r)
+
+# check that it throws an error for zero bits
+try:
+ random.getrandbits(0)
+except ValueError:
+ print('ValueError')
diff --git a/tests/extmod 2/ure1.py b/tests/extmod 2/ure1.py
new file mode 100644
index 000000000..710720c8b
--- /dev/null
+++ b/tests/extmod 2/ure1.py
@@ -0,0 +1,103 @@
+try:
+ import ure as re
+except ImportError:
+ try:
+ import re
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+r = re.compile(".+")
+m = r.match("abc")
+print(m.group(0))
+try:
+ m.group(1)
+except IndexError:
+ print("IndexError")
+
+# conversion of re and match to string
+str(r)
+str(m)
+
+r = re.compile("(.+)1")
+m = r.match("xyz781")
+print(m.group(0))
+print(m.group(1))
+try:
+ m.group(2)
+except IndexError:
+ print("IndexError")
+
+r = re.compile(r"\n")
+m = r.match("\n")
+print(m.group(0))
+m = r.match("\\")
+print(m)
+r = re.compile(r"[\n-\r]")
+m = r.match("\n")
+print(m.group(0))
+r = re.compile(r"[\]]")
+m = r.match("]")
+print(m.group(0))
+print("===")
+
+r = re.compile("[a-cu-z]")
+m = r.match("a")
+print(m.group(0))
+m = r.match("z")
+print(m.group(0))
+m = r.match("d")
+print(m)
+m = r.match("A")
+print(m)
+print("===")
+
+r = re.compile("[^a-cu-z]")
+m = r.match("a")
+print(m)
+m = r.match("z")
+print(m)
+m = r.match("d")
+print(m.group(0))
+m = r.match("A")
+print(m.group(0))
+print("===")
+
+# '-' character within character class block
+print(re.match("[-a]+", "-a]d").group(0))
+print(re.match("[a-]+", "-a]d").group(0))
+print("===")
+
+r = re.compile("o+")
+m = r.search("foobar")
+print(m.group(0))
+try:
+ m.group(1)
+except IndexError:
+ print("IndexError")
+
+
+m = re.match(".*", "foo")
+print(m.group(0))
+
+m = re.search("w.r", "hello world")
+print(m.group(0))
+
+m = re.match('a+?', 'ab'); print(m.group(0))
+m = re.match('a*?', 'ab'); print(m.group(0))
+m = re.match('^ab$', 'ab'); print(m.group(0))
+m = re.match('a|b', 'b'); print(m.group(0))
+m = re.match('a|b|c', 'c'); print(m.group(0))
+
+# Case where anchors fail to match
+r = re.compile("^b|b$")
+m = r.search("abc")
+print(m)
+
+try:
+ re.compile("*")
+except:
+ print("Caught invalid regex")
+
+# bytes objects
+m = re.match(rb'a+?', b'ab'); print(m.group(0))
diff --git a/tests/extmod 2/ure_debug.py.exp b/tests/extmod 2/ure_debug.py.exp
new file mode 100644
index 000000000..45f5e20f6
--- /dev/null
+++ b/tests/extmod 2/ure_debug.py.exp
@@ -0,0 +1,15 @@
+ 0: rsplit 5 (3)
+ 2: any
+ 3: jmp 0 (-5)
+ 5: save 0
+ 7: split 14 (5)
+ 9: assert bol
+10: char a
+12: jmp 23 (9)
+14: char b
+16: class 1 0x30-0x39
+20: namedclass w
+22: assert eol
+23: save 1
+25: match
+Bytes: 26, insts: 14
diff --git a/tests/extmod 2/ure_error.py b/tests/extmod 2/ure_error.py
new file mode 100644
index 000000000..f52f735c7
--- /dev/null
+++ b/tests/extmod 2/ure_error.py
@@ -0,0 +1,25 @@
+# test errors in regex
+
+try:
+ import ure as re
+except ImportError:
+ try:
+ import re
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def test_re(r):
+ try:
+ re.compile(r)
+ print("OK")
+ except: # uPy and CPy use different errors, so just ignore the type
+ print("Error")
+
+test_re(r'?')
+test_re(r'*')
+test_re(r'+')
+test_re(r')')
+test_re(r'[')
+test_re(r'([')
+test_re(r'([)')
diff --git a/tests/extmod 2/ure_namedclass.py b/tests/extmod 2/ure_namedclass.py
new file mode 100644
index 000000000..215d09613
--- /dev/null
+++ b/tests/extmod 2/ure_namedclass.py
@@ -0,0 +1,32 @@
+# test named char classes
+
+try:
+ import ure as re
+except ImportError:
+ try:
+ import re
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def print_groups(match):
+ print('----')
+ try:
+ i = 0
+ while True:
+ print(m.group(i))
+ i += 1
+ except IndexError:
+ pass
+
+m = re.match(r'\w+','1234hello567 abc')
+print_groups(m)
+
+m = re.match(r'(\w+)\s+(\w+)','ABC \t1234hello567 abc')
+print_groups(m)
+
+m = re.match(r'(\S+)\s+(\D+)','ABC \thello abc567 abc')
+print_groups(m)
+
+m = re.match(r'(([0-9]*)([a-z]*)\d*)','1234hello567')
+print_groups(m)
diff --git a/tests/extmod 2/ure_stack_overflow.py.exp b/tests/extmod 2/ure_stack_overflow.py.exp
new file mode 100644
index 000000000..8a2b9bfdd
--- /dev/null
+++ b/tests/extmod 2/ure_stack_overflow.py.exp
@@ -0,0 +1 @@
+RuntimeError
diff --git a/tests/extmod 2/ure_sub_unmatched.py.exp b/tests/extmod 2/ure_sub_unmatched.py.exp
new file mode 100644
index 000000000..1e5f0fda0
--- /dev/null
+++ b/tests/extmod 2/ure_sub_unmatched.py.exp
@@ -0,0 +1 @@
+1-a2
diff --git a/tests/extmod 2/ussl_basic.py b/tests/extmod 2/ussl_basic.py
new file mode 100644
index 000000000..e8710ed51
--- /dev/null
+++ b/tests/extmod 2/ussl_basic.py
@@ -0,0 +1,59 @@
+# very basic test of ssl module, just to test the methods exist
+
+try:
+ import uio as io
+ import ussl as ssl
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# create in client mode
+try:
+ ss = ssl.wrap_socket(io.BytesIO())
+except OSError as er:
+ print('wrap_socket:', repr(er))
+
+# create in server mode (can use this object for further tests)
+socket = io.BytesIO()
+ss = ssl.wrap_socket(socket, server_side=1)
+
+# print
+print(repr(ss)[:12])
+
+# setblocking
+try:
+ ss.setblocking(False)
+except NotImplementedError:
+ print('setblocking: NotImplementedError')
+ss.setblocking(True)
+
+# write
+print(ss.write(b'aaaa'))
+
+# read (underlying socket has no data)
+print(ss.read(8))
+
+# read (underlying socket has data, but it's bad data)
+socket.write(b'aaaaaaaaaaaaaaaa')
+socket.seek(0)
+try:
+ ss.read(8)
+except OSError as er:
+ print('read:', repr(er))
+
+# close
+ss.close()
+# close 2nd time
+ss.close()
+
+# read on closed socket
+try:
+ ss.read(10)
+except OSError as er:
+ print('read:', repr(er))
+
+# write on closed socket
+try:
+ ss.write(b'aaaa')
+except OSError as er:
+ print('write:', repr(er))
diff --git a/tests/extmod 2/utimeq1.py b/tests/extmod 2/utimeq1.py
new file mode 100644
index 000000000..dc7f3b660
--- /dev/null
+++ b/tests/extmod 2/utimeq1.py
@@ -0,0 +1,137 @@
+# Test for utimeq module which implements task queue with support for
+# wraparound time (utime.ticks_ms() style).
+try:
+ from utime import ticks_add, ticks_diff
+ from utimeq import utimeq
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+DEBUG = 0
+
+MAX = ticks_add(0, -1)
+MODULO_HALF = MAX // 2 + 1
+
+if DEBUG:
+ def dprint(*v):
+ print(*v)
+else:
+ def dprint(*v):
+ pass
+
+# Try not to crash on invalid data
+h = utimeq(10)
+try:
+ h.push(1)
+ assert False
+except TypeError:
+ pass
+
+try:
+ h.pop(1)
+ assert False
+except IndexError:
+ pass
+
+# unsupported unary op
+try:
+ ~h
+ assert False
+except TypeError:
+ pass
+
+# pushing on full queue
+h = utimeq(1)
+h.push(1, 0, 0)
+try:
+ h.push(2, 0, 0)
+ assert False
+except IndexError:
+ pass
+
+# popping into invalid type
+try:
+ h.pop([])
+ assert False
+except TypeError:
+ pass
+
+# length
+assert len(h) == 1
+
+# peektime
+assert h.peektime() == 1
+
+# peektime with empty queue
+try:
+ utimeq(1).peektime()
+ assert False
+except IndexError:
+ pass
+
+def pop_all(h):
+ l = []
+ while h:
+ item = [0, 0, 0]
+ h.pop(item)
+ #print("!", item)
+ l.append(tuple(item))
+ dprint(l)
+ return l
+
+def add(h, v):
+ h.push(v, 0, 0)
+ dprint("-----")
+ #h.dump()
+ dprint("-----")
+
+h = utimeq(10)
+add(h, 0)
+add(h, MAX)
+add(h, MAX - 1)
+add(h, 101)
+add(h, 100)
+add(h, MAX - 2)
+dprint(h)
+l = pop_all(h)
+for i in range(len(l) - 1):
+ diff = ticks_diff(l[i + 1][0], l[i][0])
+ assert diff > 0
+
+def edge_case(edge, offset):
+ h = utimeq(10)
+ add(h, ticks_add(0, offset))
+ add(h, ticks_add(edge, offset))
+ dprint(h)
+ l = pop_all(h)
+ diff = ticks_diff(l[1][0], l[0][0])
+ dprint(diff, diff > 0)
+ return diff
+
+dprint("===")
+diff = edge_case(MODULO_HALF - 1, 0)
+assert diff == MODULO_HALF - 1
+assert edge_case(MODULO_HALF - 1, 100) == diff
+assert edge_case(MODULO_HALF - 1, -100) == diff
+
+# We expect diff to be always positive, per the definition of heappop() which should return
+# the smallest value.
+# This is the edge case where this invariant breaks, due to assymetry of two's-complement
+# range - there's one more negative integer than positive, so heappushing values like below
+# will then make ticks_diff() return the minimum negative value. We could make heappop
+# return them in a different order, but ticks_diff() result would be the same. Conclusion:
+# never add to a heap values where (a - b) == MODULO_HALF (and which are >= MODULO_HALF
+# ticks apart in real time of course).
+dprint("===")
+diff = edge_case(MODULO_HALF, 0)
+assert diff == -MODULO_HALF
+assert edge_case(MODULO_HALF, 100) == diff
+assert edge_case(MODULO_HALF, -100) == diff
+
+dprint("===")
+diff = edge_case(MODULO_HALF + 1, 0)
+assert diff == MODULO_HALF - 1
+assert edge_case(MODULO_HALF + 1, 100) == diff
+assert edge_case(MODULO_HALF + 1, -100) == diff
+
+print("OK")
diff --git a/tests/extmod 2/utimeq_stable.py.exp b/tests/extmod 2/utimeq_stable.py.exp
new file mode 100644
index 000000000..d86bac9de
--- /dev/null
+++ b/tests/extmod 2/utimeq_stable.py.exp
@@ -0,0 +1 @@
+OK
diff --git a/tests/extmod 2/uzlib_decompio.py b/tests/extmod 2/uzlib_decompio.py
new file mode 100644
index 000000000..112a82597
--- /dev/null
+++ b/tests/extmod 2/uzlib_decompio.py
@@ -0,0 +1,33 @@
+try:
+ import uzlib as zlib
+ import uio as io
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+# Raw DEFLATE bitstream
+buf = io.BytesIO(b'\xcbH\xcd\xc9\xc9\x07\x00')
+inp = zlib.DecompIO(buf, -8)
+print(buf.seek(0, 1))
+print(inp.read(1))
+print(buf.seek(0, 1))
+print(inp.read(2))
+print(inp.read())
+print(buf.seek(0, 1))
+print(inp.read(1))
+print(inp.read())
+print(buf.seek(0, 1))
+
+
+# zlib bitstream
+inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc1'))
+print(inp.read(10))
+print(inp.read())
+
+# zlib bitstream, wrong checksum
+inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc0'))
+try:
+ print(inp.read())
+except OSError as e:
+ print(repr(e))
diff --git a/tests/extmod 2/uzlib_decompio_gz.py.exp b/tests/extmod 2/uzlib_decompio_gz.py.exp
new file mode 100644
index 000000000..20a30c82a
--- /dev/null
+++ b/tests/extmod 2/uzlib_decompio_gz.py.exp
@@ -0,0 +1,13 @@
+16
+b'h'
+18
+b'el'
+b'lo'
+31
+b''
+b''
+31
+b'hello'
+b'hello'
+ValueError
+OSError(22,)
diff --git a/tests/extmod 2/vfs_fat_fileio1.py b/tests/extmod 2/vfs_fat_fileio1.py
new file mode 100644
index 000000000..4635ca84b
--- /dev/null
+++ b/tests/extmod 2/vfs_fat_fileio1.py
@@ -0,0 +1,139 @@
+try:
+ import uerrno
+ import uos
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+try:
+ uos.VfsFat
+except AttributeError:
+ print("SKIP")
+ raise SystemExit
+
+
+class RAMFS:
+
+ SEC_SIZE = 512
+
+ def __init__(self, blocks):
+ self.data = bytearray(blocks * self.SEC_SIZE)
+
+ def readblocks(self, n, buf):
+ #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
+ for i in range(len(buf)):
+ buf[i] = self.data[n * self.SEC_SIZE + i]
+ return 0
+
+ def writeblocks(self, n, buf):
+ #print("writeblocks(%s, %x)" % (n, id(buf)))
+ for i in range(len(buf)):
+ self.data[n * self.SEC_SIZE + i] = buf[i]
+ return 0
+
+ def ioctl(self, op, arg):
+ #print("ioctl(%d, %r)" % (op, arg))
+ if op == 4: # BP_IOCTL_SEC_COUNT
+ return len(self.data) // self.SEC_SIZE
+ if op == 5: # BP_IOCTL_SEC_SIZE
+ return self.SEC_SIZE
+
+
+try:
+ bdev = RAMFS(50)
+except MemoryError:
+ print("SKIP")
+ raise SystemExit
+
+uos.VfsFat.mkfs(bdev)
+vfs = uos.VfsFat(bdev)
+uos.mount(vfs, '/ramdisk')
+uos.chdir('/ramdisk')
+
+# file IO
+f = open("foo_file.txt", "w")
+print(str(f)[:17], str(f)[-1:])
+f.write("hello!")
+f.flush()
+f.close()
+f.close() # allowed
+try:
+ f.write("world!")
+except OSError as e:
+ print(e.args[0] == uerrno.EINVAL)
+
+try:
+ f.read()
+except OSError as e:
+ print(e.args[0] == uerrno.EINVAL)
+
+try:
+ f.flush()
+except OSError as e:
+ print(e.args[0] == uerrno.EINVAL)
+
+try:
+ open("foo_file.txt", "x")
+except OSError as e:
+ print(e.args[0] == uerrno.EEXIST)
+
+with open("foo_file.txt", "a") as f:
+ f.write("world!")
+
+with open("foo_file.txt") as f2:
+ print(f2.read())
+ print(f2.tell())
+
+ f2.seek(0, 0) # SEEK_SET
+ print(f2.read(1))
+
+ f2.seek(0, 1) # SEEK_CUR
+ print(f2.read(1))
+ f2.seek(2, 1) # SEEK_CUR
+ print(f2.read(1))
+
+ f2.seek(-2, 2) # SEEK_END
+ print(f2.read(1))
+
+# using constructor of FileIO type to open a file
+# no longer working with new VFS sub-system
+#FileIO = type(f)
+#with FileIO("/ramdisk/foo_file.txt") as f:
+# print(f.read())
+
+# dirs
+vfs.mkdir("foo_dir")
+
+try:
+ vfs.rmdir("foo_file.txt")
+except OSError as e:
+ print(e.args[0] == 20) # uerrno.ENOTDIR
+
+vfs.remove("foo_file.txt")
+print(list(vfs.ilistdir()))
+
+# Here we test that opening a file with the heap locked fails correctly. This
+# is a special case because file objects use a finaliser and allocating with a
+# finaliser is a different path to normal allocation. It would be better to
+# test this in the core tests but there are no core objects that use finaliser.
+import micropython
+micropython.heap_lock()
+try:
+ vfs.open('x', 'r')
+except MemoryError:
+ print('MemoryError')
+micropython.heap_unlock()
+
+# Here we test that the finaliser is actually called during a garbage collection.
+import gc
+N = 4
+for i in range(N):
+ n = 'x%d' % i
+ f = vfs.open(n, 'w')
+ f.write(n)
+ f = None # release f without closing
+ [0, 1, 2, 3] # use up Python stack so f is really gone
+gc.collect() # should finalise all N files by closing them
+for i in range(N):
+ with vfs.open('x%d' % i, 'r') as f:
+ print(f.read())
diff --git a/tests/extmod 2/vfs_fat_fileio1.py.exp b/tests/extmod 2/vfs_fat_fileio1.py.exp
new file mode 100644
index 000000000..4eb50402c
--- /dev/null
+++ b/tests/extmod 2/vfs_fat_fileio1.py.exp
@@ -0,0 +1,18 @@
+<io.TextIOWrapper >
+True
+True
+True
+True
+hello!world!
+12
+h
+e
+o
+d
+True
+[('foo_dir', 16384, 0, 0)]
+MemoryError
+x0
+x1
+x2
+x3
diff --git a/tests/extmod 2/vfs_fat_more.py.exp b/tests/extmod 2/vfs_fat_more.py.exp
new file mode 100644
index 000000000..24429ee09
--- /dev/null
+++ b/tests/extmod 2/vfs_fat_more.py.exp
@@ -0,0 +1,29 @@
+/
+['test.txt']
+['test.txt']
+(16384, 0, 0, 0, 0, 0, 0)
+(16384, 0, 0, 0, 0, 0, 0)
+(32768, 0, 0, 0, 0, 0, 5)
+(32768, 0, 0, 0, 0, 0, 5)
+hello
+['test2.txt']
+['test3.txt']
+['test4.txt']
+['test5.txt']
+['test5.txt', 'dir']
+['test5.txt', 'dir', 'dir2']
+['subdir']
+mkdir OSError True
+mkdir OSError True
+mkdir OSError True
+mkdir OSError True
+mkdir OSError True
+(32768, 0, 0, 0, 0, 0, 5)
+['sys', 'test5.txt', 'dir', 'dir2']
+[]
+[]
+['sys', 'dir']
+/
+['sys']
+[]
+test_module!
diff --git a/tests/extmod 2/vfs_fat_oldproto.py.exp b/tests/extmod 2/vfs_fat_oldproto.py.exp
new file mode 100644
index 000000000..b97468316
--- /dev/null
+++ b/tests/extmod 2/vfs_fat_oldproto.py.exp
@@ -0,0 +1,3 @@
+[('file.txt', 32768, 0, 6)]
+hello!
+[]
diff --git a/tests/extmod 2/vfs_fat_ramdisk.py.exp b/tests/extmod 2/vfs_fat_ramdisk.py.exp
new file mode 100644
index 000000000..704408cd0
--- /dev/null
+++ b/tests/extmod 2/vfs_fat_ramdisk.py.exp
@@ -0,0 +1,17 @@
+True
+True
+label: LABEL TEST
+statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255)
+getcwd: /
+True
+[('foo_file.txt', 32768, 0, 6)]
+stat root: (16384, 0, 0, 0, 0, 0, 0, 946684800, 946684800, 946684800)
+stat file: (32768, 0, 0, 0, 0, 0, 6)
+True
+True
+getcwd: /foo_dir
+[]
+True
+getcwd: /
+[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)]
+ENOENT: True
diff --git a/tests/extmod 2/websocket_basic.py.exp b/tests/extmod 2/websocket_basic.py.exp
new file mode 100644
index 000000000..2d7657b53
--- /dev/null
+++ b/tests/extmod 2/websocket_basic.py.exp
@@ -0,0 +1,14 @@
+b'ping'
+b'ping'
+b'\x81\x04pong'
+b'pingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingping'
+b'\x81~\x00\x80pongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpong'
+b'\x00\x00\x00\x00'
+b''
+b'\x81\x02\x88\x00'
+b'ping'
+b'pong'
+0
+1
+2
+ioctl: EINVAL: True
diff --git a/tests/feature_check 2/README b/tests/feature_check 2/README
new file mode 100644
index 000000000..d062020f7
--- /dev/null
+++ b/tests/feature_check 2/README
@@ -0,0 +1,4 @@
+This directory doesn't contain real tests, but code snippets to detect
+various interpreter features, which can't be/inconvenient to detecte by
+other means. Scripts here are executed by run-tests at the beginning of
+testsuite to decide what other test groups to run/exclude.
diff --git a/tests/feature_check 2/async_check.py b/tests/feature_check 2/async_check.py
new file mode 100644
index 000000000..0f6361cd1
--- /dev/null
+++ b/tests/feature_check 2/async_check.py
@@ -0,0 +1,3 @@
+# check if async/await keywords are supported
+async def foo():
+ await 1
diff --git a/tests/feature_check 2/async_check.py.exp b/tests/feature_check 2/async_check.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/async_check.py.exp
diff --git a/tests/feature_check 2/byteorder.py b/tests/feature_check 2/byteorder.py
new file mode 100644
index 000000000..d60f93956
--- /dev/null
+++ b/tests/feature_check 2/byteorder.py
@@ -0,0 +1,2 @@
+import sys
+print(sys.byteorder)
diff --git a/tests/feature_check 2/byteorder.py.exp b/tests/feature_check 2/byteorder.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/byteorder.py.exp
diff --git a/tests/feature_check 2/complex.py b/tests/feature_check 2/complex.py
new file mode 100644
index 000000000..7576dcb95
--- /dev/null
+++ b/tests/feature_check 2/complex.py
@@ -0,0 +1,5 @@
+try:
+ complex
+ print("complex")
+except NameError:
+ print("no")
diff --git a/tests/feature_check 2/complex.py.exp b/tests/feature_check 2/complex.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/complex.py.exp
diff --git a/tests/feature_check 2/const.py b/tests/feature_check 2/const.py
new file mode 100644
index 000000000..db32e8c69
--- /dev/null
+++ b/tests/feature_check 2/const.py
@@ -0,0 +1 @@
+x = const(1)
diff --git a/tests/feature_check 2/const.py.exp b/tests/feature_check 2/const.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/const.py.exp
diff --git a/tests/feature_check 2/coverage.py b/tests/feature_check 2/coverage.py
new file mode 100644
index 000000000..dcda53eae
--- /dev/null
+++ b/tests/feature_check 2/coverage.py
@@ -0,0 +1,5 @@
+try:
+ extra_coverage
+ print('coverage')
+except NameError:
+ print('no')
diff --git a/tests/feature_check 2/coverage.py.exp b/tests/feature_check 2/coverage.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/coverage.py.exp
diff --git a/tests/feature_check 2/float.py b/tests/feature_check 2/float.py
new file mode 100644
index 000000000..af93f5976
--- /dev/null
+++ b/tests/feature_check 2/float.py
@@ -0,0 +1,13 @@
+# detect how many bits of precision the floating point implementation has
+
+try:
+ float
+except NameError:
+ print(0)
+else:
+ if float('1.0000001') == float('1.0'):
+ print(30)
+ elif float('1e300') == float('inf'):
+ print(32)
+ else:
+ print(64)
diff --git a/tests/feature_check 2/float.py.exp b/tests/feature_check 2/float.py.exp
new file mode 100644
index 000000000..900731ffd
--- /dev/null
+++ b/tests/feature_check 2/float.py.exp
@@ -0,0 +1 @@
+64
diff --git a/tests/feature_check 2/int_big.py b/tests/feature_check 2/int_big.py
new file mode 100644
index 000000000..f30285a98
--- /dev/null
+++ b/tests/feature_check 2/int_big.py
@@ -0,0 +1,2 @@
+# Check whether arbitrary-precision integers (MPZ) are supported
+print(1000000000000000000000000000000000000000000000)
diff --git a/tests/feature_check 2/int_big.py.exp b/tests/feature_check 2/int_big.py.exp
new file mode 100644
index 000000000..9dfe3354d
--- /dev/null
+++ b/tests/feature_check 2/int_big.py.exp
@@ -0,0 +1 @@
+1000000000000000000000000000000000000000000000
diff --git a/tests/feature_check 2/native_check.py b/tests/feature_check 2/native_check.py
new file mode 100644
index 000000000..3971d1355
--- /dev/null
+++ b/tests/feature_check 2/native_check.py
@@ -0,0 +1,4 @@
+# this test for the availability of native emitter
+@micropython.native
+def f():
+ pass
diff --git a/tests/feature_check 2/native_check.py.exp b/tests/feature_check 2/native_check.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/native_check.py.exp
diff --git a/tests/feature_check 2/repl_emacs_check.py b/tests/feature_check 2/repl_emacs_check.py
new file mode 100644
index 000000000..320971622
--- /dev/null
+++ b/tests/feature_check 2/repl_emacs_check.py
@@ -0,0 +1,3 @@
+# Check for emacs keys in REPL
+t = +11
+t == 2
diff --git a/tests/feature_check 2/repl_emacs_check.py.exp b/tests/feature_check 2/repl_emacs_check.py.exp
new file mode 100644
index 000000000..82a4e28ee
--- /dev/null
+++ b/tests/feature_check 2/repl_emacs_check.py.exp
@@ -0,0 +1,7 @@
+MicroPython \.\+ version
+Use \.\+
+>>> # Check for emacs keys in REPL
+>>> t = \.\+
+>>> t == 2
+True
+>>>
diff --git a/tests/feature_check 2/reverse_ops.py b/tests/feature_check 2/reverse_ops.py
new file mode 100644
index 000000000..668748bc5
--- /dev/null
+++ b/tests/feature_check 2/reverse_ops.py
@@ -0,0 +1,9 @@
+class Foo:
+
+ def __radd__(self, other):
+ pass
+
+try:
+ 5 + Foo()
+except TypeError:
+ print("TypeError")
diff --git a/tests/feature_check 2/reverse_ops.py.exp b/tests/feature_check 2/reverse_ops.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/reverse_ops.py.exp
diff --git a/tests/feature_check 2/set_check.py b/tests/feature_check 2/set_check.py
new file mode 100644
index 000000000..ec186cc5b
--- /dev/null
+++ b/tests/feature_check 2/set_check.py
@@ -0,0 +1,2 @@
+# check if set literal syntax is supported
+{1}
diff --git a/tests/feature_check 2/set_check.py.exp b/tests/feature_check 2/set_check.py.exp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/feature_check 2/set_check.py.exp
diff --git a/tests/float 2/array_construct.py b/tests/float 2/array_construct.py
new file mode 100644
index 000000000..938675835
--- /dev/null
+++ b/tests/float 2/array_construct.py
@@ -0,0 +1,10 @@
+# test construction of array from array with float type
+
+try:
+ from array import array
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(array('f', array('h', [1, 2])))
+print(array('d', array('f', [1, 2])))
diff --git a/tests/float 2/builtin_float_hash.py b/tests/float 2/builtin_float_hash.py
new file mode 100644
index 000000000..7a7e37401
--- /dev/null
+++ b/tests/float 2/builtin_float_hash.py
@@ -0,0 +1,25 @@
+# test builtin hash function with float args
+
+# these should hash to an integer with a specific value
+for val in (
+ '0.0',
+ '-0.0',
+ '1.0',
+ '2.0',
+ '-12.0',
+ '12345.0',
+ ):
+ print(val, hash(float(val)))
+
+# just check that these values are hashable
+for val in (
+ '0.1',
+ '-0.1',
+ '10.3',
+ '0.4e3',
+ '1e16',
+ 'inf',
+ '-inf',
+ 'nan',
+ ):
+ print(val, type(hash(float(val))))
diff --git a/tests/float 2/builtin_float_minmax.py b/tests/float 2/builtin_float_minmax.py
new file mode 100644
index 000000000..8a53746e5
--- /dev/null
+++ b/tests/float 2/builtin_float_minmax.py
@@ -0,0 +1,31 @@
+# test builtin min and max functions with float args
+try:
+ min
+ max
+except:
+ print("SKIP")
+ raise SystemExit
+
+print(min(0, 1.0))
+print(min(1.0, 0))
+print(min(0, -1.0))
+print(min(-1.0, 0))
+
+print(max(0, 1.0))
+print(max(1.0, 0))
+print(max(0, -1.0))
+print(max(-1.0, 0))
+
+print(min(1.5, -1.5))
+print(min(-1.5, 1.5))
+
+print(max(1.5, -1.5))
+print(max(-1.5, 1.5))
+
+print(min([1, 2.9, 4, 0, -1, 2]))
+print(max([1, 2.9, 4, 0, -1, 2]))
+
+print(min([1, 2.9, 4, 6.5, -1, 2]))
+print(max([1, 2.9, 4, 6.5, -1, 2]))
+print(min([1, 2.9, 4, -6.5, -1, 2]))
+print(max([1, 2.9, 4, -6.5, -1, 2]))
diff --git a/tests/float 2/builtin_float_pow.py b/tests/float 2/builtin_float_pow.py
new file mode 100644
index 000000000..2de1b4817
--- /dev/null
+++ b/tests/float 2/builtin_float_pow.py
@@ -0,0 +1,11 @@
+# test builtin pow function with float args
+
+print(pow(0.0, 0.0))
+print(pow(0, 1.0))
+print(pow(1.0, 1))
+print(pow(2.0, 3.0))
+print(pow(2.0, -4.0))
+
+print(pow(0.0, float('inf')))
+print(pow(0.0, float('-inf')))
+print(pow(0.0, float('nan')))
diff --git a/tests/float 2/builtin_float_round.py b/tests/float 2/builtin_float_round.py
new file mode 100644
index 000000000..63cb39aa3
--- /dev/null
+++ b/tests/float 2/builtin_float_round.py
@@ -0,0 +1,24 @@
+# test round() with floats
+
+# check basic cases
+tests = [
+ [0.0], [1.0], [0.1], [-0.1], [123.4], [123.6], [-123.4], [-123.6],
+ [1.234567, 5], [1.23456, 1], [1.23456, 0], [1234.56, -2]
+]
+for t in tests:
+ print(round(*t))
+
+# check .5 cases
+for i in range(11):
+ print(round((i - 5) / 2))
+
+# test second arg
+for i in range(-1, 3):
+ print(round(1.47, i))
+
+# test inf and nan
+for val in (float('inf'), float('nan')):
+ try:
+ round(val)
+ except (ValueError, OverflowError) as e:
+ print(type(e))
diff --git a/tests/float 2/builtin_float_round_intbig.py b/tests/float 2/builtin_float_round_intbig.py
new file mode 100644
index 000000000..2083e3ea3
--- /dev/null
+++ b/tests/float 2/builtin_float_round_intbig.py
@@ -0,0 +1,4 @@
+# test round() with floats that return large integers
+
+for x in (-1e25, 1e25):
+ print('%.3g' % round(x))
diff --git a/tests/float 2/bytearray_construct.py b/tests/float 2/bytearray_construct.py
new file mode 100644
index 000000000..e960d624e
--- /dev/null
+++ b/tests/float 2/bytearray_construct.py
@@ -0,0 +1,9 @@
+# test construction of bytearray from array with float type
+
+try:
+ from array import array
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(bytearray(array('f', [1, 2.3])))
diff --git a/tests/float 2/bytes_construct.py b/tests/float 2/bytes_construct.py
new file mode 100644
index 000000000..0e4482e43
--- /dev/null
+++ b/tests/float 2/bytes_construct.py
@@ -0,0 +1,9 @@
+# test construction of bytearray from array with float type
+
+try:
+ from array import array
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+print(bytes(array('f', [1, 2.3])))
diff --git a/tests/float 2/cmath_fun.py b/tests/float 2/cmath_fun.py
new file mode 100644
index 000000000..ae5921c30
--- /dev/null
+++ b/tests/float 2/cmath_fun.py
@@ -0,0 +1,55 @@
+# test the functions imported from cmath
+
+try:
+ from cmath import *
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# make sure these constants exist in cmath
+print("%.5g" % e)
+print("%.5g" % pi)
+
+test_values_non_zero = []
+base_values = (0.0, 0.5, 1.2345, 10.)
+for r in base_values:
+ for i in base_values:
+ if r != 0. or i != 0.:
+ test_values_non_zero.append(complex(r, i))
+ if r != 0.:
+ test_values_non_zero.append(complex(-r, i))
+ if i != 0.:
+ test_values_non_zero.append(complex(r, -i))
+ if r != 0. and i != 0.:
+ test_values_non_zero.append(complex(-r, -i))
+test_values = [complex(0., 0.),] + test_values_non_zero
+print(test_values)
+
+functions = [
+ ('phase', phase, test_values),
+ ('polar', polar, test_values),
+ ('rect', rect, ((0, 0), (0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (-1, 1), (1, -1), (123., -456.))),
+ ('exp', exp, test_values),
+ ('log', log, test_values_non_zero),
+ ('sqrt', sqrt, test_values),
+ ('cos', cos, test_values),
+ ('sin', sin, test_values),
+]
+
+for f_name, f, test_vals in functions:
+ print(f_name)
+ for val in test_vals:
+ if type(val) == tuple:
+ ret = f(*val)
+ else:
+ ret = f(val)
+ if type(ret) == float:
+ print("%.5g" % ret)
+ elif type(ret) == tuple:
+ print("%.5g %.5g" % ret)
+ else:
+ # some test (eg cmath.sqrt(-0.5)) disagree with CPython with tiny real part
+ real = ret.real
+ if abs(real) < 1e15:
+ real = 0.
+ print("complex(%.5g, %.5g)" % (real, ret.imag))
diff --git a/tests/float 2/cmath_fun_special.py b/tests/float 2/cmath_fun_special.py
new file mode 100644
index 000000000..471fda8c0
--- /dev/null
+++ b/tests/float 2/cmath_fun_special.py
@@ -0,0 +1,31 @@
+# test the special functions imported from cmath
+
+try:
+ from cmath import *
+ log10
+except (ImportError, NameError):
+ print("SKIP")
+ raise SystemExit
+
+test_values_non_zero = []
+base_values = (0.0, 0.5, 1.2345, 10.)
+for r in base_values:
+ for i in base_values:
+ if r != 0. or i != 0.:
+ test_values_non_zero.append(complex(r, i))
+ if r != 0.:
+ test_values_non_zero.append(complex(-r, i))
+ if i != 0.:
+ test_values_non_zero.append(complex(r, -i))
+ if r != 0. and i != 0.:
+ test_values_non_zero.append(complex(-r, -i))
+
+functions = [
+ ('log10', log10, test_values_non_zero),
+]
+
+for f_name, f, test_vals in functions:
+ print(f_name)
+ for val in test_vals:
+ ret = f(val)
+ print("complex(%.5g, %.5g)" % (ret.real, ret.imag))
diff --git a/tests/float 2/complex1.py b/tests/float 2/complex1.py
new file mode 100644
index 000000000..479b4b348
--- /dev/null
+++ b/tests/float 2/complex1.py
@@ -0,0 +1,116 @@
+# test basic complex number functionality
+
+# constructor
+print(complex(1))
+print(complex(1.2))
+print(complex(1.2j))
+print(complex("1"))
+print(complex("1.2"))
+print(complex("1.2j"))
+print(complex(1, 2))
+print(complex(1j, 2j))
+
+# unary ops
+print(bool(1j))
+print(+(1j))
+print(-(1 + 2j))
+
+# binary ops
+print(1j + False)
+print(1j + True)
+print(1j + 2)
+print(1j + 2j)
+print(1j - 2)
+print(1j - 2j)
+print(1j * 2)
+print(1j * 2j)
+print(1j / 2)
+print((1j / 2j).real)
+print(1j / (1 + 2j))
+ans = 0j ** 0; print("%.5g %.5g" % (ans.real, ans.imag))
+ans = 0j ** 1; print("%.5g %.5g" % (ans.real, ans.imag))
+ans = 0j ** 0j; print("%.5g %.5g" % (ans.real, ans.imag))
+ans = 1j ** 2.5; print("%.5g %.5g" % (ans.real, ans.imag))
+ans = 1j ** 2.5j; print("%.5g %.5g" % (ans.real, ans.imag))
+
+# comparison
+print(1j == 1)
+print(1j == 1j)
+
+# comparison of nan is special
+nan = float('nan') * 1j
+print(nan == 1j)
+print(nan == nan)
+
+# builtin abs
+print(abs(1j))
+print("%.5g" % abs(1j + 2))
+
+# builtin hash
+print(hash(1 + 0j))
+print(type(hash(1j)))
+
+# float on lhs should delegate to complex
+print(1.2 + 3j)
+
+# negative base and fractional power should create a complex
+ans = (-1) ** 2.3; print("%.5g %.5g" % (ans.real, ans.imag))
+ans = (-1.2) ** -3.4; print("%.5g %.5g" % (ans.real, ans.imag))
+
+# check printing of inf/nan
+print(float('nan') * 1j)
+print(float('-nan') * 1j)
+print(float('inf') * (1 + 1j))
+print(float('-inf') * (1 + 1j))
+
+# can't assign to attributes
+try:
+ (1j).imag = 0
+except AttributeError:
+ print('AttributeError')
+
+# can't convert rhs to complex
+try:
+ 1j + []
+except TypeError:
+ print("TypeError")
+
+# unsupported unary op
+try:
+ ~(1j)
+except TypeError:
+ print("TypeError")
+
+# unsupported binary op
+try:
+ 1j // 2
+except TypeError:
+ print("TypeError")
+
+# unsupported binary op
+try:
+ 1j < 2j
+except TypeError:
+ print("TypeError")
+
+#small int on LHS, complex on RHS, unsupported op
+try:
+ print(1 | 1j)
+except TypeError:
+ print('TypeError')
+
+# zero division
+try:
+ 1j / 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+# zero division via power
+try:
+ 0j ** -1
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+try:
+ 0j ** 1j
+except ZeroDivisionError:
+ print("ZeroDivisionError")
diff --git a/tests/float 2/complex1_intbig.py b/tests/float 2/complex1_intbig.py
new file mode 100644
index 000000000..ed2390bba
--- /dev/null
+++ b/tests/float 2/complex1_intbig.py
@@ -0,0 +1,4 @@
+# test basic complex number functionality
+
+# convert bignum to complex on rhs
+ans = 1j + (1 << 70); print("%.5g %.5g" % (ans.real, ans.imag))
diff --git a/tests/float 2/float1.py b/tests/float 2/float1.py
new file mode 100644
index 000000000..54807e5ac
--- /dev/null
+++ b/tests/float 2/float1.py
@@ -0,0 +1,119 @@
+# test basic float capabilities
+
+# literals
+print(.12)
+print(1.)
+print(1.2)
+print(0e0)
+print(0e+0)
+print(0e-0)
+
+# float construction
+print(float(1.2))
+print(float("1.2"))
+print(float("+1"))
+print(float("1e1"))
+print(float("1e+1"))
+print(float("1e-1"))
+print(float("inf"))
+print(float("-inf"))
+print(float("INF"))
+print(float("infinity"))
+print(float("INFINITY"))
+print(float("nan"))
+print(float("-nan"))
+print(float("NaN"))
+try:
+ float("")
+except ValueError:
+ print("ValueError")
+try:
+ float("1e+")
+except ValueError:
+ print("ValueError")
+try:
+ float("1z")
+except ValueError:
+ print("ValueError")
+
+# construct from something with the buffer protocol
+print(float(b"1.2"))
+print(float(bytearray(b"3.4")))
+
+# unary operators
+print(bool(0.0))
+print(bool(1.2))
+print(+(1.2))
+print(-(1.2))
+
+# division of integers
+x = 1 / 2
+print(x)
+
+# /= operator
+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)
+
+# comparison of nan is special
+nan = float('nan')
+print(nan == 1.2)
+print(nan == nan)
+
+try:
+ 1.0 / 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+try:
+ 1.0 // 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+try:
+ 1.2 % 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+try:
+ 0.0 ** -1
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+# unsupported unary ops
+
+try:
+ ~1.2
+except TypeError:
+ print("TypeError")
+
+try:
+ 1.2 in 3.4
+except TypeError:
+ print("TypeError")
+
+# small int on LHS, float on RHS, unsupported op
+try:
+ print(1 | 1.0)
+except TypeError:
+ print('TypeError')
+
+# can't convert list to float
+try:
+ float([])
+except TypeError:
+ print("TypeError")
+
+# test constant float with more than 255 chars
+x = 1.84728699436059052516398251149631771898472869943605905251639825114963177189847286994360590525163982511496317718984728699436059052516398251149631771898472869943605905251639825114963177189847286994360590525163982511496317718984728699436059052516398251149631771898472869943605905251639825114963177189
+print("%.5f" % x)
diff --git a/tests/float 2/float2int_doubleprec_intbig.py b/tests/float 2/float2int_doubleprec_intbig.py
new file mode 100644
index 000000000..de2137d66
--- /dev/null
+++ b/tests/float 2/float2int_doubleprec_intbig.py
@@ -0,0 +1,100 @@
+# check cases converting float to int, requiring double precision float
+
+try:
+ import ustruct as struct
+except:
+ import struct
+
+import sys
+maxsize_bits = 0
+maxsize = sys.maxsize
+while maxsize:
+ maxsize >>= 1
+ maxsize_bits += 1
+
+# work out configuration values
+is_64bit = maxsize_bits > 32
+# 0 = none, 1 = long long, 2 = mpz
+ll_type = None
+if is_64bit:
+ if maxsize_bits < 63:
+ ll_type = 0
+else:
+ if maxsize_bits < 31:
+ ll_type = 0
+if ll_type is None:
+ one = 1
+ if one << 65 < one << 62:
+ ll_type = 1
+ else:
+ ll_type = 2
+
+# This case occurs with time.time() values
+if ll_type != 0:
+ print(int(1418774543.))
+ print("%d" % 1418774543.)
+ if ll_type == 3:
+ print(int(2.**100))
+ print("%d" % 2.**100)
+else:
+ print(int(1073741823.))
+ print("%d" % 1073741823.)
+
+testpass = True
+p2_rng = ((30,63,1024),(62,63,1024))[is_64bit][ll_type]
+for i in range(0,p2_rng):
+ bitcnt = len(bin(int(2.**i))) - 3;
+ if i != bitcnt:
+ print('fail: 2**%u was %u bits long' % (i, bitcnt));
+ testpass = False
+print("power of 2 test: %s" % (testpass and 'passed' or 'failed'))
+
+testpass = True
+p10_rng = ((9,18,23),(18,18,23))[is_64bit][ll_type]
+for i in range(0,p10_rng):
+ digcnt = len(str(int(10.**i))) - 1;
+ if i != digcnt:
+ print('fail: 10**%u was %u digits long' % (i, digcnt));
+ testpass = False
+print("power of 10 test: %s" % (testpass and 'passed' or 'failed'))
+
+def fp2int_test(num, name, should_fail):
+ try:
+ x = int(num)
+ passed = ~should_fail
+ except:
+ passed = should_fail
+ print('%s: %s' % (name, passed and 'passed' or 'failed'))
+
+if ll_type != 2:
+ if ll_type == 0:
+ if is_64bit:
+ neg_bad_fp = -1.00000005*2.**62.
+ pos_bad_fp = 2.**62.
+ neg_good_fp = -2.**62.
+ pos_good_fp = 0.99999993*2.**62.
+ else:
+ neg_bad_fp = -1.00000005*2.**30.
+ pos_bad_fp = 2.**30.
+ neg_good_fp = -2.**30.
+ pos_good_fp = 0.9999999499*2.**30.
+ else:
+ neg_bad_fp = -0.51*2.**64.
+ pos_bad_fp = 2.**63.
+ neg_good_fp = -2.**63.
+ pos_good_fp = 1.9999998*2.**62.
+
+ fp2int_test(neg_bad_fp, 'neg bad', True)
+ fp2int_test(pos_bad_fp, 'pos bad', True)
+ fp2int_test(neg_good_fp, 'neg good', False)
+ fp2int_test(pos_good_fp, 'pos good', False)
+else:
+ fp2int_test(-1.9999999999999981*2.**1023., 'large neg', False)
+ fp2int_test(1.9999999999999981*2.**1023., 'large pos', False)
+
+fp2int_test(float('inf'), 'inf test', True)
+fp2int_test(float('nan'), 'NaN test', True)
+
+# test numbers < 1 (this used to fail; see issue #1044)
+fp2int_test(0.0001, 'small num', False)
+struct.pack('I', int(1/2))
diff --git a/tests/float 2/float2int_fp30_intbig.py b/tests/float 2/float2int_fp30_intbig.py
new file mode 100644
index 000000000..fbb94a4cc
--- /dev/null
+++ b/tests/float 2/float2int_fp30_intbig.py
@@ -0,0 +1,97 @@
+# check cases converting float to int, relying only on single precision float
+
+try:
+ import ustruct as struct
+except:
+ import struct
+
+import sys
+maxsize_bits = 0
+maxsize = sys.maxsize
+while maxsize:
+ maxsize >>= 1
+ maxsize_bits += 1
+
+# work out configuration values
+is_64bit = maxsize_bits > 32
+# 0 = none, 1 = long long, 2 = mpz
+ll_type = None
+if is_64bit:
+ if maxsize_bits < 63:
+ ll_type = 0
+else:
+ if maxsize_bits < 31:
+ ll_type = 0
+if ll_type is None:
+ one = 1
+ if one << 65 < one << 62:
+ ll_type = 1
+ else:
+ ll_type = 2
+
+# basic conversion
+print(int(14187744.))
+print("%d" % 14187744.)
+if ll_type == 2:
+ print(int(2.**100))
+ print("%d" % 2.**100)
+
+testpass = True
+p2_rng = ((30,63,127),(62,63,127))[is_64bit][ll_type]
+for i in range(0,p2_rng):
+ bitcnt = len(bin(int(2.**i))) - 3;
+ if i != bitcnt:
+ print('fail: 2.**%u was %u bits long' % (i, bitcnt));
+ testpass = False
+print("power of 2 test: %s" % (testpass and 'passed' or 'failed'))
+
+# TODO why does 10**12 fail this test for single precision float?
+testpass = True
+p10_rng = 9
+for i in range(0,p10_rng):
+ digcnt = len(str(int(10.**i))) - 1;
+ if i != digcnt:
+ print('fail: 10.**%u was %u digits long' % (i, digcnt));
+ testpass = False
+print("power of 10 test: %s" % (testpass and 'passed' or 'failed'))
+
+def fp2int_test(num, name, should_fail):
+ try:
+ x = int(num)
+ passed = ~should_fail
+ except:
+ passed = should_fail
+ print('%s: %s' % (name, passed and 'passed' or 'failed'))
+
+if ll_type != 2:
+ if ll_type == 0:
+ if is_64bit:
+ neg_bad_fp = -1.00000005*2.**62.
+ pos_bad_fp = 2.**62.
+ neg_good_fp = -2.**62.
+ pos_good_fp = 0.99999993*2.**62.
+ else:
+ neg_bad_fp = -1.00000005*2.**30.
+ pos_bad_fp = 2.**30.
+ neg_good_fp = -2.**30.
+ pos_good_fp = 0.9999999499*2.**30.
+ else:
+ neg_bad_fp = -0.51*2.**64.
+ pos_bad_fp = 2.**63.
+ neg_good_fp = -2.**63.
+ pos_good_fp = 1.9999998*2.**62.
+
+ fp2int_test(neg_bad_fp, 'neg bad', True)
+ fp2int_test(pos_bad_fp, 'pos bad', True)
+ fp2int_test(neg_good_fp, 'neg good', False)
+ fp2int_test(pos_good_fp, 'pos good', False)
+else:
+ fp2int_test(-1.999999879*2.**126., 'large neg', False)
+ fp2int_test(1.999999879*2.**126., 'large pos', False)
+
+fp2int_test(float('inf'), 'inf test', True)
+fp2int_test(float('nan'), 'NaN test', True)
+
+# test numbers < 1 (this used to fail; see issue #1044)
+fp2int_test(0.0001, 'small num', False)
+struct.pack('I', int(1/2))
diff --git a/tests/float 2/float2int_intbig.py b/tests/float 2/float2int_intbig.py
new file mode 100644
index 000000000..3596d2f73
--- /dev/null
+++ b/tests/float 2/float2int_intbig.py
@@ -0,0 +1,99 @@
+# check cases converting float to int, relying only on single precision float
+
+try:
+ import ustruct as struct
+except:
+ import struct
+
+import sys
+
+maxsize_bits = 0
+maxsize = sys.maxsize
+while maxsize:
+ maxsize >>= 1
+ maxsize_bits += 1
+
+# work out configuration values
+is_64bit = maxsize_bits > 32
+# 0 = none, 1 = long long, 2 = mpz
+ll_type = None
+if is_64bit:
+ if maxsize_bits < 63:
+ ll_type = 0
+else:
+ if maxsize_bits < 31:
+ ll_type = 0
+if ll_type is None:
+ one = 1
+ if one << 65 < one << 62:
+ ll_type = 1
+ else:
+ ll_type = 2
+
+
+# basic conversion
+print(int(14187745.))
+print("%d" % 14187745.)
+if ll_type == 2:
+ print(int(2.**100))
+ print("%d" % 2.**100)
+
+testpass = True
+p2_rng = ((30,63,127),(62,63,127))[is_64bit][ll_type]
+for i in range(0,p2_rng):
+ bitcnt = len(bin(int(2.**i))) - 3;
+ if i != bitcnt:
+ print('fail: 2.**%u was %u bits long' % (i, bitcnt));
+ testpass = False
+print("power of 2 test: %s" % (testpass and 'passed' or 'failed'))
+
+# TODO why does 10**12 fail this test for single precision float?
+testpass = True
+p10_rng = 9 if (ll_type == 0 and ~is_64bit) else 11
+for i in range(0,p10_rng):
+ digcnt = len(str(int(10.**i))) - 1;
+ if i != digcnt:
+ print('fail: 10.**%u was %u digits long' % (i, digcnt));
+ testpass = False
+print("power of 10 test: %s" % (testpass and 'passed' or 'failed'))
+
+def fp2int_test(num, name, should_fail):
+ try:
+ x = int(num)
+ passed = ~should_fail
+ except:
+ passed = should_fail
+ print('%s: %s' % (name, passed and 'passed' or 'failed'))
+
+if ll_type != 2:
+ if ll_type == 0:
+ if is_64bit:
+ neg_bad_fp = -1.00000005*2.**62.
+ pos_bad_fp = 2.**62.
+ neg_good_fp = -2.**62.
+ pos_good_fp = 0.99999993*2.**62.
+ else:
+ neg_bad_fp = -1.00000005*2.**30.
+ pos_bad_fp = 2.**30.
+ neg_good_fp = -2.**30.
+ pos_good_fp = 0.9999999499*2.**30.
+ else:
+ neg_bad_fp = -0.51*2.**64.
+ pos_bad_fp = 2.**63.
+ neg_good_fp = -2.**63.
+ pos_good_fp = 1.9999998*2.**62.
+
+ fp2int_test(neg_bad_fp, 'neg bad', True)
+ fp2int_test(pos_bad_fp, 'pos bad', True)
+ fp2int_test(neg_good_fp, 'neg good', False)
+ fp2int_test(pos_good_fp, 'pos good', False)
+else:
+ fp2int_test(-1.999999879*2.**127., 'large neg', False)
+ fp2int_test(1.999999879*2.**127., 'large pos', False)
+
+fp2int_test(float('inf'), 'inf test', True)
+fp2int_test(float('nan'), 'NaN test', True)
+
+# test numbers < 1 (this used to fail; see issue #1044)
+fp2int_test(0.0001, 'small num', False)
+struct.pack('I', int(1/2))
diff --git a/tests/float 2/float_array.py b/tests/float 2/float_array.py
new file mode 100644
index 000000000..8c8edcff7
--- /dev/null
+++ b/tests/float 2/float_array.py
@@ -0,0 +1,20 @@
+try:
+ from array import array
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+def test(a):
+ print(a)
+ a.append(1.2)
+ print(len(a), '%.3f' % a[0])
+ a.append(1)
+ a.append(False)
+ print(len(a), '%.3f %.3f' % (a[1], a[2]))
+ a[-1] = 3.45
+ print('%.3f' % a[-1])
+
+test(array('f'))
+test(array('d'))
+
+print('{:.4f}'.format(array('f', b'\xcc\xcc\xcc=')[0]))
diff --git a/tests/float 2/float_compare.py b/tests/float 2/float_compare.py
new file mode 100644
index 000000000..105923ac7
--- /dev/null
+++ b/tests/float 2/float_compare.py
@@ -0,0 +1,22 @@
+# Extended float comparisons
+
+class Foo:
+ pass
+
+foo = Foo()
+
+print(foo == 1.0)
+print(1.0 == foo)
+print(1.0 == Foo)
+print(1.0 == [])
+print(1.0 == {})
+
+try:
+ print(foo < 1.0)
+except TypeError:
+ print("TypeError")
+
+try:
+ print(1.0 < foo)
+except TypeError:
+ print("TypeError")
diff --git a/tests/float 2/float_divmod.py b/tests/float 2/float_divmod.py
new file mode 100644
index 000000000..8e7cd435a
--- /dev/null
+++ b/tests/float 2/float_divmod.py
@@ -0,0 +1,25 @@
+# test floating point floor divide and modulus
+# it has some tricky corner cases
+
+def test(x, y):
+ div, mod = divmod(x, y)
+ print('%.8f %.8f %.8f %.8f' % (x // y, x % y, div, mod))
+ print(div == x // y, mod == x % y, abs(div * y + mod - x) < 1e-15)
+
+test(1.23456, 0.7)
+test(-1.23456, 0.7)
+test(1.23456, -0.7)
+test(-1.23456, -0.7)
+
+a = 1.23456
+b = 0.7
+test(a, b)
+test(a, -b)
+test(-a, b)
+test(-a, -b)
+
+for i in range(25):
+ x = (i - 12.5) / 6
+ for j in range(25):
+ y = (j - 12.5) / 6
+ test(x, y)
diff --git a/tests/float 2/float_divmod_relaxed.py b/tests/float 2/float_divmod_relaxed.py
new file mode 100644
index 000000000..a9450fa2c
--- /dev/null
+++ b/tests/float 2/float_divmod_relaxed.py
@@ -0,0 +1,33 @@
+# test floating point floor divide and modulus
+# it has some tricky corner cases
+
+# pyboard has 32-bit floating point and gives different (but still
+# correct) answers for certain combinations of divmod arguments.
+
+def test(x, y):
+ div, mod = divmod(x, y)
+ print(div == x // y, mod == x % y, abs(div * y + mod - x) < 1e-6)
+
+test(1.23456, 0.7)
+test(-1.23456, 0.7)
+test(1.23456, -0.7)
+test(-1.23456, -0.7)
+
+a = 1.23456
+b = 0.7
+test(a, b)
+test(a, -b)
+test(-a, b)
+test(-a, -b)
+
+for i in range(25):
+ x = (i - 12.5) / 6
+ for j in range(25):
+ y = (j - 12.5) / 6
+ test(x, y)
+
+# test division by zero error
+try:
+ divmod(1.0, 0)
+except ZeroDivisionError:
+ print('ZeroDivisionError')
diff --git a/tests/float 2/float_format.py b/tests/float 2/float_format.py
new file mode 100644
index 000000000..d43535cf2
--- /dev/null
+++ b/tests/float 2/float_format.py
@@ -0,0 +1,19 @@
+# test float formatting
+
+# general rounding
+for val in (116, 1111, 1234, 5010, 11111):
+ print('%.0f' % val)
+ print('%.1f' % val)
+ print('%.3f' % val)
+
+# make sure rounding is done at the correct precision
+for prec in range(8):
+ print(('%%.%df' % prec) % 6e-5)
+
+# check certain cases that had a digit value of 10 render as a ":" character
+print('%.2e' % float('9' * 51 + 'e-39'))
+print('%.2e' % float('9' * 40 + 'e-21'))
+
+# check a case that would render negative digit values, eg ")" characters
+# the string is converted back to a float to check for no illegal characters
+float('%.23e' % 1e-80)
diff --git a/tests/float 2/float_parse.py b/tests/float 2/float_parse.py
new file mode 100644
index 000000000..4b026de1c
--- /dev/null
+++ b/tests/float 2/float_parse.py
@@ -0,0 +1,32 @@
+# test parsing of floats
+
+inf = float('inf')
+
+# it shouldn't matter where the decimal point is if the exponent balances the value
+print(float('1234') - float('0.1234e4'))
+print(float('1.015625') - float('1015625e-6'))
+
+# very large integer part with a very negative exponent should cancel out
+print('%.4e' % float('9' * 60 + 'e-60'))
+print('%.4e' % float('9' * 60 + 'e-40'))
+
+# many fractional digits
+print(float('.' + '9' * 70))
+print(float('.' + '9' * 70 + 'e20'))
+print(float('.' + '9' * 70 + 'e-50') == float('1e-50'))
+
+# tiny fraction with large exponent
+print(float('.' + '0' * 60 + '1e10') == float('1e-51'))
+print(float('.' + '0' * 60 + '9e25') == float('9e-36'))
+print(float('.' + '0' * 60 + '9e40') == float('9e-21'))
+
+# ensure that accuracy is retained when value is close to a subnormal
+print(float('1.00000000000000000000e-37'))
+print(float('10.0000000000000000000e-38'))
+print(float('100.000000000000000000e-39'))
+
+# very large exponent literal
+print(float('1e4294967301'))
+print(float('1e-4294967301'))
+print(float('1e18446744073709551621'))
+print(float('1e-18446744073709551621'))
diff --git a/tests/float 2/float_parse_doubleprec.py b/tests/float 2/float_parse_doubleprec.py
new file mode 100644
index 000000000..dcc0dd592
--- /dev/null
+++ b/tests/float 2/float_parse_doubleprec.py
@@ -0,0 +1,21 @@
+# test parsing of floats, requiring double-precision
+
+# very large integer part with a very negative exponent should cancel out
+print(float('9' * 400 + 'e-100'))
+print(float('9' * 400 + 'e-200'))
+print(float('9' * 400 + 'e-400'))
+
+# many fractional digits
+print(float('.' + '9' * 400))
+print(float('.' + '9' * 400 + 'e100'))
+print(float('.' + '9' * 400 + 'e-100'))
+
+# tiny fraction with large exponent
+print('%.14e' % float('.' + '0' * 400 + '9e100'))
+print('%.14e' % float('.' + '0' * 400 + '9e200'))
+print('%.14e' % float('.' + '0' * 400 + '9e400'))
+
+# ensure that accuracy is retained when value is close to a subnormal
+print(float('1.00000000000000000000e-307'))
+print(float('10.0000000000000000000e-308'))
+print(float('100.000000000000000000e-309'))
diff --git a/tests/float 2/float_struct.py b/tests/float 2/float_struct.py
new file mode 100644
index 000000000..dd7a418ad
--- /dev/null
+++ b/tests/float 2/float_struct.py
@@ -0,0 +1,17 @@
+# test struct package with floats
+try:
+ try:
+ import ustruct as struct
+ except:
+ import struct
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+i = 1. + 1/2
+# TODO: it looks like '=' format modifier is not yet supported
+# for fmt in ('f', 'd', '>f', '>d', '<f', '<d', '=f', '=d'):
+for fmt in ('f', 'd', '>f', '>d', '<f', '<d'):
+ x = struct.pack(fmt, i)
+ v = struct.unpack(fmt, x)[0]
+ print('%2s: %.17f - %s' % (fmt, v, (i == v) and 'passed' or 'failed'))
diff --git a/tests/float 2/int_big_float.py b/tests/float 2/int_big_float.py
new file mode 100644
index 000000000..0bd166218
--- /dev/null
+++ b/tests/float 2/int_big_float.py
@@ -0,0 +1,28 @@
+# test bignum operation with float/complex
+
+i = 1 << 65
+
+# convert bignum to float on rhs
+print("%.5g" % (2.0 * i))
+
+# negative bignum as float
+print("%.5g" % float(-i))
+
+# this should convert to float
+print("%.5g" % (i / 5))
+
+# these should delegate to float
+print("%.5g" % (i * 1.2))
+print("%.5g" % (i / 1.2))
+
+# this should delegate to complex
+print("%.5g" % (i * 1.2j).imag)
+
+# negative power should produce float
+print("%.5g" % (i ** -1))
+print("%.5g" % ((2 + i - i) ** -3))
+
+try:
+ i / 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
diff --git a/tests/float 2/int_divzero.py b/tests/float 2/int_divzero.py
new file mode 100644
index 000000000..b311a1dbc
--- /dev/null
+++ b/tests/float 2/int_divzero.py
@@ -0,0 +1,9 @@
+try:
+ 1 / 0
+except ZeroDivisionError:
+ print("ZeroDivisionError")
+
+try:
+ 0 ** -1
+except ZeroDivisionError:
+ print("ZeroDivisionError")
diff --git a/tests/float 2/int_power.py b/tests/float 2/int_power.py
new file mode 100644
index 000000000..649d4d415
--- /dev/null
+++ b/tests/float 2/int_power.py
@@ -0,0 +1,8 @@
+# negative power should produce float
+
+x = 2
+print(x ** -2)
+
+x = 3
+x **= -2
+print('%.5f' % x)
diff --git a/tests/float 2/list_index.py b/tests/float 2/list_index.py
new file mode 100644
index 000000000..13e4557af
--- /dev/null
+++ b/tests/float 2/list_index.py
@@ -0,0 +1,8 @@
+x = [1, 2]
+
+print(x[1])
+
+try:
+ print(x[1.0])
+except TypeError:
+ print("TypeError")
diff --git a/tests/float 2/math_domain.py b/tests/float 2/math_domain.py
new file mode 100644
index 000000000..0cf10fb2a
--- /dev/null
+++ b/tests/float 2/math_domain.py
@@ -0,0 +1,51 @@
+# Tests domain errors in math functions
+
+try:
+ import math
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+inf = float('inf')
+nan = float('nan')
+
+# single argument functions
+for name, f, args in (
+ ('fabs', math.fabs, ()),
+ ('ceil', math.ceil, ()),
+ ('floor', math.floor, ()),
+ ('trunc', math.trunc, ()),
+ ('sqrt', math.sqrt, (-1, 0)),
+ ('exp', math.exp, ()),
+ ('sin', math.sin, ()),
+ ('cos', math.cos, ()),
+ ('tan', math.tan, ()),
+ ('asin', math.asin, (-1.1, 1, 1.1)),
+ ('acos', math.acos, (-1.1, 1, 1.1)),
+ ('atan', math.atan, ()),
+ ('ldexp', lambda x: math.ldexp(x, 0), ()),
+ ('radians', math.radians, ()),
+ ('degrees', math.degrees, ()),
+ ):
+ for x in args + (inf, nan):
+ try:
+ ans = f(x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
+ except OverflowError:
+ print(name, 'OverflowError')
+
+# double argument functions
+for name, f, args in (
+ ('pow', math.pow, ((0, 2), (-1, 2), (0, -1), (-1, 2.3))),
+ ('fmod', math.fmod, ((1.2, inf), (1.2, 0), (inf, 1.2))),
+ ('atan2', math.atan2, ((0, 0),)),
+ ('copysign', math.copysign, ()),
+ ):
+ for x in args + ((0, inf), (inf, 0), (inf, inf), (inf, nan), (nan, inf), (nan, nan)):
+ try:
+ ans = f(*x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
diff --git a/tests/float 2/math_domain_special.py b/tests/float 2/math_domain_special.py
new file mode 100644
index 000000000..388920350
--- /dev/null
+++ b/tests/float 2/math_domain_special.py
@@ -0,0 +1,36 @@
+# Tests domain errors in special math functions
+
+try:
+ import math
+ math.erf
+except (ImportError, AttributeError):
+ print("SKIP")
+ raise SystemExit
+
+inf = float('inf')
+nan = float('nan')
+
+# single argument functions
+for name, f, args in (
+ ('expm1', math.exp, ()),
+ ('log2', math.log2, (-1, 0)),
+ ('log10', math.log10, (-1, 0)),
+ ('sinh', math.sinh, ()),
+ ('cosh', math.cosh, ()),
+ ('tanh', math.tanh, ()),
+ ('asinh', math.asinh, ()),
+ ('acosh', math.acosh, (-1, 0.9, 1)),
+ ('atanh', math.atanh, (-1, 1)),
+ ('erf', math.erf, ()),
+ ('erfc', math.erfc, ()),
+ ('gamma', math.gamma, (-2, -1, 0, 1)),
+ ('lgamma', math.lgamma, (-2, -1, 0, 1)),
+ ):
+ for x in args + (inf, nan):
+ try:
+ ans = f(x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
+ except OverflowError:
+ print(name, 'OverflowError')
diff --git a/tests/float 2/math_fun.py b/tests/float 2/math_fun.py
new file mode 100644
index 000000000..2835b9bfb
--- /dev/null
+++ b/tests/float 2/math_fun.py
@@ -0,0 +1,63 @@
+# Tests the functions imported from math
+
+try:
+ from math import *
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+test_values = [-100., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 100.]
+test_values_small = [-10., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 10.] # so we don't overflow 32-bit precision
+unit_range_test_values = [-1., -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 1.]
+
+functions = [('sqrt', sqrt, test_values),
+ ('exp', exp, test_values_small),
+ ('log', log, test_values),
+ ('cos', cos, test_values),
+ ('sin', sin, test_values),
+ ('tan', tan, test_values),
+ ('acos', acos, unit_range_test_values),
+ ('asin', asin, unit_range_test_values),
+ ('atan', atan, test_values),
+ ('ceil', ceil, test_values),
+ ('fabs', fabs, test_values),
+ ('floor', floor, test_values),
+ ('trunc', trunc, test_values),
+ ('radians', radians, test_values),
+ ('degrees', degrees, test_values),
+ ]
+
+for function_name, function, test_vals in functions:
+ print(function_name)
+ for value in test_vals:
+ try:
+ print("{:.5g}".format(function(value)))
+ except ValueError as e:
+ print(str(e))
+
+tuple_functions = [('frexp', frexp, test_values),
+ ('modf', modf, test_values),
+ ]
+
+for function_name, function, test_vals in tuple_functions:
+ print(function_name)
+ for value in test_vals:
+ x, y = function(value)
+ print("{:.5g} {:.5g}".format(x, y))
+
+binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.),
+ (-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),)),
+ ('log', log, ((2., 2.), (3., 2.), (4., 5.), (0., 1.), (1., 0.), (-1., 1.), (1., -1.), (2., 1.))),
+ ]
+
+for function_name, function, test_vals in binary_functions:
+ print(function_name)
+ for value1, value2 in test_vals:
+ try:
+ print("{:.5g}".format(function(value1, value2)))
+ except (ValueError, ZeroDivisionError) as e:
+ print(type(e))
diff --git a/tests/float 2/math_fun_bool.py b/tests/float 2/math_fun_bool.py
new file mode 100644
index 000000000..761871b41
--- /dev/null
+++ b/tests/float 2/math_fun_bool.py
@@ -0,0 +1,16 @@
+# Test the bool functions from math
+
+try:
+ from math import isfinite, isnan, isinf
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+test_values = [1, 0, -1, 1.0, 0.0, -1.0, float('NaN'), float('Inf'),
+ -float('NaN'), -float('Inf')]
+
+functions = [isfinite, isnan, isinf]
+
+for val in test_values:
+ for f in functions:
+ print(f(val))
diff --git a/tests/float 2/math_fun_int.py b/tests/float 2/math_fun_int.py
new file mode 100644
index 000000000..5cadbb1e5
--- /dev/null
+++ b/tests/float 2/math_fun_int.py
@@ -0,0 +1,14 @@
+# test the math functions that return ints
+
+try:
+ import math
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+for fun in (math.ceil, math.floor, math.trunc):
+ for x in (-1.6, -0.2, 0, 0.6, 1.4, float('inf'), float('nan')):
+ try:
+ print(fun(x))
+ except (ValueError, OverflowError) as e:
+ print(type(e))
diff --git a/tests/float 2/math_fun_intbig.py b/tests/float 2/math_fun_intbig.py
new file mode 100644
index 000000000..697ca7a6d
--- /dev/null
+++ b/tests/float 2/math_fun_intbig.py
@@ -0,0 +1,11 @@
+# test the math functions that return ints, with very large results
+
+try:
+ import math
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+for fun in (math.ceil, math.floor, math.trunc):
+ for x in (-1e25, 1e25):
+ print('%.3g' % fun(x))
diff --git a/tests/float 2/math_fun_special.py b/tests/float 2/math_fun_special.py
new file mode 100644
index 000000000..c3665a7cd
--- /dev/null
+++ b/tests/float 2/math_fun_special.py
@@ -0,0 +1,35 @@
+# test the special functions imported from math
+
+try:
+ from math import *
+ erf
+except (ImportError, NameError):
+ print("SKIP")
+ raise SystemExit
+
+test_values = [-8., -2.5, -1, -0.5, 0.0, 0.5, 2.5, 8.,]
+pos_test_values = [0.001, 0.1, 0.5, 1.0, 1.5, 10.,]
+
+functions = [
+ ('expm1', expm1, test_values),
+ ('log2', log2, test_values),
+ ('log10', log10, test_values),
+ ('cosh', cosh, test_values),
+ ('sinh', sinh, test_values),
+ ('tanh', tanh, test_values),
+ ('acosh', acosh, [1.0, 5.0, 1.0]),
+ ('asinh', asinh, test_values),
+ ('atanh', atanh, [-0.99, -0.5, 0.0, 0.5, 0.99]),
+ ('erf', erf, test_values),
+ ('erfc', erfc, test_values),
+ ('gamma', gamma, pos_test_values),
+ ('lgamma', lgamma, pos_test_values + [50., 100.,]),
+]
+
+for function_name, function, test_vals in functions:
+ print(function_name)
+ for value in test_vals:
+ try:
+ print("{:.4g}".format(function(value)))
+ except ValueError as e:
+ print(str(e))
diff --git a/tests/float 2/python36.py b/tests/float 2/python36.py
new file mode 100644
index 000000000..6e8fb1f21
--- /dev/null
+++ b/tests/float 2/python36.py
@@ -0,0 +1,10 @@
+# tests for things that only Python 3.6 supports, needing floats
+
+# underscores in numeric literals
+print(1_000.1_8)
+print('%.2g' % 1e1_2)
+
+# underscore supported by int/float constructors
+print(float('1_2_3'))
+print(float('1_2_3.4'))
+print('%.2g' % float('1e1_3'))
diff --git a/tests/float 2/python36.py.exp b/tests/float 2/python36.py.exp
new file mode 100644
index 000000000..3febfed9a
--- /dev/null
+++ b/tests/float 2/python36.py.exp
@@ -0,0 +1,5 @@
+1000.18
+1e+12
+123.0
+123.4
+1e+13
diff --git a/tests/float 2/string_format.py b/tests/float 2/string_format.py
new file mode 100644
index 000000000..6fb11c35a
--- /dev/null
+++ b/tests/float 2/string_format.py
@@ -0,0 +1,41 @@
+def test(fmt, *args):
+ print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<')
+
+test("{:10.4}", 123.456)
+test("{:10.4e}", 123.456)
+test("{:10.4e}", -123.456)
+test("{:10.4f}", 123.456)
+test("{:10.4f}", -123.456)
+test("{:10.4g}", 123.456)
+test("{:10.4g}", -123.456)
+test("{:10.4n}", 123.456)
+test("{:e}", 100)
+test("{:f}", 200)
+test("{:g}", 300)
+
+test("{:10.4E}", 123.456)
+test("{:10.4E}", -123.456)
+test("{:10.4F}", 123.456)
+test("{:10.4F}", -123.456)
+test("{:10.4G}", 123.456)
+test("{:10.4G}", -123.456)
+
+test("{:06e}", float("inf"))
+test("{:06e}", float("-inf"))
+test("{:06e}", float("nan"))
+
+# The following fails right now
+#test("{:10.1}", 0.0)
+
+print("%.0f" % (1.750000 % 0.08333333333))
+# Below isn't compatible with single-precision float
+#print("%.1f" % (1.750000 % 0.08333333333))
+#print("%.2f" % (1.750000 % 0.08333333333))
+#print("%.12f" % (1.750000 % 0.08333333333))
+
+# tests for errors in format string
+
+try:
+ '{:10.1b}'.format(0.0)
+except ValueError:
+ print('ValueError')
diff --git a/tests/float 2/string_format2.py b/tests/float 2/string_format2.py
new file mode 100644
index 000000000..269023e7f
--- /dev/null
+++ b/tests/float 2/string_format2.py
@@ -0,0 +1,106 @@
+# Change the following to True to get a much more comprehensive set of tests
+# to run, albeit, which take considerably longer.
+
+full_tests = False
+
+def test(fmt, *args):
+ print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<')
+
+def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg):
+ fmt = '{'
+ if conv:
+ fmt += '!'
+ fmt += conv
+ fmt += ':'
+ if alignment:
+ fmt += fill
+ fmt += alignment
+ fmt += sign
+ fmt += prefix
+ fmt += width
+ if precision:
+ fmt += '.'
+ fmt += precision
+ fmt += type
+ fmt += '}'
+ test(fmt, arg)
+ if fill == '0' and alignment == '=':
+ fmt = '{:'
+ fmt += sign
+ fmt += prefix
+ fmt += width
+ if precision:
+ fmt += '.'
+ fmt += precision
+ fmt += type
+ fmt += '}'
+ test(fmt, arg)
+
+eg_nums = (0.0, -0.0, 0.1, 1.234, 12.3459, 1.23456789, 123456789.0, -0.0,
+ -0.1, -1.234, -12.3459, 1e4, 1e-4, 1e5, 1e-5, 1e6, 1e-6, 1e10,
+ 1e37, -1e37, 1e-37, -1e-37,
+ 1.23456e8, 1.23456e7, 1.23456e6, 1.23456e5, 1.23456e4, 1.23456e3, 1.23456e2, 1.23456e1, 1.23456e0,
+ 1.23456e-1, 1.23456e-2, 1.23456e-3, 1.23456e-4, 1.23456e-5, 1.23456e-6, 1.23456e-7, 1.23456e-8,
+ -1.23456e8, -1.23456e7, -1.23456e6, -1.23456e5, -1.23456e4, -1.23456e3, -1.23456e2, -1.23456e1, -1.23456e0,
+ -1.23456e-1, -1.23456e-2, -1.23456e-3, -1.23456e-4, -1.23456e-5, -1.23456e-6, -1.23456e-7, -1.23456e-8)
+
+if full_tests:
+ for type in ('e', 'E', 'g', 'G', 'n'):
+ for width in ('', '4', '6', '8', '10'):
+ for alignment in ('', '<', '>', '=', '^'):
+ for fill in ('', '@', '0', ' '):
+ for sign in ('', '+', '-', ' '):
+ for prec in ('', '1', '3', '6'):
+ for num in eg_nums:
+ test_fmt('', fill, alignment, sign, '', width, prec, type, num)
+
+# Note: We use 1.23459 rather than 1.2345 because '{:3f}'.format(1.2345)
+# rounds differently than print("%.3f", 1.2345);
+
+f_nums = (0.0, -0.0, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0,
+ 0.0012, 0.0123, 0.1234, 1.23459, 12.3456,
+ -0.0001, -0.001, -0.01, -0.1, -1.0, -10.0,
+ -0.0012, -0.0123, -0.1234, -1.23459, -12.3456)
+
+if full_tests:
+ for type in ('f', 'F'):
+ for width in ('', '4', '6', '8', '10'):
+ for alignment in ('', '<', '>', '=', '^'):
+ for fill in ('', ' ', '0', '@'):
+ for sign in ('', '+', '-', ' '):
+ # An empty precision defaults to 6, but when uPy is
+ # configured to use a float, we can only use a
+ # precision of 6 with numbers less than 10 and still
+ # get results that compare to CPython (which uses
+ # long doubles).
+ for prec in ('1', '2', '3'):
+ for num in f_nums:
+ test_fmt('', fill, alignment, sign, '', width, prec, type, num)
+ for num in int_nums2:
+ test_fmt('', fill, alignment, sign, '', width, '', type, num)
+
+pct_nums1 = (0.1, 0.58, 0.99, -0.1, -0.58, -0.99)
+pct_nums2 = (True, False, 1, 0, -1)
+
+if full_tests:
+ type = '%'
+ for width in ('', '4', '6', '8', '10'):
+ for alignment in ('', '<', '>', '=', '^'):
+ for fill in ('', ' ', '0', '@'):
+ for sign in ('', '+', '-', ' '):
+ # An empty precision defaults to 6, but when uPy is
+ # configured to use a float, we can only use a
+ # precision of 6 with numbers less than 10 and still
+ # get results that compare to CPython (which uses
+ # long doubles).
+ for prec in ('1', '2', '3'):
+ for num in pct_nums1:
+ test_fmt('', fill, alignment, sign, '', width, prec, type, num)
+ for num in pct_nums2:
+ test_fmt('', fill, alignment, sign, '', width, '', type, num)
+else:
+ for num in pct_nums1:
+ test_fmt('', '', '', '', '', '', '1', '%', num)
+
+# We don't currently test a type of '' with floats (see the detailed comment
+# in objstr.c)
diff --git a/tests/float 2/string_format_fp30.py b/tests/float 2/string_format_fp30.py
new file mode 100644
index 000000000..77b2a5288
--- /dev/null
+++ b/tests/float 2/string_format_fp30.py
@@ -0,0 +1,41 @@
+def test(fmt, *args):
+ print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<')
+
+test("{:10.4}", 123.456)
+test("{:10.4e}", 123.456)
+test("{:10.4e}", -123.456)
+#test("{:10.4f}", 123.456)
+#test("{:10.4f}", -123.456)
+test("{:10.4g}", 123.456)
+test("{:10.4g}", -123.456)
+test("{:10.4n}", 123.456)
+test("{:e}", 100)
+test("{:f}", 200)
+test("{:g}", 300)
+
+test("{:10.4E}", 123.456)
+test("{:10.4E}", -123.456)
+#test("{:10.4F}", 123.456)
+#test("{:10.4F}", -123.456)
+test("{:10.4G}", 123.456)
+test("{:10.4G}", -123.456)
+
+test("{:06e}", float("inf"))
+test("{:06e}", float("-inf"))
+test("{:06e}", float("nan"))
+
+# The following fails right now
+#test("{:10.1}", 0.0)
+
+print("%.0f" % (1.750000 % 0.08333333333))
+# Below isn't compatible with single-precision float
+#print("%.1f" % (1.750000 % 0.08333333333))
+#print("%.2f" % (1.750000 % 0.08333333333))
+#print("%.12f" % (1.750000 % 0.08333333333))
+
+# tests for errors in format string
+
+try:
+ '{:10.1b}'.format(0.0)
+except ValueError:
+ print('ValueError')
diff --git a/tests/float 2/string_format_modulo.py b/tests/float 2/string_format_modulo.py
new file mode 100644
index 000000000..aea534247
--- /dev/null
+++ b/tests/float 2/string_format_modulo.py
@@ -0,0 +1,49 @@
+print("%s" % 1.0)
+print("%r" % 1.0)
+
+print("%d" % 1.0)
+print("%i" % 1.0)
+print("%u" % 1.0)
+
+# these 3 have different behaviour in Python 3.x versions
+# uPy raises a TypeError, following Python 3.5 (earlier versions don't)
+#print("%x" % 18.0)
+#print("%o" % 18.0)
+#print("%X" % 18.0)
+
+print("%e" % 1.23456)
+print("%E" % 1.23456)
+print("%f" % 1.23456)
+print("%F" % 1.23456)
+print("%g" % 1.23456)
+print("%G" % 1.23456)
+
+print("%06e" % float("inf"))
+print("%06e" % float("-inf"))
+print("%06e" % float("nan"))
+
+print("%02.3d" % 123) # prec > width
+print("%+f %+f" % (1.23, -1.23)) # float sign
+print("% f % f" % (1.23, -1.23)) # float space sign
+print("%0f" % -1.23) # negative number with 0 padding
+
+# numbers with large negative exponents
+print('%f' % 1e-10)
+print('%f' % 1e-20)
+print('%f' % 1e-50)
+print('%f' % 1e-100)
+print('%f' % 1e-300)
+
+# large decimal precision should be truncated and not overflow buffer
+# the output depends on the FP calculation so only first 2 digits are printed
+# (the 'g' with small e are printed using 'f' style, so need to be checked)
+print(('%.40f' % 1e-300)[:2])
+print(('%.40g' % 1e-1)[:2])
+print(('%.40g' % 1e-2)[:2])
+print(('%.40g' % 1e-3)[:2])
+print(('%.40g' % 1e-4)[:2])
+
+print("%.0g" % 1) # 0 precision 'g'
+
+print('%.1e' % 9.99) # round up with positive exponent
+print('%.1e' % 0.999) # round up with negative exponent
diff --git a/tests/float 2/string_format_modulo2.py b/tests/float 2/string_format_modulo2.py
new file mode 100644
index 000000000..f6b1ae537
--- /dev/null
+++ b/tests/float 2/string_format_modulo2.py
@@ -0,0 +1,24 @@
+# test formatting floats with large precision, that it doesn't overflow the buffer
+
+def test(num, num_str):
+ if num == float('inf') or num == 0.0 and num_str != '0.0':
+ # skip numbers that overflow or underflow the FP precision
+ return
+ for kind in ('e', 'f', 'g'):
+ # check precision either side of the size of the buffer (32 bytes)
+ for prec in range(23, 36, 2):
+ fmt = '%.' + '%d' % prec + kind
+ s = fmt % num
+ check = abs(float(s) - num)
+ if num > 1:
+ check /= num
+ if check > 1e-6:
+ print('FAIL', num_str, fmt, s, len(s), check)
+
+# check pure zero
+test(0.0, '0.0')
+
+# check some powers of 10, making sure to include exponents with 3 digits
+for e in range(-8, 8):
+ num = pow(10, e)
+ test(num, '1e%d' % e)
diff --git a/tests/float 2/string_format_modulo2_intbig.py b/tests/float 2/string_format_modulo2_intbig.py
new file mode 100644
index 000000000..9992ba65d
--- /dev/null
+++ b/tests/float 2/string_format_modulo2_intbig.py
@@ -0,0 +1,21 @@
+# test formatting floats with large precision, that it doesn't overflow the buffer
+
+def test(num, num_str):
+ if num == float('inf') or num == 0.0 and num_str != '0.0':
+ # skip numbers that overflow or underflow the FP precision
+ return
+ for kind in ('e', 'f', 'g'):
+ # check precision either side of the size of the buffer (32 bytes)
+ for prec in range(23, 36, 2):
+ fmt = '%.' + '%d' % prec + kind
+ s = fmt % num
+ check = abs(float(s) - num)
+ if num > 1:
+ check /= num
+ if check > 1e-6:
+ print('FAIL', num_str, fmt, s, len(s), check)
+
+# check most powers of 10, making sure to include exponents with 3 digits
+for e in range(-101, 102):
+ num = pow(10, e)
+ test(num, '1e%d' % e)
diff --git a/tests/float 2/string_format_modulo3.py b/tests/float 2/string_format_modulo3.py
new file mode 100644
index 000000000..5d26f2575
--- /dev/null
+++ b/tests/float 2/string_format_modulo3.py
@@ -0,0 +1,3 @@
+# uPy and CPython outputs differ for the following
+print("%.1g" % -9.9) # round up 'g' with '-' sign
+print("%.2g" % 99.9) # round up
diff --git a/tests/float 2/string_format_modulo3.py.exp b/tests/float 2/string_format_modulo3.py.exp
new file mode 100644
index 000000000..71432b340
--- /dev/null
+++ b/tests/float 2/string_format_modulo3.py.exp
@@ -0,0 +1,2 @@
+-10
+100
diff --git a/tests/float 2/true_value.py b/tests/float 2/true_value.py
new file mode 100644
index 000000000..df415f003
--- /dev/null
+++ b/tests/float 2/true_value.py
@@ -0,0 +1,7 @@
+# Test true-ish value handling
+
+if not 0.0:
+ print("float 0")
+
+if not 0+0j:
+ print("complex 0")
diff --git a/tests/float 2/types.py b/tests/float 2/types.py
new file mode 100644
index 000000000..75674c924
--- /dev/null
+++ b/tests/float 2/types.py
@@ -0,0 +1,17 @@
+# float types
+
+print(float)
+print(complex)
+
+print(type(float()) == float)
+print(type(complex()) == complex)
+
+print(type(0.0) == float)
+print(type(1j) == complex)
+
+# hashing float types
+
+d = dict()
+d[float] = complex
+d[complex] = float
+print(len(d))
diff --git a/tests/inlineasm 2/asmargs.py b/tests/inlineasm 2/asmargs.py
new file mode 100644
index 000000000..047d9ed42
--- /dev/null
+++ b/tests/inlineasm 2/asmargs.py
@@ -0,0 +1,29 @@
+# test passing arguments
+
+@micropython.asm_thumb
+def arg0():
+ mov(r0, 1)
+print(arg0())
+
+@micropython.asm_thumb
+def arg1(r0):
+ add(r0, r0, 1)
+print(arg1(1))
+
+@micropython.asm_thumb
+def arg2(r0, r1):
+ add(r0, r0, r1)
+print(arg2(1, 2))
+
+@micropython.asm_thumb
+def arg3(r0, r1, r2):
+ add(r0, r0, r1)
+ add(r0, r0, r2)
+print(arg3(1, 2, 3))
+
+@micropython.asm_thumb
+def arg4(r0, r1, r2, r3):
+ add(r0, r0, r1)
+ add(r0, r0, r2)
+ add(r0, r0, r3)
+print(arg4(1, 2, 3, 4))
diff --git a/tests/inlineasm 2/asmargs.py.exp b/tests/inlineasm 2/asmargs.py.exp
new file mode 100644
index 000000000..e33a6964f
--- /dev/null
+++ b/tests/inlineasm 2/asmargs.py.exp
@@ -0,0 +1,5 @@
+1
+2
+3
+6
+10
diff --git a/tests/inlineasm 2/asmbcc.py b/tests/inlineasm 2/asmbcc.py
new file mode 100644
index 000000000..540fa6591
--- /dev/null
+++ b/tests/inlineasm 2/asmbcc.py
@@ -0,0 +1,27 @@
+# test bcc instructions
+# at the moment only tests beq, narrow and wide versions
+
+@micropython.asm_thumb
+def f(r0):
+ mov(r1, r0)
+
+ mov(r0, 10)
+ cmp(r1, 1)
+ beq(end)
+
+ mov(r0, 20)
+ cmp(r1, 2)
+ beq_n(end)
+
+ mov(r0, 30)
+ cmp(r1, 3)
+ beq_w(end)
+
+ mov(r0, 0)
+
+ label(end)
+
+print(f(0))
+print(f(1))
+print(f(2))
+print(f(3))
diff --git a/tests/inlineasm 2/asmbcc.py.exp b/tests/inlineasm 2/asmbcc.py.exp
new file mode 100644
index 000000000..39da7d1a9
--- /dev/null
+++ b/tests/inlineasm 2/asmbcc.py.exp
@@ -0,0 +1,4 @@
+0
+10
+20
+30
diff --git a/tests/inlineasm 2/asmbitops.py b/tests/inlineasm 2/asmbitops.py
new file mode 100644
index 000000000..8cf92b301
--- /dev/null
+++ b/tests/inlineasm 2/asmbitops.py
@@ -0,0 +1,13 @@
+@micropython.asm_thumb
+def clz(r0):
+ clz(r0, r0)
+
+print(clz(0xf0))
+print(clz(0x8000))
+
+@micropython.asm_thumb
+def rbit(r0):
+ rbit(r0, r0)
+
+print(hex(rbit(0xf0)))
+print(hex(rbit(0x8000)))
diff --git a/tests/inlineasm 2/asmbitops.py.exp b/tests/inlineasm 2/asmbitops.py.exp
new file mode 100644
index 000000000..8c560045f
--- /dev/null
+++ b/tests/inlineasm 2/asmbitops.py.exp
@@ -0,0 +1,4 @@
+24
+16
+0xf000000
+0x10000
diff --git a/tests/inlineasm 2/asmblbx.py b/tests/inlineasm 2/asmblbx.py
new file mode 100644
index 000000000..d08c0ed6b
--- /dev/null
+++ b/tests/inlineasm 2/asmblbx.py
@@ -0,0 +1,21 @@
+# test bl and bx instructions
+
+@micropython.asm_thumb
+def f(r0):
+ # jump over the internal functions
+ b(entry)
+
+ label(func1)
+ add(r0, 2)
+ bx(lr)
+
+ label(func2)
+ sub(r0, 1)
+ bx(lr)
+
+ label(entry)
+ bl(func1)
+ bl(func2)
+
+print(f(0))
+print(f(1))
diff --git a/tests/inlineasm 2/asmblbx.py.exp b/tests/inlineasm 2/asmblbx.py.exp
new file mode 100644
index 000000000..1191247b6
--- /dev/null
+++ b/tests/inlineasm 2/asmblbx.py.exp
@@ -0,0 +1,2 @@
+1
+2
diff --git a/tests/inlineasm 2/asmconst.py b/tests/inlineasm 2/asmconst.py
new file mode 100644
index 000000000..299a25093
--- /dev/null
+++ b/tests/inlineasm 2/asmconst.py
@@ -0,0 +1,8 @@
+# test constants in assembler
+
+@micropython.asm_thumb
+def c1():
+ movwt(r0, 0xffffffff)
+ movwt(r1, 0xf0000000)
+ sub(r0, r0, r1)
+print(hex(c1()))
diff --git a/tests/inlineasm 2/asmconst.py.exp b/tests/inlineasm 2/asmconst.py.exp
new file mode 100644
index 000000000..3ef9fcabd
--- /dev/null
+++ b/tests/inlineasm 2/asmconst.py.exp
@@ -0,0 +1 @@
+0xfffffff
diff --git a/tests/inlineasm 2/asmdiv.py b/tests/inlineasm 2/asmdiv.py
new file mode 100644
index 000000000..b97d566eb
--- /dev/null
+++ b/tests/inlineasm 2/asmdiv.py
@@ -0,0 +1,16 @@
+@micropython.asm_thumb
+def sdiv(r0, r1):
+ sdiv(r0, r0, r1)
+
+@micropython.asm_thumb
+def udiv(r0, r1):
+ udiv(r0, r0, r1)
+
+print(sdiv(1234, 3))
+print(sdiv(-1234, 3))
+print(sdiv(1234, -3))
+print(sdiv(-1234, -3))
+
+print(udiv(1234, 3))
+print(udiv(0xffffffff, 0x7fffffff))
+print(udiv(0xffffffff, 0xffffffff))
diff --git a/tests/inlineasm 2/asmdiv.py.exp b/tests/inlineasm 2/asmdiv.py.exp
new file mode 100644
index 000000000..f1b80deb3
--- /dev/null
+++ b/tests/inlineasm 2/asmdiv.py.exp
@@ -0,0 +1,7 @@
+411
+-411
+-411
+411
+411
+2
+1
diff --git a/tests/inlineasm 2/asmfpaddsub.py b/tests/inlineasm 2/asmfpaddsub.py
new file mode 100644
index 000000000..2bdfccf0e
--- /dev/null
+++ b/tests/inlineasm 2/asmfpaddsub.py
@@ -0,0 +1,14 @@
+@micropython.asm_thumb # r0 = r0+r1-r2
+def add_sub(r0, r1, r2):
+ vmov(s0, r0)
+ vcvt_f32_s32(s0, s0)
+ vmov(s1, r1)
+ vcvt_f32_s32(s1, s1)
+ vmov(s2, r2)
+ vcvt_f32_s32(s2, s2)
+ vadd(s0, s0, s1)
+ vsub(s0, s0, s2)
+ vcvt_s32_f32(s31, s0)
+ vmov(r0, s31)
+
+print(add_sub(100, 20, 30))
diff --git a/tests/inlineasm 2/asmfpaddsub.py.exp b/tests/inlineasm 2/asmfpaddsub.py.exp
new file mode 100644
index 000000000..d61f00d8c
--- /dev/null
+++ b/tests/inlineasm 2/asmfpaddsub.py.exp
@@ -0,0 +1 @@
+90
diff --git a/tests/inlineasm 2/asmfpcmp.py b/tests/inlineasm 2/asmfpcmp.py
new file mode 100644
index 000000000..d4fa1f241
--- /dev/null
+++ b/tests/inlineasm 2/asmfpcmp.py
@@ -0,0 +1,14 @@
+@micropython.asm_thumb # test vcmp, vmrs
+def f(r0, r1):
+ vmov(s0, r0)
+ vcvt_f32_s32(s0, s0)
+ vmov(s1, r1)
+ vcvt_f32_s32(s1, s1)
+ vcmp(s1, s0)
+ vmrs(r0, FPSCR)
+ mov(r1, 28)
+ lsr(r0, r1)
+
+print(f(0,1))
+print(f(1,1))
+print(f(1,0))
diff --git a/tests/inlineasm 2/asmfpcmp.py.exp b/tests/inlineasm 2/asmfpcmp.py.exp
new file mode 100644
index 000000000..104b3580f
--- /dev/null
+++ b/tests/inlineasm 2/asmfpcmp.py.exp
@@ -0,0 +1,3 @@
+2
+6
+8
diff --git a/tests/inlineasm 2/asmfpldrstr.py b/tests/inlineasm 2/asmfpldrstr.py
new file mode 100644
index 000000000..4c480671f
--- /dev/null
+++ b/tests/inlineasm 2/asmfpldrstr.py
@@ -0,0 +1,11 @@
+import array
+@micropython.asm_thumb # test vldr, vstr
+def arrayadd(r0):
+ vldr(s0, [r0, 0])
+ vldr(s1, [r0, 4])
+ vadd(s2, s0, s1)
+ vstr(s2, [r0, 8])
+
+z = array.array("f", [2, 4, 10])
+arrayadd(z)
+print(z[2])
diff --git a/tests/inlineasm 2/asmfpldrstr.py.exp b/tests/inlineasm 2/asmfpldrstr.py.exp
new file mode 100644
index 000000000..e0ea36fee
--- /dev/null
+++ b/tests/inlineasm 2/asmfpldrstr.py.exp
@@ -0,0 +1 @@
+6.0
diff --git a/tests/inlineasm 2/asmfpmuldiv.py b/tests/inlineasm 2/asmfpmuldiv.py
new file mode 100644
index 000000000..043a28e22
--- /dev/null
+++ b/tests/inlineasm 2/asmfpmuldiv.py
@@ -0,0 +1,14 @@
+@micropython.asm_thumb # r0 = (int)(r0*r1/r2)
+def muldiv(r0, r1, r2):
+ vmov(s0, r0)
+ vcvt_f32_s32(s0, s0)
+ vmov(s1, r1)
+ vcvt_f32_s32(s1, s1)
+ vmov(s2, r2)
+ vcvt_f32_s32(s2, s2)
+ vmul(s7, s0, s1)
+ vdiv(s8, s7, s2)
+ vcvt_s32_f32(s31, s8)
+ vmov(r0, s31)
+
+print(muldiv(100, 10, 50))
diff --git a/tests/inlineasm 2/asmfpmuldiv.py.exp b/tests/inlineasm 2/asmfpmuldiv.py.exp
new file mode 100644
index 000000000..209e3ef4b
--- /dev/null
+++ b/tests/inlineasm 2/asmfpmuldiv.py.exp
@@ -0,0 +1 @@
+20
diff --git a/tests/inlineasm 2/asmfpsqrt.py b/tests/inlineasm 2/asmfpsqrt.py
new file mode 100644
index 000000000..7b7d52e23
--- /dev/null
+++ b/tests/inlineasm 2/asmfpsqrt.py
@@ -0,0 +1,14 @@
+# test vsqrt, vneg
+@micropython.asm_thumb # r0 = -(int)(sqrt(r0)*r1)
+def sqrt_test(r0, r1):
+ vmov(s1, r0)
+ vcvt_f32_s32(s1, s1)
+ vsqrt(s1, s1)
+ vmov(s2, r1)
+ vcvt_f32_s32(s2, s2)
+ vmul(s0, s1, s2)
+ vneg(s7, s0)
+ vcvt_s32_f32(s31, s7)
+ vmov(r0, s31)
+
+print(sqrt_test(256, 10))
diff --git a/tests/inlineasm 2/asmfpsqrt.py.exp b/tests/inlineasm 2/asmfpsqrt.py.exp
new file mode 100644
index 000000000..88a1e93ba
--- /dev/null
+++ b/tests/inlineasm 2/asmfpsqrt.py.exp
@@ -0,0 +1 @@
+-160
diff --git a/tests/inlineasm 2/asmit.py b/tests/inlineasm 2/asmit.py
new file mode 100644
index 000000000..57bfcc7f9
--- /dev/null
+++ b/tests/inlineasm 2/asmit.py
@@ -0,0 +1,16 @@
+# test it instruction
+
+@micropython.asm_thumb
+def f(r0, r1):
+ cmp(r0, r1)
+ it(eq)
+ mov(r0, 100)
+print(f(0, 0), f(1, 2))
+
+@micropython.asm_thumb
+def g(r0, r1):
+ cmp(r0, r1)
+ ite(eq)
+ mov(r0, 100)
+ mov(r0, 200)
+print(g(0, 0), g(0, 1))
diff --git a/tests/inlineasm 2/asmit.py.exp b/tests/inlineasm 2/asmit.py.exp
new file mode 100644
index 000000000..d06c72d9b
--- /dev/null
+++ b/tests/inlineasm 2/asmit.py.exp
@@ -0,0 +1,2 @@
+100 1
+100 200
diff --git a/tests/inlineasm 2/asmpushpop.py b/tests/inlineasm 2/asmpushpop.py
new file mode 100644
index 000000000..c9005434b
--- /dev/null
+++ b/tests/inlineasm 2/asmpushpop.py
@@ -0,0 +1,8 @@
+@micropython.asm_thumb
+def f(r0, r1, r2):
+ push({r0})
+ push({r1, r2})
+ pop({r0})
+ pop({r1, r2})
+
+print(f(0, 1, 2))
diff --git a/tests/inlineasm 2/asmpushpop.py.exp b/tests/inlineasm 2/asmpushpop.py.exp
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/inlineasm 2/asmpushpop.py.exp
@@ -0,0 +1 @@
+1
diff --git a/tests/inlineasm 2/asmrettype.py b/tests/inlineasm 2/asmrettype.py
new file mode 100644
index 000000000..f1918696e
--- /dev/null
+++ b/tests/inlineasm 2/asmrettype.py
@@ -0,0 +1,21 @@
+# test return type of inline asm
+
+@micropython.asm_thumb
+def ret_obj(r0) -> object:
+ pass
+ret_obj(print)(1)
+
+@micropython.asm_thumb
+def ret_bool(r0) -> bool:
+ pass
+print(ret_bool(0), ret_bool(1))
+
+@micropython.asm_thumb
+def ret_int(r0) -> int:
+ lsl(r0, r0, 29)
+print(ret_int(0), hex(ret_int(1)), hex(ret_int(2)), hex(ret_int(4)))
+
+@micropython.asm_thumb
+def ret_uint(r0) -> uint:
+ lsl(r0, r0, 29)
+print(ret_uint(0), hex(ret_uint(1)), hex(ret_uint(2)), hex(ret_uint(4)))
diff --git a/tests/inlineasm 2/asmrettype.py.exp b/tests/inlineasm 2/asmrettype.py.exp
new file mode 100644
index 000000000..cbb49d247
--- /dev/null
+++ b/tests/inlineasm 2/asmrettype.py.exp
@@ -0,0 +1,4 @@
+1
+False True
+0 0x20000000 0x40000000 -0x80000000
+0 0x20000000 0x40000000 0x80000000
diff --git a/tests/inlineasm 2/asmshift.py b/tests/inlineasm 2/asmshift.py
new file mode 100644
index 000000000..0df218734
--- /dev/null
+++ b/tests/inlineasm 2/asmshift.py
@@ -0,0 +1,29 @@
+@micropython.asm_thumb
+def lsl1(r0):
+ lsl(r0, r0, 1)
+print(hex(lsl1(0x123)))
+
+@micropython.asm_thumb
+def lsl23(r0):
+ lsl(r0, r0, 23)
+print(hex(lsl23(1)))
+
+@micropython.asm_thumb
+def lsr1(r0):
+ lsr(r0, r0, 1)
+print(hex(lsr1(0x123)))
+
+@micropython.asm_thumb
+def lsr31(r0):
+ lsr(r0, r0, 31)
+print(hex(lsr31(0x80000000)))
+
+@micropython.asm_thumb
+def asr1(r0):
+ asr(r0, r0, 1)
+print(hex(asr1(0x123)))
+
+@micropython.asm_thumb
+def asr31(r0):
+ asr(r0, r0, 31)
+print(hex(asr31(0x80000000)))
diff --git a/tests/inlineasm 2/asmshift.py.exp b/tests/inlineasm 2/asmshift.py.exp
new file mode 100644
index 000000000..c6c3a7217
--- /dev/null
+++ b/tests/inlineasm 2/asmshift.py.exp
@@ -0,0 +1,6 @@
+0x246
+0x800000
+0x91
+0x1
+0x91
+-0x1
diff --git a/tests/inlineasm 2/asmspecialregs.py b/tests/inlineasm 2/asmspecialregs.py
new file mode 100644
index 000000000..2d3b0e396
--- /dev/null
+++ b/tests/inlineasm 2/asmspecialregs.py
@@ -0,0 +1,10 @@
+@micropython.asm_thumb
+def getIPSR():
+ mrs(r0, IPSR)
+
+@micropython.asm_thumb
+def getBASEPRI():
+ mrs(r0, BASEPRI)
+
+print(getBASEPRI())
+print(getIPSR())
diff --git a/tests/inlineasm 2/asmspecialregs.py.exp b/tests/inlineasm 2/asmspecialregs.py.exp
new file mode 100644
index 000000000..aa47d0d46
--- /dev/null
+++ b/tests/inlineasm 2/asmspecialregs.py.exp
@@ -0,0 +1,2 @@
+0
+0
diff --git a/tests/inlineasm 2/asmsum.py b/tests/inlineasm 2/asmsum.py
new file mode 100644
index 000000000..07e71c738
--- /dev/null
+++ b/tests/inlineasm 2/asmsum.py
@@ -0,0 +1,57 @@
+@micropython.asm_thumb
+def asm_sum_words(r0, r1):
+
+ # r0 = len
+ # r1 = ptr
+ # r2 = sum
+ # r3 = dummy
+ mov(r2, 0)
+
+ b(loop_entry)
+
+ label(loop1)
+ ldr(r3, [r1, 0])
+ add(r2, r2, r3)
+
+ add(r1, r1, 4)
+ sub(r0, r0, 1)
+
+ label(loop_entry)
+ cmp(r0, 0)
+ bgt(loop1)
+
+ mov(r0, r2)
+
+@micropython.asm_thumb
+def asm_sum_bytes(r0, r1):
+
+ # r0 = len
+ # r1 = ptr
+ # r2 = sum
+ # r3 = dummy
+ mov(r2, 0)
+
+ b(loop_entry)
+
+ label(loop1)
+ ldrb(r3, [r1, 0])
+ add(r2, r2, r3)
+
+ add(r1, r1, 1)
+ sub(r0, r0, 1)
+
+ label(loop_entry)
+ cmp(r0, 0)
+ bgt(loop1)
+
+ mov(r0, r2)
+
+import array
+
+b = array.array('l', (100, 200, 300, 400))
+n = asm_sum_words(len(b), b)
+print(b, n)
+
+b = array.array('b', (10, 20, 30, 40, 50, 60, 70, 80))
+n = asm_sum_bytes(len(b), b)
+print(b, n)
diff --git a/tests/inlineasm 2/asmsum.py.exp b/tests/inlineasm 2/asmsum.py.exp
new file mode 100644
index 000000000..d50a94c8d
--- /dev/null
+++ b/tests/inlineasm 2/asmsum.py.exp
@@ -0,0 +1,2 @@
+array('l', [100, 200, 300, 400]) 1000
+array('b', [10, 20, 30, 40, 50, 60, 70, 80]) 360
diff --git a/tests/io/data/file1 2 b/tests/io/data/file1 2
new file mode 100644
index 000000000..e08206337
--- /dev/null
+++ b/tests/io/data/file1 2
@@ -0,0 +1,3 @@
+longer line1
+line2
+line3
diff --git a/tests/jni 2/README b/tests/jni 2/README
new file mode 100644
index 000000000..a0689e924
--- /dev/null
+++ b/tests/jni 2/README
@@ -0,0 +1,11 @@
+Running "jni" module tests (as well as just using this module) requires
+being able to load libjvm.so, which requires path to it set via
+LD_LIBRARY_PATH environment variable. This path is not set automatically
+and there is no easy way to guess it, because there can be installed
+different implementations of JVM, for one implementation, there can be
+different versions, and single version may include different variants
+of JVM.
+
+For example, for OpenJDK 7 on x86_64, following may work:
+
+LD_LIBRARY_PATH=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server ./run-tests jni/*.py
diff --git a/tests/jni 2/list.py b/tests/jni 2/list.py
new file mode 100644
index 000000000..d58181d0b
--- /dev/null
+++ b/tests/jni 2/list.py
@@ -0,0 +1,15 @@
+import jni
+try:
+ ArrayList = jni.cls("java/util/ArrayList")
+except:
+ print("SKIP")
+ raise SystemExit
+
+l = ArrayList()
+print(l)
+l.add("one")
+l.add("two")
+
+print(l.toString())
+print(l)
+print(l[0], l[1])
diff --git a/tests/jni 2/list.py.exp b/tests/jni 2/list.py.exp
new file mode 100644
index 000000000..cc34bb0a2
--- /dev/null
+++ b/tests/jni 2/list.py.exp
@@ -0,0 +1,4 @@
+[]
+[one, two]
+[one, two]
+one two
diff --git a/tests/jni 2/object.py b/tests/jni 2/object.py
new file mode 100644
index 000000000..aa67615ec
--- /dev/null
+++ b/tests/jni 2/object.py
@@ -0,0 +1,15 @@
+import jni
+try:
+ Integer = jni.cls("java/lang/Integer")
+except:
+ print("SKIP")
+ raise SystemExit
+
+# Create object
+i = Integer(42)
+print(i)
+# Call object method
+print(i.hashCode())
+# Pass object to another method
+System = jni.cls("java/lang/System")
+System.out.println(i)
diff --git a/tests/jni 2/object.py.exp b/tests/jni 2/object.py.exp
new file mode 100644
index 000000000..bda709ecf
--- /dev/null
+++ b/tests/jni 2/object.py.exp
@@ -0,0 +1,3 @@
+42
+42
+42
diff --git a/tests/jni 2/system_out.py b/tests/jni 2/system_out.py
new file mode 100644
index 000000000..86c4b9e11
--- /dev/null
+++ b/tests/jni 2/system_out.py
@@ -0,0 +1,8 @@
+try:
+ import jni
+ System = jni.cls("java/lang/System")
+except:
+ print("SKIP")
+ raise SystemExit
+
+System.out.println("Hello, Java!")
diff --git a/tests/jni 2/system_out.py.exp b/tests/jni 2/system_out.py.exp
new file mode 100644
index 000000000..01dd954f9
--- /dev/null
+++ b/tests/jni 2/system_out.py.exp
@@ -0,0 +1 @@
+Hello, Java!
diff --git a/tests/net_hosted 2/README b/tests/net_hosted 2/README
new file mode 100644
index 000000000..724dd6158
--- /dev/null
+++ b/tests/net_hosted 2/README
@@ -0,0 +1,11 @@
+This directory contains network tests which require just "peer to peer"
+network connection between test host and device under test, instead of
+full Internet connection.
+
+Note that setup for these tests and tests themselves are WIP, and may
+not yet fully correspond to the functional specification above.
+
+So far, these tests are not run as part of the main testsuite and need
+to be run seperately (from the main test/ directory):
+
+ ./run-tests net_hosted/*.py
diff --git a/tests/net_hosted 2/accept_nonblock.py b/tests/net_hosted 2/accept_nonblock.py
new file mode 100644
index 000000000..56f3288e2
--- /dev/null
+++ b/tests/net_hosted 2/accept_nonblock.py
@@ -0,0 +1,16 @@
+# test that socket.accept() on a non-blocking socket raises EAGAIN
+
+try:
+ import usocket as socket
+except:
+ import socket
+
+s = socket.socket()
+s.bind(socket.getaddrinfo('127.0.0.1', 8123)[0][-1])
+s.setblocking(False)
+s.listen(1)
+try:
+ s.accept()
+except OSError as er:
+ print(er.args[0] == 11) # 11 is EAGAIN
+s.close()
diff --git a/tests/net_hosted 2/accept_nonblock.py.exp b/tests/net_hosted 2/accept_nonblock.py.exp
new file mode 100644
index 000000000..0ca95142b
--- /dev/null
+++ b/tests/net_hosted 2/accept_nonblock.py.exp
@@ -0,0 +1 @@
+True
diff --git a/tests/net_hosted 2/accept_timeout.py b/tests/net_hosted 2/accept_timeout.py
new file mode 100644
index 000000000..44b3b8c7c
--- /dev/null
+++ b/tests/net_hosted 2/accept_timeout.py
@@ -0,0 +1,22 @@
+# test that socket.accept() on a socket with timeout raises ETIMEDOUT
+
+try:
+ import usocket as socket
+except:
+ import socket
+
+try:
+ socket.socket.settimeout
+except AttributeError:
+ print('SKIP')
+ raise SystemExit
+
+s = socket.socket()
+s.bind(socket.getaddrinfo('127.0.0.1', 8123)[0][-1])
+s.settimeout(1)
+s.listen(1)
+try:
+ s.accept()
+except OSError as er:
+ print(er.args[0] in (110, 'timed out')) # 110 is ETIMEDOUT; CPython uses a string
+s.close()
diff --git a/tests/net_hosted 2/accept_timeout.py.exp b/tests/net_hosted 2/accept_timeout.py.exp
new file mode 100644
index 000000000..0ca95142b
--- /dev/null
+++ b/tests/net_hosted 2/accept_timeout.py.exp
@@ -0,0 +1 @@
+True
diff --git a/tests/net_hosted 2/connect_nonblock.py b/tests/net_hosted 2/connect_nonblock.py
new file mode 100644
index 000000000..6479978be
--- /dev/null
+++ b/tests/net_hosted 2/connect_nonblock.py
@@ -0,0 +1,20 @@
+# test that socket.connect() on a non-blocking socket raises EINPROGRESS
+
+try:
+ import usocket as socket
+except:
+ import socket
+
+
+def test(peer_addr):
+ s = socket.socket()
+ s.setblocking(False)
+ try:
+ s.connect(peer_addr)
+ except OSError as er:
+ print(er.args[0] == 115) # 115 is EINPROGRESS
+ s.close()
+
+
+if __name__ == "__main__":
+ test(socket.getaddrinfo('micropython.org', 80)[0][-1])
diff --git a/tests/net_hosted 2/connect_nonblock.py.exp b/tests/net_hosted 2/connect_nonblock.py.exp
new file mode 100644
index 000000000..0ca95142b
--- /dev/null
+++ b/tests/net_hosted 2/connect_nonblock.py.exp
@@ -0,0 +1 @@
+True
diff --git a/tests/net_hosted 2/connect_poll.py b/tests/net_hosted 2/connect_poll.py
new file mode 100644
index 000000000..ece6aa0da
--- /dev/null
+++ b/tests/net_hosted 2/connect_poll.py
@@ -0,0 +1,32 @@
+# test that socket.connect() has correct polling behaviour before, during and after
+
+try:
+ import usocket as socket, uselect as select
+except:
+ import socket, select
+
+
+def test(peer_addr):
+ s = socket.socket()
+ poller = select.poll()
+ poller.register(s)
+
+ # test poll before connect
+ # note: CPython can return POLLHUP, so use the IN|OUT mask
+ p = poller.poll(0)
+ print(len(p), p[0][-1] & (select.POLLIN | select.POLLOUT))
+
+ s.connect(peer_addr)
+
+ # test poll during connection
+ print(len(poller.poll(0)))
+
+ # test poll after connection is established
+ p = poller.poll(1000)
+ print(len(p), p[0][-1])
+
+ s.close()
+
+
+if __name__ == "__main__":
+ test(socket.getaddrinfo('micropython.org', 80)[0][-1])
diff --git a/tests/net_hosted 2/connect_poll.py.exp b/tests/net_hosted 2/connect_poll.py.exp
new file mode 100644
index 000000000..cdf520e09
--- /dev/null
+++ b/tests/net_hosted 2/connect_poll.py.exp
@@ -0,0 +1,3 @@
+1 4
+1
+1 4
diff --git a/tests/net_hosted 2/ssl_getpeercert.py b/tests/net_hosted 2/ssl_getpeercert.py
new file mode 100644
index 000000000..e265c830d
--- /dev/null
+++ b/tests/net_hosted 2/ssl_getpeercert.py
@@ -0,0 +1,21 @@
+# test ssl.getpeercert() method
+
+try:
+ import usocket as socket
+ import ussl as ssl
+except:
+ import socket
+ import ssl
+
+
+def test(peer_addr):
+ s = socket.socket()
+ s.connect(peer_addr)
+ s = ssl.wrap_socket(s)
+ cert = s.getpeercert(True)
+ print(type(cert), len(cert) > 100)
+ s.close()
+
+
+if __name__ == "__main__":
+ test(socket.getaddrinfo('micropython.org', 443)[0][-1])
diff --git a/tests/net_hosted 2/ssl_getpeercert.py.exp b/tests/net_hosted 2/ssl_getpeercert.py.exp
new file mode 100644
index 000000000..ff7ef5adf
--- /dev/null
+++ b/tests/net_hosted 2/ssl_getpeercert.py.exp
@@ -0,0 +1 @@
+<class 'bytes'> True
diff --git a/tests/net_inet 2/README b/tests/net_inet 2/README
new file mode 100644
index 000000000..9a5614efa
--- /dev/null
+++ b/tests/net_inet 2/README
@@ -0,0 +1,5 @@
+This directory contains network tests which require Internet connection.
+Note that these tests are not run as part of the main testsuite and need
+to be run seperately (from the main test/ directory):
+
+ ./run-tests net_inet/*.py
diff --git a/tests/net_inet 2/test_tls_sites.py b/tests/net_inet 2/test_tls_sites.py
new file mode 100644
index 000000000..bf8071d08
--- /dev/null
+++ b/tests/net_inet 2/test_tls_sites.py
@@ -0,0 +1,59 @@
+try:
+ import usocket as _socket
+except:
+ import _socket
+try:
+ import ussl as ssl
+except:
+ import ssl
+ # CPython only supports server_hostname with SSLContext
+ ssl = ssl.SSLContext()
+
+
+def test_one(site, opts):
+ ai = _socket.getaddrinfo(site, 443)
+ addr = ai[0][-1]
+
+ s = _socket.socket()
+
+ try:
+ s.connect(addr)
+
+ if "sni" in opts:
+ s = ssl.wrap_socket(s, server_hostname=opts["host"])
+ else:
+ s = ssl.wrap_socket(s)
+
+ s.write(b"GET / HTTP/1.0\r\nHost: %s\r\n\r\n" % bytes(site, 'latin'))
+ resp = s.read(4096)
+# print(resp)
+
+ finally:
+ s.close()
+
+
+SITES = [
+ "google.com",
+ "www.google.com",
+ "api.telegram.org",
+ {"host": "api.pushbullet.com", "sni": True},
+# "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com",
+ {"host": "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", "sni": True},
+]
+
+
+def main():
+ for site in SITES:
+ opts = {}
+ if isinstance(site, dict):
+ opts = site
+ site = opts["host"]
+
+ try:
+ test_one(site, opts)
+ print(site, "ok")
+ except Exception as e:
+ print(site, repr(e))
+
+
+main()
diff --git a/tests/net_inet 2/test_tls_sites.py.exp b/tests/net_inet 2/test_tls_sites.py.exp
new file mode 100644
index 000000000..2f3c113d2
--- /dev/null
+++ b/tests/net_inet 2/test_tls_sites.py.exp
@@ -0,0 +1,5 @@
+google.com ok
+www.google.com ok
+api.telegram.org ok
+api.pushbullet.com ok
+w9rybpfril.execute-api.ap-southeast-2.amazonaws.com ok
diff --git a/tests/run-bench-tests 2 b/tests/run-bench-tests 2
new file mode 100755
index 000000000..f4a6776cb
--- /dev/null
+++ b/tests/run-bench-tests 2
@@ -0,0 +1,97 @@
+#! /usr/bin/env python3
+
+import os
+import subprocess
+import sys
+import argparse
+import re
+from glob import glob
+from collections import defaultdict
+
+# Tests require at least CPython 3.3. If your default python3 executable
+# is of lower version, you can point MICROPY_CPYTHON3 environment var
+# to the correct executable.
+if os.name == 'nt':
+ CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe')
+ MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe')
+else:
+ CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
+ MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython')
+
+def run_tests(pyb, test_dict):
+ test_count = 0
+ testcase_count = 0
+
+ for base_test, tests in sorted(test_dict.items()):
+ print(base_test + ":")
+ for test_file in tests:
+
+ # run MicroPython
+ if pyb is None:
+ # run on PC
+ try:
+ output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file[0]])
+ except subprocess.CalledProcessError:
+ output_mupy = b'CRASH'
+ else:
+ # run on pyboard
+ pyb.enter_raw_repl()
+ try:
+ output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n')
+ except pyboard.PyboardError:
+ output_mupy = b'CRASH'
+
+ output_mupy = float(output_mupy.strip())
+ test_file[1] = output_mupy
+ testcase_count += 1
+
+ test_count += 1
+ baseline = None
+ for t in tests:
+ if baseline is None:
+ baseline = t[1]
+ print(" %.3fs (%+06.2f%%) %s" % (t[1], (t[1] * 100 / baseline) - 100, t[0]))
+
+ print("{} tests performed ({} individual testcases)".format(test_count, testcase_count))
+
+ # all tests succeeded
+ return True
+
+def main():
+ cmd_parser = argparse.ArgumentParser(description='Run tests for MicroPython.')
+ cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard')
+ cmd_parser.add_argument('files', nargs='*', help='input test files')
+ args = cmd_parser.parse_args()
+
+ # Note pyboard support is copied over from run-tests, not testes, and likely needs revamping
+ if args.pyboard:
+ import pyboard
+ pyb = pyboard.Pyboard('/dev/ttyACM0')
+ pyb.enter_raw_repl()
+ else:
+ pyb = None
+
+ if len(args.files) == 0:
+ if pyb is None:
+ # run PC tests
+ test_dirs = ('bench',)
+ else:
+ # run pyboard tests
+ test_dirs = ('basics', 'float', 'pyb')
+ tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files)
+ else:
+ # tests explicitly given
+ tests = sorted(args.files)
+
+ test_dict = defaultdict(lambda: [])
+ for t in tests:
+ m = re.match(r"(.+?)-(.+)\.py", t)
+ if not m:
+ continue
+ test_dict[m.group(1)].append([t, None])
+
+ if not run_tests(pyb, test_dict):
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/run-tests 2 b/tests/run-tests 2
new file mode 100755
index 000000000..e28600361
--- /dev/null
+++ b/tests/run-tests 2
@@ -0,0 +1,615 @@
+#! /usr/bin/env python3
+
+import os
+import subprocess
+import sys
+import platform
+import argparse
+import re
+import threading
+import multiprocessing
+from multiprocessing.pool import ThreadPool
+from glob import glob
+
+# Tests require at least CPython 3.3. If your default python3 executable
+# is of lower version, you can point MICROPY_CPYTHON3 environment var
+# to the correct executable.
+if os.name == 'nt':
+ CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe')
+ MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe')
+else:
+ CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
+ MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython')
+
+# mpy-cross is only needed if --via-mpy command-line arg is passed
+MPYCROSS = os.getenv('MICROPY_MPYCROSS', '../mpy-cross/mpy-cross')
+
+# Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale
+os.environ['PYTHONIOENCODING'] = 'utf-8'
+
+def rm_f(fname):
+ if os.path.exists(fname):
+ os.remove(fname)
+
+
+# unescape wanted regex chars and escape unwanted ones
+def convert_regex_escapes(line):
+ cs = []
+ escape = False
+ for c in str(line, 'utf8'):
+ if escape:
+ escape = False
+ cs.append(c)
+ elif c == '\\':
+ escape = True
+ elif c in ('(', ')', '[', ']', '{', '}', '.', '*', '+', '^', '$'):
+ cs.append('\\' + c)
+ else:
+ cs.append(c)
+ # accept carriage-return(s) before final newline
+ if cs[-1] == '\n':
+ cs[-1] = '\r*\n'
+ return bytes(''.join(cs), 'utf8')
+
+
+def run_micropython(pyb, args, test_file, is_special=False):
+ special_tests = (
+ 'micropython/meminfo.py', 'basics/bytes_compare3.py',
+ 'basics/builtin_help.py', 'thread/thread_exc2.py',
+ )
+ had_crash = False
+ if pyb is None:
+ # run on PC
+ if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests:
+ # special handling for tests of the unix cmdline program
+ is_special = True
+
+ if is_special:
+ # check for any cmdline options needed for this test
+ args = [MICROPYTHON]
+ with open(test_file, 'rb') as f:
+ line = f.readline()
+ if line.startswith(b'# cmdline:'):
+ # subprocess.check_output on Windows only accepts strings, not bytes
+ args += [str(c, 'utf-8') for c in line[10:].strip().split()]
+
+ # run the test, possibly with redirected input
+ try:
+ if 'repl_' in test_file:
+ # Need to use a PTY to test command line editing
+ try:
+ import pty
+ except ImportError:
+ # in case pty module is not available, like on Windows
+ return b'SKIP\n'
+ import select
+
+ def get(required=False):
+ rv = b''
+ while True:
+ ready = select.select([emulator], [], [], 0.02)
+ if ready[0] == [emulator]:
+ rv += os.read(emulator, 1024)
+ else:
+ if not required or rv:
+ return rv
+
+ def send_get(what):
+ os.write(emulator, what)
+ return get()
+
+ with open(test_file, 'rb') as f:
+ # instead of: output_mupy = subprocess.check_output(args, stdin=f)
+ # openpty returns two read/write file descriptors. The first one is
+ # used by the program which provides the virtual
+ # terminal service, and the second one is used by the
+ # subprogram which requires a tty to work.
+ emulator, subterminal = pty.openpty()
+ p = subprocess.Popen(args, stdin=subterminal, stdout=subterminal,
+ stderr=subprocess.STDOUT, bufsize=0)
+ banner = get(True)
+ output_mupy = banner + b''.join(send_get(line) for line in f)
+ send_get(b'\x04') # exit the REPL, so coverage info is saved
+ p.kill()
+ os.close(emulator)
+ os.close(subterminal)
+ else:
+ output_mupy = subprocess.check_output(args + [test_file], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError:
+ return b'CRASH'
+
+ else:
+ # a standard test run on PC
+
+ # create system command
+ cmdlist = [MICROPYTHON, '-X', 'emit=' + args.emit]
+ if args.heapsize is not None:
+ cmdlist.extend(['-X', 'heapsize=' + args.heapsize])
+
+ # if running via .mpy, first compile the .py file
+ if args.via_mpy:
+ subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', test_file])
+ cmdlist.extend(['-m', 'mpytest'])
+ else:
+ cmdlist.append(test_file)
+
+ # run the actual test
+ e = {"MICROPYPATH": os.getcwd() + ":", "LANG": "en_US.UTF-8"}
+ p = subprocess.Popen(cmdlist, env=e, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ output_mupy = b''
+ while p.poll() is None:
+ output_mupy += p.stdout.read()
+ output_mupy += p.stdout.read()
+ if p.returncode != 0:
+ output_mupy = b'CRASH'
+
+ # clean up if we had an intermediate .mpy file
+ if args.via_mpy:
+ rm_f('mpytest.mpy')
+
+ else:
+ # run on pyboard
+ import pyboard
+ pyb.enter_raw_repl()
+ try:
+ output_mupy = pyb.execfile(test_file)
+ except pyboard.PyboardError:
+ had_crash = True
+ output_mupy = b'CRASH'
+
+ # canonical form for all ports/platforms is to use \n for end-of-line
+ output_mupy = output_mupy.replace(b'\r\n', b'\n')
+
+ # don't try to convert the output if we should skip this test
+ if had_crash or output_mupy in (b'SKIP\n', b'CRASH'):
+ return output_mupy
+
+ if is_special or test_file in special_tests:
+ # convert parts of the output that are not stable across runs
+ with open(test_file + '.exp', 'rb') as f:
+ lines_exp = []
+ for line in f.readlines():
+ if line == b'########\n':
+ line = (line,)
+ else:
+ line = (line, re.compile(convert_regex_escapes(line)))
+ lines_exp.append(line)
+ lines_mupy = [line + b'\n' for line in output_mupy.split(b'\n')]
+ if output_mupy.endswith(b'\n'):
+ lines_mupy = lines_mupy[:-1] # remove erroneous last empty line
+ i_mupy = 0
+ for i in range(len(lines_exp)):
+ if lines_exp[i][0] == b'########\n':
+ # 8x #'s means match 0 or more whole lines
+ line_exp = lines_exp[i + 1]
+ skip = 0
+ while i_mupy + skip < len(lines_mupy) and not line_exp[1].match(lines_mupy[i_mupy + skip]):
+ skip += 1
+ if i_mupy + skip >= len(lines_mupy):
+ lines_mupy[i_mupy] = b'######## FAIL\n'
+ break
+ del lines_mupy[i_mupy:i_mupy + skip]
+ lines_mupy.insert(i_mupy, b'########\n')
+ i_mupy += 1
+ else:
+ # a regex
+ if lines_exp[i][1].match(lines_mupy[i_mupy]):
+ lines_mupy[i_mupy] = lines_exp[i][0]
+ else:
+ #print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG
+ pass
+ i_mupy += 1
+ if i_mupy >= len(lines_mupy):
+ break
+ output_mupy = b''.join(lines_mupy)
+
+ return output_mupy
+
+
+def run_feature_check(pyb, args, base_path, test_file):
+ return run_micropython(pyb, args, base_path + "/feature_check/" + test_file, is_special=True)
+
+class ThreadSafeCounter:
+ def __init__(self, start=0):
+ self._value = start
+ self._lock = threading.Lock()
+
+ def add(self, to_add):
+ with self._lock: self._value += to_add
+
+ def append(self, arg):
+ self.add([arg])
+
+ @property
+ def value(self):
+ return self._value
+
+def run_tests(pyb, tests, args, base_path=".", num_threads=1):
+ test_count = ThreadSafeCounter()
+ testcase_count = ThreadSafeCounter()
+ passed_count = ThreadSafeCounter()
+ failed_tests = ThreadSafeCounter([])
+ skipped_tests = ThreadSafeCounter([])
+
+ skip_tests = set()
+ skip_native = False
+ skip_int_big = False
+ skip_set_type = False
+ skip_async = False
+ skip_const = False
+ skip_revops = False
+ skip_endian = False
+ has_complex = True
+ has_coverage = False
+
+ upy_float_precision = 32
+
+ # If we're asked to --list-tests, we can't assume that there's a
+ # connection to target, so we can't run feature checks usefully.
+ if not (args.list_tests or args.write_exp):
+ # Check if micropython.native is supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'native_check.py')
+ if output == b'CRASH':
+ skip_native = True
+
+ # Check if arbitrary-precision integers are supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'int_big.py')
+ if output != b'1000000000000000000000000000000000000000000000\n':
+ skip_int_big = True
+
+ # Check if set type (and set literals) is supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'set_check.py')
+ if output == b'CRASH':
+ skip_set_type = True
+
+ # Check if async/await keywords are supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'async_check.py')
+ if output == b'CRASH':
+ skip_async = True
+
+ # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'const.py')
+ if output == b'CRASH':
+ skip_const = True
+
+ # Check if __rOP__ special methods are supported, and skip such tests if it's not
+ output = run_feature_check(pyb, args, base_path, 'reverse_ops.py')
+ if output == b'TypeError\n':
+ skip_revops = True
+
+ # Check if emacs repl is supported, and skip such tests if it's not
+ t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py')
+ if not 'True' in str(t, 'ascii'):
+ skip_tests.add('cmdline/repl_emacs_keys.py')
+
+ upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py')
+ upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py'))
+ has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n'
+ has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n'
+ cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py'])
+ skip_endian = (upy_byteorder != cpy_byteorder)
+
+ # Some tests shouldn't be run under Travis CI
+ if os.getenv('TRAVIS') == 'true':
+ skip_tests.add('basics/memoryerror.py')
+ skip_tests.add('thread/thread_gc1.py') # has reliability issues
+ skip_tests.add('thread/thread_lock4.py') # has reliability issues
+ skip_tests.add('thread/stress_heap.py') # has reliability issues
+ skip_tests.add('thread/stress_recurse.py') # has reliability issues
+
+ if upy_float_precision == 0:
+ skip_tests.add('extmod/ujson_dumps_float.py')
+ skip_tests.add('extmod/ujson_loads_float.py')
+ skip_tests.add('misc/rge_sm.py')
+ if upy_float_precision < 32:
+ skip_tests.add('float/float2int_intbig.py') # requires fp32, there's float2int_fp30_intbig.py instead
+ skip_tests.add('float/string_format.py') # requires fp32, there's string_format_fp30.py instead
+ skip_tests.add('float/bytes_construct.py') # requires fp32
+ skip_tests.add('float/bytearray_construct.py') # requires fp32
+ if upy_float_precision < 64:
+ skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
+ skip_tests.add('float/float2int_doubleprec_intbig.py')
+ skip_tests.add('float/float_parse_doubleprec.py')
+
+ if not has_complex:
+ skip_tests.add('float/complex1.py')
+ skip_tests.add('float/complex1_intbig.py')
+ skip_tests.add('float/int_big_float.py')
+ skip_tests.add('float/true_value.py')
+ skip_tests.add('float/types.py')
+
+ if not has_coverage:
+ skip_tests.add('cmdline/cmd_parsetree.py')
+
+ # Some tests shouldn't be run on a PC
+ if args.target == 'unix':
+ # unix build does not have the GIL so can't run thread mutation tests
+ for t in tests:
+ if t.startswith('thread/mutate_'):
+ skip_tests.add(t)
+
+ # Some tests shouldn't be run on pyboard
+ if args.target != 'unix':
+ skip_tests.add('basics/exception_chain.py') # warning is not printed
+ skip_tests.add('micropython/meminfo.py') # output is very different to PC output
+ skip_tests.add('extmod/machine_mem.py') # raw memory access not supported
+
+ if args.target == 'wipy':
+ skip_tests.add('misc/print_exception.py') # requires error reporting full
+ skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes
+ skip_tests.add('extmod/zlibd_decompress.py') # requires zlib
+ skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy
+ skip_tests.add('extmod/urandom_basic.py') # requires urandom
+ skip_tests.add('extmod/urandom_extra.py') # requires urandom
+ elif args.target == 'esp8266':
+ skip_tests.add('misc/rge_sm.py') # too large
+ elif args.target == 'minimal':
+ skip_tests.add('basics/class_inplace_op.py') # all special methods not supported
+ skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support
+ skip_tests.add('misc/rge_sm.py') # too large
+ skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored
+
+ # Some tests are known to fail on 64-bit machines
+ if pyb is None and platform.architecture()[0] == '64bit':
+ pass
+
+ # Some tests use unsupported features on Windows
+ if os.name == 'nt':
+ skip_tests.add('import/import_file.py') # works but CPython prints forward slashes
+
+ # Some tests are known to fail with native emitter
+ # Remove them from the below when they work
+ if args.emit == 'native':
+ skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield
+ skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join gen_stack_overflow'.split()}) # require yield
+ skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2 coroutine'.split()}) # require yield
+ skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs
+ skip_tests.update({'basics/%s.py' % t for t in 'with_break with_continue with_return'.split()}) # require complete with support
+ skip_tests.add('basics/array_construct2.py') # requires generators
+ skip_tests.add('basics/bool1.py') # seems to randomly fail
+ skip_tests.add('basics/builtin_hash_gen.py') # requires yield
+ skip_tests.add('basics/class_bind_self.py') # requires yield
+ skip_tests.add('basics/del_deref.py') # requires checking for unbound local
+ skip_tests.add('basics/del_local.py') # requires checking for unbound local
+ skip_tests.add('basics/exception_chain.py') # raise from is not supported
+ skip_tests.add('basics/for_range.py') # requires yield_value
+ skip_tests.add('basics/try_finally_loops.py') # requires proper try finally code
+ skip_tests.add('basics/try_finally_return.py') # requires proper try finally code
+ skip_tests.add('basics/try_finally_return2.py') # requires proper try finally code
+ skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local
+ skip_tests.add('import/gen_context.py') # requires yield_value
+ skip_tests.add('misc/features.py') # requires raise_varargs
+ skip_tests.add('misc/rge_sm.py') # requires yield
+ skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info
+ skip_tests.add('misc/sys_exc_info.py') # sys.exc_info() is not supported for native
+ skip_tests.add('micropython/emg_exc.py') # because native doesn't have proper traceback info
+ skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info
+ skip_tests.add('micropython/heapalloc_iter.py') # requires generators
+ skip_tests.add('micropython/schedule.py') # native code doesn't check pending events
+ skip_tests.add('stress/gc_trace.py') # requires yield
+ skip_tests.add('stress/recursive_gen.py') # requires yield
+ skip_tests.add('extmod/vfs_userfs.py') # because native doesn't properly handle globals across different modules
+ skip_tests.add('../extmod/ulab/tests/argminmax.py') # requires yield
+
+ def run_one_test(test_file):
+ test_file = test_file.replace('\\', '/')
+
+ if args.filters:
+ # Default verdict is the opposit of the first action
+ verdict = "include" if args.filters[0][0] == "exclude" else "exclude"
+ for action, pat in args.filters:
+ if pat.search(test_file):
+ verdict = action
+ if verdict == "exclude":
+ return
+
+ test_basename = os.path.basename(test_file)
+ test_name = os.path.splitext(test_basename)[0]
+ is_native = test_name.startswith("native_") or test_name.startswith("viper_")
+ is_endian = test_name.endswith("_endian")
+ is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig")
+ is_set_type = test_name.startswith("set_") or test_name.startswith("frozenset")
+ is_async = test_name.startswith("async_")
+ is_const = test_name.startswith("const")
+
+ skip_it = test_file in skip_tests
+ skip_it |= skip_native and is_native
+ skip_it |= skip_endian and is_endian
+ skip_it |= skip_int_big and is_int_big
+ skip_it |= skip_set_type and is_set_type
+ skip_it |= skip_async and is_async
+ skip_it |= skip_const and is_const
+ skip_it |= skip_revops and test_name.startswith("class_reverse_op")
+
+ if args.list_tests:
+ if not skip_it:
+ print(test_file)
+ return
+
+ if skip_it:
+ print("skip ", test_file)
+ skipped_tests.append(test_name)
+ return
+
+ # get expected output
+ test_file_expected = test_file + '.exp'
+ if os.path.isfile(test_file_expected):
+ # expected output given by a file, so read that in
+ with open(test_file_expected, 'rb') as f:
+ output_expected = f.read()
+ else:
+ # run CPython to work out expected output
+ e = {"PYTHONPATH": os.getcwd(),
+ "PATH": os.environ["PATH"],
+ "LANG": "en_US.UTF-8"}
+ p = subprocess.Popen([CPYTHON3, '-B', test_file], env=e, stdout=subprocess.PIPE)
+ output_expected = b''
+ while p.poll() is None:
+ output_expected += p.stdout.read()
+ output_expected += p.stdout.read()
+ if p.returncode != 0:
+ output_expected = b'CPYTHON3 CRASH'
+ elif args.write_exp:
+ with open(test_file_expected, 'wb') as f:
+ f.write(output_expected)
+
+ # canonical form for all host platforms is to use \n for end-of-line
+ output_expected = output_expected.replace(b'\r\n', b'\n')
+
+ if args.write_exp:
+ return
+
+ # run MicroPython
+ output_mupy = run_micropython(pyb, args, test_file)
+
+ if output_mupy == b'SKIP\n':
+ print("skip ", test_file)
+ skipped_tests.append(test_name)
+ return
+
+ testcase_count.add(len(output_expected.splitlines()))
+
+ filename_expected = test_basename + ".exp"
+ filename_mupy = test_basename + ".out"
+
+ if output_expected == output_mupy:
+ print("pass ", test_file)
+ passed_count.add(1)
+ rm_f(filename_expected)
+ rm_f(filename_mupy)
+ else:
+ with open(filename_expected, "wb") as f:
+ f.write(output_expected)
+ with open(filename_mupy, "wb") as f:
+ f.write(output_mupy)
+ print("### Expected")
+ print(output_expected)
+ print("### Actual")
+ print(output_mupy)
+ print("FAIL ", test_file)
+ failed_tests.append(test_name)
+
+ test_count.add(1)
+
+ if args.list_tests:
+ return True
+
+ if num_threads > 1:
+ pool = ThreadPool(num_threads)
+ pool.map(run_one_test, tests)
+ else:
+ for test in tests:
+ run_one_test(test)
+
+ print("{} tests performed ({} individual testcases)".format(test_count.value, testcase_count.value))
+ print("{} tests passed".format(passed_count.value))
+
+ if len(skipped_tests.value) > 0:
+ print("{} tests skipped: {}".format(len(skipped_tests.value), ' '.join(sorted(skipped_tests.value))))
+ if len(failed_tests.value) > 0:
+ print("{} tests failed: {}".format(len(failed_tests.value), ' '.join(sorted(failed_tests.value))))
+ return False
+
+ # all tests succeeded
+ return True
+
+
+class append_filter(argparse.Action):
+
+ def __init__(self, option_strings, dest, **kwargs):
+ super().__init__(option_strings, dest, default=[], **kwargs)
+
+ def __call__(self, parser, args, value, option):
+ if not hasattr(args, self.dest):
+ args.filters = []
+ if option.startswith(("-e", "--e")):
+ option = "exclude"
+ else:
+ option = "include"
+ args.filters.append((option, re.compile(value)))
+
+
+def main():
+ cmd_parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='Run and manage tests for MicroPython.',
+ epilog='''\
+Options -i and -e can be multiple and processed in the order given. Regex
+"search" (vs "match") operation is used. An action (include/exclude) of
+the last matching regex is used:
+ run-tests -i async - exclude all, then include tests containg "async" anywhere
+ run-tests -e '/big.+int' - include all, then exclude by regex
+ run-tests -e async -i async_foo - include all, exclude async, yet still include async_foo
+''')
+ cmd_parser.add_argument('--target', default='unix', help='the target platform')
+ cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard')
+ cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device')
+ cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username')
+ cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password')
+ cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)')
+ cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py')
+ cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py')
+ cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython')
+ cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them')
+ cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)')
+ cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)')
+ cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first')
+ cmd_parser.add_argument('--keep-path', action='store_true', help='do not clear MICROPYPATH when running tests')
+ cmd_parser.add_argument('-j', '--jobs', default=1, metavar='N', type=int, help='Number of tests to run simultaneously')
+ cmd_parser.add_argument('--auto-jobs', action='store_const', dest='jobs', const=multiprocessing.cpu_count(), help='Set the -j values to the CPU (thread) count')
+ cmd_parser.add_argument('files', nargs='*', help='input test files')
+ args = cmd_parser.parse_args()
+
+ EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal')
+ if args.target == 'unix' or args.list_tests:
+ pyb = None
+ elif args.target in EXTERNAL_TARGETS:
+ import pyboard
+ pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password)
+ pyb.enter_raw_repl()
+ else:
+ raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS))
+
+ if len(args.files) == 0:
+ if args.test_dirs is None:
+ if args.target == 'pyboard':
+ # run pyboard tests
+ test_dirs = ('basics', 'micropython', 'float', 'misc', 'stress', 'extmod', 'pyb', 'pybnative', 'inlineasm')
+ elif args.target in ('esp8266', 'esp32', 'minimal'):
+ test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod')
+ elif args.target == 'wipy':
+ # run WiPy tests
+ test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'wipy')
+ else:
+ # run PC tests
+ test_dirs = (
+ 'basics', 'micropython', 'float', 'import', 'io', 'misc',
+ 'stress', 'unicode', 'extmod', '../extmod/ulab/tests', 'unix', 'cmdline',
+ )
+ else:
+ # run tests from these directories
+ test_dirs = args.test_dirs
+ tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files)
+ else:
+ # tests explicitly given
+ tests = args.files
+
+ if not args.keep_path:
+ # clear search path to make sure tests use only builtin modules
+ os.environ['MICROPYPATH'] = ''
+
+ # Even if we run completely different tests in a different directory,
+ # we need to access feature_check's from the same directory as the
+ # run-tests script itself.
+ base_path = os.path.dirname(sys.argv[0]) or "."
+ try:
+ res = run_tests(pyb, tests, args, base_path, args.jobs)
+ finally:
+ if pyb:
+ pyb.close()
+
+ if not res:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/stress 2/dict_copy.py b/tests/stress 2/dict_copy.py
new file mode 100644
index 000000000..36db9bb7e
--- /dev/null
+++ b/tests/stress 2/dict_copy.py
@@ -0,0 +1,7 @@
+# copying a large dictionary
+
+a = {i:2*i for i in range(1000)}
+b = a.copy()
+for i in range(1000):
+ print(i, b[i])
+print(len(b))
diff --git a/tests/stress 2/dict_create.py b/tests/stress 2/dict_create.py
new file mode 100644
index 000000000..e9db40a8e
--- /dev/null
+++ b/tests/stress 2/dict_create.py
@@ -0,0 +1,8 @@
+# create a large dictionary
+
+d = {}
+x = 1
+while x < 1000:
+ d[x] = x
+ x += 1
+print(d[500])
diff --git a/tests/stress 2/dict_create_max.py b/tests/stress 2/dict_create_max.py
new file mode 100644
index 000000000..3c75db20d
--- /dev/null
+++ b/tests/stress 2/dict_create_max.py
@@ -0,0 +1,13 @@
+# The aim with this test is to hit the maximum resize/rehash size of a dict,
+# where there are no more primes in the table of growing allocation sizes.
+# This value is 54907 items.
+
+d = {}
+try:
+ for i in range(54908):
+ d[i] = i
+except MemoryError:
+ pass
+
+# Just check the dict still has the first value
+print(d[0])
diff --git a/tests/stress 2/gc_trace.py b/tests/stress 2/gc_trace.py
new file mode 100644
index 000000000..72dc7b627
--- /dev/null
+++ b/tests/stress 2/gc_trace.py
@@ -0,0 +1,17 @@
+# test that the GC can trace nested objects
+
+try:
+ import gc
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+# test a big shallow object pointing to many unique objects
+lst = [[i] for i in range(200)]
+gc.collect()
+print(lst)
+
+# test a deep object
+lst = [[[[[(i, j, k, l)] for i in range(3)] for j in range(3)] for k in range(3)] for l in range(3)]
+gc.collect()
+print(lst)
diff --git a/tests/stress 2/list_sort.py b/tests/stress 2/list_sort.py
new file mode 100644
index 000000000..3a7701a1e
--- /dev/null
+++ b/tests/stress 2/list_sort.py
@@ -0,0 +1,6 @@
+# test large list sorting (should not stack overflow)
+l = list(range(2000))
+l.sort()
+print(l[0], l[-1])
+l.sort(reverse=True)
+print(l[0], l[-1])
diff --git a/tests/stress 2/recursion.py b/tests/stress 2/recursion.py
new file mode 100644
index 000000000..227f48396
--- /dev/null
+++ b/tests/stress 2/recursion.py
@@ -0,0 +1,7 @@
+def foo():
+ foo()
+
+try:
+ foo()
+except RuntimeError:
+ print("RuntimeError")
diff --git a/tests/stress 2/recursive_data.py b/tests/stress 2/recursive_data.py
new file mode 100644
index 000000000..3b7fa5095
--- /dev/null
+++ b/tests/stress 2/recursive_data.py
@@ -0,0 +1,13 @@
+# This tests that printing recursive data structure doesn't lead to segfault.
+try:
+ import uio as io
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+l = [1, 2, 3, None]
+l[-1] = l
+try:
+ print(l, file=io.StringIO())
+except RuntimeError:
+ print("RuntimeError")
diff --git a/tests/stress 2/recursive_data.py.exp b/tests/stress 2/recursive_data.py.exp
new file mode 100644
index 000000000..8a2b9bfdd
--- /dev/null
+++ b/tests/stress 2/recursive_data.py.exp
@@ -0,0 +1 @@
+RuntimeError
diff --git a/tests/stress 2/recursive_gen.py b/tests/stress 2/recursive_gen.py
new file mode 100644
index 000000000..0e0d3914e
--- /dev/null
+++ b/tests/stress 2/recursive_gen.py
@@ -0,0 +1,18 @@
+# test deeply recursive generators
+
+# simple "yield from" recursion
+def gen():
+ yield from gen()
+try:
+ list(gen())
+except RuntimeError:
+ print('RuntimeError')
+
+# recursion via an iterator over a generator
+def gen2():
+ for x in gen2():
+ yield x
+try:
+ next(gen2())
+except RuntimeError:
+ print('RuntimeError')
diff --git a/tests/stress 2/recursive_iternext.py b/tests/stress 2/recursive_iternext.py
new file mode 100644
index 000000000..edb5a843f
--- /dev/null
+++ b/tests/stress 2/recursive_iternext.py
@@ -0,0 +1,57 @@
+# This tests that recursion with iternext doesn't lead to segfault.
+try:
+ enumerate
+ filter
+ map
+ max
+ zip
+except:
+ print("SKIP")
+ raise SystemExit
+
+# We need to pick an N that is large enough to hit the recursion
+# limit, but not too large that we run out of heap memory.
+try:
+ # large stack/heap, eg unix
+ [0] * 80000
+ N = 2400
+except:
+ try:
+ # medium, eg pyboard
+ [0] * 10000
+ N = 1000
+ except:
+ # small, eg esp8266
+ N = 100
+
+try:
+ x = (1, 2)
+ for i in range(N):
+ x = enumerate(x)
+ tuple(x)
+except RuntimeError:
+ print("RuntimeError")
+
+try:
+ x = (1, 2)
+ for i in range(N):
+ x = filter(None, x)
+ tuple(x)
+except RuntimeError:
+ print("RuntimeError")
+
+try:
+ x = (1, 2)
+ for i in range(N):
+ x = map(max, x, ())
+ tuple(x)
+except RuntimeError:
+ print("RuntimeError")
+
+try:
+ x = (1, 2)
+ for i in range(N):
+ x = zip(x)
+ tuple(x)
+except RuntimeError:
+ print("RuntimeError")
diff --git a/tests/stress 2/recursive_iternext.py.exp b/tests/stress 2/recursive_iternext.py.exp
new file mode 100644
index 000000000..80d1488a3
--- /dev/null
+++ b/tests/stress 2/recursive_iternext.py.exp
@@ -0,0 +1,4 @@
+RuntimeError
+RuntimeError
+RuntimeError
+RuntimeError
diff --git a/tests/thread 2/mutate_bytearray.py b/tests/thread 2/mutate_bytearray.py
new file mode 100644
index 000000000..5015c3f9c
--- /dev/null
+++ b/tests/thread 2/mutate_bytearray.py
@@ -0,0 +1,46 @@
+# test concurrent mutating access to a shared bytearray object
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# the shared bytearray
+ba = bytearray()
+
+# main thread function
+def th(n, lo, hi):
+ for repeat in range(n):
+ for i in range(lo, hi):
+ l = len(ba)
+ ba.append(i)
+ assert len(ba) >= l + 1
+
+ l = len(ba)
+ ba.extend(bytearray([i]))
+ assert len(ba) >= l + 1
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+n_repeat = 4 # use 40 for more stressful test (uses more heap)
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (n_repeat, i * 256 // n_thread, (i + 1) * 256 // n_thread))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+
+# check bytearray has correct contents
+print(len(ba))
+count = [0 for _ in range(256)]
+for b in ba:
+ count[b] += 1
+print(count)
diff --git a/tests/thread 2/mutate_dict.py b/tests/thread 2/mutate_dict.py
new file mode 100644
index 000000000..563fce39d
--- /dev/null
+++ b/tests/thread 2/mutate_dict.py
@@ -0,0 +1,44 @@
+# test concurrent mutating access to a shared dict object
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# the shared dict
+di = {'a':'A', 'b':'B', 'c':'C', 'd':'D'}
+
+# main thread function
+def th(n, lo, hi):
+ for repeat in range(n):
+ for i in range(lo, hi):
+ di[i] = repeat + i
+ assert di[i] == repeat + i
+
+ del di[i]
+ assert i not in di
+
+ di[i] = repeat + i
+ assert di[i] == repeat + i
+
+ assert di.pop(i) == repeat + i
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (30, i * 300, (i + 1) * 300))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+
+# check dict has correct contents
+print(sorted(di.items()))
diff --git a/tests/thread 2/mutate_instance.py b/tests/thread 2/mutate_instance.py
new file mode 100644
index 000000000..2ecfbe109
--- /dev/null
+++ b/tests/thread 2/mutate_instance.py
@@ -0,0 +1,45 @@
+# test concurrent mutating access to a shared user instance
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# the shared user class and instance
+class User:
+ def __init__(self):
+ self.a = 'A'
+ self.b = 'B'
+ self.c = 'C'
+user = User()
+
+# main thread function
+def th(n, lo, hi):
+ for repeat in range(n):
+ for i in range(lo, hi):
+ setattr(user, 'attr_%u' % i, repeat + i)
+ assert getattr(user, 'attr_%u' % i) == repeat + i
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_repeat = 30
+n_range = 50 # 300 for stressful test (uses more heap)
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (n_repeat, i * n_range, (i + 1) * n_range))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+
+# check user instance has correct contents
+print(user.a, user.b, user.c)
+for i in range(n_thread * n_range):
+ assert getattr(user, 'attr_%u' % i) == n_repeat - 1 + i
diff --git a/tests/thread 2/mutate_list.py b/tests/thread 2/mutate_list.py
new file mode 100644
index 000000000..d70e8a8a3
--- /dev/null
+++ b/tests/thread 2/mutate_list.py
@@ -0,0 +1,46 @@
+# test concurrent mutating access to a shared list object
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# the shared list
+li = list()
+
+# main thread function
+def th(n, lo, hi):
+ for repeat in range(n):
+ for i in range(lo, hi):
+ li.append(i)
+ assert li.count(i) == repeat + 1
+
+ li.extend([i, i])
+ assert li.count(i) == repeat + 3
+
+ li.remove(i)
+ assert li.count(i) == repeat + 2
+
+ li.remove(i)
+ assert li.count(i) == repeat + 1
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (4, i * 60, (i + 1) * 60))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+
+# check list has correct contents
+li.sort()
+print(li)
diff --git a/tests/thread 2/mutate_set.py b/tests/thread 2/mutate_set.py
new file mode 100644
index 000000000..c4529f356
--- /dev/null
+++ b/tests/thread 2/mutate_set.py
@@ -0,0 +1,39 @@
+# test concurrent mutating access to a shared set object
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# the shared set
+se = set([-1, -2, -3, -4])
+
+# main thread function
+def th(n, lo, hi):
+ for repeat in range(n):
+ for i in range(lo, hi):
+ se.add(i)
+ assert i in se
+
+ se.remove(i)
+ assert i not in se
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (50, i * 500, (i + 1) * 500))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+
+# check set has correct contents
+print(sorted(se))
diff --git a/tests/thread 2/stress_aes.py b/tests/thread 2/stress_aes.py
new file mode 100644
index 000000000..ebf7af371
--- /dev/null
+++ b/tests/thread 2/stress_aes.py
@@ -0,0 +1,257 @@
+# Stress test for threads using AES encryption routines.
+#
+# AES was chosen because it is integer based and inplace so doesn't use the
+# heap. It is therefore a good test of raw performance and correctness of the
+# VM/runtime. It can be used to measure threading performance (concurrency is
+# in principle possible) and correctness (it's non trivial for the encryption/
+# decryption to give the correct answer).
+#
+# The AES code comes first (code originates from a C version authored by D.P.George)
+# and then the test harness at the bottom. It can be tuned to be more/less
+# aggressive by changing the amount of data to encrypt, the number of loops and
+# the number of threads.
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+##################################################################
+# discrete arithmetic routines, mostly from a precomputed table
+
+# non-linear, invertible, substitution box
+aes_s_box_table = bytes((
+ 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
+ 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
+ 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
+ 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
+ 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
+ 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
+ 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
+ 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
+ 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
+ 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
+ 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
+ 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
+ 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
+ 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
+ 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
+ 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
+))
+
+# multiplication of polynomials modulo x^8 + x^4 + x^3 + x + 1 = 0x11b
+def aes_gf8_mul_2(x):
+ if x & 0x80:
+ return (x << 1) ^ 0x11b
+ else:
+ return x << 1
+
+def aes_gf8_mul_3(x):
+ return x ^ aes_gf8_mul_2(x)
+
+# non-linear, invertible, substitution box
+def aes_s_box(a):
+ return aes_s_box_table[a & 0xff]
+
+# return 0x02^(a-1) in GF(2^8)
+def aes_r_con(a):
+ ans = 1
+ while a > 1:
+ ans <<= 1;
+ if ans & 0x100:
+ ans ^= 0x11b
+ a -= 1
+ return ans
+
+##################################################################
+# basic AES algorithm; see FIPS-197
+#
+# Think of it as a pseudo random number generator, with each
+# symbol in the sequence being a 16 byte block (the state). The
+# key is a parameter of the algorithm and tells which particular
+# sequence of random symbols you want. The initial vector, IV,
+# sets the start of the sequence. The idea of a strong cipher
+# is that it's very difficult to guess the key even if you know
+# a large part of the sequence. The basic AES algorithm simply
+# provides such a sequence. En/de-cryption is implemented here
+# using OCB, where the sequence is xored against the plaintext.
+# Care must be taken to (almost) always choose a different IV.
+
+# all inputs must be size 16
+def aes_add_round_key(state, w):
+ for i in range(16):
+ state[i] ^= w[i]
+
+# combined sub_bytes, shift_rows, mix_columns, add_round_key
+# all inputs must be size 16
+def aes_sb_sr_mc_ark(state, w, w_idx, temp):
+ temp_idx = 0
+ for i in range(4):
+ x0 = aes_s_box_table[state[i * 4]]
+ x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]]
+ x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]]
+ x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]]
+ temp[temp_idx] = aes_gf8_mul_2(x0) ^ aes_gf8_mul_3(x1) ^ x2 ^ x3 ^ w[w_idx]
+ temp[temp_idx + 1] = x0 ^ aes_gf8_mul_2(x1) ^ aes_gf8_mul_3(x2) ^ x3 ^ w[w_idx + 1]
+ temp[temp_idx + 2] = x0 ^ x1 ^ aes_gf8_mul_2(x2) ^ aes_gf8_mul_3(x3) ^ w[w_idx + 2]
+ temp[temp_idx + 3] = aes_gf8_mul_3(x0) ^ x1 ^ x2 ^ aes_gf8_mul_2(x3) ^ w[w_idx + 3]
+ w_idx += 4
+ temp_idx += 4
+ for i in range(16):
+ state[i] = temp[i]
+
+# combined sub_bytes, shift_rows, add_round_key
+# all inputs must be size 16
+def aes_sb_sr_ark(state, w, w_idx, temp):
+ temp_idx = 0
+ for i in range(4):
+ x0 = aes_s_box_table[state[i * 4]]
+ x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]]
+ x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]]
+ x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]]
+ temp[temp_idx] = x0 ^ w[w_idx]
+ temp[temp_idx + 1] = x1 ^ w[w_idx + 1]
+ temp[temp_idx + 2] = x2 ^ w[w_idx + 2]
+ temp[temp_idx + 3] = x3 ^ w[w_idx + 3]
+ w_idx += 4
+ temp_idx += 4
+ for i in range(16):
+ state[i] = temp[i]
+
+# take state as input and change it to the next state in the sequence
+# state and temp have size 16, w has size 16 * (Nr + 1), Nr >= 1
+def aes_state(state, w, temp, nr):
+ aes_add_round_key(state, w)
+ w_idx = 16
+ for i in range(nr - 1):
+ aes_sb_sr_mc_ark(state, w, w_idx, temp)
+ w_idx += 16
+ aes_sb_sr_ark(state, w, w_idx, temp)
+
+# expand 'key' to 'w' for use with aes_state
+# key has size 4 * Nk, w has size 16 * (Nr + 1), temp has size 16
+def aes_key_expansion(key, w, temp, nk, nr):
+ for i in range(4 * nk):
+ w[i] = key[i]
+ w_idx = 4 * nk - 4
+ for i in range(nk, 4 * (nr + 1)):
+ t = temp
+ t_idx = 0
+ if i % nk == 0:
+ t[0] = aes_s_box(w[w_idx + 1]) ^ aes_r_con(i // nk)
+ for j in range(1, 4):
+ t[j] = aes_s_box(w[w_idx + (j + 1) % 4])
+ elif nk > 6 and i % nk == 4:
+ for j in range(0, 4):
+ t[j] = aes_s_box(w[w_idx + j])
+ else:
+ t = w
+ t_idx = w_idx
+ w_idx += 4
+ for j in range(4):
+ w[w_idx + j] = w[w_idx + j - 4 * nk] ^ t[t_idx + j]
+
+##################################################################
+# simple use of AES algorithm, using output feedback (OFB) mode
+
+class AES:
+ def __init__(self, keysize):
+ if keysize == 128:
+ self.nk = 4
+ self.nr = 10
+ elif keysize == 192:
+ self.nk = 6
+ self.nr = 12
+ else:
+ assert keysize == 256
+ self.nk = 8
+ self.nr = 14
+
+ self.state = bytearray(16)
+ self.w = bytearray(16 * (self.nr + 1))
+ self.temp = bytearray(16)
+ self.state_pos = 16
+
+ def set_key(self, key):
+ aes_key_expansion(key, self.w, self.temp, self.nk, self.nr)
+ self.state_pos = 16
+
+ def set_iv(self, iv):
+ for i in range(16):
+ self.state[i] = iv[i]
+ self.state_pos = 16;
+
+ def get_some_state(self, n_needed):
+ if self.state_pos >= 16:
+ aes_state(self.state, self.w, self.temp, self.nr)
+ self.state_pos = 0
+ n = 16 - self.state_pos
+ if n > n_needed:
+ n = n_needed
+ return n
+
+ def apply_to(self, data):
+ idx = 0
+ n = len(data)
+ while n > 0:
+ ln = self.get_some_state(n)
+ n -= ln
+ for i in range(ln):
+ data[idx + i] ^= self.state[self.state_pos + i]
+ idx += ln
+ self.state_pos += n
+
+##################################################################
+# test code
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+class LockedCounter:
+ def __init__(self):
+ self.lock = _thread.allocate_lock()
+ self.value = 0
+
+ def add(self, val):
+ self.lock.acquire()
+ self.value += val
+ self.lock.release()
+
+count = LockedCounter()
+
+def thread_entry():
+ global count
+
+ aes = AES(256)
+ key = bytearray(256 // 8)
+ iv = bytearray(16)
+ data = bytearray(128)
+ # from now on we don't use the heap
+
+ for loop in range(5):
+ # encrypt
+ aes.set_key(key)
+ aes.set_iv(iv)
+ for i in range(8):
+ aes.apply_to(data)
+
+ # decrypt
+ aes.set_key(key)
+ aes.set_iv(iv)
+ for i in range(8):
+ aes.apply_to(data)
+
+ # verify
+ for i in range(len(data)):
+ assert data[i] == 0
+
+ count.add(1)
+
+if __name__ == '__main__':
+ n_thread = 20
+ for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, ())
+ while count.value < n_thread:
+ time.sleep(1)
diff --git a/tests/thread 2/stress_create.py b/tests/thread 2/stress_create.py
new file mode 100644
index 000000000..2399746cc
--- /dev/null
+++ b/tests/thread 2/stress_create.py
@@ -0,0 +1,22 @@
+# stress test for creating many threads
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def thread_entry(n):
+ pass
+
+thread_num = 0
+while thread_num < 500:
+ try:
+ _thread.start_new_thread(thread_entry, (thread_num,))
+ thread_num += 1
+ except MemoryError:
+ pass
+
+# wait for the last threads to terminate
+time.sleep(1)
+print('done')
diff --git a/tests/thread 2/stress_heap.py b/tests/thread 2/stress_heap.py
new file mode 100644
index 000000000..206cf1a86
--- /dev/null
+++ b/tests/thread 2/stress_heap.py
@@ -0,0 +1,48 @@
+# stress test for the heap by allocating lots of objects within threads
+# allocates about 5mb on the heap
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def last(l):
+ return l[-1]
+
+def thread_entry(n):
+ # allocate a bytearray and fill it
+ data = bytearray(i for i in range(256))
+
+ # run a loop which allocates a small list and uses it each iteration
+ lst = 8 * [0]
+ sum = 0
+ for i in range(n):
+ sum += last(lst)
+ lst = [0, 0, 0, 0, 0, 0, 0, i + 1]
+
+ # check that the bytearray still has the right data
+ for i, b in enumerate(data):
+ assert i == b
+
+ # print the result of the loop and indicate we are finished
+ with lock:
+ print(sum, lst[-1])
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 10
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, (10000,))
+
+# wait for threads to finish
+while n_finished < n_thread:
+ time.sleep(1)
diff --git a/tests/thread 2/stress_recurse.py b/tests/thread 2/stress_recurse.py
new file mode 100644
index 000000000..8edee246a
--- /dev/null
+++ b/tests/thread 2/stress_recurse.py
@@ -0,0 +1,27 @@
+# test hitting the function recursion limit within a thread
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+def foo():
+ foo()
+
+def thread_entry():
+ try:
+ foo()
+ except RuntimeError:
+ print('RuntimeError')
+ global finished
+ finished = True
+
+finished = False
+
+_thread.start_new_thread(thread_entry, ())
+
+# busy wait for thread to finish
+while not finished:
+ pass
+print('done')
diff --git a/tests/thread 2/thread_exc1.py b/tests/thread 2/thread_exc1.py
new file mode 100644
index 000000000..e00a16bd2
--- /dev/null
+++ b/tests/thread 2/thread_exc1.py
@@ -0,0 +1,32 @@
+# test raising and catching an exception within a thread
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+def foo():
+ raise ValueError
+
+def thread_entry():
+ try:
+ foo()
+ except ValueError:
+ pass
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, ())
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+print('done')
diff --git a/tests/thread 2/thread_exc2.py b/tests/thread 2/thread_exc2.py
new file mode 100644
index 000000000..35cb32441
--- /dev/null
+++ b/tests/thread 2/thread_exc2.py
@@ -0,0 +1,10 @@
+# test raising exception within thread which is not caught
+import utime
+import _thread
+
+def thread_entry():
+ raise ValueError
+
+_thread.start_new_thread(thread_entry, ())
+utime.sleep(1)
+print('done')
diff --git a/tests/thread 2/thread_exc2.py.exp b/tests/thread 2/thread_exc2.py.exp
new file mode 100644
index 000000000..cc7a20aa2
--- /dev/null
+++ b/tests/thread 2/thread_exc2.py.exp
@@ -0,0 +1,5 @@
+Unhandled exception in thread started by <function thread_entry at 0x\[0-9a-f\]\+>
+Traceback (most recent call last):
+ File \.\+, line 6, in thread_entry
+ValueError:
+done
diff --git a/tests/thread 2/thread_exit1.py b/tests/thread 2/thread_exit1.py
new file mode 100644
index 000000000..ad7b01d89
--- /dev/null
+++ b/tests/thread 2/thread_exit1.py
@@ -0,0 +1,21 @@
+# test _thread.exit() function
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def thread_entry():
+ _thread.exit()
+
+_thread.start_new_thread(thread_entry, ())
+_thread.start_new_thread(thread_entry, ())
+
+# wait for threads to finish
+time.sleep(1)
+print('done')
diff --git a/tests/thread 2/thread_exit2.py b/tests/thread 2/thread_exit2.py
new file mode 100644
index 000000000..6bff8a173
--- /dev/null
+++ b/tests/thread 2/thread_exit2.py
@@ -0,0 +1,21 @@
+# test raising SystemExit to finish a thread
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def thread_entry():
+ raise SystemExit
+
+_thread.start_new_thread(thread_entry, ())
+_thread.start_new_thread(thread_entry, ())
+
+# wait for threads to finish
+time.sleep(1)
+print('done')
diff --git a/tests/thread 2/thread_gc1.py b/tests/thread 2/thread_gc1.py
new file mode 100644
index 000000000..2ea189161
--- /dev/null
+++ b/tests/thread 2/thread_gc1.py
@@ -0,0 +1,36 @@
+# test that we can run the garbage collector within threads
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import gc
+import _thread
+
+def thread_entry(n):
+ # allocate a bytearray and fill it
+ data = bytearray(i for i in range(256))
+
+ # do some work and call gc.collect() a few times
+ for i in range(n):
+ for i in range(len(data)):
+ data[i] = data[i]
+ gc.collect()
+
+ # print whether the data remains intact and indicate we are finished
+ with lock:
+ print(list(data) == list(range(256)))
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, (10,))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
diff --git a/tests/thread 2/thread_ident1.py b/tests/thread 2/thread_ident1.py
new file mode 100644
index 000000000..9a6f89ff5
--- /dev/null
+++ b/tests/thread 2/thread_ident1.py
@@ -0,0 +1,23 @@
+# test _thread.get_ident() function
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+def thread_entry():
+ tid = _thread.get_ident()
+ print('thread', type(tid) == int, tid != 0, tid != tid_main)
+ global finished
+ finished = True
+
+tid_main = _thread.get_ident()
+print('main', type(tid_main) == int, tid_main != 0)
+
+finished = False
+_thread.start_new_thread(thread_entry, ())
+
+while not finished:
+ pass
+print('done')
diff --git a/tests/thread 2/thread_lock1.py b/tests/thread 2/thread_lock1.py
new file mode 100644
index 000000000..c2d7c9d1e
--- /dev/null
+++ b/tests/thread 2/thread_lock1.py
@@ -0,0 +1,48 @@
+# test _thread lock object using a single thread
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+# create lock
+lock = _thread.allocate_lock()
+
+print(type(lock) == _thread.LockType)
+
+# should be unlocked
+print(lock.locked())
+
+# basic acquire and release
+print(lock.acquire())
+print(lock.locked())
+lock.release()
+print(lock.locked())
+
+# try acquire twice (second should fail)
+print(lock.acquire())
+print(lock.locked())
+print(lock.acquire(0))
+print(lock.locked())
+lock.release()
+print(lock.locked())
+
+# test with capabilities of lock
+with lock:
+ print(lock.locked())
+
+# test that lock is unlocked if an error is rasied
+try:
+ with lock:
+ print(lock.locked())
+ raise KeyError
+except KeyError:
+ print('KeyError')
+ print(lock.locked())
+
+# test that we can't release an unlocked lock
+try:
+ lock.release()
+except RuntimeError:
+ print('RuntimeError')
diff --git a/tests/thread 2/thread_lock2.py b/tests/thread 2/thread_lock2.py
new file mode 100644
index 000000000..4ef912dff
--- /dev/null
+++ b/tests/thread 2/thread_lock2.py
@@ -0,0 +1,26 @@
+# test _thread lock objects with multiple threads
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+lock = _thread.allocate_lock()
+
+def thread_entry():
+ lock.acquire()
+ print('have it')
+ lock.release()
+
+# spawn the threads
+for i in range(4):
+ _thread.start_new_thread(thread_entry, ())
+
+# wait for threads to finish
+time.sleep(1)
+print('done')
diff --git a/tests/thread 2/thread_lock3.py b/tests/thread 2/thread_lock3.py
new file mode 100644
index 000000000..35808d99c
--- /dev/null
+++ b/tests/thread 2/thread_lock3.py
@@ -0,0 +1,29 @@
+# test thread coordination using a lock object
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+lock = _thread.allocate_lock()
+n_thread = 10
+n_finished = 0
+
+def thread_entry(idx):
+ global n_finished
+ while True:
+ with lock:
+ if n_finished == idx:
+ break
+ print('my turn:', idx)
+ with lock:
+ n_finished += 1
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, (i,))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
diff --git a/tests/thread 2/thread_lock4.py b/tests/thread 2/thread_lock4.py
new file mode 100644
index 000000000..440f3e90c
--- /dev/null
+++ b/tests/thread 2/thread_lock4.py
@@ -0,0 +1,53 @@
+# test using lock to coordinate access to global mutable objects
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def fac(n):
+ x = 1
+ for i in range(1, n + 1):
+ x *= i
+ return x
+
+def thread_entry():
+ while True:
+ with jobs_lock:
+ try:
+ f, arg = jobs.pop(0)
+ except IndexError:
+ return
+ ans = f(arg)
+ with output_lock:
+ output.append((arg, ans))
+
+# create a list of jobs
+jobs = [(fac, i) for i in range(20, 80)]
+jobs_lock = _thread.allocate_lock()
+n_jobs = len(jobs)
+
+# create a list to store the results
+output = []
+output_lock = _thread.allocate_lock()
+
+# spawn threads to do the jobs
+for i in range(4):
+ _thread.start_new_thread(thread_entry, ())
+
+# wait for the jobs to complete
+while True:
+ with jobs_lock:
+ if len(output) == n_jobs:
+ break
+ time.sleep(1)
+
+# sort and print the results
+output.sort(key=lambda x: x[0])
+for arg, ans in output:
+ print(arg, ans)
diff --git a/tests/thread 2/thread_qstr1.py b/tests/thread 2/thread_qstr1.py
new file mode 100644
index 000000000..dccfb7f51
--- /dev/null
+++ b/tests/thread 2/thread_qstr1.py
@@ -0,0 +1,41 @@
+# test concurrent interning of strings
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+# function to check the interned string
+def check(s, val):
+ assert type(s) == str
+ assert int(s) == val
+
+# main thread function
+def th(base, n):
+ for i in range(n):
+ # this will intern the string and check it
+ exec("check('%u', %u)" % (base + i, base + i))
+
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+n_qstr_per_thread = 100 # make 1000 for a more stressful test (uses more heap)
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(th, (i * n_qstr_per_thread, n_qstr_per_thread))
+
+# wait for threads to finish
+while n_finished < n_thread:
+ time.sleep(1)
+
+print('pass')
diff --git a/tests/thread 2/thread_shared1.py b/tests/thread 2/thread_shared1.py
new file mode 100644
index 000000000..de339ad7f
--- /dev/null
+++ b/tests/thread 2/thread_shared1.py
@@ -0,0 +1,33 @@
+# test capability for threads to access a shared immutable data structure
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+def foo(i):
+ pass
+
+def thread_entry(n, tup):
+ for i in tup:
+ foo(i)
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 2
+n_finished = 0
+
+# the shared data structure
+tup = (1, 2, 3, 4)
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, (100, tup))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+print(tup)
diff --git a/tests/thread 2/thread_shared2.py b/tests/thread 2/thread_shared2.py
new file mode 100644
index 000000000..2c749e688
--- /dev/null
+++ b/tests/thread 2/thread_shared2.py
@@ -0,0 +1,34 @@
+# test capability for threads to access a shared mutable data structure
+# (without contention because they access different parts of the structure)
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import _thread
+
+def foo(lst, i):
+ lst[i] += 1
+
+def thread_entry(n, lst, idx):
+ for i in range(n):
+ foo(lst, idx)
+ with lock:
+ global n_finished
+ n_finished += 1
+
+lock = _thread.allocate_lock()
+n_thread = 2
+n_finished = 0
+
+# the shared data structure
+lst = [0, 0]
+
+# spawn threads
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, ((i + 1) * 10, lst, i))
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+print(lst)
diff --git a/tests/thread 2/thread_sleep1.py b/tests/thread 2/thread_sleep1.py
new file mode 100644
index 000000000..d5aa99f97
--- /dev/null
+++ b/tests/thread 2/thread_sleep1.py
@@ -0,0 +1,33 @@
+# test threads sleeping
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime
+ sleep_ms = utime.sleep_ms
+except ImportError:
+ import time
+ sleep_ms = lambda t: time.sleep(t / 1000)
+
+import _thread
+
+lock = _thread.allocate_lock()
+n_thread = 4
+n_finished = 0
+
+def thread_entry(t):
+ global n_finished
+ sleep_ms(t)
+ sleep_ms(2 * t)
+ with lock:
+ n_finished += 1
+
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, (10 * i,))
+
+# wait for threads to finish
+while n_finished < n_thread:
+ sleep_ms(100)
+print('done', n_thread)
diff --git a/tests/thread 2/thread_stacksize1.py b/tests/thread 2/thread_stacksize1.py
new file mode 100644
index 000000000..e7189fafb
--- /dev/null
+++ b/tests/thread 2/thread_stacksize1.py
@@ -0,0 +1,49 @@
+# test setting the thread stack size
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+import sys
+import _thread
+
+# different implementations have different minimum sizes
+if sys.implementation.name == 'micropython':
+ sz = 2 * 1024
+else:
+ sz = 32 * 1024
+
+def foo():
+ pass
+
+def thread_entry():
+ foo()
+ with lock:
+ global n_finished
+ n_finished += 1
+
+# reset stack size to default
+_thread.stack_size()
+
+# test set/get of stack size
+print(_thread.stack_size())
+print(_thread.stack_size(sz))
+print(_thread.stack_size() == sz)
+print(_thread.stack_size())
+
+lock = _thread.allocate_lock()
+n_thread = 2
+n_finished = 0
+
+# set stack size and spawn a few threads
+_thread.stack_size(sz)
+for i in range(n_thread):
+ _thread.start_new_thread(thread_entry, ())
+
+# reset stack size to default (for subsequent scripts on baremetal)
+_thread.stack_size()
+
+# busy wait for threads to finish
+while n_finished < n_thread:
+ pass
+print('done')
diff --git a/tests/thread 2/thread_start1.py b/tests/thread 2/thread_start1.py
new file mode 100644
index 000000000..94df6dc62
--- /dev/null
+++ b/tests/thread 2/thread_start1.py
@@ -0,0 +1,25 @@
+# test basic capability to start a new thread
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def foo():
+ pass
+
+def thread_entry(n):
+ for i in range(n):
+ foo()
+
+_thread.start_new_thread(thread_entry, (10,))
+_thread.start_new_thread(thread_entry, (20,))
+
+# wait for threads to finish
+time.sleep(1)
+print('done')
diff --git a/tests/thread 2/thread_start2.py b/tests/thread 2/thread_start2.py
new file mode 100644
index 000000000..9412bb618
--- /dev/null
+++ b/tests/thread 2/thread_start2.py
@@ -0,0 +1,28 @@
+# test capability to start a thread with keyword args
+#
+# SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
+#
+# SPDX-License-Identifier: MIT
+
+try:
+ import utime as time
+except ImportError:
+ import time
+import _thread
+
+def thread_entry(a0, a1, a2, a3):
+ print('thread', a0, a1, a2, a3)
+
+# spawn thread using kw args
+_thread.start_new_thread(thread_entry, (10, 20), {'a2': 0, 'a3': 1})
+
+# wait for thread to finish
+time.sleep(1)
+
+# incorrect argument where dictionary is needed for keyword args
+try:
+ _thread.start_new_thread(thread_entry, (), ())
+except TypeError:
+ print('TypeError')
+
+print('done')
diff --git a/tests/unix 2/extra_coverage.py b/tests/unix 2/extra_coverage.py
new file mode 100644
index 000000000..13721f1f4
--- /dev/null
+++ b/tests/unix 2/extra_coverage.py
@@ -0,0 +1,74 @@
+try:
+ extra_coverage
+except NameError:
+ print("SKIP")
+ raise SystemExit
+
+import uerrno
+import uio
+
+data = extra_coverage()
+
+# test hashing of str/bytes that have an invalid hash
+print(data[0], data[1])
+print(hash(data[0]))
+print(hash(data[1]))
+print(hash(bytes(data[0], 'utf8')))
+print(hash(str(data[1], 'utf8')))
+
+# test streams
+stream = data[2] # has set_error and set_buf. Write always returns error
+stream.set_error(uerrno.EAGAIN) # non-blocking error
+print(stream.read()) # read all encounters non-blocking error
+print(stream.read(1)) # read 1 byte encounters non-blocking error
+print(stream.readline()) # readline encounters non-blocking error
+print(stream.readinto(bytearray(10))) # readinto encounters non-blocking error
+print(stream.write(b'1')) # write encounters non-blocking error
+print(stream.write1(b'1')) # write1 encounters non-blocking error
+stream.set_buf(b'123')
+print(stream.read(4)) # read encounters non-blocking error after successful reads
+stream.set_buf(b'123')
+print(stream.read1(4)) # read1 encounters non-blocking error after successful reads
+stream.set_buf(b'123')
+print(stream.readline(4)) # readline encounters non-blocking error after successful reads
+try:
+ print(stream.ioctl(0, 0)) # ioctl encounters non-blocking error; raises OSError
+except OSError:
+ print('OSError')
+stream.set_error(0)
+print(stream.ioctl(0, bytearray(10))) # successful ioctl call
+
+stream2 = data[3] # is textio
+print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream
+
+# test BufferedWriter with stream errors
+stream.set_error(uerrno.EAGAIN)
+buf = uio.BufferedWriter(stream, 8)
+print(buf.write(bytearray(16)))
+
+# test basic import of frozen scripts
+import frzstr1
+import frzmpy1
+
+# test import of frozen packages with __init__.py
+import frzstr_pkg1
+print(frzstr_pkg1.x)
+import frzmpy_pkg1
+print(frzmpy_pkg1.x)
+
+# test import of frozen packages without __init__.py
+from frzstr_pkg2.mod import Foo
+print(Foo.x)
+from frzmpy_pkg2.mod import Foo
+print(Foo.x)
+
+# test raising exception in frozen script
+try:
+ import frzmpy2
+except ZeroDivisionError:
+ print('ZeroDivisionError')
+
+# test loading a resource from a frozen string
+import uio
+buf = uio.resource_stream('frzstr_pkg2', 'mod.py')
+print(buf.read(21))
diff --git a/tests/unix 2/extra_coverage.py.exp b/tests/unix 2/extra_coverage.py.exp
new file mode 100644
index 000000000..06b5d3790
--- /dev/null
+++ b/tests/unix 2/extra_coverage.py.exp
@@ -0,0 +1,106 @@
+# mp_printf
+-123 +123 123
+-0123
+123
+123
+1ABCDEF
+ab abc
+
+false true
+(null)
+-2147483648
+2147483648
+80000000
+80000000
+abc
+# GC
+0
+0
+# vstr
+tests
+sts
+
+test
+tes
+RuntimeError:
+RuntimeError:
+# repl
+ame__
+
+argv byteorder exc_info exit
+getsizeof implementation maxsize modules
+path platform print_exception
+stderr stdin stdout version
+version_info
+ementation
+# attrtuple
+(start=1, stop=2, step=3)
+# str
+1
+# bytearray
+data
+# mpz
+1
+12345678
+0
+0
+0
+0
+0
+1
+12345
+6
+# runtime utils
+TypeError: unsupported type for __abs__: 'str'
+TypeError: unsupported types for __divmod__: 'str', 'str'
+Warning: test
+# format float
+?
++1e+00
++1e+00
+# binary
+123
+456
+# VM
+2 1
+# scheduler
+sched(0)=1
+sched(1)=1
+sched(2)=1
+sched(3)=1
+sched(4)=0
+unlocked
+3
+2
+1
+0
+0123456789 b'0123456789'
+7300
+7300
+7300
+7300
+None
+None
+None
+None
+None
+None
+b'123'
+b'123'
+b'123'
+OSError
+0
+None
+None
+frzstr1
+frzmpy1
+frzstr_pkg1.__init__
+1
+frzmpy_pkg1.__init__
+1
+frzstr_pkg2.mod
+1
+frzmpy_pkg2.mod
+1
+ZeroDivisionError
+b'# test frozen package'
diff --git a/tests/unix 2/ffi_callback.py b/tests/unix 2/ffi_callback.py
new file mode 100644
index 000000000..23b058bce
--- /dev/null
+++ b/tests/unix 2/ffi_callback.py
@@ -0,0 +1,33 @@
+try:
+ import ffi
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+def ffi_open(names):
+ err = None
+ for n in names:
+ try:
+ mod = ffi.open(n)
+ return mod
+ except OSError as e:
+ err = e
+ raise err
+
+libc = ffi_open(('libc.so', 'libc.so.0', 'libc.so.6', 'libc.dylib'))
+
+qsort = libc.func("v", "qsort", "piip")
+
+def cmp(pa, pb):
+ a = ffi.as_bytearray(pa, 1)
+ b = ffi.as_bytearray(pb, 1)
+ #print("cmp:", a, b)
+ return a[0] - b[0]
+
+cmp_c = ffi.callback("i", cmp, "pp")
+
+s = bytearray(b"foobar")
+print("org string:", s)
+qsort(s, len(s), 1, cmp_c)
+print("qsort'ed:", s)
diff --git a/tests/unix 2/ffi_callback.py.exp b/tests/unix 2/ffi_callback.py.exp
new file mode 100644
index 000000000..d06fec52f
--- /dev/null
+++ b/tests/unix 2/ffi_callback.py.exp
@@ -0,0 +1,2 @@
+org string: bytearray(b'foobar')
+qsort'ed: bytearray(b'abfoor')
diff --git a/tests/unix 2/ffi_float.py b/tests/unix 2/ffi_float.py
new file mode 100644
index 000000000..c92a39bcd
--- /dev/null
+++ b/tests/unix 2/ffi_float.py
@@ -0,0 +1,32 @@
+# test ffi float support
+try:
+ import ffi
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+def ffi_open(names):
+ err = None
+ for n in names:
+ try:
+ mod = ffi.open(n)
+ return mod
+ except OSError as e:
+ err = e
+ raise err
+
+libc = ffi_open(('libc.so', 'libc.so.0', 'libc.so.6', 'libc.dylib'))
+
+strtof = libc.func("f", "strtof", "sp")
+print('%.6f' % strtof('1.23', None))
+
+strtod = libc.func("d", "strtod", "sp")
+print('%.6f' % strtod('1.23', None))
+
+# test passing double and float args
+libm = ffi_open(('libm.so', 'libm.so.6', 'libc.so.0', 'libc.so.6', 'libc.dylib'))
+tgamma = libm.func('d', 'tgamma', 'd')
+for fun in (tgamma,):
+ for val in (0.5, 1, 1.0, 1.5, 4, 4.0):
+ print('%.6f' % fun(val))
diff --git a/tests/unix 2/ffi_float.py.exp b/tests/unix 2/ffi_float.py.exp
new file mode 100644
index 000000000..b9d7da2bd
--- /dev/null
+++ b/tests/unix 2/ffi_float.py.exp
@@ -0,0 +1,8 @@
+1.230000
+1.230000
+1.772454
+1.000000
+1.000000
+0.886227
+6.000000
+6.000000
diff --git a/tests/unix 2/ffi_float2.py b/tests/unix 2/ffi_float2.py
new file mode 100644
index 000000000..721eb4d19
--- /dev/null
+++ b/tests/unix 2/ffi_float2.py
@@ -0,0 +1,31 @@
+# test ffi float support
+try:
+ import ffi
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+
+def ffi_open(names):
+ err = None
+ for n in names:
+ try:
+ mod = ffi.open(n)
+ return mod
+ except OSError as e:
+ err = e
+ raise err
+
+libm = ffi_open(('libm.so', 'libm.so.6', 'libc.so.0', 'libc.so.6', 'libc.dylib'))
+
+# Some libc's implement tgammaf as header macro with tgamma(), so don't assume
+# it'll be in library.
+try:
+ tgammaf = libm.func('f', 'tgammaf', 'f')
+except OSError:
+ print("SKIP")
+ raise SystemExit
+
+for fun in (tgammaf,):
+ for val in (0.5, 1, 1.0, 1.5, 4, 4.0):
+ print('%.6f' % fun(val))
diff --git a/tests/unix 2/ffi_float2.py.exp b/tests/unix 2/ffi_float2.py.exp
new file mode 100644
index 000000000..58fc6a01a
--- /dev/null
+++ b/tests/unix 2/ffi_float2.py.exp
@@ -0,0 +1,6 @@
+1.772454
+1.000000
+1.000000
+0.886227
+6.000000
+6.000000
diff --git a/tools/.gitattributes 2 b/tools/.gitattributes 2
new file mode 100644
index 000000000..9206a0bfc
--- /dev/null
+++ b/tools/.gitattributes 2
@@ -0,0 +1 @@
+*.tar.gz binary
diff --git a/tools/.gitignore 2 b/tools/.gitignore 2
new file mode 100644
index 000000000..9f65f493b
--- /dev/null
+++ b/tools/.gitignore 2
@@ -0,0 +1,8 @@
+tinytest/.gitignore
+tinytest/.travis.yml
+tinytest/Makefile
+tinytest/Makefile.arm-cortex-m3-qemu
+tinytest/Makefile.avr
+tinytest/TODO
+tinytest/portable_demo.c
+tinytest/tinytest_demo.c