Example #1
0
    def test_env_cxx_gcc(self, case):
        lang = "cpp"
        ext = ".cpp"
        expected_filename = TESTS_DIR / "expected" / f"{case}{ext}"
        if not os.path.exists(expected_filename):
            raise unittest.SkipTest(f"{expected_filename} not found")

        env = os.environ.copy()
        env["CXX"] = "g++-11" if sys.platform == "darwin" else "g++"
        env["CXXFLAGS"] = "-std=c++14 -Wall -Werror"

        if not spawn.find_executable(env["CXX"]):
            raise unittest.SkipTest(f"{env['CXX']} not available")

        settings = _get_all_settings(Mock(indent=4), env=env)[lang]
        assert settings.linter[0].startswith("g++")

        if not spawn.find_executable("astyle"):
            raise unittest.SkipTest("astyle not available")

        settings.formatter = ["astyle"]

        exe = BUILD_DIR / a_dot_out
        exe.unlink(missing_ok=True)

        case_filename = TESTS_DIR / "cases" / f"{case}.py"
        case_output = GENERATED_DIR / f"{case}{ext}"

        args = [
            f"--{lang}=1",
            "--comment-unsupported",
            str(case_filename),
            "--outdir",
            str(GENERATED_DIR),
        ]

        linter = _create_cmd(settings.linter, case_output)

        try:
            rv = main(args=args, env=env)
            assert rv == 0

            linter.append("-Wno-unused-variable")
            if case == "coverage":
                linter.append("-Wno-pointer-arith")
            proc = run(linter, env=env)
            assert not proc.returncode
        except FileNotFoundError as e:
            raise unittest.SkipTest(
                f"Failed invoking {env['CXX']} or {linter}: {e}")
        finally:
            if not KEEP_GENERATED:
                case_output.unlink(missing_ok=True)
            exe.unlink(missing_ok=True)
