Turn on Rosie CI testing to test new builds on real hardware.

This introduces a skip_if module that can be used by tests to
determine when they should be skipped due to the environment.

Some tests have been split in order to have finer grained skip
control.
This commit is contained in:
Scott Shawcroft 2017-07-03 15:05:08 -07:00 committed by Scott Shawcroft
parent f6a702538a
commit fab634e3ee
31 changed files with 306 additions and 84 deletions

13
.rosie.yml Normal file
View File

@ -0,0 +1,13 @@
# This configuration file tells Rosie where to find prebuilt .bin files (Travis
# builds them) and where to find the tests.
binaries:
prebuilt_s3: adafruit-circuit-python
file_pattern: bin/{board}/adafruit-circuitpython-{board}-*-{short_sha}.{extension}
circuitpython_tests:
test_directories:
- tests/basics
- tests/circuitpython
test_helper:
- tests/skip_if.py

View File

@ -20,6 +20,14 @@ notifications:
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: never # options: [always|never|change] default: always
webhooks:
urls:
- https://rosie-ci.ngrok.io/travis
on_success: always
on_failure: always
on_start: always
on_cancel: always
on_error: always
before_script:
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa

View File

@ -33,7 +33,6 @@
#define MICROPY_ENABLE_DOC_STRING (0)
//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_PY_ASYNC_AWAIT (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
@ -61,7 +60,6 @@
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
#define MICROPY_PY_STRUCT (1)
#define MICROPY_PY_SYS (1)
#define MICROPY_CPYTHON_COMPAT (0)
// If you change MICROPY_LONGINT_IMPL, also change MPY_TOOL_LONGINT_IMPL in mpconfigport.mk.
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
@ -166,6 +164,13 @@ extern const struct _mp_obj_module_t usb_hid_module;
#define MICROPY_PY_URE (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_FRAMEBUF (1)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_CPYTHON_COMPAT (1)
#define EXTRA_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_audiobusio), (mp_obj_t)&audiobusio_module }, \
@ -177,6 +182,9 @@ extern const struct _mp_obj_module_t usb_hid_module;
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#define MICROPY_PY_FRAMEBUF (0)
#define EXTRA_BUILTIN_MODULES
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_CPYTHON_COMPAT (0)
#endif
#define MICROPY_PORT_BUILTIN_MODULES \

View File

