1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-21 23:32:35 +00:00

test: use new tr_variant API (#7268)

* test: new `tr_variant` API in `json-test.cc`

* test: new `tr_variant` API in `variant-test.cc`

* chore: housekeeping

* test: new `tr_variant` API in `dht-test.cc`

* fix: use `reinterpret_cast` in `tr_variant::make_raw()`

* fix: add missing `typename` in `tr_variant::make_raw()`

* test: new `tr_variant` API in `settings-test.cc`

* test: new `tr_variant` API in `move-test.cc`

* test: new `tr_variant` API in `rpc-test.cc`

* test: new `tr_variant` API in `makemeta-test.cc`

* test: new `tr_variant` API in `session-test.cc`
This commit is contained in:
Yat Ho 2024-12-10 09:22:54 +08:00 committed by GitHub
parent 510286f419
commit 90859fe115
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 515 additions and 483 deletions

View file

@ -219,13 +219,13 @@ public:
[[nodiscard]] static auto make_raw(void const* value, size_t n_bytes)
{
return tr_variant{ std::string{ static_cast<char const*>(value), n_bytes } };
return tr_variant{ std::string_view{ reinterpret_cast<char const*>(value), n_bytes } };
}
template<typename CharSpan>
[[nodiscard]] static auto make_raw(CharSpan const& value)
{
static_assert(sizeof(CharSpan::value_type) == 1U);
static_assert(sizeof(typename CharSpan::value_type) == 1U);
return make_raw(std::data(value), std::size(value));
}

View file

@ -46,7 +46,7 @@
#include <libtransmission/tr-macros.h>
#include <libtransmission/tr-strbuf.h>
#include <libtransmission/utils.h>
#include <libtransmission/variant.h> // tr_variantDictAddRaw
#include <libtransmission/variant.h>
#include "gtest/gtest.h"
#include "test-fixtures.h"
@ -126,23 +126,22 @@ protected:
{
auto const dat_file = MockStateFile::filename(path);
auto dict = tr_variant{};
tr_variantInitDict(&dict, 3U);
tr_variantDictAddRaw(&dict, TR_KEY_id, std::data(id_), std::size(id_));
tr_variantDictAddInt(&dict, TR_KEY_id_timestamp, id_timestamp_);
auto map = tr_variant::Map{ 3U };
map.try_emplace(TR_KEY_id, tr_variant::make_raw(id_));
map.try_emplace(TR_KEY_id_timestamp, id_timestamp_);
auto compact = std::vector<std::byte>{};
for (auto const& socket_address : ipv4_nodes_)
{
socket_address.to_compact(std::back_inserter(compact));
}
tr_variantDictAddRaw(&dict, TR_KEY_nodes, std::data(compact), std::size(compact));
map.try_emplace(TR_KEY_nodes, tr_variant::make_raw(compact));
compact.clear();
for (auto const& socket_address : ipv6_nodes_)
{
socket_address.to_compact(std::back_inserter(compact));
}
tr_variantDictAddRaw(&dict, TR_KEY_nodes6, std::data(compact), std::size(compact));
tr_variant_serde::benc().to_file(dict, dat_file);
map.try_emplace(TR_KEY_nodes6, tr_variant::make_raw(compact));
tr_variant_serde::benc().to_file(tr_variant{ std::move(map) }, dat_file);
}
};

View file

