Add unit test

This commit is contained in:
King_DuckZ 2025-04-07 22:56:52 +01:00
parent 86c6b1ca89
commit 3f10b30efc
7 changed files with 161 additions and 0 deletions

Binary file not shown.

View file

@ -15,3 +15,7 @@ boost_dep = dependency('boost', version: '>=1.75.0')
libstriezel_dep = dependency('libstriezel')
subdir('src')
if get_option('build_testing')
subdir('test')
endif

View file

@ -1 +1,2 @@
option('build_tools', type: 'boolean', value: true, description: 'Enable or disable building the cli tools')
option('build_testing', type: 'boolean', value: true, description: 'Enable or disable building of automated test programs')

1
test/meson.build Normal file
View file

@ -0,0 +1 @@
subdir('unit')

28
test/unit/main.cpp Normal file
View file

@ -0,0 +1,28 @@
/* 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_session.hpp>
int main( int argc, char* argv[] ) {
// your setup ...
int result = Catch::Session().run( argc, argv );
// your clean-up...
return result;
}

12
test/unit/meson.build Normal file
View file

@ -0,0 +1,12 @@
catch2_dep = dependency('Catch2', version: '>=3.5.2')
unit_test_prog = executable(meson.project_name() + '_unittest',
'main.cpp',
'test_parser.cpp',
install: false,
dependencies: [ducktorrent_dep, catch2_dep],
)
test ('unit_' + meson.project_name(),
unit_test_prog
)

115
test/unit/test_parser.cpp Normal file
View file

@ -0,0 +1,115 @@
/* 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 "NjˆwŒ\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);
}