summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorKurt Pattyn <pattyn.kurt@gmail.com>2013-10-13 15:30:33 +0200
committerKurt Pattyn <pattyn.kurt@gmail.com>2013-10-13 16:58:45 +0200
commit4f884ef7b5588ee4f639a61a0a812d3efac90e81 (patch)
tree94add0e4ae3939347965e46c24c7e4b503c7afd8 /tests
parenta0032d285f9148a9ae7f46e2d9c0e24a6fa84d0d (diff)
downloadqtwebsockets-4f884ef7b5588ee4f639a61a0a812d3efac90e81.tar.gz
Completed websocketframe unit tests
Replaced tab with space Change-Id: Ifc47621069870123b5db458a1ba2bb0d66a5419d Reviewed-by: Steven Ceuppens <steven.ceuppens@icloud.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/websocketframe/tst_websocketframe.cpp456
1 files changed, 456 insertions, 0 deletions
diff --git a/tests/auto/websocketframe/tst_websocketframe.cpp b/tests/auto/websocketframe/tst_websocketframe.cpp
index bd38c65..c53d02c 100644
--- a/tests/auto/websocketframe/tst_websocketframe.cpp
+++ b/tests/auto/websocketframe/tst_websocketframe.cpp
@@ -41,11 +41,104 @@
#include <QtTest/QtTest>
#include <QtTest/qtestcase.h>
#include <QDebug>
+#include <QByteArray>
+#include <QtEndian>
#include "private/qwebsocketframe_p.h"
+#include "qwebsocketprotocol.h"
QT_USE_NAMESPACE
+Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
+Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
+
+/*!
+ * \brief class FrameHelper is used to encode a single frame.
+ *
+ * \internal
+ */
+class FrameHelper
+{
+public:
+ FrameHelper();
+
+ QByteArray wireRepresentation();
+
+ void setRsv1(int value) { m_rsv1 = value; }
+ void setRsv2(int value) { m_rsv2 = value; }
+ void setRsv3(int value) { m_rsv3 = value; }
+ void setMask(quint32 mask) { m_mask = mask; }
+ void setOpCode(QWebSocketProtocol::OpCode opCode) { m_opCode = opCode; }
+ void setPayload(const QByteArray &payload) { m_payload = payload; }
+ void setFinalFrame(bool isFinal) { m_isFinalFrame = isFinal; }
+
+private:
+ int m_rsv1;
+ int m_rsv2;
+ int m_rsv3;
+ quint32 m_mask;
+ QWebSocketProtocol::OpCode m_opCode;
+ QByteArray m_payload;
+ bool m_isFinalFrame;
+};
+
+FrameHelper::FrameHelper() :
+ m_rsv1(0), m_rsv2(0), m_rsv3(0),
+ m_mask(0), m_opCode(QWebSocketProtocol::OC_RESERVED_3),
+ m_payload(), m_isFinalFrame(false)
+{}
+
+QByteArray FrameHelper::wireRepresentation()
+{
+ quint8 byte = 0x00;
+ QByteArray wireRep;
+ quint64 payloadLength = m_payload.length();
+
+ //FIN, opcode
+ byte = static_cast<quint8>((m_opCode & 0x0F) | (m_isFinalFrame ? 0x80 : 0x00)); //FIN, opcode
+ //RSV1-3
+ byte |= static_cast<quint8>(((m_rsv1 & 0x01) << 6) | ((m_rsv2 & 0x01) << 5) | ((m_rsv3 & 0x01) << 4));
+ wireRep.append(static_cast<char>(byte));
+
+ byte = 0x00;
+ if (m_mask != 0)
+ {
+ byte |= 0x80;
+ }
+ if (payloadLength <= 125)
+ {
+ byte |= static_cast<quint8>(payloadLength);
+ wireRep.append(static_cast<char>(byte));
+ }
+ else if (payloadLength <= 0xFFFFU)
+ {
+ byte |= 126;
+ wireRep.append(static_cast<char>(byte));
+ quint16 swapped = qToBigEndian<quint16>(static_cast<quint16>(payloadLength));
+ wireRep.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 2);
+ }
+ else if (payloadLength <= 0x7FFFFFFFFFFFFFFFULL)
+ {
+ byte |= 127;
+ wireRep.append(static_cast<char>(byte));
+ quint64 swapped = qToBigEndian<quint64>(payloadLength);
+ wireRep.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 8);
+ }
+ //Write mask
+ if (m_mask != 0)
+ {
+ wireRep.append(static_cast<const char *>(static_cast<const void *>(&m_mask)), sizeof(quint32));
+ }
+ QByteArray tmpData = m_payload;
+ if (m_mask)
+ {
+ tmpData.detach();
+ QWebSocketProtocol::mask(&tmpData, m_mask);
+ }
+ wireRep.append(tmpData);
+ return wireRep;
+}
+
class tst_WebSocketFrame : public QObject
{
Q_OBJECT
@@ -60,6 +153,15 @@ private Q_SLOTS:
void cleanup();
void tst_initialization();
+
+ void tst_goodFrames_data();
+ void tst_goodFrames();
+
+ void tst_invalidFrames_data();
+ void tst_invalidFrames();
+
+ void tst_malformedFrames_data();
+ void tst_malformedFrames();
};
tst_WebSocketFrame::tst_WebSocketFrame()
@@ -74,6 +176,8 @@ void tst_WebSocketFrame::cleanupTestCase()
void tst_WebSocketFrame::init()
{
+ qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
+ qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
}
void tst_WebSocketFrame::cleanup()
@@ -87,6 +191,358 @@ void tst_WebSocketFrame::tst_initialization()
QCOMPARE(frame.payload().length(), 0);
}
+void tst_WebSocketFrame::tst_goodFrames_data()
+{
+ QTest::addColumn<int>("rsv1");
+ QTest::addColumn<int>("rsv2");
+ QTest::addColumn<int>("rsv3");
+ QTest::addColumn<quint32>("mask");
+ QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
+ QTest::addColumn<bool>("isFinal");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isControlFrame");
+ QTest::addColumn<bool>("isDataFrame");
+ QTest::addColumn<bool>("isContinuationFrame");
+
+ QTest::newRow("Non masked final text frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << false << true << false;
+ QTest::newRow("Non masked final binary frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_BINARY
+ << true << QByteArray("\x00\x01\x02\x03\x04")
+ << false << true << false;
+ QTest::newRow("Non masked final text frame with no payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QByteArray()
+ << false << true << false;
+ QTest::newRow("Non masked final binary frame with no payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_BINARY
+ << true << QByteArray()
+ << false << true << false;
+
+ QTest::newRow("Non masked final close frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CLOSE
+ << true << QString("Hello world!").toUtf8()
+ << true << false << false;
+ QTest::newRow("Non masked final close frame with no payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CLOSE
+ << true << QByteArray()
+ << true << false << false;
+ QTest::newRow("Non masked final ping frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PING
+ << true << QString("Hello world!").toUtf8()
+ << true << false << false;
+ QTest::newRow("Non masked final pong frame with no payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PONG
+ << true << QByteArray()
+ << true << false << false;
+
+ QTest::newRow("Non masked final continuation frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CONTINUE
+ << true << QString("Hello world!").toUtf8()
+ << false << true << true;
+ QTest::newRow("Non masked non-final continuation frame with small payload")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CONTINUE
+ << false << QString("Hello world!").toUtf8()
+ << false << true << true;
+}
+
+void tst_WebSocketFrame::tst_goodFrames()
+{
+ QFETCH(int, rsv1);
+ QFETCH(int, rsv2);
+ QFETCH(int, rsv3);
+ QFETCH(quint32, mask);
+ QFETCH(QWebSocketProtocol::OpCode, opCode);
+ QFETCH(bool, isFinal);
+ QFETCH(QByteArray, payload);
+ QFETCH(bool, isControlFrame);
+ QFETCH(bool, isDataFrame);
+ QFETCH(bool, isContinuationFrame);
+
+ FrameHelper helper;
+ helper.setRsv1(rsv1);
+ helper.setRsv2(rsv2);
+ helper.setRsv3(rsv3);
+ helper.setMask(mask);
+ helper.setOpCode(opCode);
+ helper.setFinalFrame(isFinal);
+ helper.setPayload(payload);
+
+ QByteArray wireRepresentation = helper.wireRepresentation();
+ QBuffer buffer;
+ buffer.setData(wireRepresentation);
+ buffer.open(QIODevice::ReadOnly);
+ QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ buffer.close();
+ QCOMPARE(frame.isValid(), true);
+ QCOMPARE(frame.rsv1(), rsv1);
+ QCOMPARE(frame.rsv2(), rsv2);
+ QCOMPARE(frame.rsv3(), rsv3);
+ QCOMPARE(frame.hasMask(), (mask != 0));
+ QCOMPARE(frame.opCode(), opCode);
+ QCOMPARE(frame.isFinalFrame(), isFinal);
+ QCOMPARE(frame.isControlFrame(), isControlFrame);
+ QCOMPARE(frame.isDataFrame(), isDataFrame);
+ QCOMPARE(frame.isContinuationFrame(), isContinuationFrame);
+ QCOMPARE(frame.payload().length(), payload.length());
+ QCOMPARE(frame.payload(), payload);
+}
+
+void tst_WebSocketFrame::tst_invalidFrames_data()
+{
+ QTest::addColumn<int>("rsv1");
+ QTest::addColumn<int>("rsv2");
+ QTest::addColumn<int>("rsv3");
+ QTest::addColumn<quint32>("mask");
+ QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
+ QTest::addColumn<bool>("isFinal");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedError");
+
+ QTest::newRow("RSV1 != 0")
+ << 1 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("RSV2 != 0")
+ << 0 << 1 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("RSV3 != 0")
+ << 0 << 0 << 1
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("RSV1 != 0 and RSV2 != 0")
+ << 1 << 1 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("RSV1 != 0 and RSV3 != 0")
+ << 1 << 0 << 1
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("RSV2 != 0 and RSV3 != 0")
+ << 0 << 1 << 1
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+ QTest::newRow("Reserved OpCode 3")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_3
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode 4")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_4
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode 5")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_5
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode 6")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_6
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode 7")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_7
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode B")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_B
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode C")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_C
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode D")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_D
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode E")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_E
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Reserved OpCode F")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_RESERVED_F
+ << true << QString("Hello world!").toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+ QTest::newRow("Close Frame with payload > 125 bytes")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CLOSE
+ << true << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Non-final Close Frame")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_CLOSE
+ << false << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Ping Frame with payload > 125 bytes")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PING
+ << true << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Non-final Ping Frame")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PING
+ << false << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Pong Frame with payload > 125 bytes")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PONG
+ << true << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Non-final Pong Frame")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_PONG
+ << false << QString(126, 'a').toUtf8()
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+}
+
+void tst_WebSocketFrame::tst_invalidFrames()
+{
+ QFETCH(int, rsv1);
+ QFETCH(int, rsv2);
+ QFETCH(int, rsv3);
+ QFETCH(quint32, mask);
+ QFETCH(QWebSocketProtocol::OpCode, opCode);
+ QFETCH(bool, isFinal);
+ QFETCH(QByteArray, payload);
+ QFETCH(QWebSocketProtocol::CloseCode, expectedError);
+
+ FrameHelper helper;
+ helper.setRsv1(rsv1);
+ helper.setRsv2(rsv2);
+ helper.setRsv3(rsv3);
+ helper.setMask(mask);
+ helper.setOpCode(opCode);
+ helper.setFinalFrame(isFinal);
+ helper.setPayload(payload);
+
+ QByteArray wireRepresentation = helper.wireRepresentation();
+ QBuffer buffer;
+ buffer.setData(wireRepresentation);
+ buffer.open(QIODevice::ReadOnly);
+ QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ buffer.close();
+
+ QVERIFY(!frame.isValid());
+ QCOMPARE(frame.closeCode(), expectedError);
+}
+
+
+/*
+ * Incomplete or overly large frames
+ * Payload must be crafted manually
+ *
+ QTest::newRow("Frame Too Big")
+ << 0 << 0 << 0
+ << 0U << QWebSocketProtocol::OC_TEXT
+ << true << QString(MAX_FRAME_SIZE_IN_BYTES + 1, 'a').toUtf8()
+ << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+
+ */
+void tst_WebSocketFrame::tst_malformedFrames_data()
+{
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedError");
+
+ //too little data
+ QTest::newRow("No data") << QByteArray() << QWebSocketProtocol::CC_GOING_AWAY;
+ FrameHelper helper;
+ helper.setRsv1(0);
+ helper.setRsv2(0);
+ helper.setRsv3(0);
+ helper.setMask(0U);
+ helper.setOpCode(QWebSocketProtocol::OC_TEXT);
+ helper.setFinalFrame(true);
+ helper.setPayload(QString(10, 'a').toUtf8());
+ QByteArray wireRep = helper.wireRepresentation();
+
+ //too little data
+ //header + payload should be 12 bytes for non-masked payloads < 126 bytes
+ for (int i = 1; i < 12; ++i)
+ {
+ QTest::newRow(QString("Header too small - %1 byte(s)").arg(i).toLatin1().constData()) << wireRep.left(i) << QWebSocketProtocol::CC_GOING_AWAY;
+ }
+ //too much data
+ {
+ const char bigpayloadIndicator = char(127);
+ const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1;
+ uchar swapped[8] = {0};
+ qToBigEndian<quint64>(payloadSize, swapped);
+ QTest::newRow("Frame too big")
+ << wireRep.left(1).append(bigpayloadIndicator).append(reinterpret_cast<char *>(swapped), 8)
+ << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+ }
+ //overlong size field
+ {
+ const char largepayloadIndicator = char(126);
+ const quint16 payloadSize = 120;
+ uchar swapped[2] = {0};
+ qToBigEndian<quint16>(payloadSize, swapped);
+ QTest::newRow("Overlong 16-bit size field")
+ << wireRep.left(1).append(largepayloadIndicator).append(reinterpret_cast<char *>(swapped), 2)
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ }
+ {
+ const char bigpayloadIndicator = char(127);
+ quint64 payloadSize = 120;
+ uchar swapped[8] = {0};
+ qToBigEndian<quint64>(payloadSize, swapped);
+ QTest::newRow("Overlong 64-bit size field; should be 7-bit")
+ << wireRep.left(1).append(bigpayloadIndicator).append(reinterpret_cast<char *>(swapped), 8)
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+ payloadSize = 256;
+ qToBigEndian<quint64>(payloadSize, swapped);
+ QTest::newRow("Overlong 64-bit size field; should be 16-bit")
+ << wireRep.left(1).append(bigpayloadIndicator).append(reinterpret_cast<char *>(swapped), 8)
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ }
+}
+
+void tst_WebSocketFrame::tst_malformedFrames()
+{
+ QFETCH(QByteArray, payload);
+ QFETCH(QWebSocketProtocol::CloseCode, expectedError);
+
+ QBuffer buffer;
+ buffer.setData(payload);
+ buffer.open(QIODevice::ReadOnly);
+ QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ buffer.close();
+
+ QVERIFY(!frame.isValid());
+ QCOMPARE(frame.closeCode(), expectedError);
+}
+
QTEST_MAIN(tst_WebSocketFrame)
#include "tst_websocketframe.moc"