@ -51,7 +51,7 @@ private:
TEST_P(JSONTest, testElements)
{
auto const in = std::string{
static auto constexpr In = std::string_view{
"{ \"string\": \"hello world\","
" \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\","
" \"int\": 5, "
@ -61,54 +61,60 @@ TEST_P(JSONTest, testElements)
" \"null\": null }"
};
auto var = tr_variant_serde::json().inplace().parse(in).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
auto const var = tr_variant_serde::json().inplace().parse(In).value_or(tr_variant{});
auto const* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto sv = std::string_view{};
auto key = tr_quark_new("string"sv);
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("hello world"sv, sv);
auto sv = map->value_if<std::string_view>(tr_quark_new("string"sv));
ASSERT_TRUE(sv);
EXPECT_EQ("hello world"sv, *sv);
EXPECT_TRUE(tr_variantDictFindStrView(&var, tr_quark_new("escaped"sv), &sv));
EXPECT_EQ("bell \b formfeed \f linefeed \n carriage return \r tab \t"sv, sv);
sv = map->value_if<std::string_view>(tr_quark_new("escaped"sv));
ASSERT_TRUE(sv);
EXPECT_EQ("bell \b formfeed \f linefeed \n carriage return \r tab \t"sv, *sv);
auto i = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, tr_quark_new("int"sv), &i));
EXPECT_EQ(5, i);
auto i = map->value_if<int64_t>(tr_quark_new("int"sv));
ASSERT_TRUE(i);
EXPECT_EQ(5, *i);
auto d = double{};
EXPECT_TRUE(tr_variantDictFindReal(&var, tr_quark_new("float"sv), &d));
EXPECT_EQ(65, int(d * 10));
auto d = map->value_if<double>(tr_quark_new("float"sv));
ASSERT_TRUE(d);
EXPECT_EQ(65, int(*d * 10));
auto f = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&var, tr_quark_new("true"sv), &f));
EXPECT_TRUE(f);
auto b = map->value_if<bool>(tr_quark_new("true"sv));
ASSERT_TRUE(b);
EXPECT_TRUE(*b);
EXPECT_TRUE(tr_variantDictFindBool(&var, tr_quark_new("false"sv), &f));
EXPECT_FALSE(f);
b = map->value_if<bool>(tr_quark_new("false"sv));
ASSERT_TRUE(b);
EXPECT_FALSE(*b);
EXPECT_TRUE(tr_variantDictFindStrView(&var, tr_quark_new("null"sv), &sv));
EXPECT_EQ(""sv, sv);
sv = map->value_if<std::string_view>(tr_quark_new("null"sv));
ASSERT_TRUE(sv);
EXPECT_EQ(""sv, *sv);
}
TEST_P(JSONTest, testUtf8)
{
auto in = "{ \"key\": \"Letöltések\" }"sv;
auto sv = std::string_view{};
tr_quark const key = tr_quark_new("key"sv);
auto serde = tr_variant_serde::json().inplace().compact();
auto var = serde.parse(in).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
auto* map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("Letöltések"sv, *sv);
var.clear();
in = R"({ "key": "\u005C" })"sv;
var = serde.parse(in).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("\\"sv, sv);
map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("\\"sv, *sv);
var.clear();
/**
@ -121,41 +127,51 @@ TEST_P(JSONTest, testUtf8)
*/
in = R"({ "key": "Let\u00f6lt\u00e9sek" })"sv;
var = serde.parse(in).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("Letöltések"sv, *sv);
auto json = serde.to_string(var);
var.clear();
EXPECT_FALSE(std::empty(json));
EXPECT_EQ(R"({"key":"Letöltések"})"sv, json);
var = serde.parse(json).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("Letöltések"sv, *sv);
// Test string known to be prone to locale issues
// https://github.com/transmission/transmission/issues/5967
var.clear();
tr_variantInitDict(&var, 1U);
tr_variantDictAddStr(&var, key, "Дыскаграфія"sv);
var = tr_variant::make_map(1U);
map = var.get_if<tr_variant::Map>();
map->try_emplace(key, "Дыскаграфія"sv);
json = serde.to_string(var);
EXPECT_EQ(R"({"key":"Дыскаграфія"})"sv, json);
var = serde.parse(json).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("Дыскаграфія"sv, sv);
map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("Дыскаграфія"sv, *sv);
// Thinking emoji 🤔
var.clear();
tr_variantInitDict(&var, 1U);
tr_variantDictAddStr(&var, key, "\xf0\x9f\xa4\x94"sv);
var = tr_variant::make_map(1U);
map = var.get_if<tr_variant::Map>();
map->try_emplace(key, "\xf0\x9f\xa4\x94"sv);
json = serde.to_string(var);
EXPECT_EQ("{\"key\":\"\xf0\x9f\xa4\x94\"}"sv, json);
var = serde.parse(json).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(&var, key, &sv));
EXPECT_EQ("\xf0\x9f\xa4\x94"sv, sv);
map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
sv = map->value_if<std::string_view>(key);
ASSERT_TRUE(sv);
EXPECT_EQ("\xf0\x9f\xa4\x94"sv, *sv);
}
TEST_P(JSONTest, test1)
@ -176,32 +192,33 @@ TEST_P(JSONTest, test1)
auto serde = tr_variant_serde::json();
auto var = serde.inplace().parse(Input).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
auto* map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto sv = std::string_view{};
auto i = int64_t{};
auto* headers = tr_variantDictFind(&var, tr_quark_new("headers"sv));
EXPECT_NE(nullptr, headers);
EXPECT_TRUE(headers->holds_alternative<tr_variant::Map>());
EXPECT_TRUE(tr_variantDictFindStrView(headers, tr_quark_new("type"sv), &sv));
EXPECT_EQ("request"sv, sv);
EXPECT_TRUE(tr_variantDictFindInt(headers, TR_KEY_tag, &i));
EXPECT_EQ(666, i);
auto* body = tr_variantDictFind(&var, tr_quark_new("body"sv));
EXPECT_NE(nullptr, body);
EXPECT_TRUE(tr_variantDictFindStrView(body, TR_KEY_name, &sv));
EXPECT_EQ("torrent-info"sv, sv);
auto* args = tr_variantDictFind(body, tr_quark_new("arguments"sv));
EXPECT_NE(nullptr, args);
EXPECT_TRUE(args->holds_alternative<tr_variant::Map>());
auto* ids = tr_variantDictFind(args, TR_KEY_ids);
ASSERT_NE(nullptr, ids);
EXPECT_TRUE(ids->holds_alternative<tr_variant::Vector>());
EXPECT_EQ(2U, tr_variantListSize(ids));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(ids, 0), &i));
EXPECT_EQ(7, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(ids, 1), &i));
EXPECT_EQ(10, i);
auto* headers = map->find_if<tr_variant::Map>(tr_quark_new("headers"sv));
ASSERT_NE(headers, nullptr);
auto sv = headers->value_if<std::string_view>(tr_quark_new("type"sv));
ASSERT_TRUE(sv);
EXPECT_EQ("request"sv, *sv);
auto i = headers->value_if<int64_t>(TR_KEY_tag);
ASSERT_TRUE(i);
EXPECT_EQ(666, *i);
auto* body = map->find_if<tr_variant::Map>(tr_quark_new("body"sv));
ASSERT_NE(body, nullptr);
sv = body->value_if<std::string_view>(TR_KEY_name);
ASSERT_TRUE(sv);
EXPECT_EQ("torrent-info"sv, *sv);
auto* args = body->find_if<tr_variant::Map>(tr_quark_new("arguments"sv));
ASSERT_NE(args, nullptr);
auto* ids = args->find_if<tr_variant::Vector>(TR_KEY_ids);
ASSERT_NE(ids, nullptr);
EXPECT_EQ(2U, std::size(*ids));
i = (*ids)[0].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(7, *i);
i = (*ids)[1].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(10, *i);
}
TEST_P(JSONTest, test2)
@ -221,11 +238,12 @@ TEST_P(JSONTest, test3)
" \"leftUntilDone\": 2275655680 }"sv;
auto var = tr_variant_serde::json().inplace().parse(Input).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
auto* map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto sv = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, TR_KEY_errorString, &sv));
EXPECT_EQ("torrent not registered with this tracker 6UHsVW'*C"sv, sv);
auto sv = map->value_if<std::string_view>(TR_KEY_errorString);
ASSERT_TRUE(sv);
EXPECT_EQ("torrent not registered with this tracker 6UHsVW'*C"sv, *sv);
}
TEST_P(JSONTest, unescape)
@ -233,11 +251,12 @@ TEST_P(JSONTest, unescape)
static auto constexpr Input = R"({ "string-1": "\/usr\/lib" })"sv;
auto var = tr_variant_serde::json().inplace().parse(Input).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Map>());
auto* map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto sv = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, tr_quark_new("string-1"sv), &sv));
EXPECT_EQ("/usr/lib"sv, sv);
auto sv = map->value_if<std::string_view>(tr_quark_new("string-1"sv));
ASSERT_TRUE(sv);
EXPECT_EQ("/usr/lib"sv, *sv);
}
TEST_P(JSONTest, parseJsonFuzz)

View file

@ -239,15 +239,16 @@ TEST_F(MakemetaTest, announceSingleTracker)
// generate the torrent and parse it as a variant
EXPECT_FALSE(builder.make_checksums().get().has_value());
auto top = tr_variant_serde::benc().parse(builder.benc());
EXPECT_TRUE(top.has_value());
ASSERT_TRUE(top);
auto* map = top->get_if<tr_variant::Map>();
// confirm there's an "announce" entry
auto single_announce = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&*top, TR_KEY_announce, &single_announce));
EXPECT_EQ(SingleAnnounce, single_announce);
auto single_announce = map->value_if<std::string_view>(TR_KEY_announce);
ASSERT_TRUE(single_announce);
EXPECT_EQ(SingleAnnounce, *single_announce);
// confirm there's not an "announce-list" entry
EXPECT_EQ(nullptr, tr_variantDictFind(&*top, TR_KEY_announce_list));
EXPECT_EQ(map->find(TR_KEY_announce_list), std::end(*map));
}
TEST_F(MakemetaTest, announceMultiTracker)
@ -267,18 +268,18 @@ TEST_F(MakemetaTest, announceMultiTracker)
// generate the torrent and parse it as a variant
EXPECT_FALSE(builder.make_checksums().get().has_value());
auto top = tr_variant_serde::benc().parse(builder.benc());
EXPECT_TRUE(top.has_value());
ASSERT_TRUE(top);
auto* map = top->get_if<tr_variant::Map>();
// confirm there's an "announce" entry
auto single_announce = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&*top, TR_KEY_announce, &single_announce));
EXPECT_EQ(builder.announce_list().at(0).announce.sv(), single_announce);
auto single_announce = map->value_if<std::string_view>(TR_KEY_announce);
ASSERT_TRUE(single_announce);
EXPECT_EQ(builder.announce_list().at(0).announce.sv(), *single_announce);
// confirm there's an "announce-list" entry
tr_variant* announce_list_variant = nullptr;
EXPECT_TRUE(tr_variantDictFindList(&*top, TR_KEY_announce_list, &announce_list_variant));
EXPECT_NE(nullptr, announce_list_variant);
EXPECT_EQ(std::size(builder.announce_list()), tr_variantListSize(announce_list_variant));
auto* announce_list_variant = map->find_if<tr_variant::Vector>(TR_KEY_announce_list);
ASSERT_NE(announce_list_variant, nullptr);
EXPECT_EQ(std::size(builder.announce_list()), std::size(*announce_list_variant));
}
TEST_F(MakemetaTest, privateAndSourceHasDifferentInfoHash)

