diff --git a/libmamba/environment-dev.yml b/libmamba/environment-dev.yml index 4389f16aa5..087697a038 100644 --- a/libmamba/environment-dev.yml +++ b/libmamba/environment-dev.yml @@ -10,8 +10,7 @@ dependencies: - libarchive - libsodium - libcurl >=7.86 - - gtest - - gmock + - doctest - cpp-expected - reproc-cpp - yaml-cpp diff --git a/libmamba/tests/CMakeLists.txt b/libmamba/tests/CMakeLists.txt index 1640596305..cf29078553 100644 --- a/libmamba/tests/CMakeLists.txt +++ b/libmamba/tests/CMakeLists.txt @@ -11,6 +11,7 @@ mamba_target_add_compile_warnings(testing_libmamba_lock WARNING_AS_ERROR ${MAMBA set(LIBMAMBA_TEST_SRCS + src/test_main.cpp # C++ wrapping of libsolv src/solv-cpp/test_queue.cpp # Utility library @@ -60,13 +61,13 @@ target_include_directories( PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/libmamba/src" ) -find_package(GTest REQUIRED) +find_package(doctest REQUIRED) find_package(Threads REQUIRED) target_link_libraries( test_libmamba PUBLIC libmamba - PRIVATE GTest::GTest GTest::Main Threads::Threads + PRIVATE doctest::doctest Threads::Threads ) # Copy data directory into binary dir to avoid modifications diff --git a/libmamba/tests/src/core/test_activation.cpp b/libmamba/tests/src/core/test_activation.cpp index 1d7bbe27fb..c216e216e0 100644 --- a/libmamba/tests/src/core/test_activation.cpp +++ b/libmamba/tests/src/core/test_activation.cpp @@ -1,14 +1,17 @@ -#include - #include "mamba/core/activation.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(activation, activation) + TEST_SUITE("activation") { - PosixActivator a; - // std::cout << a.add_prefix_to_path("/home/wolfv/miniconda3", 0) << - // std::endl; std::cout << a.activate("/home/wolfv/miniconda3/", false) << - // std::endl; + TEST_CASE("activation") + { + PosixActivator a; + // std::cout << a.add_prefix_to_path("/home/wolfv/miniconda3", 0) << + // std::endl; std::cout << a.activate("/home/wolfv/miniconda3/", false) << + // std::endl; + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_channel.cpp b/libmamba/tests/src/core/test_channel.cpp index 645f027f0c..1d933aae10 100644 --- a/libmamba/tests/src/core/test_channel.cpp +++ b/libmamba/tests/src/core/test_channel.cpp @@ -1,10 +1,10 @@ -#include - #include "mamba/core/channel.hpp" #include "mamba/core/channel_builder.hpp" #include "mamba/core/context.hpp" #include "mamba/core/output.hpp" +#include "doctest/doctest.h" + namespace mamba { std::string fix_win_path(const std::string& path); @@ -27,598 +27,623 @@ namespace mamba #endif #ifdef _WIN32 - TEST(Channel, fix_win_path) + TEST_SUITE("Channel") { - std::string test_str("file://\\unc\\path\\on\\win"); - auto out = fix_win_path(test_str); - EXPECT_EQ(out, "file:///unc/path/on/win"); - auto out2 = fix_win_path("file://C:\\Program\\ (x74)\\Users\\hello\\ world"); - EXPECT_EQ(out2, "file://C:/Program\\ (x74)/Users/hello\\ world"); - auto out3 = fix_win_path("file://\\\\Programs\\xyz"); - EXPECT_EQ(out3, "file://Programs/xyz"); + TEST_CASE("fix_win_path") + { + std::string test_str("file://\\unc\\path\\on\\win"); + auto out = fix_win_path(test_str); + CHECK_EQ(out, "file:///unc/path/on/win"); + auto out2 = fix_win_path("file://C:\\Program\\ (x74)\\Users\\hello\\ world"); + CHECK_EQ(out2, "file://C:/Program\\ (x74)/Users/hello\\ world"); + auto out3 = fix_win_path("file://\\\\Programs\\xyz"); + CHECK_EQ(out3, "file://Programs/xyz"); + } } #endif - TEST(ChannelContext, init) + TEST_SUITE("ChannelContext") { - // ChannelContext builds its custom channels with - // make_simple_channel - - const auto& ch = ChannelContext::instance().get_channel_alias(); - EXPECT_EQ(ch.scheme(), "https"); - EXPECT_EQ(ch.location(), "conda.anaconda.org"); - EXPECT_EQ(ch.name(), ""); - EXPECT_EQ(ch.canonical_name(), ""); - - const auto& custom = ChannelContext::instance().get_custom_channels(); - - auto it = custom.find("pkgs/main"); - EXPECT_NE(it, custom.end()); - EXPECT_EQ(it->second.name(), "pkgs/main"); - EXPECT_EQ(it->second.location(), "repo.anaconda.com"); - EXPECT_EQ(it->second.canonical_name(), "defaults"); - - it = custom.find("pkgs/pro"); - EXPECT_NE(it, custom.end()); - EXPECT_EQ(it->second.name(), "pkgs/pro"); - EXPECT_EQ(it->second.location(), "repo.anaconda.com"); - EXPECT_EQ(it->second.canonical_name(), "pkgs/pro"); - - it = custom.find("pkgs/r"); - EXPECT_NE(it, custom.end()); - EXPECT_EQ(it->second.name(), "pkgs/r"); - EXPECT_EQ(it->second.location(), "repo.anaconda.com"); - EXPECT_EQ(it->second.canonical_name(), "defaults"); - } - - TEST(ChannelContext, channel_alias) - { - // ChannelContext builds its custom channels with - // make_simple_channel - auto& ctx = Context::instance(); - ctx.channel_alias = "https://mydomain.com/channels/"; - ChannelContext::instance().reset(); - - const auto& ch = ChannelContext::instance().get_channel_alias(); - EXPECT_EQ(ch.scheme(), "https"); - EXPECT_EQ(ch.location(), "mydomain.com/channels"); - EXPECT_EQ(ch.name(), ""); - EXPECT_EQ(ch.canonical_name(), ""); - - const auto& custom = ChannelContext::instance().get_custom_channels(); - - auto it = custom.find("pkgs/main"); - EXPECT_NE(it, custom.end()); - EXPECT_EQ(it->second.name(), "pkgs/main"); - EXPECT_EQ(it->second.location(), "repo.anaconda.com"); - EXPECT_EQ(it->second.canonical_name(), "defaults"); - - std::string value = "conda-forge"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "mydomain.com/channels"); - EXPECT_EQ(c.name(), "conda-forge"); - EXPECT_EQ(c.canonical_name(), "conda-forge"); - // EXPECT_EQ(c.url(), "conda-forge"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - - ctx.channel_alias = "https://conda.anaconda.org"; - ChannelContext::instance().reset(); - } - - // Regression test for https://github.com/mamba-org/mamba/issues/1671 - TEST(ChannelContext, channel_alias_with_custom_default_channels) - { - auto& ctx = Context::instance(); - auto old_default_channels = ctx.default_channels; - ctx.channel_alias = "https://ali.as/"; - ctx.default_channels = { "prefix" }; - ctx.channels = { "prefix-and-more" }; - ChannelContext::instance().reset(); - - auto base = std::string("https://ali.as/prefix-and-more/"); - auto& chan = make_channel(base); - std::vector expected_urls = { base + platform, base + "noarch" }; - EXPECT_EQ(chan.urls(), expected_urls); - - ctx.channel_alias = "https://conda.anaconda.org"; - ctx.custom_channels.clear(); - ctx.default_channels = old_default_channels; - ChannelContext::instance().reset(); - } - - TEST(ChannelContext, custom_channels) - { - // ChannelContext builds its custom channels with - // make_simple_channel - auto& ctx = Context::instance(); - ctx.channel_alias = "https://mydomain.com/channels/"; - ctx.custom_channels = { - { "test_channel", "file:///tmp" }, - { "some_channel", "https://conda.mydomain.xyz/" }, - }; - ChannelContext::instance().reset(); - - const auto& ch = ChannelContext::instance().get_channel_alias(); - EXPECT_EQ(ch.scheme(), "https"); - EXPECT_EQ(ch.location(), "mydomain.com/channels"); - EXPECT_EQ(ch.name(), ""); - EXPECT_EQ(ch.canonical_name(), ""); - + TEST_CASE("init") { - std::string value = "test_channel"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "file"); - EXPECT_EQ(c.location(), "/tmp"); - EXPECT_EQ(c.name(), "test_channel"); - EXPECT_EQ(c.canonical_name(), "test_channel"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - std::vector exp_urls({ std::string("file:///tmp/test_channel/") + platform, - std::string("file:///tmp/test_channel/noarch") }); - EXPECT_EQ(c.urls(), exp_urls); + // ChannelContext builds its custom channels with + // make_simple_channel + + const auto& ch = ChannelContext::instance().get_channel_alias(); + CHECK_EQ(ch.scheme(), "https"); + CHECK_EQ(ch.location(), "conda.anaconda.org"); + CHECK_EQ(ch.name(), ""); + CHECK_EQ(ch.canonical_name(), ""); + + const auto& custom = ChannelContext::instance().get_custom_channels(); + + auto it = custom.find("pkgs/main"); + CHECK_NE(it, custom.end()); + CHECK_EQ(it->second.name(), "pkgs/main"); + CHECK_EQ(it->second.location(), "repo.anaconda.com"); + CHECK_EQ(it->second.canonical_name(), "defaults"); + + it = custom.find("pkgs/pro"); + CHECK_NE(it, custom.end()); + CHECK_EQ(it->second.name(), "pkgs/pro"); + CHECK_EQ(it->second.location(), "repo.anaconda.com"); + CHECK_EQ(it->second.canonical_name(), "pkgs/pro"); + + it = custom.find("pkgs/r"); + CHECK_NE(it, custom.end()); + CHECK_EQ(it->second.name(), "pkgs/r"); + CHECK_EQ(it->second.location(), "repo.anaconda.com"); + CHECK_EQ(it->second.canonical_name(), "defaults"); } + TEST_CASE("channel_alias") { - std::string value = "some_channel"; + // ChannelContext builds its custom channels with + // make_simple_channel + auto& ctx = Context::instance(); + ctx.channel_alias = "https://mydomain.com/channels/"; + ChannelContext::instance().reset(); + + const auto& ch = ChannelContext::instance().get_channel_alias(); + CHECK_EQ(ch.scheme(), "https"); + CHECK_EQ(ch.location(), "mydomain.com/channels"); + CHECK_EQ(ch.name(), ""); + CHECK_EQ(ch.canonical_name(), ""); + + const auto& custom = ChannelContext::instance().get_custom_channels(); + + auto it = custom.find("pkgs/main"); + CHECK_NE(it, custom.end()); + CHECK_EQ(it->second.name(), "pkgs/main"); + CHECK_EQ(it->second.location(), "repo.anaconda.com"); + CHECK_EQ(it->second.canonical_name(), "defaults"); + + std::string value = "conda-forge"; const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "conda.mydomain.xyz"); - EXPECT_EQ(c.name(), "some_channel"); - EXPECT_EQ(c.canonical_name(), "some_channel"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - std::vector exp_urls( - { std::string("https://conda.mydomain.xyz/some_channel/") + platform, - std::string("https://conda.mydomain.xyz/some_channel/noarch") } - ); - EXPECT_EQ(c.urls(), exp_urls); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "mydomain.com/channels"); + CHECK_EQ(c.name(), "conda-forge"); + CHECK_EQ(c.canonical_name(), "conda-forge"); + // CHECK_EQ(c.url(), "conda-forge"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + + ctx.channel_alias = "https://conda.anaconda.org"; + ChannelContext::instance().reset(); } - ctx.channel_alias = "https://conda.anaconda.org"; - ctx.custom_channels.clear(); - ChannelContext::instance().reset(); - } + // Regression test for https://github.com/mamba-org/mamba/issues/1671 + TEST_CASE("channel_alias_with_custom_default_channels") + { + auto& ctx = Context::instance(); + auto old_default_channels = ctx.default_channels; + ctx.channel_alias = "https://ali.as/"; + ctx.default_channels = { "prefix" }; + ctx.channels = { "prefix-and-more" }; + ChannelContext::instance().reset(); + + auto base = std::string("https://ali.as/prefix-and-more/"); + auto& chan = make_channel(base); + std::vector expected_urls = { base + platform, base + "noarch" }; + CHECK_EQ(chan.urls(), expected_urls); + + ctx.channel_alias = "https://conda.anaconda.org"; + ctx.custom_channels.clear(); + ctx.default_channels = old_default_channels; + ChannelContext::instance().reset(); + } - TEST(ChannelContext, custom_multichannels) - { - // ChannelContext builds its custom channels with - // make_simple_channel - auto& ctx = Context::instance(); - ctx.custom_multichannels["xtest"] = std::vector{ - "https://mydomain.com/conda-forge", - "https://mydomain.com/bioconda", - "https://mydomain.com/snakepit" - }; - ctx.custom_multichannels["ytest"] = std::vector{ - "https://otherdomain.com/conda-forge", - "https://otherdomain.com/bioconda", - "https://otherdomain.com/snakepit" - }; + TEST_CASE("custom_channels") + { + // ChannelContext builds its custom channels with + // make_simple_channel + auto& ctx = Context::instance(); + ctx.channel_alias = "https://mydomain.com/channels/"; + ctx.custom_channels = { + { "test_channel", "file:///tmp" }, + { "some_channel", "https://conda.mydomain.xyz/" }, + }; + ChannelContext::instance().reset(); + + const auto& ch = ChannelContext::instance().get_channel_alias(); + CHECK_EQ(ch.scheme(), "https"); + CHECK_EQ(ch.location(), "mydomain.com/channels"); + CHECK_EQ(ch.name(), ""); + CHECK_EQ(ch.canonical_name(), ""); + + { + std::string value = "test_channel"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "file"); + CHECK_EQ(c.location(), "/tmp"); + CHECK_EQ(c.name(), "test_channel"); + CHECK_EQ(c.canonical_name(), "test_channel"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + std::vector exp_urls({ std::string("file:///tmp/test_channel/") + platform, + std::string("file:///tmp/test_channel/noarch") }); + CHECK_EQ(c.urls(), exp_urls); + } + + { + std::string value = "some_channel"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "conda.mydomain.xyz"); + CHECK_EQ(c.name(), "some_channel"); + CHECK_EQ(c.canonical_name(), "some_channel"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + std::vector exp_urls( + { std::string("https://conda.mydomain.xyz/some_channel/") + platform, + std::string("https://conda.mydomain.xyz/some_channel/noarch") } + ); + CHECK_EQ(c.urls(), exp_urls); + } + + ctx.channel_alias = "https://conda.anaconda.org"; + ctx.custom_channels.clear(); + ChannelContext::instance().reset(); + } - ChannelContext::instance().reset(); + TEST_CASE("custom_multichannels") + { + // ChannelContext builds its custom channels with + // make_simple_channel + auto& ctx = Context::instance(); + ctx.custom_multichannels["xtest"] = std::vector{ + "https://mydomain.com/conda-forge", + "https://mydomain.com/bioconda", + "https://mydomain.com/snakepit" + }; + ctx.custom_multichannels["ytest"] = std::vector{ + "https://otherdomain.com/conda-forge", + "https://otherdomain.com/bioconda", + "https://otherdomain.com/snakepit" + }; + + ChannelContext::instance().reset(); + + auto x = get_channels({ "xtest" }); + + CHECK_EQ(x.size(), 3); + auto* c1 = x[0]; - auto x = get_channels({ "xtest" }); + std::vector exp_urls( + { std::string("https://mydomain.com/conda-forge/") + platform, + std::string("https://mydomain.com/conda-forge/noarch") } + ); - EXPECT_EQ(x.size(), 3); - auto* c1 = x[0]; + CHECK_EQ(c1->urls(), exp_urls); - std::vector exp_urls({ std::string("https://mydomain.com/conda-forge/") + platform, - std::string("https://mydomain.com/conda-forge/noarch") }); + std::vector exp_urlsy3( + { std::string("https://otherdomain.com/snakepit/") + platform, + std::string("https://otherdomain.com/snakepit/noarch") } + ); - EXPECT_EQ(c1->urls(), exp_urls); + auto y = get_channels({ "ytest" }); + auto* y3 = y[2]; - std::vector exp_urlsy3( - { std::string("https://otherdomain.com/snakepit/") + platform, - std::string("https://otherdomain.com/snakepit/noarch") } - ); + CHECK_EQ(y3->urls(), exp_urlsy3); - auto y = get_channels({ "ytest" }); - auto* y3 = y[2]; + ctx.channel_alias = "https://conda.anaconda.org"; + ctx.custom_multichannels.clear(); + ChannelContext::instance().reset(); + } - EXPECT_EQ(y3->urls(), exp_urlsy3); + TEST_CASE("custom_extended_multichannels") + { + // ChannelContext builds its custom channels with + // make_simple_channel + auto& ctx = Context::instance(); - ctx.channel_alias = "https://conda.anaconda.org"; - ctx.custom_multichannels.clear(); - ChannelContext::instance().reset(); - } + ctx.channel_alias = "https://condaforge.org/channels/"; - TEST(ChannelContext, custom_extended_multichannels) - { - // ChannelContext builds its custom channels with - // make_simple_channel - auto& ctx = Context::instance(); + ctx.custom_channels["xyz"] = "https://mydomain.xyz/xyzchannel"; - ctx.channel_alias = "https://condaforge.org/channels/"; + ctx.custom_multichannels["everything"] = std::vector{ + "conda-forge", + "https://mydomain.com/bioconda", + "xyz" + }; - ctx.custom_channels["xyz"] = "https://mydomain.xyz/xyzchannel"; + ChannelContext::instance().reset(); - ctx.custom_multichannels["everything"] = std::vector{ - "conda-forge", - "https://mydomain.com/bioconda", - "xyz" - }; + auto x = get_channels({ "everything" }); - ChannelContext::instance().reset(); + CHECK_EQ(x.size(), 3); + auto* c1 = x[0]; + auto* c2 = x[1]; + auto* c3 = x[2]; - auto x = get_channels({ "everything" }); + std::vector exp_urls( + { std::string("https://condaforge.org/channels/conda-forge/") + platform, + std::string("https://condaforge.org/channels/conda-forge/noarch") } + ); - EXPECT_EQ(x.size(), 3); - auto* c1 = x[0]; - auto* c2 = x[1]; - auto* c3 = x[2]; + CHECK_EQ(c1->urls(), exp_urls); - std::vector exp_urls( - { std::string("https://condaforge.org/channels/conda-forge/") + platform, - std::string("https://condaforge.org/channels/conda-forge/noarch") } - ); + std::vector exp_urls2( + { std::string("https://mydomain.com/bioconda/") + platform, + std::string("https://mydomain.com/bioconda/noarch") } + ); - EXPECT_EQ(c1->urls(), exp_urls); + CHECK_EQ(c2->urls(), exp_urls2); - std::vector exp_urls2({ std::string("https://mydomain.com/bioconda/") + platform, - std::string("https://mydomain.com/bioconda/noarch") }); + std::vector exp_urls3( + { std::string("https://mydomain.xyz/xyzchannel/xyz/") + platform, + std::string("https://mydomain.xyz/xyzchannel/xyz/noarch") } + ); - EXPECT_EQ(c2->urls(), exp_urls2); + CHECK_EQ(c3->urls(), exp_urls3); - std::vector exp_urls3( - { std::string("https://mydomain.xyz/xyzchannel/xyz/") + platform, - std::string("https://mydomain.xyz/xyzchannel/xyz/noarch") } - ); + ctx.channel_alias = "https://conda.anaconda.org"; + ctx.custom_multichannels.clear(); + ctx.custom_channels.clear(); + ChannelContext::instance().reset(); + } - EXPECT_EQ(c3->urls(), exp_urls3); + TEST_CASE("default_channels") + { + auto& ctx = Context::instance(); + ChannelContext::instance().reset(); - ctx.channel_alias = "https://conda.anaconda.org"; - ctx.custom_multichannels.clear(); - ctx.custom_channels.clear(); - ChannelContext::instance().reset(); - } + auto x = get_channels({ "defaults" }); +#if !defined(_WIN32) + const Channel* c1 = x[0]; + const Channel* c2 = x[1]; + CHECK_EQ(c1->name(), "pkgs/main"); + std::vector exp_urls( + { std::string("https://repo.anaconda.com/pkgs/main/") + platform, + std::string("https://repo.anaconda.com/pkgs/main/noarch") } + ); + CHECK_EQ(c1->urls(), exp_urls); - TEST(ChannelContext, default_channels) - { - auto& ctx = Context::instance(); - ChannelContext::instance().reset(); + CHECK_EQ(c2->name(), "pkgs/r"); + std::vector exp_urls2( + { std::string("https://repo.anaconda.com/pkgs/r/") + platform, + std::string("https://repo.anaconda.com/pkgs/r/noarch") } + ); + CHECK_EQ(c2->urls(), exp_urls2); - auto x = get_channels({ "defaults" }); -#if !defined(_WIN32) - const Channel* c1 = x[0]; - const Channel* c2 = x[1]; - - EXPECT_EQ(c1->name(), "pkgs/main"); - std::vector exp_urls( - { std::string("https://repo.anaconda.com/pkgs/main/") + platform, - std::string("https://repo.anaconda.com/pkgs/main/noarch") } - ); - EXPECT_EQ(c1->urls(), exp_urls); - - EXPECT_EQ(c2->name(), "pkgs/r"); - std::vector exp_urls2( - { std::string("https://repo.anaconda.com/pkgs/r/") + platform, - std::string("https://repo.anaconda.com/pkgs/r/noarch") } - ); - EXPECT_EQ(c2->urls(), exp_urls2); - - EXPECT_EQ(c1->location(), "repo.anaconda.com"); - EXPECT_EQ(c1->scheme(), "https"); + CHECK_EQ(c1->location(), "repo.anaconda.com"); + CHECK_EQ(c1->scheme(), "https"); #endif - ctx.custom_channels.clear(); - ChannelContext::instance().reset(); - } + ctx.custom_channels.clear(); + ChannelContext::instance().reset(); + } - TEST(ChannelContext, custom_default_channels) - { - auto& ctx = Context::instance(); - ctx.default_channels = { "https://mamba.com/test/channel", - "https://mamba.com/stable/channel" }; - ChannelContext::instance().reset(); - - auto x = get_channels({ "defaults" }); - const Channel* c1 = x[0]; - const Channel* c2 = x[1]; - - EXPECT_EQ(c1->name(), "test/channel"); - std::vector exp_urls({ std::string("https://mamba.com/test/channel/") + platform, - std::string("https://mamba.com/test/channel/noarch") }); - EXPECT_EQ(c1->urls(), exp_urls); - std::vector exp_urls2( - { std::string("https://mamba.com/stable/channel/") + platform, - std::string("https://mamba.com/stable/channel/noarch") } - ); - EXPECT_EQ(c2->urls(), exp_urls2); - - EXPECT_EQ(c2->name(), "stable/channel"); - EXPECT_EQ(c2->location(), "mamba.com"); - EXPECT_EQ(c2->scheme(), "https"); - - ctx.custom_channels.clear(); - ChannelContext::instance().reset(); - } + TEST_CASE("custom_default_channels") + { + auto& ctx = Context::instance(); + ctx.default_channels = { "https://mamba.com/test/channel", + "https://mamba.com/stable/channel" }; + ChannelContext::instance().reset(); - TEST(ChannelContext, custom_channels_with_labels) - { - auto& ctx = Context::instance(); - ctx.custom_channels = { - { "test_channel", "https://server.com/private/channels" }, - }; - ChannelContext::instance().reset(); + auto x = get_channels({ "defaults" }); + const Channel* c1 = x[0]; + const Channel* c2 = x[1]; - { - std::string value = "test_channel"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "server.com/private/channels"); - EXPECT_EQ(c.name(), "test_channel"); - EXPECT_EQ(c.canonical_name(), "test_channel"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); + CHECK_EQ(c1->name(), "test/channel"); std::vector exp_urls( - { std::string("https://server.com/private/channels/test_channel/") + platform, - std::string("https://server.com/private/channels/test_channel/noarch") } + { std::string("https://mamba.com/test/channel/") + platform, + std::string("https://mamba.com/test/channel/noarch") } + ); + CHECK_EQ(c1->urls(), exp_urls); + std::vector exp_urls2( + { std::string("https://mamba.com/stable/channel/") + platform, + std::string("https://mamba.com/stable/channel/noarch") } ); - EXPECT_EQ(c.urls(), exp_urls); + CHECK_EQ(c2->urls(), exp_urls2); + + CHECK_EQ(c2->name(), "stable/channel"); + CHECK_EQ(c2->location(), "mamba.com"); + CHECK_EQ(c2->scheme(), "https"); + + ctx.custom_channels.clear(); + ChannelContext::instance().reset(); } + TEST_CASE("custom_channels_with_labels") { - std::string value = "test_channel/mylabel/xyz"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "server.com/private/channels"); - EXPECT_EQ(c.name(), "test_channel/mylabel/xyz"); - EXPECT_EQ(c.canonical_name(), "test_channel/mylabel/xyz"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - std::vector exp_urls( - { std::string("https://server.com/private/channels/test_channel/mylabel/xyz/") - + platform, - std::string("https://server.com/private/channels/test_channel/mylabel/xyz/noarch") } - ); - EXPECT_EQ(c.urls(), exp_urls); + auto& ctx = Context::instance(); + ctx.custom_channels = { + { "test_channel", "https://server.com/private/channels" }, + }; + ChannelContext::instance().reset(); + + { + std::string value = "test_channel"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "server.com/private/channels"); + CHECK_EQ(c.name(), "test_channel"); + CHECK_EQ(c.canonical_name(), "test_channel"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + std::vector exp_urls( + { std::string("https://server.com/private/channels/test_channel/") + platform, + std::string("https://server.com/private/channels/test_channel/noarch") } + ); + CHECK_EQ(c.urls(), exp_urls); + } + + { + std::string value = "test_channel/mylabel/xyz"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "server.com/private/channels"); + CHECK_EQ(c.name(), "test_channel/mylabel/xyz"); + CHECK_EQ(c.canonical_name(), "test_channel/mylabel/xyz"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + std::vector exp_urls( + { std::string("https://server.com/private/channels/test_channel/mylabel/xyz/") + + platform, + std::string("https://server.com/private/channels/test_channel/mylabel/xyz/noarch" + ) } + ); + CHECK_EQ(c.urls(), exp_urls); + } + + ctx.channel_alias = "https://conda.anaconda.org"; + ctx.custom_channels.clear(); + ChannelContext::instance().reset(); } - - ctx.channel_alias = "https://conda.anaconda.org"; - ctx.custom_channels.clear(); - ChannelContext::instance().reset(); } - TEST(Channel, channel_name) + TEST_SUITE("Channel") { - std::string value = "https://repo.mamba.pm/conda-forge"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "repo.mamba.pm"); - EXPECT_EQ(c.name(), "conda-forge"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - } + TEST_CASE("channel_name") + { + std::string value = "https://repo.mamba.pm/conda-forge"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "repo.mamba.pm"); + CHECK_EQ(c.name(), "conda-forge"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + } - TEST(Channel, make_channel) - { - std::string value = "conda-forge"; - const Channel& c = make_channel(value); - EXPECT_EQ(c.scheme(), "https"); - EXPECT_EQ(c.location(), "conda.anaconda.org"); - EXPECT_EQ(c.name(), "conda-forge"); - EXPECT_EQ(c.platforms(), std::vector({ platform, "noarch" })); - - std::string value2 = "https://repo.anaconda.com/pkgs/main[" + platform + "]"; - const Channel& c2 = make_channel(value2); - EXPECT_EQ(c2.scheme(), "https"); - EXPECT_EQ(c2.location(), "repo.anaconda.com"); - EXPECT_EQ(c2.name(), "pkgs/main"); - EXPECT_EQ(c2.platforms(), std::vector({ platform })); - - std::string value3 = "https://conda.anaconda.org/conda-forge[" + platform + "]"; - const Channel& c3 = make_channel(value3); - EXPECT_EQ(c3.scheme(), c.scheme()); - EXPECT_EQ(c3.location(), c.location()); - EXPECT_EQ(c3.name(), c.name()); - EXPECT_EQ(c3.platforms(), std::vector({ platform })); - - std::string value4 = "/home/mamba/test/channel_b"; - const Channel& c4 = make_channel(value4); - EXPECT_EQ(c4.scheme(), "file"); + TEST_CASE("make_channel") + { + std::string value = "conda-forge"; + const Channel& c = make_channel(value); + CHECK_EQ(c.scheme(), "https"); + CHECK_EQ(c.location(), "conda.anaconda.org"); + CHECK_EQ(c.name(), "conda-forge"); + CHECK_EQ(c.platforms(), std::vector({ platform, "noarch" })); + + std::string value2 = "https://repo.anaconda.com/pkgs/main[" + platform + "]"; + const Channel& c2 = make_channel(value2); + CHECK_EQ(c2.scheme(), "https"); + CHECK_EQ(c2.location(), "repo.anaconda.com"); + CHECK_EQ(c2.name(), "pkgs/main"); + CHECK_EQ(c2.platforms(), std::vector({ platform })); + + std::string value3 = "https://conda.anaconda.org/conda-forge[" + platform + "]"; + const Channel& c3 = make_channel(value3); + CHECK_EQ(c3.scheme(), c.scheme()); + CHECK_EQ(c3.location(), c.location()); + CHECK_EQ(c3.name(), c.name()); + CHECK_EQ(c3.platforms(), std::vector({ platform })); + + std::string value4 = "/home/mamba/test/channel_b"; + const Channel& c4 = make_channel(value4); + CHECK_EQ(c4.scheme(), "file"); #ifdef _WIN32 - std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); - EXPECT_EQ(c4.location(), driveletter + ":/home/mamba/test"); + std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); + CHECK_EQ(c4.location(), driveletter + ":/home/mamba/test"); #else - EXPECT_EQ(c4.location(), "/home/mamba/test"); + CHECK_EQ(c4.location(), "/home/mamba/test"); #endif - EXPECT_EQ(c4.name(), "channel_b"); - EXPECT_EQ(c4.platforms(), std::vector({ platform, "noarch" })); + CHECK_EQ(c4.name(), "channel_b"); + CHECK_EQ(c4.platforms(), std::vector({ platform, "noarch" })); - std::string value5 = "/home/mamba/test/channel_b[" + platform + "]"; - const Channel& c5 = make_channel(value5); - EXPECT_EQ(c5.scheme(), "file"); + std::string value5 = "/home/mamba/test/channel_b[" + platform + "]"; + const Channel& c5 = make_channel(value5); + CHECK_EQ(c5.scheme(), "file"); #ifdef _WIN32 - EXPECT_EQ(c5.location(), driveletter + ":/home/mamba/test"); + CHECK_EQ(c5.location(), driveletter + ":/home/mamba/test"); #else - EXPECT_EQ(c5.location(), "/home/mamba/test"); + CHECK_EQ(c5.location(), "/home/mamba/test"); #endif - EXPECT_EQ(c5.name(), "channel_b"); - EXPECT_EQ(c5.platforms(), std::vector({ platform })); - - std::string value6a = "http://localhost:8000/conda-forge[noarch]"; - const Channel& c6a = make_channel(value6a); - EXPECT_EQ( - c6a.urls(false), - std::vector({ "http://localhost:8000/conda-forge/noarch" }) - ); - - std::string value6b = "http://localhost:8000/conda_mirror/conda-forge[noarch]"; - const Channel& c6b = make_channel(value6b); - EXPECT_EQ( - c6b.urls(false), - std::vector({ "http://localhost:8000/conda_mirror/conda-forge/noarch" }) - ); - - std::string value7 = "conda-forge[noarch,arbitrary]"; - const Channel& c7 = make_channel(value7); - EXPECT_EQ(c7.platforms(), std::vector({ "noarch", "arbitrary" })); - } + CHECK_EQ(c5.name(), "channel_b"); + CHECK_EQ(c5.platforms(), std::vector({ platform })); + + std::string value6a = "http://localhost:8000/conda-forge[noarch]"; + const Channel& c6a = make_channel(value6a); + CHECK_EQ( + c6a.urls(false), + std::vector({ "http://localhost:8000/conda-forge/noarch" }) + ); - TEST(Channel, urls) - { - std::string value = "https://conda.anaconda.org/conda-forge[noarch,win-64,arbitrary]"; - const Channel& c = make_channel(value); - EXPECT_EQ( - c.urls(), - std::vector({ "https://conda.anaconda.org/conda-forge/noarch", - "https://conda.anaconda.org/conda-forge/win-64", - "https://conda.anaconda.org/conda-forge/arbitrary" }) - ); - - const Channel& c1 = make_channel("https://conda.anaconda.org/conda-forge"); - EXPECT_EQ( - c1.urls(), - std::vector({ "https://conda.anaconda.org/conda-forge/" + platform, - "https://conda.anaconda.org/conda-forge/noarch" }) - ); - } + std::string value6b = "http://localhost:8000/conda_mirror/conda-forge[noarch]"; + const Channel& c6b = make_channel(value6b); + CHECK_EQ( + c6b.urls(false), + std::vector({ "http://localhost:8000/conda_mirror/conda-forge/noarch" }) + ); - TEST(Channel, add_token) - { - auto& ctx = Context::instance(); - ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{ - AuthenticationType::kCondaToken, - "my-12345-token" - }; - - ChannelBuilder::clear_cache(); - - const auto& chan = make_channel("conda-forge[noarch]"); - EXPECT_EQ(chan.token(), "my-12345-token"); - EXPECT_EQ( - chan.urls(true), - std::vector{ - { "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch" } } - ); - EXPECT_EQ( - chan.urls(false), - std::vector{ { "https://conda.anaconda.org/conda-forge/noarch" } } - ); - } + std::string value7 = "conda-forge[noarch,arbitrary]"; + const Channel& c7 = make_channel(value7); + CHECK_EQ(c7.platforms(), std::vector({ "noarch", "arbitrary" })); + } - TEST(Channel, add_multiple_tokens) - { - auto& ctx = Context::instance(); - ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{ - AuthenticationType::kCondaToken, - "base-token" - }; - ctx.authentication_info()["conda.anaconda.org/conda-forge"] = AuthenticationInfo{ - AuthenticationType::kCondaToken, - "channel-token" - }; - - ChannelBuilder::clear_cache(); - - const auto& chan = make_channel("conda-forge[noarch]"); - EXPECT_EQ(chan.token(), "channel-token"); - } + TEST_CASE("urls") + { + std::string value = "https://conda.anaconda.org/conda-forge[noarch,win-64,arbitrary]"; + const Channel& c = make_channel(value); + CHECK_EQ( + c.urls(), + std::vector({ "https://conda.anaconda.org/conda-forge/noarch", + "https://conda.anaconda.org/conda-forge/win-64", + "https://conda.anaconda.org/conda-forge/arbitrary" }) + ); - TEST(Channel, fix_win_file_path) - { - if (platform == "win-64") + const Channel& c1 = make_channel("https://conda.anaconda.org/conda-forge"); + CHECK_EQ( + c1.urls(), + std::vector({ "https://conda.anaconda.org/conda-forge/" + platform, + "https://conda.anaconda.org/conda-forge/noarch" }) + ); + } + + TEST_CASE("add_token") { - const Channel& c = make_channel("C:\\test\\channel"); - EXPECT_EQ( - c.urls(false), - std::vector({ "file:///C:/test/channel/win-64", - "file:///C:/test/channel/noarch" }) + auto& ctx = Context::instance(); + ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{ + AuthenticationType::kCondaToken, + "my-12345-token" + }; + + ChannelBuilder::clear_cache(); + + const auto& chan = make_channel("conda-forge[noarch]"); + CHECK_EQ(chan.token(), "my-12345-token"); + CHECK_EQ( + chan.urls(true), + std::vector{ + { "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch" } } ); + CHECK_EQ( + chan.urls(false), + std::vector{ { "https://conda.anaconda.org/conda-forge/noarch" } } + ); + } + + TEST_CASE("add_multiple_tokens") + { + auto& ctx = Context::instance(); + ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{ + AuthenticationType::kCondaToken, + "base-token" + }; + ctx.authentication_info()["conda.anaconda.org/conda-forge"] = AuthenticationInfo{ + AuthenticationType::kCondaToken, + "channel-token" + }; + + ChannelBuilder::clear_cache(); + + const auto& chan = make_channel("conda-forge[noarch]"); + CHECK_EQ(chan.token(), "channel-token"); + } + + TEST_CASE("fix_win_file_path") + { + if (platform == "win-64") + { + const Channel& c = make_channel("C:\\test\\channel"); + CHECK_EQ( + c.urls(false), + std::vector({ "file:///C:/test/channel/win-64", + "file:///C:/test/channel/noarch" }) + ); + } + else + { + const Channel& c = make_channel("/test/channel"); + CHECK_EQ( + c.urls(false), + std::vector({ std::string("file:///test/channel/") + platform, + "file:///test/channel/noarch" }) + ); + } } - else + + TEST_CASE("trailing_slash") { - const Channel& c = make_channel("/test/channel"); - EXPECT_EQ( - c.urls(false), - std::vector({ std::string("file:///test/channel/") + platform, - "file:///test/channel/noarch" }) + const Channel& c = make_channel("http://localhost:8000/"); + CHECK_EQ(c.platform_url("win-64", false), "http://localhost:8000/win-64"); + CHECK_EQ(c.base_url(), "http://localhost:8000"); + std::vector expected_urls({ std::string("http://localhost:8000/") + platform, + "http://localhost:8000/noarch" }); + CHECK_EQ(c.urls(true), expected_urls); + const Channel& c4 = make_channel("http://localhost:8000"); + CHECK_EQ(c4.platform_url("linux-64", false), "http://localhost:8000/linux-64"); + const Channel& c2 = make_channel("http://user:test@localhost:8000/"); + CHECK_EQ(c2.platform_url("win-64", false), "http://localhost:8000/win-64"); + CHECK_EQ(c2.platform_url("win-64", true), "http://user:test@localhost:8000/win-64"); + const Channel& c3 = make_channel( + "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012" + ); + CHECK_EQ(c3.platform_url("win-64", false), "https://localhost:8000/win-64"); + CHECK_EQ( + c3.platform_url("win-64", true), + "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/win-64" ); + + std::vector expected_urls2( + { std::string("https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/") + + platform, + "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/noarch" } + ); + + CHECK_EQ(c3.urls(true), expected_urls2); } - } - TEST(Channel, trailing_slash) - { - const Channel& c = make_channel("http://localhost:8000/"); - EXPECT_EQ(c.platform_url("win-64", false), "http://localhost:8000/win-64"); - EXPECT_EQ(c.base_url(), "http://localhost:8000"); - std::vector expected_urls({ std::string("http://localhost:8000/") + platform, - "http://localhost:8000/noarch" }); - EXPECT_EQ(c.urls(true), expected_urls); - const Channel& c4 = make_channel("http://localhost:8000"); - EXPECT_EQ(c4.platform_url("linux-64", false), "http://localhost:8000/linux-64"); - const Channel& c2 = make_channel("http://user:test@localhost:8000/"); - EXPECT_EQ(c2.platform_url("win-64", false), "http://localhost:8000/win-64"); - EXPECT_EQ(c2.platform_url("win-64", true), "http://user:test@localhost:8000/win-64"); - const Channel& c3 = make_channel( - "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012" - ); - EXPECT_EQ(c3.platform_url("win-64", false), "https://localhost:8000/win-64"); - EXPECT_EQ( - c3.platform_url("win-64", true), - "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/win-64" - ); - - std::vector expected_urls2( - { std::string("https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/") - + platform, - "https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/noarch" } - ); - - EXPECT_EQ(c3.urls(true), expected_urls2); - } + TEST_CASE("load_tokens") + { + // touch(env::home_directory() / ".continuum" / "anaconda") + // auto& ctx = Context::instance(); + // ctx.channel_tokens["https://conda.anaconda.org"] = "my-12345-token"; - TEST(Channel, load_tokens) - { - // touch(env::home_directory() / ".continuum" / "anaconda") - // auto& ctx = Context::instance(); - // ctx.channel_tokens["https://conda.anaconda.org"] = "my-12345-token"; + // Channel::clear_cache(); - // Channel::clear_cache(); + // const auto& chan = make_channel("conda-forge"); + // CHECK_EQ(chan.token(), "my-12345-token"); + // CHECK_EQ(chan.url(true), + // "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch"); + // CHECK_EQ(chan.url(false), "https://conda.anaconda.org/conda-forge/noarch"); + } - // const auto& chan = make_channel("conda-forge"); - // EXPECT_EQ(chan.token(), "my-12345-token"); - // EXPECT_EQ(chan.url(true), - // "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch"); - // EXPECT_EQ(chan.url(false), "https://conda.anaconda.org/conda-forge/noarch"); - } + TEST_CASE("split_platform") + { + std::string platform_found, cleaned_url; + split_platform( + { "noarch", "linux-64" }, + "https://mamba.com/linux-64/package.tar.bz2", + cleaned_url, + platform_found + ); - TEST(Channel, split_platform) - { - std::string platform_found, cleaned_url; - split_platform( - { "noarch", "linux-64" }, - "https://mamba.com/linux-64/package.tar.bz2", - cleaned_url, - platform_found - ); - - EXPECT_EQ(platform_found, "linux-64"); - EXPECT_EQ(cleaned_url, "https://mamba.com/package.tar.bz2"); - - split_platform( - { "noarch", "linux-64" }, - "https://mamba.com/linux-64/noarch-package.tar.bz2", - cleaned_url, - platform_found - ); - EXPECT_EQ(platform_found, "linux-64"); - EXPECT_EQ(cleaned_url, "https://mamba.com/noarch-package.tar.bz2"); - - split_platform( - { "linux-64", "osx-arm64", "noarch" }, - "https://mamba.com/noarch/kernel_linux-64-package.tar.bz2", - cleaned_url, - platform_found - ); - EXPECT_EQ(platform_found, "noarch"); - EXPECT_EQ(cleaned_url, "https://mamba.com/kernel_linux-64-package.tar.bz2"); - - split_platform({ "noarch", "linux-64" }, "https://mamba.com/linux-64", cleaned_url, platform_found); - - EXPECT_EQ(platform_found, "linux-64"); - EXPECT_EQ(cleaned_url, "https://mamba.com"); - - split_platform({ "noarch", "linux-64" }, "https://mamba.com/noarch", cleaned_url, platform_found); - - EXPECT_EQ(platform_found, "noarch"); - EXPECT_EQ(cleaned_url, "https://mamba.com"); + CHECK_EQ(platform_found, "linux-64"); + CHECK_EQ(cleaned_url, "https://mamba.com/package.tar.bz2"); + + split_platform( + { "noarch", "linux-64" }, + "https://mamba.com/linux-64/noarch-package.tar.bz2", + cleaned_url, + platform_found + ); + CHECK_EQ(platform_found, "linux-64"); + CHECK_EQ(cleaned_url, "https://mamba.com/noarch-package.tar.bz2"); + + split_platform( + { "linux-64", "osx-arm64", "noarch" }, + "https://mamba.com/noarch/kernel_linux-64-package.tar.bz2", + cleaned_url, + platform_found + ); + CHECK_EQ(platform_found, "noarch"); + CHECK_EQ(cleaned_url, "https://mamba.com/kernel_linux-64-package.tar.bz2"); + + split_platform( + { "noarch", "linux-64" }, + "https://mamba.com/linux-64", + cleaned_url, + platform_found + ); + + CHECK_EQ(platform_found, "linux-64"); + CHECK_EQ(cleaned_url, "https://mamba.com"); + + split_platform( + { "noarch", "linux-64" }, + "https://mamba.com/noarch", + cleaned_url, + platform_found + ); + + CHECK_EQ(platform_found, "noarch"); + CHECK_EQ(cleaned_url, "https://mamba.com"); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_configuration.cpp b/libmamba/tests/src/core/test_configuration.cpp index ec6256fd1e..6c202f26e6 100644 --- a/libmamba/tests/src/core/test_configuration.cpp +++ b/libmamba/tests/src/core/test_configuration.cpp @@ -4,13 +4,13 @@ // // The full license is in the file LICENSE, distributed with this software. -#include - #include "mamba/api/configuration.hpp" #include "mamba/core/context.hpp" #include "mamba/core/util.hpp" #include "mamba/core/util_string.hpp" +#include "doctest/doctest.h" + #include "test_data.hpp" namespace mamba @@ -28,15 +28,26 @@ namespace mamba namespace testing { - class Configuration : public ::testing::Test + class Configuration { public: Configuration() { + m_channel_alias_bu = ctx.channel_alias; + m_ssl_verify = ctx.ssl_verify; + m_proxy_servers = ctx.proxy_servers; mamba::Configuration::instance().at("show_banner").set_default_value(false); } + ~Configuration() + { + config.reset_configurables(); + ctx.channel_alias = m_channel_alias_bu; + ctx.ssl_verify = m_ssl_verify; + ctx.proxy_servers = m_proxy_servers; + } + protected: void load_test_config(std::string rc) @@ -91,682 +102,695 @@ namespace mamba mamba::Configuration& config = mamba::Configuration::instance(); mamba::Context& ctx = mamba::Context::instance(); + + private: + + // Variables to restore the original COntext state and avoid + // side effect across the tests. A better solution would be to + // save and restore the whole context (that requires refactoring + // of the Context class) + std::string m_channel_alias_bu; + std::string m_ssl_verify; + std::map m_proxy_servers; }; - TEST_F(Configuration, target_prefix_options) + TEST_SUITE("Configuration") { - EXPECT_EQ(!MAMBA_ALLOW_EXISTING_PREFIX, 0); - EXPECT_EQ(!MAMBA_ALLOW_MISSING_PREFIX, 0); - EXPECT_EQ(!MAMBA_ALLOW_NOT_ENV_PREFIX, 0); - EXPECT_EQ(!MAMBA_EXPECT_EXISTING_PREFIX, 0); - - EXPECT_EQ(!MAMBA_ALLOW_EXISTING_PREFIX, MAMBA_NOT_ALLOW_EXISTING_PREFIX); + TEST_CASE_FIXTURE(Configuration, "target_prefix_options") + { + CHECK_EQ(!MAMBA_ALLOW_EXISTING_PREFIX, 0); + CHECK_EQ(!MAMBA_ALLOW_MISSING_PREFIX, 0); + CHECK_EQ(!MAMBA_ALLOW_NOT_ENV_PREFIX, 0); + CHECK_EQ(!MAMBA_EXPECT_EXISTING_PREFIX, 0); - EXPECT_EQ( - MAMBA_NOT_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX - | MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX, - 0 - ); - } + CHECK_EQ(!MAMBA_ALLOW_EXISTING_PREFIX, MAMBA_NOT_ALLOW_EXISTING_PREFIX); - TEST_F(Configuration, load_rc_file) - { - std::string rc = unindent(R"( - channels: - - test1)"); - load_test_config(rc); - const auto src = env::shrink_user(tempfile_ptr->path()); - EXPECT_EQ(config.sources().size(), 1); - EXPECT_EQ(config.valid_sources().size(), 1); - EXPECT_EQ(config.dump(), "channels:\n - test1"); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "channels:\n - test1 # '" + src.string() + "'" - ); + CHECK_EQ( + MAMBA_NOT_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX + | MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX, + 0 + ); + } - // ill-formed config file - rc = unindent(R"( - channels: - - test10 - - https://repo.mamba.pm/conda-forge)"); + TEST_CASE_FIXTURE(Configuration, "load_rc_file") + { + std::string rc = unindent(R"( + channels: + - test1)"); + load_test_config(rc); + const auto src = env::shrink_user(tempfile_ptr->path()); + CHECK_EQ(config.sources().size(), 1); + CHECK_EQ(config.valid_sources().size(), 1); + CHECK_EQ(config.dump(), "channels:\n - test1"); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "channels:\n - test1 # '" + src.string() + "'" + ); - load_test_config(rc); + // ill-formed config file + rc = unindent(R"( + channels: + - test10 + - https://repo.mamba.pm/conda-forge)"); - EXPECT_EQ(config.sources().size(), 1); - EXPECT_EQ(config.valid_sources().size(), 0); - EXPECT_EQ(config.dump(), ""); - EXPECT_EQ(config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), ""); - } + load_test_config(rc); - TEST_F(Configuration, load_rc_files) - { - std::string rc1 = unindent(R"( - channels: - - test1 - ssl_verify: false)"); + CHECK_EQ(config.sources().size(), 1); + CHECK_EQ(config.valid_sources().size(), 0); + CHECK_EQ(config.dump(), ""); + CHECK_EQ(config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), ""); + } - std::string rc2 = unindent(R"( - channels: - - test2 - - test1)"); + TEST_CASE_FIXTURE(Configuration, "load_rc_files") + { + std::string rc1 = unindent(R"( + channels: + - test1 + ssl_verify: false)"); + + std::string rc2 = unindent(R"( + channels: + - test2 + - test1)"); + + std::vector rcs = { rc1, rc2 }; + load_test_config(rcs); + + REQUIRE_EQ(config.sources().size(), 2); + REQUIRE_EQ(config.valid_sources().size(), 2); + + std::string src1 = shrink_source(0); + std::string src2 = shrink_source(1); + CHECK_EQ(config.dump(), unindent(R"( + channels: + - test1 + - test2 + ssl_verify: )")); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + channels: + - test1 # ')" + + src1 + R"(' + - test2 # ')" + + src2 + R"(' + ssl_verify: # ')" + + src1 + "'") + .c_str()) + ); - std::vector rcs = { rc1, rc2 }; - load_test_config(rcs); + // ill-formed key + std::string rc3 = unindent(R"( + channels: + - test3 + override_channels_enabled: + - false)"); + rcs.push_back(rc3); + load_test_config(rcs); + + REQUIRE_EQ(config.sources().size(), 3); + REQUIRE_EQ(config.valid_sources().size(), 3); + + // tmp files changed + src1 = shrink_source(0); + src2 = shrink_source(1); + std::string src3 = shrink_source(2); + CHECK_EQ(config.dump(), unindent(R"( + channels: + - test1 + - test2 + - test3 + ssl_verify: )")); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + channels: + - test1 # ')" + + src1 + R"(' + - test2 # ')" + + src2 + R"(' + - test3 # ')" + + src3 + R"(' + ssl_verify: # ')" + + src1 + "'") + .c_str()) + ); - ASSERT_EQ(config.sources().size(), 2); - ASSERT_EQ(config.valid_sources().size(), 2); + // ill-formed file + std::string rc4 = unindent(R"( + channels: + - test3 + - test4)"); + rcs.push_back(rc4); + load_test_config(rcs); + + REQUIRE_EQ(config.sources().size(), 4); + REQUIRE_EQ(config.valid_sources().size(), 3); + + // tmp files changed + src1 = shrink_source(0); + src2 = shrink_source(1); + src3 = shrink_source(2); + CHECK_EQ(config.dump(), unindent(R"( + channels: + - test1 + - test2 + - test3 + ssl_verify: )")); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + channels: + - test1 # ')" + + src1 + R"(' + - test2 # ')" + + src2 + R"(' + - test3 # ')" + + src3 + R"(' + ssl_verify: # ')" + + src1 + "'") + .c_str()) + ); + } - std::string src1 = shrink_source(0); - std::string src2 = shrink_source(1); - EXPECT_EQ(config.dump(), unindent(R"( + TEST_CASE_FIXTURE(Configuration, "dump") + { + std::string rc1 = unindent(R"( + channels: + - test1 + - https://repo.mamba.pm/conda-forge + override_channels_enabled: true + allow_softlinks: true + test_complex_structure: + - foo: bar + - bar: baz)"); + + std::string rc2 = unindent(R"( + channels: + - test10 + override_channels_enabled: false)"); + + load_test_config({ rc1, rc2 }); + + REQUIRE_EQ(config.sources().size(), 2); + REQUIRE_EQ(config.valid_sources().size(), 2); + std::string src1 = shrink_source(0); + std::string src2 = env::shrink_user(shrink_source(1)).string(); + + std::string res = config.dump(); + // Unexpected/handled keys are dropped + CHECK_EQ(res, unindent(R"( channels: - test1 - - test2 - ssl_verify: )")); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( + - https://repo.mamba.pm/conda-forge + - test10 + override_channels_enabled: true + allow_softlinks: true)")); + + res = config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS); + CHECK_EQ( + res, + unindent((R"( channels: - test1 # ')" - + src1 + R"(' - - test2 # ')" - + src2 + R"(' - ssl_verify: # ')" - + src1 + "'") - .c_str()) - ); + + src1 + R"(' + - https://repo.mamba.pm/conda-forge # ')" + + src1 + R"(' + - test10 # ')" + + src2 + R"(' + override_channels_enabled: true # ')" + + src1 + "' > '" + src2 + R"(' + allow_softlinks: true # ')" + + src1 + "'") + .c_str()) + ); + } - // ill-formed key - std::string rc3 = unindent(R"( - channels: - - test3 - override_channels_enabled: - - false)"); - rcs.push_back(rc3); - load_test_config(rcs); - - ASSERT_EQ(config.sources().size(), 3); - ASSERT_EQ(config.valid_sources().size(), 3); - - // tmp files changed - src1 = shrink_source(0); - src2 = shrink_source(1); - std::string src3 = shrink_source(2); - EXPECT_EQ(config.dump(), unindent(R"( - channels: - - test1 - - test2 - - test3 - ssl_verify: )")); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( + TEST_CASE_FIXTURE(Configuration, "channels") + { + std::string rc1 = unindent(R"( + channels: + - c11 + - c12)"); + std::string rc2 = unindent(R"( + channels: + - c21 + - c12)"); + std::string rc3 = unindent(R"( + channels: + - c11 + - c32 + - c21)"); + load_test_config({ rc1, rc2, rc3 }); + + CHECK_EQ(config.dump(), unindent(R"( channels: - - test1 # ')" - + src1 + R"(' - - test2 # ')" - + src2 + R"(' - - test3 # ')" - + src3 + R"(' - ssl_verify: # ')" - + src1 + "'") - .c_str()) - ); + - c11 + - c12 + - c21 + - c32)")); - // ill-formed file - std::string rc4 = unindent(R"( - channels: - - test3 - - test4)"); - rcs.push_back(rc4); - load_test_config(rcs); - - ASSERT_EQ(config.sources().size(), 4); - ASSERT_EQ(config.valid_sources().size(), 3); - - // tmp files changed - src1 = shrink_source(0); - src2 = shrink_source(1); - src3 = shrink_source(2); - EXPECT_EQ(config.dump(), unindent(R"( + env::set("CONDA_CHANNELS", "c90,c101"); + load_test_config(rc1); + + CHECK_EQ(config.dump(), unindent(R"( channels: - - test1 - - test2 - - test3 - ssl_verify: )")); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( + - c90 + - c101 + - c11 + - c12)")); + + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( channels: - - test1 # ')" - + src1 + R"(' - - test2 # ')" - + src2 + R"(' - - test3 # ')" - + src3 + R"(' - ssl_verify: # ')" - + src1 + "'") - .c_str()) - ); - } - - TEST_F(Configuration, dump) - { - std::string rc1 = unindent(R"( - channels: - - test1 - - https://repo.mamba.pm/conda-forge - override_channels_enabled: true - allow_softlinks: true - test_complex_structure: - - foo: bar - - bar: baz)"); - - std::string rc2 = unindent(R"( - channels: - - test10 - override_channels_enabled: false)"); - - load_test_config({ rc1, rc2 }); - - ASSERT_EQ(config.sources().size(), 2); - ASSERT_EQ(config.valid_sources().size(), 2); - std::string src1 = shrink_source(0); - std::string src2 = env::shrink_user(shrink_source(1)).string(); - - std::string res = config.dump(); - // Unexpected/handled keys are dropped - EXPECT_EQ(res, unindent(R"( - channels: - - test1 - - https://repo.mamba.pm/conda-forge - - test10 - override_channels_enabled: true - allow_softlinks: true)")); - - res = config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS); - EXPECT_EQ( - res, - unindent((R"( - channels: - - test1 # ')" - + src1 + R"(' - - https://repo.mamba.pm/conda-forge # ')" - + src1 + R"(' - - test10 # ')" - + src2 + R"(' - override_channels_enabled: true # ')" - + src1 + "' > '" + src2 + R"(' - allow_softlinks: true # ')" - + src1 + "'") - .c_str()) - ); - } - - TEST_F(Configuration, channels) - { - std::string rc1 = unindent(R"( - channels: - - c11 - - c12)"); - std::string rc2 = unindent(R"( - channels: - - c21 - - c12)"); - std::string rc3 = unindent(R"( - channels: - - c11 - - c32 - - c21)"); - load_test_config({ rc1, rc2, rc3 }); - - EXPECT_EQ(config.dump(), unindent(R"( - channels: - - c11 - - c12 - - c21 - - c32)")); - - env::set("CONDA_CHANNELS", "c90,c101"); - load_test_config(rc1); - - EXPECT_EQ(config.dump(), unindent(R"( - channels: - - c90 - - c101 - - c11 - - c12)")); - - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - channels: - - c90 # 'CONDA_CHANNELS' - - c101 # 'CONDA_CHANNELS' - - c11 # ')" - + src1 + R"(' - - c12 # ')" - + src1 + "'") - .c_str()) - ); + - c90 # 'CONDA_CHANNELS' + - c101 # 'CONDA_CHANNELS' + - c11 # ')" + + src1 + R"(' + - c12 # ')" + + src1 + "'") + .c_str()) + ); - config.at("channels").set_yaml_value("https://my.channel, https://my2.channel").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - channels: - - https://my.channel # 'API' - - https://my2.channel # 'API' - - c90 # 'CONDA_CHANNELS' - - c101 # 'CONDA_CHANNELS' - - c11 # ')" - + src1 + R"(' - - c12 # ')" - + src1 + "'") - .c_str()) - ); - EXPECT_EQ(ctx.channels, config.at("channels").value>()); + config.at("channels").set_yaml_value("https://my.channel, https://my2.channel").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + channels: + - https://my.channel # 'API' + - https://my2.channel # 'API' + - c90 # 'CONDA_CHANNELS' + - c101 # 'CONDA_CHANNELS' + - c11 # ')" + + src1 + R"(' + - c12 # ')" + + src1 + "'") + .c_str()) + ); + CHECK_EQ(ctx.channels, config.at("channels").value>()); - env::unset("CONDA_CHANNELS"); - } + env::unset("CONDA_CHANNELS"); + } - TEST_F(Configuration, default_channels) - { - std::string rc1 = unindent(R"( - default_channels: - - c11 - - c12)"); - std::string rc2 = unindent(R"( - default_channels: - - c21 - - c12)"); - std::string rc3 = unindent(R"( - default_channels: - - c11 - - c32 - - c21)"); - load_test_config({ rc1, rc2, rc3 }); - - EXPECT_EQ(config.dump(), unindent(R"( - default_channels: - - c11 - - c12 - - c21 - - c32)")); - - env::set("MAMBA_DEFAULT_CHANNELS", "c91,c100"); - load_test_config(rc1); - - EXPECT_EQ(config.dump(), unindent(R"( - default_channels: - - c91 - - c100 - - c11 - - c12)")); - - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - default_channels: - - c91 # 'MAMBA_DEFAULT_CHANNELS' - - c100 # 'MAMBA_DEFAULT_CHANNELS' - - c11 # ')" - + src1 + R"(' - - c12 # ')" - + src1 + "'") - .c_str()) - ); + TEST_CASE_FIXTURE(Configuration, "default_channels") + { + std::string rc1 = unindent(R"( + default_channels: + - c11 + - c12)"); + std::string rc2 = unindent(R"( + default_channels: + - c21 + - c12)"); + std::string rc3 = unindent(R"( + default_channels: + - c11 + - c32 + - c21)"); + load_test_config({ rc1, rc2, rc3 }); + + CHECK_EQ(config.dump(), unindent(R"( + default_channels: + - c11 + - c12 + - c21 + - c32)")); + + env::set("MAMBA_DEFAULT_CHANNELS", "c91,c100"); + load_test_config(rc1); + + CHECK_EQ(config.dump(), unindent(R"( + default_channels: + - c91 + - c100 + - c11 + - c12)")); + + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + default_channels: + - c91 # 'MAMBA_DEFAULT_CHANNELS' + - c100 # 'MAMBA_DEFAULT_CHANNELS' + - c11 # ')" + + src1 + R"(' + - c12 # ')" + + src1 + "'") + .c_str()) + ); - config.at("default_channels") - .set_yaml_value("https://my.channel, https://my2.channel") - .compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - default_channels: - - https://my.channel # 'API' - - https://my2.channel # 'API' - - c91 # 'MAMBA_DEFAULT_CHANNELS' - - c100 # 'MAMBA_DEFAULT_CHANNELS' - - c11 # ')" - + src1 + R"(' - - c12 # ')" - + src1 + "'") - .c_str()) - ); - EXPECT_EQ( - ctx.default_channels, - config.at("default_channels").value>() - ); + config.at("default_channels") + .set_yaml_value("https://my.channel, https://my2.channel") + .compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + default_channels: + - https://my.channel # 'API' + - https://my2.channel # 'API' + - c91 # 'MAMBA_DEFAULT_CHANNELS' + - c100 # 'MAMBA_DEFAULT_CHANNELS' + - c11 # ')" + + src1 + R"(' + - c12 # ')" + + src1 + "'") + .c_str()) + ); + CHECK_EQ( + ctx.default_channels, + config.at("default_channels").value>() + ); - env::unset("MAMBA_DEFAULT_CHANNELS"); - } + env::unset("MAMBA_DEFAULT_CHANNELS"); + } - TEST_F(Configuration, channel_alias) - { - std::string rc1 = "channel_alias: http://repo.mamba.pm/"; - std::string rc2 = "channel_alias: https://conda.anaconda.org/"; + TEST_CASE_FIXTURE(Configuration, "channel_alias") + { + std::string rc1 = "channel_alias: http://repo.mamba.pm/"; + std::string rc2 = "channel_alias: https://conda.anaconda.org/"; - load_test_config({ rc1, rc2 }); - EXPECT_EQ(config.dump(), "channel_alias: http://repo.mamba.pm/"); + load_test_config({ rc1, rc2 }); + CHECK_EQ(config.dump(), "channel_alias: http://repo.mamba.pm/"); - load_test_config({ rc2, rc1 }); - EXPECT_EQ(config.dump(), "channel_alias: https://conda.anaconda.org/"); + load_test_config({ rc2, rc1 }); + CHECK_EQ(config.dump(), "channel_alias: https://conda.anaconda.org/"); - env::set("MAMBA_CHANNEL_ALIAS", "https://foo.bar"); - load_test_config(rc1); + env::set("MAMBA_CHANNEL_ALIAS", "https://foo.bar"); + load_test_config(rc1); - EXPECT_EQ(config.dump(), "channel_alias: https://foo.bar"); + CHECK_EQ(config.dump(), "channel_alias: https://foo.bar"); - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "channel_alias: https://foo.bar # 'MAMBA_CHANNEL_ALIAS' > '" + src1 + "'" - ); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "channel_alias: https://foo.bar # 'MAMBA_CHANNEL_ALIAS' > '" + src1 + "'" + ); - config.at("channel_alias").set_yaml_value("https://my.channel").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "channel_alias: https://my.channel # 'API' > 'MAMBA_CHANNEL_ALIAS' > '" + src1 + "'" - ); - EXPECT_EQ(ctx.channel_alias, config.at("channel_alias").value()); + config.at("channel_alias").set_yaml_value("https://my.channel").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "channel_alias: https://my.channel # 'API' > 'MAMBA_CHANNEL_ALIAS' > '" + src1 + "'" + ); + CHECK_EQ(ctx.channel_alias, config.at("channel_alias").value()); - env::unset("MAMBA_CHANNEL_ALIAS"); - } + env::unset("MAMBA_CHANNEL_ALIAS"); + } - TEST_F(Configuration, pkgs_dirs) - { - std::string cache1 = (env::home_directory() / "foo").string(); - std::string cache2 = (env::home_directory() / "bar").string(); - - std::string rc1 = "pkgs_dirs:\n - " + cache1; - std::string rc2 = "pkgs_dirs:\n - " + cache2; - - load_test_config({ rc1, rc2 }); - EXPECT_EQ(config.dump(), "pkgs_dirs:\n - " + cache1 + "\n - " + cache2); - - load_test_config({ rc2, rc1 }); - EXPECT_EQ(config.dump(), "pkgs_dirs:\n - " + cache2 + "\n - " + cache1); - - std::string cache3 = (env::home_directory() / "baz").string(); - env::set("CONDA_PKGS_DIRS", cache3); - load_test_config(rc1); - EXPECT_EQ(config.dump(), "pkgs_dirs:\n - " + cache3 + "\n - " + cache1); - - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - pkgs_dirs: - - )" - + cache3 + R"( # 'CONDA_PKGS_DIRS' - - )" - + cache1 + " # '" + src1 + "'") - .c_str()) - ); + TEST_CASE_FIXTURE(Configuration, "pkgs_dirs") + { + std::string cache1 = (env::home_directory() / "foo").string(); + std::string cache2 = (env::home_directory() / "bar").string(); + + std::string rc1 = "pkgs_dirs:\n - " + cache1; + std::string rc2 = "pkgs_dirs:\n - " + cache2; + + load_test_config({ rc1, rc2 }); + CHECK_EQ(config.dump(), "pkgs_dirs:\n - " + cache1 + "\n - " + cache2); + + load_test_config({ rc2, rc1 }); + CHECK_EQ(config.dump(), "pkgs_dirs:\n - " + cache2 + "\n - " + cache1); + + std::string cache3 = (env::home_directory() / "baz").string(); + env::set("CONDA_PKGS_DIRS", cache3); + load_test_config(rc1); + CHECK_EQ(config.dump(), "pkgs_dirs:\n - " + cache3 + "\n - " + cache1); + + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + pkgs_dirs: + - )" + + cache3 + R"( # 'CONDA_PKGS_DIRS' + - )" + + cache1 + " # '" + src1 + "'") + .c_str()) + ); - env::unset("CONDA_PKGS_DIRS"); + env::unset("CONDA_PKGS_DIRS"); - std::string empty_rc = ""; - std::string root_prefix_str = (env::home_directory() / "any_prefix").string(); - env::set("MAMBA_ROOT_PREFIX", root_prefix_str); - load_test_config(empty_rc); + std::string empty_rc = ""; + std::string root_prefix_str = (env::home_directory() / "any_prefix").string(); + env::set("MAMBA_ROOT_PREFIX", root_prefix_str); + load_test_config(empty_rc); #ifdef _WIN32 - std::string extra_cache = "\n - " - + (fs::u8path(env::get("APPDATA").value_or("")) / ".mamba" - / "pkgs") - .string() - + " # 'fallback'"; + std::string extra_cache = "\n - " + + (fs::u8path(env::get("APPDATA").value_or("")) / ".mamba" + / "pkgs") + .string() + + " # 'fallback'"; #else - std::string extra_cache = ""; + std::string extra_cache = ""; #endif - EXPECT_EQ( - config.dump( - MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS | MAMBA_SHOW_ALL_CONFIGS, - { "pkgs_dirs" } - ), - unindent((R"( - pkgs_dirs: - - )" - + (fs::u8path(root_prefix_str) / "pkgs").string() + R"( # 'fallback' - - )" - + (env::home_directory() / ".mamba" / "pkgs").string() - + R"( # 'fallback')" + extra_cache) - .c_str()) - ); - EXPECT_EQ(ctx.pkgs_dirs, config.at("pkgs_dirs").value>()); - - std::string cache4 = (env::home_directory() / "babaz").string(); - env::set("CONDA_PKGS_DIRS", cache4); - load_test_config(empty_rc); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - pkgs_dirs: - - )" - + cache4 + " # 'CONDA_PKGS_DIRS'") - .c_str()) - ); + CHECK_EQ( + config.dump( + MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS | MAMBA_SHOW_ALL_CONFIGS, + { "pkgs_dirs" } + ), + unindent((R"( + pkgs_dirs: + - )" + + (fs::u8path(root_prefix_str) / "pkgs").string() + R"( # 'fallback' + - )" + + (env::home_directory() / ".mamba" / "pkgs").string() + + R"( # 'fallback')" + extra_cache) + .c_str()) + ); + CHECK_EQ(ctx.pkgs_dirs, config.at("pkgs_dirs").value>()); + + std::string cache4 = (env::home_directory() / "babaz").string(); + env::set("CONDA_PKGS_DIRS", cache4); + load_test_config(empty_rc); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + pkgs_dirs: + - )" + + cache4 + " # 'CONDA_PKGS_DIRS'") + .c_str()) + ); - env::unset("CONDA_PKGS_DIRS"); - env::unset("MAMBA_ROOT_PREFIX"); - config.clear_values(); - } + env::unset("CONDA_PKGS_DIRS"); + env::unset("MAMBA_ROOT_PREFIX"); + config.clear_values(); + } - TEST_F(Configuration, ssl_verify) - { - // Default empty string value - ctx.ssl_verify = ""; - std::string rc = ""; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: true"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: "; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: 1"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: 10"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, "10"); - - rc = "ssl_verify: false"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: "; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: 0"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, ""); - - rc = "ssl_verify: /foo/bar/baz"; - load_test_config(rc); - EXPECT_EQ(ctx.ssl_verify, "/foo/bar/baz"); - - std::string rc1 = "ssl_verify: true"; - std::string rc2 = "ssl_verify: false"; - load_test_config({ rc1, rc2 }); - EXPECT_EQ(config.at("ssl_verify").value(), ""); - EXPECT_EQ(ctx.ssl_verify, ""); - - load_test_config({ rc2, rc1 }); - EXPECT_EQ(config.at("ssl_verify").value(), ""); - EXPECT_EQ(ctx.ssl_verify, ""); - - env::set("MAMBA_SSL_VERIFY", "/env/bar/baz"); - load_test_config(rc1); - - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "ssl_verify: /env/bar/baz # 'MAMBA_SSL_VERIFY' > '" + src1 + "'" - ); + TEST_CASE_FIXTURE(Configuration, "ssl_verify") + { + // Default empty string value + ctx.ssl_verify = ""; + std::string rc = ""; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: true"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: "; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: 1"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: 10"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, "10"); + + rc = "ssl_verify: false"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: "; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: 0"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, ""); + + rc = "ssl_verify: /foo/bar/baz"; + load_test_config(rc); + CHECK_EQ(ctx.ssl_verify, "/foo/bar/baz"); + + std::string rc1 = "ssl_verify: true"; + std::string rc2 = "ssl_verify: false"; + load_test_config({ rc1, rc2 }); + CHECK_EQ(config.at("ssl_verify").value(), ""); + CHECK_EQ(ctx.ssl_verify, ""); + + load_test_config({ rc2, rc1 }); + CHECK_EQ(config.at("ssl_verify").value(), ""); + CHECK_EQ(ctx.ssl_verify, ""); + + env::set("MAMBA_SSL_VERIFY", "/env/bar/baz"); + load_test_config(rc1); + + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "ssl_verify: /env/bar/baz # 'MAMBA_SSL_VERIFY' > '" + src1 + "'" + ); - config.at("ssl_verify").set_yaml_value("/new/test").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "ssl_verify: /new/test # 'API' > 'MAMBA_SSL_VERIFY' > '" + src1 + "'" - ); + config.at("ssl_verify").set_yaml_value("/new/test").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "ssl_verify: /new/test # 'API' > 'MAMBA_SSL_VERIFY' > '" + src1 + "'" + ); - env::unset("MAMBA_SSL_VERIFY"); - } + env::unset("MAMBA_SSL_VERIFY"); + } #undef EXPECT_CA_EQUAL - TEST_F(Configuration, cacert_path) - { - std::string rc = "ssl_verify: /foo/bar/baz\ncacert_path: /other/foo/bar/baz"; - load_test_config(rc); - EXPECT_EQ(config.at("ssl_verify").value(), "/other/foo/bar/baz"); - EXPECT_EQ(config.at("cacert_path").value(), "/other/foo/bar/baz"); - EXPECT_EQ(ctx.ssl_verify, "/other/foo/bar/baz"); - - env::set("MAMBA_CACERT_PATH", "/env/ca/baz"); - load_test_config(rc); - - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - cacert_path: /env/ca/baz # 'MAMBA_CACERT_PATH' > ')" - + src + R"(' - ssl_verify: /env/ca/baz # ')" - + src + "'") - .c_str()) - ); - EXPECT_EQ(ctx.ssl_verify, "/env/ca/baz"); - - config.at("cacert_path").set_yaml_value("/new/test").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - cacert_path: /new/test # 'API' > 'MAMBA_CACERT_PATH' > ')" - + src + R"(' - ssl_verify: /env/ca/baz # ')" - + src + "'") - .c_str()) - ); - EXPECT_EQ(ctx.ssl_verify, "/env/ca/baz"); - - config.at("ssl_verify").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - cacert_path: /new/test # 'API' > 'MAMBA_CACERT_PATH' > ')" - + src + R"(' - ssl_verify: /new/test # ')" - + src + "'") - .c_str()) - ); - EXPECT_EQ(ctx.ssl_verify, "/new/test"); + TEST_CASE_FIXTURE(Configuration, "cacert_path") + { + std::string rc = "ssl_verify: /foo/bar/baz\ncacert_path: /other/foo/bar/baz"; + load_test_config(rc); + CHECK_EQ(config.at("ssl_verify").value(), "/other/foo/bar/baz"); + CHECK_EQ(config.at("cacert_path").value(), "/other/foo/bar/baz"); + CHECK_EQ(ctx.ssl_verify, "/other/foo/bar/baz"); + + env::set("MAMBA_CACERT_PATH", "/env/ca/baz"); + load_test_config(rc); + + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + cacert_path: /env/ca/baz # 'MAMBA_CACERT_PATH' > ')" + + src + R"(' + ssl_verify: /env/ca/baz # ')" + + src + "'") + .c_str()) + ); + CHECK_EQ(ctx.ssl_verify, "/env/ca/baz"); + + config.at("cacert_path").set_yaml_value("/new/test").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + cacert_path: /new/test # 'API' > 'MAMBA_CACERT_PATH' > ')" + + src + R"(' + ssl_verify: /env/ca/baz # ')" + + src + "'") + .c_str()) + ); + CHECK_EQ(ctx.ssl_verify, "/env/ca/baz"); + + config.at("ssl_verify").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + cacert_path: /new/test # 'API' > 'MAMBA_CACERT_PATH' > ')" + + src + R"(' + ssl_verify: /new/test # ')" + + src + "'") + .c_str()) + ); + CHECK_EQ(ctx.ssl_verify, "/new/test"); - env::unset("MAMBA_CACERT_PATH"); - load_test_config("cacert_path:\nssl_verify: true"); // reset ssl verify to default - } + env::unset("MAMBA_CACERT_PATH"); + load_test_config("cacert_path:\nssl_verify: true"); // reset ssl verify to default + } - TEST_F(Configuration, proxy_servers) - { - std::string rc = unindent(R"( - proxy_servers: - http: foo - https: bar)"); - load_test_config(rc); - auto& actual = config.at("proxy_servers").value>(); - std::map expected = { { "http", "foo" }, { "https", "bar" } }; - EXPECT_EQ(actual, expected); - EXPECT_EQ(ctx.proxy_servers, expected); - - EXPECT_EQ(config.sources().size(), 1); - EXPECT_EQ(config.valid_sources().size(), 1); - EXPECT_EQ(config.dump(), "proxy_servers:\n http: foo\n https: bar"); - } + TEST_CASE_FIXTURE(Configuration, "proxy_servers") + { + std::string rc = unindent(R"( + proxy_servers: + http: foo + https: bar)"); + load_test_config(rc); + auto& actual = config.at("proxy_servers").value>(); + std::map expected = { { "http", "foo" }, + { "https", "bar" } }; + CHECK_EQ(actual, expected); + CHECK_EQ(ctx.proxy_servers, expected); + + CHECK_EQ(config.sources().size(), 1); + CHECK_EQ(config.valid_sources().size(), 1); + CHECK_EQ(config.dump(), "proxy_servers:\n http: foo\n https: bar"); + } - TEST_F(Configuration, platform) - { - EXPECT_EQ(ctx.platform, ctx.host_platform); - - std::string rc = "platform: mylinux-128"; - load_test_config(rc); - std::string src = shrink_source(0); - EXPECT_EQ(config.at("platform").value(), "mylinux-128"); - EXPECT_EQ(ctx.platform, "mylinux-128"); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - platform: mylinux-128 # ')" - + src + "'") - .c_str()) - ); + TEST_CASE_FIXTURE(Configuration, "platform") + { + CHECK_EQ(ctx.platform, ctx.host_platform); + + std::string rc = "platform: mylinux-128"; + load_test_config(rc); + std::string src = shrink_source(0); + CHECK_EQ(config.at("platform").value(), "mylinux-128"); + CHECK_EQ(ctx.platform, "mylinux-128"); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + platform: mylinux-128 # ')" + + src + "'") + .c_str()) + ); - env::set("CONDA_SUBDIR", "win-32"); - load_test_config(rc); - src = shrink_source(0); - EXPECT_EQ(config.at("platform").value(), "win-32"); - EXPECT_EQ(ctx.platform, "win-32"); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - platform: win-32 # 'CONDA_SUBDIR' > ')" - + src + "'") - .c_str()) - ); + env::set("CONDA_SUBDIR", "win-32"); + load_test_config(rc); + src = shrink_source(0); + CHECK_EQ(config.at("platform").value(), "win-32"); + CHECK_EQ(ctx.platform, "win-32"); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + platform: win-32 # 'CONDA_SUBDIR' > ')" + + src + "'") + .c_str()) + ); - config.at("platform").clear_values(); - ctx.platform = ctx.host_platform; - } + config.at("platform").clear_values(); + ctx.platform = ctx.host_platform; + } #define TEST_BOOL_CONFIGURABLE(NAME, CTX) \ - TEST_F(Configuration, NAME) \ + TEST_CASE_FIXTURE(Configuration, #NAME) \ { \ std::string rc1 = std::string(#NAME) + ": true"; \ std::string rc2 = std::string(#NAME) + ": false"; \ if (config.at(#NAME).rc_configurable()) \ { \ load_test_config({ rc1, rc2 }); \ - EXPECT_TRUE(config.at(#NAME).value()); \ - EXPECT_TRUE(CTX); \ + CHECK(config.at(#NAME).value()); \ + CHECK(CTX); \ \ load_test_config({ rc2, rc1 }); \ - EXPECT_FALSE(config.at(#NAME).value()); \ - EXPECT_FALSE(CTX); \ + CHECK_FALSE(config.at(#NAME).value()); \ + CHECK_FALSE(CTX); \ } \ \ std::string env_name = "MAMBA_" + to_upper(#NAME); \ env::set(env_name, "true"); \ load_test_config(rc2); \ \ - ASSERT_EQ(config.sources().size(), 1); \ - ASSERT_EQ(config.valid_sources().size(), 1); \ + REQUIRE_EQ(config.sources().size(), 1); \ + REQUIRE_EQ(config.valid_sources().size(), 1); \ std::string src = shrink_source(0); \ \ std::string expected; \ @@ -779,9 +803,9 @@ namespace mamba expected = std::string(#NAME) + ": true # '" + env_name + "'"; \ } \ int dump_opts = MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS; \ - EXPECT_EQ((config.dump(dump_opts, { #NAME })), expected); \ - EXPECT_TRUE(config.at(#NAME).value()); \ - EXPECT_TRUE(CTX); \ + CHECK_EQ((config.dump(dump_opts, { #NAME })), expected); \ + CHECK(config.at(#NAME).value()); \ + CHECK(CTX); \ \ if (config.at(#NAME).rc_configurable()) \ { \ @@ -792,386 +816,405 @@ namespace mamba expected = std::string(#NAME) + ": true # 'API' > '" + env_name + "'"; \ } \ config.at(#NAME).set_yaml_value("true").compute(); \ - EXPECT_EQ((config.dump(dump_opts, { #NAME })), expected); \ - EXPECT_TRUE(config.at(#NAME).value()); \ - EXPECT_TRUE(CTX); \ + CHECK_EQ((config.dump(dump_opts, { #NAME })), expected); \ + CHECK(config.at(#NAME).value()); \ + CHECK(CTX); \ \ env::set(env_name, "yeap"); \ - ASSERT_THROW(load_test_config(rc2), YAML::Exception); \ + REQUIRE_THROWS_AS(load_test_config(rc2), YAML::Exception); \ \ env::unset(env_name); \ load_test_config(rc2); \ } - TEST_BOOL_CONFIGURABLE(ssl_no_revoke, ctx.ssl_no_revoke); + TEST_BOOL_CONFIGURABLE(ssl_no_revoke, ctx.ssl_no_revoke); - TEST_BOOL_CONFIGURABLE(override_channels_enabled, ctx.override_channels_enabled); + TEST_BOOL_CONFIGURABLE(override_channels_enabled, ctx.override_channels_enabled); - TEST_BOOL_CONFIGURABLE(auto_activate_base, ctx.auto_activate_base); + TEST_BOOL_CONFIGURABLE(auto_activate_base, ctx.auto_activate_base); - TEST_F(Configuration, channel_priority) - { - std::string rc1 = "channel_priority: flexible"; - std::string rc2 = "channel_priority: strict"; - std::string rc3 = "channel_priority: disabled"; + TEST_CASE_FIXTURE(Configuration, "channel_priority") + { + std::string rc1 = "channel_priority: flexible"; + std::string rc2 = "channel_priority: strict"; + std::string rc3 = "channel_priority: disabled"; + + load_test_config({ rc1, rc2, rc3 }); + CHECK_EQ( + config.at("channel_priority").value(), + ChannelPriority::kFlexible + ); + CHECK(ctx.channel_priority == ChannelPriority::kFlexible); - load_test_config({ rc1, rc2, rc3 }); - EXPECT_EQ(config.at("channel_priority").value(), ChannelPriority::kFlexible); - EXPECT_TRUE(ctx.channel_priority == ChannelPriority::kFlexible); + load_test_config({ rc3, rc1, rc2 }); + CHECK_EQ( + config.at("channel_priority").value(), + ChannelPriority::kDisabled + ); + CHECK(ctx.channel_priority == ChannelPriority::kDisabled); - load_test_config({ rc3, rc1, rc2 }); - EXPECT_EQ(config.at("channel_priority").value(), ChannelPriority::kDisabled); - EXPECT_TRUE(ctx.channel_priority == ChannelPriority::kDisabled); + load_test_config({ rc2, rc1, rc3 }); + CHECK_EQ( + config.at("channel_priority").value(), + ChannelPriority::kStrict + ); + CHECK(ctx.channel_priority == ChannelPriority::kStrict); - load_test_config({ rc2, rc1, rc3 }); - EXPECT_EQ(config.at("channel_priority").value(), ChannelPriority::kStrict); - EXPECT_TRUE(ctx.channel_priority == ChannelPriority::kStrict); + env::set("MAMBA_CHANNEL_PRIORITY", "strict"); + load_test_config(rc3); - env::set("MAMBA_CHANNEL_PRIORITY", "strict"); - load_test_config(rc3); + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src = shrink_source(0); - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src = shrink_source(0); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "channel_priority: strict # 'MAMBA_CHANNEL_PRIORITY' > '" + src + "'" + ); + CHECK_EQ( + config.at("channel_priority").value(), + ChannelPriority::kStrict + ); + CHECK_EQ(ctx.channel_priority, ChannelPriority::kStrict); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "channel_priority: strict # 'MAMBA_CHANNEL_PRIORITY' > '" + src + "'" - ); - EXPECT_EQ(config.at("channel_priority").value(), ChannelPriority::kStrict); - EXPECT_EQ(ctx.channel_priority, ChannelPriority::kStrict); + config.at("channel_priority").set_yaml_value("flexible").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "channel_priority: flexible # 'API' > 'MAMBA_CHANNEL_PRIORITY' > '" + src + "'" + ); + CHECK_EQ( + config.at("channel_priority").value(), + ChannelPriority::kFlexible + ); + CHECK_EQ(ctx.channel_priority, ChannelPriority::kFlexible); - config.at("channel_priority").set_yaml_value("flexible").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "channel_priority: flexible # 'API' > 'MAMBA_CHANNEL_PRIORITY' > '" + src + "'" - ); - EXPECT_EQ(config.at("channel_priority").value(), ChannelPriority::kFlexible); - EXPECT_EQ(ctx.channel_priority, ChannelPriority::kFlexible); + env::set("MAMBA_CHANNEL_PRIORITY", "stric"); + REQUIRE_THROWS_AS(load_test_config(rc3), YAML::Exception); - env::set("MAMBA_CHANNEL_PRIORITY", "stric"); - ASSERT_THROW(load_test_config(rc3), YAML::Exception); + env::unset("MAMBA_CHANNEL_PRIORITY"); + } - env::unset("MAMBA_CHANNEL_PRIORITY"); - } + TEST_CASE_FIXTURE(Configuration, "pinned_packages") + { + std::string rc1 = unindent(R"( + pinned_packages: + - jupyterlab=3 + - numpy=1.19)"); + std::string rc2 = unindent(R"( + pinned_packages: + - matplotlib + - numpy=1.19)"); + std::string rc3 = unindent(R"( + pinned_packages: + - jupyterlab=3 + - bokeh + - matplotlib)"); + + load_test_config({ rc1, rc2, rc3 }); + CHECK_EQ(config.dump(), unindent(R"( + pinned_packages: + - jupyterlab=3 + - numpy=1.19 + - matplotlib + - bokeh)")); + CHECK_EQ( + ctx.pinned_packages, + std::vector({ "jupyterlab=3", "numpy=1.19", "matplotlib", "bokeh" }) + ); - TEST_F(Configuration, pinned_packages) - { - std::string rc1 = unindent(R"( - pinned_packages: - - jupyterlab=3 - - numpy=1.19)"); - std::string rc2 = unindent(R"( - pinned_packages: - - matplotlib - - numpy=1.19)"); - std::string rc3 = unindent(R"( - pinned_packages: - - jupyterlab=3 - - bokeh - - matplotlib)"); - - load_test_config({ rc1, rc2, rc3 }); - EXPECT_EQ(config.dump(), unindent(R"( - pinned_packages: - - jupyterlab=3 - - numpy=1.19 - - matplotlib - - bokeh)")); - EXPECT_EQ( - ctx.pinned_packages, - std::vector({ "jupyterlab=3", "numpy=1.19", "matplotlib", "bokeh" }) - ); + load_test_config({ rc2, rc1, rc3 }); + REQUIRE(config.at("pinned_packages").yaml_value()); + CHECK_EQ(config.dump(), unindent(R"( + pinned_packages: + - matplotlib + - numpy=1.19 + - jupyterlab=3 + - bokeh)")); + CHECK_EQ( + ctx.pinned_packages, + std::vector({ "matplotlib", "numpy=1.19", "jupyterlab=3", "bokeh" }) + ); - load_test_config({ rc2, rc1, rc3 }); - ASSERT_TRUE(config.at("pinned_packages").yaml_value()); - EXPECT_EQ(config.dump(), unindent(R"( - pinned_packages: - - matplotlib - - numpy=1.19 - - jupyterlab=3 - - bokeh)")); - EXPECT_EQ( - ctx.pinned_packages, - std::vector({ "matplotlib", "numpy=1.19", "jupyterlab=3", "bokeh" }) - ); + env::set("MAMBA_PINNED_PACKAGES", "mpl=10.2,xtensor"); + load_test_config(rc1); + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src1 = shrink_source(0); + + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + pinned_packages: + - mpl=10.2 # 'MAMBA_PINNED_PACKAGES' + - xtensor # 'MAMBA_PINNED_PACKAGES' + - jupyterlab=3 # ')" + + src1 + R"(' + - numpy=1.19 # ')" + + src1 + "'") + .c_str()) + ); + CHECK_EQ( + ctx.pinned_packages, + std::vector({ "mpl=10.2", "xtensor", "jupyterlab=3", "numpy=1.19" }) + ); - env::set("MAMBA_PINNED_PACKAGES", "mpl=10.2,xtensor"); - load_test_config(rc1); - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src1 = shrink_source(0); - - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - pinned_packages: - - mpl=10.2 # 'MAMBA_PINNED_PACKAGES' - - xtensor # 'MAMBA_PINNED_PACKAGES' - - jupyterlab=3 # ')" - + src1 + R"(' - - numpy=1.19 # ')" - + src1 + "'") - .c_str()) - ); - EXPECT_EQ( - ctx.pinned_packages, - std::vector({ "mpl=10.2", "xtensor", "jupyterlab=3", "numpy=1.19" }) - ); + config.at("pinned_packages").set_yaml_value("pytest").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + unindent((R"( + pinned_packages: + - pytest # 'API' + - mpl=10.2 # 'MAMBA_PINNED_PACKAGES' + - xtensor # 'MAMBA_PINNED_PACKAGES' + - jupyterlab=3 # ')" + + src1 + R"(' + - numpy=1.19 # ')" + + src1 + "'") + .c_str()) + ); + CHECK_EQ( + ctx.pinned_packages, + std::vector( + { "pytest", "mpl=10.2", "xtensor", "jupyterlab=3", "numpy=1.19" } + ) + ); - config.at("pinned_packages").set_yaml_value("pytest").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - unindent((R"( - pinned_packages: - - pytest # 'API' - - mpl=10.2 # 'MAMBA_PINNED_PACKAGES' - - xtensor # 'MAMBA_PINNED_PACKAGES' - - jupyterlab=3 # ')" - + src1 + R"(' - - numpy=1.19 # ')" - + src1 + "'") - .c_str()) - ); - EXPECT_EQ( - ctx.pinned_packages, - std::vector( - { "pytest", "mpl=10.2", "xtensor", "jupyterlab=3", "numpy=1.19" } - ) - ); + env::unset("MAMBA_PINNED_PACKAGES"); + } - env::unset("MAMBA_PINNED_PACKAGES"); - } + TEST_BOOL_CONFIGURABLE(no_pin, config.at("no_pin").value()); - TEST_BOOL_CONFIGURABLE(no_pin, config.at("no_pin").value()); + TEST_BOOL_CONFIGURABLE(retry_clean_cache, config.at("retry_clean_cache").value()); - TEST_BOOL_CONFIGURABLE(retry_clean_cache, config.at("retry_clean_cache").value()); + TEST_BOOL_CONFIGURABLE(allow_softlinks, ctx.allow_softlinks); - TEST_BOOL_CONFIGURABLE(allow_softlinks, ctx.allow_softlinks); + TEST_BOOL_CONFIGURABLE(always_softlink, ctx.always_softlink); - TEST_BOOL_CONFIGURABLE(always_softlink, ctx.always_softlink); + TEST_BOOL_CONFIGURABLE(always_copy, ctx.always_copy); - TEST_BOOL_CONFIGURABLE(always_copy, ctx.always_copy); + TEST_CASE_FIXTURE(Configuration, "always_softlink_and_copy") + { + env::set("MAMBA_ALWAYS_COPY", "true"); + REQUIRE_THROWS_AS(load_test_config("always_softlink: true"), std::runtime_error); + env::unset("MAMBA_ALWAYS_COPY"); - TEST_F(Configuration, always_softlink_and_copy) - { - env::set("MAMBA_ALWAYS_COPY", "true"); - ASSERT_THROW(load_test_config("always_softlink: true"), std::runtime_error); - env::unset("MAMBA_ALWAYS_COPY"); + env::set("MAMBA_ALWAYS_SOFTLINK", "true"); + REQUIRE_THROWS_AS(load_test_config("always_copy: true"), std::runtime_error); + env::unset("MAMBA_ALWAYS_SOFTLINK"); - env::set("MAMBA_ALWAYS_SOFTLINK", "true"); - ASSERT_THROW(load_test_config("always_copy: true"), std::runtime_error); - env::unset("MAMBA_ALWAYS_SOFTLINK"); + load_test_config("always_softlink: false\nalways_copy: false"); + } - load_test_config("always_softlink: false\nalways_copy: false"); - } + TEST_CASE_FIXTURE(Configuration, "safety_checks") + { + std::string rc1 = "safety_checks: enabled"; + std::string rc2 = "safety_checks: warn"; + std::string rc3 = "safety_checks: disabled"; + + load_test_config({ rc1, rc2, rc3 }); + CHECK_EQ( + config.at("safety_checks").value(), + VerificationLevel::kEnabled + ); + CHECK_EQ(ctx.safety_checks, VerificationLevel::kEnabled); - TEST_F(Configuration, safety_checks) - { - std::string rc1 = "safety_checks: enabled"; - std::string rc2 = "safety_checks: warn"; - std::string rc3 = "safety_checks: disabled"; - - load_test_config({ rc1, rc2, rc3 }); - EXPECT_EQ(config.at("safety_checks").value(), VerificationLevel::kEnabled); - EXPECT_EQ(ctx.safety_checks, VerificationLevel::kEnabled); - - load_test_config({ rc2, rc1, rc3 }); - EXPECT_EQ(config.at("safety_checks").value(), VerificationLevel::kWarn); - EXPECT_EQ(ctx.safety_checks, VerificationLevel::kWarn); - - load_test_config({ rc3, rc1, rc3 }); - EXPECT_EQ( - config.at("safety_checks").value(), - VerificationLevel::kDisabled - ); - EXPECT_EQ(ctx.safety_checks, VerificationLevel::kDisabled); + load_test_config({ rc2, rc1, rc3 }); + CHECK_EQ(config.at("safety_checks").value(), VerificationLevel::kWarn); + CHECK_EQ(ctx.safety_checks, VerificationLevel::kWarn); - env::set("MAMBA_SAFETY_CHECKS", "warn"); - load_test_config(rc1); + load_test_config({ rc3, rc1, rc3 }); + CHECK_EQ( + config.at("safety_checks").value(), + VerificationLevel::kDisabled + ); + CHECK_EQ(ctx.safety_checks, VerificationLevel::kDisabled); - ASSERT_EQ(config.sources().size(), 1); - ASSERT_EQ(config.valid_sources().size(), 1); - std::string src = shrink_source(0); + env::set("MAMBA_SAFETY_CHECKS", "warn"); + load_test_config(rc1); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "safety_checks: warn # 'MAMBA_SAFETY_CHECKS' > '" + src + "'" - ); - EXPECT_EQ(config.at("safety_checks").value(), VerificationLevel::kWarn); - EXPECT_EQ(ctx.safety_checks, VerificationLevel::kWarn); + REQUIRE_EQ(config.sources().size(), 1); + REQUIRE_EQ(config.valid_sources().size(), 1); + std::string src = shrink_source(0); - config.at("safety_checks").set_yaml_value("disabled").compute(); - EXPECT_EQ( - config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), - "safety_checks: disabled # 'API' > 'MAMBA_SAFETY_CHECKS' > '" + src + "'" - ); - EXPECT_EQ( - config.at("safety_checks").value(), - VerificationLevel::kDisabled - ); - EXPECT_EQ(ctx.safety_checks, VerificationLevel::kDisabled); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "safety_checks: warn # 'MAMBA_SAFETY_CHECKS' > '" + src + "'" + ); + CHECK_EQ(config.at("safety_checks").value(), VerificationLevel::kWarn); + CHECK_EQ(ctx.safety_checks, VerificationLevel::kWarn); - env::set("MAMBA_SAFETY_CHECKS", "yeap"); - ASSERT_THROW(load_test_config(rc2), std::runtime_error); + config.at("safety_checks").set_yaml_value("disabled").compute(); + CHECK_EQ( + config.dump(MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS), + "safety_checks: disabled # 'API' > 'MAMBA_SAFETY_CHECKS' > '" + src + "'" + ); + CHECK_EQ( + config.at("safety_checks").value(), + VerificationLevel::kDisabled + ); + CHECK_EQ(ctx.safety_checks, VerificationLevel::kDisabled); - env::unset("MAMBA_SAFETY_CHECKS"); - load_test_config(rc2); - } + env::set("MAMBA_SAFETY_CHECKS", "yeap"); + REQUIRE_THROWS_AS(load_test_config(rc2), std::runtime_error); - TEST_BOOL_CONFIGURABLE(extra_safety_checks, ctx.extra_safety_checks); + env::unset("MAMBA_SAFETY_CHECKS"); + load_test_config(rc2); + } + + TEST_BOOL_CONFIGURABLE(extra_safety_checks, ctx.extra_safety_checks); #undef TEST_BOOL_CONFIGURABLE - TEST_F(Configuration, has_config_name) - { - using namespace detail; - - EXPECT_FALSE(has_config_name("")); - EXPECT_FALSE(has_config_name("conf")); - EXPECT_FALSE(has_config_name("config")); - EXPECT_FALSE(has_config_name("config.conda")); - EXPECT_FALSE(has_config_name("conf.condarc")); - EXPECT_FALSE(has_config_name("conf.mambarc")); - - EXPECT_TRUE(has_config_name("condarc")); - EXPECT_TRUE(has_config_name("mambarc")); - EXPECT_TRUE(has_config_name(".condarc")); - EXPECT_TRUE(has_config_name(".mambarc")); - EXPECT_TRUE(has_config_name(".yaml")); - EXPECT_TRUE(has_config_name(".yml")); - EXPECT_TRUE(has_config_name("conf.yaml")); - EXPECT_TRUE(has_config_name("config.yml")); - } + TEST_CASE_FIXTURE(Configuration, "has_config_name") + { + using namespace detail; + + CHECK_FALSE(has_config_name("")); + CHECK_FALSE(has_config_name("conf")); + CHECK_FALSE(has_config_name("config")); + CHECK_FALSE(has_config_name("config.conda")); + CHECK_FALSE(has_config_name("conf.condarc")); + CHECK_FALSE(has_config_name("conf.mambarc")); + + CHECK(has_config_name("condarc")); + CHECK(has_config_name("mambarc")); + CHECK(has_config_name(".condarc")); + CHECK(has_config_name(".mambarc")); + CHECK(has_config_name(".yaml")); + CHECK(has_config_name(".yml")); + CHECK(has_config_name("conf.yaml")); + CHECK(has_config_name("config.yml")); + } - TEST_F(Configuration, is_config_file) - { - using namespace detail; + TEST_CASE_FIXTURE(Configuration, "is_config_file") + { + using namespace detail; - fs::u8path p = test_data_dir / "config/.condarc"; + fs::u8path p = test_data_dir / "config/.condarc"; - std::vector wrong_paths = { - test_data_dir / "config", - test_data_dir / "conf", - test_data_dir / "config/condarc", - test_data_dir / "history/conda-meta/history", - }; + std::vector wrong_paths = { + test_data_dir / "config", + test_data_dir / "conf", + test_data_dir / "config/condarc", + test_data_dir / "history/conda-meta/history", + }; - EXPECT_TRUE(is_config_file(p)); + CHECK(is_config_file(p)); - for (const fs::u8path& wp : wrong_paths) - { - EXPECT_FALSE(is_config_file(wp)); + for (const fs::u8path& wp : wrong_paths) + { + CHECK_FALSE(is_config_file(wp)); + } } - } - TEST_F(Configuration, print_scalar_node) - { - using namespace detail; - - std::string rc = "foo"; - auto node = YAML::Load(rc); - auto node_src = YAML::Load("/some/source1"); - YAML::Emitter out; - print_scalar_node(out, node, node_src, true); - - std::string res = out.c_str(); - EXPECT_EQ(res, "foo # '/some/source1'"); - - // These tests do not really make sense since - // print_scalar should be called by print_configurable only - // and the check is already done in it. - /* - rc = unindent(R"( - foo: bar - bar: baz)"); - node = YAML::Load(rc); - EXPECT_THROW(print_scalar_node(out, node, node_src, true), std::runtime_error); - - rc = unindent(R"( - - foo - - bar)"); - node = YAML::Load(rc); - EXPECT_THROW(print_scalar_node(out, node, node_src, true), std::runtime_error); - - node = YAML::Node(); - EXPECT_THROW(print_scalar_node(out, node, node_src, true), std::runtime_error); - */ - } + TEST_CASE_FIXTURE(Configuration, "print_scalar_node") + { + using namespace detail; + + std::string rc = "foo"; + auto node = YAML::Load(rc); + auto node_src = YAML::Load("/some/source1"); + YAML::Emitter out; + print_scalar_node(out, node, node_src, true); + + std::string res = out.c_str(); + CHECK_EQ(res, "foo # '/some/source1'"); + + // These tests do not really make sense since + // print_scalar should be called by print_configurable only + // and the check is already done in it. + /* + rc = unindent(R"( + foo: bar + bar: baz)"); + node = YAML::Load(rc); + CHECK_THROWS_AS(print_scalar_node(out, node, node_src, true), std::runtime_error); + + rc = unindent(R"( + - foo + - bar)"); + node = YAML::Load(rc); + CHECK_THROWS_AS(print_scalar_node(out, node, node_src, true), std::runtime_error); + + node = YAML::Node(); + CHECK_THROWS_AS(print_scalar_node(out, node, node_src, true), std::runtime_error); + */ + } - TEST_F(Configuration, print_map_node) - { - using namespace detail; + TEST_CASE_FIXTURE(Configuration, "print_map_node") + { + using namespace detail; + + std::string rc = unindent(R"( + foo: bar + bar: baz)"); + auto node = YAML::Load(rc); + auto node_src = YAML::Load(unindent(R"( + foo: /some/source1 + bar: /some/source2)")); + YAML::Emitter out; + print_map_node(out, node, node_src, true); + + std::string res = out.c_str(); + CHECK_EQ(res, unindent(R"( + foo: bar # '/some/source1' + bar: baz # '/some/source2')")); + + // These tests do not really make sense since + // print_scalar should be called by print_configurable only + // and the check is already done in it. + /*rc = "foo"; + node = YAML::Load(rc); + CHECK_THROWS_AS(print_map_node(out, node, node_src, true), std::runtime_error); + + rc = unindent(R"( + - foo + - bar)"); + node = YAML::Load(rc); + CHECK_THROWS_AS(print_map_node(out, node, node_src, true), std::runtime_error); + + node = YAML::Node(); + CHECK_THROWS_AS(print_map_node(out, node, node_src, true), std::runtime_error);*/ + } - std::string rc = unindent(R"( + TEST_CASE_FIXTURE(Configuration, "print_seq_node") + { + using namespace detail; + + std::string rc = unindent(R"( + - foo + - bar + )"); + auto node = YAML::Load(rc); + auto node_src = YAML::Load(unindent(R"( + - /some/source1 + - /some/source2 + )")); + YAML::Emitter out; + print_seq_node(out, node, node_src, true); + + std::string res = out.c_str(); + CHECK_EQ(res, unindent(R"( + - foo # '/some/source1' + - bar # '/some/source2')")); + + // These tests do not really make sense since + // print_scalar should be called by print_configurable only + // and the check is already done in it. + /*rc = "foo"; + node = YAML::Load(rc); + CHECK_THROWS_AS(print_seq_node(out, node, node_src, true), std::runtime_error); + + rc = unindent(R"( foo: bar bar: baz)"); - auto node = YAML::Load(rc); - auto node_src = YAML::Load(unindent(R"( - foo: /some/source1 - bar: /some/source2)")); - YAML::Emitter out; - print_map_node(out, node, node_src, true); - - std::string res = out.c_str(); - EXPECT_EQ(res, unindent(R"( - foo: bar # '/some/source1' - bar: baz # '/some/source2')")); - - // These tests do not really make sense since - // print_scalar should be called by print_configurable only - // and the check is already done in it. - /*rc = "foo"; - node = YAML::Load(rc); - EXPECT_THROW(print_map_node(out, node, node_src, true), std::runtime_error); - - rc = unindent(R"( - - foo - - bar)"); - node = YAML::Load(rc); - EXPECT_THROW(print_map_node(out, node, node_src, true), std::runtime_error); - - node = YAML::Node(); - EXPECT_THROW(print_map_node(out, node, node_src, true), std::runtime_error);*/ - } + node = YAML::Load(rc); + CHECK_THROWS_AS(print_seq_node(out, node, node_src, true), std::runtime_error); - TEST_F(Configuration, print_seq_node) - { - using namespace detail; - - std::string rc = unindent(R"( - - foo - - bar - )"); - auto node = YAML::Load(rc); - auto node_src = YAML::Load(unindent(R"( - - /some/source1 - - /some/source2 - )")); - YAML::Emitter out; - print_seq_node(out, node, node_src, true); - - std::string res = out.c_str(); - EXPECT_EQ(res, unindent(R"( - - foo # '/some/source1' - - bar # '/some/source2')")); - - // These tests do not really make sense since - // print_scalar should be called by print_configurable only - // and the check is already done in it. - /*rc = "foo"; - node = YAML::Load(rc); - EXPECT_THROW(print_seq_node(out, node, node_src, true), std::runtime_error); - - rc = unindent(R"( - foo: bar - bar: baz)"); - node = YAML::Load(rc); - EXPECT_THROW(print_seq_node(out, node, node_src, true), std::runtime_error); - - node = YAML::Node(); - EXPECT_THROW(print_seq_node(out, node, node_src, true), std::runtime_error);*/ + node = YAML::Node(); + CHECK_THROWS_AS(print_seq_node(out, node, node_src, true), std::runtime_error);*/ + } } } // namespace testing } // namespace mamba diff --git a/libmamba/tests/src/core/test_cpp.cpp b/libmamba/tests/src/core/test_cpp.cpp index 72112df2e5..0d42d30cdd 100644 --- a/libmamba/tests/src/core/test_cpp.cpp +++ b/libmamba/tests/src/core/test_cpp.cpp @@ -8,8 +8,6 @@ #include #include -#include - #include "mamba/core/context.hpp" #include "mamba/core/environment.hpp" #include "mamba/core/fsutil.hpp" @@ -19,6 +17,8 @@ #include "mamba/core/output.hpp" #include "mamba/core/subdirdata.hpp" +#include "doctest/doctest.h" + #include "test_data.hpp" namespace mamba @@ -37,504 +37,519 @@ namespace mamba // lp.execute(); // } - TEST(match_spec, parse_version_build) - { - std::string v, b; - // >>> _parse_version_plus_build("=1.2.3 0") - // ('=1.2.3', '0') - // >>> _parse_version_plus_build("1.2.3=0") - // ('1.2.3', '0') - // >>> _parse_version_plus_build(">=1.0 , < 2.0 py34_0") - // ('>=1.0,<2.0', 'py34_0') - // >>> _parse_version_plus_build(">=1.0 , < 2.0 =py34_0") - // ('>=1.0,<2.0', 'py34_0') - // >>> _parse_version_plus_build("=1.2.3 ") - // ('=1.2.3', None) - // >>> _parse_version_plus_build(">1.8,<2|==1.7") - // ('>1.8,<2|==1.7', None) - // >>> _parse_version_plus_build("* openblas_0") - // ('*', 'openblas_0') - // >>> _parse_version_plus_build("* *") - // ('*', '*') - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 0"); - EXPECT_EQ(v, "=1.2.3"); - EXPECT_EQ(b, "0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3=0"); - EXPECT_EQ(v, "=1.2.3"); - EXPECT_EQ(b, "0"); - std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 py34_0"); - EXPECT_EQ(v, ">=1.0,<2.0"); - EXPECT_EQ(b, "py34_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 =py34_0"); - EXPECT_EQ(v, ">=1.0,<2.0"); - EXPECT_EQ(b, "py34_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 "); - EXPECT_EQ(v, "=1.2.3"); - EXPECT_EQ(b, ""); - std::tie(v, b) = MatchSpec::parse_version_and_build(">1.8,<2|==1.7"); - EXPECT_EQ(v, ">1.8,<2|==1.7"); - EXPECT_EQ(b, ""); - std::tie(v, b) = MatchSpec::parse_version_and_build("* openblas_0"); - EXPECT_EQ(v, "*"); - EXPECT_EQ(b, "openblas_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("* *"); - EXPECT_EQ(v, "*"); - EXPECT_EQ(b, "*"); - } - - TEST(match_spec, parse) + TEST_SUITE("match_spec") { + TEST_CASE("parse_version_build") { - MatchSpec ms("xtensor==0.12.3"); - EXPECT_EQ(ms.version, "0.12.3"); - EXPECT_EQ(ms.name, "xtensor"); - } - { - MatchSpec ms("ipykernel"); - EXPECT_EQ(ms.version, ""); - EXPECT_EQ(ms.name, "ipykernel"); - } - { - MatchSpec ms("ipykernel "); - EXPECT_EQ(ms.version, ""); - EXPECT_EQ(ms.name, "ipykernel"); - } - { - MatchSpec ms("numpy 1.7*"); - EXPECT_EQ(ms.version, "1.7*"); - EXPECT_EQ(ms.name, "numpy"); - EXPECT_EQ(ms.conda_build_form(), "numpy 1.7*"); - EXPECT_EQ(ms.str(), "numpy=1.7"); - } - { - MatchSpec ms("numpy[version='1.7|1.8']"); - // TODO! - // EXPECT_EQ(ms.version, "1.7|1.8"); - EXPECT_EQ(ms.name, "numpy"); - EXPECT_EQ(ms.brackets["version"], "1.7|1.8"); - EXPECT_EQ(ms.str(), "numpy[version='1.7|1.8']"); - } - { - MatchSpec ms("conda-forge/linux64::xtensor==0.12.3"); - EXPECT_EQ(ms.version, "0.12.3"); - EXPECT_EQ(ms.name, "xtensor"); - EXPECT_EQ(ms.channel, "conda-forge/linux64"); - EXPECT_EQ(ms.optional, false); - } - { - MatchSpec ms("conda-forge::foo[build=3](target=blarg,optional)"); - EXPECT_EQ(ms.version, ""); - EXPECT_EQ(ms.name, "foo"); - EXPECT_EQ(ms.channel, "conda-forge"); - EXPECT_EQ(ms.brackets["build"], "3"); - EXPECT_EQ(ms.parens["target"], "blarg"); - EXPECT_EQ(ms.optional, true); - } - { - MatchSpec ms("python[build_number=3]"); - EXPECT_EQ(ms.name, "python"); - EXPECT_EQ(ms.brackets["build_number"], "3"); - EXPECT_EQ(ms.build_number, "3"); - } - { - MatchSpec ms("python[build_number='<=3']"); - EXPECT_EQ(ms.name, "python"); - EXPECT_EQ(ms.brackets["build_number"], "<=3"); - EXPECT_EQ(ms.build_number, "<=3"); - } - { - MatchSpec ms( - "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); - EXPECT_EQ(ms.name, "_libgcc_mutex"); - EXPECT_EQ(ms.version, "0.1"); - EXPECT_EQ(ms.build_string, "conda_forge"); - EXPECT_EQ( - ms.url, - "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); - EXPECT_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); + std::string v, b; + // >>> _parse_version_plus_build("=1.2.3 0") + // ('=1.2.3', '0') + // >>> _parse_version_plus_build("1.2.3=0") + // ('1.2.3', '0') + // >>> _parse_version_plus_build(">=1.0 , < 2.0 py34_0") + // ('>=1.0,<2.0', 'py34_0') + // >>> _parse_version_plus_build(">=1.0 , < 2.0 =py34_0") + // ('>=1.0,<2.0', 'py34_0') + // >>> _parse_version_plus_build("=1.2.3 ") + // ('=1.2.3', None) + // >>> _parse_version_plus_build(">1.8,<2|==1.7") + // ('>1.8,<2|==1.7', None) + // >>> _parse_version_plus_build("* openblas_0") + // ('*', 'openblas_0') + // >>> _parse_version_plus_build("* *") + // ('*', '*') + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 0"); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, "0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3=0"); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, "0"); + std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 py34_0"); + CHECK_EQ(v, ">=1.0,<2.0"); + CHECK_EQ(b, "py34_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 =py34_0"); + CHECK_EQ(v, ">=1.0,<2.0"); + CHECK_EQ(b, "py34_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 "); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, ""); + std::tie(v, b) = MatchSpec::parse_version_and_build(">1.8,<2|==1.7"); + CHECK_EQ(v, ">1.8,<2|==1.7"); + CHECK_EQ(b, ""); + std::tie(v, b) = MatchSpec::parse_version_and_build("* openblas_0"); + CHECK_EQ(v, "*"); + CHECK_EQ(b, "openblas_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("* *"); + CHECK_EQ(v, "*"); + CHECK_EQ(b, "*"); } + + TEST_CASE("parse") { - MatchSpec ms("/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"); - EXPECT_EQ(ms.name, "_libgcc_mutex"); - EXPECT_EQ(ms.version, "0.1"); - EXPECT_EQ(ms.build_string, "conda_forge"); + { + MatchSpec ms("xtensor==0.12.3"); + CHECK_EQ(ms.version, "0.12.3"); + CHECK_EQ(ms.name, "xtensor"); + } + { + MatchSpec ms("ipykernel"); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "ipykernel"); + } + { + MatchSpec ms("ipykernel "); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "ipykernel"); + } + { + MatchSpec ms("numpy 1.7*"); + CHECK_EQ(ms.version, "1.7*"); + CHECK_EQ(ms.name, "numpy"); + CHECK_EQ(ms.conda_build_form(), "numpy 1.7*"); + CHECK_EQ(ms.str(), "numpy=1.7"); + } + { + MatchSpec ms("numpy[version='1.7|1.8']"); + // TODO! + // CHECK_EQ(ms.version, "1.7|1.8"); + CHECK_EQ(ms.name, "numpy"); + CHECK_EQ(ms.brackets["version"], "1.7|1.8"); + CHECK_EQ(ms.str(), "numpy[version='1.7|1.8']"); + } + { + MatchSpec ms("conda-forge/linux64::xtensor==0.12.3"); + CHECK_EQ(ms.version, "0.12.3"); + CHECK_EQ(ms.name, "xtensor"); + CHECK_EQ(ms.channel, "conda-forge/linux64"); + CHECK_EQ(ms.optional, false); + } + { + MatchSpec ms("conda-forge::foo[build=3](target=blarg,optional)"); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "foo"); + CHECK_EQ(ms.channel, "conda-forge"); + CHECK_EQ(ms.brackets["build"], "3"); + CHECK_EQ(ms.parens["target"], "blarg"); + CHECK_EQ(ms.optional, true); + } + { + MatchSpec ms("python[build_number=3]"); + CHECK_EQ(ms.name, "python"); + CHECK_EQ(ms.brackets["build_number"], "3"); + CHECK_EQ(ms.build_number, "3"); + } + { + MatchSpec ms("python[build_number='<=3']"); + CHECK_EQ(ms.name, "python"); + CHECK_EQ(ms.brackets["build_number"], "<=3"); + CHECK_EQ(ms.build_number, "<=3"); + } + { + MatchSpec ms( + "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); + CHECK_EQ(ms.name, "_libgcc_mutex"); + CHECK_EQ(ms.version, "0.1"); + CHECK_EQ(ms.build_string, "conda_forge"); + CHECK_EQ( + ms.url, + "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); + CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); + } + { + MatchSpec ms("/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); + CHECK_EQ(ms.name, "_libgcc_mutex"); + CHECK_EQ(ms.version, "0.1"); + CHECK_EQ(ms.build_string, "conda_forge"); #ifdef _WIN32 - std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); - EXPECT_EQ( - ms.url, - std::string("file://") + driveletter - + ":/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); + std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); + CHECK_EQ( + ms.url, + std::string("file://") + driveletter + + ":/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); #else - EXPECT_EQ( - ms.url, - "file:///home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); + CHECK_EQ( + ms.url, + "file:///home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); #endif - EXPECT_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); - } - { - MatchSpec ms("xtensor[url=file:///home/wolfv/Downloads/" - "xtensor-0.21.4-hc9558a2_0.tar.bz2]"); - EXPECT_EQ(ms.name, "xtensor"); - EXPECT_EQ( - ms.brackets["url"], - "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2" - ); - EXPECT_EQ(ms.url, "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2"); - } - { - MatchSpec ms("foo=1.0=2"); - EXPECT_EQ(ms.conda_build_form(), "foo 1.0 2"); - EXPECT_EQ(ms.str(), "foo==1.0=2"); - } - { - MatchSpec ms("foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2']"); - EXPECT_EQ(ms.conda_build_form(), "foo 1.0 2"); - EXPECT_EQ(ms.str(), "foo==1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']"); - } - { - MatchSpec ms("foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2', url='abcdef']" - ); - EXPECT_EQ(ms.conda_build_form(), "foo 1.0 2"); - EXPECT_EQ(ms.str(), "foo==1.0=2[url=abcdef,md5=123123123,license=BSD-3]"); - } - { - MatchSpec ms("libblas=*=*mkl"); - EXPECT_EQ(ms.conda_build_form(), "libblas * *mkl"); - // EXPECT_EQ(ms.str(), "foo==1.0=2"); - } - { - MatchSpec ms("libblas=0.15*"); - EXPECT_EQ(ms.conda_build_form(), "libblas 0.15*"); - } - { - MatchSpec ms("xtensor =0.15*"); - EXPECT_EQ(ms.conda_build_form(), "xtensor 0.15*"); - EXPECT_EQ(ms.str(), "xtensor=0.15"); + CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); + } + { + MatchSpec ms("xtensor[url=file:///home/wolfv/Downloads/" + "xtensor-0.21.4-hc9558a2_0.tar.bz2]"); + CHECK_EQ(ms.name, "xtensor"); + CHECK_EQ( + ms.brackets["url"], + "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2" + ); + CHECK_EQ(ms.url, "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2"); + } + { + MatchSpec ms("foo=1.0=2"); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2"); + } + { + MatchSpec ms("foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2']"); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']"); + } + { + MatchSpec ms( + "foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2', url='abcdef']" + ); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2[url=abcdef,md5=123123123,license=BSD-3]"); + } + { + MatchSpec ms("libblas=*=*mkl"); + CHECK_EQ(ms.conda_build_form(), "libblas * *mkl"); + // CHECK_EQ(ms.str(), "foo==1.0=2"); + } + { + MatchSpec ms("libblas=0.15*"); + CHECK_EQ(ms.conda_build_form(), "libblas 0.15*"); + } + { + MatchSpec ms("xtensor =0.15*"); + CHECK_EQ(ms.conda_build_form(), "xtensor 0.15*"); + CHECK_EQ(ms.str(), "xtensor=0.15"); + } + { + MatchSpec ms("numpy=1.20"); + CHECK_EQ(ms.str(), "numpy=1.20"); + } } + + TEST_CASE("is_simple") { - MatchSpec ms("numpy=1.20"); - EXPECT_EQ(ms.str(), "numpy=1.20"); + { + MatchSpec ms("libblas"); + CHECK(ms.is_simple()); + } + { + MatchSpec ms("libblas=12.9=abcdef"); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("libblas=0.15*"); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("libblas[version=12.2]"); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("xtensor =0.15*"); + CHECK_FALSE(ms.is_simple()); + } } } - TEST(match_spec, is_simple) + TEST_SUITE("history") { + TEST_CASE("user_request") { - MatchSpec ms("libblas"); - EXPECT_TRUE(ms.is_simple()); - } - { - MatchSpec ms("libblas=12.9=abcdef"); - EXPECT_FALSE(ms.is_simple()); - } - { - MatchSpec ms("libblas=0.15*"); - EXPECT_FALSE(ms.is_simple()); - } - { - MatchSpec ms("libblas[version=12.2]"); - EXPECT_FALSE(ms.is_simple()); - } - { - MatchSpec ms("xtensor =0.15*"); - EXPECT_FALSE(ms.is_simple()); + auto u = History::UserRequest::prefilled(); + // update in 100 years! + CHECK_EQ(u.date[0], '2'); + CHECK_EQ(u.date[1], '0'); } } - TEST(history, user_request) + TEST_SUITE("output") { - auto u = History::UserRequest::prefilled(); - // update in 100 years! - EXPECT_TRUE(u.date[0] == '2' && u.date[1] == '0'); - } - - TEST(output, hide_secrets) - { - auto res = Console::instance().hide_secrets("http://myweb.com/t/my-12345-token/test.repo"); - EXPECT_EQ(res, "http://myweb.com/t/*****/test.repo"); - - res = Console::instance().hide_secrets("http://root:secretpassword@myweb.com/test.repo"); - EXPECT_EQ(res, "http://root:*****@myweb.com/test.repo"); - - res = Console::instance().hide_secrets( - "http://root:secretpassword@myweb.com/test.repo http://root:secretpassword@myweb.com/test.repo" - ); - EXPECT_EQ(res, "http://root:*****@myweb.com/test.repo http://root:*****@myweb.com/test.repo"); - - res = Console::instance().hide_secrets( - "http://root:secretpassword@myweb.com/test.repo\nhttp://myweb.com/t/my-12345-token/test.repo http://myweb.com/t/my-12345-token/test.repo http://root:secretpassword@myweb.com/test.repo" - ); - EXPECT_EQ( - res, - "http://root:*****@myweb.com/test.repo\nhttp://myweb.com/t/*****/test.repo http://myweb.com/t/*****/test.repo http://root:*****@myweb.com/test.repo" - ); + TEST_CASE("hide_secrets") + { + auto res = Console::instance().hide_secrets("http://myweb.com/t/my-12345-token/test.repo"); + CHECK_EQ(res, "http://myweb.com/t/*****/test.repo"); - res = Console::instance().hide_secrets("myweb.com/t/my-12345-token/test.repo"); - EXPECT_EQ(res, "myweb.com/t/*****/test.repo"); + res = Console::instance().hide_secrets("http://root:secretpassword@myweb.com/test.repo"); + CHECK_EQ(res, "http://root:*****@myweb.com/test.repo"); - res = Console::instance().hide_secrets("root:secretpassword@myweb.com/test.repo"); - EXPECT_EQ(res, "root:*****@myweb.com/test.repo"); - } + res = Console::instance().hide_secrets( + "http://root:secretpassword@myweb.com/test.repo http://root:secretpassword@myweb.com/test.repo" + ); + CHECK_EQ(res, "http://root:*****@myweb.com/test.repo http://root:*****@myweb.com/test.repo"); + res = Console::instance().hide_secrets( + "http://root:secretpassword@myweb.com/test.repo\nhttp://myweb.com/t/my-12345-token/test.repo http://myweb.com/t/my-12345-token/test.repo http://root:secretpassword@myweb.com/test.repo" + ); + CHECK_EQ( + res, + "http://root:*****@myweb.com/test.repo\nhttp://myweb.com/t/*****/test.repo http://myweb.com/t/*****/test.repo http://root:*****@myweb.com/test.repo" + ); - class OutputPromptTests : public testing::TestWithParam> - { - }; + res = Console::instance().hide_secrets("myweb.com/t/my-12345-token/test.repo"); + CHECK_EQ(res, "myweb.com/t/*****/test.repo"); - TEST_P(OutputPromptTests, prompt) - { - auto params = GetParam(); + res = Console::instance().hide_secrets("root:secretpassword@myweb.com/test.repo"); + CHECK_EQ(res, "root:*****@myweb.com/test.repo"); + } - std::stringstream test_stream; - test_stream << std::get<0>(params) << std::endl; - EXPECT_EQ( - Console::instance().prompt("Test prompt", std::get<1>(params), test_stream), - std::get<2>(params) - ); + // Note: this was initially a value-parametrized test; unfortunately, + // doctest does not support this feature yet. + TEST_CASE("prompt") + { + using param_type = std::tuple; + std::vector param_values = { + std::make_tuple("y", 'y', true), std::make_tuple("yes", 'y', true), + std::make_tuple("Y", 'y', true), std::make_tuple("Yes", 'y', true), + std::make_tuple("", 'y', true), std::make_tuple("n", 'y', false), + std::make_tuple("no", 'y', false), std::make_tuple("N", 'y', false), + std::make_tuple("No", 'y', false), + + std::make_tuple("y", 'n', true), std::make_tuple("yes", 'n', true), + std::make_tuple("Y", 'n', true), std::make_tuple("Yes", 'n', true), + std::make_tuple("", 'n', false), std::make_tuple("n", 'n', false), + std::make_tuple("no", 'n', false), std::make_tuple("N", 'n', false), + std::make_tuple("No", 'n', false) + }; + + for (const auto& p : param_values) + { + CAPTURE(p); + std::stringstream test_stream; + test_stream << std::get<0>(p) << std::endl; + CHECK_EQ( + Console::instance().prompt("Test prompt", std::get<1>(p), test_stream), + std::get<2>(p) + ); + } + } } - INSTANTIATE_TEST_SUITE_P( - output, - OutputPromptTests, - testing::Values( - std::make_tuple("y", 'y', true), - std::make_tuple("yes", 'y', true), - std::make_tuple("Y", 'y', true), - std::make_tuple("Yes", 'y', true), - std::make_tuple("", 'y', true), - std::make_tuple("n", 'y', false), - std::make_tuple("no", 'y', false), - std::make_tuple("N", 'y', false), - std::make_tuple("No", 'y', false), - - std::make_tuple("y", 'n', true), - std::make_tuple("yes", 'n', true), - std::make_tuple("Y", 'n', true), - std::make_tuple("Yes", 'n', true), - std::make_tuple("", 'n', false), - std::make_tuple("n", 'n', false), - std::make_tuple("no", 'n', false), - std::make_tuple("N", 'n', false), - std::make_tuple("No", 'n', false) - ) - ); - - TEST(context, env_name) + TEST_SUITE("context") { - if constexpr (on_mac || on_linux) + TEST_CASE("env_name") { - auto& ctx = Context::instance(); - ctx.root_prefix = "/home/user/micromamba/"; - ctx.envs_dirs = { ctx.root_prefix / "envs" }; - fs::u8path prefix = "/home/user/micromamba/envs/testprefix"; - - EXPECT_EQ(env_name(prefix), "testprefix"); - prefix = "/home/user/micromamba/envs/a.txt"; - EXPECT_EQ(env_name(prefix), "a.txt"); - prefix = "/home/user/micromamba/envs/a.txt"; - EXPECT_EQ(env_name(prefix), "a.txt"); - prefix = "/home/user/micromamba/envs/abc/a.txt"; - EXPECT_EQ(env_name(prefix), "/home/user/micromamba/envs/abc/a.txt"); - prefix = "/home/user/env"; - EXPECT_EQ(env_name(prefix), "/home/user/env"); - -// Workaround MSVC treating warning C4102 as an error in old version of MSVC, -// here triggered by GTest's macro implementation. + if constexpr (on_mac || on_linux) + { + auto& ctx = Context::instance(); + ctx.root_prefix = "/home/user/micromamba/"; + ctx.envs_dirs = { ctx.root_prefix / "envs" }; + fs::u8path prefix = "/home/user/micromamba/envs/testprefix"; + + CHECK_EQ(env_name(prefix), "testprefix"); + prefix = "/home/user/micromamba/envs/a.txt"; + CHECK_EQ(env_name(prefix), "a.txt"); + prefix = "/home/user/micromamba/envs/a.txt"; + CHECK_EQ(env_name(prefix), "a.txt"); + prefix = "/home/user/micromamba/envs/abc/a.txt"; + CHECK_EQ(env_name(prefix), "/home/user/micromamba/envs/abc/a.txt"); + prefix = "/home/user/env"; + CHECK_EQ(env_name(prefix), "/home/user/env"); + + // Workaround MSVC treating warning C4102 as an error in old version of MSVC, + // here triggered by GTest's macro implementation. #if defined(_MSC_VER) && _MSC_VER > 1920 - EXPECT_THROW(locate_prefix_by_name("test"), std::runtime_error); + CHECK_THROWS_AS(locate_prefix_by_name("test"), std::runtime_error); #endif - // TODO implement tests for locate_prefix_by_name + // TODO implement tests for locate_prefix_by_name + } } } - TEST(fsutil, starts_with_home) + TEST_SUITE("fsutil") { - if (on_linux) + TEST_CASE("starts_with_home") { - auto home = env::expand_user("~"); - EXPECT_EQ(path::starts_with_home(home / "test" / "file.txt"), true); - EXPECT_EQ(path::starts_with_home("~"), true); - EXPECT_EQ(path::starts_with_home("/opt/bin"), false); + if (on_linux) + { + auto home = env::expand_user("~"); + CHECK_EQ(path::starts_with_home(home / "test" / "file.txt"), true); + CHECK_EQ(path::starts_with_home("~"), true); + CHECK_EQ(path::starts_with_home("/opt/bin"), false); + } } - } - - TEST(fsutil, expand_user) - { - fs::u8path pbefore = "/tmp/test/xyz.txt"; - fs::u8path p = env::expand_user(pbefore); - EXPECT_EQ(p, pbefore); - } - TEST(fsutil, touch) - { - if (on_linux) + TEST_CASE("expand_user") { - path::touch("/tmp/dir/file.txt", true); - EXPECT_TRUE(fs::exists("/tmp/dir/file.txt")); + fs::u8path pbefore = "/tmp/test/xyz.txt"; + fs::u8path p = env::expand_user(pbefore); + CHECK_EQ(p, pbefore); } - } - TEST(link, replace_long_shebang) - { - if (!on_win) + TEST_CASE("touch") { - std::string res = replace_long_shebang( - "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong/python -o test -x" - ); if (on_linux) { - EXPECT_EQ(res, "#!/usr/bin/env python -o test -x"); - } - else - { - EXPECT_EQ( - res, - "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong/python -o test -x" - ); + path::touch("/tmp/dir/file.txt", true); + CHECK(fs::exists("/tmp/dir/file.txt")); } + } + } - if (on_linux) + TEST_SUITE("link") + { + TEST_CASE("replace_long_shebang") + { + if (!on_win) { - res = replace_long_shebang( - "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/python -o test -x" - ); - EXPECT_EQ(res, "#!/usr/bin/env python -o test -x"); - res = replace_long_shebang( - "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt hon -o test -x" - ); - EXPECT_EQ(res, "#!/usr/bin/env pyt hon -o test -x"); - res = replace_long_shebang( - "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt\\ hon -o test -x" - ); - EXPECT_EQ(res, "#!/usr/bin/env pyt\\ hon -o test -x"); - res = replace_long_shebang( - "#! /this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt\\ hon -o test -x" + std::string res = replace_long_shebang( + "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong/python -o test -x" ); - EXPECT_EQ(res, "#!/usr/bin/env pyt\\ hon -o test -x"); - res = replace_long_shebang( - "#! /this/is/looooooooooooooooooooooooooooooooooooooooooooo\\ \\ ooooooo\\ oooooo\\ oooooo\\ ooooooooooooooooo\\ ooooooooooooooooooong/pyt\\ hon -o \"te st\" -x" + if (on_linux) + { + CHECK_EQ(res, "#!/usr/bin/env python -o test -x"); + } + else + { + CHECK_EQ( + res, + "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong/python -o test -x" + ); + } + + if (on_linux) + { + res = replace_long_shebang( + "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/python -o test -x" + ); + CHECK_EQ(res, "#!/usr/bin/env python -o test -x"); + res = replace_long_shebang( + "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt hon -o test -x" + ); + CHECK_EQ(res, "#!/usr/bin/env pyt hon -o test -x"); + res = replace_long_shebang( + "#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt\\ hon -o test -x" + ); + CHECK_EQ(res, "#!/usr/bin/env pyt\\ hon -o test -x"); + res = replace_long_shebang( + "#! /this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooo\\ oooooo\\ oooooo\\ oooooooooooooooooooooooooooooooooooong/pyt\\ hon -o test -x" + ); + CHECK_EQ(res, "#!/usr/bin/env pyt\\ hon -o test -x"); + res = replace_long_shebang( + "#! /this/is/looooooooooooooooooooooooooooooooooooooooooooo\\ \\ ooooooo\\ oooooo\\ oooooo\\ ooooooooooooooooo\\ ooooooooooooooooooong/pyt\\ hon -o \"te st\" -x" + ); + CHECK_EQ(res, "#!/usr/bin/env pyt\\ hon -o \"te st\" -x"); + } + + std::string shebang = fmt::format( + "#!/{}/bin/python -o test 123 -x", + std::string(500, 'a') ); - EXPECT_EQ(res, "#!/usr/bin/env pyt\\ hon -o \"te st\" -x"); + res = replace_long_shebang(shebang); + CHECK_EQ(res, "#!/usr/bin/env python -o test 123 -x"); + shebang = fmt::format("#!/{}/bin/python -o test 123 -x", std::string(500, 'a')); + shebang[299] = '\\'; + shebang[300] = ' '; + res = replace_long_shebang(shebang); + CHECK_EQ(res, "#!/usr/bin/env python -o test 123 -x"); } - - std::string shebang = fmt::format("#!/{}/bin/python -o test 123 -x", std::string(500, 'a')); - res = replace_long_shebang(shebang); - EXPECT_EQ(res, "#!/usr/bin/env python -o test 123 -x"); - shebang = fmt::format("#!/{}/bin/python -o test 123 -x", std::string(500, 'a')); - shebang[299] = '\\'; - shebang[300] = ' '; - res = replace_long_shebang(shebang); - EXPECT_EQ(res, "#!/usr/bin/env python -o test 123 -x"); } - } - TEST(link, python_shebang) - { - auto res = python_shebang("/usr/bin/python"); - EXPECT_EQ(res, "#!/usr/bin/python"); - res = python_shebang("/usr/bin/pyth on with spaces"); - EXPECT_EQ(res, "#!/bin/sh\n'''exec' \"/usr/bin/pyth on with spaces\" \"$0\" \"$@\" #'''"); - } + TEST_CASE("python_shebang") + { + auto res = python_shebang("/usr/bin/python"); + CHECK_EQ(res, "#!/usr/bin/python"); + res = python_shebang("/usr/bin/pyth on with spaces"); + CHECK_EQ(res, "#!/bin/sh\n'''exec' \"/usr/bin/pyth on with spaces\" \"$0\" \"$@\" #'''"); + } - TEST(link, shebang_regex_matches) - { - std::string shebang = "#!/simple/shebang"; - std::smatch s; - auto match = std::regex_match(shebang, s, shebang_regex); - EXPECT_TRUE(match); - EXPECT_EQ(s[0].str(), "#!/simple/shebang"); - EXPECT_EQ(s[1].str(), "#!/simple/shebang"); - EXPECT_EQ(s[2].str(), "/simple/shebang"); - EXPECT_EQ(s[3].str(), ""); - - // // with spaces - shebang = "#! /simple/shebang"; - match = std::regex_match(shebang, s, shebang_regex); - EXPECT_TRUE(match); - EXPECT_EQ(s[0].str(), "#! /simple/shebang"); - EXPECT_EQ(s[1].str(), "#! /simple/shebang"); - EXPECT_EQ(s[2].str(), "/simple/shebang"); - EXPECT_EQ(s[3].str(), ""); - - // with escaped spaces and flags - shebang = "#!/simple/shebang/escaped\\ space --and --flags -x"; - match = std::regex_match(shebang, s, shebang_regex); - EXPECT_TRUE(match); - EXPECT_EQ(s[0].str(), "#!/simple/shebang/escaped\\ space --and --flags -x"); - EXPECT_EQ(s[1].str(), "#!/simple/shebang/escaped\\ space --and --flags -x"); - EXPECT_EQ(s[2].str(), "/simple/shebang/escaped\\ space"); - EXPECT_EQ(s[3].str(), " --and --flags -x"); + TEST_CASE("shebang_regex_matches") + { + std::string shebang = "#!/simple/shebang"; + std::smatch s; + auto match = std::regex_match(shebang, s, shebang_regex); + CHECK(match); + CHECK_EQ(s[0].str(), "#!/simple/shebang"); + CHECK_EQ(s[1].str(), "#!/simple/shebang"); + CHECK_EQ(s[2].str(), "/simple/shebang"); + CHECK_EQ(s[3].str(), ""); + + // // with spaces + shebang = "#! /simple/shebang"; + match = std::regex_match(shebang, s, shebang_regex); + CHECK(match); + CHECK_EQ(s[0].str(), "#! /simple/shebang"); + CHECK_EQ(s[1].str(), "#! /simple/shebang"); + CHECK_EQ(s[2].str(), "/simple/shebang"); + CHECK_EQ(s[3].str(), ""); + + // with escaped spaces and flags + shebang = "#!/simple/shebang/escaped\\ space --and --flags -x"; + match = std::regex_match(shebang, s, shebang_regex); + CHECK(match); + CHECK_EQ(s[0].str(), "#!/simple/shebang/escaped\\ space --and --flags -x"); + CHECK_EQ(s[1].str(), "#!/simple/shebang/escaped\\ space --and --flags -x"); + CHECK_EQ(s[2].str(), "/simple/shebang/escaped\\ space"); + CHECK_EQ(s[3].str(), " --and --flags -x"); + } } - TEST(utils, quote_for_shell) + TEST_SUITE("utils") { - if (!on_win) + TEST_CASE("quote_for_shell") { - std::vector args1 = { "python", "-c", "print('is\ngreat')" }; - EXPECT_EQ(quote_for_shell(args1), "python -c 'print('\"'\"'is\ngreat'\"'\"')'"); - std::vector args2 = { "python", "-c", "print(\"is great\")" }; - EXPECT_EQ(quote_for_shell(args2), "python -c 'print(\"is great\")'"); - std::vector args3 = { "python", "very nice", "print(\"is great\")" }; - EXPECT_EQ(quote_for_shell(args3), "python 'very nice' 'print(\"is great\")'"); - std::vector args4 = { "pyt \t tab", "very nice", "print(\"is great\")" }; - EXPECT_EQ(quote_for_shell(args4), "'pyt \t tab' 'very nice' 'print(\"is great\")'"); - std::vector args5 = { "echo", "(" }; - EXPECT_EQ(quote_for_shell(args5), "echo '('"); - std::vector args6 = { "echo", "foo'bar\nspam" }; - EXPECT_EQ(quote_for_shell(args6), "echo 'foo'\"'\"'bar\nspam'"); - } + if (!on_win) + { + std::vector args1 = { "python", "-c", "print('is\ngreat')" }; + CHECK_EQ(quote_for_shell(args1), "python -c 'print('\"'\"'is\ngreat'\"'\"')'"); + std::vector args2 = { "python", "-c", "print(\"is great\")" }; + CHECK_EQ(quote_for_shell(args2), "python -c 'print(\"is great\")'"); + std::vector args3 = { "python", "very nice", "print(\"is great\")" }; + CHECK_EQ(quote_for_shell(args3), "python 'very nice' 'print(\"is great\")'"); + std::vector args4 = { "pyt \t tab", "very nice", "print(\"is great\")" }; + CHECK_EQ(quote_for_shell(args4), "'pyt \t tab' 'very nice' 'print(\"is great\")'"); + std::vector args5 = { "echo", "(" }; + CHECK_EQ(quote_for_shell(args5), "echo '('"); + std::vector args6 = { "echo", "foo'bar\nspam" }; + CHECK_EQ(quote_for_shell(args6), "echo 'foo'\"'\"'bar\nspam'"); + } - std::vector args1 = { "a b c", "d", "e" }; - EXPECT_EQ(quote_for_shell(args1, "cmdexe"), "\"a b c\" d e"); - std::vector args2 = { "ab\"c", "\\", "d" }; - EXPECT_EQ(quote_for_shell(args2, "cmdexe"), "ab\\\"c \\ d"); - std::vector args3 = { "ab\"c", " \\", "d" }; - EXPECT_EQ(quote_for_shell(args3, "cmdexe"), "ab\\\"c \" \\\\\" d"); - std::vector args4 = { "a\\\\\\b", "de fg", "h" }; - EXPECT_EQ(quote_for_shell(args4, "cmdexe"), "a\\\\\\b \"de fg\" h"); - std::vector args5 = { "a\\\"b", "c", "d" }; - EXPECT_EQ(quote_for_shell(args5, "cmdexe"), "a\\\\\\\"b c d"); - std::vector args6 = { "a\\\\b c", "d", "e" }; - EXPECT_EQ(quote_for_shell(args6, "cmdexe"), "\"a\\\\b c\" d e"); - std::vector args7 = { "a\\\\b\\ c", "d", "e" }; - EXPECT_EQ(quote_for_shell(args7, "cmdexe"), "\"a\\\\b\\ c\" d e"); - std::vector args8 = { "ab", "" }; - EXPECT_EQ(quote_for_shell(args8, "cmdexe"), "ab \"\""); - } + std::vector args1 = { "a b c", "d", "e" }; + CHECK_EQ(quote_for_shell(args1, "cmdexe"), "\"a b c\" d e"); + std::vector args2 = { "ab\"c", "\\", "d" }; + CHECK_EQ(quote_for_shell(args2, "cmdexe"), "ab\\\"c \\ d"); + std::vector args3 = { "ab\"c", " \\", "d" }; + CHECK_EQ(quote_for_shell(args3, "cmdexe"), "ab\\\"c \" \\\\\" d"); + std::vector args4 = { "a\\\\\\b", "de fg", "h" }; + CHECK_EQ(quote_for_shell(args4, "cmdexe"), "a\\\\\\b \"de fg\" h"); + std::vector args5 = { "a\\\"b", "c", "d" }; + CHECK_EQ(quote_for_shell(args5, "cmdexe"), "a\\\\\\\"b c d"); + std::vector args6 = { "a\\\\b c", "d", "e" }; + CHECK_EQ(quote_for_shell(args6, "cmdexe"), "\"a\\\\b c\" d e"); + std::vector args7 = { "a\\\\b\\ c", "d", "e" }; + CHECK_EQ(quote_for_shell(args7, "cmdexe"), "\"a\\\\b\\ c\" d e"); + std::vector args8 = { "ab", "" }; + CHECK_EQ(quote_for_shell(args8, "cmdexe"), "ab \"\""); + } - TEST(utils, lexists) - { - fs::create_symlink("empty_target", "nonexistinglink"); - EXPECT_FALSE(fs::exists("nonexistinglink")); - EXPECT_TRUE(lexists("nonexistinglink")); - fs::remove("nonexistinglink"); - EXPECT_FALSE(fs::exists("nonexistinglink")); - EXPECT_FALSE(lexists("nonexistinglink")); - - path::touch("emptytestfile"); - EXPECT_TRUE(fs::exists("emptytestfile")); - EXPECT_TRUE(lexists("emptytestfile")); - fs::create_symlink("emptytestfile", "existinglink"); - EXPECT_TRUE(fs::exists("existinglink")); - EXPECT_TRUE(lexists("existinglink")); - - fs::remove("existinglink"); - EXPECT_FALSE(fs::exists("existinglink")); - EXPECT_FALSE(lexists("existinglink")); - fs::remove("emptytestfile"); - EXPECT_FALSE(fs::exists("emptytestfile")); - EXPECT_FALSE(lexists("emptytestfile")); - - std::error_code ec; - EXPECT_FALSE(lexists("completelyinexistent", ec)); - EXPECT_FALSE(ec); - - EXPECT_FALSE(fs::exists("completelyinexistent", ec)); - EXPECT_FALSE(ec); + TEST_CASE("lexists") + { + fs::create_symlink("empty_target", "nonexistinglink"); + CHECK_FALSE(fs::exists("nonexistinglink")); + CHECK(lexists("nonexistinglink")); + fs::remove("nonexistinglink"); + CHECK_FALSE(fs::exists("nonexistinglink")); + CHECK_FALSE(lexists("nonexistinglink")); + + path::touch("emptytestfile"); + CHECK(fs::exists("emptytestfile")); + CHECK(lexists("emptytestfile")); + fs::create_symlink("emptytestfile", "existinglink"); + CHECK(fs::exists("existinglink")); + CHECK(lexists("existinglink")); + + fs::remove("existinglink"); + CHECK_FALSE(fs::exists("existinglink")); + CHECK_FALSE(lexists("existinglink")); + fs::remove("emptytestfile"); + CHECK_FALSE(fs::exists("emptytestfile")); + CHECK_FALSE(lexists("emptytestfile")); + + std::error_code ec; + CHECK_FALSE(lexists("completelyinexistent", ec)); + CHECK_FALSE(ec); + + CHECK_FALSE(fs::exists("completelyinexistent", ec)); + CHECK_FALSE(ec); + } } namespace detail @@ -556,85 +571,90 @@ namespace mamba } #endif - TEST(subdirdata, parse_mod_etag) + TEST_SUITE("subdirdata") { - bool old_value = Context::instance().repodata_use_zst; - Context::instance().repodata_use_zst = true; - fs::u8path cache_folder = fs::u8path{ test_data_dir / "repodata_json_cache" }; - auto mq = detail::read_metadata(cache_folder / "test_1.json"); - EXPECT_TRUE(mq.has_value()); - auto j = mq.value(); - EXPECT_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); - EXPECT_EQ( - j.url, - "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" - ); + TEST_CASE("parse_mod_etag") + { + bool old_value = Context::instance().repodata_use_zst; + Context::instance().repodata_use_zst = true; + fs::u8path cache_folder = fs::u8path{ test_data_dir / "repodata_json_cache" }; + auto mq = detail::read_metadata(cache_folder / "test_1.json"); + CHECK(mq.has_value()); + auto j = mq.value(); + CHECK_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); + CHECK_EQ( + j.url, + "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" + ); - j = detail::read_metadata(cache_folder / "test_2.json").value(); - EXPECT_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); - EXPECT_EQ( - j.url, - "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" - ); + j = detail::read_metadata(cache_folder / "test_2.json").value(); + CHECK_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); + CHECK_EQ( + j.url, + "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" + ); - j = detail::read_metadata(cache_folder / "test_5.json").value(); - EXPECT_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); - EXPECT_EQ( - j.url, - "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" - ); + j = detail::read_metadata(cache_folder / "test_5.json").value(); + CHECK_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); + CHECK_EQ( + j.url, + "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" + ); - j = detail::read_metadata(cache_folder / "test_4.json").value(); - EXPECT_EQ(j.cache_control, "{{}}\",,,\""); - EXPECT_EQ(j.etag, "\n\n\"\"randome ecx,,ssd\n,,\""); - EXPECT_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); - EXPECT_EQ( - j.url, - "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" - ); + j = detail::read_metadata(cache_folder / "test_4.json").value(); + CHECK_EQ(j.cache_control, "{{}}\",,,\""); + CHECK_EQ(j.etag, "\n\n\"\"randome ecx,,ssd\n,,\""); + CHECK_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); + CHECK_EQ( + j.url, + "file:///Users/wolfvollprecht/Programs/mamba/mamba/tests/channel_a/linux-64/repodata.json" + ); - mq = detail::read_metadata(cache_folder / "test_3.json"); - EXPECT_TRUE(mq.has_value() == false); + mq = detail::read_metadata(cache_folder / "test_3.json"); + CHECK(mq.has_value() == false); - j = detail::read_metadata(cache_folder / "test_6.json").value(); - EXPECT_EQ(j.mod, "Thu, 02 Apr 2020 20:21:27 GMT"); - EXPECT_EQ(j.url, "https://conda.anaconda.org/intake/osx-arm64"); + j = detail::read_metadata(cache_folder / "test_6.json").value(); + CHECK_EQ(j.mod, "Thu, 02 Apr 2020 20:21:27 GMT"); + CHECK_EQ(j.url, "https://conda.anaconda.org/intake/osx-arm64"); - auto state_file = cache_folder / "test_7.state.json"; - // set file_mtime + auto state_file = cache_folder / "test_7.state.json"; + // set file_mtime - { + { #ifdef _WIN32 - auto file_mtime = filetime_to_unix_test(fs::last_write_time(cache_folder / "test_7.json")); + auto file_mtime = filetime_to_unix_test( + fs::last_write_time(cache_folder / "test_7.json") + ); #else - auto file_mtime = fs::last_write_time(cache_folder / "test_7.json"); + auto file_mtime = fs::last_write_time(cache_folder / "test_7.json"); #endif - // auto file_size = fs::file_size(state_file); - auto ifs = open_ifstream(state_file, std::ios::in | std::ios::binary); - auto jstate = nlohmann::json::parse(ifs); - ifs.close(); - auto nsecs = std::chrono::duration_cast( - file_mtime.time_since_epoch() - ); - jstate["mtime_ns"] = nsecs.count(); + // auto file_size = fs::file_size(state_file); + auto ifs = open_ifstream(state_file, std::ios::in | std::ios::binary); + auto jstate = nlohmann::json::parse(ifs); + ifs.close(); + auto nsecs = std::chrono::duration_cast( + file_mtime.time_since_epoch() + ); + jstate["mtime_ns"] = nsecs.count(); - auto file_size = fs::file_size(cache_folder / "test_7.json"); - jstate["size"] = file_size; + auto file_size = fs::file_size(cache_folder / "test_7.json"); + jstate["size"] = file_size; - auto ofs = open_ofstream(state_file); - ofs << jstate.dump(4); - } + auto ofs = open_ofstream(state_file); + ofs << jstate.dump(4); + } - j = detail::read_metadata(cache_folder / "test_7.json").value(); - EXPECT_EQ(j.cache_control, "something"); - EXPECT_EQ(j.etag, "something else"); - EXPECT_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); - EXPECT_EQ(j.url, "https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst"); - EXPECT_EQ(j.has_zst.value().value, true); - EXPECT_EQ(j.has_zst.value().last_checked, parse_utc_timestamp("2023-01-06T16:33:06Z")); + j = detail::read_metadata(cache_folder / "test_7.json").value(); + CHECK_EQ(j.cache_control, "something"); + CHECK_EQ(j.etag, "something else"); + CHECK_EQ(j.mod, "Fri, 11 Feb 2022 13:52:44 GMT"); + CHECK_EQ(j.url, "https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst"); + CHECK_EQ(j.has_zst.value().value, true); + CHECK_EQ(j.has_zst.value().last_checked, parse_utc_timestamp("2023-01-06T16:33:06Z")); - Context::instance().repodata_use_zst = old_value; + Context::instance().repodata_use_zst = old_value; + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_env_file_reading.cpp b/libmamba/tests/src/core/test_env_file_reading.cpp index 86f56a3193..5d649bcc50 100644 --- a/libmamba/tests/src/core/test_env_file_reading.cpp +++ b/libmamba/tests/src/core/test_env_file_reading.cpp @@ -1,73 +1,82 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/api/install.hpp" +#include "doctest/doctest.h" + #include "test_data.hpp" namespace mamba { - TEST(env_file_reading, selector) + TEST_SUITE("env_file_reading") { - using namespace detail; - if constexpr (on_linux || on_mac) + TEST_CASE("selector") { - EXPECT_TRUE(eval_selector("sel(unix)")); - if (on_mac) + using namespace detail; + if constexpr (on_linux || on_mac) { - EXPECT_TRUE(eval_selector("sel(osx)")); - EXPECT_FALSE(eval_selector("sel(linux)")); - EXPECT_FALSE(eval_selector("sel(win)")); + CHECK(eval_selector("sel(unix)")); + if (on_mac) + { + CHECK(eval_selector("sel(osx)")); + CHECK_FALSE(eval_selector("sel(linux)")); + CHECK_FALSE(eval_selector("sel(win)")); + } + else + { + CHECK(eval_selector("sel(linux)")); + CHECK_FALSE(eval_selector("sel(osx)")); + CHECK_FALSE(eval_selector("sel(win)")); + } } - else + else if (on_win) { - EXPECT_TRUE(eval_selector("sel(linux)")); - EXPECT_FALSE(eval_selector("sel(osx)")); - EXPECT_FALSE(eval_selector("sel(win)")); + CHECK(eval_selector("sel(win)")); + CHECK_FALSE(eval_selector("sel(osx)")); + CHECK_FALSE(eval_selector("sel(linux)")); } } - else if (on_win) - { - EXPECT_TRUE(eval_selector("sel(win)")); - EXPECT_FALSE(eval_selector("sel(osx)")); - EXPECT_FALSE(eval_selector("sel(linux)")); - } - } - TEST(env_file_reading, specs_selection) - { - using V = std::vector; - auto res = detail::read_yaml_file(test_data_dir / "env_file/env_1.yaml"); - EXPECT_EQ(res.name, "env_1"); - EXPECT_EQ(res.channels, V({ "conda-forge", "bioconda" })); - EXPECT_EQ(res.dependencies, V({ "test1", "test2", "test3" })); - EXPECT_FALSE(res.others_pkg_mgrs_specs.size()); + TEST_CASE("specs_selection") + { + using V = std::vector; + auto res = detail::read_yaml_file(test_data_dir / "env_file/env_1.yaml"); + CHECK_EQ(res.name, "env_1"); + CHECK_EQ(res.channels, V({ "conda-forge", "bioconda" })); + CHECK_EQ(res.dependencies, V({ "test1", "test2", "test3" })); + CHECK_FALSE(res.others_pkg_mgrs_specs.size()); - auto res2 = detail::read_yaml_file(test_data_dir / "env_file/env_2.yaml"); - EXPECT_EQ(res2.name, "env_2"); - EXPECT_EQ(res2.channels, V({ "conda-forge", "bioconda" })); + auto res2 = detail::read_yaml_file(test_data_dir / "env_file/env_2.yaml"); + CHECK_EQ(res2.name, "env_2"); + CHECK_EQ(res2.channels, V({ "conda-forge", "bioconda" })); #ifdef __linux__ - EXPECT_EQ(res2.dependencies, V({ "test1-unix", "test1-linux", "test2-linux", "test4" })); + CHECK_EQ(res2.dependencies, V({ "test1-unix", "test1-linux", "test2-linux", "test4" })); #elif __APPLE__ - EXPECT_EQ(res2.dependencies, V({ "test1-unix", "test1-osx", "test4" })); + CHECK_EQ(res2.dependencies, V({ "test1-unix", "test1-osx", "test4" })); #elif _WIN32 - EXPECT_EQ(res2.dependencies, V({ "test1-win", "test4" })); + CHECK_EQ(res2.dependencies, V({ "test1-win", "test4" })); #endif - EXPECT_FALSE(res2.others_pkg_mgrs_specs.size()); - } + CHECK_FALSE(res2.others_pkg_mgrs_specs.size()); + } - TEST(env_file_reading, external_pkg_mgrs) - { - using V = std::vector; - auto res = detail::read_yaml_file(test_data_dir / "env_file/env_3.yaml"); - EXPECT_EQ(res.name, "env_3"); - EXPECT_EQ(res.channels, V({ "conda-forge", "bioconda" })); - EXPECT_EQ(res.dependencies, V({ "test1", "test2", "test3", "pip" })); + TEST_CASE("external_pkg_mgrs") + { + using V = std::vector; + auto res = detail::read_yaml_file(test_data_dir / "env_file/env_3.yaml"); + CHECK_EQ(res.name, "env_3"); + CHECK_EQ(res.channels, V({ "conda-forge", "bioconda" })); + CHECK_EQ(res.dependencies, V({ "test1", "test2", "test3", "pip" })); - EXPECT_EQ(res.others_pkg_mgrs_specs.size(), 1); - auto o = res.others_pkg_mgrs_specs[0]; - EXPECT_EQ(o.pkg_mgr, "pip"); - EXPECT_EQ(o.deps, V({ "pytest", "numpy" })); - EXPECT_EQ(o.cwd, fs::absolute(test_data_dir / "env_file")); + CHECK_EQ(res.others_pkg_mgrs_specs.size(), 1); + auto o = res.others_pkg_mgrs_specs[0]; + CHECK_EQ(o.pkg_mgr, "pip"); + CHECK_EQ(o.deps, V({ "pytest", "numpy" })); + CHECK_EQ(o.cwd, fs::absolute(test_data_dir / "env_file")); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_env_lockfile.cpp b/libmamba/tests/src/core/test_env_lockfile.cpp index 72ef55b0c9..eed00e9bfb 100644 --- a/libmamba/tests/src/core/test_env_lockfile.cpp +++ b/libmamba/tests/src/core/test_env_lockfile.cpp @@ -1,187 +1,200 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + #include #include "mamba/core/env_lockfile.hpp" #include "mamba/core/fsutil.hpp" #include "mamba/core/transaction.hpp" +#include "doctest/doctest.h" + #include "test_data.hpp" namespace mamba { - TEST(env_lockfile, absent_file_fails) - { - const auto maybe_lockfile = read_environment_lockfile("this/file/does/not/exists"); - ASSERT_FALSE(maybe_lockfile); - const auto error = maybe_lockfile.error(); - ASSERT_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); - - const auto& error_details = EnvLockFileError::get_details(error); - EXPECT_EQ(file_parsing_error_code::parsing_failure, error_details.parsing_error_code); - ASSERT_TRUE(error_details.yaml_error_type); - const std::type_index bad_file_error_id{ typeid(YAML::BadFile) }; - EXPECT_EQ(bad_file_error_id, error_details.yaml_error_type.value()); - - // NOTE: one could attempt to check if opening a file which is not an YAML file - // would fail. Unfortunately YAML parsers will accept any kind of file, - // and assume it is YAML or at worse a comment or raw string. So there - // is no good way to check that. - } - - TEST(env_lockfile, invalid_version_fails) - { - const fs::u8path invalid_version_lockfile_path{ test_data_dir - / "env_lockfile/bad_version-lock.yaml" }; - const auto maybe_lockfile = read_environment_lockfile(invalid_version_lockfile_path); - ASSERT_FALSE(maybe_lockfile); - const auto error = maybe_lockfile.error(); - ASSERT_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); - const auto& error_details = EnvLockFileError::get_details(error); - EXPECT_EQ(file_parsing_error_code::unsuported_version, error_details.parsing_error_code); - } - - TEST(env_lockfile, valid_no_package_succeed) - { - const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/good_no_package-lock.yaml" }; - const auto maybe_lockfile = read_environment_lockfile(lockfile_path); - ASSERT_TRUE(maybe_lockfile) << maybe_lockfile.error().what(); - const auto lockfile = maybe_lockfile.value(); - EXPECT_TRUE(lockfile.get_all_packages().empty()); - } - - TEST(env_lockfile, invalid_package_fails) + TEST_SUITE("env_lockfile") { - const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/bad_package-lock.yaml" }; - const auto maybe_lockfile = read_environment_lockfile(lockfile_path); - ASSERT_FALSE(maybe_lockfile); - const auto error = maybe_lockfile.error(); - ASSERT_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); - const auto& error_details = EnvLockFileError::get_details(error); - EXPECT_EQ(file_parsing_error_code::parsing_failure, error_details.parsing_error_code); - } - - TEST(env_lockfile, valid_one_package_succeed) - { - const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/good_one_package-lock.yaml" }; - const auto maybe_lockfile = read_environment_lockfile(lockfile_path); - ASSERT_TRUE(maybe_lockfile) << maybe_lockfile.error().what(); - const auto lockfile = maybe_lockfile.value(); - EXPECT_EQ(lockfile.get_all_packages().size(), 1); - } - - TEST(env_lockfile, valid_one_package_implicit_category) - { - const fs::u8path lockfile_path{ - test_data_dir / "env_lockfile/good_one_package_missing_category-lock.yaml" - }; - const auto maybe_lockfile = read_environment_lockfile(lockfile_path); - ASSERT_TRUE(maybe_lockfile) << maybe_lockfile.error().what(); - const auto lockfile = maybe_lockfile.value(); - EXPECT_EQ(lockfile.get_all_packages().size(), 1); - } + TEST_CASE("absent_file_fails") + { + const auto maybe_lockfile = read_environment_lockfile("this/file/does/not/exists"); + REQUIRE_FALSE(maybe_lockfile); + const auto error = maybe_lockfile.error(); + REQUIRE_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); + + const auto& error_details = EnvLockFileError::get_details(error); + CHECK_EQ(file_parsing_error_code::parsing_failure, error_details.parsing_error_code); + REQUIRE(error_details.yaml_error_type); + const std::type_index bad_file_error_id{ typeid(YAML::BadFile) }; + CHECK_EQ(bad_file_error_id, error_details.yaml_error_type.value()); + + // NOTE: one could attempt to check if opening a file which is not an YAML file + // would fail. Unfortunately YAML parsers will accept any kind of file, + // and assume it is YAML or at worse a comment or raw string. So there + // is no good way to check that. + } - TEST(env_lockfile, valid_multiple_packages_succeed) - { - const fs::u8path lockfile_path{ test_data_dir - / "env_lockfile/good_multiple_packages-lock.yaml" }; - const auto maybe_lockfile = read_environment_lockfile(lockfile_path); - ASSERT_TRUE(maybe_lockfile) << maybe_lockfile.error().what(); - const auto lockfile = maybe_lockfile.value(); - EXPECT_GT(lockfile.get_all_packages().size(), 1); - } + TEST_CASE("invalid_version_fails") + { + const fs::u8path invalid_version_lockfile_path{ test_data_dir + / "env_lockfile/bad_version-lock.yaml" }; + const auto maybe_lockfile = read_environment_lockfile(invalid_version_lockfile_path); + REQUIRE_FALSE(maybe_lockfile); + const auto error = maybe_lockfile.error(); + REQUIRE_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); + const auto& error_details = EnvLockFileError::get_details(error); + CHECK_EQ(file_parsing_error_code::unsuported_version, error_details.parsing_error_code); + } - TEST(env_lockfile, get_specific_packages) - { - const fs::u8path lockfile_path{ test_data_dir - / "env_lockfile/good_multiple_packages-lock.yaml" }; - const auto lockfile = read_environment_lockfile(lockfile_path).value(); - EXPECT_TRUE(lockfile.get_packages_for("", "", "").empty()); + TEST_CASE("valid_no_package_succeed") { - const auto packages = lockfile.get_packages_for("main", "linux-64", "conda"); - EXPECT_FALSE(packages.empty()); - EXPECT_GT(packages.size(), 4); + const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/good_no_package-lock.yaml" }; + const auto maybe_lockfile = read_environment_lockfile(lockfile_path); + REQUIRE_MESSAGE(maybe_lockfile, maybe_lockfile.error().what()); + const auto lockfile = maybe_lockfile.value(); + CHECK(lockfile.get_all_packages().empty()); } + + TEST_CASE("invalid_package_fails") { - const auto packages = lockfile.get_packages_for("main", "linux-64", "pip"); - EXPECT_FALSE(packages.empty()); - EXPECT_EQ(packages.size(), 2); + const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/bad_package-lock.yaml" }; + const auto maybe_lockfile = read_environment_lockfile(lockfile_path); + REQUIRE_FALSE(maybe_lockfile); + const auto error = maybe_lockfile.error(); + REQUIRE_EQ(mamba_error_code::env_lockfile_parsing_failed, error.error_code()); + const auto& error_details = EnvLockFileError::get_details(error); + CHECK_EQ(file_parsing_error_code::parsing_failure, error_details.parsing_error_code); } - } - TEST(env_lockfile, create_transaction_with_categories) - { - const fs::u8path lockfile_path{ test_data_dir - / "env_lockfile/good_multiple_categories-lock.yaml" }; - MPool pool; - mamba::MultiPackageCache pkg_cache({ "/tmp/" }); + TEST_CASE("valid_one_package_succeed") + { + const fs::u8path lockfile_path{ test_data_dir + / "env_lockfile/good_one_package-lock.yaml" }; + const auto maybe_lockfile = read_environment_lockfile(lockfile_path); + REQUIRE_MESSAGE(maybe_lockfile, maybe_lockfile.error().what()); + const auto lockfile = maybe_lockfile.value(); + CHECK_EQ(lockfile.get_all_packages().size(), 1); + } - auto& ctx = Context::instance(); + TEST_CASE("valid_one_package_implicit_category") + { + const fs::u8path lockfile_path{ + test_data_dir / "env_lockfile/good_one_package_missing_category-lock.yaml" + }; + const auto maybe_lockfile = read_environment_lockfile(lockfile_path); + REQUIRE_MESSAGE(maybe_lockfile, maybe_lockfile.error().what()); + const auto lockfile = maybe_lockfile.value(); + CHECK_EQ(lockfile.get_all_packages().size(), 1); + } - ctx.platform = "linux-64"; + TEST_CASE("valid_multiple_packages_succeed") + { + const fs::u8path lockfile_path{ test_data_dir + / "env_lockfile/good_multiple_packages-lock.yaml" }; + const auto maybe_lockfile = read_environment_lockfile(lockfile_path); + REQUIRE_MESSAGE(maybe_lockfile, maybe_lockfile.error().what()); + const auto lockfile = maybe_lockfile.value(); + CHECK_GT(lockfile.get_all_packages().size(), 1); + } - auto check_categories = - [&](std::vector categories, size_t num_conda, size_t num_pip) + TEST_CASE("get_specific_packages") { - std::vector other_specs; - auto transaction = create_explicit_transaction_from_lockfile( - pool, - lockfile_path, - categories, - pkg_cache, - other_specs - ); - auto to_install = std::get<1>(transaction.to_conda()); - EXPECT_EQ(to_install.size(), num_conda); - if (num_pip == 0) + const fs::u8path lockfile_path{ test_data_dir + / "env_lockfile/good_multiple_packages-lock.yaml" }; + const auto lockfile = read_environment_lockfile(lockfile_path).value(); + CHECK(lockfile.get_packages_for("", "", "").empty()); { - EXPECT_EQ(other_specs.size(), 0); + const auto packages = lockfile.get_packages_for("main", "linux-64", "conda"); + CHECK_FALSE(packages.empty()); + CHECK_GT(packages.size(), 4); } - else { - EXPECT_EQ(other_specs.size(), 1); - EXPECT_EQ(other_specs.at(0).deps.size(), num_pip); + const auto packages = lockfile.get_packages_for("main", "linux-64", "pip"); + CHECK_FALSE(packages.empty()); + CHECK_EQ(packages.size(), 2); } - }; + } - check_categories({ "main" }, 3, 5); - check_categories({ "main", "dev" }, 31, 6); - check_categories({ "dev" }, 28, 1); - check_categories({ "nonesuch" }, 0, 0); - } + TEST_CASE("create_transaction_with_categories") + { + const fs::u8path lockfile_path{ test_data_dir + / "env_lockfile/good_multiple_categories-lock.yaml" }; + MPool pool; + mamba::MultiPackageCache pkg_cache({ "/tmp/" }); + + auto& ctx = Context::instance(); + ctx.platform = "linux-64"; - TEST(is_env_lockfile_name, basics) + auto check_categories = + [&](std::vector categories, size_t num_conda, size_t num_pip) + { + std::vector other_specs; + auto transaction = create_explicit_transaction_from_lockfile( + pool, + lockfile_path, + categories, + pkg_cache, + other_specs + ); + auto to_install = std::get<1>(transaction.to_conda()); + CHECK_EQ(to_install.size(), num_conda); + if (num_pip == 0) + { + CHECK_EQ(other_specs.size(), 0); + } + else + { + CHECK_EQ(other_specs.size(), 1); + CHECK_EQ(other_specs.at(0).deps.size(), num_pip); + } + }; + + check_categories({ "main" }, 3, 5); + check_categories({ "main", "dev" }, 31, 6); + check_categories({ "dev" }, 28, 1); + check_categories({ "nonesuch" }, 0, 0); + } + } + + TEST_SUITE("is_env_lockfile_name") { - EXPECT_TRUE(is_env_lockfile_name("something-lock.yaml")); - EXPECT_TRUE(is_env_lockfile_name("something-lock.yml")); - EXPECT_TRUE(is_env_lockfile_name("/some/dir/something-lock.yaml")); - EXPECT_TRUE(is_env_lockfile_name("/some/dir/something-lock.yml")); - EXPECT_TRUE(is_env_lockfile_name("../../some/dir/something-lock.yaml")); - EXPECT_TRUE(is_env_lockfile_name("../../some/dir/something-lock.yml")); - - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "something-lock.yaml" }.string())); - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "something-lock.yml" }.string())); - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "/some/dir/something-lock.yaml" }.string())); - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "/some/dir/something-lock.yml" }.string())); - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "../../some/dir/something-lock.yaml" }.string())); - EXPECT_TRUE(is_env_lockfile_name(fs::u8path{ "../../some/dir/something-lock.yml" }.string())); - - EXPECT_FALSE(is_env_lockfile_name("something")); - EXPECT_FALSE(is_env_lockfile_name("something-lock")); - EXPECT_FALSE(is_env_lockfile_name("/some/dir/something")); - EXPECT_FALSE(is_env_lockfile_name("../../some/dir/something")); - - EXPECT_FALSE(is_env_lockfile_name("something.yaml")); - EXPECT_FALSE(is_env_lockfile_name("something.yml")); - EXPECT_FALSE(is_env_lockfile_name("/some/dir/something.yaml")); - EXPECT_FALSE(is_env_lockfile_name("/some/dir/something.yml")); - EXPECT_FALSE(is_env_lockfile_name("../../some/dir/something.yaml")); - EXPECT_FALSE(is_env_lockfile_name("../../some/dir/something.yml")); - - EXPECT_FALSE(is_env_lockfile_name(fs::u8path{ "something" }.string())); - EXPECT_FALSE(is_env_lockfile_name(fs::u8path{ "something-lock" }.string())); - EXPECT_FALSE(is_env_lockfile_name(fs::u8path{ "/some/dir/something" }.string())); - EXPECT_FALSE(is_env_lockfile_name(fs::u8path{ "../../some/dir/something" }.string())); + TEST_CASE("basics") + { + CHECK(is_env_lockfile_name("something-lock.yaml")); + CHECK(is_env_lockfile_name("something-lock.yml")); + CHECK(is_env_lockfile_name("/some/dir/something-lock.yaml")); + CHECK(is_env_lockfile_name("/some/dir/something-lock.yml")); + CHECK(is_env_lockfile_name("../../some/dir/something-lock.yaml")); + CHECK(is_env_lockfile_name("../../some/dir/something-lock.yml")); + + CHECK(is_env_lockfile_name(fs::u8path{ "something-lock.yaml" }.string())); + CHECK(is_env_lockfile_name(fs::u8path{ "something-lock.yml" }.string())); + CHECK(is_env_lockfile_name(fs::u8path{ "/some/dir/something-lock.yaml" }.string())); + CHECK(is_env_lockfile_name(fs::u8path{ "/some/dir/something-lock.yml" }.string())); + CHECK(is_env_lockfile_name(fs::u8path{ "../../some/dir/something-lock.yaml" }.string())); + CHECK(is_env_lockfile_name(fs::u8path{ "../../some/dir/something-lock.yml" }.string())); + + CHECK_FALSE(is_env_lockfile_name("something")); + CHECK_FALSE(is_env_lockfile_name("something-lock")); + CHECK_FALSE(is_env_lockfile_name("/some/dir/something")); + CHECK_FALSE(is_env_lockfile_name("../../some/dir/something")); + + CHECK_FALSE(is_env_lockfile_name("something.yaml")); + CHECK_FALSE(is_env_lockfile_name("something.yml")); + CHECK_FALSE(is_env_lockfile_name("/some/dir/something.yaml")); + CHECK_FALSE(is_env_lockfile_name("/some/dir/something.yml")); + CHECK_FALSE(is_env_lockfile_name("../../some/dir/something.yaml")); + CHECK_FALSE(is_env_lockfile_name("../../some/dir/something.yml")); + + CHECK_FALSE(is_env_lockfile_name(fs::u8path{ "something" }.string())); + CHECK_FALSE(is_env_lockfile_name(fs::u8path{ "something-lock" }.string())); + CHECK_FALSE(is_env_lockfile_name(fs::u8path{ "/some/dir/something" }.string())); + CHECK_FALSE(is_env_lockfile_name(fs::u8path{ "../../some/dir/something" }.string())); + } } } diff --git a/libmamba/tests/src/core/test_environments_manager.cpp b/libmamba/tests/src/core/test_environments_manager.cpp index 6e7176c243..e5691b65ba 100644 --- a/libmamba/tests/src/core/test_environments_manager.cpp +++ b/libmamba/tests/src/core/test_environments_manager.cpp @@ -1,50 +1,59 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/core/environment.hpp" #include "mamba/core/environments_manager.hpp" #include "mamba/core/mamba_fs.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(env_manager, all_envs) + TEST_SUITE("env_manager") { - EnvironmentsManager e; - auto prefixes = e.list_all_known_prefixes(); - // Test registering env without `conda-meta/history` file - e.register_env(env::expand_user("~/some/env")); - auto new_prefixes = e.list_all_known_prefixes(); - // the prefix should be cleaned out, because it doesn't have the - // `conda-meta/history` file - EXPECT_EQ(new_prefixes.size(), prefixes.size()); - - // Create an env containing `conda-meta/history` file - // and test register/unregister - auto prefix = env::expand_user("~/some_test_folder/other_env"); - path::touch(prefix / "conda-meta" / "history", true); - - e.register_env(prefix); - new_prefixes = e.list_all_known_prefixes(); - EXPECT_EQ(new_prefixes.size(), prefixes.size() + 1); - - e.unregister_env(prefix); - new_prefixes = e.list_all_known_prefixes(); - EXPECT_EQ(new_prefixes.size(), prefixes.size()); - - // Add another file in addition to `conda-meta/history` - // and test register/unregister - path::touch(prefix / "conda-meta" / "other_file", true); - - e.register_env(prefix); - new_prefixes = e.list_all_known_prefixes(); - EXPECT_EQ(new_prefixes.size(), prefixes.size() + 1); - - e.unregister_env(prefix); - new_prefixes = e.list_all_known_prefixes(); - // Shouldn't unregister because `conda-meta/other_file` - // is there - EXPECT_EQ(new_prefixes.size(), prefixes.size() + 1); - - // Remove test directory - fs::remove_all(env::expand_user("~/some_test_folder")); + TEST_CASE("all_envs") + { + EnvironmentsManager e; + auto prefixes = e.list_all_known_prefixes(); + // Test registering env without `conda-meta/history` file + e.register_env(env::expand_user("~/some/env")); + auto new_prefixes = e.list_all_known_prefixes(); + // the prefix should be cleaned out, because it doesn't have the + // `conda-meta/history` file + CHECK_EQ(new_prefixes.size(), prefixes.size()); + + // Create an env containing `conda-meta/history` file + // and test register/unregister + auto prefix = env::expand_user("~/some_test_folder/other_env"); + path::touch(prefix / "conda-meta" / "history", true); + + e.register_env(prefix); + new_prefixes = e.list_all_known_prefixes(); + CHECK_EQ(new_prefixes.size(), prefixes.size() + 1); + + e.unregister_env(prefix); + new_prefixes = e.list_all_known_prefixes(); + CHECK_EQ(new_prefixes.size(), prefixes.size()); + + // Add another file in addition to `conda-meta/history` + // and test register/unregister + path::touch(prefix / "conda-meta" / "other_file", true); + + e.register_env(prefix); + new_prefixes = e.list_all_known_prefixes(); + CHECK_EQ(new_prefixes.size(), prefixes.size() + 1); + + e.unregister_env(prefix); + new_prefixes = e.list_all_known_prefixes(); + // Shouldn't unregister because `conda-meta/other_file` + // is there + CHECK_EQ(new_prefixes.size(), prefixes.size() + 1); + + // Remove test directory + fs::remove_all(env::expand_user("~/some_test_folder")); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_execution.cpp b/libmamba/tests/src/core/test_execution.cpp index 9e07a90073..afffb7ce52 100644 --- a/libmamba/tests/src/core/test_execution.cpp +++ b/libmamba/tests/src/core/test_execution.cpp @@ -1,7 +1,13 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include +#include "doctest/doctest.h" + namespace mamba { // Spawns a number of threads that will execute the provided task a given number of times. @@ -35,73 +41,75 @@ namespace mamba } } - TEST(execution, stop_default_always_succeeds) - { - MainExecutor::stop_default(); // Make sure no other default main executor is running. - MainExecutor::instance(); // Make sure we use the defaut main executor. - MainExecutor::stop_default(); // Stop the default main executor and make sure it's not - // enabled for the following tests. - MainExecutor::stop_default(); // However the number of time we call it it should never - // fail. - } - - - TEST(execution, manual_executor_construction_destruction) + TEST_SUITE("execution") { - MainExecutor executor; - } + TEST_CASE("stop_default_always_succeeds") + { + MainExecutor::stop_default(); // Make sure no other default main executor is running. + MainExecutor::instance(); // Make sure we use the defaut main executor. + MainExecutor::stop_default(); // Stop the default main executor and make sure it's not + // enabled for the following tests. + MainExecutor::stop_default(); // However the number of time we call it it should never + // fail. + } - TEST(execution, two_main_executors_fails) - { - MainExecutor executor; - ASSERT_THROW(MainExecutor{}, MainExecutorError); - } + TEST_CASE("manual_executor_construction_destruction") + { + MainExecutor executor; + } - TEST(execution, tasks_complete_before_destruction_ends) - { - constexpr std::size_t arbitrary_task_count = 2048; - constexpr std::size_t arbitrary_tasks_per_generator = 24; - std::atomic counter{ 0 }; + TEST_CASE("two_main_executors_fails") { MainExecutor executor; + REQUIRE_THROWS_AS(MainExecutor{}, MainExecutorError); + } - execute_tasks_from_concurrent_threads( - arbitrary_task_count, - arbitrary_tasks_per_generator, - [&] { executor.schedule([&] { ++counter; }); } - ); - } // All threads from the executor must have been joined here. - EXPECT_EQ(counter, arbitrary_task_count); - } + TEST_CASE("tasks_complete_before_destruction_ends") + { + constexpr std::size_t arbitrary_task_count = 2048; + constexpr std::size_t arbitrary_tasks_per_generator = 24; + std::atomic counter{ 0 }; + { + MainExecutor executor; - TEST(execution, closed_prevents_more_scheduling_and_joins) - { - constexpr std::size_t arbitrary_task_count = 2048; - constexpr std::size_t arbitrary_tasks_per_generator = 36; - std::atomic counter{ 0 }; + execute_tasks_from_concurrent_threads( + arbitrary_task_count, + arbitrary_tasks_per_generator, + [&] { executor.schedule([&] { ++counter; }); } + ); + } // All threads from the executor must have been joined here. + CHECK_EQ(counter, arbitrary_task_count); + } + + TEST_CASE("closed_prevents_more_scheduling_and_joins") { - MainExecutor executor; + constexpr std::size_t arbitrary_task_count = 2048; + constexpr std::size_t arbitrary_tasks_per_generator = 36; + std::atomic counter{ 0 }; + { + MainExecutor executor; - execute_tasks_from_concurrent_threads( - arbitrary_task_count, - arbitrary_tasks_per_generator, - [&] { executor.schedule([&] { ++counter; }); } - ); + execute_tasks_from_concurrent_threads( + arbitrary_task_count, + arbitrary_tasks_per_generator, + [&] { executor.schedule([&] { ++counter; }); } + ); - executor.close(); - EXPECT_EQ(counter, arbitrary_task_count); + executor.close(); + CHECK_EQ(counter, arbitrary_task_count); - execute_tasks_from_concurrent_threads( - arbitrary_task_count, - arbitrary_tasks_per_generator, - [&] { executor.schedule([&] { throw "this code must never be executed"; }); } - ); + execute_tasks_from_concurrent_threads( + arbitrary_task_count, + arbitrary_tasks_per_generator, + [&] { executor.schedule([&] { throw "this code must never be executed"; }); } + ); + } + CHECK_EQ( + counter, + arbitrary_task_count + ); // We re-check to make sure no thread are executed anymore + // as soon as `.close()` was called. } - EXPECT_EQ( - counter, - arbitrary_task_count - ); // We re-check to make sure no thread are executed anymore - // as soon as `.close()` was called. } } diff --git a/libmamba/tests/src/core/test_filesystem.cpp b/libmamba/tests/src/core/test_filesystem.cpp index 3acd6f4aa8..9f967d95cb 100644 --- a/libmamba/tests/src/core/test_filesystem.cpp +++ b/libmamba/tests/src/core/test_filesystem.cpp @@ -1,276 +1,292 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. -#include +#include #include "mamba/core/mamba_fs.hpp" #include "mamba/core/util.hpp" #include "mamba/core/util_scope.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(u8path, normalized_separators) + TEST_SUITE("u8path") { - static constexpr auto value = u8"a/b/c"; - std::filesystem::path x{ value }; - const auto y = fs::normalized_separators(x); + TEST_CASE("normalized_separators") + { + static constexpr auto value = u8"a/b/c"; + std::filesystem::path x{ value }; + const auto y = fs::normalized_separators(x); #if defined(_WIN32) - ASSERT_EQ(y.u8string(), u8R"(a\b\c)"); + REQUIRE_EQ(y.u8string(), u8R"(a\b\c)"); #else - ASSERT_EQ(y.u8string(), value); + REQUIRE_EQ(y.u8string(), value); #endif - } - - TEST(u8path, normalized_separators_unicode) - { - static constexpr auto value = u8"日本語"; - const std::filesystem::path x = fs::from_utf8(value); - ASSERT_EQ(x.u8string(), u8"日本語"); // check assumption - const auto y = fs::normalized_separators(x); - ASSERT_EQ(y.u8string(), u8"日本語"); - } - - TEST(u8path, consistent_encoding) - { - const auto utf8_string = u8"日本語"; - const fs::u8path filename(utf8_string); - const auto str = filename.string(); - EXPECT_EQ(str, utf8_string); - - const fs::u8path file_path = fs::temp_directory_path() / filename; - EXPECT_EQ(file_path.filename().string(), utf8_string); - - const auto std_path = file_path.std_path(); - EXPECT_EQ(std_path.filename().u8string(), utf8_string); - } + } - TEST(u8path, string_stream_encoding) - { - const auto utf8_string = u8"日本語"; - const std::string quoted_utf8_string = std::string("\"") + utf8_string + std::string("\""); - const fs::u8path filename(utf8_string); - std::stringstream stream; - stream << filename; - EXPECT_EQ(stream.str(), quoted_utf8_string); - - fs::u8path path_read; - stream.seekg(0); - stream >> path_read; - EXPECT_EQ(path_read.string(), utf8_string); - } + TEST_CASE("normalized_separators_unicode") + { + static constexpr auto value = u8"日本語"; + const std::filesystem::path x = fs::from_utf8(value); + REQUIRE_EQ(x.u8string(), u8"日本語"); // check assumption + const auto y = fs::normalized_separators(x); + REQUIRE_EQ(y.u8string(), u8"日本語"); + } - TEST(u8path, directory_iteration) - { - const auto tmp_dir = fs::temp_directory_path() / "mamba_fs_iteration"; - mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. - const auto file_dir = tmp_dir / "kikoo" / "lol" / u8"日本語"; - const auto file_path = file_dir / u8"joël"; + TEST_CASE("consistent_encoding") + { + const auto utf8_string = u8"日本語"; + const fs::u8path filename(utf8_string); + const auto str = filename.string(); + CHECK_EQ(str, utf8_string); - fs::remove_all(tmp_dir); // Make sure it's not existing from the start. - fs::create_directories(file_dir); + const fs::u8path file_path = fs::temp_directory_path() / filename; + CHECK_EQ(file_path.filename().string(), utf8_string); - { - std::ofstream file(file_path.std_path(), std::ios::binary | std::ios::trunc); - file << u8"日本語"; + const auto std_path = file_path.std_path(); + CHECK_EQ(std_path.filename().u8string(), utf8_string); } + TEST_CASE("string_stream_encoding") { - const auto path_to_search_from = file_dir.parent_path(); - fs::recursive_directory_iterator it{ path_to_search_from }; - auto first_entry = *it; - EXPECT_EQ(first_entry.path(), file_path.parent_path()); - auto secibd_entry = *(++it); - EXPECT_EQ(secibd_entry.path(), file_path); + const auto utf8_string = u8"日本語"; + const std::string quoted_utf8_string = std::string("\"") + utf8_string + + std::string("\""); + const fs::u8path filename(utf8_string); + std::stringstream stream; + stream << filename; + CHECK_EQ(stream.str(), quoted_utf8_string); + + fs::u8path path_read; + stream.seekg(0); + stream >> path_read; + CHECK_EQ(path_read.string(), utf8_string); } + TEST_CASE("directory_iteration") { - const std::vector expected_entries{ - tmp_dir / "kikoo", - tmp_dir / "kikoo" / "lol", - tmp_dir / "kikoo" / "lol" / u8"日本語", - tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël", - }; + const auto tmp_dir = fs::temp_directory_path() / "mamba_fs_iteration"; + mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. + const auto file_dir = tmp_dir / "kikoo" / "lol" / u8"日本語"; + const auto file_path = file_dir / u8"joël"; + + fs::remove_all(tmp_dir); // Make sure it's not existing from the start. + fs::create_directories(file_dir); - std::vector entries_found; - for (const auto& entry : fs::recursive_directory_iterator(tmp_dir)) { - static_assert(std::is_same_v); - entries_found.push_back(entry.path()); + std::ofstream file(file_path.std_path(), std::ios::binary | std::ios::trunc); + file << u8"日本語"; } - EXPECT_EQ(entries_found, expected_entries); - } - { - const std::vector expected_entries{ - (tmp_dir / "kikoo").string(), - (tmp_dir / "kikoo" / "lol").string(), - (tmp_dir / "kikoo" / "lol" / u8"日本語").string(), - (tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël").string(), - }; + { + const auto path_to_search_from = file_dir.parent_path(); + fs::recursive_directory_iterator it{ path_to_search_from }; + auto first_entry = *it; + CHECK_EQ(first_entry.path(), file_path.parent_path()); + auto secibd_entry = *(++it); + CHECK_EQ(secibd_entry.path(), file_path); + } + + { + const std::vector expected_entries{ + tmp_dir / "kikoo", + tmp_dir / "kikoo" / "lol", + tmp_dir / "kikoo" / "lol" / u8"日本語", + tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël", + }; + + std::vector entries_found; + for (const auto& entry : fs::recursive_directory_iterator(tmp_dir)) + { + static_assert(std::is_same_v); + entries_found.push_back(entry.path()); + } + CHECK_EQ(entries_found, expected_entries); + } - std::vector entries_found; - for (const auto& entry : fs::recursive_directory_iterator(tmp_dir)) { - static_assert(std::is_same_v); - entries_found.push_back(entry.path().string()); + const std::vector expected_entries{ + (tmp_dir / "kikoo").string(), + (tmp_dir / "kikoo" / "lol").string(), + (tmp_dir / "kikoo" / "lol" / u8"日本語").string(), + (tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël").string(), + }; + + std::vector entries_found; + for (const auto& entry : fs::recursive_directory_iterator(tmp_dir)) + { + static_assert(std::is_same_v); + entries_found.push_back(entry.path().string()); + } + CHECK_EQ(entries_found, expected_entries); } - EXPECT_EQ(entries_found, expected_entries); - } - { - const std::vector expected_entries{ - tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël", - }; + { + const std::vector expected_entries{ + tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël", + }; + + std::vector entries_found; + for (const auto& entry : fs::directory_iterator(file_dir)) + { + static_assert(std::is_same_v); + entries_found.push_back(entry.path()); + } + CHECK_EQ(entries_found, expected_entries); + } - std::vector entries_found; - for (const auto& entry : fs::directory_iterator(file_dir)) { - static_assert(std::is_same_v); - entries_found.push_back(entry.path()); + const std::vector expected_entries{ + (tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël").string(), + }; + + std::vector entries_found; + for (const auto& entry : fs::directory_iterator(file_dir)) + { + static_assert(std::is_same_v); + entries_found.push_back(entry.path().string()); + } + CHECK_EQ(entries_found, expected_entries); } - EXPECT_EQ(entries_found, expected_entries); } + TEST_CASE("long_paths") { - const std::vector expected_entries{ - (tmp_dir / "kikoo" / "lol" / u8"日本語" / u8"joël").string(), - }; + const auto tmp_dir = fs::temp_directory_path() / "mamba_fs_long_path"; - std::vector entries_found; - for (const auto& entry : fs::directory_iterator(file_dir)) + fs::u8path long_path = tmp_dir; + for (int i = 0; i < 42; ++i) { - static_assert(std::is_same_v); - entries_found.push_back(entry.path().string()); + long_path /= u8"some_very_long_prefix"; } - EXPECT_EQ(entries_found, expected_entries); - } - } - TEST(u8path, long_paths) - { - const auto tmp_dir = fs::temp_directory_path() / "mamba_fs_long_path"; + mamba::on_scope_exit _([&] { fs::remove_all(long_path); }); + fs::create_directories(long_path); + } - fs::u8path long_path = tmp_dir; - for (int i = 0; i < 42; ++i) +#if defined(_WIN32) + TEST_CASE("append_maintains_slash_type") { - long_path /= u8"some_very_long_prefix"; + const fs::u8path path = u8R"(a/b/c/d)"; + const auto path_1 = path / u8R"(e\f\g)"; + CHECK_EQ(path_1.string(), u8R"(a\b\c\d\e\f\g)"); } - - mamba::on_scope_exit _([&] { fs::remove_all(long_path); }); - fs::create_directories(long_path); +#endif } -#if defined(_WIN32) - TEST(u8path, append_maintains_slash_type) + TEST_SUITE("filesystem") { - const fs::u8path path = u8R"(a/b/c/d)"; - const auto path_1 = path / u8R"(e\f\g)"; - EXPECT_EQ(path_1.string(), u8R"(a\b\c\d\e\f\g)"); - } -#endif + TEST_CASE("remove_readonly_file") + { + const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; + // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested + // function) + mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. + fs::create_directories(tmp_dir); - TEST(filesystem, remove_readonly_file) - { - const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; - // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested function) - mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. - fs::create_directories(tmp_dir); + const auto readonly_file_path = tmp_dir / "fs-readonly-file"; + { + std::ofstream readonly_file{ readonly_file_path.std_path(), + readonly_file.binary | readonly_file.trunc }; + readonly_file << "delete me" << std::endl; + } - const auto readonly_file_path = tmp_dir / "fs-readonly-file"; - { - std::ofstream readonly_file{ readonly_file_path.std_path(), - readonly_file.binary | readonly_file.trunc }; - readonly_file << "delete me" << std::endl; + // set to read-only + fs::permissions( + readonly_file_path, + fs::perms::owner_read | fs::perms::group_read, + fs::perm_options::replace + ); + CHECK_EQ( + (fs::status(readonly_file_path).permissions() & fs::perms::owner_write), + fs::perms::none + ); + CHECK_EQ( + (fs::status(readonly_file_path).permissions() & fs::perms::group_write), + fs::perms::none + ); + + // removing should still work. + CHECK(fs::exists(readonly_file_path)); + fs::remove(readonly_file_path); + CHECK_FALSE(fs::exists(readonly_file_path)); } - // set to read-only - fs::permissions( - readonly_file_path, - fs::perms::owner_read | fs::perms::group_read, - fs::perm_options::replace - ); - EXPECT_EQ( - (fs::status(readonly_file_path).permissions() & fs::perms::owner_write), - fs::perms::none - ); - EXPECT_EQ( - (fs::status(readonly_file_path).permissions() & fs::perms::group_write), - fs::perms::none - ); - - // removing should still work. - EXPECT_TRUE(fs::exists(readonly_file_path)); - fs::remove(readonly_file_path); - EXPECT_FALSE(fs::exists(readonly_file_path)); - } + TEST_CASE("remove_all_readonly_files") + { + const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; + // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested + // function) + mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. + fs::create_directories(tmp_dir); - TEST(filesystem, remove_all_readonly_files) - { - const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; - // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested function) - mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. - fs::create_directories(tmp_dir); + static constexpr int file_count_per_directory = 3; + static constexpr int subdir_count_per_directory = 3; + static constexpr int tree_depth = 3; - static constexpr int file_count_per_directory = 3; - static constexpr int subdir_count_per_directory = 3; - static constexpr int tree_depth = 3; + const auto create_readonly_files = [](const fs::u8path& dir_path) + { + assert(fs::is_directory(dir_path)); + for (int file_idx = 0; file_idx < file_count_per_directory; ++file_idx) + { + const auto readonly_file_path = dir_path + / fmt::format("readonly-file-{}", file_idx); + { + std::ofstream readonly_file{ readonly_file_path.std_path(), + readonly_file.binary | readonly_file.trunc }; + readonly_file << "delete me" << std::endl; + } + + // set to read-only + fs::permissions( + readonly_file_path, + fs::perms::owner_read | fs::perms::group_read, + fs::perm_options::replace + ); + CHECK_EQ( + (fs::status(readonly_file_path).permissions() & fs::perms::owner_write), + fs::perms::none + ); + CHECK_EQ( + (fs::status(readonly_file_path).permissions() & fs::perms::group_write), + fs::perms::none + ); + } + }; - const auto create_readonly_files = [](const fs::u8path& dir_path) - { - assert(fs::is_directory(dir_path)); - for (int file_idx = 0; file_idx < file_count_per_directory; ++file_idx) + const auto create_subdirs = [&](const std::vector& dirs) { - const auto readonly_file_path = dir_path / fmt::format("readonly-file-{}", file_idx); + auto subdirs = dirs; + for (const auto& dir_path : dirs) { - std::ofstream readonly_file{ readonly_file_path.std_path(), - readonly_file.binary | readonly_file.trunc }; - readonly_file << "delete me" << std::endl; + for (int subdir_idx = 0; subdir_idx < subdir_count_per_directory; ++subdir_idx) + { + subdirs.push_back(dir_path / fmt::format("{}", subdir_idx)); + } } + return subdirs; + }; - // set to read-only - fs::permissions( - readonly_file_path, - fs::perms::owner_read | fs::perms::group_read, - fs::perm_options::replace - ); - EXPECT_EQ( - (fs::status(readonly_file_path).permissions() & fs::perms::owner_write), - fs::perms::none - ); - EXPECT_EQ( - (fs::status(readonly_file_path).permissions() & fs::perms::group_write), - fs::perms::none - ); + std::vector dirs{ tmp_dir }; + for (int depth = 0; depth < tree_depth; ++depth) + { + dirs = create_subdirs(dirs); } - }; - const auto create_subdirs = [&](const std::vector& dirs) - { - auto subdirs = dirs; for (const auto& dir_path : dirs) { - for (int subdir_idx = 0; subdir_idx < subdir_count_per_directory; ++subdir_idx) - { - subdirs.push_back(dir_path / fmt::format("{}", subdir_idx)); - } + fs::create_directories(dir_path); + create_readonly_files(dir_path); } - return subdirs; - }; - std::vector dirs{ tmp_dir }; - for (int depth = 0; depth < tree_depth; ++depth) - { - dirs = create_subdirs(dirs); + CHECK(fs::exists(tmp_dir)); + fs::remove_all(tmp_dir); + CHECK_FALSE(fs::exists(tmp_dir)); } - - for (const auto& dir_path : dirs) - { - fs::create_directories(dir_path); - create_readonly_files(dir_path); - } - - EXPECT_TRUE(fs::exists(tmp_dir)); - fs::remove_all(tmp_dir); - EXPECT_FALSE(fs::exists(tmp_dir)); } } diff --git a/libmamba/tests/src/core/test_history.cpp b/libmamba/tests/src/core/test_history.cpp index 10ccc4f61f..8fdf51016f 100644 --- a/libmamba/tests/src/core/test_history.cpp +++ b/libmamba/tests/src/core/test_history.cpp @@ -1,6 +1,20 @@ +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include +#include #include -#include +#include "doctest/doctest.h" + +#ifndef _WIN32 +#include +#include +#include +#endif #include "mamba/core/history.hpp" @@ -8,83 +22,86 @@ namespace mamba { - TEST(history, parse) + TEST_SUITE("history") { - static const auto history_file_path = fs::absolute( - test_data_dir / "history/parse/conda-meta/history" - ); - static const auto aux_file_path = fs::absolute( - test_data_dir / "history/parse/conda-meta/aux_file" - ); - - // Backup history file and restore it at the end of the test, whatever the output. - struct ScopedHistoryFileBackup + TEST_CASE("parse") { - ScopedHistoryFileBackup() + static const auto history_file_path = fs::absolute( + test_data_dir / "history/parse/conda-meta/history" + ); + static const auto aux_file_path = fs::absolute( + test_data_dir / "history/parse/conda-meta/aux_file" + ); + + // Backup history file and restore it at the end of the test, whatever the output. + struct ScopedHistoryFileBackup { - fs::remove(aux_file_path); - fs::copy(history_file_path, aux_file_path); - } - ~ScopedHistoryFileBackup() + ScopedHistoryFileBackup() + { + fs::remove(aux_file_path); + fs::copy(history_file_path, aux_file_path); + } + ~ScopedHistoryFileBackup() + { + fs::remove(history_file_path); + fs::copy(aux_file_path, history_file_path); + } + } scoped_history_file_backup; + + // Gather history from current history file. + History history_instance(test_data_dir / "history/parse"); + std::vector user_reqs = history_instance.get_user_requests(); + + // Extract raw history file content into buffer. + std::ifstream history_file(history_file_path.std_path()); + std::stringstream original_history_buffer; + std::string line; + while (getline(history_file, line)) { - fs::remove(history_file_path); - fs::copy(aux_file_path, history_file_path); + original_history_buffer << line; } - } scoped_history_file_backup; + history_file.close(); - // Gather history from current history file. - History history_instance(test_data_dir / "history/parse"); - std::vector user_reqs = history_instance.get_user_requests(); + // Generate a history buffer with duplicate history. + std::stringstream check_buffer; + check_buffer << original_history_buffer.str() << original_history_buffer.str(); - // Extract raw history file content into buffer. - std::ifstream history_file(history_file_path.std_path()); - std::stringstream original_history_buffer; - std::string line; - while (getline(history_file, line)) - { - original_history_buffer << line; - } - history_file.close(); + std::cout << check_buffer.str() << '\n'; - // Generate a history buffer with duplicate history. - std::stringstream check_buffer; - check_buffer << original_history_buffer.str() << original_history_buffer.str(); - - std::cout << check_buffer.str() << '\n'; + // Re-inject history into history file: history file should then have the same duplicate + // content as the buffer. + for (const auto& req : user_reqs) + { + history_instance.add_entry(req); + } - // Re-inject history into history file: history file should then have the same duplicate - // content as the buffer. - for (const auto& req : user_reqs) - { - history_instance.add_entry(req); - } + history_file.open(history_file_path.std_path()); + std::stringstream updated_history_buffer; + while (getline(history_file, line)) + { + updated_history_buffer << line; + } + history_file.close(); - history_file.open(history_file_path.std_path()); - std::stringstream updated_history_buffer; - while (getline(history_file, line)) - { - updated_history_buffer << line; + REQUIRE_EQ(updated_history_buffer.str(), check_buffer.str()); } - history_file.close(); - - ASSERT_EQ(updated_history_buffer.str(), check_buffer.str()); - } #ifndef _WIN32 - TEST(history, parse_segfault) - { - pid_t child = fork(); - if (child) - { - int wstatus; - waitpid(child, &wstatus, 0); - ASSERT_TRUE(WIFEXITED(wstatus)); - } - else + TEST_CASE("parse_segfault") { - History history_instance("history_test/parse_segfault"); - history_instance.get_user_requests(); - exit(EXIT_SUCCESS); + pid_t child = fork(); + if (child) + { + int wstatus; + waitpid(child, &wstatus, 0); + REQUIRE(WIFEXITED(wstatus)); + } + else + { + History history_instance("history_test/parse_segfault"); + history_instance.get_user_requests(); + exit(EXIT_SUCCESS); + } } } #endif diff --git a/libmamba/tests/src/core/test_invoke.cpp b/libmamba/tests/src/core/test_invoke.cpp index b3a326aca3..be5b7d7dae 100644 --- a/libmamba/tests/src/core/test_invoke.cpp +++ b/libmamba/tests/src/core/test_invoke.cpp @@ -1,83 +1,92 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. -#include +#include #include "mamba/core/invoke.hpp" #include "mamba/core/util_string.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(safe_invoke, executes_with_success) + TEST_SUITE("safe_invoke") { - bool was_called = false; - auto result = safe_invoke([&] { was_called = true; }); - EXPECT_TRUE(result); - EXPECT_TRUE(was_called); - } - - TEST(safe_invoke, catches_std_exceptions) - { - const auto message = "expected failure"; - auto result = safe_invoke([&] { throw std::runtime_error(message); }); - EXPECT_FALSE(result); - EXPECT_TRUE(ends_with(result.error().what(), message)) << result.error().what(); - } + TEST_CASE("executes_with_success") + { + bool was_called = false; + auto result = safe_invoke([&] { was_called = true; }); + CHECK(result); + CHECK(was_called); + } - TEST(safe_invoke, catches_any_exceptions) - { - const auto message = "expected failure"; - auto result = safe_invoke([&] { throw message; }); - EXPECT_FALSE(result); - EXPECT_TRUE(ends_with(result.error().what(), "unknown error")) << result.error().what(); - } + TEST_CASE("catches_std_exceptions") + { + const auto message = "expected failure"; + auto result = safe_invoke([&] { throw std::runtime_error(message); }); + CHECK_FALSE(result); + CHECK_MESSAGE(ends_with(result.error().what(), message), result.error().what()); + } - TEST(safe_invoke, safely_catch_moved_callable_destructor_exception) - { - bool did_move_happened = false; + TEST_CASE("catches_any_exceptions") + { + const auto message = "expected failure"; + auto result = safe_invoke([&] { throw message; }); + CHECK_FALSE(result); + CHECK_MESSAGE(ends_with(result.error().what(), "unknown error"), result.error().what()); + } - struct DoNotDoThisAtHome + TEST_CASE("safely_catch_moved_callable_destructor_exception") { - bool& did_move_happened; - bool owner = true; + bool did_move_happened = false; - DoNotDoThisAtHome(bool& move_happened) - : did_move_happened(move_happened) + struct DoNotDoThisAtHome { - } + bool& did_move_happened; + bool owner = true; - DoNotDoThisAtHome(DoNotDoThisAtHome&& other) - : did_move_happened(other.did_move_happened) - { - did_move_happened = true; - other.owner = false; - } + DoNotDoThisAtHome(bool& move_happened) + : did_move_happened(move_happened) + { + } - DoNotDoThisAtHome& operator=(DoNotDoThisAtHome&& other) - { - did_move_happened = other.did_move_happened; - did_move_happened = true; - other.owner = false; - return *this; - } + DoNotDoThisAtHome(DoNotDoThisAtHome&& other) + : did_move_happened(other.did_move_happened) + { + did_move_happened = true; + other.owner = false; + } - ~DoNotDoThisAtHome() noexcept(false) - { - if (owner) + DoNotDoThisAtHome& operator=(DoNotDoThisAtHome&& other) { - throw "watever"; + did_move_happened = other.did_move_happened; + did_move_happened = true; + other.owner = false; + return *this; } - } - void operator()() const - { - // do nothing - } - }; + ~DoNotDoThisAtHome() noexcept(false) + { + if (owner) + { + throw "watever"; + } + } + + void operator()() const + { + // do nothing + } + }; - auto result = safe_invoke(DoNotDoThisAtHome{ did_move_happened }); - EXPECT_FALSE(result); - EXPECT_TRUE(ends_with(result.error().what(), "unknown error")) << result.error().what(); - EXPECT_TRUE(did_move_happened); + auto result = safe_invoke(DoNotDoThisAtHome{ did_move_happened }); + CHECK_FALSE(result); + CHECK_MESSAGE(ends_with(result.error().what(), "unknown error"), result.error().what()); + CHECK(did_move_happened); + } } } diff --git a/libmamba/tests/src/core/test_lockfile.cpp b/libmamba/tests/src/core/test_lockfile.cpp index f4d6767471..42cd760f61 100644 --- a/libmamba/tests/src/core/test_lockfile.cpp +++ b/libmamba/tests/src/core/test_lockfile.cpp @@ -1,12 +1,19 @@ +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include #include -#include #include #include "mamba/core/context.hpp" #include "mamba/core/mamba_fs.hpp" #include "mamba/core/util.hpp" +#include "doctest/doctest.h" #include "spdlog/spdlog.h" #ifdef _WIN32 @@ -32,7 +39,7 @@ namespace mamba namespace testing { - class LockDirTest : public ::testing::Test + class LockDirTest { protected: @@ -48,89 +55,134 @@ namespace mamba } ~LockDirTest() - { - spdlog::set_level(spdlog::level::info); - } - void TearDown() override { mamba::Context::instance().use_lockfiles = true; + spdlog::set_level(spdlog::level::info); } }; - TEST_F(LockDirTest, basics) + TEST_SUITE("LockDirTest") { - mamba::LockFile lock{ tempdir_path }; - EXPECT_TRUE(lock); + TEST_CASE_FIXTURE(LockDirTest, "basics") { - auto new_lock = std::move(lock); - EXPECT_FALSE(lock); - EXPECT_TRUE(new_lock); + mamba::LockFile lock{ tempdir_path }; + CHECK(lock); + { + auto new_lock = std::move(lock); + CHECK_FALSE(lock); + CHECK(new_lock); + } + CHECK_FALSE(lock); } - EXPECT_FALSE(lock); - } - - TEST_F(LockDirTest, disable_locking) - { - { - auto _ = on_scope_exit([] { mamba::Context::instance().use_lockfiles = true; }); - mamba::Context::instance().use_lockfiles = false; - auto lock = LockFile(tempdir_path); - EXPECT_FALSE(lock); - } - ASSERT_TRUE(mamba::Context::instance().use_lockfiles); + TEST_CASE_FIXTURE(LockDirTest, "disable_locking") { - ASSERT_TRUE(mamba::Context::instance().use_lockfiles); - auto lock = LockFile(tempdir_path); - EXPECT_TRUE(lock); + { + auto _ = on_scope_exit([] { mamba::Context::instance().use_lockfiles = true; }); + mamba::Context::instance().use_lockfiles = false; + auto lock = LockFile(tempdir_path); + CHECK_FALSE(lock); + } + REQUIRE(mamba::Context::instance().use_lockfiles); + { + REQUIRE(mamba::Context::instance().use_lockfiles); + auto lock = LockFile(tempdir_path); + CHECK(lock); + } } - } - TEST_F(LockDirTest, same_pid) - { + TEST_CASE_FIXTURE(LockDirTest, "same_pid") { - auto lock = LockFile(tempdir_path); - EXPECT_TRUE(lock.is_locked()); - EXPECT_EQ(lock.count_lock_owners(), 1); - EXPECT_TRUE(fs::exists(lock.lockfile_path())); - { - auto other_lock = LockFile(tempdir_path); - EXPECT_TRUE(other_lock.is_locked()); - EXPECT_EQ(other_lock.count_lock_owners(), 2); - EXPECT_EQ(lock.count_lock_owners(), 2); + auto lock = LockFile(tempdir_path); + CHECK(lock.is_locked()); + CHECK_EQ(lock.count_lock_owners(), 1); + CHECK(fs::exists(lock.lockfile_path())); + + { + auto other_lock = LockFile(tempdir_path); + CHECK(other_lock.is_locked()); + CHECK_EQ(other_lock.count_lock_owners(), 2); + CHECK_EQ(lock.count_lock_owners(), 2); + } + + CHECK_EQ(lock.count_lock_owners(), 1); + + // check the first lock is still locked + CHECK(fs::exists(lock.lockfile_path())); } + CHECK_FALSE(fs::exists(tempdir_path / (tempdir_path.filename().string() + ".lock"))); - EXPECT_EQ(lock.count_lock_owners(), 1); - - // check the first lock is still locked - EXPECT_TRUE(fs::exists(lock.lockfile_path())); + // we can still re-lock afterwards + { + auto lock = LockFile(tempdir_path); + CHECK(fs::exists(lock.lockfile_path())); + } } - EXPECT_FALSE(fs::exists(tempdir_path / (tempdir_path.filename().string() + ".lock"))); - // we can still re-lock afterwards + TEST_CASE_FIXTURE(LockDirTest, "different_pid") { - auto lock = LockFile(tempdir_path); - EXPECT_TRUE(fs::exists(lock.lockfile_path())); - } - } - - TEST_F(LockDirTest, different_pid) - { - std::string const lock_exe = testing_libmamba_lock_exe.string(); - std::string out, err; - std::vector args; + std::string const lock_exe = testing_libmamba_lock_exe.string(); + std::string out, err; + std::vector args; - { - auto lock = LockFile(tempdir_path); - EXPECT_TRUE(fs::exists(lock.lockfile_path())); + { + auto lock = LockFile(tempdir_path); + CHECK(fs::exists(lock.lockfile_path())); + + // Check lock status + CHECK(mamba::LockFile::is_locked(lock)); + + // Check lock status from another process + args = { lock_exe, "is-locked", lock.lockfile_path().string() }; + out.clear(); + err.clear(); + reproc::run( + args, + reproc::options{}, + reproc::sink::string(out), + reproc::sink::string(err) + ); + + int is_locked = 0; + try + { + is_locked = std::stoi(out); + } + catch (...) + { + std::cout << "convertion error" << std::endl; + } + CHECK(is_locked); + + // Try to lock from another process + args = { lock_exe, "lock", "--timeout=1", tempdir_path.string() }; + out.clear(); + err.clear(); + reproc::run( + args, + reproc::options{}, + reproc::sink::string(out), + reproc::sink::string(err) + ); + + bool new_lock_created = true; + try + { + new_lock_created = std::stoi(out); + } + catch (...) + { + std::cout << "convertion error" << std::endl; + } + CHECK_FALSE(new_lock_created); + } - // Check lock status - EXPECT_TRUE(mamba::LockFile::is_locked(lock)); + fs::u8path lock_path = tempdir_path / (tempdir_path.filename().string() + ".lock"); + CHECK_FALSE(fs::exists(lock_path)); - // Check lock status from another process - args = { lock_exe, "is-locked", lock.lockfile_path().string() }; + args = { lock_exe, "is-locked", lock_path.string() }; out.clear(); err.clear(); reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); @@ -142,48 +194,12 @@ namespace mamba } catch (...) { - std::cout << "convertion error" << std::endl; - } - EXPECT_TRUE(is_locked); - - // Try to lock from another process - args = { lock_exe, "lock", "--timeout=1", tempdir_path.string() }; - out.clear(); - err.clear(); - reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); - - bool new_lock_created = true; - try - { - new_lock_created = std::stoi(out); - } - catch (...) - { - std::cout << "convertion error" << std::endl; } - EXPECT_FALSE(new_lock_created); - } - - fs::u8path lock_path = tempdir_path / (tempdir_path.filename().string() + ".lock"); - EXPECT_FALSE(fs::exists(lock_path)); - - args = { lock_exe, "is-locked", lock_path.string() }; - out.clear(); - err.clear(); - reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); - - int is_locked = 0; - try - { - is_locked = std::stoi(out); + CHECK_FALSE(is_locked); } - catch (...) - { - } - EXPECT_FALSE(is_locked); } - class LockFileTest : public ::testing::Test + class LockFileTest { protected: @@ -204,44 +220,93 @@ namespace mamba } }; - TEST_F(LockFileTest, same_pid) + TEST_SUITE("LockFileTest") { + TEST_CASE_FIXTURE(LockFileTest, "same_pid") { - LockFile lock{ tempfile_path }; - EXPECT_TRUE(lock.is_locked()); - EXPECT_TRUE(fs::exists(lock.lockfile_path())); - EXPECT_EQ(lock.count_lock_owners(), 1); - { - LockFile other_lock{ tempfile_path }; - EXPECT_TRUE(other_lock.is_locked()); - EXPECT_EQ(other_lock.count_lock_owners(), 2); - EXPECT_EQ(lock.count_lock_owners(), 2); + LockFile lock{ tempfile_path }; + CHECK(lock.is_locked()); + CHECK(fs::exists(lock.lockfile_path())); + CHECK_EQ(lock.count_lock_owners(), 1); + + { + LockFile other_lock{ tempfile_path }; + CHECK(other_lock.is_locked()); + CHECK_EQ(other_lock.count_lock_owners(), 2); + CHECK_EQ(lock.count_lock_owners(), 2); + } + + CHECK_EQ(lock.count_lock_owners(), 1); + + // check the first lock is still locked + CHECK(fs::exists(lock.lockfile_path())); } - - EXPECT_EQ(lock.count_lock_owners(), 1); - - // check the first lock is still locked - EXPECT_TRUE(fs::exists(lock.lockfile_path())); + CHECK_FALSE(fs::exists(tempfile_path.string() + ".lock")); } - EXPECT_FALSE(fs::exists(tempfile_path.string() + ".lock")); - } - TEST_F(LockFileTest, different_pid) - { - std::string const lock_exe = testing_libmamba_lock_exe.string(); - std::string out, err; - std::vector args; + TEST_CASE_FIXTURE(LockFileTest, "different_pid") { - // Create a lock - auto lock = LockFile(tempfile_path); - EXPECT_TRUE(fs::exists(lock.lockfile_path())); + std::string const lock_exe = testing_libmamba_lock_exe.string(); + std::string out, err; + std::vector args; + { + // Create a lock + auto lock = LockFile(tempfile_path); + CHECK(fs::exists(lock.lockfile_path())); + + // Check lock status from current PID + CHECK(mamba::LockFile::is_locked(lock)); + + // Check lock status from another process + args = { lock_exe, "is-locked", lock.lockfile_path().string() }; + out.clear(); + err.clear(); + reproc::run( + args, + reproc::options{}, + reproc::sink::string(out), + reproc::sink::string(err) + ); + + int is_locked = 0; + try + { + is_locked = std::stoi(out); + } + catch (...) + { + std::cout << "convertion error" << std::endl; + } + CHECK(is_locked); + + // Try to lock from another process + args = { lock_exe, "lock", "--timeout=1", tempfile_path.string() }; + out.clear(); + err.clear(); + reproc::run( + args, + reproc::options{}, + reproc::sink::string(out), + reproc::sink::string(err) + ); + + bool new_lock_created = true; + try + { + new_lock_created = std::stoi(out); + } + catch (...) + { + std::cout << "convertion error" << std::endl; + } + CHECK_FALSE(new_lock_created); + } - // Check lock status from current PID - EXPECT_TRUE(mamba::LockFile::is_locked(lock)); + fs::u8path lock_path = tempfile_path.string() + ".lock"; + CHECK_FALSE(fs::exists(lock_path)); - // Check lock status from another process - args = { lock_exe, "is-locked", lock.lockfile_path().string() }; + args = { lock_exe, "is-locked", lock_path.string() }; out.clear(); err.clear(); reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); @@ -253,45 +318,9 @@ namespace mamba } catch (...) { - std::cout << "convertion error" << std::endl; } - EXPECT_TRUE(is_locked); - - // Try to lock from another process - args = { lock_exe, "lock", "--timeout=1", tempfile_path.string() }; - out.clear(); - err.clear(); - reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); - - bool new_lock_created = true; - try - { - new_lock_created = std::stoi(out); - } - catch (...) - { - std::cout << "convertion error" << std::endl; - } - EXPECT_FALSE(new_lock_created); - } - - fs::u8path lock_path = tempfile_path.string() + ".lock"; - EXPECT_FALSE(fs::exists(lock_path)); - - args = { lock_exe, "is-locked", lock_path.string() }; - out.clear(); - err.clear(); - reproc::run(args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); - - int is_locked = 0; - try - { - is_locked = std::stoi(out); - } - catch (...) - { + CHECK_FALSE(is_locked); } - EXPECT_FALSE(is_locked); } } } diff --git a/libmamba/tests/src/core/test_output.cpp b/libmamba/tests/src/core/test_output.cpp index cbd16b99df..2be9736761 100644 --- a/libmamba/tests/src/core/test_output.cpp +++ b/libmamba/tests/src/core/test_output.cpp @@ -1,20 +1,29 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/core/context.hpp" #include "mamba/core/output.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(output, no_progress_bars) + TEST_SUITE("output") { - Context::instance().no_progress_bars = true; - auto proxy = Console::instance().add_progress_bar("conda-forge"); - EXPECT_FALSE(proxy.defined()); - EXPECT_FALSE(proxy); + TEST_CASE("no_progress_bars") + { + Context::instance().no_progress_bars = true; + auto proxy = Console::instance().add_progress_bar("conda-forge"); + CHECK_FALSE(proxy.defined()); + CHECK_FALSE(proxy); - Context::instance().no_progress_bars = false; - proxy = Console::instance().add_progress_bar("conda-forge"); - EXPECT_TRUE(proxy.defined()); - EXPECT_TRUE(proxy); + Context::instance().no_progress_bars = false; + proxy = Console::instance().add_progress_bar("conda-forge"); + CHECK(proxy.defined()); + CHECK(proxy); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_pinning.cpp b/libmamba/tests/src/core/test_pinning.cpp index 54e8550561..2297a7a9db 100644 --- a/libmamba/tests/src/core/test_pinning.cpp +++ b/libmamba/tests/src/core/test_pinning.cpp @@ -1,110 +1,119 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/core/pinning.hpp" #include "mamba/core/util.hpp" +#include "doctest/doctest.h" + namespace mamba { namespace testing { - TEST(pinning, python_pin) + TEST_SUITE("pinning") { - std::vector specs; - std::string pin; - - auto sprefix_data = PrefixData::create(""); - if (!sprefix_data) + TEST_CASE("python_pin") { - // TODO: propagate tl::expected mechanism - throw std::runtime_error("could not load prefix data"); + std::vector specs; + std::string pin; + + auto sprefix_data = PrefixData::create(""); + if (!sprefix_data) + { + // TODO: propagate tl::expected mechanism + throw std::runtime_error("could not load prefix data"); + } + PrefixData& prefix_data = sprefix_data.value(); + REQUIRE_EQ(prefix_data.records().size(), 0); + + specs = { "python" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python-test" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python=3" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python==3.8" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python==3.8.3" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "numpy" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + PackageInfo pkg_info("python", "3.7.10", "abcde", 0); + prefix_data.add_packages({ pkg_info }); + REQUIRE_EQ(prefix_data.records().size(), 1); + + specs = { "python" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "numpy" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, "python 3.7.*"); + + specs = { "python-test" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, "python 3.7.*"); + + specs = { "python==3" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python=3.*" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python=3.8" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "python=3.8.3" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); + + specs = { "numpy", "python" }; + pin = python_pin(prefix_data, specs); + CHECK_EQ(pin, ""); } - PrefixData& prefix_data = sprefix_data.value(); - ASSERT_EQ(prefix_data.records().size(), 0); - - specs = { "python" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python-test" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python=3" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python==3.8" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python==3.8.3" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "numpy" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - PackageInfo pkg_info("python", "3.7.10", "abcde", 0); - prefix_data.add_packages({ pkg_info }); - ASSERT_EQ(prefix_data.records().size(), 1); - - specs = { "python" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "numpy" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, "python 3.7.*"); - specs = { "python-test" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, "python 3.7.*"); - - specs = { "python==3" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python=3.*" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python=3.8" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "python=3.8.3" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - - specs = { "numpy", "python" }; - pin = python_pin(prefix_data, specs); - EXPECT_EQ(pin, ""); - } - - TEST(pinning, file_pins) - { - std::vector pins; - - auto tempfile = std::make_unique("pinned", ""); - const auto path = tempfile->path(); - std::ofstream out_file(path.std_path()); - out_file << "numpy=1.13\njupyterlab=3"; - out_file.close(); - - pins = file_pins(path); - ASSERT_EQ(pins.size(), 2); - EXPECT_EQ(pins[0], "numpy=1.13"); - EXPECT_EQ(pins[1], "jupyterlab=3"); - - out_file.open(path.std_path(), std::ofstream::out | std::ofstream::trunc); - out_file << "numpy=1.13\npython=3.7.5"; - out_file.close(); - - pins = file_pins(path); - ASSERT_EQ(pins.size(), 2); - EXPECT_EQ(pins[0], "numpy=1.13"); - EXPECT_EQ(pins[1], "python=3.7.5"); + TEST_CASE("file_pins") + { + std::vector pins; + + auto tempfile = std::make_unique("pinned", ""); + const auto path = tempfile->path(); + std::ofstream out_file(path.std_path()); + out_file << "numpy=1.13\njupyterlab=3"; + out_file.close(); + + pins = file_pins(path); + REQUIRE_EQ(pins.size(), 2); + CHECK_EQ(pins[0], "numpy=1.13"); + CHECK_EQ(pins[1], "jupyterlab=3"); + + out_file.open(path.std_path(), std::ofstream::out | std::ofstream::trunc); + out_file << "numpy=1.13\npython=3.7.5"; + out_file.close(); + + pins = file_pins(path); + REQUIRE_EQ(pins.size(), 2); + CHECK_EQ(pins[0], "numpy=1.13"); + CHECK_EQ(pins[1], "python=3.7.5"); + } } } // namespace testing } // namespace mamba diff --git a/libmamba/tests/src/core/test_progress_bar.cpp b/libmamba/tests/src/core/test_progress_bar.cpp index e20fa0f121..4996dc1e92 100644 --- a/libmamba/tests/src/core/test_progress_bar.cpp +++ b/libmamba/tests/src/core/test_progress_bar.cpp @@ -1,14 +1,19 @@ -#include +// Copyright (c) 2019, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. -#include +#include #include "mamba/core/progress_bar.hpp" #include "../src/core/progress_bar_impl.hpp" +#include "doctest/doctest.h" namespace mamba { - class progress_bar : public ::testing::Test + class progress_bar { public: @@ -34,352 +39,355 @@ namespace mamba std::ostringstream ostream; }; - TEST_F(progress_bar, print) + TEST_SUITE("progress_bar") { - auto& r = proxy.repr(); + TEST_CASE_FIXTURE(progress_bar, "print") + { + auto& r = proxy.repr(); - EXPECT_TRUE(r.prefix.active()); - EXPECT_EQ(r.prefix.value(), "conda-forge"); - EXPECT_EQ(r.prefix.width(), 11); + CHECK(r.prefix.active()); + CHECK_EQ(r.prefix.value(), "conda-forge"); + CHECK_EQ(r.prefix.width(), 11); - EXPECT_TRUE(r.progress); - EXPECT_EQ(r.progress.value(), "??"); - EXPECT_EQ(r.progress.width(), 2); + CHECK(r.progress); + CHECK_EQ(r.progress.value(), "??"); + CHECK_EQ(r.progress.width(), 2); - EXPECT_TRUE(r.separator); - EXPECT_EQ(r.separator.value(), "-"); - EXPECT_EQ(r.separator.width(), 1); + CHECK(r.separator); + CHECK_EQ(r.separator.value(), "-"); + CHECK_EQ(r.separator.width(), 1); - EXPECT_TRUE(r.total); - EXPECT_EQ(r.total.value(), "bar"); - EXPECT_EQ(r.total.width(), 3); + CHECK(r.total); + CHECK_EQ(r.total.value(), "bar"); + CHECK_EQ(r.total.width(), 3); - EXPECT_TRUE(r.speed); - EXPECT_EQ(r.speed.value(), "@10"); - EXPECT_EQ(r.speed.width(), 3); + CHECK(r.speed); + CHECK_EQ(r.speed.value(), "@10"); + CHECK_EQ(r.speed.width(), 3); - EXPECT_TRUE(r.postfix.active()); - EXPECT_EQ(r.postfix.value(), "downloading"); - EXPECT_EQ(r.postfix.width(), 11); + CHECK(r.postfix.active()); + CHECK_EQ(r.postfix.value(), "downloading"); + CHECK_EQ(r.postfix.width(), 11); - EXPECT_TRUE(r.elapsed.active()); - EXPECT_EQ(r.elapsed.value(), "0.1s"); - EXPECT_EQ(r.elapsed.width(), 4); + CHECK(r.elapsed.active()); + CHECK_EQ(r.elapsed.value(), "0.1s"); + CHECK_EQ(r.elapsed.width(), 4); - proxy.print(ostream, 0, false); - EXPECT_EQ(ostream.str(), "conda-forge ?? foo - bar @10 downloading 0.1s"); - ostream.str(""); + proxy.print(ostream, 0, false); + CHECK_EQ(ostream.str(), "conda-forge ?? foo - bar @10 downloading 0.1s"); + ostream.str(""); - r.set_width(21); // no impact if 'update_repr' not called - proxy.print(ostream, 0, false); - EXPECT_EQ(ostream.str(), "conda-forge ?? foo - bar @10 downloading 0.1s"); - ostream.str(""); - } + r.set_width(21); // no impact if 'update_repr' not called + proxy.print(ostream, 0, false); + CHECK_EQ(ostream.str(), "conda-forge ?? foo - bar @10 downloading 0.1s"); + ostream.str(""); + } - TEST_F(progress_bar, print_no_resize) - { - auto& r = proxy.repr(); - - r.set_width(150); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_TRUE(r.separator); - EXPECT_TRUE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 106); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.separator.width(), 1); - EXPECT_EQ(r.total.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - } + TEST_CASE_FIXTURE(progress_bar, "print_no_resize") + { + auto& r = proxy.repr(); - TEST_F(progress_bar, print_reduce_bar) - { - auto& r = proxy.repr(); - - r.set_width(84); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_TRUE(r.separator); - EXPECT_TRUE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 40); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.separator.width(), 1); - EXPECT_EQ(r.total.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - - // 1: reduce bar width - // available space redistributed to the bar - r.set_width(83); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_TRUE(r.separator); - EXPECT_TRUE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 39); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.separator.width(), 1); - EXPECT_EQ(r.total.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - } + r.set_width(150); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK(r.separator); + CHECK(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 106); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.separator.width(), 1); + CHECK_EQ(r.total.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + } - TEST_F(progress_bar, print_remove_total_sep) - { - auto& r = proxy.repr(); - - r.set_width(59); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_TRUE(r.separator); - EXPECT_TRUE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 15); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.separator.width(), 1); - EXPECT_EQ(r.total.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - - // 2: remove the total value and the separator - // available space redistributed to the bar - r.set_width(58); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 20); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - } + TEST_CASE_FIXTURE(progress_bar, "print_reduce_bar") + { + auto& r = proxy.repr(); - TEST_F(progress_bar, print_remove_speed) - { - auto& r = proxy.repr(); - - r.set_width(53); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_TRUE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 15); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.speed.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - - // 3: remove the speed - // available space redistributed to the bar - r.set_width(52); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 18); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - } + r.set_width(84); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK(r.separator); + CHECK(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 40); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.separator.width(), 1); + CHECK_EQ(r.total.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + + // 1: reduce bar width + // available space redistributed to the bar + r.set_width(83); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK(r.separator); + CHECK(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 39); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.separator.width(), 1); + CHECK_EQ(r.total.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + } - TEST_F(progress_bar, print_remove_postfix) - { - auto& r = proxy.repr(); - - r.set_width(49); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_TRUE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 15); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.postfix.width(), 11); - EXPECT_EQ(r.elapsed.width(), 5); - - // 4: remove the postfix - // available space redistributed to the bar - r.set_width(48); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_FALSE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 26); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.elapsed.width(), 5); - } + TEST_CASE_FIXTURE(progress_bar, "print_remove_total_sep") + { + auto& r = proxy.repr(); - TEST_F(progress_bar, print_truncate_prefix) - { - auto& r = proxy.repr(); - proxy.set_prefix("some_very_very_long_prefix"); - - r.set_width(52); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_FALSE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 26); - EXPECT_EQ(r.progress.width(), 15); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.elapsed.width(), 5); - - // 5: truncate the prefix if too long - // available space redistributed to the prefix - r.set_width(51); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_FALSE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 25); - EXPECT_EQ(r.progress.width(), 15); - EXPECT_EQ(r.current.width(), 3); - EXPECT_EQ(r.elapsed.width(), 5); - } + r.set_width(59); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK(r.separator); + CHECK(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 15); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.separator.width(), 1); + CHECK_EQ(r.total.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + + // 2: remove the total value and the separator + // available space redistributed to the bar + r.set_width(58); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 20); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + } - TEST_F(progress_bar, print_without_bar) - { - auto& r = proxy.repr(); - - r.set_width(34).reset_fields(); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_TRUE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_FALSE(r.postfix); - EXPECT_TRUE(r.elapsed); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 12); - EXPECT_EQ(r.current.width(), 3); - // This fails because of invisible ANSI escape codes introduced with - // https://github.com/mamba-org/mamba/pull/2085/ - // EXPECT_TRUE(r.progress.overflow()); - EXPECT_EQ(r.elapsed.width(), 5); - - // 6: display progress without a bar - r.set_width(33); - proxy.update_repr(); - proxy.print(ostream, 0, false); - EXPECT_EQ(ostream.str(), "conda-forge 0% foo --"); - ostream.str(""); - } + TEST_CASE_FIXTURE(progress_bar, "print_remove_speed") + { + auto& r = proxy.repr(); - TEST_F(progress_bar, print_remove_current) - { - auto& r = proxy.repr(); - - r.set_width(26).reset_fields(); - proxy.update_repr(); - proxy.print(ostream, 0, false); - EXPECT_EQ(ostream.str(), "conda-forge 0% foo --"); - ostream.str(""); - - // 7: remove the current value - r.set_width(25).reset_fields(); - proxy.update_repr(); - proxy.print(ostream, 0, false); - EXPECT_EQ(ostream.str(), "conda-forge 0% --"); - ostream.str(""); - } + r.set_width(53); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 15); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.speed.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + + // 3: remove the speed + // available space redistributed to the bar + r.set_width(52); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 18); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + } - TEST_F(progress_bar, print_remove_elapsed) - { - auto& r = proxy.repr(); - - r.set_width(22).reset_fields(); - proxy.update_repr(); - EXPECT_TRUE(r.prefix); - EXPECT_TRUE(r.progress); - EXPECT_FALSE(r.current); - EXPECT_FALSE(r.separator); - EXPECT_FALSE(r.total); - EXPECT_FALSE(r.speed); - EXPECT_FALSE(r.postfix); - EXPECT_TRUE(r.elapsed); - proxy.print(ostream, 0, false); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 4); - EXPECT_EQ(r.elapsed.width(), 5); - EXPECT_EQ(ostream.str(), "conda-forge 0% --"); - ostream.str(""); - - // 8: remove the elapsed time - r.set_width(21); - proxy.update_repr(); - proxy.print(ostream, 0, false); - EXPECT_EQ(r.prefix.width(), 11); - EXPECT_EQ(r.progress.width(), 9); - EXPECT_EQ(ostream.str(), "conda-forge 0%"); - ostream.str(""); + TEST_CASE_FIXTURE(progress_bar, "print_remove_postfix") + { + auto& r = proxy.repr(); + + r.set_width(49); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 15); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.postfix.width(), 11); + CHECK_EQ(r.elapsed.width(), 5); + + // 4: remove the postfix + // available space redistributed to the bar + r.set_width(48); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK_FALSE(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 26); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.elapsed.width(), 5); + } + + TEST_CASE_FIXTURE(progress_bar, "print_truncate_prefix") + { + auto& r = proxy.repr(); + proxy.set_prefix("some_very_very_long_prefix"); + + r.set_width(52); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK_FALSE(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 26); + CHECK_EQ(r.progress.width(), 15); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.elapsed.width(), 5); + + // 5: truncate the prefix if too long + // available space redistributed to the prefix + r.set_width(51); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK_FALSE(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 25); + CHECK_EQ(r.progress.width(), 15); + CHECK_EQ(r.current.width(), 3); + CHECK_EQ(r.elapsed.width(), 5); + } + + TEST_CASE_FIXTURE(progress_bar, "print_without_bar") + { + auto& r = proxy.repr(); + + r.set_width(34).reset_fields(); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK_FALSE(r.postfix); + CHECK(r.elapsed); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 12); + CHECK_EQ(r.current.width(), 3); + // This fails because of invisible ANSI escape codes introduced with + // https://github.com/mamba-org/mamba/pull/2085/ + // CHECK(r.progress.overflow()); + CHECK_EQ(r.elapsed.width(), 5); + + // 6: display progress without a bar + r.set_width(33); + proxy.update_repr(); + proxy.print(ostream, 0, false); + CHECK_EQ(ostream.str(), "conda-forge 0% foo --"); + ostream.str(""); + } + + TEST_CASE_FIXTURE(progress_bar, "print_remove_current") + { + auto& r = proxy.repr(); + + r.set_width(26).reset_fields(); + proxy.update_repr(); + proxy.print(ostream, 0, false); + CHECK_EQ(ostream.str(), "conda-forge 0% foo --"); + ostream.str(""); + + // 7: remove the current value + r.set_width(25).reset_fields(); + proxy.update_repr(); + proxy.print(ostream, 0, false); + CHECK_EQ(ostream.str(), "conda-forge 0% --"); + ostream.str(""); + } + + TEST_CASE_FIXTURE(progress_bar, "print_remove_elapsed") + { + auto& r = proxy.repr(); + + r.set_width(22).reset_fields(); + proxy.update_repr(); + CHECK(r.prefix); + CHECK(r.progress); + CHECK_FALSE(r.current); + CHECK_FALSE(r.separator); + CHECK_FALSE(r.total); + CHECK_FALSE(r.speed); + CHECK_FALSE(r.postfix); + CHECK(r.elapsed); + proxy.print(ostream, 0, false); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 4); + CHECK_EQ(r.elapsed.width(), 5); + CHECK_EQ(ostream.str(), "conda-forge 0% --"); + ostream.str(""); + + // 8: remove the elapsed time + r.set_width(21); + proxy.update_repr(); + proxy.print(ostream, 0, false); + CHECK_EQ(r.prefix.width(), 11); + CHECK_EQ(r.progress.width(), 9); + CHECK_EQ(ostream.str(), "conda-forge 0%"); + ostream.str(""); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_satisfiability_error.cpp b/libmamba/tests/src/core/test_satisfiability_error.cpp index 1547c05620..62e0928260 100644 --- a/libmamba/tests/src/core/test_satisfiability_error.cpp +++ b/libmamba/tests/src/core/test_satisfiability_error.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -27,48 +26,53 @@ #include "mamba/core/util_random.hpp" #include "mamba/core/util_string.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(conflict_map, symetric) + TEST_SUITE("conflict_map") { - auto c = conflict_map(); - EXPECT_EQ(c.size(), 0); - EXPECT_FALSE(c.has_conflict(0)); - EXPECT_FALSE(c.in_conflict(0, 1)); - EXPECT_TRUE(c.add(0, 1)); - EXPECT_TRUE(c.add(1, 2)); - EXPECT_FALSE(c.add(1, 2)); - EXPECT_TRUE(c.has_conflict(0)); - EXPECT_TRUE(c.in_conflict(0, 1)); - EXPECT_TRUE(c.in_conflict(1, 2)); - EXPECT_TRUE(c.has_conflict(2)); - EXPECT_FALSE(c.in_conflict(0, 2)); - // With same - EXPECT_TRUE(c.add(5, 5)); - EXPECT_TRUE(c.has_conflict(5)); - EXPECT_TRUE(c.in_conflict(5, 5)); - } + TEST_CASE("symetric") + { + auto c = conflict_map(); + CHECK_EQ(c.size(), 0); + CHECK_FALSE(c.has_conflict(0)); + CHECK_FALSE(c.in_conflict(0, 1)); + CHECK(c.add(0, 1)); + CHECK(c.add(1, 2)); + CHECK_FALSE(c.add(1, 2)); + CHECK(c.has_conflict(0)); + CHECK(c.in_conflict(0, 1)); + CHECK(c.in_conflict(1, 2)); + CHECK(c.has_conflict(2)); + CHECK_FALSE(c.in_conflict(0, 2)); + // With same + CHECK(c.add(5, 5)); + CHECK(c.has_conflict(5)); + CHECK(c.in_conflict(5, 5)); + } - TEST(conflict_map, remove) - { - auto c = conflict_map({ { 1, 1 }, { 1, 2 }, { 1, 3 }, { 2, 4 } }); - ASSERT_EQ(c.size(), 4); - - ASSERT_TRUE(c.in_conflict(2, 4)); - ASSERT_TRUE(c.in_conflict(4, 2)); - EXPECT_TRUE(c.remove(2, 4)); - EXPECT_FALSE(c.in_conflict(4, 2)); - EXPECT_FALSE(c.in_conflict(2, 4)); - EXPECT_TRUE(c.has_conflict(2)); - EXPECT_FALSE(c.has_conflict(4)); - - EXPECT_FALSE(c.remove(2, 4)); - - EXPECT_TRUE(c.remove(1)); - EXPECT_FALSE(c.has_conflict(1)); - EXPECT_FALSE(c.in_conflict(1, 1)); - EXPECT_FALSE(c.in_conflict(1, 2)); - EXPECT_FALSE(c.in_conflict(3, 1)); + TEST_CASE("remove") + { + auto c = conflict_map({ { 1, 1 }, { 1, 2 }, { 1, 3 }, { 2, 4 } }); + REQUIRE_EQ(c.size(), 4); + + REQUIRE(c.in_conflict(2, 4)); + REQUIRE(c.in_conflict(4, 2)); + CHECK(c.remove(2, 4)); + CHECK_FALSE(c.in_conflict(4, 2)); + CHECK_FALSE(c.in_conflict(2, 4)); + CHECK(c.has_conflict(2)); + CHECK_FALSE(c.has_conflict(4)); + + CHECK_FALSE(c.remove(2, 4)); + + CHECK(c.remove(1)); + CHECK_FALSE(c.has_conflict(1)); + CHECK_FALSE(c.in_conflict(1, 1)); + CHECK_FALSE(c.in_conflict(1, 2)); + CHECK_FALSE(c.in_conflict(3, 1)); + } } /** @@ -154,11 +158,14 @@ namespace mamba /** * Test the test utility function. */ - TEST(satifiability_error, create_problem) + TEST_SUITE("satifiability_error") { - auto solver = create_problem(std::array{ mkpkg("foo", "0.1.0", {}) }, { "foo" }); - const auto solved = solver->try_solve(); - ASSERT_TRUE(solved); + TEST_CASE("create_problem") + { + auto solver = create_problem(std::array{ mkpkg("foo", "0.1.0", {}) }, { "foo" }); + const auto solved = solver->try_solve(); + REQUIRE(solved); + } } auto create_basic_conflict() -> MSolver& @@ -364,11 +371,14 @@ namespace mamba /** * Test the test utility function. */ - TEST(satifiability_error, create_conda_forge) + TEST_SUITE("satifiability_error") { - auto solver = create_conda_forge({ "xtensor>=0.7" }); - const auto solved = solver->try_solve(); - ASSERT_TRUE(solved); + TEST_CASE("create_conda_forge") + { + auto solver = create_conda_forge({ "xtensor>=0.7" }); + const auto solved = solver->try_solve(); + REQUIRE(solved); + } } auto create_pytorch_cpu() -> MSolver& @@ -433,10 +443,6 @@ namespace mamba return *solver; } - class Problem : public testing::TestWithParam - { - }; - template auto is_virtual_package(const NodeVariant& node) -> bool { @@ -454,210 +460,217 @@ namespace mamba ); }; - TEST_P(Problem, constructor) + namespace { - auto& solver = std::invoke(GetParam()); - const auto solved = solver.try_solve(); - ASSERT_FALSE(solved); - const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); - const auto& g = pbs.graph(); - - EXPECT_GE(g.number_of_nodes(), 1); - g.for_each_node_id( - [&](auto id) - { - const auto& node = g.node(id); - // Currently we do not make assumption about virtual package since - // we are not sure we are including them the same way than they would be in - // practice - if (!is_virtual_package(node)) - { - if (g.in_degree(id) == 0) - { - // Only one root node - EXPECT_EQ(id, pbs.root_node()); - EXPECT_TRUE(std::holds_alternative(node)); - } - else if (g.out_degree(id) == 0) - { - EXPECT_FALSE(std::holds_alternative(node)); - } - else - { - EXPECT_TRUE(std::holds_alternative(node)); - } - // All nodes reachable from the root - EXPECT_TRUE(is_reachable(pbs.graph(), pbs.root_node(), id)); - } - } - ); - - const auto& conflicts = pbs.conflicts(); - for (const auto& [n, _] : conflicts) - { - EXPECT_TRUE( - std::holds_alternative(g.node(n)) - || std::holds_alternative(g.node(n)) - ); - } + std::vector pb_values = { + create_basic_conflict, create_pubgrub, create_pubgrub_hard, create_pubgrub_missing, + create_pytorch_cpu, create_pytorch_cuda, create_cudatoolkit, create_jpeg9b, + create_r_base, create_scip, create_jupyterlab, create_double_python, + create_numba + }; } - TEST_P(Problem, simplify_conflicts) + TEST_SUITE("satifiability_error") { - auto& solver = std::invoke(GetParam()); - const auto solved = solver.try_solve(); - ASSERT_FALSE(solved); - const auto& pbs = ProblemsGraph::from_solver(solver, solver.pool()); - const auto& pbs_simplified = simplify_conflicts(pbs); - const auto& graph_simplified = pbs_simplified.graph(); - - EXPECT_GE(graph_simplified.number_of_nodes(), 1); - EXPECT_LE(graph_simplified.number_of_nodes(), pbs.graph().number_of_nodes()); - - for (const auto& [id, _] : pbs_simplified.conflicts()) + TEST_CASE("NamedList") { - const auto& node = graph_simplified.node(id); - // Currently we do not make assumption about virtual package since - // we are not sure we are including them the same way than they would be in - // practice - if (!is_virtual_package(node)) + auto l = CompressedProblemsGraph::PackageListNode(); + static constexpr std::size_t n_packages = 9; + for (std::size_t minor = 1; minor <= n_packages; ++minor) { - EXPECT_TRUE(graph_simplified.has_node(id)); - // Unfortunately not all conflicts are on leaves - // EXPECT_EQ(graph_simplified.out_degree(id), 0); - EXPECT_TRUE(is_reachable(graph_simplified, pbs_simplified.root_node(), id)); + l.insert({ mkpkg("pkg", fmt::format("0.{}.0", minor)) }); + } + CHECK_EQ(l.size(), n_packages); + CHECK_EQ(l.name(), "pkg"); + { + auto [str, size] = l.versions_trunc(", ", "...", 5); + CHECK_EQ(size, 9); + CHECK_EQ(str, "0.1.0, 0.2.0, ..., 0.9.0"); + } + { + auto [str, size] = l.build_strings_trunc(", ", "...", 5, false); + CHECK_EQ(size, 9); + CHECK_EQ(str, "bld, bld, ..., bld"); + } + { + auto [str, size] = l.build_strings_trunc(", ", "...", 5, true); + CHECK_EQ(size, 1); + CHECK_EQ(str, "bld"); + } + { + auto [str, size] = l.versions_and_build_strings_trunc("|", "---", 5); + CHECK_EQ(size, 9); + CHECK_EQ(str, "0.1.0 bld|0.2.0 bld|---|0.9.0 bld"); } } - } - TEST(satifiability_error, NamedList) - { - auto l = CompressedProblemsGraph::PackageListNode(); - static constexpr std::size_t n_packages = 9; - for (std::size_t minor = 1; minor <= n_packages; ++minor) - { - l.insert({ mkpkg("pkg", fmt::format("0.{}.0", minor)) }); - } - EXPECT_EQ(l.size(), n_packages); - EXPECT_EQ(l.name(), "pkg"); - { - auto [str, size] = l.versions_trunc(", ", "...", 5); - EXPECT_EQ(size, 9); - EXPECT_EQ(str, "0.1.0, 0.2.0, ..., 0.9.0"); - } + TEST_CASE("constructor") { - auto [str, size] = l.build_strings_trunc(", ", "...", 5, false); - EXPECT_EQ(size, 9); - EXPECT_EQ(str, "bld, bld, ..., bld"); - } - { - auto [str, size] = l.build_strings_trunc(", ", "...", 5, true); - EXPECT_EQ(size, 1); - EXPECT_EQ(str, "bld"); - } - { - auto [str, size] = l.versions_and_build_strings_trunc("|", "---", 5); - EXPECT_EQ(size, 9); - EXPECT_EQ(str, "0.1.0 bld|0.2.0 bld|---|0.9.0 bld"); + for (auto& p : pb_values) + { + CAPTURE(p); + auto& solver = p(); + const auto solved = solver.try_solve(); + REQUIRE_FALSE(solved); + const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); + const auto& g = pbs.graph(); + + REQUIRE_GE(g.number_of_nodes(), 1); + g.for_each_node_id( + [&](auto id) + { + const auto& node = g.node(id); + // Currently we do not make assumption about virtual package since + // we are not sure we are including them the same way than they would be in + // practice + if (!is_virtual_package(node)) + { + if (g.in_degree(id) == 0) + { + // Only one root node + CHECK_EQ(id, pbs.root_node()); + CHECK(std::holds_alternative(node)); + } + else if (g.out_degree(id) == 0) + { + CHECK_FALSE(std::holds_alternative(node)); + } + else + { + CHECK(std::holds_alternative(node)); + } + // All nodes reachable from the root + CHECK(is_reachable(pbs.graph(), pbs.root_node(), id)); + } + } + ); + + const auto& conflicts = pbs.conflicts(); + for (const auto& [n, _] : conflicts) + { + bool tmp = std::holds_alternative(g.node(n)) + || std::holds_alternative(g.node(n)); + CHECK(tmp); + } + } } - } - TEST_P(Problem, compression) - { - using CpPbGr = CompressedProblemsGraph; - - auto& solver = std::invoke(GetParam()); - const auto solved = solver.try_solve(); - ASSERT_FALSE(solved); - const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); - const auto cp_pbs = CpPbGr::from_problems_graph(simplify_conflicts(pbs)); - const auto& cp_g = cp_pbs.graph(); - - EXPECT_GE(pbs.graph().number_of_nodes(), cp_g.number_of_nodes()); - EXPECT_GE(cp_g.number_of_nodes(), 1); - cp_g.for_each_node_id( - [&](auto id) + TEST_CASE("simplify_conflicts") + { + for (auto& p : pb_values) { - const auto& node = cp_g.node(id); - // Currently we do not make assumption about virtual package since - // we are not sure we are including them the same way than they would be in - if (!is_virtual_package(node)) + CAPTURE(p); + auto& solver = p(); + const auto solved = solver.try_solve(); + REQUIRE_FALSE(solved); + const auto& pbs = ProblemsGraph::from_solver(solver, solver.pool()); + const auto& pbs_simplified = simplify_conflicts(pbs); + const auto& graph_simplified = pbs_simplified.graph(); + + REQUIRE_GE(graph_simplified.number_of_nodes(), 1); + REQUIRE_LE(graph_simplified.number_of_nodes(), pbs.graph().number_of_nodes()); + + for (const auto& [id, _] : pbs_simplified.conflicts()) { - if (cp_g.in_degree(id) == 0) + const auto& node = graph_simplified.node(id); + // Currently we do not make assumption about virtual package since + // we are not sure we are including them the same way than they would be in + // practice + if (!is_virtual_package(node)) { - // Only one root node - EXPECT_EQ(id, pbs.root_node()); - EXPECT_TRUE(std::holds_alternative(node)); + CHECK(graph_simplified.has_node(id)); + // Unfortunately not all conflicts are on leaves + // CHECK_EQ(graph_simplified.out_degree(id), 0); + CHECK(is_reachable(graph_simplified, pbs_simplified.root_node(), id)); } - else if (cp_g.out_degree(id) == 0) - { - EXPECT_FALSE(std::holds_alternative(node)); - } - else - { - EXPECT_TRUE(std::holds_alternative(node)); - } - // All nodes reachable from the root - EXPECT_TRUE(is_reachable(cp_g, cp_pbs.root_node(), id)); } } - ); + } - const auto& conflicts = cp_pbs.conflicts(); - for (const auto& [n, _] : conflicts) + TEST_CASE("compression") { - EXPECT_TRUE( - std::holds_alternative(cp_g.node(n)) - || std::holds_alternative(cp_g.node(n)) - ); - } - } + using CpPbGr = CompressedProblemsGraph; - TEST_P(Problem, problem_tree_str) - { - using CpPbGr = CompressedProblemsGraph; + for (auto& p : pb_values) + { + CAPTURE(p); + auto& solver = p(); + const auto solved = solver.try_solve(); + REQUIRE_FALSE(solved); + const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); + const auto cp_pbs = CpPbGr::from_problems_graph(simplify_conflicts(pbs)); + const auto& cp_g = cp_pbs.graph(); + + REQUIRE_GE(pbs.graph().number_of_nodes(), cp_g.number_of_nodes()); + REQUIRE_GE(cp_g.number_of_nodes(), 1); + cp_g.for_each_node_id( + [&](auto id) + { + const auto& node = cp_g.node(id); + // Currently we do not make assumption about virtual package since + // we are not sure we are including them the same way than they would be in + if (!is_virtual_package(node)) + { + if (cp_g.in_degree(id) == 0) + { + // Only one root node + CHECK_EQ(id, pbs.root_node()); + CHECK(std::holds_alternative(node)); + } + else if (cp_g.out_degree(id) == 0) + { + CHECK_FALSE(std::holds_alternative(node)); + } + else + { + CHECK(std::holds_alternative(node)); + } + // All nodes reachable from the root + CHECK(is_reachable(cp_g, cp_pbs.root_node(), id)); + } + } + ); - auto& solver = std::invoke(GetParam()); - const auto solved = solver.try_solve(); - ASSERT_FALSE(solved); - const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); - const auto cp_pbs = CpPbGr::from_problems_graph(simplify_conflicts(pbs)); - const auto message = problem_tree_msg(cp_pbs); + const auto& conflicts = cp_pbs.conflicts(); + for (const auto& [n, _] : conflicts) + { + bool tmp = std::holds_alternative(cp_g.node(n)) + || std::holds_alternative(cp_g.node(n)); + CHECK(tmp); + } + } + } - auto message_contains = [&message](const auto& node) + TEST_CASE("problem_tree_str") { - using Node = std::remove_cv_t>; - if constexpr (!std::is_same_v) - { - EXPECT_TRUE(contains(message, node.name())); - } - }; + using CpPbGr = CompressedProblemsGraph; - cp_pbs.graph().for_each_node_id( - [&message_contains, &g = cp_pbs.graph()](auto id) + for (auto& p : pb_values) { - std::visit(message_contains, g.node(id)); // + CAPTURE(p); + auto& solver = p(); + const auto solved = solver.try_solve(); + REQUIRE_FALSE(solved); + const auto pbs = ProblemsGraph::from_solver(solver, solver.pool()); + const auto cp_pbs = CpPbGr::from_problems_graph(simplify_conflicts(pbs)); + const auto message = problem_tree_msg(cp_pbs); + + auto message_contains = [&message](const auto& node) + { + using Node = std::remove_cv_t>; + if constexpr (!std::is_same_v) + { + CHECK(contains(message, node.name())); + } + }; + + cp_pbs.graph().for_each_node_id( + [&message_contains, &g = cp_pbs.graph()](auto id) + { + std::visit(message_contains, g.node(id)); // + } + ); } - ); + } } - - INSTANTIATE_TEST_SUITE_P( - satifiability_error, - Problem, - testing::Values( - create_basic_conflict, - create_pubgrub, - create_pubgrub_hard, - create_pubgrub_missing, - create_pytorch_cpu, - create_pytorch_cuda, - create_cudatoolkit, - create_jpeg9b, - create_r_base, - create_scip, - create_jupyterlab, - create_double_python, - create_numba - ) - ); } diff --git a/libmamba/tests/src/core/test_shell_init.cpp b/libmamba/tests/src/core/test_shell_init.cpp index 64a8d61a92..fb845e1fa8 100644 --- a/libmamba/tests/src/core/test_shell_init.cpp +++ b/libmamba/tests/src/core/test_shell_init.cpp @@ -1,28 +1,39 @@ -#include +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include #include "mamba/core/environment.hpp" #include "mamba/core/util.hpp" #include "mamba/core/util_string.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(shell_init, init) + TEST_SUITE("shell_init") { - // std::cout << rcfile_content("/home/wolfv/miniconda3/", "bash"); - } + TEST_CASE("init") + { + // std::cout << rcfile_content("/home/wolfv/miniconda3/", "bash"); + } - TEST(shell_init, bashrc_modifications) - { - // modify_rc_file("/home/wolfv/Programs/mamba/test/.bashrc", - // "/home/wolfv/superconda/", "bash"); - } + TEST_CASE("bashrc_modifications") + { + // modify_rc_file("/home/wolfv/Programs/mamba/test/.bashrc", + // "/home/wolfv/superconda/", "bash"); + } - TEST(shell_init, expand_user) - { - auto expanded = env::expand_user("~/this/is/a/test"); - if (on_linux) + TEST_CASE("expand_user") { - EXPECT_TRUE(starts_with(expanded.string(), "/home/")); + auto expanded = env::expand_user("~/this/is/a/test"); + if (on_linux) + { + CHECK(starts_with(expanded.string(), "/home/")); + } } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_tasksync.cpp b/libmamba/tests/src/core/test_tasksync.cpp index d9d87af280..a35191a850 100644 --- a/libmamba/tests/src/core/test_tasksync.cpp +++ b/libmamba/tests/src/core/test_tasksync.cpp @@ -1,199 +1,207 @@ +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include #include #include #include -#include - #include "mamba/core/tasksync.hpp" +#include "doctest/doctest.h" + namespace mamba { // WARNING: this file will be moved to xtl as soon as possible, do not rely on it's existence // here! - TEST(task_synchronizer, sync_types_never_move) + namespace { - static_assert(std::is_copy_constructible::value == false, ""); - static_assert(std::is_copy_assignable::value == false, ""); - static_assert(std::is_move_constructible::value == false, ""); - static_assert(std::is_move_assignable::value == false, ""); + void fail_now() + { + throw "this code should never be executed"; + } } - - TEST(task_synchronizer, no_task_no_problem) + namespace { - TaskSynchronizer task_sync; - task_sync.join_tasks(); + template + void wait_condition(Predicate&& predicate) + { + while (!std::invoke(std::forward(predicate))) + { + std::this_thread::yield(); + } + } } - TEST(task_synchronizer, tasks_are_joined_after_join_not_after_reset) + TEST_SUITE("task_synchronizer") { - TaskSynchronizer task_sync; - EXPECT_FALSE(task_sync.is_joined()); + TEST_CASE("sync_types_never_move") + { + static_assert(std::is_copy_constructible::value == false, ""); + static_assert(std::is_copy_assignable::value == false, ""); + static_assert(std::is_move_constructible::value == false, ""); + static_assert(std::is_move_assignable::value == false, ""); + } - task_sync.join_tasks(); - EXPECT_TRUE(task_sync.is_joined()); + TEST_CASE("no_task_no_problem") + { + TaskSynchronizer task_sync; + task_sync.join_tasks(); + } - task_sync.reset(); - EXPECT_FALSE(task_sync.is_joined()); + TEST_CASE("tasks_are_joined_after_join_not_after_reset") + { + TaskSynchronizer task_sync; + CHECK_FALSE(task_sync.is_joined()); - task_sync.join_tasks(); - EXPECT_TRUE(task_sync.is_joined()); - } + task_sync.join_tasks(); + CHECK(task_sync.is_joined()); - namespace - { - void fail_now() - { - throw "this code should never be executed"; - } - } + task_sync.reset(); + CHECK_FALSE(task_sync.is_joined()); - TEST(task_synchronizer, once_joined_tasks_are_noop) - { - TaskSynchronizer task_sync; - task_sync.join_tasks(); - EXPECT_TRUE(task_sync.is_joined()); + task_sync.join_tasks(); + CHECK(task_sync.is_joined()); + } - task_sync.join_tasks(); // nothing happen if we call it twice - EXPECT_TRUE(task_sync.is_joined()); + TEST_CASE("once_joined_tasks_are_noop") + { + TaskSynchronizer task_sync; + task_sync.join_tasks(); + CHECK(task_sync.is_joined()); - auto no_op = task_sync.synchronized([] { fail_now(); }); - no_op(); - } + task_sync.join_tasks(); // nothing happen if we call it twice + CHECK(task_sync.is_joined()); + auto no_op = task_sync.synchronized([] { fail_now(); }); + no_op(); + } - TEST(task_synchronizer, unexecuted_synched_task_never_blocks_join) - { - TaskSynchronizer task_sync; - auto synched_task = task_sync.synchronized([] { fail_now(); }); - task_sync.join_tasks(); - synched_task(); // noop - } + TEST_CASE("unexecuted_synched_task_never_blocks_join") + { + TaskSynchronizer task_sync; + auto synched_task = task_sync.synchronized([] { fail_now(); }); + task_sync.join_tasks(); + synched_task(); // noop + } - TEST(task_synchronizer, finished_synched_task_never_blocks_join) - { - int execution_count = 0; - TaskSynchronizer task_sync; - auto synched_task = task_sync.synchronized([&] { ++execution_count; }); - EXPECT_EQ(execution_count, 0); + TEST_CASE("finished_synched_task_never_blocks_join") + { + int execution_count = 0; + TaskSynchronizer task_sync; + auto synched_task = task_sync.synchronized([&] { ++execution_count; }); + CHECK_EQ(execution_count, 0); - synched_task(); - EXPECT_EQ(execution_count, 1); + synched_task(); + CHECK_EQ(execution_count, 1); - task_sync.join_tasks(); - EXPECT_EQ(execution_count, 1); + task_sync.join_tasks(); + CHECK_EQ(execution_count, 1); - synched_task(); - EXPECT_EQ(execution_count, 1); - } + synched_task(); + CHECK_EQ(execution_count, 1); + } - TEST(task_synchronizer, executed_synched_task_never_blocks_join) - { - int execution_count = 0; - TaskSynchronizer task_sync; + TEST_CASE("executed_synched_task_never_blocks_join") + { + int execution_count = 0; + TaskSynchronizer task_sync; - auto synched_task = task_sync.synchronized([&] { ++execution_count; }); - auto task_future = std::async(std::launch::async, synched_task); - task_future.wait(); + auto synched_task = task_sync.synchronized([&] { ++execution_count; }); + auto task_future = std::async(std::launch::async, synched_task); + task_future.wait(); - task_sync.join_tasks(); + task_sync.join_tasks(); - synched_task(); + synched_task(); - EXPECT_EQ(execution_count, 1); - } + CHECK_EQ(execution_count, 1); + } - namespace - { - template - void wait_condition(Predicate&& predicate) + TEST_CASE("executing_synched_task_always_block_join") { - while (!std::invoke(std::forward(predicate))) - { - std::this_thread::yield(); - } + std::string sequence; + TaskSynchronizer task_sync; + + const auto unlock_duration = std::chrono::seconds{ 1 }; + std::atomic task_started{ false }; + std::atomic task_continue{ false }; + std::atomic unlocker_ready{ false }; + std::atomic unlocker_start{ false }; + + auto ft_task = std::async( + std::launch::async, + task_sync.synchronized( + [&] + { + sequence.push_back('A'); + task_started = true; + wait_condition([&] { return task_continue.load(); }); + sequence.push_back('F'); + } + ) + ); + + wait_condition([&] { return task_started.load(); }); + CHECK_EQ(sequence, "A"); + + auto ft_unlocker = std::async( + std::launch::async, + task_sync.synchronized( + [&] + { + sequence.push_back('B'); + unlocker_ready = true; + wait_condition([&] { return unlocker_start.load(); }); + sequence.push_back('D'); + std::this_thread::sleep_for(unlock_duration); // Make sure the time is long + // enough for joining to + // happen only after. + sequence.push_back('E'); + task_continue = true; + } + ) + ); + + wait_condition([&] { return unlocker_ready.load(); }); + CHECK_EQ(sequence, "AB"); + + sequence.push_back('C'); + + const auto begin_time = std::chrono::high_resolution_clock::now(); + std::atomic_signal_fence(std::memory_order_acq_rel); // prevents the compiler from + // reordering + + unlocker_start = true; + task_sync.join_tasks(); + + std::atomic_signal_fence(std::memory_order_acq_rel); // prevents the compiler from + // reordering + const auto end_time = std::chrono::high_resolution_clock::now(); + + CHECK_EQ(sequence, "ABCDEF"); + REQUIRE_GE(end_time - begin_time, unlock_duration); } - } - - TEST(task_synchronizer, executing_synched_task_always_block_join) - { - std::string sequence; - TaskSynchronizer task_sync; - - const auto unlock_duration = std::chrono::seconds{ 1 }; - std::atomic task_started{ false }; - std::atomic task_continue{ false }; - std::atomic unlocker_ready{ false }; - std::atomic unlocker_start{ false }; - - auto ft_task = std::async( - std::launch::async, - task_sync.synchronized( - [&] - { - sequence.push_back('A'); - task_started = true; - wait_condition([&] { return task_continue.load(); }); - sequence.push_back('F'); - } - ) - ); - - wait_condition([&] { return task_started.load(); }); - EXPECT_EQ(sequence, "A"); - - auto ft_unlocker = std::async( - std::launch::async, - task_sync.synchronized( - [&] - { - sequence.push_back('B'); - unlocker_ready = true; - wait_condition([&] { return unlocker_start.load(); }); - sequence.push_back('D'); - std::this_thread::sleep_for(unlock_duration); // Make sure the time is long - // enough for joining to happen - // only after. - sequence.push_back('E'); - task_continue = true; - } - ) - ); - - wait_condition([&] { return unlocker_ready.load(); }); - EXPECT_EQ(sequence, "AB"); - - sequence.push_back('C'); - - const auto begin_time = std::chrono::high_resolution_clock::now(); - std::atomic_signal_fence(std::memory_order_acq_rel); // prevents the compiler from - // reordering - - unlocker_start = true; - task_sync.join_tasks(); - - std::atomic_signal_fence(std::memory_order_acq_rel); // prevents the compiler from - // reordering - const auto end_time = std::chrono::high_resolution_clock::now(); - - EXPECT_EQ(sequence, "ABCDEF"); - EXPECT_GE(end_time - begin_time, unlock_duration); - } - TEST(task_synchronizer, throwing_task_never_block_join) - { - TaskSynchronizer task_sync; + TEST_CASE("throwing_task_never_block_join") + { + TaskSynchronizer task_sync; - auto synched_task = task_sync.synchronized([] { throw 42; }); - auto task_future = std::async(std::launch::async, synched_task); - task_future.wait(); + auto synched_task = task_sync.synchronized([] { throw 42; }); + auto task_future = std::async(std::launch::async, synched_task); + task_future.wait(); - task_sync.join_tasks(); + task_sync.join_tasks(); - synched_task(); + synched_task(); - EXPECT_THROW(task_future.get(), int); + CHECK_THROWS_AS(task_future.get(), int); + } } } diff --git a/libmamba/tests/src/core/test_thread_utils.cpp b/libmamba/tests/src/core/test_thread_utils.cpp index f4d7523e13..71282635cb 100644 --- a/libmamba/tests/src/core/test_thread_utils.cpp +++ b/libmamba/tests/src/core/test_thread_utils.cpp @@ -1,10 +1,18 @@ -#include +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include #include "mamba/core/context.hpp" #include "mamba/core/execution.hpp" #include "mamba/core/output.hpp" #include "mamba/core/thread_utils.hpp" +#include "doctest/doctest.h" + namespace mamba { namespace @@ -17,7 +25,7 @@ namespace mamba int res = 0; // Ensures the compiler doe snot optimize away Context::instance() std::string current_command = Context::instance().current_command; - EXPECT_EQ(current_command, "mamba"); + CHECK_EQ(current_command, "mamba"); Console::instance().init_progress_bar_manager(ProgressBarMode::multi); { interruption_guard g( @@ -55,32 +63,35 @@ namespace mamba return res; } - TEST(thread_utils, interrupt) + TEST_SUITE("thread_utils") { - int res = test_interruption_guard(true); - EXPECT_EQ(res, -95); - } + TEST_CASE("interrupt") + { + int res = test_interruption_guard(true); + CHECK_EQ(res, -95); + } - TEST(thread_utils, no_interrupt) - { - int res = test_interruption_guard(false); - EXPECT_EQ(res, 5); - } + TEST_CASE("no_interrupt") + { + int res = test_interruption_guard(false); + CHECK_EQ(res, 5); + } - TEST(thread_utils, no_interrupt_then_interrupt) - { - int res = test_interruption_guard(false); - EXPECT_EQ(res, 5); - int res2 = test_interruption_guard(true); - EXPECT_EQ(res2, -95); - } + TEST_CASE("no_interrupt_then_interrupt") + { + int res = test_interruption_guard(false); + CHECK_EQ(res, 5); + int res2 = test_interruption_guard(true); + CHECK_EQ(res2, -95); + } - TEST(thread_utils, no_interrupt_sequence) - { - int res = test_interruption_guard(false); - EXPECT_EQ(res, 5); - int res2 = test_interruption_guard(false); - EXPECT_EQ(res2, 5); + TEST_CASE("no_interrupt_sequence") + { + int res = test_interruption_guard(false); + CHECK_EQ(res, 5); + int res2 = test_interruption_guard(false); + CHECK_EQ(res2, 5); + } } #endif } // namespace mamba diff --git a/libmamba/tests/src/core/test_transfer.cpp b/libmamba/tests/src/core/test_transfer.cpp index c50fe005d4..62d030d600 100644 --- a/libmamba/tests/src/core/test_transfer.cpp +++ b/libmamba/tests/src/core/test_transfer.cpp @@ -1,49 +1,60 @@ -#include +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include #include "mamba/core/subdirdata.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(transfer, file_not_exist) + TEST_SUITE("transfer") { -#ifdef __linux__ - Context::instance().quiet = true; + TEST_CASE("file_not_exist") { - const mamba::Channel& c = mamba::make_channel("conda-forge"); - mamba::MultiDownloadTarget multi_dl; - mamba::MultiPackageCache pkg_cache({ "/tmp/" }); - mamba::MSubdirData cf = mamba::MSubdirData::create( - c, - "linux-64", - "file:///nonexistent/repodata.json", - pkg_cache - ) - .value(); - multi_dl.add(cf.target()); +#ifdef __linux__ + Context::instance().quiet = true; + { + const mamba::Channel& c = mamba::make_channel("conda-forge"); + mamba::MultiDownloadTarget multi_dl; + mamba::MultiPackageCache pkg_cache({ "/tmp/" }); + mamba::MSubdirData cf = mamba::MSubdirData::create( + c, + "linux-64", + "file:///nonexistent/repodata.json", + pkg_cache + ) + .value(); + multi_dl.add(cf.target()); - // file:// url should not retry - EXPECT_EQ(cf.target()->can_retry(), false); + // file:// url should not retry + CHECK_EQ(cf.target()->can_retry(), false); - multi_dl.download(MAMBA_DOWNLOAD_FAILFAST); + multi_dl.download(MAMBA_DOWNLOAD_FAILFAST); - // File does not exist - EXPECT_EQ(cf.target()->result, 37); - } - { - const mamba::Channel& c = mamba::make_channel("conda-forge"); - mamba::MultiDownloadTarget multi_dl; - mamba::MultiPackageCache pkg_cache({ "/tmp/" }); - mamba::MSubdirData cf = mamba::MSubdirData::create( - c, - "noarch", - "file:///nonexistent/repodata.json", - pkg_cache - ) - .value(); - multi_dl.add(cf.target()); - EXPECT_THROW(multi_dl.download(MAMBA_DOWNLOAD_FAILFAST), std::runtime_error); - } - Context::instance().quiet = false; + // File does not exist + CHECK_EQ(cf.target()->result, 37); + } + { + const mamba::Channel& c = mamba::make_channel("conda-forge"); + mamba::MultiDownloadTarget multi_dl; + mamba::MultiPackageCache pkg_cache({ "/tmp/" }); + mamba::MSubdirData cf = mamba::MSubdirData::create( + c, + "noarch", + "file:///nonexistent/repodata.json", + pkg_cache + ) + .value(); + multi_dl.add(cf.target()); + CHECK_THROWS_AS(multi_dl.download(MAMBA_DOWNLOAD_FAILFAST), std::runtime_error); + } + Context::instance().quiet = false; #endif + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_url.cpp b/libmamba/tests/src/core/test_url.cpp index bc876097c2..922a86ae57 100644 --- a/libmamba/tests/src/core/test_url.cpp +++ b/libmamba/tests/src/core/test_url.cpp @@ -1,7 +1,13 @@ -#include +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/core/url.hpp" +#include "doctest/doctest.h" + #ifdef _WIN32 #include "mamba/core/mamba_fs.hpp" #endif @@ -14,242 +20,245 @@ namespace mamba "win-32", "win-64", "zos-z" }; - TEST(url, parse) + TEST_SUITE("url") { + TEST_CASE("parse") { - URLHandler m("http://mamba.org"); - EXPECT_EQ(m.scheme(), "http"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - } - { - URLHandler m("s3://userx123:üúßsajd@mamba.org"); - EXPECT_EQ(m.scheme(), "s3"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - EXPECT_EQ(m.user(), "userx123"); - EXPECT_EQ(m.password(), "üúßsajd"); - } - // { - // URLHandler m("http://user@email.com:test@localhost:8000"); - // EXPECT_EQ(m.scheme(), "http"); - // EXPECT_EQ(m.path(), "/"); - // EXPECT_EQ(m.host(), "localhost"); - // EXPECT_EQ(m.port(), "8000"); - // EXPECT_EQ(m.user(), "user@email.com"); - // EXPECT_EQ(m.password(), "test"); - // } - { - URLHandler m("https://mamba🆒🔬.org/this/is/a/path/?query=123&xyz=3333"); - EXPECT_EQ(m.scheme(), "https"); - EXPECT_EQ(m.path(), "/this/is/a/path/"); - EXPECT_EQ(m.host(), "mamba🆒🔬.org"); - EXPECT_EQ(m.query(), "query=123&xyz=3333"); - } - { + { + URLHandler m("http://mamba.org"); + CHECK_EQ(m.scheme(), "http"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + } + { + URLHandler m("s3://userx123:üúßsajd@mamba.org"); + CHECK_EQ(m.scheme(), "s3"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + CHECK_EQ(m.user(), "userx123"); + CHECK_EQ(m.password(), "üúßsajd"); + } + // { + // URLHandler m("http://user@email.com:test@localhost:8000"); + // CHECK_EQ(m.scheme(), "http"); + // CHECK_EQ(m.path(), "/"); + // CHECK_EQ(m.host(), "localhost"); + // CHECK_EQ(m.port(), "8000"); + // CHECK_EQ(m.user(), "user@email.com"); + // CHECK_EQ(m.password(), "test"); + // } + { + URLHandler m("https://mamba🆒🔬.org/this/is/a/path/?query=123&xyz=3333"); + CHECK_EQ(m.scheme(), "https"); + CHECK_EQ(m.path(), "/this/is/a/path/"); + CHECK_EQ(m.host(), "mamba🆒🔬.org"); + CHECK_EQ(m.query(), "query=123&xyz=3333"); + } + { #ifdef _WIN32 - URLHandler m("file://C:/Users/wolfv/test/document.json"); - EXPECT_EQ(m.scheme(), "file"); - EXPECT_EQ(m.path(), "C:/Users/wolfv/test/document.json"); + URLHandler m("file://C:/Users/wolfv/test/document.json"); + CHECK_EQ(m.scheme(), "file"); + CHECK_EQ(m.path(), "C:/Users/wolfv/test/document.json"); #else - URLHandler m("file:///home/wolfv/test/document.json"); - EXPECT_EQ(m.scheme(), "file"); - EXPECT_EQ(m.path(), "/home/wolfv/test/document.json"); + URLHandler m("file:///home/wolfv/test/document.json"); + CHECK_EQ(m.scheme(), "file"); + CHECK_EQ(m.path(), "/home/wolfv/test/document.json"); #endif + } } - } - TEST(url, path_to_url) - { - auto url = path_to_url("/users/test/miniconda3"); + TEST_CASE("path_to_url") + { + auto url = path_to_url("/users/test/miniconda3"); #ifndef _WIN32 - EXPECT_EQ(url, "file:///users/test/miniconda3"); + CHECK_EQ(url, "file:///users/test/miniconda3"); #else - std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); - EXPECT_EQ(url, std::string("file://") + driveletter + ":/users/test/miniconda3"); - auto url2 = path_to_url("D:\\users\\test\\miniconda3"); - EXPECT_EQ(url2, "file://D:/users/test/miniconda3"); + std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); + CHECK_EQ(url, std::string("file://") + driveletter + ":/users/test/miniconda3"); + auto url2 = path_to_url("D:\\users\\test\\miniconda3"); + CHECK_EQ(url2, "file://D:/users/test/miniconda3"); #endif - } - - TEST(url, unc_url) - { - { - auto out = unc_url("http://example.com/test"); - EXPECT_EQ(out, "http://example.com/test"); - } - { - auto out = unc_url("file://C:/Program\\ (x74)/Users/hello\\ world"); - EXPECT_EQ(out, "file://C:/Program\\ (x74)/Users/hello\\ world"); - } - { - auto out = unc_url("file:///C:/Program\\ (x74)/Users/hello\\ world"); - EXPECT_EQ(out, "file:///C:/Program\\ (x74)/Users/hello\\ world"); - } - { - auto out = unc_url("file:////server/share"); - EXPECT_EQ(out, "file:////server/share"); - } - { - auto out = unc_url("file:///absolute/path"); - EXPECT_EQ(out, "file:///absolute/path"); } - { - auto out = unc_url("file://server/share"); - EXPECT_EQ(out, "file:////server/share"); - } - { - auto out = unc_url("file://server"); - EXPECT_EQ(out, "file:////server"); - } - } - - TEST(url, has_scheme) - { - std::string url = "http://mamba.org"; - std::string not_url = "mamba.org"; - - EXPECT_TRUE(has_scheme(url)); - EXPECT_FALSE(has_scheme(not_url)); - EXPECT_FALSE(has_scheme("")); - } - TEST(url, value_semantic) - { + TEST_CASE("unc_url") { - URLHandler in("s3://userx123:üúßsajd@mamba.org"); - URLHandler m(in); - EXPECT_EQ(m.scheme(), "s3"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - EXPECT_EQ(m.user(), "userx123"); - EXPECT_EQ(m.password(), "üúßsajd"); + { + auto out = unc_url("http://example.com/test"); + CHECK_EQ(out, "http://example.com/test"); + } + { + auto out = unc_url("file://C:/Program\\ (x74)/Users/hello\\ world"); + CHECK_EQ(out, "file://C:/Program\\ (x74)/Users/hello\\ world"); + } + { + auto out = unc_url("file:///C:/Program\\ (x74)/Users/hello\\ world"); + CHECK_EQ(out, "file:///C:/Program\\ (x74)/Users/hello\\ world"); + } + { + auto out = unc_url("file:////server/share"); + CHECK_EQ(out, "file:////server/share"); + } + { + auto out = unc_url("file:///absolute/path"); + CHECK_EQ(out, "file:///absolute/path"); + } + { + auto out = unc_url("file://server/share"); + CHECK_EQ(out, "file:////server/share"); + } + { + auto out = unc_url("file://server"); + CHECK_EQ(out, "file:////server"); + } } + TEST_CASE("has_scheme") { - URLHandler m("http://mamba.org"); - URLHandler in("s3://userx123:üúßsajd@mamba.org"); - m = in; - EXPECT_EQ(m.scheme(), "s3"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - EXPECT_EQ(m.user(), "userx123"); - EXPECT_EQ(m.password(), "üúßsajd"); - } + std::string url = "http://mamba.org"; + std::string not_url = "mamba.org"; - { - URLHandler in("s3://userx123:üúßsajd@mamba.org"); - URLHandler m(std::move(in)); - EXPECT_EQ(m.scheme(), "s3"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - EXPECT_EQ(m.user(), "userx123"); - EXPECT_EQ(m.password(), "üúßsajd"); + CHECK(has_scheme(url)); + CHECK_FALSE(has_scheme(not_url)); + CHECK_FALSE(has_scheme("")); } + TEST_CASE("value_semantic") { - URLHandler m("http://mamba.org"); - URLHandler in("s3://userx123:üúßsajd@mamba.org"); - m = std::move(in); - EXPECT_EQ(m.scheme(), "s3"); - EXPECT_EQ(m.path(), "/"); - EXPECT_EQ(m.host(), "mamba.org"); - EXPECT_EQ(m.user(), "userx123"); - EXPECT_EQ(m.password(), "üúßsajd"); - } - } + { + URLHandler in("s3://userx123:üúßsajd@mamba.org"); + URLHandler m(in); + CHECK_EQ(m.scheme(), "s3"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + CHECK_EQ(m.user(), "userx123"); + CHECK_EQ(m.password(), "üúßsajd"); + } - TEST(url, split_ananconda_token) - { - std::string input, cleaned_url, token; - { - input = "https://1.2.3.4/t/tk-123-456/path"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://1.2.3.4/path"); - EXPECT_EQ(token, "tk-123-456"); - } + { + URLHandler m("http://mamba.org"); + URLHandler in("s3://userx123:üúßsajd@mamba.org"); + m = in; + CHECK_EQ(m.scheme(), "s3"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + CHECK_EQ(m.user(), "userx123"); + CHECK_EQ(m.password(), "üúßsajd"); + } - { - input = "https://1.2.3.4/t//path"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://1.2.3.4/path"); - EXPECT_EQ(token, ""); - } + { + URLHandler in("s3://userx123:üúßsajd@mamba.org"); + URLHandler m(std::move(in)); + CHECK_EQ(m.scheme(), "s3"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + CHECK_EQ(m.user(), "userx123"); + CHECK_EQ(m.password(), "üúßsajd"); + } - { - input = "https://some.domain/api/t/tk-123-456/path"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://some.domain/api/path"); - EXPECT_EQ(token, "tk-123-456"); + { + URLHandler m("http://mamba.org"); + URLHandler in("s3://userx123:üúßsajd@mamba.org"); + m = std::move(in); + CHECK_EQ(m.scheme(), "s3"); + CHECK_EQ(m.path(), "/"); + CHECK_EQ(m.host(), "mamba.org"); + CHECK_EQ(m.user(), "userx123"); + CHECK_EQ(m.password(), "üúßsajd"); + } } + TEST_CASE("split_ananconda_token") { - input = "https://1.2.3.4/conda/t/tk-123-456/path"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://1.2.3.4/conda/path"); - EXPECT_EQ(token, "tk-123-456"); - } + std::string input, cleaned_url, token; + { + input = "https://1.2.3.4/t/tk-123-456/path"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://1.2.3.4/path"); + CHECK_EQ(token, "tk-123-456"); + } - { - input = "https://1.2.3.4/path"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://1.2.3.4/path"); - EXPECT_EQ(token, ""); + { + input = "https://1.2.3.4/t//path"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://1.2.3.4/path"); + CHECK_EQ(token, ""); + } + + { + input = "https://some.domain/api/t/tk-123-456/path"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://some.domain/api/path"); + CHECK_EQ(token, "tk-123-456"); + } + + { + input = "https://1.2.3.4/conda/t/tk-123-456/path"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://1.2.3.4/conda/path"); + CHECK_EQ(token, "tk-123-456"); + } + + { + input = "https://1.2.3.4/path"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://1.2.3.4/path"); + CHECK_EQ(token, ""); + } + + { + input = "https://10.2.3.4:8080/conda/t/tk-123-45"; + split_anaconda_token(input, cleaned_url, token); + CHECK_EQ(cleaned_url, "https://10.2.3.4:8080/conda"); + CHECK_EQ(token, "tk-123-45"); + } } + TEST_CASE("split_scheme_auth_token") { - input = "https://10.2.3.4:8080/conda/t/tk-123-45"; - split_anaconda_token(input, cleaned_url, token); - EXPECT_EQ(cleaned_url, "https://10.2.3.4:8080/conda"); - EXPECT_EQ(token, "tk-123-45"); - } - } + std::string input = "https://u:p@conda.io/t/x1029384756/more/path"; + std::string input2 = "https://u:p@conda.io/t/a_-12345-absdj12345-xyxyxyx/more/path"; + std::string remaining_url, scheme, auth, token; + split_scheme_auth_token(input, remaining_url, scheme, auth, token); + CHECK_EQ(remaining_url, "conda.io/more/path"); + CHECK_EQ(scheme, "https"); + CHECK_EQ(auth, "u:p"); + CHECK_EQ(token, "x1029384756"); - TEST(url, split_scheme_auth_token) - { - std::string input = "https://u:p@conda.io/t/x1029384756/more/path"; - std::string input2 = "https://u:p@conda.io/t/a_-12345-absdj12345-xyxyxyx/more/path"; - std::string remaining_url, scheme, auth, token; - split_scheme_auth_token(input, remaining_url, scheme, auth, token); - EXPECT_EQ(remaining_url, "conda.io/more/path"); - EXPECT_EQ(scheme, "https"); - EXPECT_EQ(auth, "u:p"); - EXPECT_EQ(token, "x1029384756"); - - split_scheme_auth_token(input2, remaining_url, scheme, auth, token); - EXPECT_EQ(remaining_url, "conda.io/more/path"); - EXPECT_EQ(scheme, "https"); - EXPECT_EQ(auth, "u:p"); - EXPECT_EQ(token, "a_-12345-absdj12345-xyxyxyx"); + split_scheme_auth_token(input2, remaining_url, scheme, auth, token); + CHECK_EQ(remaining_url, "conda.io/more/path"); + CHECK_EQ(scheme, "https"); + CHECK_EQ(auth, "u:p"); + CHECK_EQ(token, "a_-12345-absdj12345-xyxyxyx"); #ifdef _WIN32 - split_scheme_auth_token("file://C:/Users/wolfv/test.json", remaining_url, scheme, auth, token); - EXPECT_EQ(remaining_url, "C:/Users/wolfv/test.json"); - EXPECT_EQ(scheme, "file"); - EXPECT_EQ(auth, ""); - EXPECT_EQ(token, ""); + split_scheme_auth_token("file://C:/Users/wolfv/test.json", remaining_url, scheme, auth, token); + CHECK_EQ(remaining_url, "C:/Users/wolfv/test.json"); + CHECK_EQ(scheme, "file"); + CHECK_EQ(auth, ""); + CHECK_EQ(token, ""); #else - split_scheme_auth_token("file:///home/wolfv/test.json", remaining_url, scheme, auth, token); - EXPECT_EQ(remaining_url, "/home/wolfv/test.json"); - EXPECT_EQ(scheme, "file"); - EXPECT_EQ(auth, ""); - EXPECT_EQ(token, ""); + split_scheme_auth_token("file:///home/wolfv/test.json", remaining_url, scheme, auth, token); + CHECK_EQ(remaining_url, "/home/wolfv/test.json"); + CHECK_EQ(scheme, "file"); + CHECK_EQ(auth, ""); + CHECK_EQ(token, ""); #endif - } + } - TEST(path, is_path) - { - EXPECT_TRUE(is_path("./")); - EXPECT_TRUE(is_path("..")); - EXPECT_TRUE(is_path("~")); - EXPECT_TRUE(is_path("/")); - EXPECT_FALSE(is_path("file://makefile")); - } + TEST_CASE("is_path") + { + CHECK(is_path("./")); + CHECK(is_path("..")); + CHECK(is_path("~")); + CHECK(is_path("/")); + CHECK_FALSE(is_path("file://makefile")); + } - TEST(url, cache_name_from_url) - { - EXPECT_EQ(cache_name_from_url("http://test.com/1234/"), "302f0a61"); - EXPECT_EQ(cache_name_from_url("http://test.com/1234/repodata.json"), "302f0a61"); - EXPECT_EQ(cache_name_from_url("http://test.com/1234/current_repodata.json"), "78a8cce9"); + TEST_CASE("cache_name_from_url") + { + CHECK_EQ(cache_name_from_url("http://test.com/1234/"), "302f0a61"); + CHECK_EQ(cache_name_from_url("http://test.com/1234/repodata.json"), "302f0a61"); + CHECK_EQ(cache_name_from_url("http://test.com/1234/current_repodata.json"), "78a8cce9"); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_util.cpp b/libmamba/tests/src/core/test_util.cpp index 767171601b..c076329d74 100644 --- a/libmamba/tests/src/core/test_util.cpp +++ b/libmamba/tests/src/core/test_util.cpp @@ -4,8 +4,6 @@ // // The full license is in the file LICENSE, distributed with this software. -#include - #include "mamba/core/context.hpp" #include "mamba/core/environment.hpp" #include "mamba/core/execution.hpp" @@ -15,165 +13,190 @@ #include "mamba/core/util_random.hpp" #include "mamba/core/util_scope.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(local_random_generator, one_rng_per_thread_and_type) + TEST_SUITE("local_random_generator") { - auto same_thread_checks = [] + TEST_CASE("one_rng_per_thread_and_type") { - auto& a = local_random_generator(); - auto& b = local_random_generator(); - EXPECT_EQ(&a, &b); + auto same_thread_checks = [] + { + auto& a = local_random_generator(); + auto& b = local_random_generator(); + CHECK_EQ(&a, &b); - auto& c = local_random_generator(); - EXPECT_EQ(&a, &c); + auto& c = local_random_generator(); + CHECK_EQ(&a, &c); - auto& d = local_random_generator(); - EXPECT_NE(static_cast(&a), static_cast(&d)); + auto& d = local_random_generator(); + CHECK_NE(static_cast(&a), static_cast(&d)); - return &a; - }; - void* pointer_to_this_thread_rng = same_thread_checks(); + return &a; + }; + void* pointer_to_this_thread_rng = same_thread_checks(); - void* pointer_to_another_thread_rng = nullptr; - std::thread another_thread{ [&] { pointer_to_another_thread_rng = same_thread_checks(); } }; - another_thread.join(); + void* pointer_to_another_thread_rng = nullptr; + std::thread another_thread{ [&] + { pointer_to_another_thread_rng = same_thread_checks(); } }; + another_thread.join(); - EXPECT_NE(pointer_to_this_thread_rng, pointer_to_another_thread_rng); + CHECK_NE(pointer_to_this_thread_rng, pointer_to_another_thread_rng); + } } - TEST(random_int, value_in_range) + TEST_SUITE("random_int") { - constexpr int arbitrary_min = -20; - constexpr int arbitrary_max = 20; - constexpr int attempts = 2000; - for (int i = 0; i < attempts; ++i) + TEST_CASE("value_in_range") { - const int value = random_int(arbitrary_min, arbitrary_max); - EXPECT_GE(value, arbitrary_min); - EXPECT_LE(value, arbitrary_max); + constexpr int arbitrary_min = -20; + constexpr int arbitrary_max = 20; + constexpr int attempts = 2000; + for (int i = 0; i < attempts; ++i) + { + const int value = random_int(arbitrary_min, arbitrary_max); + REQUIRE_GE(value, arbitrary_min); + REQUIRE_LE(value, arbitrary_max); + } } } - TEST(on_scope_exit, basics) + TEST_SUITE("on_scope_exit") { - bool executed = false; + TEST_CASE("basics") { - on_scope_exit _{ [&] { executed = true; } }; - EXPECT_FALSE(executed); + bool executed = false; + { + on_scope_exit _{ [&] { executed = true; } }; + CHECK_FALSE(executed); + } + CHECK(executed); } - EXPECT_TRUE(executed); } - TEST(is_yaml_file_name, basics) + TEST_SUITE("is_yaml_file_name") { - EXPECT_TRUE(is_yaml_file_name("something.yaml")); - EXPECT_TRUE(is_yaml_file_name("something.yml")); - EXPECT_TRUE(is_yaml_file_name("something-lock.yaml")); - EXPECT_TRUE(is_yaml_file_name("something-lock.yml")); - EXPECT_TRUE(is_yaml_file_name("/some/dir/something.yaml")); - EXPECT_TRUE(is_yaml_file_name("/some/dir/something.yaml")); - EXPECT_TRUE(is_yaml_file_name("../../some/dir/something.yml")); - EXPECT_TRUE(is_yaml_file_name("../../some/dir/something.yml")); - - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "something.yaml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "something.yml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "something-lock.yaml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "something-lock.yml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "/some/dir/something.yaml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "/some/dir/something.yml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "../../some/dir/something.yaml" }.string())); - EXPECT_TRUE(is_yaml_file_name(fs::u8path{ "../../some/dir/something.yml" }.string())); - - EXPECT_FALSE(is_yaml_file_name("something")); - EXPECT_FALSE(is_yaml_file_name("something-lock")); - EXPECT_FALSE(is_yaml_file_name("/some/dir/something")); - EXPECT_FALSE(is_yaml_file_name("../../some/dir/something")); - - EXPECT_FALSE(is_yaml_file_name(fs::u8path{ "something" }.string())); - EXPECT_FALSE(is_yaml_file_name(fs::u8path{ "something-lock" }.string())); - EXPECT_FALSE(is_yaml_file_name(fs::u8path{ "/some/dir/something" }.string())); - EXPECT_FALSE(is_yaml_file_name(fs::u8path{ "../../some/dir/something" }.string())); + TEST_CASE("basics") + { + CHECK(is_yaml_file_name("something.yaml")); + CHECK(is_yaml_file_name("something.yml")); + CHECK(is_yaml_file_name("something-lock.yaml")); + CHECK(is_yaml_file_name("something-lock.yml")); + CHECK(is_yaml_file_name("/some/dir/something.yaml")); + CHECK(is_yaml_file_name("/some/dir/something.yaml")); + CHECK(is_yaml_file_name("../../some/dir/something.yml")); + CHECK(is_yaml_file_name("../../some/dir/something.yml")); + + CHECK(is_yaml_file_name(fs::u8path{ "something.yaml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "something.yml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "something-lock.yaml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "something-lock.yml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "/some/dir/something.yaml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "/some/dir/something.yml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "../../some/dir/something.yaml" }.string())); + CHECK(is_yaml_file_name(fs::u8path{ "../../some/dir/something.yml" }.string())); + + CHECK_FALSE(is_yaml_file_name("something")); + CHECK_FALSE(is_yaml_file_name("something-lock")); + CHECK_FALSE(is_yaml_file_name("/some/dir/something")); + CHECK_FALSE(is_yaml_file_name("../../some/dir/something")); + + CHECK_FALSE(is_yaml_file_name(fs::u8path{ "something" }.string())); + CHECK_FALSE(is_yaml_file_name(fs::u8path{ "something-lock" }.string())); + CHECK_FALSE(is_yaml_file_name(fs::u8path{ "/some/dir/something" }.string())); + CHECK_FALSE(is_yaml_file_name(fs::u8path{ "../../some/dir/something" }.string())); + } } - TEST(utils, encode_decode_base64) + TEST_SUITE("utils") { - for (std::size_t i = 1; i < 20; ++i) + TEST_CASE("encode_decode_base64") { - for (std::size_t j = 0; j < 5; ++j) + for (std::size_t i = 1; i < 20; ++i) { - std::string r = mamba::generate_random_alphanumeric_string(i); - auto e = encode_base64(r); - EXPECT_TRUE(e); - auto x = decode_base64(e.value()); - EXPECT_TRUE(x); - EXPECT_EQ(r, x.value()); + for (std::size_t j = 0; j < 5; ++j) + { + std::string r = mamba::generate_random_alphanumeric_string(i); + auto e = encode_base64(r); + CHECK(e); + auto x = decode_base64(e.value()); + CHECK(x); + CHECK_EQ(r, x.value()); + } } } } - TEST(fsutils, is_writable) + TEST_SUITE("fsutils") { - const auto test_dir_path = fs::temp_directory_path() / "libmamba" / "writable_tests"; - fs::create_directories(test_dir_path); - on_scope_exit _{ [&] - { - fs::permissions(test_dir_path, fs::perms::all); - fs::remove_all(test_dir_path); - } }; - - EXPECT_TRUE(path::is_writable(test_dir_path)); - fs::permissions(test_dir_path, fs::perms::none); - EXPECT_FALSE(path::is_writable(test_dir_path)); - fs::permissions(test_dir_path, fs::perms::all); - EXPECT_TRUE(path::is_writable(test_dir_path)); - - EXPECT_TRUE(path::is_writable(test_dir_path / "non-existing-writable-test-delete-me.txt")); - EXPECT_TRUE(path::is_writable( - env::expand_user("~/.libmamba-non-existing-writable-test-delete-me.txt") - )); - + TEST_CASE("is_writable") { - const auto existing_file_path = test_dir_path / "existing-writable-test-delete-me.txt"; + const auto test_dir_path = fs::temp_directory_path() / "libmamba" / "writable_tests"; + fs::create_directories(test_dir_path); + on_scope_exit _{ [&] + { + fs::permissions(test_dir_path, fs::perms::all); + fs::remove_all(test_dir_path); + } }; + + CHECK(path::is_writable(test_dir_path)); + fs::permissions(test_dir_path, fs::perms::none); + CHECK_FALSE(path::is_writable(test_dir_path)); + fs::permissions(test_dir_path, fs::perms::all); + CHECK(path::is_writable(test_dir_path)); + + CHECK(path::is_writable(test_dir_path / "non-existing-writable-test-delete-me.txt")); + CHECK(path::is_writable( + env::expand_user("~/.libmamba-non-existing-writable-test-delete-me.txt") + )); + { - std::ofstream temp_file{ existing_file_path.std_path() }; - ASSERT_TRUE(temp_file.is_open()); - temp_file << "delete me" << std::endl; + const auto existing_file_path = test_dir_path + / "existing-writable-test-delete-me.txt"; + { + std::ofstream temp_file{ existing_file_path.std_path() }; + REQUIRE(temp_file.is_open()); + temp_file << "delete me" << std::endl; + } + CHECK(path::is_writable(existing_file_path)); + fs::permissions(existing_file_path, fs::perms::none); + CHECK_FALSE(path::is_writable(existing_file_path)); + fs::permissions(existing_file_path, fs::perms::all); + CHECK(path::is_writable(existing_file_path)); } - EXPECT_TRUE(path::is_writable(existing_file_path)); - fs::permissions(existing_file_path, fs::perms::none); - EXPECT_FALSE(path::is_writable(existing_file_path)); - fs::permissions(existing_file_path, fs::perms::all); - EXPECT_TRUE(path::is_writable(existing_file_path)); } } - TEST(utils, proxy_match) + TEST_SUITE("utils") { - Context::instance().proxy_servers = { { "http", "foo" }, - { "https", "bar" }, - { "https://example.net", "foobar" }, - { "all://example.net", "baz" }, - { "all", "other" } }; - - EXPECT_EQ(*proxy_match("http://example.com/channel"), "foo"); - EXPECT_EQ(*proxy_match("http://example.net/channel"), "foo"); - EXPECT_EQ(*proxy_match("https://example.com/channel"), "bar"); - EXPECT_EQ(*proxy_match("https://example.com:8080/channel"), "bar"); - EXPECT_EQ(*proxy_match("https://example.net/channel"), "foobar"); - EXPECT_EQ(*proxy_match("ftp://example.net/channel"), "baz"); - EXPECT_EQ(*proxy_match("ftp://example.org"), "other"); - - Context::instance().proxy_servers = { { "http", "foo" }, - { "https", "bar" }, - { "https://example.net", "foobar" }, - { "all://example.net", "baz" } }; - - EXPECT_FALSE(proxy_match("ftp://example.org").has_value()); - - Context::instance().proxy_servers = {}; - - EXPECT_FALSE(proxy_match("http://example.com/channel").has_value()); + TEST_CASE("proxy_match") + { + Context::instance().proxy_servers = { { "http", "foo" }, + { "https", "bar" }, + { "https://example.net", "foobar" }, + { "all://example.net", "baz" }, + { "all", "other" } }; + + CHECK_EQ(*proxy_match("http://example.com/channel"), "foo"); + CHECK_EQ(*proxy_match("http://example.net/channel"), "foo"); + CHECK_EQ(*proxy_match("https://example.com/channel"), "bar"); + CHECK_EQ(*proxy_match("https://example.com:8080/channel"), "bar"); + CHECK_EQ(*proxy_match("https://example.net/channel"), "foobar"); + CHECK_EQ(*proxy_match("ftp://example.net/channel"), "baz"); + CHECK_EQ(*proxy_match("ftp://example.org"), "other"); + + Context::instance().proxy_servers = { { "http", "foo" }, + { "https", "bar" }, + { "https://example.net", "foobar" }, + { "all://example.net", "baz" } }; + + CHECK_FALSE(proxy_match("ftp://example.org").has_value()); + + Context::instance().proxy_servers = {}; + + CHECK_FALSE(proxy_match("http://example.com/channel").has_value()); + } } } diff --git a/libmamba/tests/src/core/test_util_string.cpp b/libmamba/tests/src/core/test_util_string.cpp index b670c1f310..938631c155 100644 --- a/libmamba/tests/src/core/test_util_string.cpp +++ b/libmamba/tests/src/core/test_util_string.cpp @@ -9,373 +9,380 @@ #include #include -#include - #include "mamba/core/mamba_fs.hpp" #include "mamba/core/util_string.hpp" +#include "doctest/doctest.h" + namespace mamba { - TEST(util_string, to_lower) - { - EXPECT_EQ(to_lower('A'), 'a'); - EXPECT_EQ(to_lower('b'), 'b'); - EXPECT_EQ(to_lower("ThisIsARandomTTTeeesssT"), "thisisarandomttteeessst"); - } - - TEST(util_string, to_upper) - { - EXPECT_EQ(to_upper('a'), 'A'); - EXPECT_EQ(to_upper('B'), 'B'); - EXPECT_EQ(to_upper("ThisIsARandomTTTeeesssT"), "THISISARANDOMTTTEEESSST"); - } - - TEST(util_string, starts_with) - { - EXPECT_TRUE(starts_with(":hello", "")); - EXPECT_TRUE(starts_with(":hello", ":")); - EXPECT_TRUE(starts_with(":hello", ":h")); - EXPECT_TRUE(starts_with(":hello", ":hello")); - EXPECT_FALSE(starts_with(":hello", "lo")); - EXPECT_TRUE(starts_with("áäᜩgþhëb®hüghœ©®xb", "áäᜩ")); - } - - TEST(util_string, ends_with) - { - EXPECT_TRUE(ends_with("hello&", "")); - EXPECT_TRUE(ends_with("hello&", "&")); - EXPECT_TRUE(ends_with("hello&", "o&")); - EXPECT_TRUE(ends_with("hello&", "hello&")); - EXPECT_FALSE(ends_with("hello&", "he")); - EXPECT_TRUE(ends_with("áäᜩgþhëb®hüghœ©®xb", "©®xb")); - } - - TEST(util_string, contains) - { - EXPECT_TRUE(contains(":hello&", "")); - EXPECT_TRUE(contains(":hello&", "&")); - EXPECT_TRUE(contains(":hello&", ":")); - EXPECT_TRUE(contains(":hello&", "ll")); - EXPECT_FALSE(contains(":hello&", "eo")); - EXPECT_TRUE(contains("áäᜩgþhëb®hüghœ©®xb", "ëb®")); - } - - TEST(util_string, any_starts_with) - { - using StrVec = std::vector; - EXPECT_FALSE(any_starts_with(StrVec{}, { "not" })); - EXPECT_FALSE(any_starts_with(StrVec{}, "")); - EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, "")); - EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":")); - EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":h")); - EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":hello")); - EXPECT_FALSE(any_starts_with(StrVec{ ":hello", "world" }, "orld")); - EXPECT_TRUE(any_starts_with(StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" }, "áäá")); - } - - TEST(util_string, starts_with_any) - { - using StrVec = std::vector; - EXPECT_TRUE(starts_with_any(":hello", StrVec{ "", "not" })); - EXPECT_TRUE(starts_with_any(":hello", StrVec{ ":hello", "not" })); - EXPECT_FALSE(starts_with_any(":hello", StrVec{})); - EXPECT_FALSE(starts_with_any(":hello", StrVec{ "not", "any" })); - EXPECT_TRUE(starts_with_any("áäᜩgþhëb®hüghœ©®xb", StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" })); - } - - TEST(util_string, lstrip) + TEST_SUITE("util_string") { - EXPECT_EQ(lstrip("\n \thello \t\n"), "hello \t\n"); - EXPECT_EQ(lstrip(":::hello%:%", ":%"), "hello%:%"); - EXPECT_EQ(lstrip(":::hello%:%", ':'), "hello%:%"); - EXPECT_EQ(lstrip(":::hello%:%", '%'), ":::hello%:%"); - EXPECT_EQ(lstrip("", '%'), ""); - EXPECT_EQ(lstrip("aaa", 'a'), ""); - EXPECT_EQ(lstrip("aaa", 'b'), "aaa"); - } - - TEST(util_string, lstrip_parts) - { - using StrPair = std::array; - EXPECT_EQ(lstrip_parts(":::hello%:%", ":%"), StrPair({ ":::", "hello%:%" })); - EXPECT_EQ(lstrip_parts(":::hello%:%", ':'), StrPair({ ":::", "hello%:%" })); - EXPECT_EQ(lstrip_parts(":::hello%:%", '%'), StrPair({ "", ":::hello%:%" })); - EXPECT_EQ(lstrip_parts("", '%'), StrPair({ "", "" })); - EXPECT_EQ(lstrip_parts("aaa", 'a'), StrPair({ "aaa", "" })); - EXPECT_EQ(lstrip_parts("aaa", 'b'), StrPair({ "", "aaa" })); - } + TEST_CASE("to_lower") + { + CHECK_EQ(to_lower('A'), 'a'); + CHECK_EQ(to_lower('b'), 'b'); + CHECK_EQ(to_lower("ThisIsARandomTTTeeesssT"), "thisisarandomttteeessst"); + } - TEST(util_string, lstrip_if) - { - EXPECT_EQ(lstrip_if("", [](auto) { return true; }), ""); - EXPECT_EQ(lstrip_if("hello", [](auto) { return true; }), ""); - EXPECT_EQ(lstrip_if("hello", [](auto) { return false; }), "hello"); - EXPECT_EQ(lstrip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "hello \t\n"); - EXPECT_EQ(lstrip_if("123hello456", [](auto c) { return is_digit(c); }), "hello456"); - } + TEST_CASE("to_upper") + { + CHECK_EQ(to_upper('a'), 'A'); + CHECK_EQ(to_upper('B'), 'B'); + CHECK_EQ(to_upper("ThisIsARandomTTTeeesssT"), "THISISARANDOMTTTEEESSST"); + } - TEST(util_string, lstrip_if_parts) - { - using StrPair = std::array; - EXPECT_EQ(lstrip_if_parts("", [](auto) { return true; }), StrPair({ "", "" })); - EXPECT_EQ(lstrip_if_parts("hello", [](auto) { return true; }), StrPair({ "hello", "" })); - EXPECT_EQ(lstrip_if_parts("hello", [](auto) { return false; }), StrPair({ "", "hello" })); - EXPECT_EQ( - lstrip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), - StrPair({ "\n \t", "hello \t\n" }) - ); - EXPECT_EQ( - lstrip_if_parts("123hello456", [](auto c) { return is_digit(c); }), - StrPair({ "123", "hello456" }) - ); - } + TEST_CASE("starts_with") + { + CHECK(starts_with(":hello", "")); + CHECK(starts_with(":hello", ":")); + CHECK(starts_with(":hello", ":h")); + CHECK(starts_with(":hello", ":hello")); + CHECK_FALSE(starts_with(":hello", "lo")); + CHECK(starts_with("áäᜩgþhëb®hüghœ©®xb", "áäᜩ")); + } - TEST(util_string, rstrip) - { - EXPECT_EQ(rstrip("\n \thello \t\n"), "\n \thello"); - EXPECT_EQ(rstrip(":::hello%:%", '%'), ":::hello%:"); - EXPECT_EQ(rstrip(":::hello%:%", ":%"), ":::hello"); - EXPECT_EQ(rstrip(":::hello%:%", ':'), ":::hello%:%"); - EXPECT_EQ(rstrip("", '%'), ""); - EXPECT_EQ(rstrip("aaa", 'a'), ""); - EXPECT_EQ(rstrip("aaa", 'b'), "aaa"); - } + TEST_CASE("ends_with") + { + CHECK(ends_with("hello&", "")); + CHECK(ends_with("hello&", "&")); + CHECK(ends_with("hello&", "o&")); + CHECK(ends_with("hello&", "hello&")); + CHECK_FALSE(ends_with("hello&", "he")); + CHECK(ends_with("áäᜩgþhëb®hüghœ©®xb", "©®xb")); + } - TEST(util_string, rstrip_parts) - { - using StrPair = std::array; - EXPECT_EQ(rstrip_parts(":::hello%:%", '%'), StrPair({ ":::hello%:", "%" })); - EXPECT_EQ(rstrip_parts(":::hello%:%", ":%"), StrPair({ ":::hello", "%:%" })); - EXPECT_EQ(rstrip_parts(":::hello%:%", ':'), StrPair({ ":::hello%:%", "" })); - EXPECT_EQ(rstrip_parts("", '%'), StrPair({ "", "" })); - EXPECT_EQ(rstrip_parts("aaa", 'a'), StrPair({ "", "aaa" })); - EXPECT_EQ(rstrip_parts("aaa", 'b'), StrPair({ "aaa", "" })); - } + TEST_CASE("contains") + { + CHECK(contains(":hello&", "")); + CHECK(contains(":hello&", "&")); + CHECK(contains(":hello&", ":")); + CHECK(contains(":hello&", "ll")); + CHECK_FALSE(contains(":hello&", "eo")); + CHECK(contains("áäᜩgþhëb®hüghœ©®xb", "ëb®")); + } - TEST(util_string, rstrip_if) - { - EXPECT_EQ(rstrip_if("", [](auto) { return true; }), ""); - EXPECT_EQ(rstrip_if("hello", [](auto) { return true; }), ""); - EXPECT_EQ(rstrip_if("hello", [](auto) { return false; }), "hello"); - EXPECT_EQ(rstrip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "\n \thello"); - EXPECT_EQ(rstrip_if("123hello456", [](auto c) { return is_digit(c); }), "123hello"); - } + TEST_CASE("any_starts_with") + { + using StrVec = std::vector; + CHECK_FALSE(any_starts_with(StrVec{}, { "not" })); + CHECK_FALSE(any_starts_with(StrVec{}, "")); + CHECK(any_starts_with(StrVec{ ":hello", "world" }, "")); + CHECK(any_starts_with(StrVec{ ":hello", "world" }, ":")); + CHECK(any_starts_with(StrVec{ ":hello", "world" }, ":h")); + CHECK(any_starts_with(StrVec{ ":hello", "world" }, ":hello")); + CHECK_FALSE(any_starts_with(StrVec{ ":hello", "world" }, "orld")); + CHECK(any_starts_with(StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" }, "áäá")); + } - TEST(util_string, rstrip_if_parts) - { - using StrPair = std::array; - EXPECT_EQ(rstrip_if_parts("", [](auto) { return true; }), StrPair({ "", "" })); - EXPECT_EQ(rstrip_if_parts("hello", [](auto) { return true; }), StrPair({ "", "hello" })); - EXPECT_EQ(rstrip_if_parts("hello", [](auto) { return false; }), StrPair({ "hello", "" })); - EXPECT_EQ( - rstrip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), - StrPair({ "\n \thello", " \t\n" }) - ); - EXPECT_EQ( - rstrip_if_parts("123hello456", [](auto c) { return is_digit(c); }), - StrPair({ "123hello", "456" }) - ); - } + TEST_CASE("starts_with_any") + { + using StrVec = std::vector; + CHECK(starts_with_any(":hello", StrVec{ "", "not" })); + CHECK(starts_with_any(":hello", StrVec{ ":hello", "not" })); + CHECK_FALSE(starts_with_any(":hello", StrVec{})); + CHECK_FALSE(starts_with_any(":hello", StrVec{ "not", "any" })); + CHECK(starts_with_any("áäᜩgþhëb®hüghœ©®xb", StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" })); + } - TEST(util_string, strip) - { - EXPECT_EQ(strip(" hello \t\n"), "hello"); - EXPECT_EQ(strip(":::hello%:%", ":%"), "hello"); - EXPECT_EQ(strip(":::hello%:%", ':'), "hello%:%"); - EXPECT_EQ(strip("", '%'), ""); - EXPECT_EQ(strip("aaa", 'a'), ""); - EXPECT_EQ(strip("aaa", 'b'), "aaa"); - } + TEST_CASE("lstrip") + { + CHECK_EQ(lstrip("\n \thello \t\n"), "hello \t\n"); + CHECK_EQ(lstrip(":::hello%:%", ":%"), "hello%:%"); + CHECK_EQ(lstrip(":::hello%:%", ':'), "hello%:%"); + CHECK_EQ(lstrip(":::hello%:%", '%'), ":::hello%:%"); + CHECK_EQ(lstrip("", '%'), ""); + CHECK_EQ(lstrip("aaa", 'a'), ""); + CHECK_EQ(lstrip("aaa", 'b'), "aaa"); + } - TEST(util_string, strip_parts) - { - using StrTrio = std::array; - EXPECT_EQ(strip_parts(":::hello%:%", ":%"), StrTrio({ ":::", "hello", "%:%" })); - EXPECT_EQ(strip_parts(":::hello%:%", ':'), StrTrio({ ":::", "hello%:%", "" })); - EXPECT_EQ(strip_parts("", '%'), StrTrio({ "", "", "" })); - EXPECT_EQ(strip_parts("aaa", 'a'), StrTrio({ "aaa", "", "" })); - EXPECT_EQ(strip_parts("aaa", 'b'), StrTrio({ "", "aaa", "" })); - } + TEST_CASE("lstrip_parts") + { + using StrPair = std::array; + CHECK_EQ(lstrip_parts(":::hello%:%", ":%"), StrPair({ ":::", "hello%:%" })); + CHECK_EQ(lstrip_parts(":::hello%:%", ':'), StrPair({ ":::", "hello%:%" })); + CHECK_EQ(lstrip_parts(":::hello%:%", '%'), StrPair({ "", ":::hello%:%" })); + CHECK_EQ(lstrip_parts("", '%'), StrPair({ "", "" })); + CHECK_EQ(lstrip_parts("aaa", 'a'), StrPair({ "aaa", "" })); + CHECK_EQ(lstrip_parts("aaa", 'b'), StrPair({ "", "aaa" })); + } - TEST(util_string, strip_if) - { - EXPECT_EQ(strip_if("", [](auto) { return true; }), ""); - EXPECT_EQ(strip_if("hello", [](auto) { return true; }), ""); - EXPECT_EQ(strip_if("hello", [](auto) { return false; }), "hello"); - EXPECT_EQ(strip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "hello"); - EXPECT_EQ(strip_if("123hello456", [](auto c) { return is_digit(c); }), "hello"); - } + TEST_CASE("lstrip_if") + { + CHECK_EQ(lstrip_if("", [](auto) { return true; }), ""); + CHECK_EQ(lstrip_if("hello", [](auto) { return true; }), ""); + CHECK_EQ(lstrip_if("hello", [](auto) { return false; }), "hello"); + CHECK_EQ(lstrip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "hello \t\n"); + CHECK_EQ(lstrip_if("123hello456", [](auto c) { return is_digit(c); }), "hello456"); + } - TEST(util_string, strip_if_parts) - { - using StrTrio = std::array; - EXPECT_EQ(strip_if_parts("", [](auto) { return true; }), StrTrio({ "", "", "" })); - EXPECT_EQ(strip_if_parts("hello", [](auto) { return true; }), StrTrio({ "hello", "", "" })); - EXPECT_EQ(strip_if_parts("hello", [](auto) { return false; }), StrTrio({ "", "hello", "" })); - EXPECT_EQ( - strip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), - StrTrio({ "\n \t", "hello", " \t\n" }) - ); - EXPECT_EQ( - strip_if_parts("123hello456", [](auto c) { return is_digit(c); }), - StrTrio({ "123", "hello", "456" }) - ); - } + TEST_CASE("lstrip_if_parts") + { + using StrPair = std::array; + CHECK_EQ(lstrip_if_parts("", [](auto) { return true; }), StrPair({ "", "" })); + CHECK_EQ(lstrip_if_parts("hello", [](auto) { return true; }), StrPair({ "hello", "" })); + CHECK_EQ(lstrip_if_parts("hello", [](auto) { return false; }), StrPair({ "", "hello" })); + CHECK_EQ( + lstrip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), + StrPair({ "\n \t", "hello \t\n" }) + ); + CHECK_EQ( + lstrip_if_parts("123hello456", [](auto c) { return is_digit(c); }), + StrPair({ "123", "hello456" }) + ); + } - TEST(utils, strip_whitespaces) - { + TEST_CASE("rstrip") { - std::string x(strip(" testwhitespacestrip ")); - EXPECT_EQ(x, "testwhitespacestrip"); - std::string y(rstrip(" testwhitespacestrip ")); - EXPECT_EQ(y, " testwhitespacestrip"); - std::string z(lstrip(" testwhitespacestrip ")); - EXPECT_EQ(z, "testwhitespacestrip "); + CHECK_EQ(rstrip("\n \thello \t\n"), "\n \thello"); + CHECK_EQ(rstrip(":::hello%:%", '%'), ":::hello%:"); + CHECK_EQ(rstrip(":::hello%:%", ":%"), ":::hello"); + CHECK_EQ(rstrip(":::hello%:%", ':'), ":::hello%:%"); + CHECK_EQ(rstrip("", '%'), ""); + CHECK_EQ(rstrip("aaa", 'a'), ""); + CHECK_EQ(rstrip("aaa", 'b'), "aaa"); } + + TEST_CASE("rstrip_parts") { - std::string x(strip(" ")); - EXPECT_EQ(x, ""); - std::string y(rstrip(" ")); - EXPECT_EQ(y, ""); - std::string z(lstrip(" ")); - EXPECT_EQ(z, ""); + using StrPair = std::array; + CHECK_EQ(rstrip_parts(":::hello%:%", '%'), StrPair({ ":::hello%:", "%" })); + CHECK_EQ(rstrip_parts(":::hello%:%", ":%"), StrPair({ ":::hello", "%:%" })); + CHECK_EQ(rstrip_parts(":::hello%:%", ':'), StrPair({ ":::hello%:%", "" })); + CHECK_EQ(rstrip_parts("", '%'), StrPair({ "", "" })); + CHECK_EQ(rstrip_parts("aaa", 'a'), StrPair({ "", "aaa" })); + CHECK_EQ(rstrip_parts("aaa", 'b'), StrPair({ "aaa", "" })); } + + TEST_CASE("rstrip_if") { - std::string x(strip("a")); - EXPECT_EQ(x, "a"); - std::string y(rstrip("a")); - EXPECT_EQ(y, "a"); - std::string z(lstrip("a")); - EXPECT_EQ(z, "a"); + CHECK_EQ(rstrip_if("", [](auto) { return true; }), ""); + CHECK_EQ(rstrip_if("hello", [](auto) { return true; }), ""); + CHECK_EQ(rstrip_if("hello", [](auto) { return false; }), "hello"); + CHECK_EQ(rstrip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "\n \thello"); + CHECK_EQ(rstrip_if("123hello456", [](auto c) { return is_digit(c); }), "123hello"); } + + TEST_CASE("rstrip_if_parts") { - std::string x(strip(" a ")); - EXPECT_EQ(x, "a"); - std::string y(rstrip(" a ")); - EXPECT_EQ(y, " a"); - std::string z(lstrip(" a ")); - EXPECT_EQ(z, "a "); + using StrPair = std::array; + CHECK_EQ(rstrip_if_parts("", [](auto) { return true; }), StrPair({ "", "" })); + CHECK_EQ(rstrip_if_parts("hello", [](auto) { return true; }), StrPair({ "", "hello" })); + CHECK_EQ(rstrip_if_parts("hello", [](auto) { return false; }), StrPair({ "hello", "" })); + CHECK_EQ( + rstrip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), + StrPair({ "\n \thello", " \t\n" }) + ); + CHECK_EQ( + rstrip_if_parts("123hello456", [](auto c) { return is_digit(c); }), + StrPair({ "123hello", "456" }) + ); } + + TEST_CASE("strip") { - std::string x(strip("abc")); - EXPECT_EQ(x, "abc"); - std::string y(rstrip("abc")); - EXPECT_EQ(y, "abc"); - std::string z(lstrip("abc")); - EXPECT_EQ(z, "abc"); + CHECK_EQ(strip(" hello \t\n"), "hello"); + CHECK_EQ(strip(":::hello%:%", ":%"), "hello"); + CHECK_EQ(strip(":::hello%:%", ':'), "hello%:%"); + CHECK_EQ(strip("", '%'), ""); + CHECK_EQ(strip("aaa", 'a'), ""); + CHECK_EQ(strip("aaa", 'b'), "aaa"); } + + TEST_CASE("strip_parts") { - std::string x(strip(" \r \t \n ")); - EXPECT_EQ(x, ""); - std::string y(rstrip(" \r \t \n ")); - EXPECT_EQ(y, ""); - std::string z(lstrip(" \r \t \n ")); - EXPECT_EQ(z, ""); + using StrTrio = std::array; + CHECK_EQ(strip_parts(":::hello%:%", ":%"), StrTrio({ ":::", "hello", "%:%" })); + CHECK_EQ(strip_parts(":::hello%:%", ':'), StrTrio({ ":::", "hello%:%", "" })); + CHECK_EQ(strip_parts("", '%'), StrTrio({ "", "", "" })); + CHECK_EQ(strip_parts("aaa", 'a'), StrTrio({ "aaa", "", "" })); + CHECK_EQ(strip_parts("aaa", 'b'), StrTrio({ "", "aaa", "" })); } + + TEST_CASE("strip_if") { - std::string x(strip("\r \t \n testwhitespacestrip \r \t \n")); - EXPECT_EQ(x, "testwhitespacestrip"); - std::string y(rstrip(" \r \t \n testwhitespacestrip \r \t \n")); - EXPECT_EQ(y, " \r \t \n testwhitespacestrip"); - std::string z(lstrip(" \r \t \n testwhitespacestrip \r \t \n ")); - EXPECT_EQ(z, "testwhitespacestrip \r \t \n "); + CHECK_EQ(strip_if("", [](auto) { return true; }), ""); + CHECK_EQ(strip_if("hello", [](auto) { return true; }), ""); + CHECK_EQ(strip_if("hello", [](auto) { return false; }), "hello"); + CHECK_EQ(strip_if("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), "hello"); + CHECK_EQ(strip_if("123hello456", [](auto c) { return is_digit(c); }), "hello"); } - } - TEST(util_string, split) - { - std::string a = "hello.again.it's.me.mario"; - std::vector e1 = { "hello", "again", "it's", "me", "mario" }; - EXPECT_EQ(split(a, "."), e1); - - std::vector s2 = { "hello", "again", "it's.me.mario" }; - EXPECT_EQ(split(a, ".", 2), s2); - - EXPECT_EQ(rsplit(a, "."), e1); - std::vector r2 = { "hello.again.it's", "me", "mario" }; - EXPECT_EQ(rsplit(a, ".", 2), r2); - - std::string b = "..."; - auto es1 = std::vector{ "", "", "", "" }; - auto es2 = std::vector{ "", ".." }; - EXPECT_EQ(split(b, "."), es1); - EXPECT_EQ(split(b, ".", 1), es2); - - std::vector v = { "xtensor==0.12.3" }; - EXPECT_EQ(split(v[0], ":"), v); - EXPECT_EQ(rsplit(v[0], ":"), v); - EXPECT_EQ(split(v[0], ":", 2), v); - EXPECT_EQ(rsplit(v[0], ":", 2), v); - - std::vector v2 = { "conda-forge/linux64", "", "xtensor==0.12.3" }; - EXPECT_EQ(split("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2); - EXPECT_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2); - std::vector v21 = { "conda-forge/linux64:", "xtensor==0.12.3" }; - - EXPECT_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 1), v21); - } + TEST_CASE("strip_if_parts") + { + using StrTrio = std::array; + CHECK_EQ(strip_if_parts("", [](auto) { return true; }), StrTrio({ "", "", "" })); + CHECK_EQ(strip_if_parts("hello", [](auto) { return true; }), StrTrio({ "hello", "", "" })); + CHECK_EQ(strip_if_parts("hello", [](auto) { return false; }), StrTrio({ "", "hello", "" })); + CHECK_EQ( + strip_if_parts("\n \thello \t\n", [](auto c) { return !is_alphanum(c); }), + StrTrio({ "\n \t", "hello", " \t\n" }) + ); + CHECK_EQ( + strip_if_parts("123hello456", [](auto c) { return is_digit(c); }), + StrTrio({ "123", "hello", "456" }) + ); + } - TEST(util_string, join) - { + TEST_CASE("strip_whitespaces") { - std::vector to_join = { "a", "bc", "d" }; - auto joined = join("-", to_join); - testing::StaticAssertTypeEq(); - EXPECT_EQ(joined, "a-bc-d"); + { + std::string x(strip(" testwhitespacestrip ")); + CHECK_EQ(x, "testwhitespacestrip"); + std::string y(rstrip(" testwhitespacestrip ")); + CHECK_EQ(y, " testwhitespacestrip"); + std::string z(lstrip(" testwhitespacestrip ")); + CHECK_EQ(z, "testwhitespacestrip "); + } + { + std::string x(strip(" ")); + CHECK_EQ(x, ""); + std::string y(rstrip(" ")); + CHECK_EQ(y, ""); + std::string z(lstrip(" ")); + CHECK_EQ(z, ""); + } + { + std::string x(strip("a")); + CHECK_EQ(x, "a"); + std::string y(rstrip("a")); + CHECK_EQ(y, "a"); + std::string z(lstrip("a")); + CHECK_EQ(z, "a"); + } + { + std::string x(strip(" a ")); + CHECK_EQ(x, "a"); + std::string y(rstrip(" a ")); + CHECK_EQ(y, " a"); + std::string z(lstrip(" a ")); + CHECK_EQ(z, "a "); + } + { + std::string x(strip("abc")); + CHECK_EQ(x, "abc"); + std::string y(rstrip("abc")); + CHECK_EQ(y, "abc"); + std::string z(lstrip("abc")); + CHECK_EQ(z, "abc"); + } + { + std::string x(strip(" \r \t \n ")); + CHECK_EQ(x, ""); + std::string y(rstrip(" \r \t \n ")); + CHECK_EQ(y, ""); + std::string z(lstrip(" \r \t \n ")); + CHECK_EQ(z, ""); + } + { + std::string x(strip("\r \t \n testwhitespacestrip \r \t \n")); + CHECK_EQ(x, "testwhitespacestrip"); + std::string y(rstrip(" \r \t \n testwhitespacestrip \r \t \n")); + CHECK_EQ(y, " \r \t \n testwhitespacestrip"); + std::string z(lstrip(" \r \t \n testwhitespacestrip \r \t \n ")); + CHECK_EQ(z, "testwhitespacestrip \r \t \n "); + } } + + TEST_CASE("split") { - std::vector to_join = { "/a", "bc", "d" }; - auto joined = join("/", to_join); - testing::StaticAssertTypeEq(); - EXPECT_EQ(joined, "/a/bc/d"); + std::string a = "hello.again.it's.me.mario"; + std::vector e1 = { "hello", "again", "it's", "me", "mario" }; + CHECK_EQ(split(a, "."), e1); + + std::vector s2 = { "hello", "again", "it's.me.mario" }; + CHECK_EQ(split(a, ".", 2), s2); + + CHECK_EQ(rsplit(a, "."), e1); + std::vector r2 = { "hello.again.it's", "me", "mario" }; + CHECK_EQ(rsplit(a, ".", 2), r2); + + std::string b = "..."; + auto es1 = std::vector{ "", "", "", "" }; + auto es2 = std::vector{ "", ".." }; + CHECK_EQ(split(b, "."), es1); + CHECK_EQ(split(b, ".", 1), es2); + + std::vector v = { "xtensor==0.12.3" }; + CHECK_EQ(split(v[0], ":"), v); + CHECK_EQ(rsplit(v[0], ":"), v); + CHECK_EQ(split(v[0], ":", 2), v); + CHECK_EQ(rsplit(v[0], ":", 2), v); + + std::vector v2 = { "conda-forge/linux64", "", "xtensor==0.12.3" }; + CHECK_EQ(split("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2); + CHECK_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2); + std::vector v21 = { "conda-forge/linux64:", "xtensor==0.12.3" }; + + CHECK_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 1), v21); } + + TEST_CASE("join") { - EXPECT_EQ(join(",", std::vector()), ""); + { + std::vector to_join = { "a", "bc", "d" }; + auto joined = join("-", to_join); + static_assert(std::is_same::value); + CHECK_EQ(joined, "a-bc-d"); + } + { + std::vector to_join = { "/a", "bc", "d" }; + auto joined = join("/", to_join); + static_assert(std::is_same::value); + CHECK_EQ(joined, "/a/bc/d"); + } + { + CHECK_EQ(join(",", std::vector()), ""); + } } - } - TEST(util_string, join_trunc) - { - std::vector to_join = { "a", "bc", "d", "e", "f" }; + TEST_CASE("join_trunc") { - auto joined = join_trunc(to_join); - testing::StaticAssertTypeEq(); + std::vector to_join = { "a", "bc", "d", "e", "f" }; + { + auto joined = join_trunc(to_join); + static_assert(std::is_same::value); + } + CHECK_EQ(join_trunc(to_join, "-", "..", 5, { 2, 1 }), "a-bc-d-e-f"); + CHECK_EQ(join_trunc(to_join, ",", "..", 4, { 2, 1 }), "a,bc,..,f"); + CHECK_EQ(join_trunc(to_join, ",", "..", 4, { 0, 1 }), "..,f"); + CHECK_EQ(join_trunc(to_join, ",", "..", 4, { 2, 0 }), "a,bc,.."); + CHECK_EQ(join_trunc(to_join, ",", "..", 4, { 0, 0 }), ".."); + CHECK_EQ(join_trunc(std::vector()), ""); } - EXPECT_EQ(join_trunc(to_join, "-", "..", 5, { 2, 1 }), "a-bc-d-e-f"); - EXPECT_EQ(join_trunc(to_join, ",", "..", 4, { 2, 1 }), "a,bc,..,f"); - EXPECT_EQ(join_trunc(to_join, ",", "..", 4, { 0, 1 }), "..,f"); - EXPECT_EQ(join_trunc(to_join, ",", "..", 4, { 2, 0 }), "a,bc,.."); - EXPECT_EQ(join_trunc(to_join, ",", "..", 4, { 0, 0 }), ".."); - EXPECT_EQ(join_trunc(std::vector()), ""); - } - TEST(util_string, replace_all) - { - std::string testbuf = "this is just a test a just a a abc bca"; - - replace_all(testbuf, "just", "JU"); - EXPECT_EQ(testbuf, "this is JU a test a JU a a abc bca"); - replace_all(testbuf, "a", "MAMBA"); - EXPECT_EQ(testbuf, "this is JU MAMBA test MAMBA JU MAMBA MAMBA MAMBAbc bcMAMBA"); - replace_all(testbuf, " ", ""); - EXPECT_EQ(testbuf, "thisisJUMAMBAtestMAMBAJUMAMBAMAMBAMAMBAbcbcMAMBA"); - std::string prefix = "/I/am/a/PREFIX\n\nabcdefg\nxyz"; - - replace_all(prefix, "/I/am/a/PREFIX", "/Yes/Thats/great/"); - EXPECT_TRUE(starts_with(prefix, "/Yes/Thats/great/\n")); - - std::string testbuf2 = "this is another test wow"; - replace_all(testbuf2, "", "somereplacement"); - EXPECT_EQ(testbuf2, "this is another test wow"); - - std::string prefix_unicode = "/I/am/Dörte朩æ©fðgb®/PREFIX\n\nabcdefg\nxyz"; - replace_all(prefix_unicode, "/I/am/Dörte朩æ©fðgb®/PREFIX", "/home/åéäáßð朩ðfßfáðß/123123123"); - EXPECT_EQ(prefix_unicode, "/home/åéäáßð朩ðfßfáðß/123123123\n\nabcdefg\nxyz"); - } + TEST_CASE("replace_all") + { + std::string testbuf = "this is just a test a just a a abc bca"; + + replace_all(testbuf, "just", "JU"); + CHECK_EQ(testbuf, "this is JU a test a JU a a abc bca"); + replace_all(testbuf, "a", "MAMBA"); + CHECK_EQ(testbuf, "this is JU MAMBA test MAMBA JU MAMBA MAMBA MAMBAbc bcMAMBA"); + replace_all(testbuf, " ", ""); + CHECK_EQ(testbuf, "thisisJUMAMBAtestMAMBAJUMAMBAMAMBAMAMBAbcbcMAMBA"); + std::string prefix = "/I/am/a/PREFIX\n\nabcdefg\nxyz"; + + replace_all(prefix, "/I/am/a/PREFIX", "/Yes/Thats/great/"); + CHECK(starts_with(prefix, "/Yes/Thats/great/\n")); + + std::string testbuf2 = "this is another test wow"; + replace_all(testbuf2, "", "somereplacement"); + CHECK_EQ(testbuf2, "this is another test wow"); + + std::string prefix_unicode = "/I/am/Dörte朩æ©fðgb®/PREFIX\n\nabcdefg\nxyz"; + replace_all( + prefix_unicode, + "/I/am/Dörte朩æ©fðgb®/PREFIX", + "/home/åéäáßð朩ðfßfáðß/123123123" + ); + CHECK_EQ(prefix_unicode, "/home/åéäáßð朩ðfßfáðß/123123123\n\nabcdefg\nxyz"); + } - TEST(util_string, concat) - { - EXPECT_EQ(concat("aa", std::string("bb"), std::string_view("cc"), 'd'), "aabbccd"); + TEST_CASE("concat") + { + CHECK_EQ(concat("aa", std::string("bb"), std::string_view("cc"), 'd'), "aabbccd"); + } } } // namespace mamba diff --git a/libmamba/tests/src/core/test_validate.cpp b/libmamba/tests/src/core/test_validate.cpp index ff5c6e4ee9..7b440df9a8 100644 --- a/libmamba/tests/src/core/test_validate.cpp +++ b/libmamba/tests/src/core/test_validate.cpp @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include @@ -17,6 +15,8 @@ #include "mamba/core/util_string.hpp" #include "mamba/core/validate.hpp" +#include "doctest/doctest.h" + #include "test_data.hpp" namespace mamba::validation @@ -25,72 +25,73 @@ namespace mamba::validation { using nlohmann::json; - TEST(Validate, sha256sum) + TEST_SUITE("Validate") { - auto f = mamba::open_ofstream("sometestfile.txt"); - f << "test"; - f.close(); - auto sha256 = sha256sum("sometestfile.txt"); - EXPECT_EQ(sha256, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); - - auto md5 = md5sum("sometestfile.txt"); - EXPECT_EQ(md5, "098f6bcd4621d373cade4e832627b4f6"); - } + TEST_CASE("sha256sum") + { + auto f = mamba::open_ofstream("sometestfile.txt"); + f << "test"; + f.close(); + auto sha256 = sha256sum("sometestfile.txt"); + CHECK_EQ(sha256, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); + auto md5 = md5sum("sometestfile.txt"); + CHECK_EQ(md5, "098f6bcd4621d373cade4e832627b4f6"); + } - TEST(Validate, ed25519_key_hex_to_bytes) - { - std::array pk, sk; - generate_ed25519_keypair(pk.data(), sk.data()); + TEST_CASE("ed25519_key_hex_to_bytes") + { + std::array pk, sk; + generate_ed25519_keypair(pk.data(), sk.data()); - auto pk_hex = ::mamba::hex_string(pk); - auto pk_bytes = ed25519_key_hex_to_bytes(pk_hex); - EXPECT_EQ(pk_hex, ::mamba::hex_string(pk_bytes)); + auto pk_hex = ::mamba::hex_string(pk); + auto pk_bytes = ed25519_key_hex_to_bytes(pk_hex); + CHECK_EQ(pk_hex, ::mamba::hex_string(pk_bytes)); - spdlog::set_level(spdlog::level::debug); + spdlog::set_level(spdlog::level::debug); - std::array not_even_key; - pk_hex = ::mamba::hex_string(not_even_key); - pk_bytes = ed25519_key_hex_to_bytes(pk_hex); - EXPECT_FALSE(pk_hex == ::mamba::hex_string(pk_bytes)); + std::array not_even_key; + pk_hex = ::mamba::hex_string(not_even_key); + pk_bytes = ed25519_key_hex_to_bytes(pk_hex); + CHECK_FALSE(pk_hex == ::mamba::hex_string(pk_bytes)); - std::array wrong_size_key; - pk_hex = ::mamba::hex_string(wrong_size_key); - pk_bytes = ed25519_key_hex_to_bytes(pk_hex); - EXPECT_FALSE(pk_hex == ::mamba::hex_string(pk_bytes)); + std::array wrong_size_key; + pk_hex = ::mamba::hex_string(wrong_size_key); + pk_bytes = ed25519_key_hex_to_bytes(pk_hex); + CHECK_FALSE(pk_hex == ::mamba::hex_string(pk_bytes)); - spdlog::set_level(spdlog::level::info); - } + spdlog::set_level(spdlog::level::info); + } - TEST(Validate, ed25519_sig_hex_to_bytes) - { - std::array pk, sk; - generate_ed25519_keypair(pk.data(), sk.data()); + TEST_CASE("ed25519_sig_hex_to_bytes") + { + std::array pk, sk; + generate_ed25519_keypair(pk.data(), sk.data()); - std::array sig; - sign("Some text.", sk.data(), sig.data()); + std::array sig; + sign("Some text.", sk.data(), sig.data()); - auto sig_hex = ::mamba::hex_string(sig); - auto sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); - EXPECT_EQ(sig_hex, ::mamba::hex_string(sig_bytes)); + auto sig_hex = ::mamba::hex_string(sig); + auto sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); + CHECK_EQ(sig_hex, ::mamba::hex_string(sig_bytes)); - spdlog::set_level(spdlog::level::debug); + spdlog::set_level(spdlog::level::debug); - std::array not_even_sig; - sig_hex = ::mamba::hex_string(not_even_sig); - sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); - EXPECT_FALSE(sig_hex == ::mamba::hex_string(sig_bytes)); + std::array not_even_sig; + sig_hex = ::mamba::hex_string(not_even_sig); + sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); + CHECK_FALSE(sig_hex == ::mamba::hex_string(sig_bytes)); - std::array wrong_size_sig; - sig_hex = ::mamba::hex_string(wrong_size_sig); - sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); - EXPECT_FALSE(sig_hex == ::mamba::hex_string(sig_bytes)); + std::array wrong_size_sig; + sig_hex = ::mamba::hex_string(wrong_size_sig); + sig_bytes = ed25519_sig_hex_to_bytes(sig_hex); + CHECK_FALSE(sig_hex == ::mamba::hex_string(sig_bytes)); - spdlog::set_level(spdlog::level::info); + spdlog::set_level(spdlog::level::info); + } } - - class VerifyMsg : public ::testing::Test + class VerifyMsg { public: @@ -107,38 +108,41 @@ namespace mamba::validation unsigned char signature[MAMBA_ED25519_SIGSIZE_BYTES]; }; - TEST_F(VerifyMsg, from_bytes) + TEST_SUITE("VerifyMsg") { - EXPECT_EQ(verify("Some text.", pk, signature), 1); - } + TEST_CASE_FIXTURE(VerifyMsg, "from_bytes") + { + CHECK_EQ(verify("Some text.", pk, signature), 1); + } - TEST_F(VerifyMsg, from_hex) - { - auto signature_hex = ::mamba::hex_string(signature, MAMBA_ED25519_SIGSIZE_BYTES); - auto pk_hex = ::mamba::hex_string(pk, MAMBA_ED25519_KEYSIZE_BYTES); + TEST_CASE_FIXTURE(VerifyMsg, "from_hex") + { + auto signature_hex = ::mamba::hex_string(signature, MAMBA_ED25519_SIGSIZE_BYTES); + auto pk_hex = ::mamba::hex_string(pk, MAMBA_ED25519_KEYSIZE_BYTES); - EXPECT_EQ(verify("Some text.", pk_hex, signature_hex), 1); - } + CHECK_EQ(verify("Some text.", pk_hex, signature_hex), 1); + } - TEST_F(VerifyMsg, wrong_signature) - { - spdlog::set_level(spdlog::level::debug); - auto pk_hex = ::mamba::hex_string(pk, MAMBA_ED25519_KEYSIZE_BYTES); + TEST_CASE_FIXTURE(VerifyMsg, "wrong_signature") + { + spdlog::set_level(spdlog::level::debug); + auto pk_hex = ::mamba::hex_string(pk, MAMBA_ED25519_KEYSIZE_BYTES); - EXPECT_EQ(verify("Some text.", pk_hex, "signature_hex"), 0); - spdlog::set_level(spdlog::level::info); - } + CHECK_EQ(verify("Some text.", pk_hex, "signature_hex"), 0); + spdlog::set_level(spdlog::level::info); + } - TEST_F(VerifyMsg, wrong_public_key) - { - spdlog::set_level(spdlog::level::debug); - auto signature_hex = ::mamba::hex_string(signature, MAMBA_ED25519_SIGSIZE_BYTES); + TEST_CASE_FIXTURE(VerifyMsg, "wrong_public_key") + { + spdlog::set_level(spdlog::level::debug); + auto signature_hex = ::mamba::hex_string(signature, MAMBA_ED25519_SIGSIZE_BYTES); - EXPECT_EQ(verify("Some text.", "pk_hex", signature_hex), 0); - spdlog::set_level(spdlog::level::info); + CHECK_EQ(verify("Some text.", "pk_hex", signature_hex), 0); + spdlog::set_level(spdlog::level::info); + } } - class VerifyGPGMsg : public ::testing::Test + class VerifyGPGMsg { public: @@ -177,22 +181,25 @@ namespace mamba::validation std::string data; }; - TEST_F(VerifyGPGMsg, verify_gpg_hashed_msg_from_bin) + TEST_SUITE("VerifyGPGMsg") { - auto bin_signature = ed25519_sig_hex_to_bytes(signature); - auto bin_pk = ed25519_key_hex_to_bytes(pk); + TEST_CASE_FIXTURE(VerifyGPGMsg, "verify_gpg_hashed_msg_from_bin") + { + auto bin_signature = ed25519_sig_hex_to_bytes(signature); + auto bin_pk = ed25519_key_hex_to_bytes(pk); - EXPECT_EQ(verify_gpg_hashed_msg(hash, bin_pk.data(), bin_signature.data()), 1); - } + CHECK_EQ(verify_gpg_hashed_msg(hash, bin_pk.data(), bin_signature.data()), 1); + } - TEST_F(VerifyGPGMsg, verify_gpg_hashed_msg_from_hex) - { - EXPECT_EQ(verify_gpg_hashed_msg(hash, pk, signature), 1); - } + TEST_CASE_FIXTURE(VerifyGPGMsg, "verify_gpg_hashed_msg_from_hex") + { + CHECK_EQ(verify_gpg_hashed_msg(hash, pk, signature), 1); + } - TEST_F(VerifyGPGMsg, verify_gpg) - { - EXPECT_EQ(verify_gpg(data, trailer, pk, signature), 1); + TEST_CASE_FIXTURE(VerifyGPGMsg, "verify_gpg") + { + CHECK_EQ(verify_gpg(data, trailer, pk, signature), 1); + } } } // namespace testing @@ -202,7 +209,7 @@ namespace mamba::validation { using namespace mamba; - class RootImplT_v06 : public ::testing::Test + class RootImplT_v06 { public: @@ -365,429 +372,469 @@ namespace mamba::validation } }; - TEST_F(RootImplT_v06, ctor_from_path) + TEST_SUITE("RootImplT_v06") { - RootImpl root(trusted_root_file_raw_key()); + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_from_path") + { + RootImpl root(trusted_root_file_raw_key()); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v06, ctor_from_path_pgp_signed) - { - RootImpl root(trusted_root_file_pgp()); + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_from_path_pgp_signed") + { + RootImpl root(trusted_root_file_pgp()); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v06, ctor_from_json) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_from_json") + { + RootImpl root(root1_json); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v06, ctor_from_json_str) - { - RootImpl root(root1_json.dump()); + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_from_json_str") + { + RootImpl root(root1_json.dump()); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v06, ctor_from_json_pgp_signed) - { - RootImpl root(root1_pgp_json); + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_from_json_pgp_signed") + { + RootImpl root(root1_pgp_json); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v06, ctor_wrong_filename_spec_version) - { - fs::u8path p = channel_dir->path() / "2.sv1.root.json"; + TEST_CASE_FIXTURE(RootImplT_v06, "ctor_wrong_filename_spec_version") + { + fs::u8path p = channel_dir->path() / "2.sv1.root.json"; - std::ofstream out_file(p.std_path(), std::ofstream::out | std::ofstream::trunc); - out_file << root1_json; - out_file.close(); + std::ofstream out_file(p.std_path(), std::ofstream::out | std::ofstream::trunc); + out_file << root1_json; + out_file.close(); - // "2.sv1.root.json" is not compatible spec version (spec version N) - EXPECT_THROW(RootImpl root(p), role_file_error); - } + // "2.sv1.root.json" is not compatible spec version (spec version N) + CHECK_THROWS_AS(RootImpl root(p), role_file_error); + } - TEST_F(RootImplT_v06, update_from_path) - { - using namespace mamba; + TEST_CASE_FIXTURE(RootImplT_v06, "update_from_path") + { + using namespace mamba; - auto f = trusted_root_file_raw_key(); - RootImpl root(f); + auto f = trusted_root_file_raw_key(); + RootImpl root(f); - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; - auto updated_root = root.update(create_root_update("2.root.json", patch)); + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; + auto updated_root = root.update(create_root_update("2.root.json", patch)); - auto testing_root = static_cast(updated_root.get()); - EXPECT_EQ(testing_root->type(), "root"); - EXPECT_EQ(testing_root->file_ext(), "json"); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(testing_root->version(), 2); - } + auto testing_root = static_cast(updated_root.get()); + CHECK_EQ(testing_root->type(), "root"); + CHECK_EQ(testing_root->file_ext(), "json"); + CHECK_EQ(testing_root->spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(testing_root->version(), 2); + } - TEST_F(RootImplT_v06, wrong_version) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_version") + { + RootImpl root(root1_json); - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 3 } - ])"_json; + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 3 } + ])"_json; - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - TEST_F(RootImplT_v06, spec_version) - { - RootImpl root(root1_json); - - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.1" } - ])"_json; - auto updated_root = root.update(create_root_update("2.root.json", patch)); - - auto testing_root = static_cast(updated_root.get()); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("0.6.1")); - EXPECT_EQ(testing_root->version(), 2); - EXPECT_EQ(testing_root->expires(), root.expires()); - } + TEST_CASE_FIXTURE(RootImplT_v06, "spec_version") + { + RootImpl root(root1_json); + + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.1" } + ])"_json; + auto updated_root = root.update(create_root_update("2.root.json", patch)); + + auto testing_root = static_cast(updated_root.get()); + CHECK_EQ(testing_root->spec_version(), SpecImpl("0.6.1")); + CHECK_EQ(testing_root->version(), 2); + CHECK_EQ(testing_root->expires(), root.expires()); + } - TEST_F(RootImplT_v06, upgraded_spec_version) - { - v06::RootImpl root(root1_json); - - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "1.0.0" } - ])"_json; - - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), spec_version_error); - - json signable_patch = json::parse( - R"([ - { "op": "replace", "path": "/version", "value": 2 }, - { "op": "replace", "path": "/expires", "value": ")" - + timestamp(utc_time_now() + 1) /* force +1s */ + R"(" }, - { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, - { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, - { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } - ])" - ); - auto updated_root = root.update(upgrade_to_v1(root, signable_patch)); - - auto testing_root = dynamic_cast(updated_root.get()); - ASSERT_NE(testing_root, nullptr); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("1.0.17")); - EXPECT_EQ(testing_root->version(), 2); - EXPECT_LT(testing_root->expires(), root.expires()); - } + TEST_CASE_FIXTURE(RootImplT_v06, "upgraded_spec_version") + { + v06::RootImpl root(root1_json); - TEST_F(RootImplT_v06, equivalent_upgraded_spec_version) - { - RootImpl root(root1_json); + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "1.0.0" } + ])"_json; - json signable_patch = R"([ - { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, - { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, - { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } - ])"_json; - v1::RootImpl updated_root(upgrade_to_v1(root, signable_patch)); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + spec_version_error + ); - EXPECT_EQ(updated_root.spec_version(), v1::SpecImpl("1.0.17")); - EXPECT_EQ(updated_root.version(), 1); - } + json signable_patch = json::parse( + R"([ + { "op": "replace", "path": "/version", "value": 2 }, + { "op": "replace", "path": "/expires", "value": ")" + + timestamp(utc_time_now() + 1) /* force +1s */ + R"(" }, + { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, + { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, + { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } + ])" + ); + auto updated_root = root.update(upgrade_to_v1(root, signable_patch)); - TEST_F(RootImplT_v06, wrong_spec_version) - { - RootImpl root(root1_json); + auto testing_root = dynamic_cast(updated_root.get()); + REQUIRE_NE(testing_root, nullptr); + CHECK_EQ(testing_root->spec_version(), SpecImpl("1.0.17")); + CHECK_EQ(testing_root->version(), 2); + CHECK_LT(testing_root->expires(), root.expires()); + } - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "1.0.0" } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "equivalent_upgraded_spec_version") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), spec_version_error); + json signable_patch = R"([ + { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, + { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, + { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } + ])"_json; + v1::RootImpl updated_root(upgrade_to_v1(root, signable_patch)); - patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "wrong" } - ])"_json; + CHECK_EQ(updated_root.spec_version(), v1::SpecImpl("1.0.17")); + CHECK_EQ(updated_root.version(), 1); + } - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), spec_version_error); - } + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_spec_version") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v06, wrong_filename_role) - { - RootImpl root(root1_json); + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "1.0.0" } + ])"_json; - EXPECT_THROW(root.update(create_root_update("2.rooot.json")), role_file_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + spec_version_error + ); - TEST_F(RootImplT_v06, wrong_filename_version) - { - RootImpl root(root1_json); + patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "wrong" } + ])"_json; - EXPECT_THROW(root.update(create_root_update("3.root.json")), role_file_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + spec_version_error + ); + } - TEST_F(RootImplT_v06, wrong_filename_spec_version) - { - v06::RootImpl root(root1_json); - - // "2.sv1.root.json" is upgradable spec version (spec version N+1) - json signable_patch = R"([ - { "op": "replace", "path": "/version", "value": 2 }, - { "op": "replace", "path": "/spec_version", "value": "1.0.0" }, - { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, - { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, - { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } - ])"_json; - auto updated_root = root.update(upgrade_to_v1(root, signable_patch)); - auto testing_root = dynamic_cast(updated_root.get()); - ASSERT_NE(testing_root, nullptr); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("1.0.0")); - - // "2.sv2.root.json" is not upgradable spec version (spec version N+1) - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; - EXPECT_THROW(root.update(create_root_update("2.sv2.root.json", patch)), role_file_error); - } + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_filename_role") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v06, illformed_filename_version) - { - RootImpl root(root1_json); + CHECK_THROWS_AS(root.update(create_root_update("2.rooot.json")), role_file_error); + } - EXPECT_THROW(root.update(create_root_update("wrong.root.json")), role_file_error); - EXPECT_THROW(root.update(create_root_update("2..root.json")), role_file_error); - EXPECT_THROW(root.update(create_root_update("2.sv04.root.json")), role_file_error); - } + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_filename_version") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v06, rollback_attack) - { - RootImpl root(root1_json); + CHECK_THROWS_AS(root.update(create_root_update("3.root.json")), role_file_error); + } - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 1 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_filename_spec_version") + { + v06::RootImpl root(root1_json); + + // "2.sv1.root.json" is upgradable spec version (spec version N+1) + json signable_patch = R"([ + { "op": "replace", "path": "/version", "value": 2 }, + { "op": "replace", "path": "/spec_version", "value": "1.0.0" }, + { "op": "add", "path": "/keys/dummy_value", "value": { "keytype": "ed25519", "scheme": "ed25519", "keyval": "dummy_value" } }, + { "op": "add", "path": "/roles/snapshot/keyids", "value": ["dummy_value"] }, + { "op": "add", "path": "/roles/timestamp/keyids", "value": ["dummy_value"] } + ])"_json; + auto updated_root = root.update(upgrade_to_v1(root, signable_patch)); + auto testing_root = dynamic_cast(updated_root.get()); + REQUIRE_NE(testing_root, nullptr); + CHECK_EQ(testing_root->spec_version(), SpecImpl("1.0.0")); + + // "2.sv2.root.json" is not upgradable spec version (spec version N+1) + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; + CHECK_THROWS_AS( + root.update(create_root_update("2.sv2.root.json", patch)), + role_file_error + ); + } - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), rollback_error); - } + TEST_CASE_FIXTURE(RootImplT_v06, "illformed_filename_version") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v06, wrong_type) - { - RootImpl root(root1_json); + CHECK_THROWS_AS(root.update(create_root_update("wrong.root.json")), role_file_error); + CHECK_THROWS_AS(root.update(create_root_update("2..root.json")), role_file_error); + CHECK_THROWS_AS(root.update(create_root_update("2.sv04.root.json")), role_file_error); + } - json patch = R"([ - { "op": "replace", "path": "/signed/type", "value": "timestamp" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "rollback_attack") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 1 } + ])"_json; - TEST_F(RootImplT_v06, missing_type) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + rollback_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/type" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "wrong_type") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/type", "value": "timestamp" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, missing_delegations) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/delegations" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "missing_type") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/type" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, missing_delegation) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/delegations/root" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "missing_delegations") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/delegations" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, empty_delegation_pubkeys) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/delegations/root/pubkeys", "value": [] }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "missing_delegation") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/delegations/root" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, null_role_threshold) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/delegations/root/threshold", "value": 0 }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "empty_delegation_pubkeys") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/delegations/root/pubkeys", "value": [] }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, extra_roles) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "add", "path": "/signed/delegations/some_wrong_role", - "value": { "pubkeys": ["c"], "threshold": 1 } }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v06, "null_role_threshold") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } - /* - TEST_F(RootImplT_v06, mirrors_role) - { - json patch = R"([ - { "op": "add", "path": - "/signed/roles/mirrors", "value": { "keyids": - ["c"], "threshold": 1 } }, { "op": "replace", "path": - "/signed/version", "value": 2 } - ])"_json; - - RootImpl root(create_root_update("2.root.json", patch)); - bool mirrors_role_found = (root.roles().find("mirrors") != root.roles().end()); - EXPECT_TRUE(mirrors_role_found); - } - */ - TEST_F(RootImplT_v06, threshold_not_met) - { - RootImpl root(root1_json); + json patch = R"([ + { "op": "replace", "path": "/signed/delegations/root/threshold", "value": 0 }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/delegations/root/threshold", "value": 2 } - ])"_json; + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_error); - } + TEST_CASE_FIXTURE(RootImplT_v06, "extra_roles") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v06, expires) - { - RootImpl root(root1_json); - - // expiration is set to now+3600s in 'sign_root' - TimeRef time_ref; - EXPECT_FALSE(root.expired(time_ref)); - - time_ref.set(utc_time_now() + 7200); - EXPECT_TRUE(root.expired(time_ref)); - - json patch = json::parse( - R"([ - { "op": "replace", "path": "/signed/expiration", "value": ")" - + timestamp(utc_time_now() + 10800) + R"(" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])" - ); - auto updated_root = root.update(create_root_update("2.root.json", patch)); - - auto testing_root = static_cast(updated_root.get()); - EXPECT_FALSE(testing_root->expired(time_ref)); - } + json patch = R"([ + { "op": "add", "path": "/signed/delegations/some_wrong_role", + "value": { "pubkeys": ["c"], "threshold": 1 } }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v06, timestamp) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } + /* + TEST_CASE_FIXTURE(RootImplT_v06, mirrors_role) + { + json patch = R"([ + { "op": "add", "path": + "/signed/roles/mirrors", "value": { "keyids": + ["c"], "threshold": 1 } }, { "op": "replace", "path": + "/signed/version", "value": 2 } + ])"_json; + + RootImpl root(create_root_update("2.root.json", patch)); + bool mirrors_role_found = (root.roles().find("mirrors") != root.roles().end()); + CHECK(mirrors_role_found); + } + */ + TEST_CASE_FIXTURE(RootImplT_v06, "threshold_not_met") + { + RootImpl root(root1_json); - json patch; + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/delegations/root/threshold", "value": 2 } + ])"_json; - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09+0030" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); + CHECK_THROWS_AS(root.update(create_root_update("2.root.json", patch)), role_error); + } - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09D" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); + TEST_CASE_FIXTURE(RootImplT_v06, "expires") + { + RootImpl root(root1_json); - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09.000" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + // expiration is set to now+3600s in 'sign_root' + TimeRef time_ref; + CHECK_FALSE(root.expired(time_ref)); - TEST_F(RootImplT_v06, possible_update_files) - { - RootImpl root(root1_json); - - auto update_f = root.possible_update_files(); - EXPECT_THAT( - update_f, - ::testing::ElementsAre( - "2.sv1.root.json", - "2.sv0.7.root.json", - "2.sv0.6.root.json", - "2.root.json" - ) - ); - - json patch = json::parse(R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - auto updated_root = root.update(create_root_update("2.root.json", patch)); - update_f = updated_root->possible_update_files(); - EXPECT_THAT( - update_f, - ::testing::ElementsAre( - "3.sv1.root.json", - "3.sv0.7.root.json", - "3.sv0.6.root.json", - "3.root.json" - ) - ); - } + time_ref.set(utc_time_now() + 7200); + CHECK(root.expired(time_ref)); + + json patch = json::parse( + R"([ + { "op": "replace", "path": "/signed/expiration", "value": ")" + + timestamp(utc_time_now() + 10800) + R"(" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])" + ); + auto updated_root = root.update(create_root_update("2.root.json", patch)); + + auto testing_root = static_cast(updated_root.get()); + CHECK_FALSE(testing_root->expired(time_ref)); + } + + TEST_CASE_FIXTURE(RootImplT_v06, "timestamp") + { + RootImpl root(root1_json); + json patch; - class SpecImplT_v06 : public ::testing::Test + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09+0030" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09D" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09.000" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } + + TEST_CASE_FIXTURE(RootImplT_v06, "possible_update_files") + { + RootImpl root(root1_json); + + auto update_f = root.possible_update_files(); + CHECK(update_f[0].string().c_str() == doctest::Contains("2.sv1.root.json")); + CHECK(update_f[1].string().c_str() == doctest::Contains("2.sv0.7.root.json")); + CHECK(update_f[2].string().c_str() == doctest::Contains("2.sv0.6.root.json")); + CHECK(update_f[3].string().c_str() == doctest::Contains("2.root.json")); + + json patch = json::parse(R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + auto updated_root = root.update(create_root_update("2.root.json", patch)); + update_f = updated_root->possible_update_files(); + CHECK(update_f[0].string().c_str() == doctest::Contains("3.sv1.root.json")); + CHECK(update_f[1].string().c_str() == doctest::Contains("3.sv0.7.root.json")); + CHECK(update_f[2].string().c_str() == doctest::Contains("3.sv0.6.root.json")); + CHECK(update_f[3].string().c_str() == doctest::Contains("3.root.json")); + } + } + + class SpecImplT_v06 { public: @@ -798,91 +845,95 @@ namespace mamba::validation SpecImpl spec; }; - TEST_F(SpecImplT_v06, ctor) + TEST_SUITE("SpecImplT_v06") { - SpecImpl new_spec("0.6.1"); - EXPECT_EQ(new_spec.version_str(), "0.6.1"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "ctor") + { + SpecImpl new_spec("0.6.1"); + CHECK_EQ(new_spec.version_str(), "0.6.1"); + } - TEST_F(SpecImplT_v06, version_str) - { - EXPECT_EQ(spec.version_str(), "0.6.0"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "version_str") + { + CHECK_EQ(spec.version_str(), "0.6.0"); + } - TEST_F(SpecImplT_v06, is_compatible) - { - EXPECT_TRUE(spec.is_compatible(std::string("0.6.0"))); - EXPECT_TRUE(spec.is_compatible(std::string("0.6.1"))); - EXPECT_TRUE(spec.is_compatible(std::string("0.6.10"))); - - // minor version change with major version '0' may be - // backward incompatible - EXPECT_FALSE(spec.is_compatible(std::string("0.7.0"))); - EXPECT_FALSE(spec.is_compatible(std::string("1.0.0"))); - EXPECT_FALSE(spec.is_compatible(std::string("2.0.0"))); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "is_compatible") + { + CHECK(spec.is_compatible(std::string("0.6.0"))); + CHECK(spec.is_compatible(std::string("0.6.1"))); + CHECK(spec.is_compatible(std::string("0.6.10"))); + + // minor version change with major version '0' may be + // backward incompatible + CHECK_FALSE(spec.is_compatible(std::string("0.7.0"))); + CHECK_FALSE(spec.is_compatible(std::string("1.0.0"))); + CHECK_FALSE(spec.is_compatible(std::string("2.0.0"))); + } - TEST_F(SpecImplT_v06, is_upgrade) - { - EXPECT_TRUE(spec.is_upgrade(std::string("0.7.0"))); - EXPECT_TRUE(spec.is_upgrade(std::string("1.0.0"))); - EXPECT_TRUE(spec.is_upgrade(std::string("1.1.0"))); - EXPECT_TRUE(spec.is_upgrade(std::string("1.0.17"))); - - // 2 possible backward incompatible updates - EXPECT_FALSE(spec.is_upgrade(std::string("0.8.0"))); - EXPECT_FALSE(spec.is_upgrade(std::string("2.0.0"))); - // not an upgrade, compatible version - EXPECT_FALSE(spec.is_upgrade(std::string("0.6.1"))); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "is_upgrade") + { + CHECK(spec.is_upgrade(std::string("0.7.0"))); + CHECK(spec.is_upgrade(std::string("1.0.0"))); + CHECK(spec.is_upgrade(std::string("1.1.0"))); + CHECK(spec.is_upgrade(std::string("1.0.17"))); + + // 2 possible backward incompatible updates + CHECK_FALSE(spec.is_upgrade(std::string("0.8.0"))); + CHECK_FALSE(spec.is_upgrade(std::string("2.0.0"))); + // not an upgrade, compatible version + CHECK_FALSE(spec.is_upgrade(std::string("0.6.1"))); + } - TEST_F(SpecImplT_v06, upgradable) - { - EXPECT_TRUE(spec.upgradable()); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "upgradable") + { + CHECK(spec.upgradable()); + } - TEST_F(SpecImplT_v06, compatible_prefix) - { - EXPECT_EQ(spec.compatible_prefix(), "0.6"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "compatible_prefix") + { + CHECK_EQ(spec.compatible_prefix(), "0.6"); + } - TEST_F(SpecImplT_v06, upgrade_prefix) - { - EXPECT_THAT(spec.upgrade_prefix(), ::testing::ElementsAre("1", "0.7")); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "upgrade_prefix") + { + CHECK(spec.upgrade_prefix()[0].c_str() == doctest::Contains("1")); + CHECK(spec.upgrade_prefix()[1].c_str() == doctest::Contains("0.7")); + } - TEST_F(SpecImplT_v06, json_key) - { - EXPECT_EQ(spec.json_key(), "metadata_spec_version"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "json_key") + { + CHECK_EQ(spec.json_key(), "metadata_spec_version"); + } - TEST_F(SpecImplT_v06, expiration_json_key) - { - EXPECT_EQ(spec.expiration_json_key(), "expiration"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "expiration_json_key") + { + CHECK_EQ(spec.expiration_json_key(), "expiration"); + } - TEST_F(SpecImplT_v06, canonicalize) - { - EXPECT_EQ(spec.canonicalize(R"({"foo":"bar"})"_json), "{\n \"foo\": \"bar\"\n}"); - } + TEST_CASE_FIXTURE(SpecImplT_v06, "canonicalize") + { + CHECK_EQ(spec.canonicalize(R"({"foo":"bar"})"_json), "{\n \"foo\": \"bar\"\n}"); + } - TEST_F(SpecImplT_v06, signatures) - { - json j = R"({ - "signatures": - { - "foo": + TEST_CASE_FIXTURE(SpecImplT_v06, "signatures") + { + json j = R"({ + "signatures": { - "other_headers": "bar", - "signature": "baz" + "foo": + { + "other_headers": "bar", + "signature": "baz" + } } - } - })"_json; - auto sigs = spec.signatures(j); - EXPECT_EQ(sigs.size(), 1); - EXPECT_EQ(sigs.begin()->keyid, "foo"); - EXPECT_EQ(sigs.begin()->sig, "baz"); - EXPECT_EQ(sigs.begin()->pgp_trailer, "bar"); + })"_json; + auto sigs = spec.signatures(j); + CHECK_EQ(sigs.size(), 1); + CHECK_EQ(sigs.begin()->keyid, "foo"); + CHECK_EQ(sigs.begin()->sig, "baz"); + CHECK_EQ(sigs.begin()->pgp_trailer, "bar"); + } } @@ -966,173 +1017,187 @@ namespace mamba::validation } }; - TEST_F(KeyMgrT_v06, ctor_from_json) + TEST_SUITE("KeyMgrT_v06") { - RootImpl root(root1_json); - auto key_mgr = root.create_key_mgr(key_mgr_json); + TEST_CASE_FIXTURE(KeyMgrT_v06, "ctor_from_json") + { + RootImpl root(root1_json); + auto key_mgr = root.create_key_mgr(key_mgr_json); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 1); - } + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 1); + } - TEST_F(KeyMgrT_v06, ctor_from_json_str) - { - RootImpl root(root1_json); - auto key_mgr = KeyMgrRole( - key_mgr_json.dump(), - root.all_keys()["key_mgr"], - std::make_shared(SpecImpl()) - ); - - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 1); - } + TEST_CASE_FIXTURE(KeyMgrT_v06, "ctor_from_json_str") + { + RootImpl root(root1_json); + auto key_mgr = KeyMgrRole( + key_mgr_json.dump(), + root.all_keys()["key_mgr"], + std::make_shared(SpecImpl()) + ); - TEST_F(KeyMgrT_v06, version) - { - RootImpl root(root1_json); + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 1); + } + TEST_CASE_FIXTURE(KeyMgrT_v06, "version") { - json key_mgr_patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; - auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); + RootImpl root(root1_json); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 2); - } + { + json key_mgr_patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; + auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); - { // Any version is valid, without chaining required - json key_mgr_patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 20 } - ])"_json; - auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 2); + } + + { // Any version is valid, without chaining required + json key_mgr_patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 20 } + ])"_json; + auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 20); + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 20); + } } - } - TEST_F(KeyMgrT_v06, spec_version) - { // spec version as to match exactly 'root' spec version - RootImpl root(root1_json); + TEST_CASE_FIXTURE(KeyMgrT_v06, "spec_version") + { // spec version as to match exactly 'root' spec version + RootImpl root(root1_json); - { - json key_mgr_patch = R"([ - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.0" } - ])"_json; - auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); + { + json key_mgr_patch = R"([ + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.0" } + ])"_json; + auto key_mgr = root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 1); - } + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 1); + } - { // is compatible but not strictly the same as 'root' one - json key_mgr_patch = R"([ - { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.1" } - ])"_json; + { // is compatible but not strictly the same as 'root' one + json key_mgr_patch = R"([ + { "op": "replace", "path": "/signed/metadata_spec_version", "value": "0.6.1" } + ])"_json; - EXPECT_THROW( - root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)), - spec_version_error - ); + CHECK_THROWS_AS( + root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)), + spec_version_error + ); + } + + { // wrong type + json key_mgr_patch = R"([ + { "op": "replace", "path": "/signed/metadata_spec_version", "value": 0.6 } + ])"_json; + + CHECK_THROWS_AS( + root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)), + role_metadata_error + ); + } } - { // wrong type - json key_mgr_patch = R"([ - { "op": "replace", "path": "/signed/metadata_spec_version", "value": 0.6 } - ])"_json; + TEST_CASE_FIXTURE(KeyMgrT_v06, "ctor_from_path") + { + RootImpl root(root1_json); - EXPECT_THROW( - root.create_key_mgr(patched_key_mgr_json(key_mgr_patch)), - role_metadata_error + auto key_mgr = root.create_key_mgr(write_key_mgr_file(key_mgr_json)); + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 1); + + // TODO: enforce consistency between spec version in filename and metadata + key_mgr = root.create_key_mgr( + write_key_mgr_file(key_mgr_json, "20.sv0.6.key_mgr.json") ); - } - } + CHECK_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); + CHECK_EQ(key_mgr.version(), 1); - TEST_F(KeyMgrT_v06, ctor_from_path) - { - RootImpl root(root1_json); - auto key_mgr = root.create_key_mgr(write_key_mgr_file(key_mgr_json)); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 1); + CHECK_THROWS_AS(root.create_key_mgr(fs::u8path("not_existing")), role_file_error); + + CHECK_THROWS_AS( + root.create_key_mgr(write_key_mgr_file(key_mgr_json, "wrong.json")), + role_file_error + ); - // TODO: enforce consistency between spec version in filename and metadata - key_mgr = root.create_key_mgr(write_key_mgr_file(key_mgr_json, "20.sv0.6.key_mgr.json") - ); - EXPECT_EQ(key_mgr.spec_version(), SpecImpl("0.6.0")); - EXPECT_EQ(key_mgr.version(), 1); + CHECK_THROWS_AS( + root.create_key_mgr(write_key_mgr_file(key_mgr_json, "sv1.key_mgr.json")), + role_file_error + ); + CHECK_THROWS_AS( + root.create_key_mgr(write_key_mgr_file(key_mgr_json, "wrong.sv0.6.key_mgr.json") + ), + role_file_error + ); + } - EXPECT_THROW(root.create_key_mgr(fs::u8path("not_existing")), role_file_error); + TEST_CASE_FIXTURE(KeyMgrT_v06, "expires") + { + RootImpl root(root1_json); + auto key_mgr = root.create_key_mgr(key_mgr_json); - EXPECT_THROW( - root.create_key_mgr(write_key_mgr_file(key_mgr_json, "wrong.json")), - role_file_error - ); + // expiration is set to now+3600s in 'sign_key_mgr' + TimeRef time_ref; + CHECK_FALSE(key_mgr.expired(time_ref)); + CHECK_FALSE(root.expired(time_ref)); - EXPECT_THROW( - root.create_key_mgr(write_key_mgr_file(key_mgr_json, "sv1.key_mgr.json")), - role_file_error - ); + time_ref.set(utc_time_now() + 7200); + CHECK(key_mgr.expired(time_ref)); + CHECK(root.expired(time_ref)); - EXPECT_THROW( - root.create_key_mgr(write_key_mgr_file(key_mgr_json, "wrong.sv0.6.key_mgr.json")), - role_file_error - ); - } + json patch = json::parse( + R"([ + { "op": "replace", "path": "/signed/expiration", "value": ")" + + timestamp(utc_time_now() + 10800) + R"(" } + ])" + ); - TEST_F(KeyMgrT_v06, expires) - { - RootImpl root(root1_json); - auto key_mgr = root.create_key_mgr(key_mgr_json); - - // expiration is set to now+3600s in 'sign_key_mgr' - TimeRef time_ref; - EXPECT_FALSE(key_mgr.expired(time_ref)); - EXPECT_FALSE(root.expired(time_ref)); - - time_ref.set(utc_time_now() + 7200); - EXPECT_TRUE(key_mgr.expired(time_ref)); - EXPECT_TRUE(root.expired(time_ref)); - - json patch = json::parse( - R"([ - { "op": "replace", "path": "/signed/expiration", "value": ")" - + timestamp(utc_time_now() + 10800) + R"(" } - ])" - ); - - key_mgr = root.create_key_mgr(patched_key_mgr_json(patch)); - EXPECT_FALSE(key_mgr.expired(time_ref)); - EXPECT_TRUE(root.expired(time_ref)); - } + key_mgr = root.create_key_mgr(patched_key_mgr_json(patch)); + CHECK_FALSE(key_mgr.expired(time_ref)); + CHECK(root.expired(time_ref)); + } - TEST_F(KeyMgrT_v06, timestamp) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(KeyMgrT_v06, "timestamp") + { + RootImpl root(root1_json); - json patch; + json patch; - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09+0030" }, - { "op": "replace", "path": "/signed/version", "value": 1 } - ])"); + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09+0030" }, + { "op": "replace", "path": "/signed/version", "value": 1 } + ])"); - EXPECT_THROW(root.create_key_mgr(patched_key_mgr_json(patch)), role_metadata_error); + CHECK_THROWS_AS( + root.create_key_mgr(patched_key_mgr_json(patch)), + role_metadata_error + ); - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09D" }, - { "op": "replace", "path": "/signed/version", "value": 1 } - ])"); - EXPECT_THROW(root.create_key_mgr(patched_key_mgr_json(patch)), role_metadata_error); + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09D" }, + { "op": "replace", "path": "/signed/version", "value": 1 } + ])"); + CHECK_THROWS_AS( + root.create_key_mgr(patched_key_mgr_json(patch)), + role_metadata_error + ); - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09.000" }, - { "op": "replace", "path": "/signed/version", "value": 1 } - ])"); - EXPECT_THROW(root.create_key_mgr(patched_key_mgr_json(patch)), role_metadata_error); + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/timestamp", "value": "2021-09-20T07:07:09.000" }, + { "op": "replace", "path": "/signed/version", "value": 1 } + ])"); + CHECK_THROWS_AS( + root.create_key_mgr(patched_key_mgr_json(patch)), + role_metadata_error + ); + } } class PkgMgrT_v06 : public KeyMgrT_v06 @@ -1290,40 +1355,43 @@ namespace mamba::validation } }; - TEST_F(PkgMgrT_v06, verify_index) + TEST_SUITE("PkgMgrT_v06") { - auto key_mgr = root->create_key_mgr(key_mgr_json); - auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); + TEST_CASE_FIXTURE(PkgMgrT_v06, "verify_index") + { + auto key_mgr = root->create_key_mgr(key_mgr_json); + auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); - pkg_mgr.verify_index(signed_repodata_json); - } + pkg_mgr.verify_index(signed_repodata_json); + } - TEST_F(PkgMgrT_v06, corrupted_repodata) - { - auto key_mgr = root->create_key_mgr(key_mgr_json); - auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); - - json wrong_pkg_patch = R"([ - { "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" } - ])"_json; - EXPECT_THROW( - pkg_mgr.verify_index(signed_repodata_json.patch(wrong_pkg_patch)), - package_error - ); - } + TEST_CASE_FIXTURE(PkgMgrT_v06, "corrupted_repodata") + { + auto key_mgr = root->create_key_mgr(key_mgr_json); + auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); - TEST_F(PkgMgrT_v06, illformed_repodata) - { - auto key_mgr = root->create_key_mgr(key_mgr_json); - auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); - - json illformed_pkg_patch = R"([ - { "op": "remove", "path": "/signatures"} - ])"_json; - EXPECT_THROW( - pkg_mgr.verify_index(signed_repodata_json.patch(illformed_pkg_patch)), - index_error - ); + json wrong_pkg_patch = R"([ + { "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" } + ])"_json; + CHECK_THROWS_AS( + pkg_mgr.verify_index(signed_repodata_json.patch(wrong_pkg_patch)), + package_error + ); + } + + TEST_CASE_FIXTURE(PkgMgrT_v06, "illformed_repodata") + { + auto key_mgr = root->create_key_mgr(key_mgr_json); + auto pkg_mgr = key_mgr.create_pkg_mgr(pkg_mgr_json); + + json illformed_pkg_patch = R"([ + { "op": "remove", "path": "/signatures"} + ])"_json; + CHECK_THROWS_AS( + pkg_mgr.verify_index(signed_repodata_json.patch(illformed_pkg_patch)), + index_error + ); + } } @@ -1372,80 +1440,83 @@ namespace mamba::validation } }; - TEST_F(RepoCheckerT, ctor) + TEST_SUITE("RepoCheckerT") { - RepoChecker checker(m_repo_base_url, m_ref_path); - checker.generate_index_checker(); - EXPECT_EQ(checker.root_version(), 2); - } + TEST_CASE_FIXTURE(RepoCheckerT, "ctor") + { + RepoChecker checker(m_repo_base_url, m_ref_path); + checker.generate_index_checker(); + CHECK_EQ(checker.root_version(), 2); + } - TEST_F(RepoCheckerT, verify_index) - { - RepoChecker checker(m_repo_base_url, m_ref_path); - checker.generate_index_checker(); - checker.verify_index(signed_repodata_json); - } + TEST_CASE_FIXTURE(RepoCheckerT, "verify_index") + { + RepoChecker checker(m_repo_base_url, m_ref_path); + checker.generate_index_checker(); + checker.verify_index(signed_repodata_json); + } - TEST_F(RepoCheckerT, root_freeze_attack) - { - json patch = json::parse( - R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/expiration", "value": ")" - + timestamp(utc_time_now() - 10) + R"(" } - ])" - ); - write_role(create_root_update_json(patch), channel_dir->path() / "2.root.json"); - RepoChecker checker(m_repo_base_url, m_ref_path); - EXPECT_THROW(checker.generate_index_checker(), freeze_error); - } + TEST_CASE_FIXTURE(RepoCheckerT, "root_freeze_attack") + { + json patch = json::parse( + R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/expiration", "value": ")" + + timestamp(utc_time_now() - 10) + R"(" } + ])" + ); + write_role(create_root_update_json(patch), channel_dir->path() / "2.root.json"); + RepoChecker checker(m_repo_base_url, m_ref_path); + CHECK_THROWS_AS(checker.generate_index_checker(), freeze_error); + } - TEST_F(RepoCheckerT, key_mgr_freeze_attack) - { - json patch = json::parse( - R"([ - { "op": "replace", "path": "/signed/expiration", "value": ")" - + timestamp(utc_time_now() - 10) + R"(" } - ])" - ); - write_role(patched_key_mgr_json(patch), channel_dir->path() / "key_mgr.json"); - RepoChecker checker(m_repo_base_url, m_ref_path); - EXPECT_THROW(checker.generate_index_checker(), freeze_error); - } + TEST_CASE_FIXTURE(RepoCheckerT, "key_mgr_freeze_attack") + { + json patch = json::parse( + R"([ + { "op": "replace", "path": "/signed/expiration", "value": ")" + + timestamp(utc_time_now() - 10) + R"(" } + ])" + ); + write_role(patched_key_mgr_json(patch), channel_dir->path() / "key_mgr.json"); + RepoChecker checker(m_repo_base_url, m_ref_path); + CHECK_THROWS_AS(checker.generate_index_checker(), freeze_error); + } - TEST_F(RepoCheckerT, missing_key_mgr_file) - { - fs::remove(channel_dir->path() / "key_mgr.json"); - RepoChecker checker(m_repo_base_url, m_ref_path); - EXPECT_THROW(checker.generate_index_checker(), fetching_error); - } + TEST_CASE_FIXTURE(RepoCheckerT, "missing_key_mgr_file") + { + fs::remove(channel_dir->path() / "key_mgr.json"); + RepoChecker checker(m_repo_base_url, m_ref_path); + CHECK_THROWS_AS(checker.generate_index_checker(), fetching_error); + } - TEST_F(RepoCheckerT, corrupted_repodata) - { - RepoChecker checker(m_repo_base_url, m_ref_path); - - json wrong_pkg_patch = R"([ - { "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" } - ])"_json; - checker.generate_index_checker(); - EXPECT_THROW( - checker.verify_index(signed_repodata_json.patch(wrong_pkg_patch)), - package_error - ); - } + TEST_CASE_FIXTURE(RepoCheckerT, "corrupted_repodata") + { + RepoChecker checker(m_repo_base_url, m_ref_path); - TEST_F(RepoCheckerT, illformed_repodata) - { - RepoChecker checker(m_repo_base_url, m_ref_path); - - json illformed_pkg_patch = R"([ - { "op": "remove", "path": "/signatures"} - ])"_json; - checker.generate_index_checker(); - EXPECT_THROW( - checker.verify_index(signed_repodata_json.patch(illformed_pkg_patch)), - index_error - ); + json wrong_pkg_patch = R"([ + { "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" } + ])"_json; + checker.generate_index_checker(); + CHECK_THROWS_AS( + checker.verify_index(signed_repodata_json.patch(wrong_pkg_patch)), + package_error + ); + } + + TEST_CASE_FIXTURE(RepoCheckerT, "illformed_repodata") + { + RepoChecker checker(m_repo_base_url, m_ref_path); + + json illformed_pkg_patch = R"([ + { "op": "remove", "path": "/signatures"} + ])"_json; + checker.generate_index_checker(); + CHECK_THROWS_AS( + checker.verify_index(signed_repodata_json.patch(illformed_pkg_patch)), + index_error + ); + } } } // namespace testing } // namespace v06 @@ -1456,7 +1527,7 @@ namespace mamba::validation { using namespace mamba; - class RootImplT_v1 : public ::testing::Test + class RootImplT_v1 { public: @@ -1587,342 +1658,404 @@ namespace mamba::validation } }; - TEST_F(RootImplT_v1, ctor_from_path) + TEST_SUITE("RootImplT_v1") { - RootImpl root(trusted_root_file()); + TEST_CASE_FIXTURE(RootImplT_v1, "ctor_from_path") + { + RootImpl root(trusted_root_file()); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("1.0.17")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("1.0.17")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v1, ctor_from_json) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "ctor_from_json") + { + RootImpl root(root1_json); - EXPECT_EQ(root.type(), "root"); - EXPECT_EQ(root.file_ext(), "json"); - EXPECT_EQ(root.spec_version(), SpecImpl("1.0.17")); - EXPECT_EQ(root.version(), 1); - } + CHECK_EQ(root.type(), "root"); + CHECK_EQ(root.file_ext(), "json"); + CHECK_EQ(root.spec_version(), SpecImpl("1.0.17")); + CHECK_EQ(root.version(), 1); + } - TEST_F(RootImplT_v1, update_from_path) - { - using namespace mamba; + TEST_CASE_FIXTURE(RootImplT_v1, "update_from_path") + { + using namespace mamba; - RootImpl root(trusted_root_file()); + RootImpl root(trusted_root_file()); - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; - auto updated_root = root.update(create_root_update("2.root.json", patch)); + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; + auto updated_root = root.update(create_root_update("2.root.json", patch)); - auto testing_root = static_cast(updated_root.get()); - EXPECT_EQ(testing_root->type(), "root"); - EXPECT_EQ(testing_root->file_ext(), "json"); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("1.0.17")); - EXPECT_EQ(testing_root->version(), 2); - } + auto testing_root = static_cast(updated_root.get()); + CHECK_EQ(testing_root->type(), "root"); + CHECK_EQ(testing_root->file_ext(), "json"); + CHECK_EQ(testing_root->spec_version(), SpecImpl("1.0.17")); + CHECK_EQ(testing_root->version(), 2); + } - TEST_F(RootImplT_v1, ctor_wrong_filename_spec_version) - { - fs::u8path p = channel_dir->path() / "2.sv0.6.root.json"; + TEST_CASE_FIXTURE(RootImplT_v1, "ctor_wrong_filename_spec_version") + { + fs::u8path p = channel_dir->path() / "2.sv0.6.root.json"; - std::ofstream out_file(p.std_path(), std::ofstream::out | std::ofstream::trunc); - out_file << root1_json; - out_file.close(); + std::ofstream out_file(p.std_path(), std::ofstream::out | std::ofstream::trunc); + out_file << root1_json; + out_file.close(); - // "2.sv0.6.root.json" is not compatible spec version (spec version N) - EXPECT_THROW(RootImpl root(p), role_file_error); - } + // "2.sv0.6.root.json" is not compatible spec version (spec version N) + CHECK_THROWS_AS(RootImpl root(p), role_file_error); + } - TEST_F(RootImplT_v1, wrong_version) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_version") + { + RootImpl root(root1_json); - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 3 } - ])"_json; + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 3 } + ])"_json; - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - TEST_F(RootImplT_v1, spec_version) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "spec_version") + { + RootImpl root(root1_json); - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/spec_version", "value": "1.30.10" } - ])"_json; + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/spec_version", "value": "1.30.10" } + ])"_json; - auto updated_root = root.update(create_root_update("2.root.json", patch)); + auto updated_root = root.update(create_root_update("2.root.json", patch)); - auto testing_root = static_cast(updated_root.get()); - EXPECT_EQ(testing_root->spec_version(), SpecImpl("1.30.10")); - EXPECT_EQ(testing_root->version(), 2); - } + auto testing_root = static_cast(updated_root.get()); + CHECK_EQ(testing_root->spec_version(), SpecImpl("1.30.10")); + CHECK_EQ(testing_root->version(), 2); + } - TEST_F(RootImplT_v1, wrong_spec_version) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_spec_version") + { + RootImpl root(root1_json); - json patch = R"([ - { "op": "replace", "path": "/signed/spec_version", "value": "2.0.0" } - ])"_json; + json patch = R"([ + { "op": "replace", "path": "/signed/spec_version", "value": "2.0.0" } + ])"_json; - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), spec_version_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + spec_version_error + ); + } - TEST_F(RootImplT_v1, wrong_filename_role) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_filename_role") + { + RootImpl root(root1_json); - json patch = R"([])"_json; + json patch = R"([])"_json; - EXPECT_THROW(root.update(create_root_update("2.rooot.json", patch)), role_file_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.rooot.json", patch)), + role_file_error + ); + } - TEST_F(RootImplT_v1, wrong_filename_version) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_filename_version") + { + RootImpl root(root1_json); - json patch = R"([])"_json; + json patch = R"([])"_json; - EXPECT_THROW(root.update(create_root_update("3.root.json", patch)), role_file_error); - } + CHECK_THROWS_AS( + root.update(create_root_update("3.root.json", patch)), + role_file_error + ); + } - TEST_F(RootImplT_v1, wrong_filename_spec_version) - { - RootImpl root(root1_json); - - // "2.sv2.root.json" is upgradable spec version (spec version N+1) - // but v2 is NOT implemented yet, so v1::RootImpl is not upgradable - EXPECT_THROW(root.update(create_root_update("2.sv2.root.json")), spec_version_error); - // "2.sv3.root.json" is NOT upgradable spec version (spec version N+1) - EXPECT_THROW(root.update(create_root_update("2.sv3.root.json")), role_file_error); - EXPECT_THROW(root.update(create_root_update("2.sv0.6.root.json")), role_file_error); - } + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_filename_spec_version") + { + RootImpl root(root1_json); - TEST_F(RootImplT_v1, illformed_filename_version) - { - RootImpl root(root1_json); + // "2.sv2.root.json" is upgradable spec version (spec version N+1) + // but v2 is NOT implemented yet, so v1::RootImpl is not upgradable + CHECK_THROWS_AS( + root.update(create_root_update("2.sv2.root.json")), + spec_version_error + ); + // "2.sv3.root.json" is NOT upgradable spec version (spec version N+1) + CHECK_THROWS_AS(root.update(create_root_update("2.sv3.root.json")), role_file_error); + CHECK_THROWS_AS( + root.update(create_root_update("2.sv0.6.root.json")), + role_file_error + ); + } - json patch = R"([])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "illformed_filename_version") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("wrong.root.json", patch)), role_file_error); - } + json patch = R"([])"_json; - TEST_F(RootImplT_v1, rollback_attack) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("wrong.root.json", patch)), + role_file_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 1 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "rollback_attack") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), rollback_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 1 } + ])"_json; - TEST_F(RootImplT_v1, wrong_type) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + rollback_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/_type", "value": "timestamp" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "wrong_type") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/_type", "value": "timestamp" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, missing_type) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/_type" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "missing_type") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/_type" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, missing_keys) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/keys" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "missing_keys") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/keys" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, missing_roles) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/roles" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "missing_roles") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/roles" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, missing_role) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "remove", "path": "/signed/roles/timestamp" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "missing_role") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "remove", "path": "/signed/roles/timestamp" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, empty_role_keyids) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/roles/snapshot/keyids", "value": [] }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "empty_role_keyids") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/roles/snapshot/keyids", "value": [] }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, null_role_threshold) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "replace", "path": "/signed/roles/snapshot/threshold", "value": 0 }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "null_role_threshold") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/roles/snapshot/threshold", "value": 0 }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, extra_roles) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "add", "path": "/signed/roles/some_wrong_role", "value": { "keyids": ["c"], "threshold": 1 } }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "extra_roles") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "add", "path": "/signed/roles/some_wrong_role", "value": { "keyids": ["c"], "threshold": 1 } }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, key_not_found) - { - RootImpl root(root1_json); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - json patch = R"([ - { "op": "add", "path": "/signed/roles/snapshot/keyids/-", "value": "c" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "key_not_found") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + json patch = R"([ + { "op": "add", "path": "/signed/roles/snapshot/keyids/-", "value": "c" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, mirrors_role) - { - json patch = R"([ - { "op": "add", "path": "/signed/roles/mirrors", "value": { "keyids": ["c"], "threshold": 1 } }, - { "op": "add", "path": "/signed/keys/c", "value": { "scheme": "ed25519", "keytype": "ed25519", "keyval": "c"} }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"_json; - - const RootImpl root(create_root_update("2.root.json", patch)); - const bool mirrors_role_found = root.roles().find("mirrors") != root.roles().cend(); - EXPECT_TRUE(mirrors_role_found); - } + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } - TEST_F(RootImplT_v1, threshold_not_met) - { - RootImpl root(root1_json); + TEST_CASE_FIXTURE(RootImplT_v1, "mirrors_role") + { + json patch = R"([ + { "op": "add", "path": "/signed/roles/mirrors", "value": { "keyids": ["c"], "threshold": 1 } }, + { "op": "add", "path": "/signed/keys/c", "value": { "scheme": "ed25519", "keytype": "ed25519", "keyval": "c"} }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"_json; + + const RootImpl root(create_root_update("2.root.json", patch)); + const bool mirrors_role_found = root.roles().find("mirrors") + != root.roles().cend(); + CHECK(mirrors_role_found); + } - json patch = R"([ - { "op": "replace", "path": "/signed/version", "value": 2 }, - { "op": "replace", "path": "/signed/roles/root/threshold", "value": 2 } - ])"_json; + TEST_CASE_FIXTURE(RootImplT_v1, "threshold_not_met") + { + RootImpl root(root1_json); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_error); - } + json patch = R"([ + { "op": "replace", "path": "/signed/version", "value": 2 }, + { "op": "replace", "path": "/signed/roles/root/threshold", "value": 2 } + ])"_json; - TEST_F(RootImplT_v1, expires) - { - RootImpl root(root1_json); - - // expiration is set to now+3600s in 'sign_root' - TimeRef time_ref; - EXPECT_FALSE(root.expired(time_ref)); - - time_ref.set(utc_time_now() + 7200); - EXPECT_TRUE(root.expired(time_ref)); - - json patch = json::parse( - R"([ - { "op": "replace", "path": "/signed/expires", "value": ")" - + timestamp(utc_time_now() + 10800) + R"(" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])" - ); - auto updated_root = root.update(create_root_update("2.root.json", patch)); - - auto testing_root = static_cast(updated_root.get()); - EXPECT_FALSE(testing_root->expired(time_ref)); - - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09+0030" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); + CHECK_THROWS_AS(root.update(create_root_update("2.root.json", patch)), role_error); + } - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09D" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); + TEST_CASE_FIXTURE(RootImplT_v1, "expires") + { + RootImpl root(root1_json); - patch = json::parse(R"([ - { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09.000" }, - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - EXPECT_THROW(root.update(create_root_update("2.root.json", patch)), role_metadata_error); - } + // expiration is set to now+3600s in 'sign_root' + TimeRef time_ref; + CHECK_FALSE(root.expired(time_ref)); - TEST_F(RootImplT_v1, possible_update_files) - { - RootImpl root(root1_json); + time_ref.set(utc_time_now() + 7200); + CHECK(root.expired(time_ref)); - auto update_f = root.possible_update_files(); - EXPECT_THAT( - update_f, - ::testing::ElementsAre("2.sv2.root.json", "2.sv1.root.json", "2.root.json") - ); + json patch = json::parse( + R"([ + { "op": "replace", "path": "/signed/expires", "value": ")" + + timestamp(utc_time_now() + 10800) + R"(" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])" + ); + auto updated_root = root.update(create_root_update("2.root.json", patch)); - json patch = json::parse(R"([ - { "op": "replace", "path": "/signed/version", "value": 2 } - ])"); - auto updated_root = root.update(create_root_update("2.root.json", patch)); - update_f = updated_root->possible_update_files(); - EXPECT_THAT( - update_f, - ::testing::ElementsAre("3.sv2.root.json", "3.sv1.root.json", "3.root.json") - ); + auto testing_root = static_cast(updated_root.get()); + CHECK_FALSE(testing_root->expired(time_ref)); + + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09+0030" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09D" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + + patch = json::parse(R"([ + { "op": "replace", "path": "/signed/expires", "value": "2051-10-08T07:07:09.000" }, + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + CHECK_THROWS_AS( + root.update(create_root_update("2.root.json", patch)), + role_metadata_error + ); + } + + TEST_CASE_FIXTURE(RootImplT_v1, "possible_update_files") + { + RootImpl root(root1_json); + + auto update_f = root.possible_update_files(); + CHECK(update_f[0].string().c_str() == doctest::Contains("2.sv2.root.json")); + CHECK(update_f[1].string().c_str() == doctest::Contains("2.sv1.root.json")); + CHECK(update_f[2].string().c_str() == doctest::Contains("2.root.json")); + + json patch = json::parse(R"([ + { "op": "replace", "path": "/signed/version", "value": 2 } + ])"); + auto updated_root = root.update(create_root_update("2.root.json", patch)); + update_f = updated_root->possible_update_files(); + CHECK(update_f[0].string().c_str() == doctest::Contains("3.sv2.root.json")); + CHECK(update_f[1].string().c_str() == doctest::Contains("3.sv1.root.json")); + CHECK(update_f[2].string().c_str() == doctest::Contains("3.root.json")); + } } - class SpecImplT_v1 : public ::testing::Test + class SpecImplT_v1 { public: @@ -1933,99 +2066,105 @@ namespace mamba::validation SpecImpl spec; }; - TEST_F(SpecImplT_v1, ctor) + TEST_SUITE("SpecImplT_v1") { - SpecImpl new_spec("1.0.0"); - EXPECT_EQ(new_spec.version_str(), "1.0.0"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "ctore") + { + SpecImpl new_spec("1.0.0"); + CHECK_EQ(new_spec.version_str(), "1.0.0"); + } - TEST_F(SpecImplT_v1, version_str) - { - EXPECT_EQ(spec.version_str(), "1.0.17"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "version_str") + { + CHECK_EQ(spec.version_str(), "1.0.17"); + } - TEST_F(SpecImplT_v1, is_compatible) - { - EXPECT_TRUE(spec.is_compatible(std::string("1.0.0"))); - EXPECT_TRUE(spec.is_compatible(std::string("1.0.17"))); - EXPECT_TRUE(spec.is_compatible(std::string("1.25.10"))); + TEST_CASE_FIXTURE(SpecImplT_v1, "is_compatible") + { + CHECK(spec.is_compatible(std::string("1.0.0"))); + CHECK(spec.is_compatible(std::string("1.0.17"))); + CHECK(spec.is_compatible(std::string("1.25.10"))); - EXPECT_FALSE(spec.is_compatible(std::string("2.0.0"))); - EXPECT_FALSE(spec.is_compatible(std::string("2.0.17"))); - EXPECT_FALSE(spec.is_compatible(std::string("0.6.0"))); - } + CHECK_FALSE(spec.is_compatible(std::string("2.0.0"))); + CHECK_FALSE(spec.is_compatible(std::string("2.0.17"))); + CHECK_FALSE(spec.is_compatible(std::string("0.6.0"))); + } - TEST_F(SpecImplT_v1, is_upgrade) - { - EXPECT_TRUE(spec.is_upgrade(std::string("2.0.0"))); - EXPECT_TRUE(spec.is_upgrade(std::string("2.1.10"))); - - EXPECT_FALSE(spec.is_upgrade(std::string("0.6.0"))); - EXPECT_FALSE(spec.is_upgrade(std::string("3.0.0"))); - // not an upgrade, compatible version - EXPECT_FALSE(spec.is_upgrade(std::string("1.0.17"))); - EXPECT_FALSE(spec.is_upgrade(std::string("1.0.0"))); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "is_upgrade") + { + CHECK(spec.is_upgrade(std::string("2.0.0"))); + CHECK(spec.is_upgrade(std::string("2.1.10"))); + + CHECK_FALSE(spec.is_upgrade(std::string("0.6.0"))); + CHECK_FALSE(spec.is_upgrade(std::string("3.0.0"))); + // not an upgrade, compatible version + CHECK_FALSE(spec.is_upgrade(std::string("1.0.17"))); + CHECK_FALSE(spec.is_upgrade(std::string("1.0.0"))); + } - TEST_F(SpecImplT_v1, upgradable) - { - EXPECT_FALSE(spec.upgradable()); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "upgradable") + { + CHECK_FALSE(spec.upgradable()); + } - TEST_F(SpecImplT_v1, compatible_prefix) - { - EXPECT_EQ(spec.compatible_prefix(), "1"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "compatible_prefix") + { + CHECK_EQ(spec.compatible_prefix(), "1"); + } - TEST_F(SpecImplT_v1, upgrade_prefix) - { - EXPECT_THAT(spec.upgrade_prefix(), ::testing::ElementsAre("2")); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "upgrade_prefix") + { + CHECK(spec.upgrade_prefix()[0].c_str() == doctest::Contains("2")); + } - TEST_F(SpecImplT_v1, json_key) - { - EXPECT_EQ(spec.json_key(), "spec_version"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "json_key") + { + CHECK_EQ(spec.json_key(), "spec_version"); + } - TEST_F(SpecImplT_v1, expiration_json_key) - { - EXPECT_EQ(spec.expiration_json_key(), "expires"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "expiration_json_key") + { + CHECK_EQ(spec.expiration_json_key(), "expires"); + } - TEST_F(SpecImplT_v1, canonicalize) - { - EXPECT_EQ(spec.canonicalize(R"({"foo":"bar"})"_json), "{\"foo\":\"bar\"}"); - } + TEST_CASE_FIXTURE(SpecImplT_v1, "canonicalize") + { + CHECK_EQ(spec.canonicalize(R"({"foo":"bar"})"_json), "{\"foo\":\"bar\"}"); + } - TEST_F(SpecImplT_v1, signatures) - { - json j = R"({ - "signatures": - [ - { - "keyid": "foo", - "sig": "baz", - "other_headers": "bar" - } - ] - })"_json; - auto sigs = spec.signatures(j); - EXPECT_EQ(sigs.size(), 1); - EXPECT_EQ(sigs.begin()->keyid, "foo"); - EXPECT_EQ(sigs.begin()->sig, "baz"); - EXPECT_EQ(sigs.begin()->pgp_trailer, "bar"); + TEST_CASE_FIXTURE(SpecImplT_v1, "signatures") + { + json j = R"({ + "signatures": + [ + { + "keyid": "foo", + "sig": "baz", + "other_headers": "bar" + } + ] + })"_json; + auto sigs = spec.signatures(j); + CHECK_EQ(sigs.size(), 1); + CHECK_EQ(sigs.begin()->keyid, "foo"); + CHECK_EQ(sigs.begin()->sig, "baz"); + CHECK_EQ(sigs.begin()->pgp_trailer, "bar"); + } } - // Test serialization/deserialization - TEST(RoleSignature, to_json) + TEST_SUITE("RoleSignature") { - RoleSignature s{ "some_key_id", "some_signature", "" }; - json j = R"({"keyid": "some_key_id", "sig": "some_signature"})"_json; - EXPECT_EQ(j, json(s)); + // Test serialization/deserialization + TEST_CASE("to_json") + { + RoleSignature s{ "some_key_id", "some_signature", "" }; + json j = R"({"keyid": "some_key_id", "sig": "some_signature"})"_json; + CHECK_EQ(j, json(s)); - s = { "some_key_id", "some_signature", "some_pgp_trailer" }; - j = R"({"keyid": "some_key_id", "other_headers": "some_pgp_trailer", "sig": "some_signature"})"_json; - EXPECT_EQ(j, json(s)); + s = { "some_key_id", "some_signature", "some_pgp_trailer" }; + j = R"({"keyid": "some_key_id", "other_headers": "some_pgp_trailer", "sig": "some_signature"})"_json; + CHECK_EQ(j, json(s)); + } } } // namespace testing } // namespace v1 diff --git a/libmamba/tests/src/core/test_virtual_packages.cpp b/libmamba/tests/src/core/test_virtual_packages.cpp index 9e3aee69b9..8d7c9dacd9 100644 --- a/libmamba/tests/src/core/test_virtual_packages.cpp +++ b/libmamba/tests/src/core/test_virtual_packages.cpp @@ -1,132 +1,141 @@ -#include +// Copyright (c) 2022, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. #include "mamba/core/context.hpp" #include "mamba/core/environment.hpp" #include "mamba/core/util.hpp" #include "mamba/core/virtual_packages.hpp" +#include "doctest/doctest.h" + namespace mamba { namespace testing { - TEST(virtual_packages, make_virtual_package) - { - auto pkg = detail::make_virtual_package("test", "0.1.5", "abcd"); - - EXPECT_EQ(pkg.name, "test"); - EXPECT_EQ(pkg.version, "0.1.5"); - EXPECT_EQ(pkg.build_string, "abcd"); - EXPECT_EQ(pkg.build_number, 0); - EXPECT_EQ(pkg.channel, "@"); - // EXPECT_EQ(pkg.subdir, "osx-64"); // TODO: fix this - EXPECT_EQ(pkg.md5, "12345678901234567890123456789012"); - EXPECT_EQ(pkg.fn, pkg.name); - } - - TEST(virtual_packages, dist_packages) + TEST_SUITE("virtual_packages") { - auto pkgs = detail::dist_packages(); - auto& ctx = Context::instance(); - - if (on_win) - { - ASSERT_EQ(pkgs.size(), 2); - EXPECT_EQ(pkgs[0].name, "__win"); - } - if (on_linux) + TEST_CASE("make_virtual_package") { - ASSERT_EQ(pkgs.size(), 4); - EXPECT_EQ(pkgs[0].name, "__unix"); - EXPECT_EQ(pkgs[1].name, "__linux"); - EXPECT_EQ(pkgs[2].name, "__glibc"); + auto pkg = detail::make_virtual_package("test", "0.1.5", "abcd"); + + CHECK_EQ(pkg.name, "test"); + CHECK_EQ(pkg.version, "0.1.5"); + CHECK_EQ(pkg.build_string, "abcd"); + CHECK_EQ(pkg.build_number, 0); + CHECK_EQ(pkg.channel, "@"); + // CHECK_EQ(pkg.subdir, "osx-64"); // TODO: fix this + CHECK_EQ(pkg.md5, "12345678901234567890123456789012"); + CHECK_EQ(pkg.fn, pkg.name); } - if (on_mac) + + TEST_CASE("dist_packages") { - ASSERT_EQ(pkgs.size(), 3); - EXPECT_EQ(pkgs[0].name, "__unix"); - EXPECT_EQ(pkgs[1].name, "__osx"); - } + auto pkgs = detail::dist_packages(); + auto& ctx = Context::instance(); + + if (on_win) + { + REQUIRE_EQ(pkgs.size(), 2); + CHECK_EQ(pkgs[0].name, "__win"); + } + if (on_linux) + { + REQUIRE_EQ(pkgs.size(), 4); + CHECK_EQ(pkgs[0].name, "__unix"); + CHECK_EQ(pkgs[1].name, "__linux"); + CHECK_EQ(pkgs[2].name, "__glibc"); + } + if (on_mac) + { + REQUIRE_EQ(pkgs.size(), 3); + CHECK_EQ(pkgs[0].name, "__unix"); + CHECK_EQ(pkgs[1].name, "__osx"); + } #if __x86_64__ || defined(_WIN64) - EXPECT_EQ(pkgs.back().name, "__archspec"); - EXPECT_EQ(pkgs.back().build_string, "x86_64"); + CHECK_EQ(pkgs.back().name, "__archspec"); + CHECK_EQ(pkgs.back().build_string, "x86_64"); #endif - ctx.platform = "osx-arm"; - env::set("CONDA_OVERRIDE_OSX", "12.1"); - pkgs = detail::dist_packages(); - ASSERT_EQ(pkgs.size(), 3); - EXPECT_EQ(pkgs[0].name, "__unix"); - EXPECT_EQ(pkgs[1].name, "__osx"); - EXPECT_EQ(pkgs[1].version, "12.1"); - EXPECT_EQ(pkgs[2].name, "__archspec"); - EXPECT_EQ(pkgs[2].build_string, "arm"); - - env::unset("CONDA_OVERRIDE_OSX"); - ctx.platform = "linux-32"; - env::set("CONDA_OVERRIDE_LINUX", "5.7"); - env::set("CONDA_OVERRIDE_GLIBC", "2.15"); - pkgs = detail::dist_packages(); - ASSERT_EQ(pkgs.size(), 4); - EXPECT_EQ(pkgs[0].name, "__unix"); - EXPECT_EQ(pkgs[1].name, "__linux"); - EXPECT_EQ(pkgs[1].version, "5.7"); - EXPECT_EQ(pkgs[2].name, "__glibc"); - EXPECT_EQ(pkgs[2].version, "2.15"); - EXPECT_EQ(pkgs[3].name, "__archspec"); - EXPECT_EQ(pkgs[3].build_string, "x86"); - env::unset("CONDA_OVERRIDE_GLIBC"); - env::unset("CONDA_OVERRIDE_LINUX"); - - ctx.platform = "lin-850"; - pkgs = detail::dist_packages(); - ASSERT_EQ(pkgs.size(), 1); - EXPECT_EQ(pkgs[0].name, "__archspec"); - EXPECT_EQ(pkgs[0].build_string, "850"); - env::unset("CONDA_SUBDIR"); - - ctx.platform = "linux"; - pkgs = detail::dist_packages(); - ASSERT_EQ(pkgs.size(), 0); - - ctx.platform = ctx.host_platform; - } - - TEST(virtual_packages, get_virtual_packages) - { - env::set("CONDA_OVERRIDE_CUDA", "9.0"); - - auto pkgs = get_virtual_packages(); - int pkgs_count; - - if (on_win) - { - pkgs_count = 2; + ctx.platform = "osx-arm"; + env::set("CONDA_OVERRIDE_OSX", "12.1"); + pkgs = detail::dist_packages(); + REQUIRE_EQ(pkgs.size(), 3); + CHECK_EQ(pkgs[0].name, "__unix"); + CHECK_EQ(pkgs[1].name, "__osx"); + CHECK_EQ(pkgs[1].version, "12.1"); + CHECK_EQ(pkgs[2].name, "__archspec"); + CHECK_EQ(pkgs[2].build_string, "arm"); + + env::unset("CONDA_OVERRIDE_OSX"); + ctx.platform = "linux-32"; + env::set("CONDA_OVERRIDE_LINUX", "5.7"); + env::set("CONDA_OVERRIDE_GLIBC", "2.15"); + pkgs = detail::dist_packages(); + REQUIRE_EQ(pkgs.size(), 4); + CHECK_EQ(pkgs[0].name, "__unix"); + CHECK_EQ(pkgs[1].name, "__linux"); + CHECK_EQ(pkgs[1].version, "5.7"); + CHECK_EQ(pkgs[2].name, "__glibc"); + CHECK_EQ(pkgs[2].version, "2.15"); + CHECK_EQ(pkgs[3].name, "__archspec"); + CHECK_EQ(pkgs[3].build_string, "x86"); + env::unset("CONDA_OVERRIDE_GLIBC"); + env::unset("CONDA_OVERRIDE_LINUX"); + + ctx.platform = "lin-850"; + pkgs = detail::dist_packages(); + REQUIRE_EQ(pkgs.size(), 1); + CHECK_EQ(pkgs[0].name, "__archspec"); + CHECK_EQ(pkgs[0].build_string, "850"); + env::unset("CONDA_SUBDIR"); + + ctx.platform = "linux"; + pkgs = detail::dist_packages(); + REQUIRE_EQ(pkgs.size(), 0); + + ctx.platform = ctx.host_platform; } - if (on_linux) - { - pkgs_count = 4; - } - if (on_mac) - { - pkgs_count = 3; - } - - ++pkgs_count; - ASSERT_EQ(pkgs.size(), pkgs_count); - EXPECT_EQ(pkgs.back().name, "__cuda"); - EXPECT_EQ(pkgs.back().version, "9.0"); - - env::unset("CONDA_OVERRIDE_CUDA"); - pkgs = get_virtual_packages(); - if (!detail::cuda_version().empty()) - { - ASSERT_EQ(pkgs.size(), pkgs_count); - } - else + TEST_CASE("get_virtual_packages") { - ASSERT_EQ(pkgs.size(), pkgs_count - 1); + env::set("CONDA_OVERRIDE_CUDA", "9.0"); + + auto pkgs = get_virtual_packages(); + int pkgs_count; + + if (on_win) + { + pkgs_count = 2; + } + if (on_linux) + { + pkgs_count = 4; + } + if (on_mac) + { + pkgs_count = 3; + } + + ++pkgs_count; + REQUIRE_EQ(pkgs.size(), pkgs_count); + CHECK_EQ(pkgs.back().name, "__cuda"); + CHECK_EQ(pkgs.back().version, "9.0"); + + env::unset("CONDA_OVERRIDE_CUDA"); + pkgs = get_virtual_packages(); + + if (!detail::cuda_version().empty()) + { + REQUIRE_EQ(pkgs.size(), pkgs_count); + } + else + { + REQUIRE_EQ(pkgs.size(), pkgs_count - 1); + } } } } diff --git a/libmamba/tests/src/solv-cpp/test_queue.cpp b/libmamba/tests/src/solv-cpp/test_queue.cpp index 5387b4cc44..1f10316933 100644 --- a/libmamba/tests/src/solv-cpp/test_queue.cpp +++ b/libmamba/tests/src/solv-cpp/test_queue.cpp @@ -8,182 +8,185 @@ #include #include -#include - #include "solv-cpp/queue.hpp" -using namespace mamba::solv; +#include "doctest/doctest.h" -TEST(ObjQueue, constructor) -{ - auto q1 = ObjQueue(); - EXPECT_EQ(q1.size(), 0); - EXPECT_TRUE(q1.empty()); - - auto q2 = ObjQueue{ 1, 2, 3 }; - EXPECT_EQ(q2.size(), 3); - EXPECT_FALSE(q2.empty()); - - auto q3 = q2; - EXPECT_EQ(q3.size(), q2.size()); - EXPECT_NE(q2.data(), q3.data()); - - const auto q3_data = q3.data(); - const auto q3_size = q3.size(); - auto q4 = std::move(q3); - EXPECT_EQ(q4.size(), q3_size); - EXPECT_EQ(q4.data(), q3_data); - - const auto q4_data = q4.data(); - const auto q4_size = q4.size(); - q1 = std::move(q4); - EXPECT_EQ(q1.size(), q4_size); - EXPECT_EQ(q1.data(), q4_data); -} +using namespace mamba::solv; -TEST(ObjQueue, swap) +TEST_SUITE("ObjQueue") { - auto q1 = ObjQueue(); - const auto q1_data = q1.data(); - const auto q1_size = q1.size(); - - auto q2 = ObjQueue{ 1, 2, 3 }; - const auto q2_size = q2.size(); - const auto q2_data = q2.data(); - - swap(q1, q2); - EXPECT_EQ(q1.size(), q2_size); - EXPECT_EQ(q1.data(), q2_data); - EXPECT_EQ(q2.size(), q1_size); - EXPECT_EQ(q2.data(), q1_data); -} + TEST_CASE("constructor") + { + auto q1 = ObjQueue(); + CHECK_EQ(q1.size(), 0); + CHECK(q1.empty()); + + auto q2 = ObjQueue{ 1, 2, 3 }; + CHECK_EQ(q2.size(), 3); + CHECK_FALSE(q2.empty()); + + auto q3 = q2; + CHECK_EQ(q3.size(), q2.size()); + CHECK_NE(q2.data(), q3.data()); + + const auto q3_data = q3.data(); + const auto q3_size = q3.size(); + auto q4 = std::move(q3); + CHECK_EQ(q4.size(), q3_size); + CHECK_EQ(q4.data(), q3_data); + + const auto q4_data = q4.data(); + const auto q4_size = q4.size(); + q1 = std::move(q4); + CHECK_EQ(q1.size(), q4_size); + CHECK_EQ(q1.data(), q4_data); + } -TEST(ObjQueue, push_back) -{ - auto q = ObjQueue(); - q.push_back(1); - EXPECT_EQ(q.front(), 1); - EXPECT_EQ(q.back(), 1); - q.push_back(3); - EXPECT_EQ(q.front(), 1); - EXPECT_EQ(q.back(), 3); -} + TEST_CASE("swap") + { + auto q1 = ObjQueue(); + const auto q1_data = q1.data(); + const auto q1_size = q1.size(); + + auto q2 = ObjQueue{ 1, 2, 3 }; + const auto q2_size = q2.size(); + const auto q2_data = q2.data(); + + swap(q1, q2); + CHECK_EQ(q1.size(), q2_size); + CHECK_EQ(q1.data(), q2_data); + CHECK_EQ(q2.size(), q1_size); + CHECK_EQ(q2.data(), q1_data); + } -TEST(ObjQueue, element) -{ - auto q = ObjQueue{ 3, 2, 1 }; - EXPECT_EQ(q[0], 3); - EXPECT_EQ(q[1], 2); - EXPECT_EQ(q[2], 1); -} + TEST_CASE("push_back") + { + auto q = ObjQueue(); + q.push_back(1); + CHECK_EQ(q.front(), 1); + CHECK_EQ(q.back(), 1); + q.push_back(3); + CHECK_EQ(q.front(), 1); + CHECK_EQ(q.back(), 3); + } -TEST(ObjQueue, at) -{ - auto q = ObjQueue{ 3, 2, 1 }; - EXPECT_EQ(q.at(0), q[0]); - EXPECT_EQ(q.at(1), q[1]); - EXPECT_EQ(q.at(2), q[2]); - EXPECT_THROW(q.at(q.size()), std::out_of_range); -} + TEST_CASE("element") + { + auto q = ObjQueue{ 3, 2, 1 }; + CHECK_EQ(q[0], 3); + CHECK_EQ(q[1], 2); + CHECK_EQ(q[2], 1); + } -TEST(ObjQueue, clear) -{ - auto q = ObjQueue{ 3, 2, 1 }; - q.clear(); - EXPECT_TRUE(q.empty()); -} + TEST_CASE("at") + { + auto q = ObjQueue{ 3, 2, 1 }; + CHECK_EQ(q.at(0), q[0]); + CHECK_EQ(q.at(1), q[1]); + CHECK_EQ(q.at(2), q[2]); + CHECK_THROWS_AS(q.at(q.size()), std::out_of_range); + } -TEST(ObjQueue, iterator) -{ - const auto q = ObjQueue{ 3, 2, 1 }; - std::size_t n = 0; - for ([[maybe_unused]] auto _ : q) + TEST_CASE("clear") { - ++n; + auto q = ObjQueue{ 3, 2, 1 }; + q.clear(); + CHECK(q.empty()); } - EXPECT_EQ(n, q.size()); - const auto l = std::list<::Id>(q.begin(), q.end()); - const auto l_expected = std::list{ 3, 2, 1 }; - EXPECT_EQ(l, l_expected); -} + TEST_CASE("iterator") + { + const auto q = ObjQueue{ 3, 2, 1 }; + std::size_t n = 0; + for ([[maybe_unused]] auto _ : q) + { + ++n; + } + CHECK_EQ(n, q.size()); + + const auto l = std::list<::Id>(q.begin(), q.end()); + const auto l_expected = std::list{ 3, 2, 1 }; + CHECK_EQ(l, l_expected); + } -TEST(ObjQueue, reverse_iterator) -{ - const auto q = ObjQueue{ 3, 2, 1 }; + TEST_CASE("reverse_iterator") + { + const auto q = ObjQueue{ 3, 2, 1 }; - const auto v = std::vector(q.crbegin(), q.crend()); - EXPECT_EQ(v.front(), q.back()); - EXPECT_EQ(v.back(), q.front()); -} + const auto v = std::vector(q.crbegin(), q.crend()); + CHECK_EQ(v.front(), q.back()); + CHECK_EQ(v.back(), q.front()); + } -TEST(ObjQueue, insert_one) -{ - auto q = ObjQueue(); - auto iter = q.insert(q.cbegin(), 4); - EXPECT_EQ(*iter, 4); - EXPECT_EQ(q.front(), 4); -} + TEST_CASE("insert_one") + { + auto q = ObjQueue(); + auto iter = q.insert(q.cbegin(), 4); + CHECK_EQ(*iter, 4); + CHECK_EQ(q.front(), 4); + } -TEST(ObjQueue, insert_span) -{ - auto q = ObjQueue(); - - const auto r1 = std::vector{ 1, 2, 3 }; - // std::vector::iterator is not always a pointer - auto iter = q.insert(q.cend(), r1.data(), r1.data() + r1.size()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 1); - EXPECT_EQ(q[1], 2); - EXPECT_EQ(q[2], 3); - - const auto r2 = std::vector{ 4, 4 }; - iter = q.insert(q.cbegin(), r2.data(), r2.data() + r2.size()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 4); - EXPECT_EQ(q[1], 4); - - const auto r3 = std::vector{}; - iter = q.insert(q.cbegin(), r3.data(), r3.data() + r3.size()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 4); -} + TEST_CASE("insert_span") + { + auto q = ObjQueue(); + + const auto r1 = std::vector{ 1, 2, 3 }; + // std::vector::iterator is not always a pointer + auto iter = q.insert(q.cend(), r1.data(), r1.data() + r1.size()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 1); + CHECK_EQ(q[1], 2); + CHECK_EQ(q[2], 3); + + const auto r2 = std::vector{ 4, 4 }; + iter = q.insert(q.cbegin(), r2.data(), r2.data() + r2.size()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 4); + CHECK_EQ(q[1], 4); + + const auto r3 = std::vector{}; + iter = q.insert(q.cbegin(), r3.data(), r3.data() + r3.size()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 4); + } -TEST(ObjQueue, insert_range) -{ - auto q = ObjQueue(); - - const auto r1 = std::list{ 1, 2, 3 }; - auto iter = q.insert(q.cend(), r1.begin(), r1.end()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 1); - EXPECT_EQ(q[1], 2); - EXPECT_EQ(q[2], 3); - - const auto r2 = std::list{ 4, 4 }; - iter = q.insert(q.cbegin(), r2.begin(), r2.end()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 4); - EXPECT_EQ(q[1], 4); - - const auto r3 = std::list{}; - iter = q.insert(q.cbegin(), r3.begin(), r3.end()); - EXPECT_EQ(*iter, q[0]); - EXPECT_EQ(q[0], 4); -} + TEST_CASE("insert_range") + { + auto q = ObjQueue(); + + const auto r1 = std::list{ 1, 2, 3 }; + auto iter = q.insert(q.cend(), r1.begin(), r1.end()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 1); + CHECK_EQ(q[1], 2); + CHECK_EQ(q[2], 3); + + const auto r2 = std::list{ 4, 4 }; + iter = q.insert(q.cbegin(), r2.begin(), r2.end()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 4); + CHECK_EQ(q[1], 4); + + const auto r3 = std::list{}; + iter = q.insert(q.cbegin(), r3.begin(), r3.end()); + CHECK_EQ(*iter, q[0]); + CHECK_EQ(q[0], 4); + } -TEST(ObjQueue, erase) -{ - auto q = ObjQueue{ 3, 2, 1 }; - const auto iter = q.erase(q.cbegin() + 1); - EXPECT_EQ(*iter, 1); - EXPECT_EQ(q.size(), 2); -} + TEST_CASE("erase") + { + auto q = ObjQueue{ 3, 2, 1 }; + const auto iter = q.erase(q.cbegin() + 1); + CHECK_EQ(*iter, 1); + CHECK_EQ(q.size(), 2); + } -TEST(ObjQueue, capacity) -{ - auto q = ObjQueue(); - q.reserve(10); - EXPECT_EQ(q.size(), 0); - EXPECT_GE(q.capacity(), 10); + TEST_CASE("capacity") + { + auto q = ObjQueue(); + q.reserve(10); + CHECK_EQ(q.size(), 0); + CHECK_GE(q.capacity(), 10); + } } diff --git a/libmamba/tests/src/specs/test_repo_data.cpp b/libmamba/tests/src/specs/test_repo_data.cpp index 50041d5582..06c4da3d34 100644 --- a/libmamba/tests/src/specs/test_repo_data.cpp +++ b/libmamba/tests/src/specs/test_repo_data.cpp @@ -6,149 +6,153 @@ #include -#include #include #include "mamba/specs/repo_data.hpp" +#include "doctest/doctest.h" + using namespace mamba::specs; namespace nl = nlohmann; -TEST(repo_data, RepoDataPackage_to_json) -{ - auto p = RepoDataPackage(); - p.name = "mamba"; - p.version = Version::parse("1.0.0"); - p.build_string = "bld"; - p.build_number = 3; - p.subdir = "folder"; - p.md5 = "ffsd"; - p.noarch = NoArchType::Python; - - nl::json const j = p; - EXPECT_EQ(j.at("name"), p.name); - EXPECT_EQ(j.at("version"), p.version.str()); - EXPECT_EQ(j.at("build"), p.build_string); - EXPECT_EQ(j.at("build_number"), p.build_number); - EXPECT_EQ(j.at("subdir"), p.subdir); - EXPECT_EQ(j.at("md5"), p.md5); - EXPECT_TRUE(j.at("sha256").is_null()); - EXPECT_EQ(j.at("noarch"), "python"); -} - -TEST(repo_data, RepoDataPackage_from_json) +TEST_SUITE("repo_data") { - auto j = nl::json::object(); - j["name"] = "mamba"; - j["version"] = "1.1.0"; - j["build"] = "foo1"; - j["build_number"] = 2; - j["subdir"] = "folder"; - j["platform"] = nullptr; - j["depends"] = nl::json::array({ "libsolv>=1.0" }); - j["constrains"] = nl::json::array(); - j["track_features"] = nl::json::array(); + TEST_CASE("RepoDataPackage_to_json") { - const auto p = j.get(); - EXPECT_EQ(p.name, j.at("name")); - // Note Version::parse is not injective - EXPECT_EQ(p.version.str(), j.at("version")); - EXPECT_EQ(p.build_string, j.at("build")); - EXPECT_EQ(p.build_number, j.at("build_number")); - EXPECT_EQ(p.subdir, j.at("subdir")); - EXPECT_FALSE(p.md5.has_value()); - EXPECT_FALSE(p.platform.has_value()); - EXPECT_EQ(p.depends, decltype(p.depends){ "libsolv>=1.0" }); - EXPECT_TRUE(p.constrains.empty()); - EXPECT_TRUE(p.track_features.empty()); - EXPECT_FALSE(p.noarch.has_value()); - } - j["noarch"] = "python"; - { - const auto p = j.get(); - EXPECT_EQ(p.noarch, NoArchType::Python); - } - // Old beahiour - j["noarch"] = true; - { - const auto p = j.get(); - EXPECT_EQ(p.noarch, NoArchType::Generic); + auto p = RepoDataPackage(); + p.name = "mamba"; + p.version = Version::parse("1.0.0"); + p.build_string = "bld"; + p.build_number = 3; + p.subdir = "folder"; + p.md5 = "ffsd"; + p.noarch = NoArchType::Python; + + nl::json const j = p; + CHECK_EQ(j.at("name"), p.name); + CHECK_EQ(j.at("version"), p.version.str()); + CHECK_EQ(j.at("build"), p.build_string); + CHECK_EQ(j.at("build_number"), p.build_number); + CHECK_EQ(j.at("subdir"), p.subdir); + CHECK_EQ(j.at("md5"), p.md5); + CHECK(j.at("sha256").is_null()); + CHECK_EQ(j.at("noarch"), "python"); } - j["noarch"] = false; + + TEST_CASE("RepoDataPackage_from_json") { - const auto p = j.get(); - EXPECT_FALSE(p.noarch.has_value()); + auto j = nl::json::object(); + j["name"] = "mamba"; + j["version"] = "1.1.0"; + j["build"] = "foo1"; + j["build_number"] = 2; + j["subdir"] = "folder"; + j["platform"] = nullptr; + j["depends"] = nl::json::array({ "libsolv>=1.0" }); + j["constrains"] = nl::json::array(); + j["track_features"] = nl::json::array(); + { + const auto p = j.get(); + CHECK_EQ(p.name, j.at("name")); + // Note Version::parse is not injective + CHECK_EQ(p.version.str(), j.at("version")); + CHECK_EQ(p.build_string, j.at("build")); + CHECK_EQ(p.build_number, j.at("build_number")); + CHECK_EQ(p.subdir, j.at("subdir")); + CHECK_FALSE(p.md5.has_value()); + CHECK_FALSE(p.platform.has_value()); + CHECK_EQ(p.depends, decltype(p.depends){ "libsolv>=1.0" }); + CHECK(p.constrains.empty()); + CHECK(p.track_features.empty()); + CHECK_FALSE(p.noarch.has_value()); + } + j["noarch"] = "python"; + { + const auto p = j.get(); + CHECK_EQ(p.noarch, NoArchType::Python); + } + // Old beahiour + j["noarch"] = true; + { + const auto p = j.get(); + CHECK_EQ(p.noarch, NoArchType::Generic); + } + j["noarch"] = false; + { + const auto p = j.get(); + CHECK_FALSE(p.noarch.has_value()); + } } -} -TEST(repo_data, RepoData_to_json) -{ - auto data = RepoData(); - data.version = 1; - data.info = ChannelInfo{ /* .subdir= */ "linux-64" }; - data.packages = { - { "mamba-1.0-h12345.tar.bz2", RepoDataPackage{ "mamba" } }, - { "conda-1.0-h54321.tar.bz2", RepoDataPackage{ "conda" } }, - }; - data.removed = { "bad-package-1" }; + TEST_CASE("RepoData_to_json") + { + auto data = RepoData(); + data.version = 1; + data.info = ChannelInfo{ /* .subdir= */ "linux-64" }; + data.packages = { + { "mamba-1.0-h12345.tar.bz2", RepoDataPackage{ "mamba" } }, + { "conda-1.0-h54321.tar.bz2", RepoDataPackage{ "conda" } }, + }; + data.removed = { "bad-package-1" }; - const nl::json j = data; - EXPECT_EQ(j.at("version"), data.version); - EXPECT_EQ(j.at("info").at("subdir"), data.info.value().subdir); - EXPECT_EQ( - j.at("packages").at("mamba-1.0-h12345.tar.bz2"), - data.packages.at("mamba-1.0-h12345.tar.bz2") - ); - EXPECT_EQ( - j.at("packages").at("conda-1.0-h54321.tar.bz2"), - data.packages.at("conda-1.0-h54321.tar.bz2") - ); - EXPECT_EQ(j.at("removed"), std::vector{ "bad-package-1" }); -} + const nl::json j = data; + CHECK_EQ(j.at("version"), data.version); + CHECK_EQ(j.at("info").at("subdir"), data.info.value().subdir); + CHECK_EQ( + j.at("packages").at("mamba-1.0-h12345.tar.bz2"), + data.packages.at("mamba-1.0-h12345.tar.bz2") + ); + CHECK_EQ( + j.at("packages").at("conda-1.0-h54321.tar.bz2"), + data.packages.at("conda-1.0-h54321.tar.bz2") + ); + CHECK_EQ(j.at("removed"), std::vector{ "bad-package-1" }); + } -TEST(repo_data, RepoData_from_json) -{ - auto j = nl::json::object(); - j["version"] = 1; - j["info"]["subdir"] = "somedir"; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["name"] = "mamba"; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["version"] = "1.1.0"; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["build"] = "foo1"; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["build_number"] = 2; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["subdir"] = "folder"; - j["packages"]["mamba-1.0-h12345.tar.bz2"]["depends"] = nl::json::array({ "libsolv>=1.0" }); - j["packages"]["mamba-1.0-h12345.tar.bz2"]["constrains"] = nl::json::array(); - j["packages"]["mamba-1.0-h12345.tar.bz2"]["track_features"] = nl::json::array(); - j["conda_packages"] = nl::json::object(); - j["removed"][0] = "bad-package.tar.gz"; + TEST_CASE("RepoData_from_json") + { + auto j = nl::json::object(); + j["version"] = 1; + j["info"]["subdir"] = "somedir"; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["name"] = "mamba"; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["version"] = "1.1.0"; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["build"] = "foo1"; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["build_number"] = 2; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["subdir"] = "folder"; + j["packages"]["mamba-1.0-h12345.tar.bz2"]["depends"] = nl::json::array({ "libsolv>=1.0" }); + j["packages"]["mamba-1.0-h12345.tar.bz2"]["constrains"] = nl::json::array(); + j["packages"]["mamba-1.0-h12345.tar.bz2"]["track_features"] = nl::json::array(); + j["conda_packages"] = nl::json::object(); + j["removed"][0] = "bad-package.tar.gz"; - const auto data = j.get(); - ASSERT_TRUE(data.version.has_value()); - EXPECT_EQ(data.version, j["version"]); - ASSERT_TRUE(data.info.has_value()); - EXPECT_EQ(data.info.value().subdir, j["info"]["subdir"]); - EXPECT_EQ( - data.packages.at("mamba-1.0-h12345.tar.bz2").name, - j["packages"]["mamba-1.0-h12345.tar.bz2"]["name"] - ); - EXPECT_TRUE(data.conda_packages.empty()); - EXPECT_EQ(data.removed, j["removed"]); -} + const auto data = j.get(); + REQUIRE(data.version.has_value()); + CHECK_EQ(data.version, j["version"]); + REQUIRE(data.info.has_value()); + CHECK_EQ(data.info.value().subdir, j["info"]["subdir"]); + CHECK_EQ( + data.packages.at("mamba-1.0-h12345.tar.bz2").name, + j["packages"]["mamba-1.0-h12345.tar.bz2"]["name"] + ); + CHECK(data.conda_packages.empty()); + CHECK_EQ(data.removed, j["removed"]); + } -TEST(repo_data, repodata_json) -{ - // Maybe not the best way to set this test. - // ``repodata.json`` of interest are very large files. Should we check them in in VCS? - // Download them in CMake? Do a specific integration test? - // Could be downloaded in the tests, but we would like to keep these tests Context-free. - const char* repodata_file_path = std::getenv("MAMBA_REPODATA_JSON"); - if (repodata_file_path == nullptr) + TEST_CASE("repodata_json") { - GTEST_SKIP(); + // Maybe not the best way to set this test. + // ``repodata.json`` of interest are very large files. Should we check them in in VCS? + // Download them in CMake? Do a specific integration test? + // Could be downloaded in the tests, but we would like to keep these tests Context-free. + const char* repodata_file_path = std::getenv("MAMBA_REPODATA_JSON"); + if (repodata_file_path == nullptr) + { + return; + } + auto repodata_file = std::ifstream(repodata_file_path); + // Deserialize + auto data = nl::json::parse(repodata_file).get(); + // Serialize + const nl::json json = std::move(data); } - auto repodata_file = std::ifstream(repodata_file_path); - // Deserialize - auto data = nl::json::parse(repodata_file).get(); - // Serialize - const nl::json json = std::move(data); } diff --git a/libmamba/tests/src/specs/test_version.cpp b/libmamba/tests/src/specs/test_version.cpp index 6e199fb145..8108a573d7 100644 --- a/libmamba/tests/src/specs/test_version.cpp +++ b/libmamba/tests/src/specs/test_version.cpp @@ -8,347 +8,353 @@ #include #include -#include - #include "mamba/specs/version.hpp" +#include "doctest/doctest.h" + namespace mamba::specs { - TEST(version, atom_comparison) + TEST_SUITE("version") { - // No literal - EXPECT_EQ(VersionPartAtom(1), VersionPartAtom(1, "")); - // lowercase - EXPECT_EQ(VersionPartAtom(1, "dev"), VersionPartAtom(1, "DEV")); - // All operator comparison for mumerals - EXPECT_NE(VersionPartAtom(1), VersionPartAtom(2, "dev")); - EXPECT_LT(VersionPartAtom(1), VersionPartAtom(2, "dev")); - EXPECT_LE(VersionPartAtom(1), VersionPartAtom(2, "dev")); - EXPECT_GT(VersionPartAtom(2, "dev"), VersionPartAtom(1)); - EXPECT_GE(VersionPartAtom(2, "dev"), VersionPartAtom(1)); - // All operator comparison for literals - EXPECT_NE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - EXPECT_LT(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - EXPECT_LE(VersionPartAtom(1, "dev"), VersionPartAtom(1, "a")); - EXPECT_GT(VersionPartAtom(1, "a"), VersionPartAtom(1, "dev")); - EXPECT_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" }, - }; - // clang-format on + 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")); - // Strict ordering - EXPECT_TRUE(std::is_sorted(sorted_atoms.cbegin(), sorted_atoms.cend())); - // None compare equal (given the is_sorted assumption) - EXPECT_EQ(std::adjacent_find(sorted_atoms.cbegin(), sorted_atoms.cend()), sorted_atoms.cend()); - } + // 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" }, + }; + // clang-format on - TEST(version, atom_format) - { - EXPECT_EQ(VersionPartAtom(1, "dev").str(), "1dev"); - EXPECT_EQ(VersionPartAtom(2).str(), "2"); - } + // 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(version, version_comparison) - { - auto v = Version(0, { { { 1, "post" } } }); - ASSERT_EQ(v.version().size(), 1); - ASSERT_EQ(v.version().front().size(), 1); - ASSERT_EQ(v.version().front().front(), VersionPartAtom(1, "post")); + TEST_CASE("atom_format") + { + CHECK_EQ(VersionPartAtom(1, "dev").str(), "1dev"); + CHECK_EQ(VersionPartAtom(2).str(), "2"); + } - // Same empty 0!1post version - EXPECT_EQ(Version(0, { { { 1, "post" } } }), Version(0, { { { 1, "post" } } })); - // Empty trailing atom 0!1a == 0!1a0"" - EXPECT_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" }, {} } })); - // Empty trailing part 0!1a == 0!1a.0"" - EXPECT_EQ(Version(0, { { { 1, "a" } } }), Version(0, { { { 1, "a" } }, { {} } })); - // Mixed 0!1a0""0"" == 0!1a.0"" - EXPECT_EQ(Version(0, { { { 1, "a" }, {}, {} } }), Version(0, { { { 1, "a" } }, { {} } })); + 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")); - // Different epoch 0!2post < 1!1dev - EXPECT_LT(Version(0, { { { 2, "post" } } }), Version(1, { { { 1, "dev" } } })); - EXPECT_GE(Version(1, { { { 1, "dev" } } }), Version(0, { { { 2, "post" } } })); - // Different lenght with dev - EXPECT_LT(Version(0, { { { 1 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); - EXPECT_LT(Version(0, { { { 1 } }, { { 0 } }, { { 0, "dev" } } }), Version(0, { { { 1 } } })); - // Different major 0!1post < 0!2dev - EXPECT_LT(Version(0, { { { 1, "post" } } }), Version(0, { { { 2, "dev" } } })); - // Different length 0!2"".0"" < 0!11"".0"".0post all operator - EXPECT_NE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - EXPECT_LT(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - EXPECT_LE(Version(0, { { { 2 }, { 0 } } }), Version(0, { { { 11 }, { 0 }, { 0, "post" } } })); - EXPECT_GT(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); - EXPECT_GE(Version(0, { { { 11 }, { 0 }, { 0, "post" } } }), Version(0, { { { 2 }, { 0 } } })); - } + // 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" } }, { {} } })); - TEST(version, version_format) - { - // clang-format off - EXPECT_EQ( - Version(0, {{{11, "a"}, {0, "post"}}, {{3}}, {{4, "dev"}}}).str(), - "11a0post.3.4dev" - ); - EXPECT_EQ( - Version(1, {{{11, "a"}, {0}}, {{3}}, {{4, "dev"}}}).str(), - "1!11a0.3.4dev" - ); - EXPECT_EQ( - Version(1, {{{11, "a"}, {0}}, {{3}}, {{4, "dev"}}}, {{{1}}, {{2}}}).str(), - "1!11a0.3.4dev+1.2" - ); - // clang-format on - } + // 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 from Conda - * - * @see https://github.com/conda/conda/blob/main/tests/models/test_version.py - */ - TEST(version, parse) - { - // clang-format off - auto sorted_version = std::vector>{ - {"0.4", Version(0, {{{0}}, {{4}}})}, - {"0.4.0", Version(0, {{{0}}, {{4}}, {{0}}})}, - {"0.4.1a.vc11", Version(0, {{{0}}, {{4}}, {{1, "a"}}, {{0, "vc"}, {11}}})}, - {"0.4.1.rc", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "rc"}}})}, - {"0.4.1.vc11", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "vc"}, {11}}})}, - {"0.4.1", Version(0, {{{0}}, {{4}}, {{1}}})}, - {"0.5*", Version(0, {{{0}}, {{5, "*"}}})}, - {"0.5a1", Version(0, {{{0}}, {{5, "a"}, {1}}})}, - {"0.5b3", Version(0, {{{0}}, {{5, "b"}, {3}}})}, - {"0.5C1", Version(0, {{{0}}, {{5, "c"}, {1}}})}, - {"0.5z", Version(0, {{{0}}, {{5, "z"}}})}, - {"0.5za", Version(0, {{{0}}, {{5, "za"}}})}, - {"0.5", Version(0, {{{0}}, {{5}}})}, - {"0.5_5", Version(0, {{{0}}, {{5}}, {{5}}})}, - {"0.5-5", Version(0, {{{0}}, {{5}}, {{5}}})}, - {"0.9.6", Version(0, {{{0}}, {{9}}, {{6}}})}, - {"0.960923", Version(0, {{{0}}, {{960923}}})}, - {"1.0", Version(0, {{{1}}, {{0}}})}, - {"1.0.4a3", Version(0, {{{1}}, {{0}}, {{4, "a"}, {3}}})}, - {"1.0.4b1", Version(0, {{{1}}, {{0}}, {{4, "b"}, {1}}})}, - {"1.0.4", Version(0, {{{1}}, {{0}}, {{4}}})}, - {"1.1dev1", Version(0, {{{1}}, {{1, "dev"}, {1}}})}, - {"1.1_", Version(0, {{{1}}, {{1, "_"}}})}, - {"1.1a1", Version(0, {{{1}}, {{1, "a"}, {1}}})}, - {"1.1.dev1", Version(0, {{{1}}, {{1}}, {{0, "dev"}, {1}}})}, - {"1.1.a1", Version(0, {{{1}}, {{1}}, {{0, "a"}, {1}}})}, - {"1.1", Version(0, {{{1}}, {{1}}})}, - {"1.1.post1", Version(0, {{{1}}, {{1}}, {{0, "post"}, {1}}})}, - {"1.1.1dev1", Version(0, {{{1}}, {{1}}, {{1, "dev"}, {1}}})}, - {"1.1.1rc1", Version(0, {{{1}}, {{1}}, {{1, "rc"}, {1}}})}, - {"1.1.1", Version(0, {{{1}}, {{1}}, {{1}}})}, - {"1.1.1post1", Version(0, {{{1}}, {{1}}, {{1, "post"}, {1}}})}, - {"1.1post1", Version(0, {{{1}}, {{1, "post"}, {1}}})}, - {"2g6", Version(0, {{{2, "g"}, {6}}})}, - {"2.0b1pr0", Version(0, {{{2}}, {{0, "b"}, {1, "pr"}, {0}}})}, - {"2.2be.ta29", Version(0, {{{2}}, {{2, "be"}}, {{0, "ta"}, {29}}})}, - {"2.2be5ta29", Version(0, {{{2}}, {{2, "be"}, {5, "ta"}, {29}}})}, - {"2.2beta29", Version(0, {{{2}}, {{2, "beta"}, {29}}})}, - {"2.2.0.1", Version(0, {{{2}}, {{2}}, {{0}}, {{1}}})}, - {"3.1.1.6", Version(0, {{{3}}, {{1}}, {{1}}, {{6}}})}, - {"3.2.p.r0", Version(0, {{{3}}, {{2}}, {{0, "p"}}, {{0, "r"}, {0}}})}, - {"3.2.pr0", Version(0, {{{3}}, {{2}}, {{0, "pr"}, {0}}})}, - {"3.2.pr.1", Version(0, {{{3}}, {{2}}, {{0, "pr"}}, {{1}}})}, - {"5.5.kw", Version(0, {{{5}}, {{5}}, {{0, "kw"}}})}, - {"11g", Version(0, {{{11, "g"}}})}, - {"14.3.1", Version(0, {{{14}}, {{3}}, {{1}}})}, - { - "14.3.1.post26.g9d75ca2", - Version( 0, {{{14}}, {{3}}, {{1}}, {{0, "post"}, {26}}, {{0, "g"}, {9, "d"}, {75, "ca"}, {2}}}) - }, - {"1996.07.12", Version(0, {{{1996}}, {{7}}, {{12}}})}, - {"1!0.4.1", Version(1, {{{0}}, {{4}}, {{1}}})}, - {"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) + TEST_CASE("version_format") { - EXPECT_EQ(Version::parse(raw), expected); + // clang-format off + CHECK_EQ( + Version(0, {{{11, "a"}, {0, "post"}}, {{3}}, {{4, "dev"}}}).str(), + "11a0post.3.4dev" + ); + CHECK_EQ( + Version(1, {{{11, "a"}, {0}}, {{3}}, {{4, "dev"}}}).str(), + "1!11a0.3.4dev" + ); + CHECK_EQ( + Version(1, {{{11, "a"}, {0}}, {{3}}, {{4, "dev"}}}, {{{1}}, {{2}}}).str(), + "1!11a0.3.4dev+1.2" + ); + // clang-format on } - EXPECT_TRUE(std::is_sorted( - sorted_version.cbegin(), - sorted_version.cend(), - [](const auto& a, const auto& b) { return a.second < b.second; } - )); + /** + * 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}}})}, + {"0.4.1a.vc11", Version(0, {{{0}}, {{4}}, {{1, "a"}}, {{0, "vc"}, {11}}})}, + {"0.4.1.rc", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "rc"}}})}, + {"0.4.1.vc11", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "vc"}, {11}}})}, + {"0.4.1", Version(0, {{{0}}, {{4}}, {{1}}})}, + {"0.5*", Version(0, {{{0}}, {{5, "*"}}})}, + {"0.5a1", Version(0, {{{0}}, {{5, "a"}, {1}}})}, + {"0.5b3", Version(0, {{{0}}, {{5, "b"}, {3}}})}, + {"0.5C1", Version(0, {{{0}}, {{5, "c"}, {1}}})}, + {"0.5z", Version(0, {{{0}}, {{5, "z"}}})}, + {"0.5za", Version(0, {{{0}}, {{5, "za"}}})}, + {"0.5", Version(0, {{{0}}, {{5}}})}, + {"0.5_5", Version(0, {{{0}}, {{5}}, {{5}}})}, + {"0.5-5", Version(0, {{{0}}, {{5}}, {{5}}})}, + {"0.9.6", Version(0, {{{0}}, {{9}}, {{6}}})}, + {"0.960923", Version(0, {{{0}}, {{960923}}})}, + {"1.0", Version(0, {{{1}}, {{0}}})}, + {"1.0.4a3", Version(0, {{{1}}, {{0}}, {{4, "a"}, {3}}})}, + {"1.0.4b1", Version(0, {{{1}}, {{0}}, {{4, "b"}, {1}}})}, + {"1.0.4", Version(0, {{{1}}, {{0}}, {{4}}})}, + {"1.1dev1", Version(0, {{{1}}, {{1, "dev"}, {1}}})}, + {"1.1_", Version(0, {{{1}}, {{1, "_"}}})}, + {"1.1a1", Version(0, {{{1}}, {{1, "a"}, {1}}})}, + {"1.1.dev1", Version(0, {{{1}}, {{1}}, {{0, "dev"}, {1}}})}, + {"1.1.a1", Version(0, {{{1}}, {{1}}, {{0, "a"}, {1}}})}, + {"1.1", Version(0, {{{1}}, {{1}}})}, + {"1.1.post1", Version(0, {{{1}}, {{1}}, {{0, "post"}, {1}}})}, + {"1.1.1dev1", Version(0, {{{1}}, {{1}}, {{1, "dev"}, {1}}})}, + {"1.1.1rc1", Version(0, {{{1}}, {{1}}, {{1, "rc"}, {1}}})}, + {"1.1.1", Version(0, {{{1}}, {{1}}, {{1}}})}, + {"1.1.1post1", Version(0, {{{1}}, {{1}}, {{1, "post"}, {1}}})}, + {"1.1post1", Version(0, {{{1}}, {{1, "post"}, {1}}})}, + {"2g6", Version(0, {{{2, "g"}, {6}}})}, + {"2.0b1pr0", Version(0, {{{2}}, {{0, "b"}, {1, "pr"}, {0}}})}, + {"2.2be.ta29", Version(0, {{{2}}, {{2, "be"}}, {{0, "ta"}, {29}}})}, + {"2.2be5ta29", Version(0, {{{2}}, {{2, "be"}, {5, "ta"}, {29}}})}, + {"2.2beta29", Version(0, {{{2}}, {{2, "beta"}, {29}}})}, + {"2.2.0.1", Version(0, {{{2}}, {{2}}, {{0}}, {{1}}})}, + {"3.1.1.6", Version(0, {{{3}}, {{1}}, {{1}}, {{6}}})}, + {"3.2.p.r0", Version(0, {{{3}}, {{2}}, {{0, "p"}}, {{0, "r"}, {0}}})}, + {"3.2.pr0", Version(0, {{{3}}, {{2}}, {{0, "pr"}, {0}}})}, + {"3.2.pr.1", Version(0, {{{3}}, {{2}}, {{0, "pr"}}, {{1}}})}, + {"5.5.kw", Version(0, {{{5}}, {{5}}, {{0, "kw"}}})}, + {"11g", Version(0, {{{11, "g"}}})}, + {"14.3.1", Version(0, {{{14}}, {{3}}, {{1}}})}, + { + "14.3.1.post26.g9d75ca2", + Version( 0, {{{14}}, {{3}}, {{1}}, {{0, "post"}, {26}}, {{0, "g"}, {9, "d"}, {75, "ca"}, {2}}}) + }, + {"1996.07.12", Version(0, {{{1996}}, {{7}}, {{12}}})}, + {"1!0.4.1", Version(1, {{{0}}, {{4}}, {{1}}})}, + {"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); + } - // Lowercase and strip - EXPECT_EQ(Version::parse("0.4.1.rc"), Version::parse(" 0.4.1.RC ")); - EXPECT_EQ(Version::parse(" 0.4.1.RC "), Version::parse("0.4.1.rc")); + CHECK(std::is_sorted( + sorted_version.cbegin(), + sorted_version.cend(), + [](const auto& a, const auto& b) { return a.second < b.second; } + )); - // Functional assertions - EXPECT_EQ(Version::parse(" 0.4.rc "), Version::parse("0.4.RC")); - EXPECT_EQ(Version::parse("0.4"), Version::parse("0.4.0")); - EXPECT_NE(Version::parse("0.4"), Version::parse("0.4.1")); - EXPECT_EQ(Version::parse("0.4.a1"), Version::parse("0.4.0a1")); - EXPECT_NE(Version::parse("0.4.a1"), Version::parse("0.4.1a1")); - } + // 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")); - TEST(version, parse_invalid) - { - // Wrong epoch - EXPECT_THROW(Version::parse("!1.1"), std::invalid_argument); - EXPECT_THROW(Version::parse("-1!1.1"), std::invalid_argument); - EXPECT_THROW(Version::parse("foo!1.1"), std::invalid_argument); - EXPECT_THROW(Version::parse("0post1!1.1"), std::invalid_argument); + // 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")); + } - // Empty parts - EXPECT_THROW(Version::parse(""), std::invalid_argument); - EXPECT_THROW(Version::parse(" "), std::invalid_argument); - EXPECT_THROW(Version::parse("!2.2"), std::invalid_argument); - EXPECT_THROW(Version::parse("0!"), std::invalid_argument); - EXPECT_THROW(Version::parse("!"), std::invalid_argument); - EXPECT_THROW(Version::parse("1."), std::invalid_argument); - EXPECT_THROW(Version::parse("1..1"), std::invalid_argument); - EXPECT_THROW(Version::parse("5.5..mw"), std::invalid_argument); - EXPECT_THROW(Version::parse("1.2post+"), std::invalid_argument); - EXPECT_THROW(Version::parse("1!+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); - // Repeated delimiters - EXPECT_THROW(Version::parse("5.5++"), std::invalid_argument); - EXPECT_THROW(Version::parse("5.5+1+0.0"), std::invalid_argument); - EXPECT_THROW(Version::parse("1!2!3.0"), 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); - // '-' and '_' delimiters not allowed together. - EXPECT_THROW(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); - // Forbidden characters - EXPECT_THROW(Version::parse("3.5&1"), std::invalid_argument); - EXPECT_THROW(Version::parse("3.5|1"), std::invalid_argument); - } + // '-' and '_' delimiters not allowed together. + CHECK_THROWS_AS(Version::parse("1-1_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(version, parse_openssl) - { - // clang-format off - auto versions = std::vector{ - Version::parse("1.0.1dev"), - Version::parse("1.0.1_"), // <- this - Version::parse("1.0.1a"), - Version::parse("1.0.1b"), - Version::parse("1.0.1c"), - Version::parse("1.0.1d"), - Version::parse("1.0.1r"), - Version::parse("1.0.1rc"), - Version::parse("1.0.1rc1"), - Version::parse("1.0.1rc2"), - Version::parse("1.0.1s"), - Version::parse("1.0.1"), // <- compared to this - Version::parse("1.0.1post.a"), - Version::parse("1.0.1post.b"), - Version::parse("1.0.1post.z"), - Version::parse("1.0.1post.za"), - Version::parse("1.0.2"), - }; - // clang-format on + // Forbidden characters + CHECK_THROWS_AS(Version::parse("3.5&1"), std::invalid_argument); + CHECK_THROWS_AS(Version::parse("3.5|1"), std::invalid_argument); + } - // Strict ordering - EXPECT_TRUE(std::is_sorted(versions.cbegin(), versions.cend())); - // None compare equal (given the is_sorted assumption) - EXPECT_EQ(std::adjacent_find(versions.cbegin(), versions.cend()), versions.cend()); - } + /** + * 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 + Version::parse("1.0.1a"), + Version::parse("1.0.1b"), + Version::parse("1.0.1c"), + Version::parse("1.0.1d"), + Version::parse("1.0.1r"), + Version::parse("1.0.1rc"), + Version::parse("1.0.1rc1"), + Version::parse("1.0.1rc2"), + Version::parse("1.0.1s"), + Version::parse("1.0.1"), // <- compared to this + Version::parse("1.0.1post.a"), + Version::parse("1.0.1post.b"), + Version::parse("1.0.1post.z"), + Version::parse("1.0.1post.za"), + Version::parse("1.0.2"), + }; + // 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(version, 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()); + } + + /** + * 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 - EXPECT_TRUE(std::is_sorted(versions.cbegin(), versions.cend())); - // None compare equal (given the is_sorted assumption) - EXPECT_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()); + } } } diff --git a/libmamba/tests/src/test_main.cpp b/libmamba/tests/src/test_main.cpp new file mode 100644 index 0000000000..9522fa7fdb --- /dev/null +++ b/libmamba/tests/src/test_main.cpp @@ -0,0 +1,2 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest/doctest.h" diff --git a/libmamba/tests/src/util/test_cast.cpp b/libmamba/tests/src/util/test_cast.cpp index 950bb63ec1..93bd18a291 100644 --- a/libmamba/tests/src/util/test_cast.cpp +++ b/libmamba/tests/src/util/test_cast.cpp @@ -8,19 +8,13 @@ #include #include -#include - #include "mamba/util/cast.hpp" +#include "doctest/doctest.h" + using namespace mamba::util; -template -struct cast_valid : ::testing::Test -{ - using First = typename T::first_type; - using Second = typename T::second_type; -}; -using WidenTypes = ::testing::Types< +using WidenTypes = std::tuple< // integers std::pair, std::pair, @@ -35,36 +29,8 @@ using WidenTypes = ::testing::Types< std::pair, std::pair, std::pair>; -TYPED_TEST_SUITE(cast_valid, WidenTypes); - -TYPED_TEST(cast_valid, checked_exact_num_cast_widen) -{ - using From = typename TestFixture::First; - using To = typename TestFixture::Second; - static constexpr auto from_lowest = std::numeric_limits::lowest(); - static constexpr auto from_max = std::numeric_limits::max(); - - EXPECT_EQ(safe_num_cast(From(0)), To(0)); - EXPECT_EQ(safe_num_cast(From(1)), To(1)); - EXPECT_EQ(safe_num_cast(from_lowest), static_cast(from_lowest)); - EXPECT_EQ(safe_num_cast(from_max), static_cast(from_max)); -} - -TYPED_TEST(cast_valid, checked_exact_num_cast_narrow) -{ - using From = typename TestFixture::Second; // inversed - using To = typename TestFixture::First; // inversed - EXPECT_EQ(safe_num_cast(From(0)), To(0)); - EXPECT_EQ(safe_num_cast(From(1)), To(1)); -} -template -struct cast_overflow_lowest : ::testing::Test -{ - using First = typename T::first_type; - using Second = typename T::second_type; -}; -using OverflowLowestTypes = ::testing::Types< +using OverflowLowestTypes = std::tuple< // integers std::pair, std::pair, @@ -75,19 +41,45 @@ using OverflowLowestTypes = ::testing::Types< // mixed std::pair, std::pair>; -TYPED_TEST_SUITE(cast_overflow_lowest, OverflowLowestTypes); -TYPED_TEST(cast_overflow_lowest, checked_exact_num_cast) +TEST_SUITE("cast") { - using From = typename TestFixture::First; - using To = typename TestFixture::Second; - static constexpr auto from_lowest = std::numeric_limits::lowest(); + TEST_CASE_TEMPLATE_DEFINE("checked_exact_num_cast_widen", T, cast_widen) + { + using From = typename T::first_type; + using To = typename T::second_type; + static constexpr auto from_lowest = std::numeric_limits::lowest(); + static constexpr auto from_max = std::numeric_limits::max(); - EXPECT_THROW(safe_num_cast(from_lowest), std::overflow_error); -} + CHECK_EQ(safe_num_cast(From(0)), To(0)); + CHECK_EQ(safe_num_cast(From(1)), To(1)); + CHECK_EQ(safe_num_cast(from_lowest), static_cast(from_lowest)); + CHECK_EQ(safe_num_cast(from_max), static_cast(from_max)); + } + TEST_CASE_TEMPLATE_APPLY(cast_widen, WidenTypes); -TEST(cast, precision) -{ - EXPECT_THROW(safe_num_cast(1.1), std::runtime_error); - EXPECT_THROW(safe_num_cast(std::nextafter(double(1), 2)), std::runtime_error); + TEST_CASE_TEMPLATE_DEFINE("checked_exact_num_cast_narrow", T, cast_narrow) + { + using From = typename T::second_type; // inversed + using To = typename T::first_type; // inversed + CHECK_EQ(safe_num_cast(From(0)), To(0)); + CHECK_EQ(safe_num_cast(From(1)), To(1)); + } + TEST_CASE_TEMPLATE_APPLY(cast_narrow, WidenTypes); + + TEST_CASE_TEMPLATE_DEFINE("checked_exact_num_cast_overflow", T, cast_overflow) + { + using From = typename T::first_type; + using To = typename T::second_type; + static constexpr auto from_lowest = std::numeric_limits::lowest(); + + CHECK_THROWS_AS(safe_num_cast(from_lowest), std::overflow_error); + } + TEST_CASE_TEMPLATE_APPLY(cast_overflow, OverflowLowestTypes); + + TEST_CASE("precision") + { + CHECK_THROWS_AS(safe_num_cast(1.1), std::runtime_error); + CHECK_THROWS_AS(safe_num_cast(std::nextafter(double(1), 2)), std::runtime_error); + } } diff --git a/libmamba/tests/src/util/test_compare.cpp b/libmamba/tests/src/util/test_compare.cpp index c782ae3de3..0b295fa3dc 100644 --- a/libmamba/tests/src/util/test_compare.cpp +++ b/libmamba/tests/src/util/test_compare.cpp @@ -7,80 +7,83 @@ #include #include -#include - #include "mamba/util/compare.hpp" +#include "doctest/doctest.h" + using namespace mamba::util; -TEST(compare, equal) +TEST_SUITE("compare") { - EXPECT_TRUE(cmp_equal(char{ 0 }, char{ 0 })); - EXPECT_TRUE(cmp_equal(char{ 1 }, char{ 1 })); - EXPECT_TRUE(cmp_equal(char{ -1 }, char{ -1 })); - EXPECT_TRUE(cmp_equal(int{ 0 }, int{ 0 })); - EXPECT_TRUE(cmp_equal(int{ 1 }, int{ 1 })); - EXPECT_TRUE(cmp_equal(int{ -1 }, int{ -1 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, std::size_t{ 0 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, std::size_t{ 1 })); + TEST_CASE("equal") + { + CHECK(cmp_equal(char{ 0 }, char{ 0 })); + CHECK(cmp_equal(char{ 1 }, char{ 1 })); + CHECK(cmp_equal(char{ -1 }, char{ -1 })); + CHECK(cmp_equal(int{ 0 }, int{ 0 })); + CHECK(cmp_equal(int{ 1 }, int{ 1 })); + CHECK(cmp_equal(int{ -1 }, int{ -1 })); + CHECK(cmp_equal(std::size_t{ 0 }, std::size_t{ 0 })); + CHECK(cmp_equal(std::size_t{ 1 }, std::size_t{ 1 })); - EXPECT_TRUE(cmp_equal(char{ 0 }, int{ 0 })); - EXPECT_TRUE(cmp_equal(char{ 1 }, int{ 1 })); - EXPECT_TRUE(cmp_equal(char{ -1 }, int{ -1 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, char{ 0 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, char{ 1 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, int{ 0 })); - EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, int{ 1 })); + CHECK(cmp_equal(char{ 0 }, int{ 0 })); + CHECK(cmp_equal(char{ 1 }, int{ 1 })); + CHECK(cmp_equal(char{ -1 }, int{ -1 })); + CHECK(cmp_equal(std::size_t{ 0 }, char{ 0 })); + CHECK(cmp_equal(std::size_t{ 1 }, char{ 1 })); + CHECK(cmp_equal(std::size_t{ 0 }, int{ 0 })); + CHECK(cmp_equal(std::size_t{ 1 }, int{ 1 })); - EXPECT_FALSE(cmp_equal(char{ 0 }, char{ 1 })); - EXPECT_FALSE(cmp_equal(char{ 1 }, char{ -1 })); - EXPECT_FALSE(cmp_equal(int{ 0 }, int{ 1 })); - EXPECT_FALSE(cmp_equal(int{ -1 }, int{ 1 })); - EXPECT_FALSE(cmp_equal(std::size_t{ 0 }, std::size_t{ 1 })); + CHECK_FALSE(cmp_equal(char{ 0 }, char{ 1 })); + CHECK_FALSE(cmp_equal(char{ 1 }, char{ -1 })); + CHECK_FALSE(cmp_equal(int{ 0 }, int{ 1 })); + CHECK_FALSE(cmp_equal(int{ -1 }, int{ 1 })); + CHECK_FALSE(cmp_equal(std::size_t{ 0 }, std::size_t{ 1 })); - EXPECT_FALSE(cmp_equal(char{ 0 }, int{ 1 })); - EXPECT_FALSE(cmp_equal(char{ 1 }, int{ -1 })); - EXPECT_FALSE(cmp_equal(char{ -1 }, int{ 1 })); - EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ -1 })); - EXPECT_FALSE(cmp_equal(static_cast(-1), int{ -1 })); - EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ 0 })); - EXPECT_FALSE(cmp_equal(std::numeric_limits::max(), int{ 0 })); -} + CHECK_FALSE(cmp_equal(char{ 0 }, int{ 1 })); + CHECK_FALSE(cmp_equal(char{ 1 }, int{ -1 })); + CHECK_FALSE(cmp_equal(char{ -1 }, int{ 1 })); + CHECK_FALSE(cmp_equal(std::size_t{ 1 }, int{ -1 })); + CHECK_FALSE(cmp_equal(static_cast(-1), int{ -1 })); + CHECK_FALSE(cmp_equal(std::size_t{ 1 }, int{ 0 })); + CHECK_FALSE(cmp_equal(std::numeric_limits::max(), int{ 0 })); + } -TEST(compare, less) -{ - EXPECT_TRUE(cmp_less(char{ 0 }, char{ 1 })); - EXPECT_TRUE(cmp_less(char{ -1 }, char{ 0 })); - EXPECT_TRUE(cmp_less(int{ 0 }, int{ 1 })); - EXPECT_TRUE(cmp_less(int{ -1 }, int{ 1 })); - EXPECT_TRUE(cmp_less(std::size_t{ 0 }, std::size_t{ 1 })); + TEST_CASE("less") + { + CHECK(cmp_less(char{ 0 }, char{ 1 })); + CHECK(cmp_less(char{ -1 }, char{ 0 })); + CHECK(cmp_less(int{ 0 }, int{ 1 })); + CHECK(cmp_less(int{ -1 }, int{ 1 })); + CHECK(cmp_less(std::size_t{ 0 }, std::size_t{ 1 })); - EXPECT_TRUE(cmp_less(char{ 0 }, int{ 1 })); - EXPECT_TRUE(cmp_less(char{ -1 }, int{ 0 })); - EXPECT_TRUE(cmp_less(char{ -1 }, int{ 1 })); - EXPECT_TRUE(cmp_less(char{ -1 }, std::size_t{ 1 })); - EXPECT_TRUE(cmp_less(std::size_t{ 0 }, int{ 1 })); - EXPECT_TRUE(cmp_less(std::numeric_limits::min(), char{ 0 })); - EXPECT_TRUE(cmp_less(std::numeric_limits::min(), std::size_t{ 0 })); - EXPECT_TRUE(cmp_less(int{ -1 }, std::numeric_limits::max())); - EXPECT_TRUE(cmp_less(std::size_t{ 1 }, std::numeric_limits::max())); + CHECK(cmp_less(char{ 0 }, int{ 1 })); + CHECK(cmp_less(char{ -1 }, int{ 0 })); + CHECK(cmp_less(char{ -1 }, int{ 1 })); + CHECK(cmp_less(char{ -1 }, std::size_t{ 1 })); + CHECK(cmp_less(std::size_t{ 0 }, int{ 1 })); + CHECK(cmp_less(std::numeric_limits::min(), char{ 0 })); + CHECK(cmp_less(std::numeric_limits::min(), std::size_t{ 0 })); + CHECK(cmp_less(int{ -1 }, std::numeric_limits::max())); + CHECK(cmp_less(std::size_t{ 1 }, std::numeric_limits::max())); - EXPECT_FALSE(cmp_less(char{ 1 }, char{ 0 })); - EXPECT_FALSE(cmp_less(char{ 1 }, char{ 1 })); - EXPECT_FALSE(cmp_less(char{ 0 }, char{ -1 })); - EXPECT_FALSE(cmp_less(int{ 1 }, int{ 0 })); - EXPECT_FALSE(cmp_less(int{ 1 }, int{ -1 })); - EXPECT_FALSE(cmp_less(std::size_t{ 1 }, std::size_t{ 0 })); + CHECK_FALSE(cmp_less(char{ 1 }, char{ 0 })); + CHECK_FALSE(cmp_less(char{ 1 }, char{ 1 })); + CHECK_FALSE(cmp_less(char{ 0 }, char{ -1 })); + CHECK_FALSE(cmp_less(int{ 1 }, int{ 0 })); + CHECK_FALSE(cmp_less(int{ 1 }, int{ -1 })); + CHECK_FALSE(cmp_less(std::size_t{ 1 }, std::size_t{ 0 })); - EXPECT_FALSE(cmp_less(char{ 1 }, int{ 1 })); - EXPECT_FALSE(cmp_less(char{ 1 }, int{ 0 })); - EXPECT_FALSE(cmp_less(char{ 0 }, int{ -1 })); - EXPECT_FALSE(cmp_less(char{ 1 }, int{ -11 })); - EXPECT_FALSE(cmp_less(std::size_t{ 1 }, char{ -1 })); - EXPECT_FALSE(cmp_less(int{ 1 }, std::size_t{ 0 })); - EXPECT_FALSE(cmp_less(char{ 0 }, std::numeric_limits::min())); - EXPECT_FALSE(cmp_less(std::size_t{ 0 }, std::numeric_limits::min())); - EXPECT_FALSE(cmp_less(std::numeric_limits::max(), int{ -1 })); - EXPECT_FALSE(cmp_less(std::numeric_limits::max(), std::size_t{ 1 })); + CHECK_FALSE(cmp_less(char{ 1 }, int{ 1 })); + CHECK_FALSE(cmp_less(char{ 1 }, int{ 0 })); + CHECK_FALSE(cmp_less(char{ 0 }, int{ -1 })); + CHECK_FALSE(cmp_less(char{ 1 }, int{ -11 })); + CHECK_FALSE(cmp_less(std::size_t{ 1 }, char{ -1 })); + CHECK_FALSE(cmp_less(int{ 1 }, std::size_t{ 0 })); + CHECK_FALSE(cmp_less(char{ 0 }, std::numeric_limits::min())); + CHECK_FALSE(cmp_less(std::size_t{ 0 }, std::numeric_limits::min())); + CHECK_FALSE(cmp_less(std::numeric_limits::max(), int{ -1 })); + CHECK_FALSE(cmp_less(std::numeric_limits::max(), std::size_t{ 1 })); + } } diff --git a/libmamba/tests/src/util/test_flat_set.cpp b/libmamba/tests/src/util/test_flat_set.cpp index 356d6d5f3c..e861d7e62b 100644 --- a/libmamba/tests/src/util/test_flat_set.cpp +++ b/libmamba/tests/src/util/test_flat_set.cpp @@ -4,91 +4,94 @@ // // The full license is in the file LICENSE, distributed with this software. - #include -#include - #include "mamba/util/flat_set.hpp" +#include "doctest/doctest.h" + using namespace mamba::util; -TEST(flat_set, constructor) +TEST_SUITE("flat_set") { - const auto s1 = flat_set(); - EXPECT_EQ(s1.size(), 0); - auto s2 = flat_set({ 1, 2 }); - EXPECT_EQ(s2.size(), 2); - const auto s3 = flat_set{ s2 }; - EXPECT_EQ(s3.size(), 2); - const auto s4 = flat_set{ std::move(s2) }; - EXPECT_EQ(s4.size(), 2); - // CTAD - auto s5 = flat_set({ 1, 2 }); - EXPECT_EQ(s5.size(), 2); - static_assert(std::is_same_v); - auto s6 = flat_set(s5.begin(), s5.end(), std::greater{}); - EXPECT_EQ(s6.size(), s5.size()); - static_assert(std::is_same_v); -} + TEST_CASE("constructor") + { + const auto s1 = flat_set(); + CHECK_EQ(s1.size(), 0); + auto s2 = flat_set({ 1, 2 }); + CHECK_EQ(s2.size(), 2); + const auto s3 = flat_set{ s2 }; + CHECK_EQ(s3.size(), 2); + const auto s4 = flat_set{ std::move(s2) }; + CHECK_EQ(s4.size(), 2); + // CTAD + auto s5 = flat_set({ 1, 2 }); + CHECK_EQ(s5.size(), 2); + static_assert(std::is_same_v); + auto s6 = flat_set(s5.begin(), s5.end(), std::greater{}); + CHECK_EQ(s6.size(), s5.size()); + static_assert(std::is_same_v); + } -TEST(flat_set, equality) -{ - EXPECT_EQ(flat_set(), flat_set()); - EXPECT_EQ(flat_set({ 1, 2 }), flat_set({ 1, 2 })); - EXPECT_EQ(flat_set({ 1, 2 }), flat_set({ 2, 1 })); - EXPECT_EQ(flat_set({ 1, 2, 1 }), flat_set({ 2, 2, 1 })); - EXPECT_NE(flat_set({ 1, 2 }), flat_set({ 1, 2, 3 })); - EXPECT_NE(flat_set({ 2 }), flat_set({})); -} -TEST(flat_set, insert) -{ - auto s = flat_set(); - s.insert(33); - EXPECT_EQ(s, flat_set({ 33 })); - s.insert(33); - s.insert(17); - EXPECT_EQ(s, flat_set({ 17, 33 })); - s.insert(22); - EXPECT_EQ(s, flat_set({ 17, 22, 33 })); - s.insert(33); - EXPECT_EQ(s, flat_set({ 17, 22, 33 })); - auto v = std::vector({ 33, 22, 17, 0 }); - s.insert(v.begin(), v.end()); - EXPECT_EQ(s, flat_set({ 0, 17, 22, 33 })); -} + TEST_CASE("equality") + { + CHECK_EQ(flat_set(), flat_set()); + CHECK_EQ(flat_set({ 1, 2 }), flat_set({ 1, 2 })); + CHECK_EQ(flat_set({ 1, 2 }), flat_set({ 2, 1 })); + CHECK_EQ(flat_set({ 1, 2, 1 }), flat_set({ 2, 2, 1 })); + CHECK_NE(flat_set({ 1, 2 }), flat_set({ 1, 2, 3 })); + CHECK_NE(flat_set({ 2 }), flat_set({})); + } -TEST(flat_set, erase) -{ - auto s = flat_set{ 4, 3, 2, 1 }; - EXPECT_EQ(s.erase(4), 1); - EXPECT_EQ(s, flat_set({ 1, 2, 3 })); - EXPECT_EQ(s.erase(4), 0); - EXPECT_EQ(s, flat_set({ 1, 2, 3 })); + TEST_CASE("insert") + { + auto s = flat_set(); + s.insert(33); + CHECK_EQ(s, flat_set({ 33 })); + s.insert(33); + s.insert(17); + CHECK_EQ(s, flat_set({ 17, 33 })); + s.insert(22); + CHECK_EQ(s, flat_set({ 17, 22, 33 })); + s.insert(33); + CHECK_EQ(s, flat_set({ 17, 22, 33 })); + auto v = std::vector({ 33, 22, 17, 0 }); + s.insert(v.begin(), v.end()); + CHECK_EQ(s, flat_set({ 0, 17, 22, 33 })); + } - const auto it = s.erase(s.begin()); - EXPECT_EQ(it, s.begin()); - EXPECT_EQ(s, flat_set({ 2, 3 })); -} + TEST_CASE("erase") + { + auto s = flat_set{ 4, 3, 2, 1 }; + CHECK_EQ(s.erase(4), 1); + CHECK_EQ(s, flat_set({ 1, 2, 3 })); + CHECK_EQ(s.erase(4), 0); + CHECK_EQ(s, flat_set({ 1, 2, 3 })); -TEST(flat_set, contains) -{ - const auto s = flat_set({ 1, 3, 4, 5 }); - EXPECT_FALSE(s.contains(0)); - EXPECT_TRUE(s.contains(1)); - EXPECT_FALSE(s.contains(2)); - EXPECT_TRUE(s.contains(3)); - EXPECT_TRUE(s.contains(4)); - EXPECT_TRUE(s.contains(5)); - EXPECT_FALSE(s.contains(6)); -} + const auto it = s.erase(s.begin()); + CHECK_EQ(it, s.begin()); + CHECK_EQ(s, flat_set({ 2, 3 })); + } -TEST(flat_set, key_compare) -{ - auto s = flat_set({ 1, 3, 4, 5 }, std::greater{}); - EXPECT_EQ(s.front(), 5); - EXPECT_EQ(s.back(), 1); - s.insert(6); - EXPECT_EQ(s.front(), 6); + TEST_CASE("contains") + { + const auto s = flat_set({ 1, 3, 4, 5 }); + CHECK_FALSE(s.contains(0)); + CHECK(s.contains(1)); + CHECK_FALSE(s.contains(2)); + CHECK(s.contains(3)); + CHECK(s.contains(4)); + CHECK(s.contains(5)); + CHECK_FALSE(s.contains(6)); + } + + TEST_CASE("key_compare") + { + auto s = flat_set({ 1, 3, 4, 5 }, std::greater{}); + CHECK_EQ(s.front(), 5); + CHECK_EQ(s.back(), 1); + s.insert(6); + CHECK_EQ(s.front(), 6); + } } diff --git a/libmamba/tests/src/util/test_graph.cpp b/libmamba/tests/src/util/test_graph.cpp index 7f9b28b509..c826920b97 100644 --- a/libmamba/tests/src/util/test_graph.cpp +++ b/libmamba/tests/src/util/test_graph.cpp @@ -4,10 +4,10 @@ // // The full license is in the file LICENSE, distributed with this software. -#include - #include "mamba/util/graph.hpp" +#include "doctest/doctest.h" + using namespace mamba::util; auto @@ -106,243 +106,248 @@ class test_visitor : private default_visitor edge_map m_cross_edges; }; -TEST(graph, build_simple) +TEST_SUITE("graph") { - const auto g = build_graph(); - using node_map = decltype(g)::node_map; - using node_id_list = decltype(g)::node_id_list; - EXPECT_EQ(g.number_of_nodes(), 7ul); - EXPECT_EQ(g.number_of_edges(), 7ul); - EXPECT_EQ( - g.nodes(), - node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 }, { 3, 3.5 }, { 4, 4.5 }, { 5, 5.5 }, { 6, 6.5 } }) - ); - EXPECT_EQ(g.successors(0u), node_id_list({ 1u, 2u })); - EXPECT_EQ(g.successors(1u), node_id_list({ 3u, 4u })); - EXPECT_EQ(g.successors(2u), node_id_list({ 3u, 5u })); - EXPECT_EQ(g.successors(3u), node_id_list({ 6u })); - EXPECT_EQ(g.predecessors(0u), node_id_list()); - EXPECT_EQ(g.predecessors(1u), node_id_list({ 0u })); - EXPECT_EQ(g.predecessors(2u), node_id_list({ 0u })); - EXPECT_EQ(g.predecessors(3u), node_id_list({ 1u, 2u })); -} + TEST_CASE("build_simple") + { + const auto g = build_graph(); + using node_map = decltype(g)::node_map; + using node_id_list = decltype(g)::node_id_list; + CHECK_EQ(g.number_of_nodes(), 7ul); + CHECK_EQ(g.number_of_edges(), 7ul); + CHECK_EQ( + g.nodes(), + node_map( + { { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 }, { 3, 3.5 }, { 4, 4.5 }, { 5, 5.5 }, { 6, 6.5 } } + ) + ); + CHECK_EQ(g.successors(0u), node_id_list({ 1u, 2u })); + CHECK_EQ(g.successors(1u), node_id_list({ 3u, 4u })); + CHECK_EQ(g.successors(2u), node_id_list({ 3u, 5u })); + CHECK_EQ(g.successors(3u), node_id_list({ 6u })); + CHECK_EQ(g.predecessors(0u), node_id_list()); + CHECK_EQ(g.predecessors(1u), node_id_list({ 0u })); + CHECK_EQ(g.predecessors(2u), node_id_list({ 0u })); + CHECK_EQ(g.predecessors(3u), node_id_list({ 1u, 2u })); + } -TEST(graph, build_edge_data) -{ - const auto g = build_edge_data_graph(); - using node_map = decltype(g)::node_map; - using node_id_list = decltype(g)::node_id_list; - EXPECT_EQ(g.number_of_nodes(), 3ul); - EXPECT_EQ(g.number_of_edges(), 2ul); - EXPECT_EQ(g.nodes(), node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 } })); - EXPECT_EQ(g.successors(0ul), node_id_list({ 1ul })); - EXPECT_EQ(g.successors(1ul), node_id_list({ 2ul })); - EXPECT_EQ(g.successors(2ul), node_id_list()); - EXPECT_EQ(g.predecessors(0ul), node_id_list()); - EXPECT_EQ(g.predecessors(1ul), node_id_list({ 0ul })); - EXPECT_EQ(g.predecessors(2ul), node_id_list({ 1ul })); - - using edge_map = decltype(g)::edge_map; - EXPECT_EQ(g.edges(), edge_map({ { { 0ul, 1ul }, "n0->n1" }, { { 1ul, 2ul }, "n1->n2" } })); -} + TEST_CASE("build_edge_data") + { + const auto g = build_edge_data_graph(); + using node_map = decltype(g)::node_map; + using node_id_list = decltype(g)::node_id_list; + CHECK_EQ(g.number_of_nodes(), 3ul); + CHECK_EQ(g.number_of_edges(), 2ul); + CHECK_EQ(g.nodes(), node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 } })); + CHECK_EQ(g.successors(0ul), node_id_list({ 1ul })); + CHECK_EQ(g.successors(1ul), node_id_list({ 2ul })); + CHECK_EQ(g.successors(2ul), node_id_list()); + CHECK_EQ(g.predecessors(0ul), node_id_list()); + CHECK_EQ(g.predecessors(1ul), node_id_list({ 0ul })); + CHECK_EQ(g.predecessors(2ul), node_id_list({ 1ul })); + + using edge_map = decltype(g)::edge_map; + CHECK_EQ(g.edges(), edge_map({ { { 0ul, 1ul }, "n0->n1" }, { { 1ul, 2ul }, "n1->n2" } })); + } -TEST(graph, has_node_edge) -{ - const auto g = build_graph(); - EXPECT_TRUE(g.has_node(1ul)); - EXPECT_TRUE(g.has_node(4ul)); - EXPECT_FALSE(g.has_node(g.number_of_nodes())); - EXPECT_TRUE(g.has_edge(1ul, 4ul)); - EXPECT_FALSE(g.has_edge(4ul, 1ul)); - EXPECT_TRUE(g.has_edge(0ul, 2ul)); - EXPECT_FALSE(g.has_edge(0ul, 5ul)); - EXPECT_FALSE(g.has_edge(0ul, g.number_of_nodes())); - EXPECT_FALSE(g.has_edge(g.number_of_nodes(), 1ul)); -} + TEST_CASE("has_node_edge") + { + const auto g = build_graph(); + CHECK(g.has_node(1ul)); + CHECK(g.has_node(4ul)); + CHECK_FALSE(g.has_node(g.number_of_nodes())); + CHECK(g.has_edge(1ul, 4ul)); + CHECK_FALSE(g.has_edge(4ul, 1ul)); + CHECK(g.has_edge(0ul, 2ul)); + CHECK_FALSE(g.has_edge(0ul, 5ul)); + CHECK_FALSE(g.has_edge(0ul, g.number_of_nodes())); + CHECK_FALSE(g.has_edge(g.number_of_nodes(), 1ul)); + } -TEST(graph, data_modifier) -{ - auto g = build_edge_data_graph(); + TEST_CASE("data_modifier") + { + auto g = build_edge_data_graph(); - static constexpr auto new_node_val = -1.5; - EXPECT_NE(g.node(0ul), new_node_val); - g.node(0ul) = new_node_val; - EXPECT_EQ(g.node(0ul), new_node_val); + static constexpr auto new_node_val = -1.5; + CHECK_NE(g.node(0ul), new_node_val); + g.node(0ul) = new_node_val; + CHECK_EQ(g.node(0ul), new_node_val); - static constexpr auto new_edge_val = "data"; - EXPECT_NE(g.edge(0ul, 1ul), new_edge_val); - g.edge(0ul, 1ul) = new_edge_val; - EXPECT_EQ(g.edge(0ul, 1ul), new_edge_val); -} + static constexpr auto new_edge_val = "data"; + CHECK_NE(g.edge(0ul, 1ul), new_edge_val); + g.edge(0ul, 1ul) = new_edge_val; + CHECK_EQ(g.edge(0ul, 1ul), new_edge_val); + } -TEST(graph, remove_edge) -{ - auto g = build_edge_data_graph(); - const auto n_edges_init = g.number_of_edges(); - - ASSERT_FALSE(g.has_edge(1, 0)); - ASSERT_TRUE(g.has_edge(0, 1)); - EXPECT_FALSE(g.remove_edge(1, 0)); - EXPECT_EQ(g.number_of_edges(), n_edges_init); - EXPECT_FALSE(g.has_edge(1, 0)); - EXPECT_TRUE(g.has_edge(0, 1)); - - ASSERT_TRUE(g.has_edge(0, 1)); - EXPECT_TRUE(g.remove_edge(0, 1)); - EXPECT_EQ(g.number_of_edges(), n_edges_init - 1u); - EXPECT_FALSE(g.has_edge(0, 1)); - EXPECT_EQ(g.edges().count({ 0, 1 }), 0); -} + TEST_CASE("remove_edge") + { + auto g = build_edge_data_graph(); + const auto n_edges_init = g.number_of_edges(); + + REQUIRE_FALSE(g.has_edge(1, 0)); + REQUIRE(g.has_edge(0, 1)); + CHECK_FALSE(g.remove_edge(1, 0)); + CHECK_EQ(g.number_of_edges(), n_edges_init); + CHECK_FALSE(g.has_edge(1, 0)); + CHECK(g.has_edge(0, 1)); + + REQUIRE(g.has_edge(0, 1)); + CHECK(g.remove_edge(0, 1)); + CHECK_EQ(g.number_of_edges(), n_edges_init - 1u); + CHECK_FALSE(g.has_edge(0, 1)); + CHECK_EQ(g.edges().count({ 0, 1 }), 0); + } -TEST(graph, remove_node) -{ - auto g = build_edge_data_graph(); - - ASSERT_TRUE(g.has_node(0)); - ASSERT_TRUE(g.has_node(1)); - ASSERT_TRUE(g.has_node(2)); - ASSERT_TRUE(g.has_edge(0, 1)); - ASSERT_TRUE(g.has_edge(1, 2)); - - const auto n_edges_init = g.number_of_edges(); - const auto n_nodes_init = g.number_of_nodes(); - const auto node_1_degree = g.in_degree(1) + g.out_degree(1); - - EXPECT_TRUE(g.remove_node(1)); - EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u); - EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree); - EXPECT_EQ(g.number_of_edges(), g.edges().size()); - EXPECT_TRUE(g.has_node(0)); - EXPECT_FALSE(g.has_node(1)); - EXPECT_TRUE(g.has_node(2)); - EXPECT_EQ(g.in_degree(1), 0); - EXPECT_EQ(g.out_degree(1), 0); - EXPECT_FALSE(g.has_edge(0, 1)); - EXPECT_FALSE(g.has_edge(1, 2)); - g.for_each_node_id([&](auto id) { EXPECT_TRUE(g.has_node(id)); }); - - EXPECT_FALSE(g.remove_node(1)); - EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u); - EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree); - EXPECT_EQ(g.number_of_edges(), g.edges().size()); - - const auto new_id = g.add_node(.7); - EXPECT_EQ(new_id, n_nodes_init); // Ids are not invalidated so new id is used - EXPECT_FALSE(g.has_node(1)); // Old id is not being confused - EXPECT_EQ(g.number_of_nodes(), n_nodes_init); -} + TEST_CASE("remove_node") + { + auto g = build_edge_data_graph(); + + REQUIRE(g.has_node(0)); + REQUIRE(g.has_node(1)); + REQUIRE(g.has_node(2)); + REQUIRE(g.has_edge(0, 1)); + REQUIRE(g.has_edge(1, 2)); + + const auto n_edges_init = g.number_of_edges(); + const auto n_nodes_init = g.number_of_nodes(); + const auto node_1_degree = g.in_degree(1) + g.out_degree(1); + + CHECK(g.remove_node(1)); + CHECK_EQ(g.number_of_nodes(), n_nodes_init - 1u); + CHECK_EQ(g.number_of_edges(), n_edges_init - node_1_degree); + CHECK_EQ(g.number_of_edges(), g.edges().size()); + CHECK(g.has_node(0)); + CHECK_FALSE(g.has_node(1)); + CHECK(g.has_node(2)); + CHECK_EQ(g.in_degree(1), 0); + CHECK_EQ(g.out_degree(1), 0); + CHECK_FALSE(g.has_edge(0, 1)); + CHECK_FALSE(g.has_edge(1, 2)); + g.for_each_node_id([&](auto id) { CHECK(g.has_node(id)); }); + + CHECK_FALSE(g.remove_node(1)); + CHECK_EQ(g.number_of_nodes(), n_nodes_init - 1u); + CHECK_EQ(g.number_of_edges(), n_edges_init - node_1_degree); + CHECK_EQ(g.number_of_edges(), g.edges().size()); + + const auto new_id = g.add_node(.7); + CHECK_EQ(new_id, n_nodes_init); // Ids are not invalidated so new id is used + CHECK_FALSE(g.has_node(1)); // Old id is not being confused + CHECK_EQ(g.number_of_nodes(), n_nodes_init); + } -TEST(graph, degree) -{ - const auto g = build_graph(); - EXPECT_EQ(g.out_degree(0), 2); - EXPECT_EQ(g.out_degree(1), 2); - EXPECT_EQ(g.out_degree(6), 0); - EXPECT_EQ(g.in_degree(0), 0); - EXPECT_EQ(g.in_degree(3), 2); - EXPECT_EQ(g.in_degree(6), 1); -} + TEST_CASE("degree") + { + const auto g = build_graph(); + CHECK_EQ(g.out_degree(0), 2); + CHECK_EQ(g.out_degree(1), 2); + CHECK_EQ(g.out_degree(6), 0); + CHECK_EQ(g.in_degree(0), 0); + CHECK_EQ(g.in_degree(3), 2); + CHECK_EQ(g.in_degree(6), 1); + } -TEST(graph, for_each_node) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - std::size_t n_nodes = 0; - g.for_each_node_id( - [&](node_id id) - { - EXPECT_TRUE(g.has_node(id)); - ++n_nodes; - } - ); - EXPECT_EQ(n_nodes, g.number_of_nodes()); -} + TEST_CASE("for_each_node") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + std::size_t n_nodes = 0; + g.for_each_node_id( + [&](node_id id) + { + CHECK(g.has_node(id)); + ++n_nodes; + } + ); + CHECK_EQ(n_nodes, g.number_of_nodes()); + } -TEST(graph, for_each_edge) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - std::size_t n_edges = 0; - g.for_each_edge_id( - [&g, &n_edges](node_id from, node_id to) - { - EXPECT_TRUE(g.has_edge(from, to)); - ++n_edges; - } - ); - EXPECT_EQ(n_edges, g.number_of_edges()); -} + TEST_CASE("for_each_edge") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + std::size_t n_edges = 0; + g.for_each_edge_id( + [&g, &n_edges](node_id from, node_id to) + { + CHECK(g.has_edge(from, to)); + ++n_edges; + } + ); + CHECK_EQ(n_edges, g.number_of_edges()); + } -TEST(graph, for_each_leaf) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - using node_id_list = decltype(g)::node_id_list; - auto leaves = node_id_list(); - g.for_each_leaf_id([&leaves](node_id leaf) { leaves.insert(leaf); }); - EXPECT_EQ(leaves, node_id_list({ 4ul, 5ul, 6ul })); -} + TEST_CASE("for_each_leaf") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + using node_id_list = decltype(g)::node_id_list; + auto leaves = node_id_list(); + g.for_each_leaf_id([&leaves](node_id leaf) { leaves.insert(leaf); }); + CHECK_EQ(leaves, node_id_list({ 4ul, 5ul, 6ul })); + } -TEST(graph, for_each_leaf_from) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - using node_id_list = decltype(g)::node_id_list; - auto leaves = node_id_list(); - g.for_each_leaf_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); }); - EXPECT_EQ(leaves, node_id_list({ 5ul, 6ul })); -} + TEST_CASE("for_each_leaf_from") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + using node_id_list = decltype(g)::node_id_list; + auto leaves = node_id_list(); + g.for_each_leaf_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); }); + CHECK_EQ(leaves, node_id_list({ 5ul, 6ul })); + } -TEST(graph, for_each_root) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - using node_id_list = decltype(g)::node_id_list; - auto roots = node_id_list(); - g.for_each_root_id([&roots](node_id root) { roots.insert(root); }); - EXPECT_EQ(roots, node_id_list({ 0ul })); -} + TEST_CASE("for_each_root") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + using node_id_list = decltype(g)::node_id_list; + auto roots = node_id_list(); + g.for_each_root_id([&roots](node_id root) { roots.insert(root); }); + CHECK_EQ(roots, node_id_list({ 0ul })); + } -TEST(graph, for_each_root_from) -{ - const auto g = build_graph(); - using node_id = decltype(g)::node_id; - using node_id_list = decltype(g)::node_id_list; - auto leaves = node_id_list(); - g.for_each_root_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); }); - EXPECT_EQ(leaves, node_id_list({ 0ul })); -} + TEST_CASE("for_each_root_from") + { + const auto g = build_graph(); + using node_id = decltype(g)::node_id; + using node_id_list = decltype(g)::node_id_list; + auto leaves = node_id_list(); + g.for_each_root_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); }); + CHECK_EQ(leaves, node_id_list({ 0ul })); + } -TEST(graph, depth_first_search) -{ - const auto g = build_graph(); - test_visitor> vis; - g.depth_first_search(vis); - EXPECT_TRUE(vis.get_back_edge_map().empty()); - EXPECT_EQ(vis.get_cross_edge_map().find(2u)->second, 3u); -} + TEST_CASE("depth_first_search") + { + const auto g = build_graph(); + test_visitor> vis; + g.depth_first_search(vis); + CHECK(vis.get_back_edge_map().empty()); + CHECK_EQ(vis.get_cross_edge_map().find(2u)->second, 3u); + } -TEST(graph, dfs_cyclic) -{ - const auto g = build_cyclic_graph(); - test_visitor> vis; - g.depth_first_search(vis); - EXPECT_EQ(vis.get_back_edge_map().find(2u)->second, 0u); - EXPECT_TRUE(vis.get_cross_edge_map().empty()); -} + TEST_CASE("dfs_cyclic") + { + const auto g = build_cyclic_graph(); + test_visitor> vis; + g.depth_first_search(vis); + CHECK_EQ(vis.get_back_edge_map().find(2u)->second, 0u); + CHECK(vis.get_cross_edge_map().empty()); + } -TEST(graph, dfs_empty) -{ - DiGraph g; - test_visitor> vis; - g.depth_first_search(vis); - EXPECT_TRUE(vis.get_back_edge_map().empty()); - EXPECT_TRUE(vis.get_cross_edge_map().empty()); -} + TEST_CASE("dfs_empty") + { + DiGraph g; + test_visitor> vis; + g.depth_first_search(vis); + CHECK(vis.get_back_edge_map().empty()); + CHECK(vis.get_cross_edge_map().empty()); + } -TEST(graph_algorithm, is_reachable) -{ - auto graph = build_graph(); - EXPECT_TRUE(is_reachable(graph, 0, 6)); - EXPECT_FALSE(is_reachable(graph, 6, 0)); + TEST_CASE("is_reachable") + { + auto graph = build_graph(); + CHECK(is_reachable(graph, 0, 6)); + CHECK_FALSE(is_reachable(graph, 6, 0)); + } }