@ -13,6 +13,10 @@ Adafruit CircuitPython API Reference
:target: https://gitter.im/adafruit/circuitpython?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
:alt: Gitter
.. image :: https://img.shields.io/discord/327254708534116352.svg
:target: https://adafru.it/discord
:alt: Discord
Welcome! This is the documentation for Adafruit CircuitPython. It is an open
source derivative of `MicroPython <https://micropython.org>`_ for use on
educational development boards designed and sold by `Adafruit

View File

@ -136,10 +136,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
if (mp_obj_is_exception_instance(return_value)) {
size_t n, *values;
mp_obj_exception_get_traceback(return_value, &n, &values);
if (values != NULL) {
result->exception_line = values[n - 2];
}
}
}
}
// display debugging info if wanted
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {

View File

@ -115,6 +115,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
vstr_reset(dest);
size_t p_len;
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
DEBUG_printf("Looking in path: %d =%s=\n", i, p);
if (p_len > 0) {
vstr_add_strn(dest, p, p_len);
vstr_add_char(dest, PATH_SEP_CHAR);
@ -386,6 +387,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
mp_import_stat_t stat;
if (vstr_len(&path) == 0) {
// first module in the dotted-name; search for a directory or file
DEBUG_printf("Find file =%.*s=\n", vstr_len(&path), vstr_str(&path));
stat = find_file(mod_str, i, &path);
} else {
// latter module in the dotted-name; append to path

View File

@ -72,7 +72,6 @@ STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t str_len) {
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, file_len, 0);
return lex;
}
#endif
#if MICROPY_MODULE_FROZEN_MPY

View File

@ -107,6 +107,7 @@ $(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/wind
$(Q)$(MAKE) -C $(TOP)/mpy-cross
# make a list of all the .py files that need compiling and freezing
BLAH := $(info $(shell pwd))
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==')
FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy))

View File

@ -40,7 +40,7 @@
// to another, you must rebuild from scratch using "-B" switch to make.
#ifdef MP_CONFIGFILE
#include MP_CONFIGFILE
#include "mpconfigport_coverage.h"
#else
#include <mpconfigport.h>
#endif

View File

@ -1,4 +1,6 @@
# test array types QqLl that require big-ints
import skip_if
skip_if.no_bigint()
try:
from array import array

View File

@ -1,9 +1,5 @@
# test the builtin reverse() function
try:
reversed
except:
print("SKIP")
raise SystemExit
import skip_if
skip_if.no_reversed()
# list
print(list(reversed([])))

View File

@ -1 +1,12 @@
# Skip if long ints are not supported.
try:
# We have to use variables because 1 << 40 causes an exception on parse and
# cannot be caught.
x = 40
x = 1 << x
except OverflowError:
print("SKIP")
import sys
sys.exit(1)
print(bytearray(2**65 - (2**65 - 1)))

View File

@ -11,6 +11,9 @@ except ImportError:
print("SKIP")
raise SystemExit
import skip_if
skip_if.no_cpython_compat()
_DefragResultBase = namedtuple('DefragResult', [ 'foo', 'bar' ])
class _ResultMixinStr(object):

View File

@ -1,8 +1,5 @@
try:
reversed
except:
print("SKIP")
raise SystemExit
import skip_if
skip_if.no_reversed()
# argument to fromkeys has no __len__
d = dict.fromkeys(reversed(range(1)))

View File

@ -0,0 +1,7 @@
# Skip this test if reversed() isn't built in.
import skip_if
skip_if.no_reversed()
# argument to fromkeys has no __len__
d = dict.fromkeys(reversed(range(1)))
print(d)

View File

@ -1,5 +1,16 @@
# test [0,-0,1,-1] edge cases of bignum
# Skip if long ints are not supported.
try:
# We have to use variables because 1 << 40 causes an exception on parse and
# cannot be caught.
x = 40
x = 1 << x
except OverflowError:
print("SKIP")
import sys
sys.exit(1)
long_zero = (2**64) >> 65
long_neg_zero = -long_zero
long_one = long_zero + 1

View File

@ -1,9 +1,6 @@
print((10).to_bytes(1, "little"))
print((111111).to_bytes(4, "little"))
print((100).to_bytes(10, "little"))
print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little"))
print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little"))
print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little"))
# check that extra zero bytes don't change the internal int value
print(int.from_bytes(bytes(20), "little") == 0)

View File

@ -1,3 +1,6 @@
import skip_if
skip_if.no_bigint()
print((2**64).to_bytes(9, "little"))
b = bytes(range(20))

View File

@ -0,0 +1,15 @@
# Skip if long ints are not supported.
try:
# We have to use variables because 1 << 40 causes an exception on parse and
# cannot be caught.
x = 40
x = 1 << x
except OverflowError:
print("SKIP")
import sys
sys.exit(1)
print((2**64).to_bytes(9, "little"))
print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little"))
print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little"))
print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little"))

View File

@ -46,51 +46,3 @@ print(list(m))
print(list(m[1:-1]))
m[2] = 6
print(a)
# test slice assignment between memoryviews
b1 = bytearray(b'1234')
b2 = bytearray(b'5678')
b3 = bytearray(b'5678')
m1 = memoryview(b1)
m2 = memoryview(b2)
m3 = memoryview(b3)
m2[1:3] = m1[0:2]
print(b2)
b3[1:3] = m1[0:2]
print(b3)
m1[2:4] = b3[1:3]
print(b1)
try:
m2[1:3] = b1[0:4]
except ValueError:
print("ValueError")
try:
m2[1:3] = m1[0:4]
except ValueError:
print("ValueError")
try:
m2[0:4] = m1[1:3]
except ValueError:
print("ValueError")
# test memoryview of arrays with items sized larger than 1
a1 = array.array('i', [0]*5)
m4 = memoryview(a1)
a2 = array.array('i', [3]*5)
m5 = memoryview(a2)
m4[1:3] = m5[1:3]
print(a1)
try:
m4[1:3] = m2[1:3]
except ValueError:
print("ValueError")
# invalid assignment on RHS
try:
memoryview(array.array('i'))[0:2] = b'1234'
except ValueError:
print('ValueError')

View File

@ -0,0 +1,58 @@
import skip_if
try:
memoryview
except:
skip_if.skip()
skip_if.no_slice_assign()
# test slice assignment between memoryviews
b1 = bytearray(b'1234')
b2 = bytearray(b'5678')
b3 = bytearray(b'5678')
m1 = memoryview(b1)
m2 = memoryview(b2)
m3 = memoryview(b3)
m2[1:3] = m1[0:2]
print(b2)
b3[1:3] = m1[0:2]
print(b3)
m1[2:4] = b3[1:3]
print(b1)
try:
m2[1:3] = b1[0:4]
except ValueError:
print("ValueError")
try:
m2[1:3] = m1[0:4]
except ValueError:
print("ValueError")
try:
m2[0:4] = m1[1:3]
except ValueError:
print("ValueError")
import array
# test memoryview of arrays with items sized larger than 1
a1 = array.array('i', [0]*5)
m4 = memoryview(a1)
a2 = array.array('i', [3]*5)
m5 = memoryview(a2)
m4[1:3] = m5[1:3]
print(a1)
try:
m4[1:3] = m2[1:3]
except ValueError:
print("ValueError")
# invalid assignment on RHS
try:
memoryview(array.array('i'))[0:2] = b'1234'
except ValueError:
print('ValueError')

View File

@ -65,11 +65,6 @@ try:
except TypeError:
print("TypeError")
# Try single string
T3 = namedtuple("TupComma", "foo bar")
t = T3(1, 2)
print(t.foo, t.bar)
# Try tuple
T4 = namedtuple("TupTuple", ("foo", "bar"))
t = T4(1, 2)

View File

@ -0,0 +1,20 @@
import skip_if
skip_if.no_cpython_compat()
try:
try:
from collections import namedtuple
except ImportError:
from ucollections import namedtuple
except ImportError:
skip_if.skip()
# Try single string
T3 = namedtuple("TupComma", "foo bar")
t = T3(1, 2)
print(t.foo, t.bar)
# Try single string with comma field separator
# Not implemented so far
#T2 = namedtuple("TupComma", "foo,bar")
#t = T2(1, 2)

View File

@ -1,5 +1,6 @@
# test builtin print function
print("break the test")
print()
print(None)
print('')

View File

@ -1,4 +1,6 @@
# make sure type of first arg (self) to a builtin method is checked
import skip_if
skip_if.board_in("gemma_m0", "trinket_m0")
list.append

View File

@ -0,0 +1,2 @@
import digitalio
import board

View File

@ -123,9 +123,13 @@ def run_micropython(pyb, args, test_file, is_special=False):
cmdlist.append(test_file)
# run the actual test
try:
output_mupy = subprocess.check_output(cmdlist)
except subprocess.CalledProcessError:
e = {"MICROPYPATH": os.getcwd() + ":", "LANG": "en_US.UTF-8"}
p = subprocess.Popen(cmdlist, env=e, stdout=subprocess.PIPE)
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
@ -368,13 +372,19 @@ def run_tests(pyb, tests, args, base_path="."):
output_expected = f.read()
else:
# run CPython to work out expected output
try:
output_expected = subprocess.check_output([CPYTHON3, '-B', test_file])
if args.write_exp:
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)
except subprocess.CalledProcessError:
output_expected = b'CPYTHON3 CRASH'
# canonical form for all host platforms is to use \n for end-of-line
output_expected = output_expected.replace(b'\r\n', b'\n')
@ -405,6 +415,10 @@ def run_tests(pyb, tests, args, base_path="."):
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)

80
tests/skip_if.py Normal file
View File

@ -0,0 +1,80 @@
# 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 must be on one line so its skipped when built into tests.
"""This file provides helpers to detect particular running conditions and skip the test when appropriate."""
def skip():
print("SKIP")
raise SystemExit
def no_reversed():
import builtins
if "reversed" not in dir(builtins):
skip()
def no_bigint():
try:
# We have to use variables because 1 << 40 causes an exception on parse and
# cannot be caught.
x = 40
x = 1 << x
except OverflowError:
skip()
def board_in(*board):
try:
import test_env
except ImportError:
class Env:
def __init__(self, board):
self.board = board
test_env = Env("unknown")
if test_env.board in board:
skip()
def no_cpython_compat():
try:
try:
from collections import namedtuple
except ImportError:
from ucollections import namedtuple
except ImportError:
skip()
try:
T3 = namedtuple("TupComma", "foo bar")
except TypeError:
skip()
def no_slice_assign():
try:
memoryview
except:
skip()
b1 = bytearray(b'1234')
b2 = bytearray(b'5678')
m1 = memoryview(b1)
m2 = memoryview(b2)
try:
m2[1:3] = m1[0:2]
except TypeError:
skip()

View File

@ -20,7 +20,23 @@ def chew_filename(t):
def script_to_map(t):
r = { 'name': chew_filename(t)['func'] }
with open(t) as f: r['script'] = escape(''.join(f.readlines()))
with open(t) as test:
script = test.readlines()
# Test for import skip_if and inject it into the test as needed.
if "import skip_if\n" in script:
index = script.index("import skip_if\n")
script.pop(index)
script.insert(index, "class skip_if:\n")
with open("../tests/skip_if.py") as skip_if:
total_lines = 1
for line in skip_if:
stripped = line.strip()
if not stripped or stripped.startswith(("#", "\"\"\"")):
continue
script.insert(index + total_lines, "\t" + line)
total_lines += 1
r['script'] = escape(''.join(script))
return r
test_function = (

View File

@ -242,8 +242,8 @@ freedos:
# build an interpreter for coverage testing and do the testing
coverage:
$(MAKE) \
COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_coverage.h>" \
$(MAKE) V=2 \
COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="\"mpconfigport_coverage.h\"" \
-fprofile-arcs -ftest-coverage \
-Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \
-Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \

View File

@ -492,6 +492,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
}
}
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
#if defined(MICROPY_UNIX_COVERAGE)