From 848b7f5bd71871bc527bf208db3b427bbb9497be Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Thu, 29 Jun 2023 17:53:32 +0200 Subject: [PATCH 1/6] Use array instead of vector --- libmamba/tests/src/specs/test_version.cpp | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index f882bcbc13..20622f349d 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -5,6 +5,7 @@ // The full license is in the file LICENSE, distributed with this software. #include +#include #include #include @@ -37,19 +38,19 @@ namespace mamba::specs CHECK_GE(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); // clang-format off - auto sorted_atoms = std::vector{ - { 1, "*" }, - { 1, "dev" }, - { 1, "_" }, - { 1, "a" }, - { 1, "alpha" }, - { 1, "b" }, - { 1, "beta" }, - { 1, "c" }, - { 1, "r" }, - { 1, "rc" }, - { 1, "" }, - { 1, "post" }, + auto sorted_atoms = std::array{ + VersionPartAtom{ 1, "*" }, + VersionPartAtom{ 1, "dev" }, + VersionPartAtom{ 1, "_" }, + VersionPartAtom{ 1, "a" }, + VersionPartAtom{ 1, "alpha" }, + VersionPartAtom{ 1, "b" }, + VersionPartAtom{ 1, "beta" }, + VersionPartAtom{ 1, "c" }, + VersionPartAtom{ 1, "r" }, + VersionPartAtom{ 1, "rc" }, + VersionPartAtom{ 1, "" }, + VersionPartAtom{ 1, "post" }, }; // clang-format on From 08ebe7afbc091b7d1623f56cd2c30e7c6177b8c6 Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Thu, 29 Jun 2023 17:54:55 +0200 Subject: [PATCH 2/6] Remove test indentation --- libmamba/tests/src/specs/test_version.cpp | 437 +++++++++++----------- 1 file changed, 216 insertions(+), 221 deletions(-) diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index 20622f349d..c9f15d564d 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -13,31 +13,30 @@ #include "mamba/specs/version.hpp" -namespace mamba::specs -{ +using namespace mamba::specs; - TEST_SUITE("version") +TEST_SUITE("version") +{ + TEST_CASE("atom_comparison") { - TEST_CASE("atom_comparison") - { - // No literal - CHECK_EQ(VersionPartAtom(1), VersionPartAtom(1, "")); - // lowercase - CHECK_EQ(VersionPartAtom(1, "dev"), VersionPartAtom(1, "DEV")); - // All operator comparison for mumerals - CHECK_NE(VersionPartAtom(1), VersionPartAtom(2, "dev")); - CHECK_LT(VersionPartAtom(1), VersionPartAtom(2, "dev")); - CHECK_LE(VersionPartAtom(1), VersionPartAtom(2, "dev")); - CHECK_GT(VersionPartAtom(2, "dev"), VersionPartAtom(1)); - CHECK_GE(VersionPartAtom(2, "dev"), VersionPartAtom(1)); - // All operator comparison for literals - CHECK_NE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - CHECK_LT(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - CHECK_LE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - CHECK_GT(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); - CHECK_GE(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); + // No literal + CHECK_EQ(VersionPartAtom(1), VersionPartAtom(1, "")); + // lowercase + CHECK_EQ(VersionPartAtom(1, "dev"), VersionPartAtom(1, "DEV")); + // All operator comparison for mumerals + CHECK_NE(VersionPartAtom(1), VersionPartAtom(2, "dev")); + CHECK_LT(VersionPartAtom(1), VersionPartAtom(2, "dev")); + CHECK_LE(VersionPartAtom(1), VersionPartAtom(2, "dev")); + CHECK_GT(VersionPartAtom(2, "dev"), VersionPartAtom(1)); + CHECK_GE(VersionPartAtom(2, "dev"), VersionPartAtom(1)); + // All operator comparison for literals + CHECK_NE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); + CHECK_LT(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); + CHECK_LE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); + CHECK_GT(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); + CHECK_GE(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); - // clang-format off + // clang-format off auto sorted_atoms = std::array{ VersionPartAtom{ 1, "*" }, VersionPartAtom{ 1, "dev" }, @@ -52,58 +51,55 @@ namespace mamba::specs VersionPartAtom{ 1, "" }, VersionPartAtom{ 1, "post" }, }; - // clang-format on + // clang-format on - // Strict ordering - CHECK(std::is_sorted(sorted_atoms.cbegin(), sorted_atoms.cend())); - // None compare equal (given the is_sorted assumption) - CHECK_EQ( - std::adjacent_find(sorted_atoms.cbegin(), sorted_atoms.cend()), - sorted_atoms.cend() - ); - } + // Strict ordering + CHECK(std::is_sorted(sorted_atoms.cbegin(), sorted_atoms.cend())); + // None compare equal (given the is_sorted assumption) + CHECK_EQ(std::adjacent_find(sorted_atoms.cbegin(), sorted_atoms.cend()), sorted_atoms.cend()); + } - TEST_CASE("atom_format") - { - CHECK_EQ(VersionPartAtom(1, "dev").str(), "1dev"); - CHECK_EQ(VersionPartAtom(2).str(), "2"); - } + TEST_CASE("atom_format") + { + CHECK_EQ(VersionPartAtom(1, "dev").str(), "1dev"); + CHECK_EQ(VersionPartAtom(2).str(), "2"); + } - TEST_CASE("version_comparison") - { - auto v = Version(0, { { { 1, "post" } } }); - REQUIRE_EQ(v.version().size(), 1); - REQUIRE_EQ(v.version().front().size(), 1); - REQUIRE_EQ(v.version().front().front(), VersionPartAtom(1, "post")); + TEST_CASE("version_comparison") + { + auto v = Version(0, { { { 1, "post" } } }); + REQUIRE_EQ(v.version().size(), 1); + REQUIRE_EQ(v.version().front().size(), 1); + REQUIRE_EQ(v.version().front().front(), VersionPartAtom(1, "post")); - // Same empty 0!1post version - CHECK_EQ(Version(0, { { { 1, "post" } } }), Version(0, { { { 1, "post" } } })); - // Empty trailing atom 0!1a == 0!1a0"" - CHECK_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" }, {} } })); - // Empty trailing part 0!1a == 0!1a.0"" - CHECK_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" } }, { {} } })); - // Mixed 0!1a0""0"" == 0!1a.0"" - CHECK_EQ(Version(0, { { { 1, "a" }, {}, {} } }), Version(0, { { { 1, "a" } }, { {} } })); + // Same empty 0!1post version + CHECK_EQ(Version(0, { { { 1, "post" } } }), Version(0, { { { 1, "post" } } })); + // Empty trailing atom 0!1a == 0!1a0"" + CHECK_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" }, {} } })); + // Empty trailing part 0!1a == 0!1a.0"" + CHECK_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" } }, { {} } })); + // Mixed 0!1a0""0"" == 0!1a.0"" + CHECK_EQ(Version(0, { { { 1, "a" }, {}, {} } }), Version(0, { { { 1, "a" } }, { {} } })); - // Different epoch 0!2post < 1!1dev - CHECK_LT(Version(0, { { { 2, "post" } } }), Version(1, { { { 1, "dev" } } })); - CHECK_GE(Version(1, { { { 1, "dev" } } }), Version(0, { { { 2, "post" } } })); - // Different lenght with dev - CHECK_LT(Version(0, { { { 1 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); - CHECK_LT(Version(0, { { { 1 } }, { { 0 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); - // Different major 0!1post < 0!2dev - CHECK_LT(Version(0, { { { 1, "post" } } }), Version(0, { { { 2, "dev" } } })); - // Different length 0!2"".0"" < 0!11"".0"".0post all operator - CHECK_NE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - CHECK_LT(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - CHECK_LE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - CHECK_GT(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); - CHECK_GE(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); - } + // Different epoch 0!2post < 1!1dev + CHECK_LT(Version(0, { { { 2, "post" } } }), Version(1, { { { 1, "dev" } } })); + CHECK_GE(Version(1, { { { 1, "dev" } } }), Version(0, { { { 2, "post" } } })); + // Different lenght with dev + CHECK_LT(Version(0, { { { 1 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); + CHECK_LT(Version(0, { { { 1 } }, { { 0 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); + // Different major 0!1post < 0!2dev + CHECK_LT(Version(0, { { { 1, "post" } } }), Version(0, { { { 2, "dev" } } })); + // Different length 0!2"".0"" < 0!11"".0"".0post all operator + CHECK_NE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); + CHECK_LT(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); + CHECK_LE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); + CHECK_GT(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); + CHECK_GE(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); + } - TEST_CASE("version_format") - { - // clang-format off + TEST_CASE("version_format") + { + // clang-format off CHECK_EQ( Version(0, {{{11, "a"}, {0, "post"}}, {{3}}, {{4, "dev"}}}).str(), "11a0post.3.4dev" @@ -116,17 +112,17 @@ namespace mamba::specs Version(1, {{{11, "a"}, {0}}, {{3}}, {{4, "dev"}}}, {{{1}}, {{2}}}).str(), "1!11a0.3.4dev+1.2" ); - // clang-format on - } + // clang-format on + } - /** - * Test from Conda - * - * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py - */ - TEST_CASE("parse") - { - // clang-format off + /** + * Test from Conda + * + * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py + */ + TEST_CASE("parse") + { + // clang-format off auto sorted_version = std::vector>{ {"0.4", Version(0, {{{0}}, {{4}}})}, {"0.4.0", Version(0, {{{0}}, {{4}}, {{0}}})}, @@ -183,82 +179,82 @@ namespace mamba::specs {"1!3.1.1.6", Version(1, {{{3}}, {{1}}, {{1}}, {{6}}})}, {"2!0.4.1", Version(2, {{{0}}, {{4}}, {{1}}})}, }; - // clang-format on - for (const auto& [raw, expected] : sorted_version) - { - CHECK_EQ(Version::parse(raw), expected); - } + // clang-format on + for (const auto& [raw, expected] : sorted_version) + { + CHECK_EQ(Version::parse(raw), expected); + } - CHECK(std::is_sorted( - sorted_version.cbegin(), - sorted_version.cend(), - [](const auto& a, const auto& b) { return a.second < b.second; } - )); + CHECK(std::is_sorted( + sorted_version.cbegin(), + sorted_version.cend(), + [](const auto& a, const auto& b) { return a.second < b.second; } + )); - // Lowercase and strip - CHECK_EQ(Version::parse("0.4.1.rc"), Version::parse(" 0.4.1.RC ")); - CHECK_EQ(Version::parse(" 0.4.1.RC "), Version::parse("0.4.1.rc")); + // Lowercase and strip + CHECK_EQ(Version::parse("0.4.1.rc"), Version::parse(" 0.4.1.RC ")); + CHECK_EQ(Version::parse(" 0.4.1.RC "), Version::parse("0.4.1.rc")); - // Functional assertions - CHECK_EQ(Version::parse(" 0.4.rc "), Version::parse("0.4.RC")); - CHECK_EQ(Version::parse("0.4"), Version::parse("0.4.0")); - CHECK_NE(Version::parse("0.4"), Version::parse("0.4.1")); - CHECK_EQ(Version::parse("0.4.a1"), Version::parse("0.4.0a1")); - CHECK_NE(Version::parse("0.4.a1"), Version::parse("0.4.1a1")); - } + // Functional assertions + CHECK_EQ(Version::parse(" 0.4.rc "), Version::parse("0.4.RC")); + CHECK_EQ(Version::parse("0.4"), Version::parse("0.4.0")); + CHECK_NE(Version::parse("0.4"), Version::parse("0.4.1")); + CHECK_EQ(Version::parse("0.4.a1"), Version::parse("0.4.0a1")); + CHECK_NE(Version::parse("0.4.a1"), Version::parse("0.4.1a1")); + } - TEST_CASE("parse_invalid") - { - // Wrong epoch - CHECK_THROWS_AS(Version::parse("!1.1"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("-1!1.1"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("foo!1.1"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("0post1!1.1"), std::invalid_argument); + TEST_CASE("parse_invalid") + { + // Wrong epoch + CHECK_THROWS_AS(Version::parse("!1.1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("-1!1.1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("foo!1.1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("0post1!1.1"), std::invalid_argument); - // Empty parts - CHECK_THROWS_AS(Version::parse(""), std::invalid_argument); - CHECK_THROWS_AS(Version::parse(" "), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("!2.2"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("0!"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("!"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("1."), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("1..1"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("5.5..mw"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("1.2post+"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("1!+1.1"), std::invalid_argument); + // Empty parts + CHECK_THROWS_AS(Version::parse(""), std::invalid_argument); + CHECK_THROWS_AS(Version::parse(" "), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("!2.2"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("0!"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("!"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("1."), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("1..1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("5.5..mw"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("1.2post+"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("1!+1.1"), std::invalid_argument); - // Repeated delimiters - CHECK_THROWS_AS(Version::parse("5.5++"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("5.5+1+0.0"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("1!2!3.0"), std::invalid_argument); + // Repeated delimiters + CHECK_THROWS_AS(Version::parse("5.5++"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("5.5+1+0.0"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("1!2!3.0"), std::invalid_argument); - // '-' and '_' delimiters not allowed together. - CHECK_THROWS_AS(Version::parse("1-1_1"), std::invalid_argument); + // '-' and '_' delimiters not allowed together. + CHECK_THROWS_AS(Version::parse("1-1_1"), std::invalid_argument); - // Forbidden characters - CHECK_THROWS_AS(Version::parse("3.5&1"), std::invalid_argument); - CHECK_THROWS_AS(Version::parse("3.5|1"), std::invalid_argument); - } + // Forbidden characters + CHECK_THROWS_AS(Version::parse("3.5&1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("3.5|1"), std::invalid_argument); + } - /** - * Test from Conda. - * - * Some packages (most notably openssl) have incompatible version conventions. - * In particular, openssl interprets letters as version counters rather than - * pre-release identifiers. For openssl, the relation - * - * 1.0.1 < 1.0.1a => False # should be true for openssl - * - * holds, whereas conda packages use the opposite ordering. You can work-around - * this problem by appending an underscore to plain version numbers: - * - * 1.0.1_ < 1.0.1a => True # ensure correct ordering for openssl - * - * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py - */ - TEST_CASE("parse_openssl") - { - // clang-format off + /** + * Test from Conda. + * + * Some packages (most notably openssl) have incompatible version conventions. + * In particular, openssl interprets letters as version counters rather than + * pre-release identifiers. For openssl, the relation + * + * 1.0.1 < 1.0.1a => False # should be true for openssl + * + * holds, whereas conda packages use the opposite ordering. You can work-around + * this problem by appending an underscore to plain version numbers: + * + * 1.0.1_ < 1.0.1a => True # ensure correct ordering for openssl + * + * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py + */ + TEST_CASE("parse_openssl") + { + // clang-format off auto versions = std::vector{ Version::parse("1.0.1dev"), Version::parse("1.0.1_"), // <- this @@ -278,84 +274,83 @@ namespace mamba::specs Version::parse("1.0.1post.za"), Version::parse("1.0.2"), }; - // clang-format on + // clang-format on - // Strict ordering - CHECK(std::is_sorted(versions.cbegin(), versions.cend())); - // None compare equal (given the is_sorted assumption) - CHECK_EQ(std::adjacent_find(versions.cbegin(), versions.cend()), versions.cend()); - } + // Strict ordering + CHECK(std::is_sorted(versions.cbegin(), versions.cend())); + // None compare equal (given the is_sorted assumption) + CHECK_EQ(std::adjacent_find(versions.cbegin(), versions.cend()), versions.cend()); + } - /** - * Test from Conda slightly modified from the PEP 440 test suite. - * - * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py - * @see https://github.com/pypa/packaging/blob/master/tests/test_version.py - */ - TEST_CASE("parse_pep440") - { - auto versions = std::vector{ - // Implicit epoch of 0 - Version::parse("1.0a1"), - Version::parse("1.0a2.dev456"), - Version::parse("1.0a12.dev456"), - Version::parse("1.0a12"), - Version::parse("1.0b1.dev456"), - Version::parse("1.0b2"), - Version::parse("1.0b2.post345.dev456"), - Version::parse("1.0b2.post345"), - Version::parse("1.0c1.dev456"), - Version::parse("1.0c1"), - Version::parse("1.0c3"), - Version::parse("1.0rc2"), - Version::parse("1.0.dev456"), - Version::parse("1.0"), - Version::parse("1.0.post456.dev34"), - Version::parse("1.0.post456"), - Version::parse("1.1.dev1"), - Version::parse("1.2.r32+123456"), - Version::parse("1.2.rev33+123456"), - Version::parse("1.2+abc"), - Version::parse("1.2+abc123def"), - Version::parse("1.2+abc123"), - Version::parse("1.2+123abc"), - Version::parse("1.2+123abc456"), - Version::parse("1.2+1234.abc"), - Version::parse("1.2+123456"), - // Explicit epoch of 1 - Version::parse("1!1.0a1"), - Version::parse("1!1.0a2.dev456"), - Version::parse("1!1.0a12.dev456"), - Version::parse("1!1.0a12"), - Version::parse("1!1.0b1.dev456"), - Version::parse("1!1.0b2"), - Version::parse("1!1.0b2.post345.dev456"), - Version::parse("1!1.0b2.post345"), - Version::parse("1!1.0c1.dev456"), - Version::parse("1!1.0c1"), - Version::parse("1!1.0c3"), - Version::parse("1!1.0rc2"), - Version::parse("1!1.0.dev456"), - Version::parse("1!1.0"), - Version::parse("1!1.0.post456.dev34"), - Version::parse("1!1.0.post456"), - Version::parse("1!1.1.dev1"), - Version::parse("1!1.2.r32+123456"), - Version::parse("1!1.2.rev33+123456"), - Version::parse("1!1.2+abc"), - Version::parse("1!1.2+abc123def"), - Version::parse("1!1.2+abc123"), - Version::parse("1!1.2+123abc"), - Version::parse("1!1.2+123abc456"), - Version::parse("1!1.2+1234.abc"), - Version::parse("1!1.2+123456"), - }; - // clang-format on + /** + * Test from Conda slightly modified from the PEP 440 test suite. + * + * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py + * @see https://github.com/pypa/packaging/blob/master/tests/test_version.py + */ + TEST_CASE("parse_pep440") + { + auto versions = std::vector{ + // Implicit epoch of 0 + Version::parse("1.0a1"), + Version::parse("1.0a2.dev456"), + Version::parse("1.0a12.dev456"), + Version::parse("1.0a12"), + Version::parse("1.0b1.dev456"), + Version::parse("1.0b2"), + Version::parse("1.0b2.post345.dev456"), + Version::parse("1.0b2.post345"), + Version::parse("1.0c1.dev456"), + Version::parse("1.0c1"), + Version::parse("1.0c3"), + Version::parse("1.0rc2"), + Version::parse("1.0.dev456"), + Version::parse("1.0"), + Version::parse("1.0.post456.dev34"), + Version::parse("1.0.post456"), + Version::parse("1.1.dev1"), + Version::parse("1.2.r32+123456"), + Version::parse("1.2.rev33+123456"), + Version::parse("1.2+abc"), + Version::parse("1.2+abc123def"), + Version::parse("1.2+abc123"), + Version::parse("1.2+123abc"), + Version::parse("1.2+123abc456"), + Version::parse("1.2+1234.abc"), + Version::parse("1.2+123456"), + // Explicit epoch of 1 + Version::parse("1!1.0a1"), + Version::parse("1!1.0a2.dev456"), + Version::parse("1!1.0a12.dev456"), + Version::parse("1!1.0a12"), + Version::parse("1!1.0b1.dev456"), + Version::parse("1!1.0b2"), + Version::parse("1!1.0b2.post345.dev456"), + Version::parse("1!1.0b2.post345"), + Version::parse("1!1.0c1.dev456"), + Version::parse("1!1.0c1"), + Version::parse("1!1.0c3"), + Version::parse("1!1.0rc2"), + Version::parse("1!1.0.dev456"), + Version::parse("1!1.0"), + Version::parse("1!1.0.post456.dev34"), + Version::parse("1!1.0.post456"), + Version::parse("1!1.1.dev1"), + Version::parse("1!1.2.r32+123456"), + Version::parse("1!1.2.rev33+123456"), + Version::parse("1!1.2+abc"), + Version::parse("1!1.2+abc123def"), + Version::parse("1!1.2+abc123"), + Version::parse("1!1.2+123abc"), + Version::parse("1!1.2+123abc456"), + Version::parse("1!1.2+1234.abc"), + Version::parse("1!1.2+123456"), + }; + // clang-format on - // Strict ordering - CHECK(std::is_sorted(versions.cbegin(), versions.cend())); - // None compare equal (given the is_sorted assumption) - CHECK_EQ(std::adjacent_find(versions.cbegin(), versions.cend()), versions.cend()); - } + // Strict ordering + CHECK(std::is_sorted(versions.cbegin(), versions.cend())); + // None compare equal (given the is_sorted assumption) + CHECK_EQ(std::adjacent_find(versions.cbegin(), versions.cend()), versions.cend()); } } From 2cddc5031734d26d33aea36e5bb6b0a30eee37ee Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Thu, 29 Jun 2023 18:47:00 +0200 Subject: [PATCH 3/6] Implement Version::starts_with --- libmamba/include/mamba/specs/version.hpp | 36 +++++--- libmamba/src/specs/version.cpp | 104 ++++++++++++++++++++-- libmamba/tests/src/specs/test_version.cpp | 77 ++++++++++++++++ 3 files changed, 200 insertions(+), 17 deletions(-) diff --git a/libmamba/include/mamba/specs/version.hpp b/libmamba/include/mamba/specs/version.hpp index 9ec2970f56..1c563dff61 100644 --- a/libmamba/include/mamba/specs/version.hpp +++ b/libmamba/include/mamba/specs/version.hpp @@ -103,20 +103,32 @@ namespace mamba::specs static auto parse(std::string_view str) -> Version; + /** Construct version ``0.0``. */ + Version() noexcept = default; Version(std::size_t epoch, CommonVersion&& version, CommonVersion&& local = {}) noexcept; - auto epoch() const noexcept -> std::size_t; - auto version() const noexcept -> const CommonVersion&; - auto local() const noexcept -> const CommonVersion&; - - auto str() const -> std::string; - - auto operator==(const Version& other) const -> bool; - auto operator!=(const Version& other) const -> bool; - auto operator<(const Version& other) const -> bool; - auto operator<=(const Version& other) const -> bool; - auto operator>(const Version& other) const -> bool; - auto operator>=(const Version& other) const -> bool; + [[nodiscard]] auto epoch() const noexcept -> std::size_t; + [[nodiscard]] auto version() const noexcept -> const CommonVersion&; + [[nodiscard]] auto local() const noexcept -> const CommonVersion&; + + [[nodiscard]] auto str() const -> std::string; + + [[nodiscard]] auto operator==(const Version& other) const -> bool; + [[nodiscard]] auto operator!=(const Version& other) const -> bool; + [[nodiscard]] auto operator<(const Version& other) const -> bool; + [[nodiscard]] auto operator<=(const Version& other) const -> bool; + [[nodiscard]] auto operator>(const Version& other) const -> bool; + [[nodiscard]] auto operator>=(const Version& other) const -> bool; + + /** + * Return true if this version starts with the other prefix. + * + * For instance 1.2.3 starts with 1.2 but not the opposite. + * Because Conda versions can contain an arbitrary number of segments, some of which + * with alpha releases, this function cannot be written as a comparison. + * One would need to comoare with a version with infinitely pre-release segments. + */ + [[nodiscard]] auto starts_with(const Version& prefix) const -> bool; private: diff --git a/libmamba/src/specs/version.cpp b/libmamba/src/specs/version.cpp index 1475a68273..b4e2b9ef3c 100644 --- a/libmamba/src/specs/version.cpp +++ b/libmamba/src/specs/version.cpp @@ -47,7 +47,6 @@ namespace mamba::specs { return compare_three_way(std::strcmp(a.c_str(), b.c_str()), 0); } - } /*************************************** @@ -218,13 +217,14 @@ namespace mamba::specs * Similarily ``[1, 1] is less than ``[1, 2, 0]`` but more than ``[1, 1, -1]`` * because ``-1 < 0``. */ - template + template constexpr auto lexicographical_compare_three_way_trailing( Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, - T empty, + Empty1 empty1, + Empty2 empty2, Cmp comp ) -> strong_ordering { @@ -242,7 +242,7 @@ namespace mamba::specs { for (; first1 != last1; ++first1) { - if (auto c = comp(*first1, empty); c != strong_ordering::equal) + if (auto c = comp(*first1, empty2); c != strong_ordering::equal) { return c; } @@ -255,7 +255,7 @@ namespace mamba::specs { for (; first2 != last2; ++first2) { - if (auto c = comp(empty, *first2); c != strong_ordering::equal) + if (auto c = comp(empty1, *first2); c != strong_ordering::equal) { return c; } @@ -265,6 +265,27 @@ namespace mamba::specs return strong_ordering::equal; } + template + constexpr auto lexicographical_compare_three_way_trailing( + Iter1 first1, + Iter1 last1, + Iter2 first2, + Iter2 last2, + Empty empty, + Cmp comp + ) -> strong_ordering + { + return lexicographical_compare_three_way_trailing( + first1, + last1, + first2, + last2, + empty, + empty, + comp + ); + } + template <> auto compare_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering { @@ -337,6 +358,79 @@ namespace mamba::specs return compare_three_way(*this, other) != strong_ordering::less; } + namespace + { + struct AlwaysEqual + { + }; + + template + auto starts_with_three_way(const AlwaysEqual&, const T&) -> strong_ordering + { + return strong_ordering::equal; + } + + template + auto starts_with_three_way(const T&, const AlwaysEqual&) -> strong_ordering + { + return strong_ordering::equal; + } + + auto starts_with_three_way(const VersionPartAtom& a, const VersionPartAtom& b) + -> strong_ordering + { + if ((a.numeral() == b.numeral()) && b.literal().empty()) + { + return strong_ordering::equal; + } + return compare_three_way(a, b); + } + + auto starts_with_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering + { + return lexicographical_compare_three_way_trailing( + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPartAtom{}, + AlwaysEqual{}, + [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } + ); + } + + auto starts_with_three_way(const CommonVersion& a, const CommonVersion& b) -> strong_ordering + { + return lexicographical_compare_three_way_trailing( + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPart{}, + AlwaysEqual{}, + [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } + ); + } + + auto starts_with_three_way(const Version& a, const Version& b) -> strong_ordering + { + if (auto c = compare_three_way(a.epoch(), b.epoch()); c != strong_ordering::equal) + { + return c; + } + if (auto c = starts_with_three_way(a.version(), b.version()); c != strong_ordering::equal) + { + return c; + } + return compare_three_way(a.local(), b.local()); + } + } + + auto Version::starts_with(const Version& prefix) const -> bool + { + return starts_with_three_way(*this, prefix) == strong_ordering::equal; + } + namespace { // TODO(C++20) This is a std::string_view constructor diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index c9f15d564d..746fbf7757 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -97,6 +97,83 @@ TEST_SUITE("version") CHECK_GE(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); } + TEST_CASE("starts_with") + { + SUBCASE("positive") + { + // clang-format off + auto const versions = std::vector>{ + // 0!1.0.0, 0!1 + {Version(), Version()}, + // 0!1a2post, 0!1a2post + {Version(0, {{{1, "a"}, {2, "post"}}}), Version(0, {{{1, "a"}, {2, "post"}}})}, + // 0!1a2post, 0!1a2post + {Version(0, {{{1, "a"}, {2, "post"}}}), Version(0, {{{1, "a"}, {2, "post"}}})}, + // 0!1, 0!1 + {Version(0, {{{1}}}), Version(0, {{{1}}})}, + // 0!1, 0!1.1 + {Version(0, {{{1}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1, 0!1.3 + {Version(0, {{{1}}}), Version(0, {{{1}}, {{3}}})}, + // 0!1, 0!1.1a + {Version(0, {{{1}}}), Version(0, {{{1}}, {{1, "a"}}})}, + // 0!1, 0!1a + {Version(0, {{{1}}}), Version(0, {{{1, "a"}}})}, + // 0!1, 0!1.0a + {Version(0, {{{1}}}), Version(0, {{{1}}, {{0, "a"}}})}, + // 0!1, 0!1post + {Version(0, {{{1}}}), Version(0, {{{1, "post"}}})}, + // 0!1a, 0!1a.1 + {Version(0, {{{1, "a"}}}), Version(0, {{{1, "a"}}, {{1}}})}, + // 0!1a, 0!1a.1post3 + {Version(0, {{{1, "a"}}}), Version(0, {{{1, "a"}}, {{1, "post"}, {3}}})}, + // 0!1.0.0, 0!1 + {Version(0, {{{1}}, {{0}}, {{0}}}), Version(0, {{{1}}})}, + }; + // clang-format on + + for (const auto& [prefix, ver] : versions) + { + CAPTURE(prefix.str()); + CAPTURE(ver.str()); + CHECK(ver.starts_with(prefix)); + } + } + + SUBCASE("negative") + { + // clang-format off + auto const versions = std::vector>{ + // 0!1a, 1!1a + {Version(0, {{{1, "a"}}}), Version(1, {{{1, "a"}}})}, + // 0!2, 0!1 + {Version(0, {{{2}}}), Version(0, {{{1}}})}, + // 0!1, 0!2 + {Version(0, {{{1}}}), Version(0, {{{2}}})}, + // 0!1.2, 0!1.3 + {Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{3}}})}, + // 0!1.2, 0!1.1 + {Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1.2, 0!1 + {Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}})}, + // 0!1a, 0!1b + {Version(0, {{{1, "a"}}}), Version(0, {{{1, "b"}}})}, + // 0!1.1a, 0!1.1b + {Version(0, {{{1}}, {{1, "a"}}}), Version(0, {{{1}}, {{1, "b"}}})}, + // 0!1.1a, 0!1.1 + {Version(0, {{{1}}, {{1, "a"}}}), Version(0, {{{1}}, {{1}}})}, + }; + // clang-format on + + for (const auto& [prefix, ver] : versions) + { + CAPTURE(prefix.str()); + CAPTURE(ver.str()); + CHECK_FALSE(ver.starts_with(prefix)); + } + } + } + TEST_CASE("version_format") { // clang-format off From f1f047ec1225af02e5566b64c03263200c0f83ee Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Fri, 30 Jun 2023 12:19:38 +0200 Subject: [PATCH 4/6] Implement Version::comaptible_with --- libmamba/include/mamba/specs/version.hpp | 10 ++ libmamba/src/specs/version.cpp | 134 ++++++++++++++-------- libmamba/tests/src/specs/test_version.cpp | 105 +++++++++++++++++ 3 files changed, 199 insertions(+), 50 deletions(-) diff --git a/libmamba/include/mamba/specs/version.hpp b/libmamba/include/mamba/specs/version.hpp index 1c563dff61..c59a7b5001 100644 --- a/libmamba/include/mamba/specs/version.hpp +++ b/libmamba/include/mamba/specs/version.hpp @@ -130,6 +130,16 @@ namespace mamba::specs */ [[nodiscard]] auto starts_with(const Version& prefix) const -> bool; + /** + * Return true if this version is a compatible upgrade to the given one. + * + * For instance 1.3.1 is compatible with 1.2.1 at level 0 (first component `1 == 1``), + * at level 1 (second component `` 3 >= 2``), but not at level two (because the second + * component is stricly larger ``3 > 2``). + * Compatible versions are always smaller than the current version. + */ + [[nodiscard]] auto compatible_with(const Version& older, std::size_t level) const -> bool; + private: // Stored in decreasing size order for performance diff --git a/libmamba/src/specs/version.cpp b/libmamba/src/specs/version.cpp index b4e2b9ef3c..31f22a652a 100644 --- a/libmamba/src/specs/version.cpp +++ b/libmamba/src/specs/version.cpp @@ -216,53 +216,61 @@ namespace mamba::specs * ``[1, 2, 0, 0]`` are considered equal, however ``[1, 2]`` and ``[1, 0, 2]`` are not. * Similarily ``[1, 1] is less than ``[1, 2, 0]`` but more than ``[1, 1, -1]`` * because ``-1 < 0``. + * + * @return The comparison between the two sequence + * @return The first index where the two sequence diverge. */ template constexpr auto lexicographical_compare_three_way_trailing( - Iter1 first1, - Iter1 last1, - Iter2 first2, - Iter2 last2, - Empty1 empty1, - Empty2 empty2, + const Iter1 first1, + const Iter1 last1, + const Iter2 first2, + const Iter2 last2, + const Empty1 empty1, + const Empty2 empty2, Cmp comp - ) -> strong_ordering + ) -> std::pair { - for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) + assert(first1 <= last1); + assert(first2 <= last2); + + auto iter1 = first1; + auto iter2 = first2; + for (; (iter1 != last1) && (iter2 != last2); ++iter1, ++iter2) { - if (auto c = comp(*first1, *first2); c != strong_ordering::equal) + if (auto c = comp(*iter1, *iter2); c != strong_ordering::equal) { - return c; + return { c, static_cast(std::distance(first1, iter1)) }; } } // They have the same leading elements but 1 has more elements // We do a lexicographic compare with an infite sequence of empties - if ((first1 != last1)) + if ((iter1 != last1)) { - for (; first1 != last1; ++first1) + for (; iter1 != last1; ++iter1) { - if (auto c = comp(*first1, empty2); c != strong_ordering::equal) + if (auto c = comp(*iter1, empty2); c != strong_ordering::equal) { - return c; + return { c, static_cast(std::distance(first1, iter1)) }; } } } // first2 != last2 // They have the same leading elements but 2 has more elements // We do a lexicographic compare with an infite sequence of empties - if ((first2 != last2)) + if ((iter2 != last2)) { - for (; first2 != last2; ++first2) + for (; iter2 != last2; ++iter2) { - if (auto c = comp(empty1, *first2); c != strong_ordering::equal) + if (auto c = comp(empty1, *iter2); c != strong_ordering::equal) { - return c; + return { c, static_cast(std::distance(first2, iter2)) }; } } } // They have the same elements - return strong_ordering::equal; + return { strong_ordering::equal, static_cast(std::distance(first1, iter1)) }; } template @@ -273,7 +281,7 @@ namespace mamba::specs Iter2 last2, Empty empty, Cmp comp - ) -> strong_ordering + ) -> std::pair { return lexicographical_compare_three_way_trailing( first1, @@ -290,26 +298,26 @@ namespace mamba::specs auto compare_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering { return lexicographical_compare_three_way_trailing( - a.cbegin(), - a.cend(), - b.cbegin(), - b.cend(), - VersionPartAtom{}, - [](const auto& x, const auto& y) { return compare_three_way(x, y); } - ); + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPartAtom{}, + [](const auto& x, const auto& y) { return compare_three_way(x, y); } + ).first; } template <> auto compare_three_way(const CommonVersion& a, const CommonVersion& b) -> strong_ordering { return lexicographical_compare_three_way_trailing( - a.cbegin(), - a.cend(), - b.cbegin(), - b.cend(), - VersionPart{}, - [](const auto& x, const auto& y) { return compare_three_way(x, y); } - ); + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPart{}, + [](const auto& x, const auto& y) { return compare_three_way(x, y); } + ).first; } template <> @@ -389,27 +397,27 @@ namespace mamba::specs auto starts_with_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering { return lexicographical_compare_three_way_trailing( - a.cbegin(), - a.cend(), - b.cbegin(), - b.cend(), - VersionPartAtom{}, - AlwaysEqual{}, - [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } - ); + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPartAtom{}, + AlwaysEqual{}, + [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } + ).first; } auto starts_with_three_way(const CommonVersion& a, const CommonVersion& b) -> strong_ordering { return lexicographical_compare_three_way_trailing( - a.cbegin(), - a.cend(), - b.cbegin(), - b.cend(), - VersionPart{}, - AlwaysEqual{}, - [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } - ); + a.cbegin(), + a.cend(), + b.cbegin(), + b.cend(), + VersionPart{}, + AlwaysEqual{}, + [](const auto& x, const auto& y) { return starts_with_three_way(x, y); } + ).first; } auto starts_with_three_way(const Version& a, const Version& b) -> strong_ordering @@ -431,6 +439,32 @@ namespace mamba::specs return starts_with_three_way(*this, prefix) == strong_ordering::equal; } + namespace + { + auto + compatible_with_impl(const CommonVersion& newer, const CommonVersion& older, std::size_t level) + -> bool + { + auto [cmp, idx] = lexicographical_compare_three_way_trailing( + newer.cbegin(), + newer.cend(), + older.cbegin(), + older.cend(), + VersionPart{}, + [](const auto& x, const auto& y) { return compare_three_way(x, y); } + ); + + return (cmp == strong_ordering::equal) + || ((cmp == strong_ordering::greater) && (idx >= level)); + } + } + + auto Version::compatible_with(const Version& older, std::size_t level) const -> bool + { + return (epoch() == older.epoch()) && compatible_with_impl(version(), older.version(), level) + && compatible_with_impl(local(), older.local(), level); + } + namespace { // TODO(C++20) This is a std::string_view constructor diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index 746fbf7757..b7c80d5e33 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -174,6 +174,111 @@ TEST_SUITE("version") } } + TEST_CASE("compatible_with") + { + SUBCASE("positive") + { + // clang-format off + auto const versions = std::vector>{ + {0, Version(), Version()}, + {1, Version(), Version()}, + // 0!1a2post, 0!1a2post + {1, Version(0, {{{1, "a"}, {2, "post"}}}), Version(0, {{{1, "a"}, {2, "post"}}})}, + // 0!1, 0!1 + {0, Version(0, {{{1}}}), Version(0, {{{1}}})}, + // 0!1, 0!1 + {0, Version(0, {{{1}}}), Version(0, {{{1}}})}, + // 0!1, 0!2 + {0, Version(0, {{{1}}}), Version(0, {{{2}}})}, + // 0!1, 0!1 + {1, Version(0, {{{1}}}), Version(0, {{{1}}})}, + // 0!1, 0!1.1 + {0, Version(0, {{{1}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1, 0!1.1 + {1, Version(0, {{{1}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1, 0!1.3 + {1, Version(0, {{{1}}}), Version(0, {{{1}}, {{3}}})}, + // 0!1, 0!1.1a + {0, Version(0, {{{1}}}), Version(0, {{{1}}, {{1, "a"}}})}, + // 0!1a, 0!1 + {0, Version(0, {{{1, "a"}}}), Version(0, {{{1}}})}, + // 0!1a, 0!1b + {0, Version(0, {{{1, "a"}}}), Version(0, {{{1, "b"}}})}, + // 0!1a, 0!1b + {1, Version(0, {{{1}}, {{1, "a"}}}), Version(0, {{{1}}, {{1, "b"}}})}, + // 0!1, 0!1post + {0, Version(0, {{{1}}}), Version(0, {{{1, "post"}}})}, + // 0!1a, 0!1a.1 + {0, Version(0, {{{1, "a"}}}), Version(0, {{{1, "a"}}, {{1}}})}, + // 0!1a, 0!1a.1post3 + {0, Version(0, {{{1, "a"}}}), Version(0, {{{1, "a"}}, {{1, "post"}, {3}}})}, + // 0!1.1a, 0!1.1 + {1, Version(0, {{{1}}, {{1, "a"}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1.0.0, 0!1 + {2, Version(0, {{{1}}, {{0}}, {{0}}}), Version(0, {{{1}}})}, + // 0!1.2.3, 0!1.2.3 + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{1}}, {{2}}, {{3}}})}, + // 0!1.2.3, 0!1.2.4 + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{1}}, {{2}}, {{4}}})}, + // 0!1.2, 0!1.3 + {1, Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{3}}})}, + }; + // clang-format on + + for (const auto& [level, older, newer] : versions) + { + CAPTURE(level); + CAPTURE(older.str()); + CAPTURE(newer.str()); + CHECK(newer.compatible_with(older, level)); + } + } + + SUBCASE("negative") + { + // clang-format off + auto const versions = std::vector>{ + // 0!1a, 1!1a + {0, Version(0, {{{1, "a"}}}), Version(1, {{{1, "a"}}})}, + // 0!1, 0!1a + {0, Version(0, {{{1}}}), Version(0, {{{1, "a"}}})}, + // 0!1, 0!1a.0a + {0, Version(0, {{{1}}}), Version(0, {{{1}}, {{0, "a"}}})}, + // 0!2, 0!1 + {0, Version(0, {{{2}}}), Version(0, {{{1}}})}, + // 0!1, 0!2 + {1, Version(0, {{{1}}}), Version(0, {{{2}}})}, + // 0!1.2, 0!1.1 + {1, Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1.2, 0!1 + {1, Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}})}, + // 0!1.2.3, 0!1.3.1 + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{1}}, {{3}}, {{1}}})}, + // 0!1.2.3, 0!1.3a.0 + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{1}}, {{3, "a"}}, {{0}}})}, + // 0!1.2.3, 0!1.3 + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{1}}, {{3}}})}, + // 0!1.2.3, 0!2a + {2, Version(0, {{{1}}, {{2}}, {{3}}}), Version(0, {{{2, "a"}}})}, + // 0!1.2, 0!1.1 + {1, Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1, 0!1.1 + {2, Version(0, {{{1}}}), Version(0, {{{1}}, {{1}}})}, + // 0!1.2, 0!1.1 + {0, Version(0, {{{1}}, {{2}}}), Version(0, {{{1}}, {{1}}})}, + }; + // clang-format on + + for (const auto& [level, older, newer] : versions) + { + CAPTURE(level); + CAPTURE(older.str()); + CAPTURE(newer.str()); + CHECK_FALSE(newer.compatible_with(older, level)); + } + } + } + TEST_CASE("version_format") { // clang-format off From 74ec8ff8b7436f174ae1b36450ac7becbac72b2d Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Fri, 30 Jun 2023 14:20:05 +0200 Subject: [PATCH 5/6] Fix clang compilation error --- libmamba/tests/src/specs/test_version.cpp | 33 ++++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index b7c80d5e33..a7df004353 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "mamba/specs/version.hpp" @@ -134,8 +135,9 @@ TEST_SUITE("version") for (const auto& [prefix, ver] : versions) { - CAPTURE(prefix.str()); - CAPTURE(ver.str()); + // Working around clang compilation issue. + const auto msg = fmt::format(R"(prefix="{}" version="{}")", prefix.str(), ver.str()); + CAPTURE(msg); CHECK(ver.starts_with(prefix)); } } @@ -167,8 +169,9 @@ TEST_SUITE("version") for (const auto& [prefix, ver] : versions) { - CAPTURE(prefix.str()); - CAPTURE(ver.str()); + // Working around clang compilation issue. + const auto msg = fmt::format(R"(prefix="{}" version="{}")", prefix.str(), ver.str()); + CAPTURE(msg); CHECK_FALSE(ver.starts_with(prefix)); } } @@ -227,9 +230,14 @@ TEST_SUITE("version") for (const auto& [level, older, newer] : versions) { - CAPTURE(level); - CAPTURE(older.str()); - CAPTURE(newer.str()); + // Working around clang compilation issue. + const auto msg = fmt::format( + R"(level={} prefix="{}" version="{}")", + level, + older.str(), + newer.str() + ); + CAPTURE(msg); CHECK(newer.compatible_with(older, level)); } } @@ -271,9 +279,14 @@ TEST_SUITE("version") for (const auto& [level, older, newer] : versions) { - CAPTURE(level); - CAPTURE(older.str()); - CAPTURE(newer.str()); + // Working around clang compilation issue. + const auto msg = fmt::format( + R"(level={} prefix="{}" version="{}")", + level, + older.str(), + newer.str() + ); + CAPTURE(msg); CHECK_FALSE(newer.compatible_with(older, level)); } } From 272ab930cffabe06235fcd279b975c67af9fae8c Mon Sep 17 00:00:00 2001 From: AntoinePrv Date: Mon, 3 Jul 2023 12:05:40 +0200 Subject: [PATCH 6/6] Implement review comments from @JohanMabille --- libmamba/src/specs/version.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/libmamba/src/specs/version.cpp b/libmamba/src/specs/version.cpp index 31f22a652a..b99a05e37b 100644 --- a/libmamba/src/specs/version.cpp +++ b/libmamba/src/specs/version.cpp @@ -222,17 +222,17 @@ namespace mamba::specs */ template constexpr auto lexicographical_compare_three_way_trailing( - const Iter1 first1, - const Iter1 last1, - const Iter2 first2, - const Iter2 last2, - const Empty1 empty1, - const Empty2 empty2, + Iter1 first1, + Iter1 last1, + Iter2 first2, + Iter2 last2, + const Empty1& empty1, + const Empty2& empty2, Cmp comp ) -> std::pair { - assert(first1 <= last1); - assert(first2 <= last2); + assert(std::distance(first1, last1) >= 0); + assert(std::distance(first2, last2) >= 0); auto iter1 = first1; auto iter2 = first2; @@ -279,7 +279,7 @@ namespace mamba::specs Iter1 last1, Iter2 first2, Iter2 last2, - Empty empty, + const Empty& empty, Cmp comp ) -> std::pair { @@ -372,6 +372,14 @@ namespace mamba::specs { }; + [[maybe_unused]] auto starts_with_three_way(const AlwaysEqual&, const AlwaysEqual&) + -> strong_ordering + { + // This comparison should not happen with the current usage. + assert(false); + return strong_ordering::equal; + } + template auto starts_with_three_way(const AlwaysEqual&, const T&) -> strong_ordering {