summaryrefslogtreecommitdiff
path: root/tests/micropython/import_mpy_native.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/micropython/import_mpy_native.py')
-rw-r--r--tests/micropython/import_mpy_native.py129
1 files changed, 129 insertions, 0 deletions
diff --git a/tests/micropython/import_mpy_native.py b/tests/micropython/import_mpy_native.py
new file mode 100644
index 000000000..d7da16581
--- /dev/null
+++ b/tests/micropython/import_mpy_native.py
@@ -0,0 +1,129 @@
+# test importing of .mpy files with native code
+
+try:
+ import usys, uio, uos
+
+ usys.implementation._mpy
+ uio.IOBase
+ uos.mount
+except (ImportError, AttributeError):
+ print("SKIP")
+ raise SystemExit
+
+mpy_arch = usys.implementation._mpy >> 8
+if mpy_arch == 0:
+ print("SKIP")
+ raise SystemExit
+
+
+class UserFile(uio.IOBase):
+ def __init__(self, data):
+ self.data = memoryview(data)
+ self.pos = 0
+
+ def readinto(self, buf):
+ n = min(len(buf), len(self.data) - self.pos)
+ buf[:n] = self.data[self.pos : self.pos + n]
+ self.pos += n
+ return n
+
+ def ioctl(self, req, arg):
+ return 0
+
+
+class UserFS:
+ def __init__(self, files):
+ self.files = files
+
+ def mount(self, readonly, mksfs):
+ pass
+
+ def umount(self):
+ pass
+
+ def stat(self, path):
+ if path in self.files:
+ return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ raise OSError
+
+ def open(self, path, mode):
+ return UserFile(self.files[path])
+
+
+# these are the test .mpy files
+valid_header = bytes([77, 6, mpy_arch, 31])
+# fmt: off
+user_files = {
+ # bad architecture
+ '/mod0.mpy': b'M\x06\xfc\x1f',
+
+ # test loading of viper and asm
+ '/mod1.mpy': valid_header + (
+ b'\x02' # n_qstr
+ b'\x00' # n_obj
+
+ b'\x0emod1.py\x00' # qstr0 = "mod1.py"
+ b'\x0aouter\x00' # qstr1 = "outer"
+
+ b'\x2c' # 5 bytes, have children, bytecode
+ b'\x00\x02' # prelude
+ b'\x01' # simple name (qstr index)
+ b'\x51' # LOAD_CONST_NONE
+ b'\x63' # RETURN_VALUE
+
+ b'\x02' # 2 children
+
+ b'\x42' # 8 bytes, no children, viper code
+ b'\x00\x00\x00\x00\x00\x00' # dummy machine code
+ b'\x00\x00' # slot for qstr0
+ b'\x01\x0c\x0aprint\x00' # n_qstr=1, qstr0
+ b'\x00' # scope_flags
+
+ b'\x43' # 8 bytes, no children, asm code
+ b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
+ b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
+ ),
+
+ # test loading viper with additional scope flags and relocation
+ '/mod2.mpy': valid_header + (
+ b'\x02' # n_qstr
+ b'\x00' # n_obj
+
+ b'\x0emod2.py\x00' # qstr0 = "mod2.py"
+ b'\x0aouter\x00' # qstr1 = "outer"
+
+ b'\x2c' # 5 bytes, have children, bytecode
+ b'\x00\x02' # prelude
+ b'\x01' # simple name (qstr index)
+ b'\x51' # LOAD_CONST_NONE
+ b'\x63' # RETURN_VALUE
+
+ b'\x01' # 1 child
+
+ b'\x22' # 4 bytes, no children, viper code
+ b'\x00\x00\x00\x00' # dummy machine code
+ b'\x00' # n_qstr=0
+ b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC
+ b'\x06\x04' # rodata=6 bytes, bss=4 bytes
+ b'rodata' # rodata content
+ b'\x03\x01\x00' # dummy relocation of rodata
+ ),
+}
+# fmt: on
+
+# create and mount a user filesystem
+uos.mount(UserFS(user_files), "/userfs")
+usys.path.append("/userfs")
+
+# import .mpy files from the user filesystem
+for i in range(len(user_files)):
+ mod = "mod%u" % i
+ try:
+ __import__(mod)
+ print(mod, "OK")
+ except ValueError as er:
+ print(mod, "ValueError", er)
+
+# unmount and undo path addition
+uos.umount("/userfs")
+usys.path.pop()