Added unit tests for:
authorKurt Pattyn <pattyn.kurt@gmail.com>
Tue, 27 Aug 2013 22:01:22 +0000 (00:01 +0200)
committerKurt Pattyn <pattyn.kurt@gmail.com>
Tue, 27 Aug 2013 22:01:22 +0000 (00:01 +0200)
- incomplete headers
- invalid headers
- invalid payloads

src/qwebsocketserver.cpp
tests/tst_dataprocessor.cpp

index c331a10..8431b41 100644 (file)
@@ -396,9 +396,9 @@ QList<QString> QWebSocketServer::supportedExtensions() const
     By default, every origin is accepted.
 
     \note Checking on the origin does not make much sense when the server is accessed
-via a non-browser client, as that client can set whatever origin header it likes
-In case of a browser client, the server SHOULD check the validity of the origin.
-\sa http://tools.ietf.org/html/rfc6455#section-10
+    via a non-browser client, as that client can set whatever origin header it likes
+    In case of a browser client, the server SHOULD check the validity of the origin.
+    \sa http://tools.ietf.org/html/rfc6455#section-10
 */
 bool QWebSocketServer::isOriginAllowed(const QString &origin) const
 {
index 086c3ce..219ef1d 100644 (file)
@@ -6,14 +6,21 @@
 #include <QDebug>
 #include "dataprocessor_p.h"
 #include "unittests.h"
-Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode);
 
-class DataProcessorTest : public QObject
+Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
+
+const quint8 FIN = 0x80;
+const quint8 RSV1 = 0x40;
+const quint8 RSV2 = 0x30;
+const quint8 RSV3 = 0x10;
+const quint8 MASK = 0x80;
+
+class tst_DataProcessor : public QObject
 {
     Q_OBJECT
 
 public:
-    DataProcessorTest();
+    tst_DataProcessor();
 
 private Q_SLOTS:
     void initTestCase();
@@ -22,264 +29,328 @@ private Q_SLOTS:
     void cleanup();
 
     /*!
-        \brief Tests the DataProcessor for correct handling of malformed frames.
+      \brief Tests all kinds of valid binary frames, including zero length frames
+      */
+    void goodBinaryFrames();
+
+    /*!
+      \brief Tests all kinds of valid text frames, including zero length frames
+      */
+    void goodTextFrames();
+
+    /*!
+        \brief Tests the DataProcessor for correct handling of frames that don't contain the starting 2 bytes.
+        This test does not test sequences of frames, only single frames are tested
+     */
+    void frameTooSmall();
+    /*!
+        \brief Tests the DataProcessor for correct handling of malformed frame headers.
+        This test does not test sequences of frames, only single frames are tested
+     */
+    void invalidHeader();
+    /*!
+        \brief Tests the DataProcessor for correct handling of incomplete payloads.
+        This includes:
+        - incomplete length bytes for large and big payloads (16- and 64-bit values),
+        - minimum size representation (see RFC 6455 paragraph 5.2),
+        - frames that are too large (larger than MAX_INT in bytes)
+        - incomplete payloads (less bytes than indicated in the size field)
+        - invalid UTF-8 sequences in text frames
         This test does not test sequences of frames, only single frames are tested
      */
-    void testMalformedFrames();
+    void incompletePayload();
 
     /*!
         \brief Tests the DataProcessor for correct handling of incorrect sequences of frames.
-        This test does not test the welformedness of frames, only incorrect sequences, e.g. received a continuation frame without a preceding start frame
+        This test does not test the welformedness of frames, only incorrect sequences,
+        e.g. received a continuation frame without a preceding start frame
      */
     //void testBadSequenceOfFrames();
+
+    void invalidHeader_data();
+    void incompletePayload_data();
 };
 
-DataProcessorTest::DataProcessorTest()
+tst_DataProcessor::tst_DataProcessor()
 {
 }
 
-void DataProcessorTest::initTestCase()
+void tst_DataProcessor::initTestCase()
 {
     qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
 }
 
-void DataProcessorTest::cleanupTestCase()
+void tst_DataProcessor::cleanupTestCase()
 {
 }
 
-void DataProcessorTest::init()
+void tst_DataProcessor::init()
 {
 }
 
-void DataProcessorTest::cleanup()
+void tst_DataProcessor::cleanup()
 {
 }
 
-union FrameHeaderBytes
+void tst_DataProcessor::goodBinaryFrames()
 {
-    int FIN     : 1;
-    int RSV1    : 1;
-    int RSV2    : 1;
-    int RSV3    : 1;
-    int OpCode  : 4;
-    int Mask    : 1;
-    int Len     : 7;
-};
+    QByteArray data;
+    QBuffer buffer;
+    DataProcessor dataProcessor;
 
