MicroPythonのテストに関するメモ

前回着手したMicroPythonのテストですが、とりあえずbasicsテストがパスするようになりました。(未実装によりskipしているものもありますが)

421 tests performed (12506 individual testcases)
421 tests passed
34 tests skipped: builtin_compile builtin_override builtin_pow3 builtin_pow3_intbig builtin_range_binop builtin_round_int builtin_round_intbig bytes_partition class_delattr_setattr class_descriptor class_inplace_op class_notimpl class_reverse_op deque1 deque2 dict_fixed errno1 exception_chain fun_name generator_name io_buffered_writer namedtuple_asdict ordereddict1 ordereddict_eq parser slice_attrs special_methods2 string_center string_partition string_rpartition string_splitlines subclass_native_call subclass_native_init sys_getsizeof

この過程で気付いたことをメモとして残しておきます。

(1)Python3.6が必要

MicroPythonのテストでは、一部のテストケースにおいて正解を生成するためにPython3.6が必要になりますが、私が使っているUbuntu 16.04ではPython3.6は標準ではサポートされていません。
以下のリンクに、新たなリポジトリを指定してPython3.6を導入する方法が書かれています。

16.04 – How do I install Python 3.6 using apt-get? – Ask Ubuntu

software installation – How to install pip for Python 3.6 on Ubuntu 16.10? – Ask Ubuntu

シリアルポート制御用のpyserialモジュールも必要になります。

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6
sudo apt-get install python3.6-venv
curl https://bootstrap.pypa.io/get-pip.py | sudo python3.6
sudo python3.6 -m pip install pyserial
export MICROPY_CPYTHON3=python3.6

標準のpython3が置き換わるわけではなく、/usr/bin/python3.6が使えるようになります。
そのため、run-testsスクリプトも先頭行を「#! /usr/bin/env python3.6 」と書き換える必要があります。

これで、これまで失敗していた「io_bytesio_ext2.py」「io_write_ext.py」「python36.py」のテストが成功するようになりました。
もともとMicroPythonの出力結果は正しかったのですが、正解を表すexpファイルのほうが正しく生成できていませんでした。

(2)タイムアウトは10秒

テストスクリプトをボード上で走らせて結果を得る場合、タイムアウトはデフォルトで10秒になっています。
これはtests/pyboard.pyの中で以下のように定義されています。

    def exec_raw(self, command, timeout=10, data_consumer=None):
        self.exec_raw_no_follow(command);
        return self.follow(timeout, data_consumer)

ですが、Raspberry Pi版のMicroPythonではヒープが普通のマイコンの1000倍くらいありますので、一部のテスト(「gc1.py」と「memoryerror.py」)では処理に10秒以上かかってしまいます。
すると、run-testsスクリプトは「MicroPythonがクラッシュした」と判定してしまいますが、実際にはクラッシュしておらず時間がかかっているだけです。

そこで、上記のtimeout=10をtimeout=100に変更することでテストをパスできるようになりました。
(なおmicropython/extreme_exc.pyのテストはさらに重く、timeout=300くらいにする必要があります。つまり5分近くかかるということです。)

(3)IOBaseのテストに標準入出力が必要

一番最後にパスしたテストが、「io_iobase」というテストです。スクリプトは以下のようになっています。

try:
    import uio as io
except:
    import io

try:
    io.IOBase
except AttributeError:
    print('SKIP')
    raise SystemExit


class MyIO(io.IOBase):
    def write(self, buf):
        # CPython and uPy pass in different types for buf (str vs bytearray)
        print('write', len(buf))
        return len(buf)

print('test', file=MyIO())

最後のprint文で、fileというキーワードは知らない、ということでエラーになっていました。

このfileキーワードですが、printの出力を標準出力以外へ出したいときに使います。
この実装はpy/modbuiltins.cの中で

#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES

という条件が成立する場合のみ有効になっています。

そのため、IOBaseをテストするためにはMICROPY_PY_SYS_STDFILESも有効にする必要があります。
具体的にはmpconfigport.hの中でMICROPY_PY_SYS_STDFILESを1に設定し、かつこの機能をサポートするためにutils/sys_stdio_mphal.cを(Makefileに)追加します。

コメント