/* Настоящий frontend и C-транспорт, управляемый backend без радио/системной шины. */ #include "../transport/desktop_ble.h" #include "../../../lib/ble/ble_backend.h" #include "../../../lib/ble/ble_identity.h" #include "../../../lib/u_async.h" #include "../../../lib/debug_config.h" #include #include struct ble_backend { ble_transport* owner = nullptr; }; static ble_backend backend; static int creations, destructions, advertisements; static QByteArray advertised; extern "C" ble_backend* ble_backend_create(ble_transport* owner, UASYNC*, const ble_config*) { backend.owner = owner; ++creations; return &backend; } extern "C" void ble_backend_destroy(ble_backend*) { backend.owner = nullptr; ++destructions; } extern "C" int ble_backend_advertise(ble_backend*, const uint8_t* data, size_t len) { advertised = QByteArray(reinterpret_cast(data), int(len)); ++advertisements; return 0; } extern "C" int ble_backend_connect(ble_backend*, ble_link_id, const ble_endpoint*) { return BLE_ERROR; } extern "C" void ble_backend_close(ble_backend*, ble_link_id) {} extern "C" int ble_backend_send(ble_backend*, ble_link_id, enum ble_channel, const uint8_t*, size_t) { return BLE_ERROR; } class DesktopBleTest : public QObject { Q_OBJECT private slots: void policyAndDiscovery() { debug_config_init(); auto destroy = [](UASYNC* ua) { uasync_destroy(ua, 0); }; std::unique_ptr ua(uasync_create(), destroy); QVERIFY(ua); DesktopBle radio(ua.get(), 1); radio.apply(0, "Desktop"); QVERIFY(!radio.transport()); QCOMPARE(creations, 0); radio.apply(3, "Desktop"); QVERIFY(radio.transport()); QCOMPARE(creations, 1); QCOMPARE(radio.snapshot().state, BLE_STARTING); QCOMPARE(advertisements, 0); ble_endpoint endpoint{}; strcpy(endpoint.id, "peer"); QCOMPARE(ble_backend_incoming(backend.owner, &endpoint), ble_link_id(0)); ble_backend_status(backend.owner, 1, "ready"); QCOMPARE(advertisements, 1); ble_identity identity{}; QCOMPARE(ble_identity_decode(&identity, reinterpret_cast(advertised.constData()), advertised.size()), 0); QCOMPARE(identity.node_id, uint64_t(1)); QCOMPARE(QByteArray(identity.name), QByteArray("Desktop")); radio.apply(3, "Desktop"); QCOMPARE(advertisements, 1); radio.apply(7, "Renamed"); QCOMPARE(advertisements, 2); QVERIFY(ble_backend_incoming(backend.owner, &endpoint) != 0); uint8_t bytes[24]; int length = ble_identity_encode(bytes, 2, "Android"); ble_backend_broadcast(backend.owner, &endpoint, bytes, length, -42); const auto peers = radio.snapshot().peers; QCOMPARE(peers.size(), 1); QVERIFY(peers.first().contains("Android")); QVERIFY(peers.first().contains("-42")); ble_backend_broadcast(backend.owner, &endpoint, bytes, length, -40); QCOMPARE(radio.snapshot().peers.size(), 1); radio.apply(1, "Renamed"); QVERIFY(advertised.isEmpty()); QCOMPARE(ble_backend_incoming(backend.owner, &endpoint), ble_link_id(0)); radio.apply(0, "Renamed"); QVERIFY(!radio.transport()); QCOMPARE(destructions, 1); QVERIFY(radio.snapshot().peers.isEmpty()); QCOMPARE(radio.snapshot().state, BLE_CLOSED); radio.apply(1, "Renamed"); QCOMPARE(creations, 2); ble_backend_status(backend.owner, 0, "adapter is off"); QCOMPARE(radio.snapshot().reason, QString("adapter is off")); radio.apply(0, "Renamed"); QCOMPARE(destructions, 2); } }; QTEST_GUILESS_MAIN(DesktopBleTest) #include "test_desktop_ble.moc"