-const quint8 FIN = 0x80;
-const quint8 RSV1 = 0x40;
-const quint8 RSV2 = 0x30;
-const quint8 RSV3 = 0x10;
-const quint8 MASK = 0x80;
+    //empty binary payload; this should be OK
+    data.append((char)(FIN | QWebSocketProtocol::OC_BINARY)).append(char(0x0));
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadWrite);
+
+    QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    dataProcessor.process(&buffer);
+    QCOMPARE(spyFrameReceived.count(), 1);
+    QCOMPARE(spyMessageReceived.count(), 1);
+    QList<QVariant> arguments = spyFrameReceived.takeFirst();
+    QCOMPARE(arguments.at(0).toByteArray().length(), 0);
+    arguments = spyMessageReceived.takeFirst();
+    QCOMPARE(arguments.at(0).toByteArray().length(), 0);
+    buffer.close();
+    spyFrameReceived.clear();
+    spyMessageReceived.clear();
+    data.clear();
+}
 
-void DataProcessorTest::testMalformedFrames()
+void tst_DataProcessor::goodTextFrames()
 {
     QByteArray data;
     QBuffer buffer;
+    DataProcessor dataProcessor;
+
+    //empty text payload; this should be OK
+    data.append((char)(FIN | QWebSocketProtocol::OC_TEXT)).append(char(0x0));
     buffer.setData(data);
     buffer.open(QIODevice::ReadWrite);
+
+    QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+    QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    dataProcessor.process(&buffer);
+    QCOMPARE(spyFrameReceived.count(), 1);
+    QCOMPARE(spyMessageReceived.count(), 1);
+    QList<QVariant> arguments = spyFrameReceived.takeFirst();
+    QCOMPARE(arguments.at(0).toString().length(), 0);
+    arguments = spyMessageReceived.takeFirst();
+    QCOMPARE(arguments.at(0).toString().length(), 0);
+    buffer.close();
+    spyFrameReceived.clear();
+    spyMessageReceived.clear();
+    data.clear();
+}
+
+void tst_DataProcessor::frameTooSmall()
+{
+    QByteArray data;
+    QBuffer buffer;
     DataProcessor dataProcessor;
 
     //with nothing in the buffer, the dataProcessor should time out and the error should be CC_GOING_AWAY
+    //meaning the socket will be closed
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadWrite);
     QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
     dataProcessor.process(&buffer);
     QCOMPARE(spy.count(), 1);
     QList<QVariant> arguments = spy.takeFirst();
     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
-
-    //only one byte; this is far too little; should get a time out as well
-    buffer.putChar('1');
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
-
-    //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
-    //The second byte contains the MaskFlag and the length of the frame
     spy.clear();
-    data.clear();
-    data.append((char)(FIN | RSV1)).append((char)0x0u);
     buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
-    //now check with RSV2 bit set
-    spy.clear();
     data.clear();
-    data.append((char)(FIN | RSV2)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
 
-    //now check with RSV3 bit set
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | RSV3)).append((char)0x0u);
-    buffer.close();
+    //only one byte; this is far too little; should get a time out as well and the error should be CC_GOING_AWAY
+    //meaning the socket will be closed
+    data.append(quint8('1'));   //put 1 byte in the buffer; this is too little
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
     dataProcessor.process(&buffer);
     QCOMPARE(spy.count(), 1);
     arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
-    //now check with RSV1 and RSV2 bit set
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | RSV1 | RSV2)).append((char)0x0u);
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
     buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
-    //now check with RSV1 and RSV3 bit set
     spy.clear();
     data.clear();
-    data.append((char)(FIN | RSV1 | RSV3)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+}
 
-    //now check with RSV2 and RSV3 bit set
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | RSV2 | RSV3)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+void tst_DataProcessor::invalidHeader_data()
+{
+    //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
+    //The second byte contains the MaskFlag and the length of the frame
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+
+    //invalid bit fields
+    QTest::newRow("RSV1 set")                << quint8(FIN | RSV1)              << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV2 set")                << quint8(FIN | RSV2)              << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV3 set")                << quint8(FIN | RSV3)              << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV1 and RSV2 set")       << quint8(FIN | RSV1 | RSV2)       << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV1 and RSV3 set")       << quint8(FIN | RSV1 | RSV3)       << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV2 and RSV3 set")       << quint8(FIN | RSV2 | RSV3)       << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("RSV1, RSV2 and RSV3 set") << quint8(FIN | RSV1 |RSV2 | RSV3) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+    //invalid opcodes
+    QTest::newRow("Invalid OpCode 3") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_3) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode 4") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_4) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode 5") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_5) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode 6") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_6) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode 7") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_7) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode B") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_B) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode C") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_C) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode D") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_D) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode E") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_E) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Invalid OpCode F") << quint8(FIN | QWebSocketProtocol::OC_RESERVED_F) << quint8(0x00) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+}
 
