/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file LICENSE.rst or https://cmake.org/licensing for details. */ #include #include #include #include #include #include #include #include #include "cmFileAPI.h" namespace { // Identity oracle over a name->id map. A name absent from the map models a // file whose identity cannot be obtained (GetFileId failure). std::function makeOracle( std::map const& ids) { return [ids](std::string const& name, int& id) -> bool { auto const it = ids.find(name); if (it == ids.end()) { return false; } id = it->second; return true; }; } bool checkCase(char const* label, std::vector const& entries, std::unordered_set const& replyNames, std::map const& ids, std::set const& expected) { std::vector const removed = cmFileAPI::FilesToRemove(entries, replyNames, makeOracle(ids)); std::set const actual(removed.begin(), removed.end()); if (actual != expected) { std::cout << "FAILED: " << label << "\n expected removals:"; for (std::string const& e : expected) { std::cout << ' ' << e; } std::cout << "\n actual removals: "; for (std::string const& a : actual) { std::cout << ' ' << a; } std::cout << '\n'; return false; } return true; } } // namespace int testCMFileAPI(int /*unused*/, char* /*unused*/[]) { bool ok = true; // An on-disk entry that resolves to the same identity as a just-written // reply (a case-only-different name aliasing one inode) is kept. ok &= checkCase( "case-variant alias kept", { "target-foo-Debug-H.json" }, { "target-foo-debug-H.json" }, { { "target-foo-debug-H.json", 1 }, { "target-foo-Debug-H.json", 1 } }, {}); // A genuinely stale entry with a distinct identity is removed. ok &= checkCase("distinct stale removed", { "target-old-H.json" }, { "target-new-H.json" }, { { "target-new-H.json", 1 }, { "target-old-H.json", 2 } }, { "target-old-H.json" }); // An entry whose exact name was just written is kept without consulting the // identity oracle (its name is intentionally absent from the id map). ok &= checkCase("exact-name match kept", { "index-x.json" }, { "index-x.json" }, {}, {}); // Fail-safe: an entry whose identity cannot be obtained is retained. ok &= checkCase("candidate id failure retained", { "unreadable.json" }, { "target-new-H.json" }, { { "target-new-H.json", 1 } }, {}); // No kept-side fail-safe is needed: an alias shares its inode, so when a // kept reply's identity is unknown the candidate's is too and the // candidate-side fail-safe retains it. Both names are absent to model it. ok &= checkCase("unknown kept id: correlated alias retained", { "alias-of-unidentified.json" }, { "target-new-H.json", "unidentified-kept.json" }, { { "target-new-H.json", 1 } }, {}); // Mixed: an aliasing entry is kept while an unrelated stale entry is // removed. ok &= checkCase("mixed alias and stale", { "a-alias.json", "stale.json" }, { "a.json", "b.json" }, { { "a.json", 1 }, { "b.json", 2 }, { "a-alias.json", 1 }, { "stale.json", 3 } }, { "stale.json" }); return ok ? 0 : 1; }