#include #include #include "core/message_bus.hpp" using namespace battlefield; // ==================== Singleton ==================== TEST(MessageBusTest, InstanceReturnsSame) { MessageBus& bus1 = MessageBus::Instance(); MessageBus& bus2 = MessageBus::Instance(); EXPECT_EQ(&bus1, &bus2); } // ==================== Subscribe / Publish ==================== TEST(MessageBusTest, SubscribeAndPublish) { auto& bus = MessageBus::Instance(); bool wasCalled = false; int subId = bus.Subscribe("test.topic", [&wasCalled](const BusMessage& msg) { wasCalled = true; EXPECT_EQ(msg.topic, "test.topic"); EXPECT_EQ(msg.sender, "sender1"); EXPECT_EQ(msg.payload["key"], "value"); }); bus.Publish("test.topic", "sender1", nlohmann::json::object({{"key", "value"}})); EXPECT_TRUE(wasCalled); bus.Unsubscribe(subId); } // ==================== Unsubscribe ==================== TEST(MessageBusTest, UnsubscribeStopsDelivery) { auto& bus = MessageBus::Instance(); int callCount = 0; int subId = bus.Subscribe("topic.unsub", [&callCount](const BusMessage&) { ++callCount; }); bus.Publish("topic.unsub", "test", nlohmann::json::object()); EXPECT_EQ(callCount, 1); bus.Unsubscribe(subId); bus.Publish("topic.unsub", "test", nlohmann::json::object()); EXPECT_EQ(callCount, 1); // 不再增长 } // ==================== Multiple Subscribers ==================== TEST(MessageBusTest, MultipleSubscribers) { auto& bus = MessageBus::Instance(); int count = 0; int s1 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; }); int s2 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; }); int s3 = bus.Subscribe("multi", [&count](const BusMessage&) { ++count; }); bus.Publish("multi", "sender", nlohmann::json::object()); EXPECT_EQ(count, 3); bus.Unsubscribe(s1); bus.Unsubscribe(s2); bus.Unsubscribe(s3); } // ==================== Wildcard Subscriber ==================== TEST(MessageBusTest, WildcardSubscription) { auto& bus = MessageBus::Instance(); int wildcardCount = 0; int specificCount = 0; int wildcard = bus.Subscribe("*", [&wildcardCount](const BusMessage&) { ++wildcardCount; }); int specific = bus.Subscribe("specific", [&specificCount](const BusMessage&) { ++specificCount; }); bus.Publish("specific", "test", nlohmann::json::object()); EXPECT_EQ(wildcardCount, 1); EXPECT_EQ(specificCount, 1); bus.Publish("other", "test", nlohmann::json::object()); EXPECT_EQ(wildcardCount, 2); EXPECT_EQ(specificCount, 1); // 不变 bus.Unsubscribe(wildcard); bus.Unsubscribe(specific); } // ==================== PublishString ==================== TEST(MessageBusTest, PublishString) { auto& bus = MessageBus::Instance(); std::string receivedMessage; int sub = bus.Subscribe("string.topic", [&receivedMessage](const BusMessage& msg) { receivedMessage = msg.payload["message"]; }); bus.PublishString("string.topic", "string_sender", "Hello World!"); EXPECT_EQ(receivedMessage, "Hello World!"); bus.Unsubscribe(sub); } // ==================== SubscriberCount ==================== TEST(MessageBusTest, SubscriberCount) { auto& bus = MessageBus::Instance(); EXPECT_EQ(bus.SubscriberCount("count.topic"), 0u); int s1 = bus.Subscribe("count.topic", [](const BusMessage&) {}); EXPECT_EQ(bus.SubscriberCount("count.topic"), 1u); int s2 = bus.Subscribe("count.topic", [](const BusMessage&) {}); EXPECT_EQ(bus.SubscriberCount("count.topic"), 2u); bus.Unsubscribe(s1); EXPECT_EQ(bus.SubscriberCount("count.topic"), 1u); bus.Unsubscribe(s2); EXPECT_EQ(bus.SubscriberCount("count.topic"), 0u); } // ==================== History ==================== TEST(MessageBusTest, HistoryCount) { auto& bus = MessageBus::Instance(); size_t before = bus.HistoryCount(); bus.Publish("history.topic", "test", nlohmann::json::object()); EXPECT_GT(bus.HistoryCount(), before); bus.PublishString("history.topic2", "test", "msg"); EXPECT_GT(bus.HistoryCount(), before + 1); } // ==================== Exception Safety ==================== TEST(MessageBusTest, ExceptionInHandlerDoesNotCrash) { auto& bus = MessageBus::Instance(); int normalCount = 0; int badSub = bus.Subscribe("error.topic", [](const BusMessage&) { throw std::runtime_error("handler error"); }); int goodSub = bus.Subscribe("error.topic", [&normalCount](const BusMessage&) { ++normalCount; }); // 不应崩溃 bus.Publish("error.topic", "test", nlohmann::json::object()); EXPECT_EQ(normalCount, 1); bus.Unsubscribe(badSub); bus.Unsubscribe(goodSub); } // ==================== Multiple Topics ==================== TEST(MessageBusTest, DifferentTopicsIndependent) { auto& bus = MessageBus::Instance(); int topicACount = 0; int topicBCount = 0; int sa = bus.Subscribe("topicA", [&topicACount](const BusMessage&) { ++topicACount; }); int sb = bus.Subscribe("topicB", [&topicBCount](const BusMessage&) { ++topicBCount; }); bus.Publish("topicA", "", nlohmann::json::object()); EXPECT_EQ(topicACount, 1); EXPECT_EQ(topicBCount, 0); bus.Publish("topicB", "", nlohmann::json::object()); EXPECT_EQ(topicACount, 1); EXPECT_EQ(topicBCount, 1); bus.Publish("topicC", "", nlohmann::json::object()); EXPECT_EQ(topicACount, 1); EXPECT_EQ(topicBCount, 1); bus.Unsubscribe(sa); bus.Unsubscribe(sb); } // ==================== Timestamp ==================== TEST(MessageBusTest, MessageHasTimestamp) { auto& bus = MessageBus::Instance(); std::string ts; int sub = bus.Subscribe("ts.topic", [&ts](const BusMessage& msg) { ts = msg.timestamp; }); bus.Publish("ts.topic", "test", nlohmann::json::object()); EXPECT_FALSE(ts.empty()); // 验证时间戳格式:YYYY-MM-DDTHH:MM:SS.mmmZ EXPECT_GE(ts.length(), 20u); EXPECT_THAT(ts, testing::HasSubstr("T")); EXPECT_THAT(ts, testing::HasSubstr("Z")); bus.Unsubscribe(sub); } // ==================== BusMessage Fields ==================== TEST(MessageBusTest, BusMessageAllFields) { auto& bus = MessageBus::Instance(); std::string rcvTopic, rcvSender, rcvTs; nlohmann::json rcvPayload; int sub = bus.Subscribe("full.topic", [&](const BusMessage& msg) { rcvTopic = msg.topic; rcvSender = msg.sender; rcvPayload = msg.payload; rcvTs = msg.timestamp; }); nlohmann::json payload = {{"a", 1}, {"b", "text"}, {"c", nlohmann::json::array({1,2,3})}}; bus.Publish("full.topic", "module_x", payload); EXPECT_EQ(rcvTopic, "full.topic"); EXPECT_EQ(rcvSender, "module_x"); EXPECT_EQ(rcvPayload["a"], 1); EXPECT_EQ(rcvPayload["b"], "text"); EXPECT_FALSE(rcvTs.empty()); bus.Unsubscribe(sub); }