| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file LICENSE.rst or https://cmake.org/licensing for details. */ |
| #include <functional> |
| #include <iostream> |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <unordered_set> |
| #include <utility> |
| #include <vector> |
| |
| #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<bool(std::string const&, int&)> makeOracle( |
| std::map<std::string, int> 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<std::string> const& entries, |
| std::unordered_set<std::string> const& replyNames, |
| std::map<std::string, int> const& ids, |
| std::set<std::string> const& expected) |
| { |
| std::vector<std::string> const removed = |
| cmFileAPI::FilesToRemove<int>(entries, replyNames, makeOracle(ids)); |
| std::set<std::string> 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; |
| } |