test: specs and ProjectDependency() in a project file's static initialisers
ProjectArgs gets a sibling that makes its own sibling's spec at namespace scope. Before the fix that spec took the args the file was first loaded with; now it takes none on every load. The checks go through one CheckLoaded helper, which prints what each sibling was given, so a failure says which args a wrong frame handed over. ProjectDependency loads a fixture whose static initialiser asks for its pragma dependency, in a child, because a throw there terminates the process: before the fix it found none. The check that the dependency gets none of the consumer's args moves into the first load, which now passes the app an arg it ignores; the separate load could not fail its own check, and its early return skipped every later one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
060ab4380f
commit
e6363b95fe
5 changed files with 102 additions and 36 deletions
|
|
@ -90,14 +90,19 @@ int main(int argc, char** argv) {
|
|||
|
||||
const fs::path app = scratch / "app" / "project.cpp";
|
||||
const fs::path appSo = scratch / "app" / "build" / "project.so";
|
||||
std::array<std::string_view, 0> noArgs = {};
|
||||
|
||||
Check(IsTopLevelProject(), "outside any project file counts as top level");
|
||||
|
||||
// The dependency is fetched, built and linked before project.cpp runs,
|
||||
// and ProjectDependency() hands it back by either name.
|
||||
// and ProjectDependency() hands it back by either name. The app ignores
|
||||
// the arg it is loaded with, and the dependency must not get it: host
|
||||
// tooling gets none of the consumer's args, although a LocalProject spec
|
||||
// defaults to them. The consumer's flags would split the tool's variant
|
||||
// from every other consumer's, and its --target= would have the tool's
|
||||
// project.cpp choose for the wrong triple.
|
||||
try {
|
||||
Configuration cfg = LoadProject(app, noArgs);
|
||||
std::array<std::string_view, 1> flavored = { "--flavor=x" };
|
||||
Configuration cfg = LoadProject(app, flavored);
|
||||
Check(cfg.name == "hello from greeter", std::format("project.cpp imported and called the dependency's module (got '{}')", cfg.name));
|
||||
Check(std::ranges::contains(cfg.compileFlags, "-DTOP_LEVEL=1"), "the project LoadProject was pointed at sees itself as top level");
|
||||
Check(cfg.dependencies.size() == 2, "ProjectDependency resolved by module name and by configuration name");
|
||||
|
|
@ -109,6 +114,7 @@ int main(int argc, char** argv) {
|
|||
Check(dep.march == "native", "the environment's march was overridden for host tooling");
|
||||
Check(std::ranges::contains(dep.compileFlags, "-fPIC"), "the dependency archive was built position-independent");
|
||||
Check(std::ranges::contains(dep.compileFlags, "-DTOP_LEVEL=0"), "a dependency's project file does not see itself as top level");
|
||||
Check(dep.projectArgs.empty(), std::format("the dependency got none of the consumer's args (got {})", dep.projectArgs));
|
||||
Check(fs::exists(ExpectedOutput(dep)), "the dependency archive exists");
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
|
@ -116,20 +122,15 @@ int main(int argc, char** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Host tooling gets none of the consumer's args, although a LocalProject
|
||||
// spec defaults to them: the consumer's flags would split the tool's
|
||||
// variant from every other consumer's, and its --target= would have the
|
||||
// tool's project.cpp choose for the wrong triple.
|
||||
try {
|
||||
std::array<std::string_view, 1> flavored = { "--flavor=x" };
|
||||
Configuration cfg = LoadProject(app, flavored);
|
||||
const bool found = !cfg.dependencies.empty();
|
||||
Check(found, "a consumer loaded with args still finds its pragma dependency");
|
||||
if (found) Check(cfg.dependencies[0]->projectArgs.empty(), std::format("a pragma dependency is loaded without the consumer's args (got {})", cfg.dependencies[0]->projectArgs));
|
||||
} catch (const std::exception& e) {
|
||||
std::println(std::cerr, "FAIL: LoadProject with args threw: {}", e.what());
|
||||
return 1;
|
||||
// A static initialiser of the project file runs while LoadProject
|
||||
// dlopens it, before CrafterBuildProject is called, and can already ask
|
||||
// for a dependency. In a child, because a static initialiser that
|
||||
// throws terminates the process.
|
||||
{
|
||||
const std::string loaded = LoadInChild(scratch / "static-dep" / "project.cpp");
|
||||
Check(loaded == "static greeter", std::format("ProjectDependency() works in a static initialiser (got '{}')", loaded));
|
||||
}
|
||||
|
||||
Check(fs::exists(appSo), "project.so was produced");
|
||||
if (!fs::exists(appSo)) return 1;
|
||||
const fs::file_time_type firstSo = fs::last_write_time(appSo);
|
||||
|
|
|
|||
Loading…
Reference in a new issue