/* Copyright (c) 2020-2021, Arvid Norberg All rights reserved. You may use, distribute and modify this code under the terms of the BSD license, see LICENSE file. */ #include "test.hpp" #include "libtorrent/aux_/store_buffer.hpp" #include "libtorrent/io_context.hpp" #include "libtorrent/disk_interface.hpp" // for default_block_size using lt::aux::torrent_location; using lt::aux::store_buffer; namespace { char buf1; char buf2; char buf3; char buf4; lt::storage_index_t const st0(0); lt::storage_index_t const st1(1); lt::piece_index_t const p0(0); lt::piece_index_t const p1(1); std::vector build_locations() { std::vector ret; for (auto s : {st0, st1}) { for (auto p : {p0, p1}) { for (auto o : {0, lt::default_block_size}) { ret.emplace_back(s, p, o); } } } return ret; } void check(store_buffer const& sb, torrent_location l, char const* expected) { bool called = false; bool const ret = sb.get(l, [&](char const* buf) { TEST_EQUAL(buf, expected); called = true; }); TEST_EQUAL(called, true); TEST_EQUAL(ret, true); } void check_miss(store_buffer const& sb, torrent_location l) { int const ret = sb.get(l, [&](char const* b) { TEST_ERROR(b); return 1337; }); TEST_EQUAL(ret, 0); } void check2(store_buffer const& sb, torrent_location l0, torrent_location l1 , char const* expected0, char const* expected1) { bool called = false; int const ret = sb.get2(l0, l1, [&](char const* b0, char const* b1) { TEST_EQUAL(b0, expected0); TEST_EQUAL(b1, expected1); called = true; return 1337; }); TEST_EQUAL(called, true); TEST_EQUAL(ret, 1337); } void check2_miss(store_buffer const& sb, torrent_location l0, torrent_location l1) { int const ret = sb.get2(l0, l1, [&](char const* b0, char const* b1) { TEST_ERROR(b0); TEST_ERROR(b1); return 1337; }); TEST_EQUAL(ret, 0); } } TORRENT_TEST(store_buffer_unique_keys) { auto const locations = build_locations(); lt::io_context ios; store_buffer sb(ios); // ensure all locations are independent for (auto l1 : locations) { sb.insert(l1, &buf1); for (auto l2 : locations) { if (l1 == l2) check(sb, l1, &buf1); else check_miss(sb, l2); } sb.erase(l1); } } TORRENT_TEST(store_buffer_get) { auto const loc = build_locations(); lt::io_context ios; store_buffer sb(ios); sb.insert(loc[0], &buf1); sb.insert(loc[1], &buf2); sb.insert(loc[2], &buf3); sb.insert(loc[3], &buf4); check(sb, loc[0], &buf1); check(sb, loc[1], &buf2); check(sb, loc[2], &buf3); check(sb, loc[3], &buf4); check_miss(sb, loc[4]); check_miss(sb, loc[5]); check_miss(sb, loc[6]); check_miss(sb, loc[7]); } TORRENT_TEST(store_buffer_get2) { auto const loc = build_locations(); lt::io_context ios; store_buffer sb(ios); sb.insert(loc[0], &buf1); sb.insert(loc[1], &buf2); sb.insert(loc[2], &buf3); sb.insert(loc[3], &buf4); // left side check2(sb, loc[0], loc[4], &buf1, nullptr); check2(sb, loc[1], loc[5], &buf2, nullptr); check2(sb, loc[2], loc[6], &buf3, nullptr); check2(sb, loc[3], loc[7], &buf4, nullptr); // right side check2(sb, loc[4], loc[0], nullptr, &buf1); check2(sb, loc[5], loc[1], nullptr, &buf2); check2(sb, loc[6], loc[2], nullptr, &buf3); check2(sb, loc[7], loc[3], nullptr, &buf4); // both sides check2(sb, loc[3], loc[0], &buf4, &buf1); check2(sb, loc[2], loc[1], &buf3, &buf2); check2(sb, loc[1], loc[2], &buf2, &buf3); check2(sb, loc[0], loc[3], &buf1, &buf4); // neither side check2_miss(sb, loc[4], loc[7]); check2_miss(sb, loc[5], loc[6]); check2_miss(sb, loc[6], loc[5]); check2_miss(sb, loc[7], loc[4]); }