115 lines
4.6 KiB
C++
115 lines
4.6 KiB
C++
/* Copyright 2025, Michele "King_DuckZ" Santullo
|
||
* This file is part of ducktorrent.
|
||
*
|
||
* Ducktorrent is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* Ducktorrent is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with ducktorrent. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "catch2/catch_test_macros.hpp"
|
||
#include "ducktorrent/parser.hpp"
|
||
|
||
#define INPUT1_BINARY_BLOB "Njw\0XLóPO_æ5iÄ@\\#ú·<jâ"
|
||
|
||
namespace {
|
||
constexpr char g_input1_binary_blob[] = INPUT1_BINARY_BLOB;
|
||
constexpr auto g_input1_binary_blob_size = sizeof(g_input1_binary_blob) / sizeof(g_input1_binary_blob[0]) - 1;
|
||
constexpr char g_input1[] = "d8:announce41:http://bttracker.debian.org:6969/ann"
|
||
"ounce7:comment33:Debian CD from cdimage.debian.org10:created by13:mktorren"
|
||
"t 1.113:creation datei1742039925e4:infod6:lengthi663748608e4:name32:debian"
|
||
"-12.10.0-amd64-netinst.iso12:piece lengthi262144e6:pieces40:"
|
||
INPUT1_BINARY_BLOB "ee";
|
||
constexpr auto g_input1_size = sizeof(g_input1) / sizeof(g_input1[0]) - 1u;
|
||
|
||
constexpr char g_input2[] = "hello world";
|
||
constexpr auto g_input2_size = sizeof(g_input2) / sizeof(g_input2[0]) - 1u;
|
||
|
||
constexpr char g_input3[] = "d5:helloe";
|
||
constexpr auto g_input3_size = sizeof(g_input3) / sizeof(g_input3[0]) - 1u;
|
||
|
||
constexpr char g_input4[] = "d5:hello5:worldee";
|
||
constexpr auto g_input4_size = sizeof(g_input4) / sizeof(g_input4[0]) - 1u;
|
||
|
||
constexpr char g_input5[] = "d5:hello5:world";
|
||
constexpr auto g_input5_size = sizeof(g_input5) / sizeof(g_input5[0]) - 1u;
|
||
|
||
constexpr char g_input6[] = "d5:hello100:worlde";
|
||
constexpr auto g_input6_size = sizeof(g_input6) / sizeof(g_input6[0]) - 1u;
|
||
|
||
template <typename T>
|
||
void check_map_entry (
|
||
const std::map<duck::TorrentStringType, duck::TorrentValue>& map,
|
||
duck::TorrentStringType key,
|
||
T expected,
|
||
int expected_var_which
|
||
) {
|
||
REQUIRE(map.contains(key));
|
||
REQUIRE(map.at(key).get().which() == expected_var_which);
|
||
const auto& val = boost::get<T>(map.at(key));
|
||
CHECK(val == expected);
|
||
}
|
||
} //unnamed namespace
|
||
|
||
TEST_CASE ("Parse valid bencoded test input", "[parse][bencoding]") {
|
||
using duck::TorrentStringType;
|
||
using duck::TorrentIntType;
|
||
|
||
auto res = duck::parse_torrent(std::string_view{g_input1, g_input1_size});
|
||
REQUIRE(res.size() == 1);
|
||
|
||
const duck::TorrentValue& root = res.front();
|
||
REQUIRE(root.get().which() == 3);
|
||
|
||
const std::map<TorrentStringType, duck::TorrentValue>& main_map =
|
||
boost::get<
|
||
boost::spirit::x3::forward_ast< std::map<TorrentStringType, duck::TorrentValue> >
|
||
>(root).get();
|
||
|
||
check_map_entry<TorrentStringType>(main_map, "announce", "http://bttracker.debian.org:6969/announce", 1);
|
||
check_map_entry<TorrentStringType>(main_map, "comment", "Debian CD from cdimage.debian.org", 1);
|
||
check_map_entry<TorrentStringType>(main_map, "created by", "mktorrent 1.1", 1);
|
||
check_map_entry<TorrentIntType>(main_map, "creation date", 1742039925, 0);
|
||
|
||
REQUIRE(main_map.contains("info"));
|
||
REQUIRE(main_map.at("info").get().which() == 3);
|
||
const std::map<TorrentStringType, duck::TorrentValue>& info_map =
|
||
boost::get<
|
||
boost::spirit::x3::forward_ast< std::map<TorrentStringType, duck::TorrentValue> >
|
||
>(main_map.at("info")).get();
|
||
|
||
check_map_entry<TorrentStringType>(info_map, "name", "debian-12.10.0-amd64-netinst.iso", 1);
|
||
check_map_entry<TorrentIntType>(info_map, "piece length", 262144, 0);
|
||
check_map_entry<TorrentStringType>(info_map, "pieces", TorrentStringType{g_input1_binary_blob, g_input1_binary_blob_size}, 1);
|
||
}
|
||
|
||
TEST_CASE ("Parse empty test input", "[parse][bencoding]") {
|
||
CHECK_THROWS_AS(duck::parse_torrent(""), duck::ParseError);
|
||
}
|
||
|
||
TEST_CASE ("Parse invalid test input", "[parse][bencoding]") {
|
||
std::string_view input;
|
||
|
||
input = std::string_view{g_input2, g_input2_size};
|
||
CHECK_THROWS_AS(duck::parse_torrent(input), duck::ParseError);
|
||
|
||
input = std::string_view{g_input3, g_input3_size};
|
||
CHECK_THROWS_AS(duck::parse_torrent(input), duck::ParseError);
|
||
|
||
input = std::string_view{g_input4, g_input4_size};
|
||
CHECK_THROWS_AS(duck::parse_torrent(input), duck::ParseError);
|
||
|
||
input = std::string_view{g_input5, g_input5_size};
|
||
CHECK_THROWS_AS(duck::parse_torrent(input), duck::ParseError);
|
||
|
||
input = std::string_view{g_input6, g_input6_size};
|
||
CHECK_THROWS_AS(duck::parse_torrent(input), duck::ParseError);
|
||
}
|