fix backwards compatibility issue when loading the torrent info dict from resume data
This commit is contained in:
parent
b13ac50f4e
commit
3c8450d47c
|
@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#ifdef __MACH__
|
#ifdef __MACH__
|
||||||
#include <mach/task_info.h>
|
#include <mach/task_info.h>
|
||||||
|
|
|
@ -45,22 +45,23 @@ namespace libtorrent {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void apply_flag(std::uint64_t& current_flags
|
void apply_flag(std::uint64_t& current_flags
|
||||||
, bdecode_node const& n
|
, bdecode_node const& n
|
||||||
, char const* name
|
, char const* name
|
||||||
, std::uint64_t const flag)
|
, std::uint64_t const flag)
|
||||||
|
{
|
||||||
|
if (n.dict_find_int_value(name, 0) == 0)
|
||||||
{
|
{
|
||||||
if (n.dict_find_int_value(name, 0) == 0)
|
current_flags &= ~flag;
|
||||||
{
|
}
|
||||||
current_flags &= ~flag;
|
else
|
||||||
}
|
{
|
||||||
else
|
current_flags |= flag;
|
||||||
{
|
|
||||||
current_flags |= flag;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonyous namespace
|
||||||
|
|
||||||
add_torrent_params read_resume_data(bdecode_node const& rd, error_code& ec)
|
add_torrent_params read_resume_data(bdecode_node const& rd, error_code& ec)
|
||||||
{
|
{
|
||||||
add_torrent_params ret;
|
add_torrent_params ret;
|
||||||
|
@ -89,7 +90,6 @@ namespace {
|
||||||
|
|
||||||
ret.info_hash.assign(info_hash.data());
|
ret.info_hash.assign(info_hash.data());
|
||||||
|
|
||||||
// TODO: 4 add unit test for this, and all other fields of the resume data
|
|
||||||
bdecode_node const info = rd.dict_find_dict("info");
|
bdecode_node const info = rd.dict_find_dict("info");
|
||||||
if (info)
|
if (info)
|
||||||
{
|
{
|
||||||
|
|
|
@ -201,121 +201,128 @@ namespace libtorrent {
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void handle_backwards_compatible_resume_data(add_torrent_params& atp)
|
void handle_backwards_compatible_resume_data(add_torrent_params& atp)
|
||||||
|
{
|
||||||
|
// if there's no resume data set, there's nothing to do. It's either
|
||||||
|
// using the previous API without resume data, or the resume data has
|
||||||
|
// already been parsed out into the add_torrent_params struct.
|
||||||
|
if (atp.resume_data.empty()) return;
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
add_torrent_params resume_data
|
||||||
|
= read_resume_data(atp.resume_data, ec);
|
||||||
|
|
||||||
|
resume_data.internal_resume_data_error = ec;
|
||||||
|
if (ec) return;
|
||||||
|
|
||||||
|
// now, merge resume_data into atp according to the merge flags
|
||||||
|
if (atp.flags & add_torrent_params::flag_use_resume_save_path
|
||||||
|
&& !resume_data.save_path.empty())
|
||||||
{
|
{
|
||||||
// if there's no resume data set, there's nothing to do. It's either
|
atp.save_path = std::move(resume_data.save_path);
|
||||||
// using the previous API without resume data, or the resume data has
|
}
|
||||||
// already been parsed out into the add_torrent_params struct.
|
|
||||||
if (atp.resume_data.empty()) return;
|
|
||||||
|
|
||||||
error_code ec;
|
if (!atp.ti)
|
||||||
add_torrent_params resume_data
|
{
|
||||||
= read_resume_data(atp.resume_data, ec);
|
atp.ti = std::move(resume_data.ti);
|
||||||
|
}
|
||||||
|
|
||||||
resume_data.internal_resume_data_error = ec;
|
if (!resume_data.trackers.empty())
|
||||||
if (ec) return;
|
{
|
||||||
|
atp.tracker_tiers.resize(atp.trackers.size(), 0);
|
||||||
|
atp.trackers.insert(atp.trackers.end()
|
||||||
|
, resume_data.trackers.begin()
|
||||||
|
, resume_data.trackers.end());
|
||||||
|
atp.tracker_tiers.insert(atp.tracker_tiers.end()
|
||||||
|
, resume_data.tracker_tiers.begin()
|
||||||
|
, resume_data.tracker_tiers.end());
|
||||||
|
if ((resume_data.flags & add_torrent_params::flag_merge_resume_trackers) == 0)
|
||||||
|
atp.flags |= add_torrent_params::flag_override_trackers;
|
||||||
|
}
|
||||||
|
|
||||||
// now, merge resume_data into atp according to the merge flags
|
if (!resume_data.url_seeds.empty())
|
||||||
if (atp.flags & add_torrent_params::flag_use_resume_save_path
|
{
|
||||||
&& !resume_data.save_path.empty())
|
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
||||||
{
|
atp.url_seeds.clear();
|
||||||
atp.save_path = resume_data.save_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resume_data.trackers.empty())
|
atp.url_seeds.insert(atp.url_seeds.end()
|
||||||
{
|
, resume_data.url_seeds.begin()
|
||||||
atp.tracker_tiers.resize(atp.trackers.size(), 0);
|
, resume_data.url_seeds.end());
|
||||||
atp.trackers.insert(atp.trackers.end()
|
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
||||||
, resume_data.trackers.begin()
|
atp.flags |= add_torrent_params::flag_override_web_seeds;
|
||||||
, resume_data.trackers.end());
|
}
|
||||||
atp.tracker_tiers.insert(atp.tracker_tiers.end()
|
|
||||||
, resume_data.tracker_tiers.begin()
|
|
||||||
, resume_data.tracker_tiers.end());
|
|
||||||
if ((resume_data.flags & add_torrent_params::flag_merge_resume_trackers) == 0)
|
|
||||||
atp.flags |= add_torrent_params::flag_override_trackers;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resume_data.url_seeds.empty())
|
if (!resume_data.http_seeds.empty())
|
||||||
{
|
{
|
||||||
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
||||||
atp.url_seeds.clear();
|
atp.http_seeds.clear();
|
||||||
|
|
||||||
atp.url_seeds.insert(atp.url_seeds.end()
|
atp.http_seeds.insert(atp.http_seeds.end()
|
||||||
, resume_data.url_seeds.begin()
|
, resume_data.http_seeds.begin()
|
||||||
, resume_data.url_seeds.end());
|
, resume_data.http_seeds.end());
|
||||||
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
||||||
atp.flags |= add_torrent_params::flag_override_web_seeds;
|
atp.flags |= add_torrent_params::flag_override_web_seeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resume_data.http_seeds.empty())
|
atp.total_uploaded = resume_data.total_uploaded;
|
||||||
{
|
atp.total_downloaded = resume_data.total_downloaded;
|
||||||
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
atp.num_complete = resume_data.num_complete;
|
||||||
atp.http_seeds.clear();
|
atp.num_incomplete = resume_data.num_incomplete;
|
||||||
|
atp.num_downloaded = resume_data.num_downloaded;
|
||||||
|
atp.total_uploaded = resume_data.total_uploaded;
|
||||||
|
atp.total_downloaded = resume_data.total_downloaded;
|
||||||
|
atp.active_time = resume_data.active_time;
|
||||||
|
atp.finished_time = resume_data.finished_time;
|
||||||
|
atp.seeding_time = resume_data.seeding_time;
|
||||||
|
|
||||||
atp.http_seeds.insert(atp.http_seeds.end()
|
atp.last_seen_complete = resume_data.last_seen_complete;
|
||||||
, resume_data.http_seeds.begin()
|
atp.url = resume_data.url;
|
||||||
, resume_data.http_seeds.end());
|
atp.uuid = resume_data.uuid;
|
||||||
if ((atp.flags & add_torrent_params::flag_merge_resume_http_seeds) == 0)
|
|
||||||
atp.flags |= add_torrent_params::flag_override_web_seeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
atp.total_uploaded = resume_data.total_uploaded;
|
atp.added_time = resume_data.added_time;
|
||||||
atp.total_downloaded = resume_data.total_downloaded;
|
atp.completed_time = resume_data.completed_time;
|
||||||
atp.num_complete = resume_data.num_complete;
|
|
||||||
atp.num_incomplete = resume_data.num_incomplete;
|
|
||||||
atp.num_downloaded = resume_data.num_downloaded;
|
|
||||||
atp.total_uploaded = resume_data.total_uploaded;
|
|
||||||
atp.total_downloaded = resume_data.total_downloaded;
|
|
||||||
atp.active_time = resume_data.active_time;
|
|
||||||
atp.finished_time = resume_data.finished_time;
|
|
||||||
atp.seeding_time = resume_data.seeding_time;
|
|
||||||
|
|
||||||
atp.last_seen_complete = resume_data.last_seen_complete;
|
atp.peers.swap(resume_data.peers);
|
||||||
atp.url = resume_data.url;
|
atp.banned_peers.swap(resume_data.banned_peers);
|
||||||
atp.uuid = resume_data.uuid;
|
|
||||||
|
|
||||||
atp.added_time = resume_data.added_time;
|
atp.unfinished_pieces.swap(resume_data.unfinished_pieces);
|
||||||
atp.completed_time = resume_data.completed_time;
|
atp.have_pieces.swap(resume_data.have_pieces);
|
||||||
|
atp.verified_pieces.swap(resume_data.verified_pieces);
|
||||||
|
atp.piece_priorities.swap(resume_data.piece_priorities);
|
||||||
|
|
||||||
atp.peers.swap(resume_data.peers);
|
atp.merkle_tree = std::move(resume_data.merkle_tree);
|
||||||
atp.banned_peers.swap(resume_data.banned_peers);
|
|
||||||
|
|
||||||
atp.unfinished_pieces.swap(resume_data.unfinished_pieces);
|
atp.renamed_files = std::move(resume_data.renamed_files);
|
||||||
atp.have_pieces.swap(resume_data.have_pieces);
|
|
||||||
atp.verified_pieces.swap(resume_data.verified_pieces);
|
|
||||||
atp.piece_priorities.swap(resume_data.piece_priorities);
|
|
||||||
|
|
||||||
atp.merkle_tree.swap(resume_data.merkle_tree);
|
if ((atp.flags & add_torrent_params::flag_override_resume_data) == 0)
|
||||||
|
{
|
||||||
|
atp.download_limit = resume_data.download_limit;
|
||||||
|
atp.upload_limit = resume_data.upload_limit;
|
||||||
|
atp.max_connections = resume_data.max_connections;
|
||||||
|
atp.max_uploads = resume_data.max_uploads;
|
||||||
|
atp.trackerid = resume_data.trackerid;
|
||||||
|
if (!resume_data.file_priorities.empty())
|
||||||
|
atp.file_priorities = resume_data.file_priorities;
|
||||||
|
|
||||||
atp.renamed_files.swap(resume_data.renamed_files);
|
std::uint64_t const mask =
|
||||||
|
add_torrent_params::flag_seed_mode
|
||||||
|
| add_torrent_params::flag_super_seeding
|
||||||
|
| add_torrent_params::flag_auto_managed
|
||||||
|
| add_torrent_params::flag_sequential_download
|
||||||
|
| add_torrent_params::flag_paused;
|
||||||
|
|
||||||
if ((atp.flags & add_torrent_params::flag_override_resume_data) == 0)
|
atp.flags &= ~mask;
|
||||||
{
|
atp.flags |= resume_data.flags & mask;
|
||||||
atp.download_limit = resume_data.download_limit;
|
}
|
||||||
atp.upload_limit = resume_data.upload_limit;
|
else
|
||||||
atp.max_connections = resume_data.max_connections;
|
{
|
||||||
atp.max_uploads = resume_data.max_uploads;
|
if (atp.file_priorities.empty())
|
||||||
atp.trackerid = resume_data.trackerid;
|
atp.file_priorities = resume_data.file_priorities;
|
||||||
if (!resume_data.file_priorities.empty())
|
|
||||||
atp.file_priorities = resume_data.file_priorities;
|
|
||||||
|
|
||||||
std::uint64_t const mask =
|
|
||||||
add_torrent_params::flag_seed_mode
|
|
||||||
| add_torrent_params::flag_super_seeding
|
|
||||||
| add_torrent_params::flag_auto_managed
|
|
||||||
| add_torrent_params::flag_sequential_download
|
|
||||||
| add_torrent_params::flag_paused;
|
|
||||||
|
|
||||||
atp.flags &= ~mask;
|
|
||||||
atp.flags |= resume_data.flags & mask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (atp.file_priorities.empty())
|
|
||||||
atp.file_priorities = resume_data.file_priorities;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
|
|
@ -751,19 +751,80 @@ TORRENT_TEST(zero_file_prio_deprecated)
|
||||||
{
|
{
|
||||||
test_zero_file_prio(true);
|
test_zero_file_prio(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(backwards_compatible_resume_info_dict)
|
||||||
|
{
|
||||||
|
// make sure the "info" dictionary is picked up correctly from the
|
||||||
|
// resume data in backwards compatible mode
|
||||||
|
|
||||||
|
std::shared_ptr<torrent_info> ti = generate_torrent();
|
||||||
|
entry rd;
|
||||||
|
rd["file-format"] = "libtorrent resume file";
|
||||||
|
rd["name"] = ti->name();
|
||||||
|
rd["info-hash"] = ti->info_hash();
|
||||||
|
auto metainfo = ti->metadata();
|
||||||
|
rd["info"] = bdecode(metainfo.get(), metainfo.get() + ti->metadata_size());
|
||||||
|
std::vector<char> resume_data;
|
||||||
|
bencode(back_inserter(resume_data), rd);
|
||||||
|
|
||||||
|
add_torrent_params atp;
|
||||||
|
atp.resume_data = std::move(resume_data);
|
||||||
|
atp.save_path = ".";
|
||||||
|
|
||||||
|
session ses;
|
||||||
|
torrent_handle h = ses.add_torrent(atp);
|
||||||
|
auto torrent = h.torrent_file();
|
||||||
|
TEST_CHECK(torrent->info_hash() == ti->info_hash());
|
||||||
|
torrent_status s = h.status();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TORRENT_TEST(resume_info_dict)
|
||||||
|
{
|
||||||
|
// make sure the "info" dictionary is picked up correctly from the
|
||||||
|
// resume data
|
||||||
|
|
||||||
|
std::shared_ptr<torrent_info> ti = generate_torrent();
|
||||||
|
entry rd;
|
||||||
|
rd["file-format"] = "libtorrent resume file";
|
||||||
|
rd["name"] = ti->name();
|
||||||
|
rd["info-hash"] = ti->info_hash();
|
||||||
|
auto metainfo = ti->metadata();
|
||||||
|
rd["info"] = bdecode(metainfo.get(), metainfo.get() + ti->metadata_size());
|
||||||
|
std::vector<char> resume_data;
|
||||||
|
bencode(back_inserter(resume_data), rd);
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
add_torrent_params atp = read_resume_data(resume_data, ec);
|
||||||
|
TEST_CHECK(atp.ti->info_hash() == ti->info_hash());
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_TEST(zero_file_prio)
|
TORRENT_TEST(zero_file_prio)
|
||||||
{
|
{
|
||||||
test_zero_file_prio();
|
test_zero_file_prio();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_seed_mode(bool const file_prio, bool const pieces_have, bool const piece_prio
|
enum class test_mode_t
|
||||||
, bool const all_files_zero = false, bool const test_deprecated = false)
|
|
||||||
{
|
{
|
||||||
std::printf("test_seed_mode file_prio: %d pieces_have: %d piece_prio: %d\n"
|
none = 0,
|
||||||
, file_prio, pieces_have, piece_prio);
|
file_prio = 1,
|
||||||
|
pieces_have = 2,
|
||||||
|
piece_prio = 4,
|
||||||
|
all_files_zero = 8,
|
||||||
|
deprecated = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
namespace flags {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct enable_flag_operators<test_mode_t> : std::true_type {};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_seed_mode(test_mode_t const flags)
|
||||||
|
{
|
||||||
lt::session ses(settings());
|
lt::session ses(settings());
|
||||||
std::shared_ptr<torrent_info> ti = generate_torrent();
|
std::shared_ptr<torrent_info> ti = generate_torrent();
|
||||||
add_torrent_params p;
|
add_torrent_params p;
|
||||||
|
@ -777,12 +838,12 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie
|
||||||
rd["info-hash"] = ti->info_hash().to_string();
|
rd["info-hash"] = ti->info_hash().to_string();
|
||||||
rd["blocks per piece"] = (std::max)(1, ti->piece_length() / 0x4000);
|
rd["blocks per piece"] = (std::max)(1, ti->piece_length() / 0x4000);
|
||||||
|
|
||||||
if (file_prio)
|
if (test(flags & test_mode_t::file_prio))
|
||||||
{
|
{
|
||||||
// this should take it out of seed_mode
|
// this should take it out of seed_mode
|
||||||
entry::list_type& file_prio = rd["file_priority"].list();
|
entry::list_type& file_prio = rd["file_priority"].list();
|
||||||
file_prio.push_back(entry(0));
|
file_prio.push_back(entry(0));
|
||||||
if (all_files_zero)
|
if (test(flags & test_mode_t::all_files_zero))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
|
@ -792,14 +853,14 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pieces(ti->num_pieces(), '\x01');
|
std::string pieces(ti->num_pieces(), '\x01');
|
||||||
if (pieces_have)
|
if (test(flags & test_mode_t::pieces_have))
|
||||||
{
|
{
|
||||||
pieces[0] = '\0';
|
pieces[0] = '\0';
|
||||||
}
|
}
|
||||||
rd["pieces"] = pieces;
|
rd["pieces"] = pieces;
|
||||||
|
|
||||||
std::string pieces_prio(ti->num_pieces(), '\x01');
|
std::string pieces_prio(ti->num_pieces(), '\x01');
|
||||||
if (piece_prio)
|
if (test(flags & test_mode_t::piece_prio))
|
||||||
{
|
{
|
||||||
pieces_prio[0] = '\0';
|
pieces_prio[0] = '\0';
|
||||||
}
|
}
|
||||||
|
@ -811,7 +872,7 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie
|
||||||
bencode(back_inserter(resume_data), rd);
|
bencode(back_inserter(resume_data), rd);
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
if (test_deprecated)
|
if (test(flags & test_mode_t::deprecated))
|
||||||
{
|
{
|
||||||
p.resume_data = resume_data;
|
p.resume_data = resume_data;
|
||||||
}
|
}
|
||||||
|
@ -828,7 +889,9 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie
|
||||||
torrent_handle h = ses.add_torrent(p);
|
torrent_handle h = ses.add_torrent(p);
|
||||||
|
|
||||||
torrent_status s = h.status();
|
torrent_status s = h.status();
|
||||||
if (file_prio || piece_prio || pieces_have)
|
if (test(flags & (test_mode_t::file_prio
|
||||||
|
| test_mode_t::piece_prio
|
||||||
|
| test_mode_t::pieces_have)))
|
||||||
{
|
{
|
||||||
TEST_EQUAL(s.seed_mode, false);
|
TEST_EQUAL(s.seed_mode, false);
|
||||||
}
|
}
|
||||||
|
@ -840,43 +903,43 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
TORRENT_TEST(seed_mode_file_prio_deprecated)
|
TORRENT_TEST(seed_mode_file_prio_deprecated)
|
||||||
{
|
{
|
||||||
test_seed_mode(true, false, false, true);
|
test_seed_mode(test_mode_t::file_prio | test_mode_t::deprecated);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_piece_prio_deprecated)
|
TORRENT_TEST(seed_mode_piece_prio_deprecated)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, true, false, true);
|
test_seed_mode(test_mode_t::pieces_have | test_mode_t::deprecated);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_piece_have_deprecated)
|
TORRENT_TEST(seed_mode_piece_have_deprecated)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, false, true, true);
|
test_seed_mode(test_mode_t::piece_prio | test_mode_t::deprecated);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_preserve_deprecated)
|
TORRENT_TEST(seed_mode_preserve_deprecated)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, false, false, true);
|
test_seed_mode(test_mode_t::deprecated);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_file_prio)
|
TORRENT_TEST(seed_mode_file_prio)
|
||||||
{
|
{
|
||||||
test_seed_mode(true, false, false);
|
test_seed_mode(test_mode_t::file_prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_piece_prio)
|
TORRENT_TEST(seed_mode_piece_prio)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, true, false);
|
test_seed_mode(test_mode_t::pieces_have);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_piece_have)
|
TORRENT_TEST(seed_mode_piece_have)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, false, true);
|
test_seed_mode(test_mode_t::piece_prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(seed_mode_preserve)
|
TORRENT_TEST(seed_mode_preserve)
|
||||||
{
|
{
|
||||||
test_seed_mode(false, false, false);
|
test_seed_mode(test_mode_t::none);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(resume_save_load)
|
TORRENT_TEST(resume_save_load)
|
||||||
|
|
Loading…
Reference in New Issue