Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Comparability and hashability of PackageInfo and MatchSpec #3369

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions libmamba/include/mamba/specs/match_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
9 changes: 9 additions & 0 deletions libmamba/include/mamba/specs/regex_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
};

Hind-M marked this conversation as resolved.
Show resolved Hide resolved
#endif
2 changes: 1 addition & 1 deletion libmamba/include/mamba/util/flat_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Member Author

@jjerphan jjerphan Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hash_vals hashes set as a value rather than its' internal elements (I thought it would).

hash_range considers set a range and hashes all of its elements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually wondering about the use cases of using hash_vals, and btw I just realized there are no tests for hash_vals. Would you mind adding them please? (in this PR or another one, as you prefer).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hash_vals is used to combine the hashes of individual scalar values. I can open a PR after this one to test its behavior.

}
};

Expand Down
13 changes: 0 additions & 13 deletions libmamba/include/mamba/util/heap_optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};

Hind-M marked this conversation as resolved.
Show resolved Hide resolved
#endif
5 changes: 5 additions & 0 deletions libmamba/src/specs/match_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions libmamba/tests/src/specs/test_build_number_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
14 changes: 14 additions & 0 deletions libmamba/tests/src/specs/test_chimera_string_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
14 changes: 14 additions & 0 deletions libmamba/tests/src/specs/test_glob_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
27 changes: 27 additions & 0 deletions libmamba/tests/src/specs/test_match_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
34 changes: 34 additions & 0 deletions libmamba/tests/src/specs/test_package_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
14 changes: 14 additions & 0 deletions libmamba/tests/src/specs/test_regex_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
14 changes: 14 additions & 0 deletions libmamba/tests/src/specs/test_unresolved_channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
15 changes: 15 additions & 0 deletions libmamba/tests/src/specs/test_version_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Loading