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