Example #2
0
class CodeGeneratorTests(unittest.TestCase):
    maxDiff = None

    SHOW_ERRORS = SHOW_ERRORS
    KEEP_GENERATED = KEEP_GENERATED
    UPDATE_EXPECTED = UPDATE_EXPECTED
    LINT = os.environ.get("LINT", True)

    def setUp(self):
        os.makedirs(BUILD_DIR, exist_ok=True)
        os.chdir(BUILD_DIR)
        py2many.cli.CWD = BUILD_DIR

    @foreach(sorted(LANGS))
    @foreach(sorted(TEST_CASES))
    def test_generated(self, case, lang):
        env = os.environ.copy()
        if ENV.get(lang):
            env.update(ENV.get(lang))

        settings = _get_all_settings(Mock(indent=4), env=env)[lang]
        ext = settings.ext
        expected_filename = TESTS_DIR / "expected" / f"{case}{ext}"

        if (not self.UPDATE_EXPECTED and not self.KEEP_GENERATED
                and not os.path.exists(expected_filename)):
            raise unittest.SkipTest(f"{expected_filename} not found")

        if settings.formatter:
            if not spawn.find_executable(settings.formatter[0]):
                raise unittest.SkipTest(
                    f"{settings.formatter[0]} not available")

        case_filename = TESTS_DIR / "cases" / f"{case}.py"
        case_output = GENERATED_DIR / f"{case}{ext}"

        exe = get_exe_filename(case, ext)
        exe.unlink(missing_ok=True)

        is_script = has_main(case_filename)
        self.assertTrue(is_script)

        main_args = CASE_ARGS.get(case, tuple())
        expected_exit_code = CASE_EXPECTED_EXITCODE.get(case, 0)
        expected_output = get_python_case_output(case_filename, main_args,
                                                 expected_exit_code)
        self.assertTrue(expected_output, "Test cases must print something")
        expected_output = expected_output.splitlines()

        args = [
            f"--{lang}=1",
            "--comment-unsupported",
            str(case_filename),
            "--outdir",
            str(GENERATED_DIR),
        ]

        try:
            rv = main(args=args, env=env)
            with open(case_output) as actual:
                generated = actual.read()
                if os.path.exists(
                        expected_filename) and not self.UPDATE_EXPECTED:
                    with open(expected_filename) as f2:
                        expected_case_contents = f2.read()
                        generated_cleaned = generated
                        if ext == ".py":
                            expected_case_contents = standardise_python(
                                expected_case_contents)
                            generated_cleaned = standardise_python(generated)
                        self.assertEqual(expected_case_contents,
                                         generated_cleaned)
                        print("expected = generated")

            expect_failure = (not self.SHOW_ERRORS
                              and f"{case}{ext}" in EXPECTED_LINT_FAILURES)

            if not expect_failure:
                assert rv == 0, "formatting failed"
            elif rv:
                raise unittest.SkipTest("formatting failed")

            compiler = COMPILERS.get(lang)
            if compiler:
                if not spawn.find_executable(compiler[0]):
                    raise unittest.SkipTest(f"{compiler[0]} not available")
                expect_compile_failure = (not self.SHOW_ERRORS
                                          and f"{case}{ext}"
                                          in EXPECTED_COMPILE_FAILURES)
                if expect_compile_failure:
                    return
                cmd = _create_cmd(compiler, filename=case_output, exe=exe)
                print(f"Running {cmd} ...")
                proc = run(cmd, env=env, check=not expect_failure)

                if proc.returncode:
                    raise unittest.SkipTest(f"{case}{ext} doesnt compile")

                if self.UPDATE_EXPECTED or not os.path.exists(
                        expected_filename):
                    with open(expected_filename, "w") as f:
                        f.write(generated)

            stdout = None
            if ext == ".cpp" and (BUILD_DIR / a_dot_out).exists():
                os.rename(BUILD_DIR / a_dot_out, exe)

            if INVOKER.get(lang):
                invoker = INVOKER.get(lang)
                if not spawn.find_executable(invoker[0]):
                    raise unittest.SkipTest(f"{invoker[0]} not available")
                cmd = _create_cmd(invoker, filename=case_output, exe=exe)
                cmd += main_args
                proc = run(
                    cmd,
                    env=env,
                    capture_output=True,
                )

                stdout = proc.stdout

                if expect_failure and expected_exit_code != proc.returncode:
                    raise unittest.SkipTest(f"Execution of {case}{ext} failed")
                assert (
                    expected_exit_code == proc.returncode
                ), f"Execution of {case}{ext} failed:\n{stdout}{proc.stderr}"

                if self.UPDATE_EXPECTED or not os.path.exists(
                        expected_filename):
                    with open(expected_filename, "w") as f:
                        f.write(generated)
            elif exe.exists() and os.access(exe, os.X_OK):
                cmd = [exe, *main_args]
                print(f"Running {cmd} ...")
                proc = run(cmd, env=env, capture_output=True)
                assert expected_exit_code == proc.returncode

                stdout = proc.stdout
            else:
                raise RuntimeError(f"Compiled output {exe} not detected")

            self.assertTrue(stdout, "Invoked code produced no stdout")
            stdout = stdout.splitlines()
            self.assertEqual(expected_output, stdout)

            if settings.linter and self.LINT:
                if not spawn.find_executable(settings.linter[0]):
                    raise unittest.SkipTest(
                        f"{settings.linter[0]} not available")
                if settings.ext == ".kt" and case_output.is_absolute():
                    # KtLint does not support absolute path in globs
                    case_output = _relative_to_cwd(case_output)
                linter = _create_cmd(settings.linter, case_output)
                if ext == ".cpp":
                    linter.append("-Wno-unused-variable")
                    if case == "coverage":
                        linter.append("-Wno-null-arithmetic" if CXX ==
                                      "clang++" else "-Wno-pointer-arith")
                proc = run(linter, env=env)
                # golint is failing regularly due to exports without docs
                if proc.returncode and linter[0] == "golint":
                    expect_failure = True
                if proc.returncode and expect_failure:
                    raise unittest.SkipTest(f"{case}{ext} failed linter")
                self.assertFalse(proc.returncode)

                if expect_failure:
                    raise AssertionError(f"{case}{ext} passed unexpectedly")

        finally:
            if not self.KEEP_GENERATED:
                case_output.unlink(missing_ok=True)
                exe.unlink(missing_ok=True)
        if settings.ext == ".rs":
            assert in_cargo_toml(case)
