test: Comparability and hashability of `PackageInfo` and `MatchSpec` (#3369)

test: Add test for comparability and hashability

Signed-off-by: Julien Jerphanion <git@jjerphan.xyz>
This commit is contained in:
Julien Jerphanion 2024-07-30 17:35:50 +02:00 committed by GitHub
parent d0d7eea49a
commit ca8cee50fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 166 additions and 18 deletions

View File

@ -153,10 +153,7 @@ namespace mamba::specs
return !(*this == other);
}
auto extra_members_hash() const -> std::size_t
{
return mamba::util::hash_vals(m_extra);
}
auto extra_members_hash() const -> std::size_t;
private:

View File

@ -75,4 +75,13 @@ struct fmt::formatter<mamba::specs::RegexSpec>
format(const ::mamba::specs::RegexSpec& spec, format_context& ctx) const -> decltype(ctx.out());
};
template <>
struct std::hash<mamba::specs::RegexSpec>
{
auto operator()(const mamba::specs::RegexSpec& spec) const -> std::size_t
{
return std::hash<std::string>{}(spec.str());
}
};
#endif

View File

@ -565,7 +565,7 @@ struct std::hash<mamba::util::flat_set<Key, Compare, Allocator>>
{
auto operator()(const mamba::util::flat_set<Key, Compare, Allocator>& set) const -> std::size_t
{
return mamba::util::hash_vals(set);
return mamba::util::hash_range(set);
}
};

View File

@ -251,17 +251,4 @@ namespace mamba::util
}
}
template <typename T>
struct std::hash<mamba::util::heap_optional<T>>
{
std::size_t operator()(const mamba::util::heap_optional<T>& opt) const
{
if (opt.has_value())
{
return std::hash<T>{}(*opt);
}
return 0;
}
};
#endif

View File

@ -1044,6 +1044,11 @@ namespace mamba::specs
return *m_extra;
}
auto MatchSpec::extra_members_hash() const -> std::size_t
{
return std::hash<ExtraMembers>{}(m_extra.value_or(ExtraMembers()));
}
namespace match_spec_literals
{
auto operator""_ms(const char* str, std::size_t len) -> MatchSpec

View File

@ -137,4 +137,22 @@ TEST_SUITE("specs::build_number_spec")
CHECK_FALSE(BuildNumberSpec::parse("=3").value().is_explicitly_free());
CHECK_FALSE(BuildNumberSpec::parse("<2").value().is_explicitly_free());
}
TEST_CASE("Comparability and hashability")
{
auto bn1 = BuildNumberSpec::parse("=3").value();
auto bn2 = BuildNumberSpec::parse("3").value();
auto bn3 = BuildNumberSpec::parse("*").value();
CHECK_EQ(bn1, bn2);
CHECK_NE(bn1, bn3);
auto hash_fn = std::hash<BuildNumberSpec>{};
auto bn1_hash = hash_fn(bn1);
auto bn2_hash = hash_fn(bn2);
auto bn3_hash = hash_fn(bn3);
CHECK_EQ(bn1_hash, bn2_hash);
CHECK_NE(bn1_hash, bn3_hash);
}
}

View File

@ -70,4 +70,18 @@ TEST_SUITE("specs::chimera_string_spec")
CHECK_FALSE(spec.is_exact());
CHECK_FALSE(spec.is_glob());
}
TEST_CASE("Comparability and hashability")
{
auto spec1 = ChimeraStringSpec::parse("mkl").value();
auto spec2 = ChimeraStringSpec::parse("mkl").value();
auto spec3 = ChimeraStringSpec::parse("*").value();
CHECK_EQ(spec1, spec2);
CHECK_NE(spec1, spec3);
std::hash<ChimeraStringSpec> hash_fn;
CHECK_EQ(hash_fn(spec1), hash_fn(spec2));
CHECK_NE(hash_fn(spec1), hash_fn(spec3));
}
}

View File

@ -55,4 +55,18 @@ TEST_SUITE("specs::glob_spec")
CHECK_FALSE(spec.is_free());
CHECK_FALSE(spec.is_exact());
}
TEST_CASE("Comparability and hashability")
{
auto spec1 = GlobSpec("py*");
auto spec2 = GlobSpec("py*");
auto spec3 = GlobSpec("pyth*");
CHECK_EQ(spec1, spec2);
CHECK_NE(spec1, spec3);
auto hash_fn = std::hash<GlobSpec>();
CHECK_EQ(hash_fn(spec1), hash_fn(spec2));
CHECK_NE(hash_fn(spec1), hash_fn(spec3));
}
}

View File