View file

@ -37,11 +37,14 @@ class IncompleteDirTest
protected:
void SetUp() override
{
auto const download_dir = GetParam().second;
tr_variantDictAddStr(settings(), TR_KEY_download_dir, download_dir);
auto const incomplete_dir = GetParam().first;
tr_variantDictAddStr(settings(), TR_KEY_incomplete_dir, incomplete_dir);
tr_variantDictAddBool(settings(), TR_KEY_incomplete_dir_enabled, true);
if (auto* map = settings()->get_if<tr_variant::Map>(); map != nullptr)
{
auto const download_dir = GetParam().second;
map->insert_or_assign(TR_KEY_download_dir, download_dir);
auto const incomplete_dir = GetParam().first;
map->insert_or_assign(TR_KEY_incomplete_dir, incomplete_dir);
map->insert_or_assign(TR_KEY_incomplete_dir_enabled, true);
}
SessionTest::SetUp();
}

View file

@ -32,38 +32,43 @@ using RpcTest = SessionTest;
TEST_F(RpcTest, list)
{
auto i = int64_t{};
auto sv = std::string_view{};
auto top = tr_rpc_parse_list_str("12"sv);
EXPECT_TRUE(top.holds_alternative<int64_t>());
EXPECT_TRUE(tr_variantGetInt(&top, &i));
EXPECT_EQ(12, i);
auto i = top.value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(12, *i);
top = tr_rpc_parse_list_str("6,7"sv);
EXPECT_TRUE(top.holds_alternative<tr_variant::Vector>());
EXPECT_EQ(2U, tr_variantListSize(&top));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 0), &i));
EXPECT_EQ(6, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 1), &i));
EXPECT_EQ(7, i);
auto* v = top.get_if<tr_variant::Vector>();
ASSERT_NE(v, nullptr);
EXPECT_EQ(2U, std::size(*v));
i = (*v)[0].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(6, *i);
i = (*v)[1].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(7, *i);
top = tr_rpc_parse_list_str("asdf"sv);
EXPECT_TRUE(top.holds_alternative<std::string_view>());
EXPECT_TRUE(tr_variantGetStrView(&top, &sv));
EXPECT_EQ("asdf"sv, sv);
auto sv = top.value_if<std::string_view>();
ASSERT_TRUE(sv);
EXPECT_EQ("asdf"sv, *sv);
top = tr_rpc_parse_list_str("1,3-5"sv);
EXPECT_TRUE(top.holds_alternative<tr_variant::Vector>());
EXPECT_EQ(4U, tr_variantListSize(&top));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 0), &i));
EXPECT_EQ(1, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 1), &i));
EXPECT_EQ(3, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 2), &i));
EXPECT_EQ(4, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 3), &i));
EXPECT_EQ(5, i);
v = top.get_if<tr_variant::Vector>();
ASSERT_NE(v, nullptr);
EXPECT_EQ(4U, std::size(*v));
i = (*v)[0].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(1, *i);
i = (*v)[1].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(3, *i);
i = (*v)[2].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(4, *i);
i = (*v)[3].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(5, *i);
}
TEST_F(RpcTest, tagSync)
@ -154,18 +159,18 @@ TEST_F(RpcTest, sessionGet)
auto* tor = zeroTorrentInit(ZeroTorrentState::NoFiles);
EXPECT_NE(nullptr, tor);
auto request = tr_variant{};
tr_variantInitDict(&request, 1);
tr_variantDictAddStrView(&request, TR_KEY_method, "session-get");
auto request_map = tr_variant::Map{ 1U };
request_map.try_emplace(TR_KEY_method, "session-get"sv);
auto response = tr_variant{};
tr_rpc_request_exec(
session_,
request,
std::move(request_map),
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
EXPECT_TRUE(response.holds_alternative<tr_variant::Map>());
tr_variant* args = nullptr;
EXPECT_TRUE(tr_variantDictFindDict(&response, TR_KEY_arguments, &args));
auto* response_map = response.get_if<tr_variant::Map>();
ASSERT_NE(response_map, nullptr);
auto* args_map = response_map->find_if<tr_variant::Map>(TR_KEY_arguments);
ASSERT_NE(args_map, nullptr);
// what we expected
static auto constexpr ExpectedKeys = std::array{
@ -233,10 +238,7 @@ TEST_F(RpcTest, sessionGet)
// what we got
std::set<tr_quark> actual_keys;
auto key = tr_quark{};
tr_variant* val = nullptr;
auto n = size_t{};
while ((tr_variantDictChild(args, n++, &key, &val)))
for (auto const& [key, val] : *args_map)
{
actual_keys.insert(key);
}
@ -268,35 +270,36 @@ TEST_F(RpcTest, torrentGet)
auto* tor = zeroTorrentInit(ZeroTorrentState::NoFiles);
EXPECT_NE(nullptr, tor);
tr_variant request;
tr_variantInitDict(&request, 1);
auto request = tr_variant::Map{ 1U };
tr_variantDictAddStrView(&request, TR_KEY_method, "torrent-get");
request.try_emplace(TR_KEY_method, "torrent-get");
tr_variant* args_in = tr_variantDictAddDict(&request, TR_KEY_arguments, 1);
tr_variant* fields = tr_variantDictAddList(args_in, TR_KEY_fields, 1);
tr_variantListAddStrView(fields, tr_quark_get_string_view(TR_KEY_id));
auto args_in = tr_variant::Map{ 1U };
auto fields = tr_variant::Vector{};
fields.emplace_back(tr_quark_get_string_view(TR_KEY_id));
args_in.try_emplace(TR_KEY_fields, std::move(fields));
request.try_emplace(TR_KEY_arguments, std::move(args_in));
auto response = tr_variant{};
tr_rpc_request_exec(
session_,
request,
std::move(request),
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
EXPECT_TRUE(response.holds_alternative<tr_variant::Map>());
tr_variant* args = nullptr;
EXPECT_TRUE(tr_variantDictFindDict(&response, TR_KEY_arguments, &args));
auto* response_map = response.get_if<tr_variant::Map>();
ASSERT_NE(response_map, nullptr);
auto* args_out = response_map->find_if<tr_variant::Map>(TR_KEY_arguments);
ASSERT_NE(args_out, nullptr);
tr_variant* torrents = nullptr;
EXPECT_TRUE(tr_variantDictFindList(args, TR_KEY_torrents, &torrents));
EXPECT_EQ(1UL, tr_variantListSize(torrents));
auto* torrents = args_out->find_if<tr_variant::Vector>(TR_KEY_torrents);
ASSERT_NE(torrents, nullptr);
EXPECT_EQ(1UL, std::size(*torrents));
tr_variant* first_torrent = tr_variantListChild(torrents, 0);
EXPECT_TRUE(first_torrent != nullptr);
EXPECT_TRUE(first_torrent->holds_alternative<tr_variant::Map>());
int64_t first_torrent_id = 0;
EXPECT_TRUE(tr_variantDictFindInt(first_torrent, TR_KEY_id, &first_torrent_id));
EXPECT_EQ(1, first_torrent_id);
auto* first_torrent = (*torrents)[0].get_if<tr_variant::Map>();
ASSERT_NE(first_torrent, nullptr);
auto first_torrent_id = first_torrent->value_if<int64_t>(TR_KEY_id);
ASSERT_TRUE(first_torrent_id);
EXPECT_EQ(1, *first_torrent_id);
// cleanup
tr_torrentRemove(tor, false, nullptr, nullptr, nullptr, nullptr);

View file

@ -283,14 +283,16 @@ TEST_F(SessionTest, sessionId)
TEST_F(SessionTest, getDefaultSettingsIncludesSubmodules)
{
auto settings = tr_sessionGetDefaultSettings();
auto* settings_map = settings.get_if<tr_variant::Map>();
ASSERT_NE(settings_map, nullptr);
// Choose a setting from each of [tr_session, tr_session_alt_speeds, tr_rpc_server] to test all of them.
// These are all `false` by default
for (auto const& key : { TR_KEY_peer_port_random_on_start, TR_KEY_alt_speed_time_enabled, TR_KEY_rpc_enabled })
{
auto flag = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&settings, key, &flag));
EXPECT_FALSE(flag);
auto flag = settings_map->value_if<bool>(key);
ASSERT_TRUE(flag);
EXPECT_FALSE(*flag);
}
}
@ -304,10 +306,11 @@ TEST_F(SessionTest, honorsSettings)
// Choose a setting from each of [tr_session, tr_session_alt_speeds, tr_rpc_server] to test all of them.
// These are all `false` by default
auto settings = tr_sessionGetDefaultSettings();
auto* settings_map = settings.get_if<tr_variant::Map>();
ASSERT_NE(settings_map, nullptr);
for (auto const& key : { TR_KEY_peer_port_random_on_start, TR_KEY_alt_speed_time_enabled, TR_KEY_rpc_enabled })
{
tr_variantDictRemove(&settings, key);
tr_variantDictAddBool(&settings, key, true);
settings_map->insert_or_assign(key, true);
}
auto* session = tr_sessionInit(sandboxDir().data(), false, settings);
@ -332,11 +335,13 @@ TEST_F(SessionTest, savesSettings)
// Choose a setting from each of [tr_session, tr_session_alt_speeds, tr_rpc_server] to test all of them.
auto settings = tr_sessionGetSettings(session_);
auto* settings_map = settings.get_if<tr_variant::Map>();
ASSERT_NE(settings_map, nullptr);
for (auto const& key : { TR_KEY_peer_port_random_on_start, TR_KEY_alt_speed_time_enabled, TR_KEY_rpc_enabled })
{
auto flag = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&settings, key, &flag));
EXPECT_TRUE(flag);
auto flag = settings_map->value_if<bool>(key);
ASSERT_TRUE(flag);
EXPECT_TRUE(*flag);
}
}

