#include "mediapipe/framework/api2/packet.h" #include "absl/strings/str_cat.h" #include "mediapipe/framework/port/gmock.h" #include "mediapipe/framework/port/gtest.h" #include "mediapipe/framework/port/status_matchers.h" namespace mediapipe { namespace api2 { namespace { class LiveCheck { public: explicit LiveCheck(bool* alive) : alive_(*alive) { alive_ = true; } ~LiveCheck() { alive_ = false; } private: bool& alive_; }; TEST(PacketTest, PacketBaseDefault) { PacketBase p; EXPECT_TRUE(p.IsEmpty()); } TEST(PacketTest, PacketBaseNonEmpty) { PacketBase p = PacketAdopting(new int(5)); EXPECT_FALSE(p.IsEmpty()); } TEST(PacketTest, PacketBaseRefCount) { bool alive = false; PacketBase p = PacketAdopting(new LiveCheck(&alive)); EXPECT_TRUE(alive); PacketBase p2 = p; p = {}; EXPECT_TRUE(alive); p2 = {}; EXPECT_FALSE(alive); } TEST(PacketTest, PacketBaseSame) { int* ip = new int(5); PacketBase p = PacketAdopting(ip); PacketBase p2 = p; EXPECT_EQ(&p2.Get(), ip); } TEST(PacketTest, PacketNonEmpty) { Packet p = MakePacket(5); EXPECT_FALSE(p.IsEmpty()); } TEST(PacketTest, Get) { Packet p = MakePacket(5); EXPECT_EQ(*p, 5); EXPECT_EQ(p.Get(), 5); } TEST(PacketTest, GetOr) { Packet p_0 = MakePacket(0); Packet p_5 = MakePacket(5); Packet p_empty; EXPECT_EQ(p_0.GetOr(1), 0); EXPECT_EQ(p_5.GetOr(1), 5); EXPECT_EQ(p_empty.GetOr(1), 1); } // This show how GetOr can be used with a lambda that is only called if the "or" // case is needed. Can be useful when generating the fallback value is // expensive. // We could also add an overload to GetOr for types which are not convertible to // T, but are callable and return T. // TODO: consider adding it to make things easier. template struct Lazy { F f; using ValueT = decltype(f()); Lazy(F fun) : f(fun) {} operator ValueT() const { return f(); } }; template Lazy(F f) -> Lazy; TEST(PacketTest, GetOrLazy) { int expensive_call_count = 0; auto expensive_string_generation = [&expensive_call_count] { ++expensive_call_count; return "an expensive fallback"; }; auto p_hello = MakePacket("hello"); Packet p_empty; EXPECT_EQ(p_hello.GetOr(Lazy(expensive_string_generation)), "hello"); EXPECT_EQ(expensive_call_count, 0); EXPECT_EQ(p_empty.GetOr(Lazy(expensive_string_generation)), "an expensive fallback"); EXPECT_EQ(expensive_call_count, 1); } TEST(PacketTest, OneOf) { Packet> p = MakePacket("hi"); EXPECT_TRUE(p.Has()); EXPECT_FALSE(p.Has()); EXPECT_EQ(p.Get(), "hi"); std::string out = p.Visit([](std::string s) { return absl::StrCat("string: ", s); }, [](int i) { return absl::StrCat("int: ", i); }); EXPECT_EQ(out, "string: hi"); p = MakePacket(2); EXPECT_FALSE(p.Has()); EXPECT_TRUE(p.Has()); EXPECT_EQ(p.Get(), 2); out = p.Visit([](std::string s) { return absl::StrCat("string: ", s); }, [](int i) { return absl::StrCat("int: ", i); }); EXPECT_EQ(out, "int: 2"); } TEST(PacketTest, PacketRefCount) { bool alive = false; auto p = MakePacket(&alive); EXPECT_TRUE(alive); auto p2 = p; p = {}; EXPECT_TRUE(alive); p2 = {}; EXPECT_FALSE(alive); } TEST(PacketTest, PacketTimestamp) { auto p = MakePacket(5); EXPECT_EQ(p.timestamp(), Timestamp::Unset()); auto p2 = p.At(Timestamp(1)); EXPECT_EQ(p.timestamp(), Timestamp::Unset()); EXPECT_EQ(p2.timestamp(), Timestamp(1)); auto p3 = std::move(p2).At(Timestamp(3)); EXPECT_EQ(p3.timestamp(), Timestamp(3)); } TEST(PacketTest, PacketFromGeneric) { Packet<> pb = PacketAdopting(new int(5)); Packet p = pb.As(); EXPECT_EQ(p.Get(), 5); } TEST(PacketTest, PacketAdopting) { Packet p = PacketAdopting(new float(1.0)); EXPECT_FALSE(p.IsEmpty()); } TEST(PacketTest, PacketGeneric) { // With C++17, Packet<> could be written simply as Packet. Packet<> p = PacketAdopting(new float(1.0)); EXPECT_FALSE(p.IsEmpty()); } TEST(PacketTest, PacketGenericTimestamp) { Packet<> p = MakePacket(5); EXPECT_EQ(p.timestamp(), mediapipe::Timestamp::Unset()); auto p2 = p.At(Timestamp(1)); EXPECT_EQ(p.timestamp(), mediapipe::Timestamp::Unset()); EXPECT_EQ(p2.timestamp(), Timestamp(1)); auto p3 = std::move(p2).At(Timestamp(3)); EXPECT_EQ(p3.timestamp(), Timestamp(3)); } TEST(PacketTest, FromOldPacket) { mediapipe::Packet op = mediapipe::MakePacket(7); Packet p = FromOldPacket(op).As(); EXPECT_EQ(p.Get(), 7); EXPECT_EQ(op.Get(), 7); } TEST(PacketTest, FromOldPacketConsume) { mediapipe::Packet op = mediapipe::MakePacket(7); Packet p = FromOldPacket(std::move(op)).As(); MP_EXPECT_OK(p.Consume()); } TEST(PacketTest, ToOldPacket) { auto p = MakePacket(7); mediapipe::Packet op = ToOldPacket(p); EXPECT_EQ(op.Get(), 7); EXPECT_EQ(p.Get(), 7); } TEST(PacketTest, ToOldPacketConsume) { auto p = MakePacket(7); mediapipe::Packet op = ToOldPacket(std::move(p)); MP_EXPECT_OK(op.Consume()); } TEST(PacketTest, OldRefCounting) { bool alive = false; PacketBase p = PacketAdopting(new LiveCheck(&alive)); EXPECT_TRUE(alive); mediapipe::Packet op = ToOldPacket(p); p = {}; EXPECT_TRUE(alive); PacketBase p2 = FromOldPacket(op); op = {}; EXPECT_TRUE(alive); p2 = {}; EXPECT_FALSE(alive); } TEST(PacketTest, Consume) { auto p = MakePacket(7); auto maybe_int = p.Consume(); EXPECT_TRUE(p.IsEmpty()); ASSERT_TRUE(maybe_int.ok()); EXPECT_EQ(*maybe_int.value(), 7); p = MakePacket(3); auto p2 = p; maybe_int = p.Consume(); EXPECT_FALSE(maybe_int.ok()); EXPECT_FALSE(p.IsEmpty()); EXPECT_FALSE(p2.IsEmpty()); } TEST(PacketTest, OneOfConsume) { Packet> p = MakePacket("hi"); EXPECT_TRUE(p.Has()); EXPECT_FALSE(p.Has()); EXPECT_EQ(p.Get(), "hi"); absl::StatusOr out = p.ConsumeAndVisit( [](std::unique_ptr s) { return absl::StrCat("string: ", *s); }, [](std::unique_ptr i) { return absl::StrCat("int: ", *i); }); MP_EXPECT_OK(out); EXPECT_EQ(out.value(), "string: hi"); EXPECT_TRUE(p.IsEmpty()); p = MakePacket(3); absl::Status out2 = p.ConsumeAndVisit([](std::unique_ptr s) {}, [](std::unique_ptr i) {}); MP_EXPECT_OK(out2); EXPECT_TRUE(p.IsEmpty()); } } // namespace } // namespace api2 } // namespace mediapipe