#include "catch.hpp" #include <ftl/protocol/streams.hpp> #include <ftl/protocol/muxer.hpp> #include <ftl/protocol/broadcaster.hpp> #include <nlohmann/json.hpp> using ftl::protocol::Muxer; using ftl::protocol::Broadcast; using ftl::protocol::Stream; using ftl::protocol::StreamPacket; using ftl::protocol::Packet; using ftl::protocol::Channel; using ftl::protocol::FrameID; class TestStream : public ftl::protocol::Stream { public: TestStream() {}; ~TestStream() {}; bool post(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt) { seen(FrameID(spkt.streamID, spkt.frame_number), spkt.channel); trigger(spkt, pkt); return true; } bool begin() override { return true; } bool end() override { return true; } bool active() override { return true; } void setProperty(ftl::protocol::StreamProperty opt, int value) override {} int getProperty(ftl::protocol::StreamProperty opt) override { return 0; } bool supportsProperty(ftl::protocol::StreamProperty opt) override { return true; } private: //std::function<void(const StreamPacket &, const Packet &)> cb_; }; TEST_CASE("ftl::stream::Muxer()::post, distinct framesets", "[stream]") { std::unique_ptr<Muxer> mux = std::make_unique<Muxer>(); REQUIRE(mux); SECTION("write with one stream fails") { std::shared_ptr<Stream> s = std::make_shared<TestStream>(); REQUIRE(s); mux->add(s); ftl::protocol::StreamPacket tspkt = {4,0,0,1, Channel::kColour}; auto h = s->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( !mux->post({4,100,0,1,ftl::protocol::Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 0 ); } SECTION("write to previously read") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); mux->add(s1); mux->add(s2); ftl::protocol::StreamPacket tspkt = {4,0,0,1,Channel::kColour}; auto h = mux->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( s1->post({4,100,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 0 ); REQUIRE( tspkt.timestamp == 100 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,101,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 1 ); REQUIRE( tspkt.timestamp == 101 ); REQUIRE( tspkt.frame_number == 0 ); StreamPacket tspkt2 = {4,0,0,1,Channel::kColour}; StreamPacket tspkt3 = {4,0,0,1,Channel::kColour}; auto h2 = s1->onPacket([&tspkt2](const StreamPacket &spkt, const Packet &pkt) { tspkt2 = spkt; return true; }); auto h3 = s2->onPacket([&tspkt3](const StreamPacket &spkt, const Packet &pkt) { tspkt3 = spkt; return true; }); REQUIRE( mux->post({4,200,1,0,Channel::kColour},{}) ); REQUIRE( tspkt3.timestamp == 200 ); REQUIRE( tspkt3.streamID == 0 ); REQUIRE( tspkt3.frame_number == 0 ); } } TEST_CASE("ftl::stream::Muxer()::post, single frameset", "[stream]") { std::unique_ptr<Muxer> mux = std::make_unique<Muxer>(); REQUIRE(mux); SECTION("write to previously read") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); mux->add(s1,1); mux->add(s2,1); StreamPacket tspkt = {4,0,0,1,Channel::kColour}; auto h = mux->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( s1->post({4,100,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 1 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,101,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 1 ); REQUIRE( tspkt.frame_number == 1 ); StreamPacket tspkt2 = {4,0,4,4,Channel::kColour}; StreamPacket tspkt3 = {4,0,4,4,Channel::kColour}; auto h2 = s1->onPacket([&tspkt2](const StreamPacket &spkt, const Packet &pkt) { tspkt2 = spkt; return true; }); auto h3 = s2->onPacket([&tspkt3](const StreamPacket &spkt, const Packet &pkt) { tspkt3 = spkt; return true; }); REQUIRE( mux->post({4,200,1,1,Channel::kColour},{}) ); REQUIRE( tspkt2.streamID == 4 ); REQUIRE( tspkt2.frame_number == 4 ); REQUIRE( tspkt3.streamID == 0 ); REQUIRE( tspkt3.frame_number == 0 ); REQUIRE( mux->post({4,200,1,0,Channel::kColour},{}) ); REQUIRE( tspkt2.streamID == 0 ); REQUIRE( tspkt2.frame_number == 0 ); } } TEST_CASE("ftl::stream::Muxer()::read", "[stream]") { std::unique_ptr<Muxer> mux = std::make_unique<Muxer>(); REQUIRE(mux); SECTION("read with two writing streams") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); mux->add(s1, 0); mux->add(s2, 0); StreamPacket tspkt = {4,0,0,1,Channel::kColour}; auto h = mux->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( s1->post({4,100,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 100 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,101,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 101 ); REQUIRE( tspkt.frame_number == 1 ); REQUIRE( s1->post({4,102,0,1,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 102 ); REQUIRE( tspkt.frame_number == 2 ); REQUIRE( s2->post({4,103,0,1,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 103 ); REQUIRE( tspkt.frame_number == 3 ); } SECTION("read consistency with two writing streams") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); mux->add(s1, 0); mux->add(s2, 0); StreamPacket tspkt = {4,0,0,1,Channel::kColour}; auto h = mux->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( s1->post({4,100,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 100 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,101,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 101 ); REQUIRE( tspkt.frame_number == 1 ); REQUIRE( s1->post({4,102,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 102 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,103,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.timestamp == 103 ); REQUIRE( tspkt.frame_number == 1 ); } } TEST_CASE("ftl::stream::Muxer()::read multi-frameset", "[stream]") { std::unique_ptr<Muxer> mux = std::make_unique<Muxer>(); REQUIRE(mux); //SECTION("read with two writing streams") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); std::shared_ptr<Stream> s3 = std::make_shared<TestStream>(); REQUIRE(s3); std::shared_ptr<Stream> s4 = std::make_shared<TestStream>(); REQUIRE(s4); mux->add(s1,0); mux->add(s2,1); mux->add(s3,0); mux->add(s4,1); StreamPacket tspkt = {4,0,0,1,Channel::kColour}; auto h = mux->onPacket([&tspkt](const StreamPacket &spkt, const Packet &pkt) { tspkt = spkt; return true; }); REQUIRE( s1->post({4,100,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 0 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s2->post({4,101,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 1 ); REQUIRE( tspkt.frame_number == 0 ); REQUIRE( s3->post({4,102,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 0 ); REQUIRE( tspkt.frame_number == 1 ); REQUIRE( s4->post({4,103,0,0,Channel::kColour},{}) ); REQUIRE( tspkt.streamID == 1 ); REQUIRE( tspkt.frame_number == 1 ); //} } TEST_CASE("ftl::stream::Broadcast()::write", "[stream]") { std::unique_ptr<Broadcast> mux = std::make_unique<Broadcast>(); REQUIRE(mux); SECTION("write with two streams") { std::shared_ptr<Stream> s1 = std::make_shared<TestStream>(); REQUIRE(s1); std::shared_ptr<Stream> s2 = std::make_shared<TestStream>(); REQUIRE(s2); mux->add(s1); mux->add(s2); StreamPacket tspkt1 = {4,0,0,1,Channel::kColour}; StreamPacket tspkt2 = {4,0,0,1,Channel::kColour}; auto h1 = s1->onPacket([&tspkt1](const StreamPacket &spkt, const Packet &pkt) { tspkt1 = spkt; return true; }); auto h2 = s2->onPacket([&tspkt2](const StreamPacket &spkt, const Packet &pkt) { tspkt2 = spkt; return true; }); REQUIRE( mux->post({4,100,0,1,Channel::kColour},{}) ); REQUIRE( tspkt1.timestamp == 100 ); REQUIRE( tspkt2.timestamp == 100 ); } }