View file

@ -39,10 +39,9 @@ TEST_F(SettingsTest, canLoadBools)
auto settings = tr_session::Settings{};
auto const expected_value = !settings.seed_queue_enabled;
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddBool(&var, Key, expected_value);
settings.load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, expected_value);
settings.load(tr_variant{ std::move(map) });
EXPECT_EQ(expected_value, settings.seed_queue_enabled);
}
@ -56,9 +55,11 @@ TEST_F(SettingsTest, canSaveBools)
settings.seed_queue_enabled = expected_value;
auto var = settings.save();
auto val = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&var, Key, &val));
EXPECT_EQ(expected_value, val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<bool>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(expected_value, *val);
}
TEST_F(SettingsTest, canLoadDoubles)
@ -68,10 +69,9 @@ TEST_F(SettingsTest, canLoadDoubles)
auto settings = tr_session::Settings{};
auto const expected_value = settings.ratio_limit + 1.0;
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddReal(&var, Key, expected_value);
settings.load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, expected_value);
settings.load(tr_variant{ std::move(map) });
EXPECT_NEAR(expected_value, settings.ratio_limit, 0.001);
}
@ -85,9 +85,11 @@ TEST_F(SettingsTest, canSaveDoubles)
settings.seed_queue_enabled = expected_value;
auto var = settings.save();
auto val = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&var, Key, &val));
EXPECT_EQ(expected_value, val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<bool>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(expected_value, *val);
}
TEST_F(SettingsTest, canLoadEncryptionMode)
@ -98,17 +100,15 @@ TEST_F(SettingsTest, canLoadEncryptionMode)
auto settings = std::make_unique<tr_session::Settings>();
ASSERT_NE(ExpectedValue, settings->encryption_mode);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue);
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->encryption_mode);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "required");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "required"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->encryption_mode);
}
@ -122,9 +122,11 @@ TEST_F(SettingsTest, canSaveEncryptionMode)
settings.encryption_mode = ExpectedValue;
auto var = settings.save();
auto val = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val));
EXPECT_EQ(ExpectedValue, val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<int64_t>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(ExpectedValue, *val);
}
TEST_F(SettingsTest, canLoadLogLevel)
@ -136,17 +138,15 @@ TEST_F(SettingsTest, canLoadLogLevel)
auto constexpr ExpectedValue = TR_LOG_DEBUG;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue);
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->log_level);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "debug");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "debug"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->log_level);
}
@ -161,9 +161,11 @@ TEST_F(SettingsTest, canSaveLogLevel)
settings.log_level = ExpectedValue;
auto var = settings.save();
auto val = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val));
EXPECT_EQ(ExpectedValue, val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<int64_t>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(ExpectedValue, *val);
}
TEST_F(SettingsTest, canLoadMode)
@ -175,17 +177,15 @@ TEST_F(SettingsTest, canLoadMode)
auto constexpr ExpectedValue = tr_mode_t{ 0777 };
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue);
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->umask);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "0777");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "0777"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->umask);
}
@ -200,9 +200,11 @@ TEST_F(SettingsTest, canSaveMode)
settings.umask = ExpectedValue;
auto var = settings.save();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ("0777", val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<std::string_view>(Key);
ASSERT_TRUE(val);
EXPECT_EQ("0777"sv, *val);
}
TEST_F(SettingsTest, canLoadPort)
@ -214,10 +216,9 @@ TEST_F(SettingsTest, canLoadPort)
auto constexpr ExpectedValue = tr_port::from_host(8080);
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue.host());
settings.load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue.host());
settings.load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings.peer_port);
}
@ -232,9 +233,11 @@ TEST_F(SettingsTest, canSavePort)
settings.peer_port = ExpectedValue;
auto var = settings.save();
auto val = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val));
EXPECT_EQ(ExpectedValue.host(), val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<int64_t>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(ExpectedValue.host(), *val);
}
TEST_F(SettingsTest, canLoadPreallocation)
@ -246,17 +249,15 @@ TEST_F(SettingsTest, canLoadPreallocation)
auto constexpr ExpectedValue = tr_open_files::Preallocation::Full;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, static_cast<int64_t>(ExpectedValue));
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, static_cast<int64_t>(ExpectedValue));
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->preallocation_mode);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "full");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "full"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->preallocation_mode);
}
@ -271,9 +272,11 @@ TEST_F(SettingsTest, canSavePreallocation)
settings.preallocation_mode = ExpectedValue;
auto var = settings.save();
auto val = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val));
EXPECT_EQ(static_cast<int64_t>(ExpectedValue), val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<int64_t>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(static_cast<int64_t>(ExpectedValue), *val);
}
TEST_F(SettingsTest, canLoadSizeT)
@ -283,10 +286,9 @@ TEST_F(SettingsTest, canLoadSizeT)
auto settings = tr_session::Settings{};
auto const expected_value = settings.queue_stalled_minutes + 5U;
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, expected_value);
settings.load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, expected_value);
settings.load(tr_variant{ std::move(map) });
EXPECT_EQ(expected_value, settings.queue_stalled_minutes);
}
@ -299,9 +301,11 @@ TEST_F(SettingsTest, canSaveSizeT)
settings.queue_stalled_minutes = expected_value;
auto var = settings.save();
auto val = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val));
EXPECT_EQ(expected_value, static_cast<size_t>(val));
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<int64_t>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(expected_value, static_cast<size_t>(*val));
}
TEST_F(SettingsTest, canLoadString)
@ -312,10 +316,9 @@ TEST_F(SettingsTest, canLoadString)
auto settings = tr_session::Settings{};
EXPECT_NE(ChangedValue, tr_session::Settings{}.bind_address_ipv4);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, ChangedValue);
settings.load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ChangedValue);
settings.load(tr_variant{ std::move(map) });
EXPECT_EQ(ChangedValue, settings.bind_address_ipv4);
}
@ -329,9 +332,11 @@ TEST_F(SettingsTest, canSaveString)
settings.bind_address_ipv4 = ChangedValue;
auto var = settings.save();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ(ChangedValue, val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<std::string_view>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(ChangedValue, *val);
}
TEST_F(SettingsTest, canLoadTos)
@ -343,17 +348,15 @@ TEST_F(SettingsTest, canLoadTos)
auto const default_value = settings->peer_socket_tos;
ASSERT_NE(ChangedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, 0x20);
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, 0x20);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ChangedValue, settings->peer_socket_tos);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "cs1");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "cs1"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ChangedValue, settings->peer_socket_tos);
}
@ -367,9 +370,11 @@ TEST_F(SettingsTest, canSaveTos)
settings.peer_socket_tos = tr_tos_t(0x20);
auto var = settings.save();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ(ChangedValue.toString(), val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<std::string_view>(Key);
ASSERT_TRUE(val);
EXPECT_EQ(ChangedValue.toString(), *val);
}
TEST_F(SettingsTest, canLoadVerify)
@ -381,17 +386,15 @@ TEST_F(SettingsTest, canLoadVerify)
auto const default_value = settings->torrent_added_verify_mode;
ASSERT_NE(ChangedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "full");
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, "full"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ChangedValue, settings->torrent_added_verify_mode);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ChangedValue);
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, ChangedValue);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ChangedValue, settings->torrent_added_verify_mode);
}
@ -405,9 +408,11 @@ TEST_F(SettingsTest, canSaveVerify)
settings.torrent_added_verify_mode = ChangedValue;
auto var = settings.save();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ("full", val);
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<std::string_view>(Key);
ASSERT_TRUE(val);
EXPECT_EQ("full"sv, *val);
}
TEST_F(SettingsTest, canLoadPreferredTransport)
@ -419,17 +424,15 @@ TEST_F(SettingsTest, canLoadPreferredTransport)
auto const default_value = settings->preferred_transport;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue);
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->preferred_transport);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "tcp");
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, "tcp"sv);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->preferred_transport);
}
@ -442,13 +445,13 @@ TEST_F(SettingsTest, canSavePreferredTransport)
auto const default_value = settings.preferred_transport;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 100);
settings.preferred_transport = ExpectedValue;
var = settings.save();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ("tcp", val);
auto var = settings.save();
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val = map->value_if<std::string_view>(Key);
ASSERT_TRUE(val);
EXPECT_EQ("tcp"sv, *val);
}
TEST_F(SettingsTest, canLoadSleepPerSecondsDuringVerify)
@ -460,17 +463,15 @@ TEST_F(SettingsTest, canLoadSleepPerSecondsDuringVerify)
auto const default_value = settings->sleep_per_seconds_during_verify;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue.count());
settings->load(var);
auto map = tr_variant::Map{ 1U };
map.try_emplace(Key, ExpectedValue.count());
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->sleep_per_seconds_during_verify);
var.clear();
settings = std::make_unique<tr_session::Settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, 90);
settings->load(var);
map = tr_variant::Map{ 1U };
map.try_emplace(Key, 90);
settings->load(tr_variant{ std::move(map) });
EXPECT_EQ(ExpectedValue, settings->sleep_per_seconds_during_verify);
}
@ -483,12 +484,11 @@ TEST_F(SettingsTest, canSaveSleepPerSecondsDuringVerify)
auto const default_value = settings.sleep_per_seconds_during_verify;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 100);
settings.sleep_per_seconds_during_verify = ExpectedValue;
var = settings.save();
auto val_raw = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val_raw));
EXPECT_EQ(ExpectedValue, std::chrono::milliseconds{ val_raw });
auto var = settings.save();
auto* const map = var.get_if<tr_variant::Map>();
ASSERT_NE(map, nullptr);
auto const val_raw = map->value_if<int64_t>(Key);
ASSERT_TRUE(val_raw);
EXPECT_EQ(ExpectedValue, std::chrono::milliseconds{ *val_raw });
}

