diff --git a/tests/CleanProject/main.cpp b/tests/CleanProject/main.cpp index ecad097..25f85f1 100644 --- a/tests/CleanProject/main.cpp +++ b/tests/CleanProject/main.cpp @@ -29,6 +29,12 @@ namespace { std::ofstream(root / "keep-me.txt") << "untouched"; return root; } + + std::int32_t RunWith(std::vector args) { + std::vector argv; + for (std::string& arg : args) argv.push_back(arg.data()); + return Run(static_cast(argv.size()), argv.data()); + } } int main() { @@ -71,6 +77,22 @@ int main() { Check(fs::exists(cwdBin) == cwdBinExisted, "the cwd's bin/ is untouched"); } + { + // `clean` is a verb only where a verb can stand. After `format` it + // is a rule-name glob like any other word, and a glob must never + // delete the build trees. The project file cannot compile, so the + // run fails once it gets as far as loading it — which is the proof + // that it went on to format instead of cleaning and exiting 0. + fs::path root = StageProject("format-glob"); + fs::path projectFile = root / "project.cpp"; + std::ofstream(projectFile) << "this is not valid C++ at all\n"; + + const std::int32_t exitCode = RunWith({"crafter-build", "format", "clean", std::format("--project={}", projectFile.string())}); + Check(fs::exists(root / "bin" / "app-x86_64-pc-linux-gnu-native-native-0badf00d" / "app"), "`format clean` leaves bin/ alone"); + Check(fs::exists(root / "build" / "app-x86_64-pc-linux-gnu-native-native-0badf00d" / "main_impl.o"), "`format clean` leaves build/ alone"); + Check(exitCode != 0, "`format clean` goes on to load the project instead of cleaning"); + } + if (Failures > 0) { std::println(std::cerr, "{} assertions failed", Failures); return 1;