2014-01-19 01:09:44 +00:00
|
|
|
|
/*
|
|
|
|
|
* This file Copyright (C) 2013-2014 Mnemosyne LLC
|
|
|
|
|
*
|
2014-01-21 03:10:30 +00:00
|
|
|
|
* It may be used under the GNU GPL versions 2 or 3
|
2014-01-19 01:09:44 +00:00
|
|
|
|
* or any future license endorsed by Mnemosyne LLC.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2012-10-14 18:02:47 +00:00
|
|
|
|
#include "transmission.h"
|
2021-10-16 13:20:04 +00:00
|
|
|
|
|
2021-12-05 01:32:35 +00:00
|
|
|
|
#include "error.h"
|
2019-06-23 13:23:22 +00:00
|
|
|
|
#include "metainfo.h"
|
2021-12-05 01:32:35 +00:00
|
|
|
|
#include "torrent.h"
|
2017-05-13 22:38:31 +00:00
|
|
|
|
#include "utils.h"
|
2012-10-14 18:02:47 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
#include "gtest/gtest.h"
|
2012-10-14 18:02:47 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
#include <array>
|
|
|
|
|
#include <cerrno>
|
|
|
|
|
#include <cstring>
|
2021-11-04 01:36:32 +00:00
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
|
|
using namespace std::literals;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
TEST(Metainfo, magnetLink)
|
|
|
|
|
{
|
|
|
|
|
// background info @ http://wiki.theory.org/BitTorrent_Magnet-URI_Webseeding
|
|
|
|
|
char const constexpr* const MagnetLink =
|
2017-04-19 12:04:45 +00:00
|
|
|
|
"magnet:?"
|
2021-10-16 13:20:04 +00:00
|
|
|
|
"xt=urn:btih:14ffe5dd23188fd5cb53a1d47f1289db70abf31e"
|
|
|
|
|
"&dn=ubuntu_12_04_1_desktop_32_bit"
|
2017-04-19 12:04:45 +00:00
|
|
|
|
"&tr=http%3A%2F%2Ftracker.publicbt.com%2Fannounce"
|
|
|
|
|
"&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80"
|
2021-10-16 13:20:04 +00:00
|
|
|
|
"&ws=http%3A%2F%2Ftransmissionbt.com";
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
|
|
auto* ctor = tr_ctorNew(nullptr);
|
|
|
|
|
tr_ctorSetMetainfoFromMagnetLink(ctor, MagnetLink);
|
2021-10-06 14:26:07 +00:00
|
|
|
|
auto inf = tr_info{};
|
2020-08-11 18:11:55 +00:00
|
|
|
|
auto const parse_result = tr_torrentParse(ctor, &inf);
|
|
|
|
|
EXPECT_EQ(TR_PARSE_OK, parse_result);
|
|
|
|
|
EXPECT_EQ(0, inf.fileCount); // because it's a magnet link
|
2021-11-18 00:28:16 +00:00
|
|
|
|
EXPECT_EQ(2, inf.trackerCount);
|
2021-11-17 21:56:50 +00:00
|
|
|
|
if (inf.trackerCount >= 1)
|
|
|
|
|
{
|
|
|
|
|
EXPECT_STREQ("http://tracker.publicbt.com/announce", inf.trackers[0].announce);
|
|
|
|
|
}
|
|
|
|
|
if (inf.trackerCount >= 2)
|
|
|
|
|
{
|
|
|
|
|
EXPECT_STREQ("udp://tracker.publicbt.com:80", inf.trackers[1].announce);
|
|
|
|
|
}
|
2020-08-11 18:11:55 +00:00
|
|
|
|
EXPECT_EQ(1, inf.webseedCount);
|
2021-11-17 21:56:50 +00:00
|
|
|
|
if (inf.webseedCount >= 1)
|
|
|
|
|
{
|
|
|
|
|
EXPECT_STREQ("http://transmissionbt.com", inf.webseeds[0]);
|
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
2021-10-16 13:20:04 +00:00
|
|
|
|
auto* const link = tr_torrentInfoGetMagnetLink(&inf);
|
|
|
|
|
EXPECT_STREQ(MagnetLink, link);
|
|
|
|
|
tr_free(link);
|
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
|
/* cleanup */
|
|
|
|
|
tr_metainfoFree(&inf);
|
|
|
|
|
tr_ctorFree(ctor);
|
2014-06-09 02:53:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
|
#define BEFORE_PATH \
|
|
|
|
|
"d10:created by25:Transmission/2.82 (14160)13:creation datei1402280218e8:encoding5:UTF-84:infod5:filesld6:lengthi2e4:pathl"
|
|
|
|
|
#define AFTER_PATH \
|
|
|
|
|
"eed6:lengthi2e4:pathl5:b.txteee4:name3:foo12:piece lengthi32768e6:pieces20:ÞÉ`âMs¡Å;˺¬.åÂà7:privatei0eee"
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// FIXME: split these into parameterized tests?
|
|
|
|
|
TEST(Metainfo, bucket)
|
2014-06-09 02:53:04 +00:00
|
|
|
|
{
|
2020-09-07 21:19:10 +00:00
|
|
|
|
struct LocalTest
|
2017-04-19 12:04:45 +00:00
|
|
|
|
{
|
|
|
|
|
int expected_benc_err;
|
|
|
|
|
int expected_parse_result;
|
2021-11-04 01:36:32 +00:00
|
|
|
|
std::string_view benc;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-09-08 00:33:36 +00:00
|
|
|
|
auto const tests = std::array<LocalTest, 9>{
|
2020-09-07 21:19:10 +00:00
|
|
|
|
LocalTest{ 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt" AFTER_PATH },
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
|
/* allow empty components, but not =all= empty components, see bug #5517 */
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "0:5:a.txt" AFTER_PATH },
|
|
|
|
|
{ 0, TR_PARSE_ERR, BEFORE_PATH "0:0:" AFTER_PATH },
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2019-06-23 13:23:22 +00:00
|
|
|
|
/* allow path separators in a filename (replaced with '_') */
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "7:a/a.txt" AFTER_PATH },
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2019-06-23 13:23:22 +00:00
|
|
|
|
/* allow "." components (skipped) */
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "1:.5:a.txt" AFTER_PATH },
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt1:." AFTER_PATH },
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2019-06-23 13:23:22 +00:00
|
|
|
|
/* allow ".." components (replaced with "__") */
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "2:..5:a.txt" AFTER_PATH },
|
|
|
|
|
{ 0, TR_PARSE_OK, BEFORE_PATH "5:a.txt2:.." AFTER_PATH },
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
|
/* fail on empty string */
|
2021-08-15 09:41:48 +00:00
|
|
|
|
{ EILSEQ, TR_PARSE_ERR, "" },
|
2017-04-19 12:04:45 +00:00
|
|
|
|
};
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
tr_logSetLevel(TR_LOG_SILENT);
|
2014-06-09 02:53:04 +00:00
|
|
|
|
|
2020-09-08 00:33:36 +00:00
|
|
|
|
for (auto const& test : tests)
|
2014-06-09 02:53:04 +00:00
|
|
|
|
{
|
2020-08-11 18:11:55 +00:00
|
|
|
|
auto* ctor = tr_ctorNew(nullptr);
|
2021-11-04 01:36:32 +00:00
|
|
|
|
int const err = tr_ctorSetMetainfo(ctor, std::data(test.benc), std::size(test.benc));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
EXPECT_EQ(test.expected_benc_err, err);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
|
if (err == 0)
|
2014-06-09 02:53:04 +00:00
|
|
|
|
{
|
2020-08-11 18:11:55 +00:00
|
|
|
|
tr_parse_result const parse_result = tr_torrentParse(ctor, nullptr);
|
|
|
|
|
EXPECT_EQ(test.expected_parse_result, parse_result);
|
2014-06-09 02:53:04 +00:00
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
|
|
tr_ctorFree(ctor);
|
2014-06-09 02:53:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-02 11:15:31 +00:00
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
|
TEST(Metainfo, sanitize)
|
2019-06-23 13:23:22 +00:00
|
|
|
|
{
|
2020-09-07 21:19:10 +00:00
|
|
|
|
struct LocalTest
|
2019-06-23 13:23:22 +00:00
|
|
|
|
{
|
2021-11-04 01:36:32 +00:00
|
|
|
|
std::string_view input;
|
|
|
|
|
std::string_view expected_output;
|
2019-06-23 13:23:22 +00:00
|
|
|
|
bool expected_is_adjusted;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-09-08 00:33:36 +00:00
|
|
|
|
auto const tests = std::array<LocalTest, 29>{
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// skipped
|
2021-11-04 01:36:32 +00:00
|
|
|
|
LocalTest{ ""sv, ""sv, false },
|
|
|
|
|
{ "."sv, ""sv, true },
|
|
|
|
|
{ ".."sv, ""sv, true },
|
|
|
|
|
{ "....."sv, ""sv, true },
|
|
|
|
|
{ " "sv, ""sv, true },
|
|
|
|
|
{ " . "sv, ""sv, true },
|
|
|
|
|
{ ". . ."sv, ""sv, true },
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// replaced with '_'
|
2021-11-04 01:36:32 +00:00
|
|
|
|
{ "/"sv, "_"sv, true },
|
|
|
|
|
{ "////"sv, "____"sv, true },
|
|
|
|
|
{ "\\\\"sv, "__"sv, true },
|
|
|
|
|
{ "/../"sv, "_.._"sv, true },
|
|
|
|
|
{ "foo<bar:baz/boo"sv, "foo_bar_baz_boo"sv, true },
|
|
|
|
|
{ "t\0e\x01s\tt\ri\nn\fg"sv, "t_e_s_t_i_n_g"sv, true },
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// appended with '_'
|
2021-11-04 01:36:32 +00:00
|
|
|
|
{ "con"sv, "con_"sv, true },
|
|
|
|
|
{ "cOm4"sv, "cOm4_"sv, true },
|
|
|
|
|
{ "LPt9.txt"sv, "LPt9_.txt"sv, true },
|
|
|
|
|
{ "NUL.tar.gz"sv, "NUL_.tar.gz"sv, true },
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// trimmed
|
2021-11-04 01:36:32 +00:00
|
|
|
|
{ " foo"sv, "foo"sv, true },
|
|
|
|
|
{ "foo "sv, "foo"sv, true },
|
|
|
|
|
{ " foo "sv, "foo"sv, true },
|
|
|
|
|
{ "foo."sv, "foo"sv, true },
|
|
|
|
|
{ "foo..."sv, "foo"sv, true },
|
|
|
|
|
{ " foo... "sv, "foo"sv, true },
|
2020-08-11 18:11:55 +00:00
|
|
|
|
// unmodified
|
2021-11-04 01:36:32 +00:00
|
|
|
|
{ "foo"sv, "foo"sv, false },
|
|
|
|
|
{ ".foo"sv, ".foo"sv, false },
|
|
|
|
|
{ "..foo"sv, "..foo"sv, false },
|
|
|
|
|
{ "foo.bar.baz"sv, "foo.bar.baz"sv, false },
|
|
|
|
|
{ "null"sv, "null"sv, false },
|
|
|
|
|
{ "compass"sv, "compass"sv, false },
|
2019-06-23 13:23:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-11-04 01:36:32 +00:00
|
|
|
|
auto out = std::string{};
|
|
|
|
|
auto is_adjusted = bool{};
|
2020-09-08 00:33:36 +00:00
|
|
|
|
for (auto const& test : tests)
|
2019-06-23 13:23:22 +00:00
|
|
|
|
{
|
2021-11-04 01:36:32 +00:00
|
|
|
|
out.clear();
|
|
|
|
|
auto const success = tr_metainfoAppendSanitizedPathComponent(out, test.input, &is_adjusted);
|
|
|
|
|
EXPECT_EQ(!std::empty(out), success);
|
|
|
|
|
EXPECT_EQ(test.expected_output, out);
|
|
|
|
|
EXPECT_EQ(test.expected_is_adjusted, is_adjusted);
|
2019-06-23 13:23:22 +00:00
|
|
|
|
}
|
2012-10-14 18:02:47 +00:00
|
|
|
|
}
|
2021-10-15 18:13:33 +00:00
|
|
|
|
|
|
|
|
|
TEST(Metainfo, AndroidTorrent)
|
|
|
|
|
{
|
2021-12-05 01:32:35 +00:00
|
|
|
|
auto const filename = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv);
|
2021-10-15 18:13:33 +00:00
|
|
|
|
|
2021-12-05 01:32:35 +00:00
|
|
|
|
auto* ctor = tr_ctorNew(nullptr);
|
2021-10-15 18:13:33 +00:00
|
|
|
|
auto const err = tr_ctorSetMetainfoFromFile(ctor, filename.c_str());
|
|
|
|
|
EXPECT_EQ(0, err);
|
2021-12-05 01:32:35 +00:00
|
|
|
|
tr_ctorFree(ctor);
|
|
|
|
|
}
|
2021-10-15 18:13:33 +00:00
|
|
|
|
|
2021-12-05 01:32:35 +00:00
|
|
|
|
TEST(Metainfo, ctorSaveContents)
|
|
|
|
|
{
|
|
|
|
|
auto const src_filename = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv);
|
|
|
|
|
auto const tgt_filename = tr_strvJoin(::testing::TempDir(), "save-contents-test.torrent");
|
|
|
|
|
|
|
|
|
|
// try saving without passing any metainfo.
|
|
|
|
|
auto* ctor = tr_ctorNew(nullptr);
|
|
|
|
|
tr_error* error = nullptr;
|
|
|
|
|
EXPECT_FALSE(tr_ctorSaveContents(ctor, tgt_filename.c_str(), &error));
|
2021-12-06 03:12:21 +00:00
|
|
|
|
EXPECT_NE(nullptr, error);
|
|
|
|
|
if (error != nullptr)
|
|
|
|
|
{
|
|
|
|
|
EXPECT_EQ(EINVAL, error->code);
|
|
|
|
|
tr_error_clear(&error);
|
|
|
|
|
}
|
2021-12-05 01:32:35 +00:00
|
|
|
|
|
|
|
|
|
// now try saving _with_ metainfo
|
|
|
|
|
EXPECT_EQ(0, tr_ctorSetMetainfoFromFile(ctor, src_filename.c_str()));
|
|
|
|
|
EXPECT_TRUE(tr_ctorSaveContents(ctor, tgt_filename.c_str(), &error));
|
|
|
|
|
EXPECT_EQ(nullptr, error);
|
|
|
|
|
|
|
|
|
|
// the saved contents should match the source file's contents
|
|
|
|
|
auto src_contents = std::vector<char>{};
|
|
|
|
|
EXPECT_TRUE(tr_loadFile(src_contents, src_filename.c_str(), &error));
|
|
|
|
|
auto tgt_contents = std::vector<char>{};
|
|
|
|
|
EXPECT_TRUE(tr_loadFile(tgt_contents, tgt_filename.c_str(), &error));
|
|
|
|
|
EXPECT_EQ(src_contents, tgt_contents);
|
|
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
|
EXPECT_TRUE(tr_sys_path_remove(tgt_filename.c_str(), &error));
|
|
|
|
|
EXPECT_EQ(nullptr, error);
|
|
|
|
|
tr_error_clear(&error);
|
2021-10-15 18:13:33 +00:00
|
|
|
|
tr_ctorFree(ctor);
|
|
|
|
|
}
|