-    //check on invalid opcodes
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_3)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+void tst_DataProcessor::invalidHeader()
+{
+    QFETCH(quint8, firstByte);
+    QFETCH(quint8, secondByte);
+    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_4)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+    QByteArray data;
+    QBuffer buffer;
+    DataProcessor dataProcessor;
+    QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_5)).append((char)0x0u);
-    buffer.close();
+    data.append(char(firstByte)).append(char(secondByte));
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
     dataProcessor.process(&buffer);
     QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_6)).append((char)0x0u);
+    QVariantList arguments = spy.takeFirst();
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
     buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
     spy.clear();
     data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_7)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+}
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_B)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+void tst_DataProcessor::incompletePayload_data()
+{
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+
+    QTest::newRow("Text frame with payload size 125, but no data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(125) << QByteArray() << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Binary frame with payloadsize 125, but no data")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(125) << QByteArray() << QWebSocketProtocol::CC_GOING_AWAY;
+
+    //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
+    QTest::newRow("Text frame with payload size 126, but no data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(126) << QByteArray() << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Binary frame with payloadsize 126, but only 1 byte following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(126) << QByteArray().append(quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+
+    //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
+    QTest::newRow("Text frame with payload size 127, but no data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray() << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Binary frame with payloadsize 127, but only 1 byte following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(1, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 2 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(2, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 3 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(3, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 4 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(4, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 5 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(5, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 6 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(6, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Text frame with payload size 127, but only 7 bytes following")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY) << quint8(127) << QByteArray(7, quint8(1)) << QWebSocketProtocol::CC_GOING_AWAY;
+
+    //testing for the minimum size representation requirement; see RFC 6455 para 5.2
+    quint16 swapped16 = qToBigEndian<quint16>(0);
+    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+    QTest::newRow("Text frame with payload size 0, represented in 2 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(126) << QByteArray(wireRepresentation, 2) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped16 = qToBigEndian<quint16>(64);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+    QTest::newRow("Text frame with payload size 64, represented in 2 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(126) << QByteArray(wireRepresentation, 2) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped16 = qToBigEndian<quint16>(125);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+    QTest::newRow("Text frame with payload size 125, represented in 2 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(126) << QByteArray(wireRepresentation, 2) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+    QTest::newRow("Text frame with payload size 0, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(8, quint8(0)) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+    quint64 swapped = qToBigEndian<quint64>(64);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Text frame with payload size 64, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint64>(125);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Text frame with payload size 125, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint64>(8192);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Text frame with payload size 8192, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint64>(16384);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Text frame with payload size 16384, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint64>(0xFFFFu -1);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Text frame with payload size 65535, represented in 8 bytes")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8) << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+    //test frames with payloads that are too small; should result in timeout
+    QTest::newRow("Payload size 64, but only 32 bytes of data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(64) << QByteArray(32, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
+    swapped16 = qToBigEndian<quint16>(256);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+    QTest::newRow("Payload size 256, but only 32 bytes of data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(126) << QByteArray(wireRepresentation, 2).append(QByteArray(32, 'a')) << QWebSocketProtocol::CC_GOING_AWAY;
+    swapped = qToBigEndian<quint64>(128000);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Payload size 128000, but only 32 bytes of data")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) << QWebSocketProtocol::CC_GOING_AWAY;
+
+    swapped = qToBigEndian<quint64>(quint64(INT_MAX + 1));
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Payload size > INT_MAX")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT) << quint8(127) << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+    //TODO: test for invalid payloads, i.e. UTF-8; see Autobahn
+}
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_C)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+void tst_DataProcessor::incompletePayload()
+{
+    QFETCH(quint8, firstByte);
+    QFETCH(quint8, secondByte);
+    QFETCH(QByteArray, payload);
+    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_D)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
+    QByteArray data;
+    QBuffer buffer;
+    DataProcessor dataProcessor;
+    QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
 
-    spy.clear();
-    data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_E)).append((char)0x0u);
-    buffer.close();
+    data.append(firstByte).append(secondByte);
+    data.append(payload);
     buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
+    buffer.open(QIODevice::ReadWrite);
     dataProcessor.process(&buffer);
     QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
-
+    QVariantList arguments = spy.takeFirst();
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+    buffer.close();
     spy.clear();
     data.clear();
-    data.append((char)(FIN | QWebSocketProtocol::OC_RESERVED_F)).append((char)0x0u);
-    buffer.close();
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_PROTOCOL_ERROR);
 }
 
-DECLARE_TEST(DataProcessorTest)
+//TODO: test on valid and invalid handshakes; like the errors I got with FireFox (multiple values in field)
+
+DECLARE_TEST(tst_DataProcessor)
 
 #include "tst_dataprocessor.moc"