@ -812,4 +812,31 @@ TEST_SUITE("specs::match_spec")
}));
}
}
TEST_CASE("MatchSpec comparability and hashability")
{
using namespace specs::match_spec_literals;
using namespace specs::version_literals;
const auto spec1 = "py*>=3.7=bld[build_number='<=2', md5=lemd5, track_features='mkl,openssl']"_ms;
// Create an identical specification
const auto spec2 = "py*>=3.7=bld[build_number='<=2', md5=lemd5, track_features='mkl,openssl']"_ms;
// Create a different specification
const auto spec3 = "py*>=3.7=bld[build_number='<=2', md5=lemd5, track_features='mkl']"_ms;
// Check that the two copies are equal
CHECK_EQ(spec1, spec2);
// Check that the different specification is not equal to the first one
CHECK_NE(spec1, spec3);
// Check that the hash of the two copies is the same
auto spec1_hash = std::hash<MatchSpec>{}(spec1);
auto spec2_hash = std::hash<MatchSpec>{}(spec2);
auto spec3_hash = std::hash<MatchSpec>{}(spec3);
CHECK_EQ(spec1_hash, spec2_hash);
CHECK_NE(spec1_hash, spec3_hash);
}
}

View File

@ -190,5 +190,39 @@ TEST_SUITE("specs::package_info")
CHECK_FALSE(j.get<PackageInfo>() != pkg);
}
}
SUBCASE("PackageInfo comparability and hashability")
{
auto pkg2 = PackageInfo();
pkg2.name = "foo";
pkg2.version = "4.0";
pkg2.build_string = "mybld";
pkg2.build_number = 5;
pkg2.noarch = NoArchType::Generic;
pkg2.channel = "conda-forge";
pkg2.package_url = "https://repo.mamba.pm/conda-forge/linux-64/foo-4.0-mybld.conda";
pkg2.platform = "linux-64";
pkg2.filename = "foo-4.0-mybld.conda";
pkg2.license = "MIT";
pkg2.size = 3200;
pkg2.timestamp = 4532;
pkg2.sha256 = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b";
pkg2.signatures = R"("signatures": { "some_file.tar.bz2": { "a133184c9c7a651f55db194031a6c1240b798333923dc9319d1fe2c94a1242d": { "signature": "7a67a875d0454c14671d960a02858e059d154876dab6b3873304a27102063c9c25"}}})";
pkg2.md5 = "68b329da9893e34099c7d8ad5cb9c940";
pkg2.track_features = { "mkl", "blas" };
pkg2.dependencies = { "python>=3.7", "requests" };
pkg2.constrains = { "pip>=2.1" };
auto hash_fn = std::hash<PackageInfo>{};
CHECK_EQ(pkg, pkg2);
CHECK_EQ(hash_fn(pkg), hash_fn(pkg2));
pkg2.md5[0] = '0';
CHECK_NE(pkg, pkg2);
CHECK_NE(hash_fn(pkg), hash_fn(pkg2));
}
}
}

View File

@ -66,4 +66,18 @@ TEST_SUITE("specs::regex_spec")
CHECK_FALSE(spec.is_explicitly_free());
CHECK_FALSE(spec.is_exact());
}
TEST_CASE("Comparability and hashability")
{
auto spec1 = RegexSpec::parse("pyth*").value();
auto spec2 = RegexSpec::parse("pyth*").value();
auto spec3 = RegexSpec::parse("python").value();
CHECK_EQ(spec1, spec2);
CHECK_NE(spec1, spec3);
auto hash_fn = std::hash<RegexSpec>();
CHECK_EQ(hash_fn(spec1), hash_fn(spec2));
CHECK_NE(hash_fn(spec1), hash_fn(spec3));
}
}

View File

@ -242,4 +242,18 @@ TEST_SUITE("specs::unresolved_channel")
"location[linux-64,noarch]"
);
}
TEST_CASE("Comparability and hashability")
{
auto uc1 = UnresolvedChannel::parse("conda-forge").value();
auto uc2 = UnresolvedChannel::parse("conda-forge").value();
auto uc3 = UnresolvedChannel::parse("conda-forge/linux-64").value();
CHECK_EQ(uc1, uc2);
CHECK_NE(uc1, uc3);
auto hash_fn = std::hash<UnresolvedChannel>();
CHECK_EQ(hash_fn(uc1), hash_fn(uc2));
CHECK_NE(hash_fn(uc1), hash_fn(uc3));
}
}

View File

@ -444,4 +444,19 @@ TEST_SUITE("specs::version_spec")
CHECK_FALSE(VersionSpec::parse("==2.3|!=2.3").value().is_explicitly_free());
CHECK_FALSE(VersionSpec::parse("=2.3,<3.0").value().is_explicitly_free());
}
TEST_CASE("Comparability and hashability")
{
auto spec1 = VersionSpec::parse("*").value();
auto spec2 = VersionSpec::parse("*").value();
auto spec3 = VersionSpec::parse("=2.4").value();
CHECK_EQ(spec1, spec2);
CHECK_NE(spec1, spec3);
auto hash_fn = std::hash<VersionSpec>();
CHECK_EQ(hash_fn(spec1), hash_fn(spec2));
CHECK_NE(hash_fn(spec1), hash_fn(spec3));
}
}