diff --git a/src/core/layout.cpp b/src/core/layout.cpp index 70b3f859..a4a9b0da 100644 --- a/src/core/layout.cpp +++ b/src/core/layout.cpp @@ -218,7 +218,8 @@ auto discover_variants( } } - std::sort(result.begin(), result.end()); + // StringId order is interning order, i.e. readdir order, not name order. + std::ranges::sort(result, {}, [&pool](StringId id) { return pool.get(id); }); return result; } diff --git a/test/unit/test_layout.cpp b/test/unit/test_layout.cpp index 9f0e8bab..e6a418cf 100644 --- a/test/unit/test_layout.cpp +++ b/test/unit/test_layout.cpp @@ -6,9 +6,11 @@ #include "pup/core/layout.hpp" #include "pup/core/string_pool.hpp" +#include #include #include #include +#include namespace fs = std::filesystem; @@ -199,3 +201,38 @@ TEST_CASE("discover_layout from build directory", "[e2e][layout]") REQUIRE(fs::canonical(std::string(global_pool().get(result->output_root))) == fs::canonical(tmp.path() / "build").string()); } } + +SCENARIO("discover_variants orders variants by name, not by interning order", "[e2e][layout]") +{ + GIVEN("build directories whose names were interned in reverse-lexicographic order") + { + // Names unique to this test, so the interning below decides their handles. + auto const names = std::array { + "dvar_alpha", + "dvar_bravo", + "dvar_mike", + "dvar_zeta", + }; + + auto tmp = TempDir {}; + tmp.create_file("Tupfile.ini"); + for (auto name : names) { + tmp.create_file(fs::path { name } / "tup.config"); + } + for (auto i = names.size(); i-- > 0;) { + (void)global_pool().intern(names[i]); + } + + WHEN("the source root is scanned for variants") + { + THEN("the variants are in lexicographic name order") + { + auto found = std::vector {}; + for (auto id : pup::discover_variants(tmp.path().string())) { + found.push_back(global_pool().get(id)); + } + REQUIRE(found == std::vector(names.begin(), names.end())); + } + } + } +}