View file

@ -479,9 +479,7 @@ protected:
{
if (!settings_)
{
auto* settings = new tr_variant{};
tr_variantInitDict(settings, 10);
settings_.reset(settings);
settings_ = std::make_shared<tr_variant>(tr_variant::make_map(10U));
}
return settings_.get();

View file

@ -35,65 +35,69 @@ using VariantTest = ::testing::Test;
TEST_F(VariantTest, getType)
{
auto i = int64_t{};
auto b = bool{};
auto d = double{};
auto sv = std::string_view{};
auto v = tr_variant{};
v = 30;
EXPECT_TRUE(tr_variantGetInt(&v, &i));
EXPECT_EQ(30, i);
EXPECT_TRUE(tr_variantGetReal(&v, &d));
EXPECT_EQ(30, int(d));
EXPECT_FALSE(tr_variantGetBool(&v, &b));
EXPECT_FALSE(tr_variantGetStrView(&v, &sv));
auto i = v.value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(30, *i);
auto d = v.value_if<double>();
ASSERT_TRUE(d);
EXPECT_EQ(30, static_cast<int>(*d));
EXPECT_FALSE(v.holds_alternative<bool>());
EXPECT_FALSE(v.holds_alternative<std::string_view>());
auto strkey = "foo"sv;
v = tr_variant{ strkey };
EXPECT_FALSE(tr_variantGetBool(&v, &b));
EXPECT_TRUE(tr_variantGetStrView(&v, &sv));
EXPECT_EQ(strkey, sv);
EXPECT_NE(std::data(strkey), std::data(sv));
EXPECT_FALSE(v.holds_alternative<bool>());
auto sv = v.value_if<std::string_view>();
ASSERT_TRUE(sv);
EXPECT_EQ(strkey, *sv);
EXPECT_NE(std::data(strkey), std::data(*sv));
EXPECT_EQ(std::size(strkey), std::size(*sv));
strkey = "anything"sv;
v = tr_variant::unmanaged_string(strkey);
EXPECT_TRUE(tr_variantGetStrView(&v, &sv));
EXPECT_EQ(strkey, sv);
EXPECT_EQ(std::data(strkey), std::data(sv)); // literally the same memory
EXPECT_EQ(std::size(strkey), std::size(sv));
sv = v.value_if<std::string_view>();
ASSERT_TRUE(sv);
EXPECT_EQ(strkey, *sv);
EXPECT_EQ(std::data(strkey), std::data(*sv)); // literally the same memory
EXPECT_EQ(std::size(strkey), std::size(*sv));
strkey = "true"sv;
v = tr_variant{ strkey };
EXPECT_TRUE(tr_variantGetBool(&v, &b));
EXPECT_TRUE(b);
EXPECT_TRUE(tr_variantGetStrView(&v, &sv));
EXPECT_EQ(strkey, sv);
auto b = v.value_if<bool>();
ASSERT_TRUE(b);
EXPECT_TRUE(*b);
sv = v.value_if<std::string_view>();
ASSERT_TRUE(sv);
EXPECT_EQ(strkey, *sv);
strkey = "false"sv;
v = tr_variant{ strkey };
EXPECT_TRUE(tr_variantGetBool(&v, &b));
EXPECT_FALSE(b);
EXPECT_TRUE(tr_variantGetStrView(&v, &sv));
EXPECT_EQ(strkey, sv);
b = v.value_if<bool>();
ASSERT_TRUE(b);
EXPECT_FALSE(*b);
sv = v.value_if<std::string_view>();
ASSERT_TRUE(sv);
EXPECT_EQ(strkey, *sv);
}
TEST_F(VariantTest, parseInt)
{
auto constexpr Benc = "i64e"sv;
auto constexpr ExpectVal = int64_t{ 64 };
static auto constexpr Benc = "i64e"sv;
static auto constexpr ExpectVal = int64_t{ 64 };
auto benc = Benc;
auto const value = transmission::benc::impl::ParseInt(&benc);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ(ExpectVal, *value);
EXPECT_EQ(std::data(Benc) + std::size(Benc), std::data(benc));
}
TEST_F(VariantTest, parseIntWithMissingEnd)
{
auto constexpr Benc = "i64"sv;
static auto constexpr Benc = "i64"sv;
auto benc = Benc;
EXPECT_FALSE(transmission::benc::impl::ParseInt(&benc));
@ -102,7 +106,7 @@ TEST_F(VariantTest, parseIntWithMissingEnd)
TEST_F(VariantTest, parseIntEmptyBuffer)
{
auto constexpr Benc = ""sv;
static auto constexpr Benc = ""sv;
auto benc = Benc;
EXPECT_FALSE(transmission::benc::impl::ParseInt(&benc));
@ -111,7 +115,7 @@ TEST_F(VariantTest, parseIntEmptyBuffer)
TEST_F(VariantTest, parseIntWithBadDigits)
{
auto constexpr Benc = "i6z4e"sv;
static auto constexpr Benc = "i6z4e"sv;
auto benc = Benc;
EXPECT_FALSE(transmission::benc::impl::ParseInt(&benc));
@ -120,20 +124,19 @@ TEST_F(VariantTest, parseIntWithBadDigits)
TEST_F(VariantTest, parseNegativeInt)
{
auto constexpr Benc = "i-3e"sv;
auto constexpr Expected = int64_t{ -3 };
static auto constexpr Benc = "i-3e"sv;
static auto constexpr Expected = int64_t{ -3 };
auto benc = Benc;
auto const value = transmission::benc::impl::ParseInt(&benc);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ(Expected, *value);
EXPECT_EQ(std::data(Benc) + std::size(Benc), std::data(benc));
}
TEST_F(VariantTest, parseNegativeWithLeadingZero)
{
auto constexpr Benc = "i-03e"sv;
static auto constexpr Benc = "i-03e"sv;
auto benc = Benc;
EXPECT_FALSE(transmission::benc::impl::ParseInt(&benc));
@ -142,20 +145,19 @@ TEST_F(VariantTest, parseNegativeWithLeadingZero)
TEST_F(VariantTest, parseIntZero)
{
auto constexpr Benc = "i0e"sv;
auto constexpr Expected = int64_t{ 0 };
static auto constexpr Benc = "i0e"sv;
static auto constexpr Expected = int64_t{ 0 };
auto benc = Benc;
auto const value = transmission::benc::impl::ParseInt(&benc);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ(Expected, *value);
EXPECT_EQ(std::data(Benc) + std::size(Benc), std::data(benc));
}
TEST_F(VariantTest, parseIntWithLeadingZero)
{
auto constexpr Benc = "i04e"sv;
static auto constexpr Benc = "i04e"sv;
auto benc = Benc;
EXPECT_FALSE(transmission::benc::impl::ParseInt(&benc));
@ -176,8 +178,7 @@ TEST_F(VariantTest, str)
// good string
inout = benc = "4:boat";
value = ParseString(&inout);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ("boat"sv, *value);
EXPECT_EQ(std::data(benc) + std::size(benc), std::data(inout));
@ -190,16 +191,14 @@ TEST_F(VariantTest, str)
// empty string
inout = benc = "0:"sv;
value = ParseString(&inout);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ(""sv, *value);
EXPECT_EQ(std::data(benc) + std::size(benc), std::data(inout));
// short string
inout = benc = "3:boat";
value = ParseString(&inout);
EXPECT_TRUE(value.has_value());
assert(value.has_value());
ASSERT_TRUE(value);
EXPECT_EQ("boa"sv, *value);
EXPECT_EQ(std::data(benc) + benc.find('t'), std::data(inout));
}
@ -211,23 +210,27 @@ TEST_F(VariantTest, parse)
auto benc = "i64e"sv;
auto var = serde.parse(benc).value_or(tr_variant{});
auto i = int64_t{};
EXPECT_TRUE(tr_variantGetInt(&var, &i));
EXPECT_EQ(64, i);
auto i = var.value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(64, *i);
EXPECT_EQ(std::data(benc) + std::size(benc), serde.end());
var.clear();
benc = "li64ei32ei16ee"sv;
var = serde.parse(benc).value_or(tr_variant{});
EXPECT_TRUE(var.holds_alternative<tr_variant::Vector>());
auto* l = var.get_if<tr_variant::Vector>();
ASSERT_NE(l, nullptr);
EXPECT_EQ(std::data(benc) + std::size(benc), serde.end());
EXPECT_EQ(3, tr_variantListSize(&var));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&var, 0), &i));
EXPECT_EQ(64, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&var, 1), &i));
EXPECT_EQ(32, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&var, 2), &i));
EXPECT_EQ(16, i);
ASSERT_EQ(3, std::size(*l));
i = (*l)[0].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(64, *i);
i = (*l)[1].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(32, *i);
i = (*l)[2].value_if<int64_t>();
ASSERT_TRUE(i);
EXPECT_EQ(16, *i);
EXPECT_EQ(benc, serde.to_string(var));
var.clear();
@ -252,13 +255,7 @@ TEST_F(VariantTest, parse)
TEST_F(VariantTest, bencParseAndReencode)
{
struct LocalTest
{
std::string_view benc;
bool is_good;
};
auto constexpr Tests = std::array<LocalTest, 9>{ {
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 9>{ {
{ "llleee"sv, true },
{ "d3:cow3:moo4:spam4:eggse"sv, true },
{ "d4:spaml1:a1:bee"sv, true },
@ -273,14 +270,14 @@ TEST_F(VariantTest, bencParseAndReencode)
auto serde = tr_variant_serde::benc();
serde.inplace();
for (auto const& test : Tests)
for (auto const& [benc, is_good] : Tests)
{
auto var = serde.parse(test.benc);
EXPECT_EQ(test.is_good, var.has_value());
auto var = serde.parse(benc);
EXPECT_EQ(is_good, var.has_value());
if (var)
{
EXPECT_EQ(test.benc.data() + test.benc.size(), serde.end());
EXPECT_EQ(test.benc, serde.to_string(*var));
EXPECT_EQ(benc.data() + benc.size(), serde.end());
EXPECT_EQ(benc, serde.to_string(*var));
}
}
}
@ -329,13 +326,7 @@ TEST_F(VariantTest, bencMalformedIncompleteString)
TEST_F(VariantTest, bencToJson)
{
struct LocalTest
{
std::string_view benc;
std::string_view expected;
};
auto constexpr Tests = std::array<LocalTest, 5>{
static auto constexpr Tests = std::array<std::pair<std::string_view, std::string_view>, 5>{
{ { "i6e"sv, "6"sv },
{ "d5:helloi1e5:worldi2ee"sv, R"({"hello":1,"world":2})"sv },
{ "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee"sv, R"({"foo":[1,2,3],"hello":1,"world":2})"sv },
@ -349,10 +340,10 @@ TEST_F(VariantTest, bencToJson)
benc_serde.inplace();
json_serde.compact();
for (auto const& test : Tests)
for (auto const& [benc, expected] : Tests)
{
auto top = benc_serde.parse(test.benc).value_or(tr_variant{});
EXPECT_EQ(test.expected, json_serde.to_string(top));
auto top = benc_serde.parse(benc).value_or(tr_variant{});
EXPECT_EQ(expected, json_serde.to_string(top));
}
}
@ -368,51 +359,58 @@ TEST_F(VariantTest, merge)
auto const s8 = tr_quark_new("s8"sv);
/* initial dictionary (default values) */
tr_variant dest;
tr_variantInitDict(&dest, 10);
tr_variantDictAddInt(&dest, i1, 1);
tr_variantDictAddInt(&dest, i2, 2);
tr_variantDictAddInt(&dest, i4, -35); /* remains untouched */
tr_variantDictAddStrView(&dest, s5, "abc");
tr_variantDictAddStrView(&dest, s6, "def");
tr_variantDictAddStrView(&dest, s7, "127.0.0.1"); /* remains untouched */
auto dest = tr_variant::make_map(6U);
auto* map = dest.get_if<tr_variant::Map>();
map->try_emplace(i1, 1);
map->try_emplace(i2, 2);
map->try_emplace(i4, -35); /* remains untouched */
map->try_emplace(s5, "abc");
map->try_emplace(s6, "def");
map->try_emplace(s7, "127.0.0.1"); /* remains untouched */
/* new dictionary, will overwrite items in dest */
tr_variant src;
tr_variantInitDict(&src, 10);
tr_variantDictAddInt(&src, i1, 1); /* same value */
tr_variantDictAddInt(&src, i2, 4); /* new value */
tr_variantDictAddInt(&src, i3, 3); /* new key:value */
tr_variantDictAddStrView(&src, s5, "abc"); /* same value */
tr_variantDictAddStrView(&src, s6, "xyz"); /* new value */
tr_variantDictAddStrView(&src, s8, "ghi"); /* new key:value */
auto src = tr_variant::make_map(6U);
map = src.get_if<tr_variant::Map>();
map->try_emplace(i1, 1); /* same value */
map->try_emplace(i2, 4); /* new value */
map->try_emplace(i3, 3); /* new key:value */
map->try_emplace(s5, "abc"); /* same value */
map->try_emplace(s6, "xyz"); /* new value */
map->try_emplace(s8, "ghi"); /* new key:value */
tr_variantMergeDicts(&dest, /*const*/ &src);
dest.merge(src);
auto i = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&dest, i1, &i));
EXPECT_EQ(1, i);
EXPECT_TRUE(tr_variantDictFindInt(&dest, i2, &i));
EXPECT_EQ(4, i);
EXPECT_TRUE(tr_variantDictFindInt(&dest, i3, &i));
EXPECT_EQ(3, i);
EXPECT_TRUE(tr_variantDictFindInt(&dest, i4, &i));
EXPECT_EQ(-35, i);
auto sv = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&dest, s5, &sv));
EXPECT_EQ("abc"sv, sv);
EXPECT_TRUE(tr_variantDictFindStrView(&dest, s6, &sv));
EXPECT_EQ("xyz"sv, sv);
EXPECT_TRUE(tr_variantDictFindStrView(&dest, s7, &sv));
EXPECT_EQ("127.0.0.1"sv, sv);
EXPECT_TRUE(tr_variantDictFindStrView(&dest, s8, &sv));
EXPECT_EQ("ghi"sv, sv);
map = dest.get_if<tr_variant::Map>();
auto i = map->value_if<int64_t>(i1);
ASSERT_TRUE(i);
EXPECT_EQ(1, *i);
i = map->value_if<int64_t>(i2);
ASSERT_TRUE(i);
EXPECT_EQ(4, *i);
i = map->value_if<int64_t>(i3);
ASSERT_TRUE(i);
EXPECT_EQ(3, *i);
i = map->value_if<int64_t>(i4);
ASSERT_TRUE(i);
EXPECT_EQ(-35, *i);
auto sv = map->value_if<std::string_view>(s5);
ASSERT_TRUE(sv);
EXPECT_EQ("abc"sv, *sv);
sv = map->value_if<std::string_view>(s6);
ASSERT_TRUE(sv);
EXPECT_EQ("xyz"sv, *sv);
sv = map->value_if<std::string_view>(s7);
ASSERT_TRUE(sv);
EXPECT_EQ("127.0.0.1"sv, *sv);
sv = map->value_if<std::string_view>(s8);
ASSERT_TRUE(sv);
EXPECT_EQ("ghi"sv, *sv);
}
TEST_F(VariantTest, stackSmash)
{
// make a nested list of list of lists.
int constexpr Depth = STACK_SMASH_DEPTH;
static int constexpr Depth = STACK_SMASH_DEPTH;
std::string const in = std::string(Depth, 'l') + std::string(Depth, 'e');
// confirm that it fails instead of crashing
@ -430,42 +428,48 @@ TEST_F(VariantTest, boolAndIntRecast)
auto const key3 = tr_quark_new("key3"sv);
auto const key4 = tr_quark_new("key4"sv);
auto top = tr_variant{};
tr_variantInitDict(&top, 10);
tr_variantDictAddBool(&top, key1, false);
tr_variantDictAddBool(&top, key2, 0); // NOLINT modernize-use-bool-literals
tr_variantDictAddInt(&top, key3, true); // NOLINT readability-implicit-bool-conversion
tr_variantDictAddInt(&top, key4, 1);
auto top = tr_variant::make_map(4U);
auto* map = top.get_if<tr_variant::Map>();
map->try_emplace(key1, false);
map->try_emplace(key2, 0);
map->try_emplace(key3, true);
map->try_emplace(key4, 1);
// confirm we can read both bools and ints as bools
auto b = bool{};
EXPECT_TRUE(tr_variantDictFindBool(&top, key1, &b));
EXPECT_FALSE(b);
EXPECT_TRUE(tr_variantDictFindBool(&top, key2, &b));
EXPECT_FALSE(b);
EXPECT_TRUE(tr_variantDictFindBool(&top, key3, &b));
EXPECT_TRUE(b);
EXPECT_TRUE(tr_variantDictFindBool(&top, key4, &b));
EXPECT_TRUE(b);
auto b = map->value_if<bool>(key1);
ASSERT_TRUE(b);
EXPECT_FALSE(*b);
b = map->value_if<bool>(key2);
ASSERT_TRUE(b);
EXPECT_FALSE(*b);
b = map->value_if<bool>(key3);
ASSERT_TRUE(b);
EXPECT_TRUE(*b);
b = map->value_if<bool>(key4);
ASSERT_TRUE(b);
EXPECT_TRUE(*b);
// confirm we can read both bools and ints as ints
auto i = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&top, key1, &i));
EXPECT_EQ(0, i);
EXPECT_TRUE(tr_variantDictFindInt(&top, key2, &i));
EXPECT_EQ(0, i);
EXPECT_TRUE(tr_variantDictFindInt(&top, key3, &i));
EXPECT_NE(0, i);
EXPECT_TRUE(tr_variantDictFindInt(&top, key4, &i));
EXPECT_NE(0, i);
auto i = map->value_if<int64_t>(key1);
ASSERT_TRUE(i);
EXPECT_EQ(0, *i);
i = map->value_if<int64_t>(key2);
ASSERT_TRUE(i);
EXPECT_EQ(0, *i);
i = map->value_if<int64_t>(key3);
ASSERT_TRUE(i);
EXPECT_NE(0, *i);
i = map->value_if<int64_t>(key4);
ASSERT_TRUE(i);
EXPECT_NE(0, *i);
}
TEST_F(VariantTest, dictFindType)
{
auto constexpr ExpectedStr = "this-is-a-string"sv;
auto constexpr ExpectedBool = true;
auto constexpr ExpectedInt = 1234;
auto constexpr ExpectedReal = 0.3;
static auto constexpr ExpectedStr = "this-is-a-string"sv;
static auto constexpr ExpectedBool = true;
static auto constexpr ExpectedInt = 1234;
static auto constexpr ExpectedReal = 0.3;
auto const key_bool = tr_quark_new("this-is-a-bool"sv);
auto const key_real = tr_quark_new("this-is-a-real"sv);
@ -474,50 +478,50 @@ TEST_F(VariantTest, dictFindType)
auto const key_unknown = tr_quark_new("this-is-a-missing-entry"sv);
// populate a dict
tr_variant top;
tr_variantInitDict(&top, 0);
tr_variantDictAddBool(&top, key_bool, ExpectedBool);
tr_variantDictAddInt(&top, key_int, ExpectedInt);
tr_variantDictAddReal(&top, key_real, ExpectedReal);
tr_variantDictAddStr(&top, key_str, ExpectedStr.data());
auto top = tr_variant::make_map(4U);
auto* map = top.get_if<tr_variant::Map>();
map->try_emplace(key_bool, ExpectedBool);
map->try_emplace(key_int, ExpectedInt);
map->try_emplace(key_real, ExpectedReal);
map->try_emplace(key_str, ExpectedStr);
// look up the keys as strings
auto sv = std::string_view{};
EXPECT_FALSE(tr_variantDictFindStrView(&top, key_bool, &sv));
EXPECT_FALSE(tr_variantDictFindStrView(&top, key_real, &sv));
EXPECT_FALSE(tr_variantDictFindStrView(&top, key_int, &sv));
EXPECT_TRUE(tr_variantDictFindStrView(&top, key_str, &sv));
EXPECT_EQ(ExpectedStr, sv);
EXPECT_TRUE(tr_variantDictFindStrView(&top, key_str, &sv));
EXPECT_EQ(ExpectedStr, sv);
EXPECT_FALSE(tr_variantDictFindStrView(&top, key_unknown, &sv));
EXPECT_FALSE(tr_variantDictFindStrView(&top, key_unknown, &sv));
EXPECT_FALSE(map->value_if<std::string_view>(key_bool));
EXPECT_FALSE(map->value_if<std::string_view>(key_real));
EXPECT_FALSE(map->value_if<std::string_view>(key_int));
auto sv = map->value_if<std::string_view>(key_str);
ASSERT_TRUE(sv);
EXPECT_EQ(ExpectedStr, *sv);
EXPECT_FALSE(map->value_if<std::string_view>(key_unknown));
// look up the keys as bools
auto b = bool{};
EXPECT_FALSE(tr_variantDictFindBool(&top, key_int, &b));
EXPECT_FALSE(tr_variantDictFindBool(&top, key_real, &b));
EXPECT_FALSE(tr_variantDictFindBool(&top, key_str, &b));
EXPECT_TRUE(tr_variantDictFindBool(&top, key_bool, &b));
EXPECT_FALSE(map->value_if<bool>(key_int));
EXPECT_FALSE(map->value_if<bool>(key_real));
EXPECT_FALSE(map->value_if<bool>(key_str));
auto b = map->value_if<bool>(key_bool);
ASSERT_TRUE(b);
EXPECT_EQ(ExpectedBool, b);
EXPECT_FALSE(map->value_if<bool>(key_unknown));
// look up the keys as doubles
auto d = double{};
EXPECT_FALSE(tr_variantDictFindReal(&top, key_bool, &d));
EXPECT_TRUE(tr_variantDictFindReal(&top, key_int, &d));
EXPECT_EQ(ExpectedInt, std::lrint(d));
EXPECT_FALSE(tr_variantDictFindReal(&top, key_str, &d));
EXPECT_TRUE(tr_variantDictFindReal(&top, key_real, &d));
EXPECT_EQ(std::lrint(ExpectedReal * 100), std::lrint(d * 100));
EXPECT_FALSE(map->value_if<double>(key_bool));
auto d = map->value_if<double>(key_int);
ASSERT_TRUE(d);
EXPECT_EQ(static_cast<double>(ExpectedInt), *d);
EXPECT_FALSE(map->value_if<double>(key_str));
d = map->value_if<double>(key_real);
ASSERT_TRUE(d);
EXPECT_EQ(ExpectedReal, *d);
// look up the keys as ints
auto i = int64_t{};
EXPECT_TRUE(tr_variantDictFindInt(&top, key_bool, &i));
EXPECT_EQ(ExpectedBool ? 1 : 0, i);
EXPECT_FALSE(tr_variantDictFindInt(&top, key_real, &i));
EXPECT_FALSE(tr_variantDictFindInt(&top, key_str, &i));
EXPECT_TRUE(tr_variantDictFindInt(&top, key_int, &i));
EXPECT_EQ(ExpectedInt, i);
auto i = map->value_if<int64_t>(key_bool);
ASSERT_TRUE(i);
EXPECT_EQ(ExpectedBool ? 1 : 0, *i);
EXPECT_FALSE(map->value_if<int64_t>(key_real));
EXPECT_FALSE(map->value_if<int64_t>(key_str));
i = map->value_if<int64_t>(key_int);
ASSERT_TRUE(i);
EXPECT_EQ(ExpectedInt, *i);
}
TEST_F(VariantTest, variantFromBufFuzz)