# This is a python unittest class automatically populating with all tests # in the snippets folder. import sys import os import unittest import glob import logging import subprocess import contextlib import enum from pathlib import Path class _TestType(enum.Enum): functional = 1 logger = logging.getLogger("tests") ROOT_DIR = ".." TEST_ROOT = os.path.abspath(os.path.join(ROOT_DIR, "extra_tests")) TEST_DIRS = {_TestType.functional: os.path.join(TEST_ROOT, "snippets")} @contextlib.contextmanager def pushd(path): old_dir = os.getcwd() os.chdir(path) yield os.chdir(old_dir) def perform_test(filename, method, test_type): logger.info("Running %s via %s", filename, method) if method == "cpython": run_via_cpython(filename) elif method == "rustpython": run_via_rustpython(filename, test_type) else: raise NotImplementedError(method) def run_via_cpython(filename): """ Simply invoke python itself on the script """ env = os.environ.copy() subprocess.check_call([sys.executable, filename], env=env) RUSTPYTHON_BINARY = os.environ.get("RUSTPYTHON") or os.path.join(ROOT_DIR, "target/release/rustpython") RUSTPYTHON_BINARY = os.path.abspath(RUSTPYTHON_BINARY) def run_via_rustpython(filename, test_type): env = os.environ.copy() env['RUST_LOG'] = 'info,cargo=error,jobserver=error' env['RUST_BACKTRACE'] = '1' subprocess.check_call([RUSTPYTHON_BINARY, filename], env=env) def create_test_function(cls, filename, method, test_type): """ Create a test function for a single snippet """ core_test_directory, snippet_filename = os.path.split(filename) test_function_name = "test_{}_".format(method) + os.path.splitext(snippet_filename)[ 0 ].replace(".", "_").replace("-", "_") def test_function(self): perform_test(filename, method, test_type) if hasattr(cls, test_function_name): raise ValueError("Duplicate test case {}".format(test_function_name)) setattr(cls, test_function_name, test_function) def populate(method): def wrapper(cls): """ Decorator function which can populate a unittest.TestCase class """ for test_type, filename in get_test_files(): create_test_function(cls, filename, method, test_type) return cls return wrapper def get_test_files(): """ Retrieve test files """ for test_type, test_dir in TEST_DIRS.items(): for filepath in sorted(glob.iglob(os.path.join(test_dir, "*.py"))): filename = os.path.split(filepath)[1] if filename.startswith("xfail_"): continue yield test_type, os.path.abspath(filepath) def generate_slices(path): # loop used to build slices_res.py with cpython ll = [0, 1, 2, 3] start = list(range(-7, 7)) end = list(range(-7, 7)) step = list(range(-5, 5)) step.pop(step.index(0)) for i in [start, end, step]: i.append(None) slices_res = [] for s in start: for e in end: for t in step: slices_res.append(ll[s:e:t]) path.write_text( "SLICES_RES={}\nSTART= {}\nEND= {}\nSTEP= {}\nLL={}\n".format( slices_res, start, end, step, ll ) ) @populate("cpython") @populate("rustpython") class SampleTestCase(unittest.TestCase): @classmethod def setUpClass(cls): # Here add resource files cls.slices_resource_path = Path(TEST_DIRS[_TestType.functional]) / "cpython_generated_slices.py" if cls.slices_resource_path.exists(): cls.slices_resource_path.unlink() generate_slices(cls.slices_resource_path) @classmethod def tearDownClass(cls): cls.slices_resource_path.unlink()