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)
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)
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)