/* 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 .
*/
#include "catch2/catch_test_macros.hpp"
#include "ducktorrent/parser.hpp"
#define INPUT1_BINARY_BLOB "Njw\0XLóPO_æ5iÄ@\\#ú·
void check_map_entry (
const std::map& 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(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& main_map =
boost::get<
boost::spirit::x3::forward_ast< std::map >
>(root).get();
check_map_entry(main_map, "announce", "http://bttracker.debian.org:6969/announce", 1);
check_map_entry(main_map, "comment", "Debian CD from cdimage.debian.org", 1);
check_map_entry(main_map, "created by", "mktorrent 1.1", 1);
check_map_entry(main_map, "creation date", 1742039925, 0);
REQUIRE(main_map.contains("info"));
REQUIRE(main_map.at("info").get().which() == 3);
const std::map& info_map =
boost::get<
boost::spirit::x3::forward_ast< std::map >
>(main_map.at("info")).get();
check_map_entry(info_map, "name", "debian-12.10.0-amd64-netinst.iso", 1);
check_map_entry(info_map, "piece length", 262144, 0);
check_map_entry(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);
}