commits
tags
#include <doctest/doctest.h>
#include <filesystem>
#include <fstream>
#include "torlinkc/config/paths.hpp"
#include "torlinkc/engine/persist.hpp"
#include "test_support.hpp"
using namespace torlinkc;
using torlinkc::test::StateDirSandbox;
namespace fs = std::filesystem;
TEST_CASE("torrentExportName strips filesystem-hostile characters") {
CHECK(torrentExportName("My/Movie:2024", "id1") == "My Movie 2024.torrent");
}
TEST_CASE("torrentExportName collapses whitespace and trims trailing dots/spaces") {
CHECK(torrentExportName("Weird Name... ", "id1") == "Weird Name.torrent");
}
TEST_CASE("torrentExportName falls back to the id when the name is empty after sanitizing") {
CHECK(torrentExportName(" ", "abc123") == "abc123.torrent");
}
TEST_CASE("torrentExportName caps the length at 180 characters") {
const std::string longName(300, 'x');
auto out = torrentExportName(longName, "id1");
// 180 chars of name + ".torrent"
CHECK(out.size() == 180 + std::string(".torrent").size());
}
TEST_CASE("saveQueue/loadQueue round-trips through an atomic write") {
StateDirSandbox sandbox;
QueueItem it;
it.id = "abc";
it.name = "Test Torrent";
it.magnet = "magnet:?xt=urn:btih:" + std::string(40, 'a');
it.dir = "/tmp/downloads";
it.status = DownloadStatus::Paused;
it.progress = 42;
it.totalBytes = 1000;
it.downloadedBytes = 420;
it.eta = 12.5;
it.error = "boom";
it.addedAt = 1234;
saveQueue({it});
auto loaded = loadQueue();
REQUIRE(loaded.size() == 1);
CHECK(loaded[0].id == "abc");
CHECK(loaded[0].name == "Test Torrent");
CHECK(loaded[0].status == DownloadStatus::Paused);
CHECK(loaded[0].progress == 42);
CHECK(loaded[0].totalBytes == 1000);
CHECK(loaded[0].downloadedBytes == 420);
REQUIRE(loaded[0].eta.has_value());
CHECK(*loaded[0].eta == doctest::Approx(12.5));
REQUIRE(loaded[0].error.has_value());
CHECK(*loaded[0].error == "boom");
CHECK(loaded[0].addedAt == 1234);
}
TEST_CASE("loadQueue returns an empty vector when no file exists") {
StateDirSandbox sandbox;
CHECK(loadQueue().empty());
}
TEST_CASE("saveSeeds/loadSeeds round-trips") {
StateDirSandbox sandbox;
saveSeeds({SeedRecord{"s1", SeedStatus::Seeding}, SeedRecord{"s2", SeedStatus::Paused}});
auto loaded = loadSeeds();
REQUIRE(loaded.size() == 2);
CHECK(loaded[0].id == "s1");
CHECK(loaded[0].status == SeedStatus::Seeding);
CHECK(loaded[1].id == "s2");
CHECK(loaded[1].status == SeedStatus::Paused);
}
TEST_CASE("loadSeeds accepts the legacy bare-id-array format as all-seeding") {
StateDirSandbox sandbox;
// Write the legacy format directly, matching what an old torlink install
// could have left on disk.
fs::create_directories(fs::path(paths::seedsFile()).parent_path());
std::ofstream(paths::seedsFile()) << R"(["legacy1","legacy2"])";
auto loaded = loadSeeds();
REQUIRE(loaded.size() == 2);
CHECK(loaded[0].status == SeedStatus::Seeding);
CHECK(loaded[1].status == SeedStatus::Seeding);
}
TEST_CASE("torrent metadata cache: save, exists, export, delete") {
StateDirSandbox sandbox;
CHECK_FALSE(torrentMetaExists("t1"));
saveTorrentMeta("t1", std::string("fake bencode bytes"));
CHECK(torrentMetaExists("t1"));
fs::path exportDir = fs::temp_directory_path() / "torlinkc-test-export";
auto exported = exportTorrentMeta("t1", "My Torrent", exportDir.string());
REQUIRE(exported.has_value());
CHECK(fs::exists(*exported));
fs::remove_all(exportDir);
deleteTorrentMeta("t1");
CHECK_FALSE(torrentMetaExists("t1"));
}