2020-08-11 18:11:55 +00:00
|
|
|
/*
|
|
|
|
* This file Copyright (C) 2013-2014 Mnemosyne LLC
|
|
|
|
*
|
|
|
|
* It may be used under the GNU GPL versions 2 or 3
|
|
|
|
* or any future license endorsed by Mnemosyne LLC.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define LIBTRANSMISSION_VARIANT_MODULE
|
|
|
|
|
2021-10-20 02:30:50 +00:00
|
|
|
#include <clocale> // setlocale()
|
|
|
|
#include <cstring> // strlen()
|
|
|
|
#include <string>
|
|
|
|
#include <string_view>
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
#include "transmission.h"
|
|
|
|
#include "utils.h" // tr_free()
|
|
|
|
#include "variant.h"
|
|
|
|
#include "variant-common.h"
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
2021-10-15 13:28:47 +00:00
|
|
|
using namespace std::literals;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
class JSONTest : public ::testing::TestWithParam<char const*>
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
void SetUp() override
|
|
|
|
{
|
|
|
|
auto const* locale_str = GetParam();
|
|
|
|
if (setlocale(LC_NUMERIC, locale_str) == nullptr)
|
|
|
|
{
|
|
|
|
GTEST_SKIP();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_P(JSONTest, testElements)
|
|
|
|
{
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const in = std::string{
|
2020-08-11 18:11:55 +00:00
|
|
|
"{ \"string\": \"hello world\","
|
|
|
|
" \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\","
|
|
|
|
" \"int\": 5, "
|
|
|
|
" \"float\": 6.5, "
|
|
|
|
" \"true\": true, "
|
|
|
|
" \"false\": false, "
|
|
|
|
" \"null\": null }"
|
|
|
|
};
|
|
|
|
|
|
|
|
tr_variant top;
|
|
|
|
int err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
auto sv = std::string_view{};
|
2021-10-15 13:28:47 +00:00
|
|
|
auto key = tr_quark_new("string"sv);
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
|
|
|
|
EXPECT_EQ("hello world"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, tr_quark_new("escaped"sv), &sv));
|
|
|
|
EXPECT_EQ("bell \b formfeed \f linefeed \n carriage return \r tab \t"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
auto i = int64_t{};
|
2021-10-15 13:28:47 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindInt(&top, tr_quark_new("int"sv), &i));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(5, i);
|
|
|
|
|
|
|
|
auto d = double{};
|
2021-10-15 13:28:47 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindReal(&top, tr_quark_new("float"sv), &d));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(65, int(d * 10));
|
|
|
|
|
|
|
|
auto f = bool{};
|
2021-10-15 13:28:47 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindBool(&top, tr_quark_new("true"sv), &f));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(f);
|
|
|
|
|
2021-10-15 13:28:47 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindBool(&top, tr_quark_new("false"sv), &f));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_FALSE(f);
|
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, tr_quark_new("null"sv), &sv));
|
|
|
|
EXPECT_EQ(""sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
{
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(JSONTest, testUtf8)
|
|
|
|
{
|
2021-08-15 09:41:48 +00:00
|
|
|
auto in = std::string{ "{ \"key\": \"Letöltések\" }" };
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_variant top;
|
2021-11-12 18:04:55 +00:00
|
|
|
auto sv = std::string_view{};
|
2020-08-11 18:11:55 +00:00
|
|
|
char* json;
|
|
|
|
int err;
|
2021-10-15 13:28:47 +00:00
|
|
|
tr_quark const key = tr_quark_new("key"sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
|
|
|
|
EXPECT_EQ("Letöltések"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
{
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
in = std::string{ R"({ "key": "\u005C" })" };
|
2020-08-11 18:11:55 +00:00
|
|
|
err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
|
|
|
|
EXPECT_EQ("\\"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
{
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 1. Feed it JSON-escaped nonascii to the JSON decoder.
|
|
|
|
* 2. Confirm that the result is UTF-8.
|
|
|
|
* 3. Feed the same UTF-8 back into the JSON encoder.
|
|
|
|
* 4. Confirm that the result is JSON-escaped.
|
|
|
|
* 5. Dogfood that result back into the parser.
|
|
|
|
* 6. Confirm that the result is UTF-8.
|
|
|
|
*/
|
2021-08-15 09:41:48 +00:00
|
|
|
in = std::string{ R"({ "key": "Let\u00f6lt\u00e9sek" })" };
|
2020-08-11 18:11:55 +00:00
|
|
|
err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
|
|
|
|
EXPECT_EQ("Letöltések"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
json = tr_variantToStr(&top, TR_VARIANT_FMT_JSON, nullptr);
|
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
{
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_NE(nullptr, json);
|
|
|
|
EXPECT_NE(nullptr, strstr(json, "\\u00f6"));
|
|
|
|
EXPECT_NE(nullptr, strstr(json, "\\u00e9"));
|
|
|
|
err = tr_variantFromJson(&top, json, strlen(json));
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
|
|
|
|
EXPECT_EQ("Letöltések"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
{
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
|
|
|
tr_free(json);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(JSONTest, test1)
|
|
|
|
{
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const in = std::string{
|
2020-08-11 18:11:55 +00:00
|
|
|
"{\n"
|
|
|
|
" \"headers\": {\n"
|
|
|
|
" \"type\": \"request\",\n"
|
|
|
|
" \"tag\": 666\n"
|
|
|
|
" },\n"
|
|
|
|
" \"body\": {\n"
|
|
|
|
" \"name\": \"torrent-info\",\n"
|
|
|
|
" \"arguments\": {\n"
|
|
|
|
" \"ids\": [ 7, 10 ]\n"
|
|
|
|
" }\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n"
|
|
|
|
};
|
|
|
|
|
|
|
|
tr_variant top;
|
|
|
|
auto const err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
auto sv = std::string_view{};
|
2020-08-11 18:11:55 +00:00
|
|
|
int64_t i;
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(&top));
|
2021-10-15 13:28:47 +00:00
|
|
|
auto* headers = tr_variantDictFind(&top, tr_quark_new("headers"sv));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, headers);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(headers));
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(headers, tr_quark_new("type"sv), &sv));
|
|
|
|
EXPECT_EQ("request"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindInt(headers, TR_KEY_tag, &i));
|
|
|
|
EXPECT_EQ(666, i);
|
2021-10-15 13:28:47 +00:00
|
|
|
auto* body = tr_variantDictFind(&top, tr_quark_new("body"sv));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, body);
|
2021-11-12 18:04:55 +00:00
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(body, TR_KEY_name, &sv));
|
|
|
|
EXPECT_EQ("torrent-info"sv, sv);
|
2021-10-15 13:28:47 +00:00
|
|
|
auto* args = tr_variantDictFind(body, tr_quark_new("arguments"sv));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, args);
|
|
|
|
EXPECT_TRUE(tr_variantIsDict(args));
|
|
|
|
auto* ids = tr_variantDictFind(args, TR_KEY_ids);
|
|
|
|
EXPECT_NE(nullptr, ids);
|
|
|
|
EXPECT_TRUE(tr_variantIsList(ids));
|
|
|
|
EXPECT_EQ(2, 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);
|
|
|
|
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(JSONTest, test2)
|
|
|
|
{
|
|
|
|
tr_variant top;
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const in = std::string{ " " };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
top.type = 0;
|
|
|
|
int err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
|
|
|
|
EXPECT_NE(0, err);
|
|
|
|
EXPECT_FALSE(tr_variantIsDict(&top));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(JSONTest, test3)
|
|
|
|
{
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const in = std::string{
|
2020-08-11 18:11:55 +00:00
|
|
|
"{ \"error\": 2,"
|
|
|
|
" \"errorString\": \"torrent not registered with this tracker 6UHsVW'*C\","
|
|
|
|
" \"eta\": 262792,"
|
|
|
|
" \"id\": 25,"
|
|
|
|
" \"leftUntilDone\": 2275655680 }"
|
|
|
|
};
|
|
|
|
|
|
|
|
tr_variant top;
|
|
|
|
auto const err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
auto sv = std::string_view{};
|
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, TR_KEY_errorString, &sv));
|
|
|
|
EXPECT_EQ("torrent not registered with this tracker 6UHsVW'*C"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(JSONTest, unescape)
|
|
|
|
{
|
|
|
|
tr_variant top;
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const in = std::string{ R"({ "string-1": "\/usr\/lib" })" };
|
2020-08-11 18:11:55 +00:00
|
|
|
int const err = tr_variantFromJson(&top, in.data(), in.size());
|
|
|
|
EXPECT_EQ(0, err);
|
|
|
|
|
2021-11-12 18:04:55 +00:00
|
|
|
auto sv = std::string_view{};
|
|
|
|
EXPECT_TRUE(tr_variantDictFindStrView(&top, tr_quark_new("string-1"sv), &sv));
|
|
|
|
EXPECT_EQ("/usr/lib"sv, sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_variantFree(&top);
|
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P( //
|
2020-08-11 18:11:55 +00:00
|
|
|
JSON,
|
|
|
|
JSONTest,
|
2021-08-15 09:41:48 +00:00
|
|
|
::testing::Values( //
|
|
|
|
"C",
|
|
|
|
"da_DK.UTF-8",
|
|
|
|
"fr_FR.UTF-8",
|
|
|
|
"ru_RU.UTF-8"));
|