def test_tool_output(tmp_path): assert tool.CC(["-ofoo"]).outputs == ["foo"] assert tool.CC(["-o", "foo"]).outputs == ["foo"] assert tool.CC(["foo.c"]).outputs == ["a.out"] assert tool.CC(["-E"]).outputs == ["-"] foo_input = (tmp_path / "foo.c").resolve() foo_input.touch() assert tool.CC(["-c", str(foo_input) ]).outputs == [str(foo_input.with_suffix(".o").name)] assert tool.CC(["-S", str(foo_input) ]).outputs == [str(foo_input.with_suffix(".s").name)] bar_input = (tmp_path / "bar.c").resolve() bar_input.touch() assert tool.CC(["-c", str(foo_input), str(bar_input)]).outputs == [ str(foo_input.with_suffix(".o").name), str(bar_input.with_suffix(".o").name), ] assert tool.CC(["-S", str(foo_input), str(bar_input)]).outputs == [ str(foo_input.with_suffix(".s").name), str(bar_input.with_suffix(".s").name), ] assert tool.CC([]).outputs == [] assert tool.CC(["-v"]).outputs == []
def test_tool_response_file(tmp_path): response_file = (tmp_path / "args").resolve() response_file.write_text("-some -flags -O3") cc = tool.CC([f"@{response_file}"]) assert cc.args == ["-some", "-flags", "-O3"] assert cc.opt == OptLevel.O3
def test_tool_response_file_recursion_limit(tmp_path): response_file = (tmp_path / "args").resolve() response_file.write_text(f"-foo @{response_file}") cc = tool.CC([f"@{response_file}"]) assert cc.args == [f"@{response_file}"] assert cc.canonicalized_args == ["-foo" ] * tool.RESPONSE_FILE_RECURSION_LIMIT
def test_tool_env_filters_swizzle_path(monkeypatch): path = os.getenv("PATH") monkeypatch.setenv("PATH", f"/tmp/does-not-exist-{util.SWIZZLE_SENTINEL}:{path}") cc = tool.CC(["-v"]) env = cc.asdict()["env"] assert util.SWIZZLE_SENTINEL not in env["PATH"]
def test_tool_inputs(tmp_path): foo_input = (tmp_path / "foo.c").resolve() foo_input.touch() bar_input = (tmp_path / "bar.c").resolve() bar_input.touch() cc = tool.CC([str(foo_input), str(bar_input), "-", "-o", "foo"]) assert cc.inputs == [str(foo_input), str(bar_input), "-"]
def test_compilertool_env_warns_on_injection(monkeypatch): monkeypatch.setenv("_CL_", "foo") logger = pretend.stub(warning=pretend.call_recorder(lambda s: None)) monkeypatch.setattr(tool, "logger", logger) _ = tool.CC([]) assert logger.warning.calls == [ pretend.call("not tracking compiler's own instrumentation: {'_CL_'}") ]
def test_tool_run(monkeypatch, tmp_path): bench_output = tmp_path / "bench.jsonl" monkeypatch.setenv("BLIGHT_ACTIONS", "Benchmark") monkeypatch.setenv("BLIGHT_ACTION_BENCHMARK", f"output={bench_output}") cc = tool.CC(["-v"]) cc.run() bench_record = json.loads(bench_output.read_text()) assert bench_record["tool"] == cc.asdict() assert isinstance(bench_record["elapsed"], int)
def test_tool_run_journaling(monkeypatch, tmp_path): journal_output = tmp_path / "journal.jsonl" monkeypatch.setenv("BLIGHT_ACTIONS", "Record:Benchmark:FindOutputs") monkeypatch.setenv("BLIGHT_JOURNAL_PATH", str(journal_output)) cc = tool.CC(["-v"]) cc.run() journal = json.loads(journal_output.read_text()) assert set(journal.keys()) == {"Record", "Benchmark", "FindOutputs"} assert all(isinstance(v, dict) for v in journal.values())
def test_tool_response_file_nested(tmp_path): response_file1 = (tmp_path / "args").resolve() response_file1.write_text("-some -flags @args2 -more -flags") response_file2 = (tmp_path / "args2").resolve() response_file2.write_text("-nested -flags -O3") cc = tool.CC([f"@{response_file1}"]) assert cc.args == [ "-some", "-flags", "-nested", "-flags", "-O3", "-more", "-flags" ] assert cc.opt == OptLevel.O3
def test_tool_run_journaling_multiple(monkeypatch, tmp_path): journal_output = tmp_path / "journal.jsonl" monkeypatch.setenv("BLIGHT_ACTIONS", "Record:Benchmark:FindOutputs") monkeypatch.setenv("BLIGHT_JOURNAL_PATH", str(journal_output)) for _ in range(0, 10): cc = tool.CC(["-v"]) cc.run() count = 0 with journal_output.open() as journal: for line in journal: count += 1 record = json.loads(line) assert set(record.keys()) == {"Record", "Benchmark", "FindOutputs"} assert all(isinstance(v, dict) for v in record.values()) assert count == 10
def test_tool_explicit_library_search_paths(): cc = tool.CC([ "-L.", "--library-path", "./bar", "-L..", "-L../foo", "-L", "foo", "-L/lib", "--library-path=../../baz", ]) assert cc.explicit_library_search_paths == [ cc.cwd, cc.cwd / "bar", cc.cwd.parent, cc.cwd.parent / "foo", cc.cwd / "foo", Path("/lib").resolve(), cc.cwd.parent.parent / "baz", ]
def test_cc(flags, lang, std, stage, opt): flags = shlex.split(flags) cc = tool.CC(flags) assert cc.wrapped_tool() == shutil.which("cc") assert cc.lang == lang assert cc.std == std assert cc.stage == stage assert cc.opt == opt assert repr( cc) == f"<CC {cc.wrapped_tool()} {cc.lang} {cc.std} {cc.stage}>" assert cc.asdict() == { "name": cc.__class__.__name__, "wrapped_tool": cc.wrapped_tool(), "args": flags, "cwd": str(cc.cwd), "lang": lang.name, "std": std.name, "stage": stage.name, "opt": opt.name, }
def test_tool_library_names(): cc = tool.CC(["-lfoo", "-l", "bar", "-liberty"]) assert cc.library_names == ["libfoo", "libbar", "libiberty"]
def test_tool_response_file_invalid_file(): cc = tool.CC(["@/this/file/does/not/exist"]) assert cc.args == ["@/this/file/does/not/exist"] assert cc.canonicalized_args == []
def test_tool_fails(monkeypatch): monkeypatch.setenv("BLIGHT_WRAPPED_CC", "false") with pytest.raises(BuildError): tool.CC([]).run()
def test_codemodel_mixin(flags, code_model): cc = tool.CC(shlex.split(flags)) assert cc.code_model == code_model
def test_defines_mixin(flags, defines, undefines): cc = tool.CC(shlex.split(flags)) assert cc.defines == defines assert cc.indexed_undefines == undefines