#include "geocaching/usecase/query_client.h" #include #include #include #include #include struct PagingPort : geocaching::QueryClientPort { unsigned sends = 0, commits = 0; bool fail_commit = false; std::vector sent; bool newRequestId(geocaching::RequestId& id) override { id.bytes.fill(sends == 0 ? 1 : sends == 1 ? 3 : 4); return true; } geocaching::QueryPersistence submit(const geocaching::DirectoryEntry&, const geocaching::RequestId&, geocaching::ByteView bytes) override { sent.assign(bytes.data, bytes.data + bytes.size); ++sends; return geocaching::QueryPersistence::Committed; } geocaching::QueryPersistence pollPersistence() override { return geocaching::QueryPersistence::Committed; } geocaching::QueryPersistence cancel(const geocaching::Destination&, const geocaching::RequestId&) override { return geocaching::QueryPersistence::Committed; } geocaching::QueryPersistence commitCapabilities(const geocaching::Destination&, const geocaching::RequestId&, geocaching::ByteView) override { return geocaching::QueryPersistence::Committed; } geocaching::QueryPersistence commitPage(const geocaching::Destination&, const geocaching::RequestId&, geocaching::ByteView, const geocaching::protocol::QueryPageView&) override { if (fail_commit) return geocaching::QueryPersistence::Rejected; ++commits; return geocaching::QueryPersistence::Committed; } }; int main(int argc, char** argv) { assert(argc == 4); std::vector fixture[3]; for (unsigned i = 0; i < 3; ++i) { std::ifstream f(argv[i + 1], std::ios::binary); assert(f.good()); fixture[i].assign(std::istreambuf_iterator(f), {}); } PagingPort port; auto client = std::make_unique(port); geocaching::Destination address; std::array key{}; std::vector app{0x95, 1, 0xc4, 16}; app.insert(app.end(), 16, 0); app.insert(app.end(), {0xc4, 16}); app.insert(app.end(), 16, 0); app.insert(app.end(), {0, 0xa0}); assert(client->observe(address, address, {key.data(), 64}, {app.data(), app.size()}, 0)); assert(client->query({300000000, 1200000000, 310000000, 1210000000}) && client->tick(0)); assert(client->accept(address, {fixture[0].data(), fixture[0].size()}) && client->tick(1)); assert(client->accept(address, {fixture[1].data(), fixture[1].size()}) && client->hasMore()); std::fill(fixture[1].begin(), fixture[1].end(), 0); assert(client->loadMore()); assert(port.sent.size() >= 18); assert(port.sent[port.sent.size() - 18] == 0xc4 && port.sent[port.sent.size() - 17] == 16); for (std::size_t i = port.sent.size() - 16; i < port.sent.size(); ++i) assert(port.sent[i] == 0x72); auto wrong = fixture[2]; // Snapshot starts after response header, body array header and bin16 header. wrong[27] ^= 1; assert(!client->accept(address, {wrong.data(), wrong.size()})); assert(port.commits == 1); port.fail_commit = true; assert(!client->accept(address, {fixture[2].data(), fixture[2].size()})); assert(client->phase() == geocaching::QueryClientPhase::Querying); port.fail_commit = false; assert(client->accept(address, {fixture[2].data(), fixture[2].size()})); assert(port.commits == 2 && !client->hasMore() && !client->loadMore()); }