def test_cc_for_cxx_does_not_inject(): cc_for_cxx = CCForCXX({}) cc = CC(["-std=c99", "foo.c"]) cc_for_cxx.before_run(cc) assert cc.args == shlex.split("-std=c99 foo.c")
def test_ignore_werror(): ignore_werror = IgnoreWerror({}) cc = CC(["-Wall", "-Werror", "-O3", "-Werror"]) ignore_werror.before_run(cc) assert cc.args == shlex.split("-Wall -O3")
def test_find_outputs_journaling(monkeypatch, tmp_path): journal_output = tmp_path / "journal.jsonl" monkeypatch.setenv("BLIGHT_JOURNAL_PATH", str(journal_output)) store = tmp_path / "store" contents = b"not a real object file" contents_digest = hashlib.sha256(contents).hexdigest() dummy_foo_o = tmp_path / "foo.o" dummy_foo_o_store = store / f"{dummy_foo_o.name}-{contents_digest}" find_outputs = FindOutputs({"store": store}) cc = CC(["-c", "foo.c", "-o", str(dummy_foo_o)]) find_outputs.before_run(cc) # Pretend to be the compiler: write some junk to dummy_foo_o dummy_foo_o.write_bytes(contents) find_outputs.after_run(cc) outputs = find_outputs._result["outputs"] assert len(outputs) == 1 assert outputs[0] == { "kind": OutputKind.Object.value, "prenormalized_path": str(dummy_foo_o), "path": dummy_foo_o, "store_path": dummy_foo_o_store, "content_hash": contents_digest, } assert dummy_foo_o_store.read_bytes() == contents
def test_cc_for_cxx(): cc_for_cxx = CCForCXX({}) cc = CC(["-std=c++17", "foo.cpp"]) cc_for_cxx.before_run(cc) assert cc.args == shlex.split("-x c++ -std=c++17 foo.cpp")
def test_ignore_werror(): ignore_flto = IgnoreFlto({}) cc = CC(["-Wall", "-Werror", "-flto", "-flto=thin", "-O3"]) ignore_flto.before_run(cc) assert cc.args == shlex.split("-Wall -Werror -O3")
def test_find_outputs_store_no_hash(tmp_path): output = tmp_path / "outputs.jsonl" store = tmp_path / "store" contents = b"not a real object file" contents_digest = hashlib.sha256(contents).hexdigest() dummy_foo_o = tmp_path / "foo.o" # Store filename should not have its hash appended dummy_foo_o_store = store / dummy_foo_o.name find_outputs = FindOutputs({ "output": output, "store": store, "append_hash": "false" }) cc = CC(["-c", "foo.c", "-o", str(dummy_foo_o)]) find_outputs.before_run(cc) # Pretend to be the compiler: write some junk to dummy_foo_o dummy_foo_o.write_bytes(contents) find_outputs.after_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs == [{ "kind": OutputKind.Object.value, "prenormalized_path": str(dummy_foo_o), "path": str(dummy_foo_o), "store_path": str(dummy_foo_o_store), "content_hash": contents_digest, }] assert dummy_foo_o_store.read_bytes() == contents
def test_skip_strip(monkeypatch): monkeypatch.setenv("BLIGHT_ACTIONS", "SkipStrip") monkeypatch.setenv("BLIGHT_WRAPPED_STRIP", "true") # SkipStrip causes strip runs to be skipped strip = STRIP([]) assert SkipStrip in [a.__class__ for a in strip._actions] assert not strip._skip_run strip.run() assert strip._skip_run # SkipStrip doesn't affect other tools cc = CC(["-v"]) assert SkipStrip in [a.__class__ for a in cc._actions] assert not cc._skip_run cc.run() assert not cc._skip_run
def test_record(tmp_path): output = tmp_path / "record.jsonl" record = Record({"output": output}) record.before_run(CC(["-fake", "-flags"])) record_contents = json.loads(output.read_text()) assert record_contents["wrapped_tool"] == shutil.which("cc") assert record_contents["args"] == ["-fake", "-flags"]
def test_find_outputs(tmp_path): output = tmp_path / "outputs.jsonl" find_outputs = FindOutputs({"output": output}) cc = CC(["-o", "foo", "foo.c"]) find_outputs.before_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs[OutputKind.Executable.value] == [str(cc.cwd / "foo")]
def before_run(self, tool: CC) -> None: # type: ignore # NOTE(ww): Currently, the only way we check whether CC is being used # as a C++ compiler is by checking whether one of the `-std=c++XX` # flags has been passed. This won't catch all cases; someone could use # CC as a C++ compiler with the default C++ standard. # Other options for detecting this: # * Check for common C++-only linkages, like -lstdc++fs # * Check whether tool.inputs contains files that look like C++ if tool.std.is_cxxstd(): tool.args[:0] = ["-x", "c++"]
def test_ignore_flags(): ignore_flags = IgnoreFlags({"FLAGS": "-Wextra -ffunction-sections"}) for tool in [CC, CXX]: tool = CC([ "-Wall", "-ffunction-sections", "-O3", "-ffunction-sections", "-Wextra" ]) ignore_flags.before_run(tool) assert tool.args == shlex.split("-Wall -O3")
def test_record(tmp_path): output = tmp_path / "record.jsonl" record = Record({"output": output}) record.after_run(CC(["-fake", "-flags"]), run_skipped=False) record_contents = json.loads(output.read_text()) assert record_contents["wrapped_tool"] == shutil.which("cc") assert record_contents["args"] == ["-fake", "-flags"] assert not record_contents["run_skipped"]
def test_inject_flags(): inject_flags = InjectFlags({ "CFLAGS": "-more -flags", "CXXFLAGS": "-these -are -ignored", "CPPFLAGS": "-foo" }) cc = CC(["-fake", "-flags"]) inject_flags.before_run(cc) assert cc.args == shlex.split("-fake -flags -more -flags -foo")
def test_find_outputs_multiple(tmp_path): fake_cs = [tmp_path / fake_c for fake_c in ["foo.c", "bar.c", "baz.c"]] [fake_c.touch() for fake_c in fake_cs] output = tmp_path / "outputs.jsonl" find_outputs = FindOutputs({"output": output}) cc = CC(["-c", *[str(fake_c) for fake_c in fake_cs]]) find_outputs.before_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs[OutputKind.Object.value] == [ str(cc.cwd / fake_c.with_suffix(".o").name) for fake_c in fake_cs ]
def test_inject_linker_flags(): inject_flags = InjectFlags({ "CFLAGS": "-cc-flags", "CFLAGS_LINKER": "-c-linker-flags", "CXXFLAGS": "-cxx-flags", "CXXFLAGS_LINKER": "-cxx-linker-flags", }) cc_nolink = CC(["-c"]) cc_link = CC(["-fake", "-flags"]) cxx_nolink = CXX(["-c"]) cxx_link = CXX(["-fake", "-flags"]) inject_flags.before_run(cc_nolink) inject_flags.before_run(cc_link) inject_flags.before_run(cxx_nolink) inject_flags.before_run(cxx_link) assert cc_nolink.args == shlex.split("-c -cc-flags") assert cc_link.args == shlex.split( "-fake -flags -cc-flags -c-linker-flags") assert cxx_nolink.args == shlex.split("-c -cxx-flags") assert cxx_link.args == shlex.split( "-fake -flags -cxx-flags -cxx-linker-flags")
def test_find_outputs_annoying_so_prefixes(tmp_path, soname): output = tmp_path / "outputs.jsonl" find_outputs = FindOutputs({"output": output}) cc = CC(["-shared", "-o", soname, "foo.c"]) find_outputs.before_run(cc) find_outputs.after_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs == [{ "kind": OutputKind.SharedLibrary.value, "prenormalized_path": soname, "path": str(cc.cwd / soname), "store_path": None, "content_hash": None, }]
def test_find_outputs_handles_a_out(tmp_path): output = tmp_path / "outputs.jsonl" find_outputs = FindOutputs({"output": output}) cc = CC(["foo.c"]) find_outputs.before_run(cc) find_outputs.after_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs == [{ "kind": OutputKind.Executable.value, "prenormalized_path": "a.out", "path": str(cc.cwd / "a.out"), "store_path": None, "content_hash": None, }]
def test_find_outputs_store_output_does_not_exist(tmp_path): output = tmp_path / "outputs.jsonl" store = tmp_path / "store" dummy_foo_o = tmp_path / "foo.o" find_outputs = FindOutputs({"output": output, "store": store}) cc = CC(["-c", "foo.c", "-o", str(dummy_foo_o)]) find_outputs.before_run(cc) find_outputs.after_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs == [{ "kind": OutputKind.Object.value, "prenormalized_path": str(dummy_foo_o), "path": str(dummy_foo_o), "store_path": None, "content_hash": None, }]
def test_find_outputs_multiple(tmp_path): fake_cs = [tmp_path / fake_c for fake_c in ["foo.c", "bar.c", "baz.c"]] [fake_c.touch() for fake_c in fake_cs] output = tmp_path / "outputs.jsonl" find_outputs = FindOutputs({"output": output}) cc = CC(["-c", *[str(fake_c) for fake_c in fake_cs]]) find_outputs.before_run(cc) find_outputs.after_run(cc) outputs = json.loads(output.read_text())["outputs"] assert outputs == [{ "kind": OutputKind.Object.value, "prenormalized_path": fake_c.with_suffix(".o").name, "path": str(cc.cwd / fake_c.with_suffix(".o").name), "store_path": None, "content_hash": None, } for fake_c in fake_cs]
def test_find_inputs_journaling(monkeypatch, tmp_path): journal_output = tmp_path / "journal.jsonl" monkeypatch.setenv("BLIGHT_JOURNAL_PATH", str(journal_output)) foo_input = (tmp_path / "foo.c").resolve() foo_input.touch() find_inputs = FindInputs({}) cc = CC(["-c", str(foo_input), "-o", "foo"]) find_inputs.before_run(cc) find_inputs.after_run(cc) inputs = find_inputs._result["inputs"] assert len(inputs) == 1 assert inputs[0] == { "kind": InputKind.Source.value, "prenormalized_path": str(foo_input), "path": foo_input, "store_path": None, "content_hash": None, }
def test_find_inputs(tmp_path): output = tmp_path / "outputs.jsonl" foo_input = (tmp_path / "foo.c").resolve() foo_input.touch() find_inputs = FindInputs({"output": output}) cwd_path = Path(os.getcwd()).resolve() os.chdir(tmp_path) cc = CC(["-o", "foo", "foo.c"]) os.chdir(cwd_path) find_inputs.before_run(cc) find_inputs.after_run(cc) inputs = json.loads(output.read_text())["inputs"] assert inputs == [ { "kind": InputKind.Source.value, "prenormalized_path": "foo.c", "path": str(foo_input), "store_path": None, "content_hash": None, } ]
def test_embed_bitcode(): embed_bitcode = EmbedBitcode({}) cc = CC(["-o", "foo"]) embed_bitcode.before_run(cc) assert cc.args[0] == "-fembed-bitcode"