#include <ableton/discovery/Payload.hpp>
#include <ableton/discovery/test/PayloadEntries.hpp>
#include <ableton/test/CatchWrapper.hpp>
#include <ableton/util/Log.hpp>
#include <array>
namespace ableton
{
namespace discovery
{
TEST_CASE("Payload")
{
SECTION("EmptyPayload")
{
CHECK(0 == sizeInByteStream(makePayload()));
CHECK(nullptr == toNetworkByteStream(makePayload(), nullptr));
}
SECTION("FixedSizeEntryPayloadSize")
{
CHECK(12 == sizeInByteStream(makePayload(test::Foo{})));
}
SECTION("SingleEntryPayloadEncoding")
{
const auto payload = makePayload(test::Foo{-1});
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
CHECK(bytes.size() == static_cast<size_t>(end - begin(bytes)));
const auto uresult =
ntohl(reinterpret_cast<const std::uint32_t&>(*(begin(bytes) + 8)));
CHECK(-1 == reinterpret_cast<const std::int32_t&>(uresult));
}
SECTION("DoubleEntryPayloadSize")
{
CHECK(48 == sizeInByteStream(makePayload(test::Foo{}, test::Bar{{0, 1, 2}})));
}
SECTION("DoubleEntryPayloadEncoding")
{
const auto payload = makePayload(test::Foo{1}, test::Bar{{0, 1, 2}});
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
CHECK(bytes.size() == static_cast<size_t>(end - begin(bytes)));
CHECK(1 == ntohl(reinterpret_cast<const std::uint32_t&>(*(begin(bytes) + 8))));
CHECK(3 == ntohl(reinterpret_cast<const std::uint32_t&>(*(begin(bytes) + 20))));
CHECK(0 == ntohll(reinterpret_cast<const std::uint64_t&>(*(begin(bytes) + 24))));
CHECK(1 == ntohll(reinterpret_cast<const std::uint64_t&>(*(begin(bytes) + 32))));
CHECK(2 == ntohll(reinterpret_cast<const std::uint64_t&>(*(begin(bytes) + 40))));
}
SECTION("RoundtripSingleEntry")
{
const auto expected = test::Foo{1};
const auto payload = makePayload(expected);
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
test::Foo actual{};
parsePayload<test::Foo>(
begin(bytes), end, [&actual](const test::Foo& foo) { actual = foo; });
CHECK(expected.fooVal == actual.fooVal);
}
SECTION("RoundtripDoubleEntry")
{
const auto expectedFoo = test::Foo{1};
const auto expectedBar = test::Bar{{0, 1, 2}};
const auto payload = makePayload(expectedBar, expectedFoo);
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
test::Foo actualFoo{};
test::Bar actualBar{};
parsePayload<test::Foo, test::Bar>(
begin(bytes),
end,
[&actualFoo](const test::Foo& foo) { actualFoo = foo; },
[&actualBar](const test::Bar& bar) { actualBar = bar; });
CHECK(expectedFoo.fooVal == actualFoo.fooVal);
CHECK(expectedBar.barVals == actualBar.barVals);
}
SECTION("RoundtripSingleEntryWithMultipleVectors")
{
const auto expectedFoobar = test::Foobar{{0, 1, 2}, {3, 4, 5}};
const auto payload = makePayload(expectedFoobar);
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
test::Foobar actualFoobar{};
parsePayload<test::Foobar>(begin(bytes),
end,
[&actualFoobar](const test::Foobar& foobar)
{ actualFoobar = foobar; });
CHECK(expectedFoobar.asTuple() == actualFoobar.asTuple());
}
SECTION("ParseSubset")
{
const auto expectedFoo = test::Foo{1};
const auto expectedBar = test::Bar{{0, 1, 2}};
const auto payload = makePayload(expectedFoo, expectedBar);
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
test::Bar actualBar{};
parsePayload<test::Bar>(
begin(bytes), end, [&actualBar](const test::Bar& bar) { actualBar = bar; });
CHECK(expectedBar.barVals == actualBar.barVals);
}
SECTION("ParseTruncatedEntry")
{
const auto expectedFoo = test::Foo{1};
const auto expectedBar = test::Bar{{0, 1, 2}};
const auto payload = makePayload(expectedBar, expectedFoo);
std::vector<char> bytes(sizeInByteStream(payload));
const auto end = toNetworkByteStream(payload, begin(bytes));
test::Foo actualFoo{};
test::Bar actualBar{};
REQUIRE_THROWS_AS(( parsePayload<test::Foo, test::Bar>(
begin(bytes),
end - 1,
[&actualFoo](const test::Foo& foo) { actualFoo = foo; },
[&actualBar](const test::Bar& bar) { actualBar = bar; })),
std::runtime_error);
CHECK(0 == actualFoo.fooVal);
CHECK(expectedBar.barVals == actualBar.barVals);
}
SECTION("AddPayloads")
{
const auto foo = test::Foo{1};
const auto bar = test::Bar{{0, 1, 2}};
const auto fooBarPayload = makePayload(foo, bar);
const auto sumPayload = makePayload(foo) + makePayload(bar);
REQUIRE(sizeInByteStream(fooBarPayload) == sizeInByteStream(sumPayload));
std::vector<char> fooBarBytes(sizeInByteStream(fooBarPayload));
std::vector<char> sumBytes(sizeInByteStream(sumPayload));
const auto fooBarEnd = toNetworkByteStream(fooBarPayload, begin(fooBarBytes));
toNetworkByteStream(sumPayload, begin(sumBytes));
CHECK(std::equal(begin(fooBarBytes), fooBarEnd, begin(sumBytes)));
}
}
} }