/* Формат канального события: live/history сохраняются при передаче в GUI, битые события отбрасываются. */ #include "../transport/gui_bridge.h" #include "../../../lib/debug_config.h" #include "../../../src/chat/chat_event.h" #include #include #include struct ReceivedMessage { QString channel; quint64 author; bool initialSync; bool guiThread; }; static QList received; static QList cpuLoads; static bool cpuOnGuiThread = true; static void cpu_received(int percent) { cpuLoads.append(percent); cpuOnGuiThread &= QThread::currentThread() == qApp->thread(); } static void message_received(const char* channel, int length, uint64_t author, int initial_sync) { received.append({QString::fromUtf8(channel, length), author, initial_sync != 0, QThread::currentThread() == qApp->thread()}); } static QByteArray message_event(quint64 author, bool initialSync) { const QByteArray channel("12345"); QByteArray event(1 + channel.size() + 9, '\0'); event[0] = char(channel.size()); memcpy(event.data() + 1, channel.constData(), channel.size()); memcpy(event.data() + 1 + channel.size(), &author, 8); event[event.size() - 1] = initialSync; return event; } static void post_message(const QByteArray& event) { gui_bridge_post(GUI_EVT_MSG_RECEIVED, reinterpret_cast(event.constData()), event.size()); } class MessageEventTest : public QObject { Q_OBJECT private slots: void initTestCase() { debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG); gui_bridge_init(); gui_bridge_set_msg_received_cb(message_received); } void cleanupTestCase() { gui_bridge_set_msg_received_cb(nullptr); gui_bridge_set_cpu_load_cb(nullptr); } void init() { received.clear(); } void liveAndHistory() { post_message(message_event(42, false)); post_message(message_event(43, true)); QTRY_COMPARE(received.size(), 2); QCOMPARE(received[0].channel, QString("12345")); QCOMPARE(received[0].author, quint64(42)); QVERIFY(!received[0].initialSync); QVERIFY(received[0].guiThread); QCOMPARE(received[1].author, quint64(43)); QVERIFY(received[1].initialSync); QVERIFY(received[1].guiThread); } void rejectsMalformedEvents() { QByteArray event = message_event(42, false); event.chop(1); post_message(event); event = message_event(42, false); event[event.size() - 1] = 2; post_message(event); event = message_event(42, false); event[0] = char(255); post_message(event); post_message({}); QTest::qWait(100); QVERIFY(received.isEmpty()); } void cpuLoadDeliveredToGuiThread() { cpuLoads.clear(); cpuOnGuiThread = true; gui_bridge_set_cpu_load_cb(cpu_received); std::thread worker([] { const uint8_t samples[][2] = {{1, 0}, {1, 50}, {1, 100}, {0, 90}, {1, 101}}; for (const auto& sample : samples) gui_bridge_post(CHAT_EVT_CPU_LOAD, sample, sizeof(sample)); gui_bridge_post(CHAT_EVT_CPU_LOAD, nullptr, 0); }); worker.join(); QVERIFY(cpuLoads.isEmpty()); // Worker не вызывает UI напрямую. QTRY_COMPARE(cpuLoads.size(), 6); QCOMPARE(cpuLoads, QList({0, 50, 100, 0, 0, 0})); QVERIFY(cpuOnGuiThread); gui_bridge_set_cpu_load_cb(nullptr); const uint8_t sample[] = {1, 75}; gui_bridge_post(CHAT_EVT_CPU_LOAD, sample, sizeof(sample)); QCoreApplication::processEvents(); QCOMPARE(cpuLoads.size(), 6); } }; QTEST_MAIN(MessageEventTest) #include "test_message_events.moc"