Example #3
0
class CodeGeneratorTests(unittest.TestCase):
    LANGS = list(_get_all_settings(Mock(indent=4)).keys())
    maxDiff = None

    SHOW_ERRORS = os.environ.get("SHOW_ERRORS", False)
    KEEP_GENERATED = os.environ.get("KEEP_GENERATED", False)
    UPDATE_EXPECTED = os.environ.get("UPDATE_EXPECTED", False)
    LINT = os.environ.get("LINT", True)

    def setUp(self):
        os.chdir(TESTS_DIR)

    @foreach(sorted(LANGS))
    @foreach(sorted(TEST_CASES))
    def test_generated(self, case, lang):
        env = os.environ.copy()
        if ENV.get(lang):
            env.update(ENV.get(lang))

        settings = _get_all_settings(Mock(indent=4), env=env)[lang]
        ext = settings.ext
        if (not self.UPDATE_EXPECTED and not self.KEEP_GENERATED
                and not os.path.exists(f"expected/{case}{ext}")):
            raise unittest.SkipTest(f"expected/{case}{ext} not found")

        if settings.formatter:
            if not spawn.find_executable(settings.formatter[0]):
                raise unittest.SkipTest(
                    f"{settings.formatter[0]} not available")

        if ext == ".kt":
            class_name = str(case.title()) + "Kt"
            exe = TESTS_DIR / (class_name + ".class")
        elif ext == ".cpp":
            exe = TESTS_DIR / "a.out"
        elif ext == ".dart" or (ext == ".nim" and sys.platform == "win32"):
            exe = TESTS_DIR / "cases" / f"{case}.exe"
        else:
            exe = TESTS_DIR / "cases" / f"{case}"
        exe.unlink(missing_ok=True)

        case_filename = TESTS_DIR / "cases" / f"{case}.py"
        case_output = TESTS_DIR / "cases" / f"{case}{ext}"
        is_script = has_main(case_filename)
        self.assertTrue(is_script)

        proc = run([sys.executable, str(case_filename)], capture_output=True)
        expected_output = proc.stdout
        if proc.returncode:
            raise RuntimeError(
                f"Invalid cases/{case}.py:\n{expected_output}{proc.stderr}")
        self.assertTrue(expected_output, "Test cases must print something")
        expected_output = expected_output.splitlines()

        args = [f"--{lang}=1", str(case_filename)]

        try:
            rv = main(args=args, env=env)
            with open(f"cases/{case}{ext}") as actual:
                generated = actual.read()
                if os.path.exists(
                        f"expected/{case}{ext}") and not self.UPDATE_EXPECTED:
                    with open(f"expected/{case}{ext}") as f2:
                        self.assertEqual(f2.read(), generated)
                        print("expected = generated")

            expect_failure = (not self.SHOW_ERRORS
                              and f"{case}{ext}" in EXPECTED_LINT_FAILURES)

            if not expect_failure:
                assert rv, "formatting failed"
            elif not rv:
                raise unittest.SkipTest("formatting failed")

            compiler = COMPILERS[lang]
            if compiler:
                if not spawn.find_executable(compiler[0]):
                    raise unittest.SkipTest(f"{compiler[0]} not available")
                expect_compile_failure = (not self.SHOW_ERRORS
                                          and f"{case}{ext}"
                                          in EXPECTED_COMPILE_FAILURES)
                if expect_compile_failure:
                    return
                proc = run([*compiler, f"cases/{case}{ext}"],
                           env=env,
                           check=not expect_failure)

                if proc.returncode:
                    raise unittest.SkipTest(f"{case}{ext} doesnt compile")

                if self.UPDATE_EXPECTED or not os.path.exists(
                        f"expected/{case}{ext}"):
                    with open(f"expected/{case}{ext}", "w") as f:
                        f.write(generated)

            stdout = None
            if exe.exists() and os.access(exe, os.X_OK):
                stdout = run([exe], env=env, capture_output=True,
                             check=True).stdout

            elif INVOKER.get(lang):
                invoker = INVOKER.get(lang)
                if not spawn.find_executable(invoker[0]):
                    raise unittest.SkipTest(f"{invoker[0]} not available")
                proc = run(
                    [*invoker, case_output],
                    env=env,
                    capture_output=True,
                    check=not expect_failure,
                )

                stdout = proc.stdout

                if proc.returncode:
                    raise unittest.SkipTest(f"Execution of {case}{ext} failed")
            else:
                raise RuntimeError("Compiled output not detected")

            if expected_output and stdout:
                stdout = stdout.splitlines()
                self.assertEqual(expected_output, stdout)

                if settings.linter and self.LINT:
                    if not spawn.find_executable(settings.linter[0]):
                        raise unittest.SkipTest(
                            f"{settings.linter[0]} not available")
                    if settings.ext == ".kt" and case_output.is_absolute():
                        # KtLint does not support absolute path in globs
                        case_output = case_output.relative_to(Path.cwd())
                    linter = _create_cmd(settings.linter, case_output)
                    if ext == ".cpp":
                        linter.append("-Wno-unused-variable")
                        if case == "coverage":
                            linter.append("-Wno-null-arithmetic" if CXX ==
                                          "clang++" else "-Wno-pointer-arith")
                    proc = run(linter, env=env)
                    # golint is failing regularly due to exports without docs
                    if proc.returncode and linter[0] == "golint":
                        expect_failure = True
                    if proc.returncode and expect_failure:
                        raise unittest.SkipTest(f"{case}{ext} failed linter")
                    self.assertFalse(proc.returncode)

                    if expect_failure:
                        raise AssertionError(
                            f"{case}{ext} passed unexpectedly")

        finally:
            if not self.KEEP_GENERATED:
                case_output.unlink(missing_ok=True)
            exe.unlink(missing_ok=True)