#! /usr/bin/env python3 import pytest import glob import os import sys from test_expect_pragma import ( TestExpectPragmas, cat, TestCompiler ) HERE = os.path.dirname(os.path.realpath(__file__)) if HERE == os.path.realpath('.'): HERE = '.' TEST_DIR = HERE IMPLEM_DIR = HERE SKIP_EXPECT = False if 'SKIP_EXPECT' in os.environ: SKIP_EXPECT = True DISABLE_TYPECHECK = False # True to skip typechecking ALL_FILES = [] # tests for typing AND evaluation ALL_FILES += glob.glob(os.path.join(TEST_DIR, 'TP03/tests/provided/**/*.c'), recursive=True) ALL_FILES += glob.glob(os.path.join(TEST_DIR, 'TP03/tests/students/**/*.c'), recursive=True) # Path setting if 'TEST_FILES' in os.environ: ALL_FILES = glob.glob(os.environ['TEST_FILES'], recursive=True) MINIC_EVAL = os.path.join(IMPLEM_DIR, 'MiniCC.py') if 'FILTER' in os.environ: FILTER_FILES = glob.glob(os.path.join(HERE, os.environ['FILTER']), recursive=True) ALL_FILES = list(set(FILTER_FILES) & set(ALL_FILES)) class TestInterpret(TestExpectPragmas, TestCompiler): DISABLE_CODEGEN = False def evaluate(self, file): if not DISABLE_TYPECHECK: res = self.run_command([sys.executable, MINIC_EVAL, "--mode", "eval", file]) else: res = self.run_command([sys.executable, MINIC_EVAL, "--mode", "eval", "--disable-typecheck", file]) if res.exitcode == 1: # Execution can't distinguish exit code at runtime and static # rejection of the program. But we know that an exit code of 1 is # reserved for runtime errors, hence convert this exitcode # into an execcode. res = res._replace(exitcode=0, execcode=1) return res # Not in test_expect_pragma to get assertion rewritting def assert_equal(self, actual, expected, compiler): if expected.output is not None and actual.output is not None: assert actual.output == expected.output, \ f"Output of the program is incorrect (using {compiler})." assert actual.exitcode == expected.exitcode, \ f"Exit code of the compiler ({compiler}) is incorrect" assert actual.execcode == expected.execcode, \ f"Exit code of the execution is incorrect (using {compiler})" @pytest.mark.parametrize('filename', ALL_FILES) def test_expect(self, filename): """Test the EXPECTED annotations in test files by launching the program with GCC.""" if SKIP_EXPECT: pytest.skip("Skipping all test_expect " "because $SKIP_EXPECT is set.") cat(filename) # For diagnosis expect = self.get_expect(filename) if expect.skip_test_expected: pytest.skip("Skipping test_expect with GCC because " "the test contains SKIP TEST EXPECTED") if expect.exitcode != 0: # GCC is more permissive than us, so trying to compile an # incorrect program would bring us no information (it may # compile, or fail with a different message...) pytest.skip("Not testing the expected value for " "tests expecting exitcode!=0") gcc_result = self.run_with_gcc(filename, expect) self.assert_equal(gcc_result, expect, "gcc") @pytest.mark.parametrize('filename', ALL_FILES) def test_eval(self, filename): cat(filename) # For diagnosis expect = self.get_expect(filename) actual = self.evaluate(filename) if expect: self.assert_equal(actual, expect, "MiniCC") if __name__ == '__main__': pytest.main(sys.argv)