mamba/libmamba/tests/src/core/test_cpp.cpp

661 lines
27 KiB
C++

// 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 <chrono>
#include <sstream>
#include <tuple>
#include <doctest/doctest.h>
#include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp"
#include "mamba/core/fsutil.hpp"
#include "mamba/core/history.hpp"
#include "mamba/core/link.hpp"
#include "mamba/core/match_spec.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/subdirdata.hpp"
#include "test_data.hpp"
namespace mamba
{
// TEST(cpp_install, install)
// {
// Context::instance().output_params.verbosity = 3;
// PackageInfo pkg("wheel", "0.34.2", "py_1", 1);
// fs::u8path prefix = "C:\\Users\\wolfv\\miniconda3\\";
// TransactionContext tc(prefix, "3.8.x");
// // try {
// UnlinkPackage up(pkg, &tc);
// up.execute();
// // } catch (...) { std::cout << "Nothing to delete ... \n"; }
// LinkPackage lp(pkg, prefix / "pkgs" , &tc);
// lp.execute();
// }
TEST_SUITE("match_spec")
{
TEST_CASE("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");
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("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);
CHECK_EQ(
ms.url,
std::string("file://") + driveletter
+ ":/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
);
#else
CHECK_EQ(
ms.url,
"file:///home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
);
#endif
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("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_SUITE("history")
{
TEST_CASE("user_request")
{
auto u = History::UserRequest::prefilled();
// update in 100 years!
CHECK_EQ(u.date[0], '2');
CHECK_EQ(u.date[1], '0');
}
}
TEST_SUITE("output")
{
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("http://root:secretpassword@myweb.com/test.repo");
CHECK_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"
);
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"
);
res = Console::instance().hide_secrets("myweb.com/t/my-12345-token/test.repo");
CHECK_EQ(res, "myweb.com/t/*****/test.repo");
res = Console::instance().hide_secrets("root:secretpassword@myweb.com/test.repo");
CHECK_EQ(res, "root:*****@myweb.com/test.repo");
}
// 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::string, char, bool>;
std::vector<param_type> 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)
);
}
}
}
TEST_SUITE("context")
{
TEST_CASE("env_name")
{
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
CHECK_THROWS_AS(locate_prefix_by_name("test"), std::runtime_error);
#endif
// TODO implement tests for locate_prefix_by_name
}
}
}
TEST_SUITE("fsutil")
{
TEST_CASE("starts_with_home")
{
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_CASE("expand_user")
{
fs::u8path pbefore = "/tmp/test/xyz.txt";
fs::u8path p = env::expand_user(pbefore);
CHECK_EQ(p, pbefore);
}
TEST_CASE("touch")
{
if (on_linux)
{
path::touch("/tmp/dir/file.txt", true);
CHECK(fs::exists("/tmp/dir/file.txt"));
}
}
}
TEST_SUITE("link")
{
TEST_CASE("replace_long_shebang")
{
if (!on_win)
{
std::string res = replace_long_shebang(
"#!/this/is/loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong/python -o test -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')
);
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");
}
}
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_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_SUITE("utils")
{
TEST_CASE("quote_for_shell")
{
if (!on_win)
{
std::vector<std::string> args1 = { "python", "-c", "print('is\ngreat')" };
CHECK_EQ(quote_for_shell(args1), "python -c 'print('\"'\"'is\ngreat'\"'\"')'");
std::vector<std::string> args2 = { "python", "-c", "print(\"is great\")" };
CHECK_EQ(quote_for_shell(args2), "python -c 'print(\"is great\")'");
std::vector<std::string> args3 = { "python", "very nice", "print(\"is great\")" };
CHECK_EQ(quote_for_shell(args3), "python 'very nice' 'print(\"is great\")'");
std::vector<std::string> 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<std::string> args5 = { "echo", "(" };
CHECK_EQ(quote_for_shell(args5), "echo '('");
std::vector<std::string> args6 = { "echo", "foo'bar\nspam" };
CHECK_EQ(quote_for_shell(args6), "echo 'foo'\"'\"'bar\nspam'");
}
std::vector<std::string> args1 = { "a b c", "d", "e" };
CHECK_EQ(quote_for_shell(args1, "cmdexe"), "\"a b c\" d e");
std::vector<std::string> args2 = { "ab\"c", "\\", "d" };
CHECK_EQ(quote_for_shell(args2, "cmdexe"), "ab\\\"c \\ d");
std::vector<std::string> args3 = { "ab\"c", " \\", "d" };
CHECK_EQ(quote_for_shell(args3, "cmdexe"), "ab\\\"c \" \\\\\" d");
std::vector<std::string> args4 = { "a\\\\\\b", "de fg", "h" };
CHECK_EQ(quote_for_shell(args4, "cmdexe"), "a\\\\\\b \"de fg\" h");
std::vector<std::string> args5 = { "a\\\"b", "c", "d" };
CHECK_EQ(quote_for_shell(args5, "cmdexe"), "a\\\\\\\"b c d");
std::vector<std::string> args6 = { "a\\\\b c", "d", "e" };
CHECK_EQ(quote_for_shell(args6, "cmdexe"), "\"a\\\\b c\" d e");
std::vector<std::string> args7 = { "a\\\\b\\ c", "d", "e" };
CHECK_EQ(quote_for_shell(args7, "cmdexe"), "\"a\\\\b\\ c\" d e");
std::vector<std::string> args8 = { "ab", "" };
CHECK_EQ(quote_for_shell(args8, "cmdexe"), "ab \"\"");
}
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
{
// read the header that contains json like {"_mod": "...", ...}
tl::expected<subdir_metadata, mamba_error> read_metadata(const fs::u8path& file);
}
#ifdef _WIN32
std::chrono::system_clock::time_point filetime_to_unix_test(const fs::file_time_type& filetime)
{
// windows filetime is in 100ns intervals since 1601-01-01
static constexpr auto epoch_offset = std::chrono::seconds(11644473600ULL);
return std::chrono::system_clock::time_point(
std::chrono::duration_cast<std::chrono::system_clock::duration>(
filetime.time_since_epoch() - epoch_offset
)
);
}
#endif
TEST_SUITE("subdirdata")
{
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();
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();
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();
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");
CHECK(mq.has_value() == false);
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
{
#ifdef _WIN32
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");
#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<std::chrono::nanoseconds>(
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 ofs = open_ofstream(state_file);
ofs << jstate.dump(4);
}
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;
}
}
} // namespace mamba