tst_msgpackiodevice.cpp
1 #include <QTest> 2 #include <QSignalSpy> 3 #include <QTcpServer> 4 #include <QTcpSocket> 5 #include <QRegularExpression> 6 #include <QBuffer> 7 8 #include <msgpackiodevice.h> 9 #include <msgpackrequest.h> 10 #include "common.h" 11 12 namespace NeovimQt { 13 14 /** 15 * A dummy request handler to help testing, it responds to all calls 16 * with response 17 */ 18 class RequestHandler: public QObject, public MsgpackRequestHandler 19 { 20 Q_OBJECT 21 public: 22 RequestHandler(QObject *parent=0):QObject(parent) {} 23 virtual void handleRequest(MsgpackIODevice* dev, quint32 msgid, const QByteArray& method, const QVariantList& params) { 24 dev->sendResponse(msgid, QVariant(), response); 25 emit receivedRequest(msgid, method, params); 26 } 27 QVariant response; 28 signals: 29 void receivedRequest(quint32 msgid, const QByteArray&, const QVariantList&); 30 31 }; 32 33 class Test: public QObject 34 { 35 Q_OBJECT 36 private: 37 MsgpackIODevice *one, *two; 38 void resetLoop() { 39 QTcpServer *server = new QTcpServer(); 40 QVERIFY(server->listen(QHostAddress::LocalHost)); 41 42 QVERIFY(server->isListening()); 43 44 QTcpSocket *client = new QTcpSocket(this); 45 QSignalSpy onConnected(client, SIGNAL(connected())); 46 QVERIFY(onConnected.isValid()); 47 QSignalSpy onNewConnection(server, SIGNAL(newConnection())); 48 QVERIFY(onNewConnection.isValid()); 49 50 client->connectToHost(server->serverAddress(), server->serverPort()); 51 QVERIFY(SPYWAIT(onConnected)); 52 QVERIFY(SPYWAIT(onNewConnection)); 53 54 QTcpSocket *other = server->nextPendingConnection(); 55 56 one = new MsgpackIODevice(client); 57 two = new MsgpackIODevice(other); 58 QVERIFY(one->isOpen()); 59 QVERIFY(two->isOpen()); 60 } 61 private slots: 62 void init() { 63 resetLoop(); 64 } 65 66 void cleanup() { 67 delete one; 68 delete two; 69 } 70 71 void invalidDevice() { 72 MsgpackIODevice *io = new MsgpackIODevice(new QBuffer); 73 QCOMPARE(io->errorCause(), MsgpackIODevice::InvalidDevice); 74 } 75 76 void defaultValues() { QCOMPARE(one->errorCause(), MsgpackIODevice::NoError); } 77 78 /** 79 * These errors are not fatal but increase coverage 80 */ 81 void recvError() { 82 one->send(QByteArray("Hello!")); 83 84 // An array of size 1 is an invalid msgpack-rpc 85 QVariantList brokenRequest; 86 brokenRequest << 42; 87 one->send(brokenRequest); 88 89 // Invalid method 90 QVariantList brokenRequest2; 91 brokenRequest2 << "X" << 42 << 42 << 42; 92 one->send(brokenRequest2); 93 94 // Invalid method 95 QVariantList brokenRequest3; 96 brokenRequest2 << 0 << 42 << 42 << 42; 97 one->send(brokenRequest3); 98 99 // Just to finish 100 auto req = one->startRequestUnchecked("testRequest", 0); 101 QSignalSpy gotResp(req, SIGNAL(error(quint32, quint64, QVariant))); 102 QVERIFY(gotResp.isValid()); 103 QVERIFY2(SPYWAIT(gotResp), "By default all requests get an error"); 104 } 105 106 void notification() { 107 QVariantList list; 108 list << 44 << 45; 109 110 QVariantList params; 111 params << 1 << QByteArray("one") << -3 << list; 112 QByteArray method("testNotification"); 113 114 QSignalSpy onNotification(two, SIGNAL(notification(QByteArray, QVariantList))); 115 QVERIFY(onNotification.isValid()); 116 117 one->sendNotification(method, params); 118 QVERIFY(SPYWAIT(onNotification)); 119 120 QVariantList n = onNotification.at(0); 121 QCOMPARE(n.at(0).toByteArray(), method); 122 QCOMPARE(n.at(1).toList(), params); 123 } 124 125 void request() { 126 auto req = one->startRequestUnchecked("testRequest", 0); 127 128 QSignalSpy gotResp(req, SIGNAL(error(quint32, quint64, QVariant))); 129 QVERIFY(gotResp.isValid()); 130 131 QVERIFY2(SPYWAIT(gotResp), "By default all requests get an error"); 132 133 // Now test with an actual response 134 RequestHandler *handler = new RequestHandler(two); 135 handler->response = 42; 136 two->setRequestHandler(handler); 137 138 QSignalSpy gotReq(handler, SIGNAL(receivedRequest(quint32, QByteArray, QVariantList))); 139 QVERIFY(gotReq.isValid()); 140 141 auto req2 = one->startRequestUnchecked("testRequest2", 1); 142 one->send(QByteArray("hello")); 143 QVERIFY(SPYWAIT(gotReq)); 144 145 // Make sure the request msgid/method/params matches the ones we sent 146 QVariantList signal = gotReq.at(0); 147 QCOMPARE(signal.at(0).toUInt(), req2->id); 148 QCOMPARE(signal.at(1).toByteArray(), QByteArray("testRequest2")); 149 QCOMPARE(signal.at(2).toList().at(0).toByteArray(), QByteArray("hello")); 150 151 QSignalSpy gotResp2(req2, SIGNAL(finished(quint32, quint64, QVariant))); 152 QVERIFY(gotResp2.isValid()); 153 QVERIFY2(SPYWAIT(gotResp2), "RequestHandler sends back a response"); 154 } 155 156 void checkVariant() 157 { 158 // Some Unsupported types 159 QVERIFY(!one->checkVariant(QRect())); 160 161 // Supported types 162 QVERIFY(one->checkVariant(QVariant())); 163 QVERIFY(one->checkVariant(true)); 164 QVERIFY(one->checkVariant(42)); 165 QVERIFY(one->checkVariant(4.4)); 166 QVERIFY(one->checkVariant(QStringLiteral("test"))); 167 QVERIFY(one->checkVariant(QByteArray())); 168 QVERIFY(one->checkVariant(QVariantList() << "test")); 169 QVERIFY(one->checkVariant(QVariantMap())); 170 QVERIFY(one->checkVariant(QPoint(1,1))); 171 } 172 173 void msgId() { 174 QCOMPARE(one->msgId(), (quint32)0); 175 QCOMPARE(one->msgId(), (quint32)1); 176 // Sending a request increases the id 177 one->startRequestUnchecked("testRequestMsgId", 0); 178 QCOMPARE(one->msgId(), (quint32)3); 179 // Notifications dont 180 one->sendNotification("testNotificationMsgId", QVariantList()); 181 QCOMPARE(one->msgId(), (quint32)4); 182 } 183 184 void timeout() { 185 QBuffer buf; 186 buf.open(QBuffer::ReadWrite); 187 188 // This will actually trigger a fatal error because the buffer 189 // is not a valid device, but is still enough to get the timeout 190 // below 191 MsgpackIODevice *dev = new MsgpackIODevice(&buf); 192 193 MsgpackRequest *r = dev->startRequestUnchecked("testTimeout", 0); 194 r->setTimeout(3); 195 196 QSignalSpy timedOut(r, SIGNAL(timeout(quint32))); 197 QVERIFY(timedOut.isValid()); 198 QVERIFY(SPYWAIT(timedOut)); 199 QVariantList params = timedOut.at(0); 200 QCOMPARE(params.at(0).toUInt(), r->id); 201 } 202 203 }; 204 205 } // Namespace NeovimQt 206 QTEST_MAIN(NeovimQt::Test) 207 #include "tst_msgpackiodevice.moc"