Added checks for valid control frames
authorKurt Pattyn <pattyn.kurt@gmail.com>
Thu, 10 Oct 2013 19:12:27 +0000 (21:12 +0200)
committerKurt Pattyn <pattyn.kurt@gmail.com>
Fri, 11 Oct 2013 08:36:38 +0000 (10:36 +0200)
Also added extra checks on signals
Added extra comments
Cleaned up superfluous TODOs

Change-Id: I8ec760f0984bee4bd4cc757ce3ef6d7ed1c01102
Reviewed-by: Steven Ceuppens <steven.ceuppens@icloud.com>
src/websockets/qwebsocketserver.cpp
tests/auto/dataprocessor/tst_dataprocessor.cpp

index 1ea0f99..f267001 100644 (file)
@@ -107,9 +107,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #include "qwebsocketserver.h"
 #include "qwebsocketserver_p.h"
 
-//TODO: CorsCheck: give list in constructor or use CorsAuthenticator object
-//in QNetworkAccessManager the signal cannot be connected to a queued signal, because it waits for the signal to return
-
 QT_BEGIN_NAMESPACE
 
 /*!
index fac155d..4fd14fe 100644 (file)
@@ -14,29 +14,16 @@ Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
 //TODO: test valid UTF8 sequences (see UC 6.2)
 //TODO: test on masking correctness
 //TODO: test for valid fields
-//TODO: test for valid control frames
-//DONE: test for valid close codes
-//DONE: test close frame with no close code and reason
 //TODO: test if opcode is correct after processing of a continuation frame (text and binary frames)
 
 //TODO: test valid frame sequences
 
 //rainy-day flow
-//DONE: test invalid UTF8 sequences
-//DONE: test invalid UTF8 sequences in control/close frames
 //TODO: test invalid masks
 //TODO: test for AutoBahn testcase 5
 //TODO: test for AutoBahn testcase 6.1
 //TODO: test for AutoBahn testcase 6.3 (fragmentation test)
 //TODO: test for AutoBahn testcase 6.4 (fragmentation test)
-//DONE: test for invalid fields
-//DONE: test for invalid opcodes
-//DONE: test continuation frames for too big payload
-//DONE: test continuation frames for too small frame
-//DONE: test continuation frames for bad rsv fields, etc.
-//DONE: test continuation frames for incomplete payload
-//DONE: test close frame with payload length 1 (is either 0, if no close code, or at least 2, close code + optional reason)
-//DONE: besides spying on errors, we should also check if the frame and message signals are not emitted (or partially emitted)
 
 //TODO: test invalid frame sequences
 
@@ -68,20 +55,24 @@ private Q_SLOTS:
       \brief Tests all kinds of valid binary frames, including zero length frames
       */
     void goodBinaryFrame();
+    void goodBinaryFrame_data();
 
     /*!
       \brief Tests all kinds of valid text frames, including zero length frames
       */
     void goodTextFrame();
+    void goodTextFrame_data();
 
     /*!
      * \brief Test all kinds of valid control frames.
      */
-    //void goodControlFrame();
+    void goodControlFrame();
+
     /*!
      * \brief Test all kinds of valid close frames.
      */
     void goodCloseFrame();
+    void goodCloseFrame_data();
 
     //void goodHeaders();   //test all valid opcodes
 
@@ -92,9 +83,10 @@ private Q_SLOTS:
       to allow non-characters again.
      */
     void nonCharacterCodes();
+    void nonCharacterCodes_data();
 
     /***************************************************************************
-     * Unhappy Flows
+     * Rainy Day Flows
      ***************************************************************************/
     /*!
         \brief Tests the QWebSocketDataProcessor for correct handling of frames that don't contain the starting 2 bytes.
@@ -108,12 +100,14 @@ private Q_SLOTS:
         This test does not test sequences of frames, only single frames are tested
      */
     void frameTooBig();
+    void frameTooBig_data();
 
     /*!
         \brief Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
         This test does not test sequences of frames, only single frames are tested
      */
     void invalidHeader();
+    void invalidHeader_data();
 
     /*!
         \brief Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
@@ -121,12 +115,16 @@ private Q_SLOTS:
         This test does not test sequences of frames, only single frames are tested
      */
     void invalidControlFrame();
+    void invalidControlFrame_data();
+
     void invalidCloseFrame();
+    void invalidCloseFrame_data();
 
     /*!
         \brief Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields for large and big payloads.
      */
     void incompleteSizeField();
+    void incompleteSizeField_data();
 
     /*!
         \brief Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
@@ -138,34 +136,23 @@ private Q_SLOTS:
         This test does not test sequences of frames, only single frames are tested
      */
     void incompletePayload();
+    void incompletePayload_data();
 
     /*!
         \brief Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
         This test does not test sequences of frames, only single frames are tested
      */
     void invalidPayload();
+    void invalidPayload_data(bool isControlFrame = false);
 
     void invalidPayloadInCloseFrame();
+    void invalidPayloadInCloseFrame_data();
 
     /*!
       Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation requirement of RFC 6455 (see paragraph 5.2)
      */
     void minimumSizeRequirement();
-
-    void invalidHeader_data();
-    void incompleteSizeField_data();
-    void incompletePayload_data();
-    void invalidPayload_data(bool isControlFrame = false);
-    void invalidPayloadInCloseFrame_data();
     void minimumSizeRequirement_data();
-    void invalidControlFrame_data();
-    void invalidCloseFrame_data();
-    void frameTooBig_data();
-
-    void nonCharacterCodes_data();
-    void goodTextFrame_data();
-    void goodBinaryFrame_data();
-    void goodCloseFrame_data();
 
 private:
     //helper function that constructs a new row of test data for invalid UTF8 sequences
@@ -210,80 +197,19 @@ void tst_DataProcessor::cleanup()
 {
 }
 
-void tst_DataProcessor::goodTextFrame_data()
-{
-    QTest::addColumn<QByteArray>("payload");
-
-    //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
-    for (int i = 0; i < (65536 + 256); i += 128)
-    {
-        QTest::newRow(QString("Text frame with %1 ASCII characters").arg(i).toStdString().data()) << QByteArray(i, 'a');
-    }
-    //test all valid ASCII characters
-    for (int i = 0; i < 128; ++i)
-    {
-        QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(1, char(i));
-    }
-}
-
 void tst_DataProcessor::goodBinaryFrame_data()
 {
     QTest::addColumn<QByteArray>("payload");
-    for (int i = 0; i < (65536 + 256); i += 128)
+    for (int i = 0; i < (65536 + 256); i += 128)    //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
     {
         QTest::newRow(QString("Binary frame with %1 bytes").arg(i).toStdString().data()) << QByteArray(i, char(1));
     }
-    for (int i = 0; i < 256; ++i)
+    for (int i = 0; i < 256; ++i)   //test all possible bytes in the payload
     {
         QTest::newRow(QString("Binary frame containing byte: '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(i, char(1));
     }
 }
 
-void tst_DataProcessor::goodCloseFrame_data()
-{
-    QTest::addColumn<QString>("payload");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
-    //control frame data cannot exceed 125 bytes; smaller than 124, because we also need a 2 byte close code
-    for (int i = 0; i < 124; ++i)
-    {
-        QTest::newRow(QString("Close frame with %1 ASCII characters").arg(i).toStdString().data()) << QString(i, 'a') << QWebSocketProtocol::CC_NORMAL;
-    }
-    for (int i = 0; i < 126; ++i)
-    {
-        QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QString(1, char(i)) << QWebSocketProtocol::CC_NORMAL;
-    }
-    QTest::newRow("Close frame with close code NORMAL") << QString(1, 'a') << QWebSocketProtocol::CC_NORMAL;
-    QTest::newRow("Close frame with close code BAD OPERATION") << QString(1, 'a') << QWebSocketProtocol::CC_BAD_OPERATION;
-    QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") << QString(1, 'a') << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
-    QTest::newRow("Close frame with close code GOING AWAY") << QString(1, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
-    QTest::newRow("Close frame with close code MISSING EXTENSION") << QString(1, 'a') << QWebSocketProtocol::CC_MISSING_EXTENSION;
-    QTest::newRow("Close frame with close code POLICY VIOLATED") << QString(1, 'a') << QWebSocketProtocol::CC_POLICY_VIOLATED;
-    QTest::newRow("Close frame with close code PROTOCOL ERROR") << QString(1, 'a') << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Close frame with close code TOO MUCH DATA") << QString(1, 'a') << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-    QTest::newRow("Close frame with close code WRONG DATATYPE") << QString(1, 'a') << QWebSocketProtocol::CC_WRONG_DATATYPE;
-    QTest::newRow("Close frame with close code 3000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
-    QTest::newRow("Close frame with close code 3999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
-    QTest::newRow("Close frame with close code 4000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
-    QTest::newRow("Close frame with close code 4999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
-
-    //close frames with no close reason
-    QTest::newRow("Close frame with close code NORMAL and no reason") << QString() << QWebSocketProtocol::CC_NORMAL;
-    QTest::newRow("Close frame with close code BAD OPERATION and no reason") << QString() << QWebSocketProtocol::CC_BAD_OPERATION;
-    QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") << QString() << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
-    QTest::newRow("Close frame with close code GOING AWAY and no reason") << QString() << QWebSocketProtocol::CC_GOING_AWAY;
-    QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") << QString() << QWebSocketProtocol::CC_MISSING_EXTENSION;
-    QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") << QString() << QWebSocketProtocol::CC_POLICY_VIOLATED;
-    QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") << QString() << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") << QString() << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-    QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") << QString() << QWebSocketProtocol::CC_WRONG_DATATYPE;
-    QTest::newRow("Close frame with close code 3000 and no reason") << QString() << QWebSocketProtocol::CloseCode(3000);
-    QTest::newRow("Close frame with close code 3999 and no reason") << QString() << QWebSocketProtocol::CloseCode(3999);
-    QTest::newRow("Close frame with close code 4000 and no reason") << QString() << QWebSocketProtocol::CloseCode(4000);
-    QTest::newRow("Close frame with close code 4999 and no reason") << QString() << QWebSocketProtocol::CloseCode(4999);
-
-    QTest::newRow("Close frame with no close code and no reason") << QString() << QWebSocketProtocol::CloseCode(0);
-}
-
 void tst_DataProcessor::goodBinaryFrame()
 {
     QByteArray data;
@@ -314,23 +240,44 @@ void tst_DataProcessor::goodBinaryFrame()
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
 
-    QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
-    QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
-    QSignalSpy spyTextFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
-    QSignalSpy spyTextMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+    QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+    QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
     dataProcessor.process(&buffer);
-    QCOMPARE(spyFrameReceived.count(), 1);
-    QCOMPARE(spyMessageReceived.count(), 1);
-    QCOMPARE(spyTextFrameReceived.count(), 0);
-    QCOMPARE(spyTextMessageReceived.count(), 0);
-    QList<QVariant> arguments = spyFrameReceived.takeFirst();
+    QCOMPARE(errorReceivedSpy.count(), 0);
+    QCOMPARE(pingReceivedSpy.count(), 0);
+    QCOMPARE(pongReceivedSpy.count(), 0);
+    QCOMPARE(closeReceivedSpy.count(), 0);
+    QCOMPARE(binaryFrameReceivedSpy.count(), 1);
+    QCOMPARE(binaryMessageReceivedSpy.count(), 1);
+    QCOMPARE(textFrameReceivedSpy.count(), 0);
+    QCOMPARE(textMessageReceivedSpy.count(), 0);
+    QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
     QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
-    arguments = spyMessageReceived.takeFirst();
+    arguments = binaryMessageReceivedSpy.takeFirst();
     QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
     buffer.close();
-    spyFrameReceived.clear();
-    spyMessageReceived.clear();
-    data.clear();
+}
+
+void tst_DataProcessor::goodTextFrame_data()
+{
+    QTest::addColumn<QByteArray>("payload");
+
+    //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
+    for (int i = 0; i < (65536 + 256); i += 128)
+    {
+        QTest::newRow(QString("Text frame with %1 ASCII characters").arg(i).toStdString().data()) << QByteArray(i, 'a');
+    }
+    //test all valid ASCII characters
+    for (int i = 0; i < 128; ++i)
+    {
+        QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(1, char(i));
+    }
 }
 
 void tst_DataProcessor::goodTextFrame()
@@ -363,23 +310,124 @@ void tst_DataProcessor::goodTextFrame()
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
 
-    QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
-    QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
-    QSignalSpy spyBinaryFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
-    QSignalSpy spyBinaryMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+    QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+    QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+
     dataProcessor.process(&buffer);
-    QCOMPARE(spyFrameReceived.count(), 1);
-    QCOMPARE(spyMessageReceived.count(), 1);
-    QCOMPARE(spyBinaryFrameReceived.count(), 0);
-    QCOMPARE(spyBinaryMessageReceived.count(), 0);
-    QList<QVariant> arguments = spyFrameReceived.takeFirst();
+
+    QCOMPARE(errorReceivedSpy.count(), 0);
+    QCOMPARE(pingReceivedSpy.count(), 0);
+    QCOMPARE(pongReceivedSpy.count(), 0);
+    QCOMPARE(closeReceivedSpy.count(), 0);
+    QCOMPARE(textFrameReceivedSpy.count(), 1);
+    QCOMPARE(textMessageReceivedSpy.count(), 1);
+    QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+    QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+    QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
     QCOMPARE(arguments.at(0).toString().length(), payload.length());
-    arguments = spyMessageReceived.takeFirst();
+    arguments = textMessageReceivedSpy.takeFirst();
     QCOMPARE(arguments.at(0).toString().length(), payload.length());
     buffer.close();
-    spyFrameReceived.clear();
-    spyMessageReceived.clear();
+}
+
+void tst_DataProcessor::goodControlFrame()
+{
+    QByteArray data;
+    QBuffer buffer;
+    QWebSocketDataProcessor dataProcessor;
+
+    QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+    QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+
+    data.append((char)(FIN | QWebSocketProtocol::OC_PING));
+    data.append(QChar::fromLatin1(0));
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadOnly);
+    dataProcessor.process(&buffer);
+    QCOMPARE(errorReceivedSpy.count(), 0);
+    QCOMPARE(textFrameReceivedSpy.count(), 0);
+    QCOMPARE(textMessageReceivedSpy.count(), 0);
+    QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+    QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+    QCOMPARE(closeFrameReceivedSpy.count(), 0);
+    QCOMPARE(pongReceivedSpy.count(), 0);
+    QCOMPARE(pingReceivedSpy.count(), 1);
+    buffer.close();
+
     data.clear();
+    pingReceivedSpy.clear();
+    pongReceivedSpy.clear();
+    data.append((char)(FIN | QWebSocketProtocol::OC_PONG));
+    data.append(QChar::fromLatin1(0));
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadOnly);
+    dataProcessor.process(&buffer);
+    QCOMPARE(errorReceivedSpy.count(), 0);
+    QCOMPARE(textFrameReceivedSpy.count(), 0);
+    QCOMPARE(textMessageReceivedSpy.count(), 0);
+    QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+    QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+    QCOMPARE(closeFrameReceivedSpy.count(), 0);
+    QCOMPARE(pingReceivedSpy.count(), 0);
+    QCOMPARE(pongReceivedSpy.count(), 1);
+    buffer.close();
+}
+
+void tst_DataProcessor::goodCloseFrame_data()
+{
+    QTest::addColumn<QString>("payload");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
+    //control frame data cannot exceed 125 bytes; smaller than 124, because we also need a 2 byte close code
+    for (int i = 0; i < 124; ++i)
+    {
+        QTest::newRow(QString("Close frame with %1 ASCII characters").arg(i).toStdString().data()) << QString(i, 'a') << QWebSocketProtocol::CC_NORMAL;
+    }
+    for (int i = 0; i < 126; ++i)
+    {
+        QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QString(1, char(i)) << QWebSocketProtocol::CC_NORMAL;
+    }
+    QTest::newRow("Close frame with close code NORMAL") << QString(1, 'a') << QWebSocketProtocol::CC_NORMAL;
+    QTest::newRow("Close frame with close code BAD OPERATION") << QString(1, 'a') << QWebSocketProtocol::CC_BAD_OPERATION;
+    QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") << QString(1, 'a') << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
+    QTest::newRow("Close frame with close code GOING AWAY") << QString(1, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Close frame with close code MISSING EXTENSION") << QString(1, 'a') << QWebSocketProtocol::CC_MISSING_EXTENSION;
+    QTest::newRow("Close frame with close code POLICY VIOLATED") << QString(1, 'a') << QWebSocketProtocol::CC_POLICY_VIOLATED;
+    QTest::newRow("Close frame with close code PROTOCOL ERROR") << QString(1, 'a') << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Close frame with close code TOO MUCH DATA") << QString(1, 'a') << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+    QTest::newRow("Close frame with close code WRONG DATATYPE") << QString(1, 'a') << QWebSocketProtocol::CC_WRONG_DATATYPE;
+    QTest::newRow("Close frame with close code 3000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
+    QTest::newRow("Close frame with close code 3999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
+    QTest::newRow("Close frame with close code 4000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
+    QTest::newRow("Close frame with close code 4999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
+
+    //close frames with no close reason
+    QTest::newRow("Close frame with close code NORMAL and no reason") << QString() << QWebSocketProtocol::CC_NORMAL;
+    QTest::newRow("Close frame with close code BAD OPERATION and no reason") << QString() << QWebSocketProtocol::CC_BAD_OPERATION;
+    QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") << QString() << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
+    QTest::newRow("Close frame with close code GOING AWAY and no reason") << QString() << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") << QString() << QWebSocketProtocol::CC_MISSING_EXTENSION;
+    QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") << QString() << QWebSocketProtocol::CC_POLICY_VIOLATED;
+    QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") << QString() << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") << QString() << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+    QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") << QString() << QWebSocketProtocol::CC_WRONG_DATATYPE;
+    QTest::newRow("Close frame with close code 3000 and no reason") << QString() << QWebSocketProtocol::CloseCode(3000);
+    QTest::newRow("Close frame with close code 3999 and no reason") << QString() << QWebSocketProtocol::CloseCode(3999);
+    QTest::newRow("Close frame with close code 4000 and no reason") << QString() << QWebSocketProtocol::CloseCode(4000);
+    QTest::newRow("Close frame with close code 4999 and no reason") << QString() << QWebSocketProtocol::CloseCode(4999);
+
+    QTest::newRow("Close frame with no close code and no reason") << QString() << QWebSocketProtocol::CloseCode(0);
 }
 
 void tst_DataProcessor::goodCloseFrame()
@@ -406,24 +454,72 @@ void tst_DataProcessor::goodCloseFrame()
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
 
-    QSignalSpy spyCloseFrameReceived(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
-    QSignalSpy spyTextFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
-    QSignalSpy spyTextMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
-    QSignalSpy spyBinaryFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
-    QSignalSpy spyBinaryMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+    QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+    QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
 
     dataProcessor.process(&buffer);
-    QCOMPARE(spyCloseFrameReceived.count(), 1);
-    QCOMPARE(spyTextFrameReceived.count(), 0);
-    QCOMPARE(spyTextMessageReceived.count(), 0);
-    QCOMPARE(spyBinaryFrameReceived.count(), 0);
-    QCOMPARE(spyBinaryMessageReceived.count(), 0);
-    QList<QVariant> arguments = spyCloseFrameReceived.takeFirst();
+
+    QCOMPARE(errorReceivedSpy.count(), 0);
+    QCOMPARE(pingReceivedSpy.count(), 0);
+    QCOMPARE(pongReceivedSpy.count(), 0);
+    QCOMPARE(closeFrameReceivedSpy.count(), 1);
+    QCOMPARE(textFrameReceivedSpy.count(), 0);
+    QCOMPARE(textMessageReceivedSpy.count(), 0);
+    QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+    QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+    QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
     QCOMPARE(arguments.at(1).toString().length(), payload.length());
     buffer.close();
-    spyCloseFrameReceived.clear();
-    data.clear();
+}
+
+void tst_DataProcessor::nonCharacterCodes_data()
+{
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+
+    nonCharacterSequence("efbfbe");
+    nonCharacterSequence("efbfbf");
+    nonCharacterSequence("f09fbfbe");
+    nonCharacterSequence("f09fbfbf");
+    nonCharacterSequence("f0afbfbe");
+    nonCharacterSequence("f0afbfbf");
+    nonCharacterSequence("f0bfbfbe");
+    nonCharacterSequence("f0bfbfbf");
+    nonCharacterSequence("f18fbfbe");
+    nonCharacterSequence("f18fbfbf");
+    nonCharacterSequence("f19fbfbe");
+    nonCharacterSequence("f19fbfbf");
+    nonCharacterSequence("f1afbfbe");
+    nonCharacterSequence("f1afbfbf");
+    nonCharacterSequence("f1bfbfbe");
+    nonCharacterSequence("f1bfbfbf");
+    nonCharacterSequence("f28fbfbe");
+    nonCharacterSequence("f28fbfbf");
+    nonCharacterSequence("f29fbfbe");
+    nonCharacterSequence("f29fbfbf");
+    nonCharacterSequence("f2afbfbe");
+    nonCharacterSequence("f2afbfbf");
+    nonCharacterSequence("f2bfbfbe");
+    nonCharacterSequence("f2bfbfbf");
+    nonCharacterSequence("f38fbfbe");
+    nonCharacterSequence("f38fbfbf");
+    nonCharacterSequence("f39fbfbe");
+    nonCharacterSequence("f39fbfbf");
+    nonCharacterSequence("f3afbfbe");
+    nonCharacterSequence("f3afbfbf");
+    nonCharacterSequence("f3bfbfbe");
+    nonCharacterSequence("f3bfbfbf");
+    nonCharacterSequence("f48fbfbe");
+    nonCharacterSequence("f48fbfbf");
 }
 
 void tst_DataProcessor::nonCharacterCodes()
@@ -438,8 +534,12 @@ void tst_DataProcessor::nonCharacterCodes()
         QByteArray data;
         QBuffer buffer;
         QWebSocketDataProcessor dataProcessor;
-        QSignalSpy frameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
-        QSignalSpy messageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+        QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+        QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+        QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+        QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+        QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+        QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
         QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
         QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
 
@@ -448,21 +548,22 @@ void tst_DataProcessor::nonCharacterCodes()
         buffer.setData(data);
         buffer.open(QIODevice::ReadOnly);
         dataProcessor.process(&buffer);
-        //QEXPECT_FAIL(QTest::currentDataTag(), "Due to QTextCode interpeting non-characters unicode points as invalid (QTBUG-33229).", Abort);
 
-        QCOMPARE(frameSpy.count(), 1);
-        QCOMPARE(messageSpy.count(), 1);
+        QCOMPARE(errorSpy.count(), 0);
+        QCOMPARE(closeSpy.count(), 0);
+        QCOMPARE(pingFrameSpy.count(), 0);
+        QCOMPARE(pongFrameSpy.count(), 0);
+        QCOMPARE(textFrameSpy.count(), 1);
+        QCOMPARE(textMessageSpy.count(), 1);
         QCOMPARE(binaryFrameSpy.count(), 0);
         QCOMPARE(binaryMessageSpy.count(), 0);
 
-        QVariantList arguments = frameSpy.takeFirst();
+        QVariantList arguments = textFrameSpy.takeFirst();
         QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
-        arguments = messageSpy.takeFirst();
+        QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
+        arguments = textMessageSpy.takeFirst();
         QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
         buffer.close();
-        frameSpy.clear();
-        messageSpy.clear();
-        data.clear();
     }
 }
 
@@ -479,20 +580,32 @@ void tst_DataProcessor::frameTooSmall()
     //meaning the socket will be closed
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
-    QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
     QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
     QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
     QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
     QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
     dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
+
+    QCOMPARE(errorSpy.count(), 1);
+    QCOMPARE(closeSpy.count(), 0);
+    QCOMPARE(pingMessageSpy.count(), 0);
+    QCOMPARE(pongMessageSpy.count(), 0);
     QCOMPARE(textMessageSpy.count(), 0);
     QCOMPARE(binaryMessageSpy.count(), 0);
     QCOMPARE(textFrameSpy.count(), 0);
     QCOMPARE(binaryFrameSpy.count(), 0);
-    QList<QVariant> arguments = spy.takeFirst();
+
+    QList<QVariant> arguments = errorSpy.takeFirst();
     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
-    spy.clear();
+    errorSpy.clear();
+    closeSpy.clear();
+    pingMessageSpy.clear();
+    pongMessageSpy.clear();
     textMessageSpy.clear();
     binaryMessageSpy.clear();
     textFrameSpy.clear();
@@ -505,16 +618,25 @@ void tst_DataProcessor::frameTooSmall()
     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);
+
+    QCOMPARE(errorSpy.count(), 1);
+    QCOMPARE(closeSpy.count(), 0);
+    QCOMPARE(pingMessageSpy.count(), 0);
+    QCOMPARE(pongMessageSpy.count(), 0);
     QCOMPARE(textMessageSpy.count(), 0);
     QCOMPARE(binaryMessageSpy.count(), 0);
     QCOMPARE(textFrameSpy.count(), 0);
     QCOMPARE(binaryFrameSpy.count(), 0);
-    arguments = spy.takeFirst();
+
+    arguments = errorSpy.takeFirst();
     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
     buffer.close();
-    spy.clear();
+    errorSpy.clear();
+    closeSpy.clear();
+    pingMessageSpy.clear();
+    pongMessageSpy.clear();
     textMessageSpy.clear();
     binaryMessageSpy.clear();
     textFrameSpy.clear();
@@ -527,6 +649,7 @@ void tst_DataProcessor::frameTooSmall()
         data.append((char)(QWebSocketProtocol::OC_TEXT)).append(char(0x0));
         buffer.setData(data);
         buffer.open(QIODevice::ReadOnly);
+
         dataProcessor.process(&buffer);
 
         buffer.close();
@@ -536,16 +659,24 @@ void tst_DataProcessor::frameTooSmall()
         //meaning the socket will be closed
         buffer.setData(data);
         buffer.open(QIODevice::ReadOnly);
-        QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+        QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
         dataProcessor.process(&buffer);
-        QCOMPARE(spy.count(), 1);
+
+        QCOMPARE(errorSpy.count(), 1);
+        QCOMPARE(closeSpy.count(), 0);
+        QCOMPARE(pingMessageSpy.count(), 0);
+        QCOMPARE(pongMessageSpy.count(), 0);
         QCOMPARE(textMessageSpy.count(), 0);
         QCOMPARE(binaryMessageSpy.count(), 0);
         QCOMPARE(textFrameSpy.count(), 1);
         QCOMPARE(binaryFrameSpy.count(), 0);
-        QList<QVariant> arguments = spy.takeFirst();
+
+        QList<QVariant> arguments = errorSpy.takeFirst();
         QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
-        spy.clear();
+        errorSpy.clear();
+        closeSpy.clear();
+        pingMessageSpy.clear();
+        pongMessageSpy.clear();
         textMessageSpy.clear();
         binaryMessageSpy.clear();
         textFrameSpy.clear();
@@ -559,6 +690,10 @@ void tst_DataProcessor::frameTooSmall()
         buffer.open(QIODevice::ReadOnly);
         dataProcessor.process(&buffer);
 
+        QCOMPARE(errorSpy.count(), 1);
+        QCOMPARE(closeSpy.count(), 0);
+        QCOMPARE(pingMessageSpy.count(), 0);
+        QCOMPARE(pongMessageSpy.count(), 0);
         QCOMPARE(textMessageSpy.count(), 0);
         QCOMPARE(binaryMessageSpy.count(), 0);
         QCOMPARE(textFrameSpy.count(), 1);
@@ -566,7 +701,11 @@ void tst_DataProcessor::frameTooSmall()
 
         buffer.close();
         data.clear();
-        spy.clear();
+
+        errorSpy.clear();
+        closeSpy.clear();
+        pingMessageSpy.clear();
+        pongMessageSpy.clear();
         textMessageSpy.clear();
         binaryMessageSpy.clear();
         textFrameSpy.clear();
@@ -578,496 +717,305 @@ void tst_DataProcessor::frameTooSmall()
         buffer.open(QIODevice::ReadOnly);
 
         dataProcessor.process(&buffer);
-        QCOMPARE(spy.count(), 1);
+        QCOMPARE(errorSpy.count(), 1);
+        QCOMPARE(closeSpy.count(), 0);
+        QCOMPARE(pingMessageSpy.count(), 0);
+        QCOMPARE(pongMessageSpy.count(), 0);
         QCOMPARE(textMessageSpy.count(), 0);
         QCOMPARE(binaryMessageSpy.count(), 0);
         QCOMPARE(textFrameSpy.count(), 0);
         QCOMPARE(binaryFrameSpy.count(), 0);
-        arguments = spy.takeFirst();
+        arguments = errorSpy.takeFirst();
         QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
-        spy.clear();
         buffer.close();
     }
 }
 
-void tst_DataProcessor::frameTooBig()
-{
-    doTest();
-}
-
-void tst_DataProcessor::invalidHeader()
+void tst_DataProcessor::frameTooBig_data()
 {
-    doTest();
-}
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-void tst_DataProcessor::invalidControlFrame()
-{
-    doTest();
-}
+    quint64 swapped64 = 0;
+    const char *wireRepresentation = 0;
 
-void tst_DataProcessor::invalidCloseFrame()
-{
-    doCloseFrameTest();
-}
+    //only data frames are checked for being too big
+    //control frames have explicit checking on a maximum payload size of 125, which is tested elsewhere
 
-void tst_DataProcessor::minimumSizeRequirement()
-{
-    doTest();
+    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+    QTest::newRow("Text frame with payload size > INT_MAX")
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << false
+            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+
+    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+    QTest::newRow("Binary frame with payload size > INT_MAX")
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << false
+            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+
+    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+    QTest::newRow("Continuation frame with payload size > INT_MAX")
+            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << true
+            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
 }
 
-void tst_DataProcessor::invalidPayload()
+void tst_DataProcessor::frameTooBig()
 {
     doTest();
 }
 
-void tst_DataProcessor::invalidPayloadInCloseFrame()
+void tst_DataProcessor::invalidHeader_data()
 {
-    QFETCH(quint8, firstByte);
-    QFETCH(quint8, secondByte);
-    QFETCH(QByteArray, payload);
-    QFETCH(bool, isContinuationFrame);
-    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
-
-    Q_UNUSED(isContinuationFrame)
+    //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<QByteArray>("payload");    //superfluous, but present to be able to call doTest(), which expects a payload field
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-    QByteArray data;
-    QBuffer buffer;
-    QWebSocketDataProcessor dataProcessor;
-    QSignalSpy spy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
-    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
-    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
-    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
-    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    //invalid bit fields
+    invalidField("RSV1 set", RSV1);
+    invalidField("RSV2 set", RSV2);
+    invalidField("RSV3 set", RSV3);
+    invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
+    invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
+    invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
+    invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
 
-    data.append(firstByte).append(secondByte);
-    data.append(payload);
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    QCOMPARE(textMessageSpy.count(), 0);
-    QCOMPARE(binaryMessageSpy.count(), 0);
-    QCOMPARE(textFrameSpy.count(), 0);
-    QCOMPARE(binaryFrameSpy.count(), 0);
-    QVariantList arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
-    buffer.close();
-    spy.clear();
-    data.clear();
+    //invalid opcodes
+    invalidField("Invalid OpCode 3", QWebSocketProtocol::OC_RESERVED_3);
+    invalidField("Invalid OpCode 4", QWebSocketProtocol::OC_RESERVED_4);
+    invalidField("Invalid OpCode 5", QWebSocketProtocol::OC_RESERVED_5);
+    invalidField("Invalid OpCode 6", QWebSocketProtocol::OC_RESERVED_6);
+    invalidField("Invalid OpCode 7", QWebSocketProtocol::OC_RESERVED_7);
+    invalidField("Invalid OpCode B", QWebSocketProtocol::OC_RESERVED_B);
+    invalidField("Invalid OpCode C", QWebSocketProtocol::OC_RESERVED_C);
+    invalidField("Invalid OpCode D", QWebSocketProtocol::OC_RESERVED_D);
+    invalidField("Invalid OpCode E", QWebSocketProtocol::OC_RESERVED_E);
+    invalidField("Invalid OpCode F", QWebSocketProtocol::OC_RESERVED_F);
 }
 
-void tst_DataProcessor::incompletePayload()
+void tst_DataProcessor::invalidHeader()
 {
     doTest();
 }
 
-void tst_DataProcessor::incompleteSizeField()
+void tst_DataProcessor::invalidControlFrame_data()
 {
-    doTest();
-}
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-//////////////////////////////////////////////////////////////////////////////////////////
-/// HELPER FUNCTIONS
-//////////////////////////////////////////////////////////////////////////////////////////
-void tst_DataProcessor::doTest()
-{
-    QFETCH(quint8, firstByte);
-    QFETCH(quint8, secondByte);
-    QFETCH(QByteArray, payload);
-    QFETCH(bool, isContinuationFrame);
-    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
 
-    QByteArray data;
-    QBuffer buffer;
-    QWebSocketDataProcessor dataProcessor;
-    QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
-    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
-    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
-    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
-    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+    QTest::newRow("Close control frame with payload size 126")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Ping control frame with payload size 126")
+            << quint8(FIN | QWebSocketProtocol::OC_PING) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Close control frame with payload size 126")
+            << quint8(FIN | QWebSocketProtocol::OC_PONG) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
 
-    if (isContinuationFrame)
-    {
-        data.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
-    }
-    data.append(firstByte).append(secondByte);
-    data.append(payload);
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    QCOMPARE(textMessageSpy.count(), 0);
-    QCOMPARE(binaryMessageSpy.count(), 0);
-    QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
-    QCOMPARE(binaryFrameSpy.count(), 0);
-    QVariantList arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
-    buffer.close();
-    spy.clear();
-    data.clear();
+    QTest::newRow("Non-final close control frame (fragmented)")
+            << quint8(QWebSocketProtocol::OC_CLOSE) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Non-final ping control frame (fragmented)")
+            << quint8(QWebSocketProtocol::OC_PING) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Non-final pong control frame (fragmented)")
+            << quint8(QWebSocketProtocol::OC_PONG) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
 }
 
-void tst_DataProcessor::doCloseFrameTest()
+void tst_DataProcessor::invalidControlFrame()
 {
-    QFETCH(quint8, firstByte);
-    QFETCH(quint8, secondByte);
-    QFETCH(QByteArray, payload);
-    QFETCH(bool, isContinuationFrame);
-    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
-
-    Q_UNUSED(isContinuationFrame)
-
-    QByteArray data;
-    QBuffer buffer;
-    QWebSocketDataProcessor dataProcessor;
-    QSignalSpy spy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
-    QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
-    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
-    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
-    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
-    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
-
-    data.append(firstByte).append(secondByte);
-    data.append(payload);
-    buffer.setData(data);
-    buffer.open(QIODevice::ReadOnly);
-    dataProcessor.process(&buffer);
-    QCOMPARE(spy.count(), 1);
-    QCOMPARE(errorSpy.count(), 0);
-    QCOMPARE(textMessageSpy.count(), 0);
-    QCOMPARE(binaryMessageSpy.count(), 0);
-    QCOMPARE(textFrameSpy.count(), 0);
-    QCOMPARE(binaryFrameSpy.count(), 0);
-    QVariantList arguments = spy.takeFirst();
-    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
-    buffer.close();
-    spy.clear();
-    data.clear();
+    doTest();
 }
 
-QString tst_DataProcessor::opCodeToString(quint8 opCode)
+void tst_DataProcessor::invalidCloseFrame_data()
 {
-    QString frameType;
-    switch (opCode)
-    {
-        case QWebSocketProtocol::OC_BINARY:
-        {
-            frameType = "Binary";
-            break;
-        }
-        case QWebSocketProtocol::OC_TEXT:
-        {
-            frameType = "Text";
-            break;
-        }
-        case QWebSocketProtocol::OC_PING:
-        {
-            frameType = "Ping";
-            break;
-        }
-        case QWebSocketProtocol::OC_PONG:
-        {
-            frameType = "Pong";
-            break;
-        }
-        case QWebSocketProtocol::OC_CLOSE:
-        {
-            frameType = "Close";
-            break;
-        }
-        case QWebSocketProtocol::OC_CONTINUE:
-        {
-            frameType = "Continuation";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_3:
-        {
-            frameType = "Reserved3";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_4:
-        {
-            frameType = "Reserved5";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_5:
-        {
-            frameType = "Reserved5";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_6:
-        {
-            frameType = "Reserved6";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_7:
-        {
-            frameType = "Reserved7";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_B:
-        {
-            frameType = "ReservedB";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_C:
-        {
-            frameType = "ReservedC";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_D:
-        {
-            frameType = "ReservedD";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_E:
-        {
-            frameType = "ReservedE";
-            break;
-        }
-        case QWebSocketProtocol::OC_RESERVED_F:
-        {
-            frameType = "ReservedF";
-            break;
-        }
-        default:
-        {
-            //should never come here
-            Q_ASSERT(false);
-        }
-    }
-    return frameType;
-}
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
-{
-    quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
-    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
-    QTest::newRow(QString("Text frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-            << quint8(126)
-            << QByteArray(wireRepresentation, 2)
-            << false
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow(QString("Binary frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
-            << quint8(126)
-            << QByteArray(wireRepresentation, 2)
-            << false
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow(QString("Continuation frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-            << quint8(126)
-            << QByteArray(wireRepresentation, 2)
-            << true
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow("Close control frame with payload size 1")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(1) << QByteArray(1, 'a') << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION);
+    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+
+    //Not allowed per RFC 6455 (see para 7.4.1)
+    QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_MISSING_STATUS_CODE);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    //Not allowed per RFC 6455 (see para 7.4.1)
+    QTest::newRow("Close control frame close code MISSING STATUS CODE")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(1004);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 1004")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_TLS_HANDSHAKE_FAILED);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    //Not allowed per RFC 6455 (see para 7.4.1)
+    QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(0);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 0")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(999);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 999")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(1012);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 1012")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(1013);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 1013")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(1014);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 1014")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(1100);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 1100")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(2000);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 2000")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(2999);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 2999")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(5000);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 5000")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    swapped = qToBigEndian<quint16>(65535u);
+    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    QTest::newRow("Close control frame close code 65535")
+            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+               quint8(2) <<
+               QByteArray(wireRepresentation, 2) <<
+               false <<
+               QWebSocketProtocol::CC_PROTOCOL_ERROR;
 }
 
-void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
+void tst_DataProcessor::invalidCloseFrame()
 {
-    quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
-    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-
-    QTest::newRow(QString("Text frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8)
-            << false
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-
-    QTest::newRow(QString("Binary frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8)
-            << false
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-
-    QTest::newRow(QString("Continuation frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8)
-            << true
-            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    doCloseFrameTest();
 }
 
-void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame)
+void tst_DataProcessor::minimumSizeRequirement_data()
 {
-    QByteArray payload = QByteArray::fromHex(utf8Sequence);
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-    if (isCloseFrame)
-    {
-        quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CC_NORMAL);
-        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&closeCode));
-        QTest::newRow(QString("Close frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
-                << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
-                << quint8(payload.length() + 2)
-                << QByteArray(wireRepresentation, 2).append(payload)
-                << false
-                << QWebSocketProtocol::CC_WRONG_DATATYPE;
-    }
-    else
-    {
-        QTest::newRow(QString("Text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
-                << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-                << quint8(payload.length())
-                << payload
-                << false
-                << QWebSocketProtocol::CC_WRONG_DATATYPE;
+    minimumSize16Bit(0);
+    minimumSize16Bit(64);
+    minimumSize16Bit(125);
 
-        QTest::newRow(QString("Continuation text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
-                << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-                << quint8(payload.length())
-                << payload
-                << true
-                << QWebSocketProtocol::CC_WRONG_DATATYPE;
-    }
+    minimumSize64Bit(0);
+    minimumSize64Bit(64);
+    minimumSize64Bit(125);
+    minimumSize64Bit(126);
+    minimumSize64Bit(256);
+    minimumSize64Bit(512);
+    minimumSize64Bit(1024);
+    minimumSize64Bit(2048);
+    minimumSize64Bit(4096);
+    minimumSize64Bit(8192);
+    minimumSize64Bit(16384);
+    minimumSize64Bit(32768);
+    minimumSize64Bit(0xFFFFu);
 }
 
-void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
+void tst_DataProcessor::minimumSizeRequirement()
 {
-    QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
-                           << quint8(0x00)
-                           << QByteArray()
-                           << false
-                           << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow(QString(dataTag).append(" with continuation frame").toStdString().data())
-                            << quint8(FIN | invalidFieldValue)
-                            << quint8(0x00)
-                            << QByteArray()
-                            << true
-                            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    doTest();
 }
 
-void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize)
+void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
 {
-    QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
-    QVERIFY(indicatedSize > actualPayloadSize);
-
-    QString frameType = opCodeToString(controlCode);
-    QByteArray firstFrame;
-
-    if (indicatedSize < 126)
-    {
-        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
-                << quint8(FIN | controlCode)
-                << quint8(indicatedSize)
-                << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
-                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
-                << QWebSocketProtocol::CC_GOING_AWAY;
-    }
-    else if (indicatedSize <= 0xFFFFu)
-    {
-        quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
-        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
-        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
-                << quint8(FIN | controlCode)
-                << quint8(126)
-                << firstFrame.append(QByteArray(wireRepresentation, 2).append(QByteArray(actualPayloadSize, 'a')))
-                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
-                << QWebSocketProtocol::CC_GOING_AWAY;
-    }
-    else
-    {
-        quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
-        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
-                << quint8(FIN | controlCode)
-                << quint8(127)
-                << firstFrame.append(QByteArray(wireRepresentation, 8).append(QByteArray(actualPayloadSize, 'a')))
-                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
-                << QWebSocketProtocol::CC_GOING_AWAY;
-    }
-}
-
-void tst_DataProcessor::nonCharacterSequence(const char *sequence)
-{
-    QByteArray utf8Sequence = QByteArray::fromHex(sequence);
-    //TODO: qstrdup - memory leak! qstrdup is necessary because once QString goes out of scope we have garbage
-    const char *tagName = qstrdup(qPrintable(QString("Text frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
-    const char *tagName2 = qstrdup(qPrintable(QString("Continuation frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
-
-    QTest::newRow(tagName)
-            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-            << quint8(utf8Sequence.size())
-            << utf8Sequence
-            << false;
-
-    QTest::newRow(tagName2)
-            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-            << quint8(utf8Sequence.size())
-            << utf8Sequence
-            << true;
-}
-
-void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
-{
-    QTest::newRow(QString("Text frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-            << quint8(payloadCode)
-            << QByteArray(numBytesFollowing, quint8(1))
-            << false
-            << QWebSocketProtocol::CC_GOING_AWAY;
-    QTest::newRow(QString("Binary frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
-            << quint8(payloadCode)
-            << QByteArray(numBytesFollowing, quint8(1))
-            << false
-            << QWebSocketProtocol::CC_GOING_AWAY;
-    QTest::newRow(QString("Continuation frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
-            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-            << quint8(payloadCode)
-            << QByteArray(numBytesFollowing, quint8(1))
-            << true
-            << QWebSocketProtocol::CC_GOING_AWAY;
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-//// TEST DATA
-//////////////////////////////////////////////////////////////////////////////////
-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<QByteArray>("payload");    //superfluous, but present to be able to call doTest(), which expects a payload field
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
-
-    //invalid bit fields
-    invalidField("RSV1 set", RSV1);
-    invalidField("RSV2 set", RSV2);
-    invalidField("RSV3 set", RSV3);
-    invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
-    invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
-    invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
-    invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
-
-    //invalid opcodes
-    invalidField("Invalid OpCode 3", QWebSocketProtocol::OC_RESERVED_3);
-    invalidField("Invalid OpCode 4", QWebSocketProtocol::OC_RESERVED_4);
-    invalidField("Invalid OpCode 5", QWebSocketProtocol::OC_RESERVED_5);
-    invalidField("Invalid OpCode 6", QWebSocketProtocol::OC_RESERVED_6);
-    invalidField("Invalid OpCode 7", QWebSocketProtocol::OC_RESERVED_7);
-    invalidField("Invalid OpCode B", QWebSocketProtocol::OC_RESERVED_B);
-    invalidField("Invalid OpCode C", QWebSocketProtocol::OC_RESERVED_C);
-    invalidField("Invalid OpCode D", QWebSocketProtocol::OC_RESERVED_D);
-    invalidField("Invalid OpCode E", QWebSocketProtocol::OC_RESERVED_E);
-    invalidField("Invalid OpCode F", QWebSocketProtocol::OC_RESERVED_F);
-}
-
-void tst_DataProcessor::invalidPayloadInCloseFrame_data()
-{
-    invalidPayload_data(true);
-}
-
-void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
-{
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+    QTest::addColumn<quint8>("firstByte");
+    QTest::addColumn<quint8>("secondByte");
+    QTest::addColumn<QByteArray>("payload");
+    QTest::addColumn<bool>("isContinuationFrame");
+    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
     //6.3: invalid UTF-8 sequence
     invalidUTF8("case 6.3.1",   "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
@@ -1174,34 +1122,57 @@ void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
     invalidUTF8("case 6.21.8",  "edafbfedbfbf", isControlFrame);
 }
 
-void tst_DataProcessor::minimumSizeRequirement_data()
+void tst_DataProcessor::invalidPayload()
 {
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+    doTest();
+}
 
-    minimumSize16Bit(0);
-    minimumSize16Bit(64);
-    minimumSize16Bit(125);
+void tst_DataProcessor::invalidPayloadInCloseFrame_data()
+{
+    invalidPayload_data(true);
+}
 
-    minimumSize64Bit(0);
-    minimumSize64Bit(64);
-    minimumSize64Bit(125);
-    minimumSize64Bit(126);
-    minimumSize64Bit(256);
-    minimumSize64Bit(512);
-    minimumSize64Bit(1024);
-    minimumSize64Bit(2048);
-    minimumSize64Bit(4096);
-    minimumSize64Bit(8192);
-    minimumSize64Bit(16384);
-    minimumSize64Bit(32768);
-    minimumSize64Bit(0xFFFFu);
+void tst_DataProcessor::invalidPayloadInCloseFrame()
+{
+    QFETCH(quint8, firstByte);
+    QFETCH(quint8, secondByte);
+    QFETCH(QByteArray, payload);
+    QFETCH(bool, isContinuationFrame);
+    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+    Q_UNUSED(isContinuationFrame)
+
+    QByteArray data;
+    QBuffer buffer;
+    QWebSocketDataProcessor dataProcessor;
+    QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+    QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+    data.append(firstByte).append(secondByte);
+    data.append(payload);
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadOnly);
+    dataProcessor.process(&buffer);
+    QCOMPARE(closeSpy.count(), 1);
+    QCOMPARE(errorSpy.count(), 0);
+    QCOMPARE(pingMessageSpy.count(), 0);
+    QCOMPARE(pongMessageSpy.count(), 0);
+    QCOMPARE(textMessageSpy.count(), 0);
+    QCOMPARE(binaryMessageSpy.count(), 0);
+    QCOMPARE(textFrameSpy.count(), 0);
+    QCOMPARE(binaryFrameSpy.count(), 0);
+    QVariantList arguments = closeSpy.takeFirst();
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+    buffer.close();
 }
 
-void tst_DataProcessor::invalidControlFrame_data()
+void tst_DataProcessor::incompletePayload_data()
 {
     QTest::addColumn<quint8>("firstByte");
     QTest::addColumn<quint8>("secondByte");
@@ -1209,23 +1180,30 @@ void tst_DataProcessor::invalidControlFrame_data()
     QTest::addColumn<bool>("isContinuationFrame");
     QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
+    incompleteFrame(QWebSocketProtocol::OC_TEXT, 125, 0);
+    incompleteFrame(QWebSocketProtocol::OC_TEXT, 64, 32);
+    incompleteFrame(QWebSocketProtocol::OC_TEXT, 256, 32);
+    incompleteFrame(QWebSocketProtocol::OC_TEXT, 128000, 32);
+    incompleteFrame(QWebSocketProtocol::OC_BINARY, 125, 0);
+    incompleteFrame(QWebSocketProtocol::OC_BINARY, 64, 32);
+    incompleteFrame(QWebSocketProtocol::OC_BINARY, 256, 32);
+    incompleteFrame(QWebSocketProtocol::OC_BINARY, 128000, 32);
+    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 125, 0);
+    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 64, 32);
+    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 256, 32);
+    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 128000, 32);
 
-    QTest::newRow("Close control frame with payload size 126")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Ping control frame with payload size 126")
-            << quint8(FIN | QWebSocketProtocol::OC_PING) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Close control frame with payload size 126")
-            << quint8(FIN | QWebSocketProtocol::OC_PONG) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    incompleteFrame(QWebSocketProtocol::OC_CLOSE, 64, 32);
+    incompleteFrame(QWebSocketProtocol::OC_PING, 64, 32);
+    incompleteFrame(QWebSocketProtocol::OC_PONG, 64, 32);
+}
 
-    QTest::newRow("Non-final close control frame (fragmented)")
-            << quint8(QWebSocketProtocol::OC_CLOSE) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Non-final ping control frame (fragmented)")
-            << quint8(QWebSocketProtocol::OC_PING) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    QTest::newRow("Non-final pong control frame (fragmented)")
-            << quint8(QWebSocketProtocol::OC_PONG) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+void tst_DataProcessor::incompletePayload()
+{
+    doTest();
 }
 
-void tst_DataProcessor::invalidCloseFrame_data()
+void tst_DataProcessor::incompleteSizeField_data()
 {
     QTest::addColumn<quint8>("firstByte");
     QTest::addColumn<quint8>("secondByte");
@@ -1233,262 +1211,381 @@ void tst_DataProcessor::invalidCloseFrame_data()
     QTest::addColumn<bool>("isContinuationFrame");
     QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
 
-    QTest::newRow("Close control frame with payload size 1")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(1) << QByteArray(1, 'a') << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION);
-    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    insertIncompleteSizeFieldTest(126, 0);
+    insertIncompleteSizeFieldTest(126, 1);
 
-    //Not allowed per RFC 6455 (see para 7.4.1)
-    QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_MISSING_STATUS_CODE);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    //Not allowed per RFC 6455 (see para 7.4.1)
-    QTest::newRow("Close control frame close code MISSING STATUS CODE")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(1004);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 1004")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_TLS_HANDSHAKE_FAILED);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    //Not allowed per RFC 6455 (see para 7.4.1)
-    QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(0);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 0")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(999);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 999")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(1012);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 1012")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(1013);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 1013")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(1014);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 1014")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(1100);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 1100")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(2000);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 2000")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(2999);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 2999")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(5000);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 5000")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
-    swapped = qToBigEndian<quint16>(65535u);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
-    QTest::newRow("Close control frame close code 65535")
-            << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
-               quint8(2) <<
-               QByteArray(wireRepresentation, 2) <<
-               false <<
-               QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    insertIncompleteSizeFieldTest(127, 0);
+    insertIncompleteSizeFieldTest(127, 1);
+    insertIncompleteSizeFieldTest(127, 2);
+    insertIncompleteSizeFieldTest(127, 3);
+    insertIncompleteSizeFieldTest(127, 4);
+    insertIncompleteSizeFieldTest(127, 5);
+    insertIncompleteSizeFieldTest(127, 6);
+    insertIncompleteSizeFieldTest(127, 7);
+}
+
+void tst_DataProcessor::incompleteSizeField()
+{
+    doTest();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+/// HELPER FUNCTIONS
+//////////////////////////////////////////////////////////////////////////////////////////
+void tst_DataProcessor::doTest()
+{
+    QFETCH(quint8, firstByte);
+    QFETCH(quint8, secondByte);
+    QFETCH(QByteArray, payload);
+    QFETCH(bool, isContinuationFrame);
+    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+    QByteArray data;
+    QBuffer buffer;
+    QWebSocketDataProcessor dataProcessor;
+    QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+    if (isContinuationFrame)
+    {
+        data.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
+    }
+    data.append(firstByte).append(secondByte);
+    data.append(payload);
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadOnly);
+    dataProcessor.process(&buffer);
+    QCOMPARE(errorSpy.count(), 1);
+    QCOMPARE(textMessageSpy.count(), 0);
+    QCOMPARE(binaryMessageSpy.count(), 0);
+    QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
+    QCOMPARE(binaryFrameSpy.count(), 0);
+    QVariantList arguments = errorSpy.takeFirst();
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+    buffer.close();
+    errorSpy.clear();
+    data.clear();
+}
+
+void tst_DataProcessor::doCloseFrameTest()
+{
+    QFETCH(quint8, firstByte);
+    QFETCH(quint8, secondByte);
+    QFETCH(QByteArray, payload);
+    QFETCH(bool, isContinuationFrame);
+    QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+    Q_UNUSED(isContinuationFrame)
+
+    QByteArray data;
+    QBuffer buffer;
+    QWebSocketDataProcessor dataProcessor;
+    QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+    QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+    QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+    QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+    QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+    data.append(firstByte).append(secondByte);
+    data.append(payload);
+    buffer.setData(data);
+    buffer.open(QIODevice::ReadOnly);
+    dataProcessor.process(&buffer);
+    QCOMPARE(closeSpy.count(), 1);
+    QCOMPARE(errorSpy.count(), 0);
+    QCOMPARE(textMessageSpy.count(), 0);
+    QCOMPARE(binaryMessageSpy.count(), 0);
+    QCOMPARE(textFrameSpy.count(), 0);
+    QCOMPARE(binaryFrameSpy.count(), 0);
+    QVariantList arguments = closeSpy.takeFirst();
+    QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+    buffer.close();
+}
+
+QString tst_DataProcessor::opCodeToString(quint8 opCode)
+{
+    QString frameType;
+    switch (opCode)
+    {
+        case QWebSocketProtocol::OC_BINARY:
+        {
+            frameType = "Binary";
+            break;
+        }
+        case QWebSocketProtocol::OC_TEXT:
+        {
+            frameType = "Text";
+            break;
+        }
+        case QWebSocketProtocol::OC_PING:
+        {
+            frameType = "Ping";
+            break;
+        }
+        case QWebSocketProtocol::OC_PONG:
+        {
+            frameType = "Pong";
+            break;
+        }
+        case QWebSocketProtocol::OC_CLOSE:
+        {
+            frameType = "Close";
+            break;
+        }
+        case QWebSocketProtocol::OC_CONTINUE:
+        {
+            frameType = "Continuation";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_3:
+        {
+            frameType = "Reserved3";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_4:
+        {
+            frameType = "Reserved5";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_5:
+        {
+            frameType = "Reserved5";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_6:
+        {
+            frameType = "Reserved6";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_7:
+        {
+            frameType = "Reserved7";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_B:
+        {
+            frameType = "ReservedB";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_C:
+        {
+            frameType = "ReservedC";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_D:
+        {
+            frameType = "ReservedD";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_E:
+        {
+            frameType = "ReservedE";
+            break;
+        }
+        case QWebSocketProtocol::OC_RESERVED_F:
+        {
+            frameType = "ReservedF";
+            break;
+        }
+        default:
+        {
+            //should never come here
+            Q_ASSERT(false);
+        }
+    }
+    return frameType;
+}
+
+void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
+{
+    quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
+    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+    QTest::newRow(QString("Text frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+            << quint8(126)
+            << QByteArray(wireRepresentation, 2)
+            << false
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow(QString("Binary frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+            << quint8(126)
+            << QByteArray(wireRepresentation, 2)
+            << false
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow(QString("Continuation frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+            << quint8(126)
+            << QByteArray(wireRepresentation, 2)
+            << true
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
 }
 
-void tst_DataProcessor::incompleteSizeField_data()
+void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
 {
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+    quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
+    const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
 
-    //////////////////////////////////////////////////////////////////////////////////////////////////
-    //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
-    //////////////////////////////////////////////////////////////////////////////////////////////////
-    insertIncompleteSizeFieldTest(126, 0);
-    insertIncompleteSizeFieldTest(126, 1);
+    QTest::newRow(QString("Text frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8)
+            << false
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
 
-    //////////////////////////////////////////////////////////////////////////////////////////////////
-    //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
-    //////////////////////////////////////////////////////////////////////////////////////////////////
-    insertIncompleteSizeFieldTest(127, 0);
-    insertIncompleteSizeFieldTest(127, 1);
-    insertIncompleteSizeFieldTest(127, 2);
-    insertIncompleteSizeFieldTest(127, 3);
-    insertIncompleteSizeFieldTest(127, 4);
-    insertIncompleteSizeFieldTest(127, 5);
-    insertIncompleteSizeFieldTest(127, 6);
-    insertIncompleteSizeFieldTest(127, 7);
+    QTest::newRow(QString("Binary frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8)
+            << false
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+    QTest::newRow(QString("Continuation frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+            << quint8(127)
+            << QByteArray(wireRepresentation, 8)
+            << true
+            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
 }
 
-void tst_DataProcessor::nonCharacterCodes_data()
+void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame)
 {
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
+    QByteArray payload = QByteArray::fromHex(utf8Sequence);
 
-    nonCharacterSequence("efbfbe");
-    nonCharacterSequence("efbfbf");
-    nonCharacterSequence("f09fbfbe");
-    nonCharacterSequence("f09fbfbf");
-    nonCharacterSequence("f0afbfbe");
-    nonCharacterSequence("f0afbfbf");
-    nonCharacterSequence("f0bfbfbe");
-    nonCharacterSequence("f0bfbfbf");
-    nonCharacterSequence("f18fbfbe");
-    nonCharacterSequence("f18fbfbf");
-    nonCharacterSequence("f19fbfbe");
-    nonCharacterSequence("f19fbfbf");
-    nonCharacterSequence("f1afbfbe");
-    nonCharacterSequence("f1afbfbf");
-    nonCharacterSequence("f1bfbfbe");
-    nonCharacterSequence("f1bfbfbf");
-    nonCharacterSequence("f28fbfbe");
-    nonCharacterSequence("f28fbfbf");
-    nonCharacterSequence("f29fbfbe");
-    nonCharacterSequence("f29fbfbf");
-    nonCharacterSequence("f2afbfbe");
-    nonCharacterSequence("f2afbfbf");
-    nonCharacterSequence("f2bfbfbe");
-    nonCharacterSequence("f2bfbfbf");
-    nonCharacterSequence("f38fbfbe");
-    nonCharacterSequence("f38fbfbf");
-    nonCharacterSequence("f39fbfbe");
-    nonCharacterSequence("f39fbfbf");
-    nonCharacterSequence("f3afbfbe");
-    nonCharacterSequence("f3afbfbf");
-    nonCharacterSequence("f3bfbfbe");
-    nonCharacterSequence("f3bfbfbf");
-    nonCharacterSequence("f48fbfbe");
-    nonCharacterSequence("f48fbfbf");
+    if (isCloseFrame)
+    {
+        quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CC_NORMAL);
+        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&closeCode));
+        QTest::newRow(QString("Close frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+                << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
+                << quint8(payload.length() + 2)
+                << QByteArray(wireRepresentation, 2).append(payload)
+                << false
+                << QWebSocketProtocol::CC_WRONG_DATATYPE;
+    }
+    else
+    {
+        QTest::newRow(QString("Text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+                << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+                << quint8(payload.length())
+                << payload
+                << false
+                << QWebSocketProtocol::CC_WRONG_DATATYPE;
+
+        QTest::newRow(QString("Continuation text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+                << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+                << quint8(payload.length())
+                << payload
+                << true
+                << QWebSocketProtocol::CC_WRONG_DATATYPE;
+    }
 }
 
-void tst_DataProcessor::incompletePayload_data()
+void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
 {
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+    QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
+                           << quint8(0x00)
+                           << QByteArray()
+                           << false
+                           << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+    QTest::newRow(QString(dataTag).append(" with continuation frame").toStdString().data())
+                            << quint8(FIN | invalidFieldValue)
+                            << quint8(0x00)
+                            << QByteArray()
+                            << true
+                            << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+}
 
-    incompleteFrame(QWebSocketProtocol::OC_TEXT, 125, 0);
-    incompleteFrame(QWebSocketProtocol::OC_TEXT, 64, 32);
-    incompleteFrame(QWebSocketProtocol::OC_TEXT, 256, 32);
-    incompleteFrame(QWebSocketProtocol::OC_TEXT, 128000, 32);
-    incompleteFrame(QWebSocketProtocol::OC_BINARY, 125, 0);
-    incompleteFrame(QWebSocketProtocol::OC_BINARY, 64, 32);
-    incompleteFrame(QWebSocketProtocol::OC_BINARY, 256, 32);
-    incompleteFrame(QWebSocketProtocol::OC_BINARY, 128000, 32);
-    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 125, 0);
-    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 64, 32);
-    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 256, 32);
-    incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 128000, 32);
+void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize)
+{
+    QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
+    QVERIFY(indicatedSize > actualPayloadSize);
 
-    incompleteFrame(QWebSocketProtocol::OC_CLOSE, 64, 32);
-    incompleteFrame(QWebSocketProtocol::OC_PING, 64, 32);
-    incompleteFrame(QWebSocketProtocol::OC_PONG, 64, 32);
+    QString frameType = opCodeToString(controlCode);
+    QByteArray firstFrame;
+
+    if (indicatedSize < 126)
+    {
+        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+                << quint8(FIN | controlCode)
+                << quint8(indicatedSize)
+                << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
+                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+                << QWebSocketProtocol::CC_GOING_AWAY;
+    }
+    else if (indicatedSize <= 0xFFFFu)
+    {
+        quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
+        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+                << quint8(FIN | controlCode)
+                << quint8(126)
+                << firstFrame.append(QByteArray(wireRepresentation, 2).append(QByteArray(actualPayloadSize, 'a')))
+                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+                << QWebSocketProtocol::CC_GOING_AWAY;
+    }
+    else
+    {
+        quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
+        const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+        QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+                << quint8(FIN | controlCode)
+                << quint8(127)
+                << firstFrame.append(QByteArray(wireRepresentation, 8).append(QByteArray(actualPayloadSize, 'a')))
+                << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+                << QWebSocketProtocol::CC_GOING_AWAY;
+    }
 }
 
-void tst_DataProcessor::frameTooBig_data()
+void tst_DataProcessor::nonCharacterSequence(const char *sequence)
 {
-    QTest::addColumn<quint8>("firstByte");
-    QTest::addColumn<quint8>("secondByte");
-    QTest::addColumn<QByteArray>("payload");
-    QTest::addColumn<bool>("isContinuationFrame");
-    QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+    QByteArray utf8Sequence = QByteArray::fromHex(sequence);
+    //TODO: qstrdup - memory leak! qstrdup is necessary because once QString goes out of scope we have garbage
+    const char *tagName = qstrdup(qPrintable(QString("Text frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
+    const char *tagName2 = qstrdup(qPrintable(QString("Continuation frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
 
-    quint64 swapped64 = 0;
-    const char *wireRepresentation = 0;
+    QTest::newRow(tagName)
+            << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+            << quint8(utf8Sequence.size())
+            << utf8Sequence
+            << false;
 
-    //only data frames are checked for being too big
-    //control frames have explicit checking on a maximum payload size of 125, which is tested elsewhere
+    QTest::newRow(tagName2)
+            << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+            << quint8(utf8Sequence.size())
+            << utf8Sequence
+            << true;
+}
 
-    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-    QTest::newRow("Text frame with payload size > INT_MAX")
+void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
+{
+    QTest::newRow(QString("Text frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
             << quint8(FIN | QWebSocketProtocol::OC_TEXT)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << quint8(payloadCode)
+            << QByteArray(numBytesFollowing, quint8(1))
             << false
-            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-
-    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-    QTest::newRow("Binary frame with payload size > INT_MAX")
+            << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow(QString("Binary frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
             << quint8(FIN | QWebSocketProtocol::OC_BINARY)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << quint8(payloadCode)
+            << QByteArray(numBytesFollowing, quint8(1))
             << false
-            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-
-    swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
-    wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-    QTest::newRow("Continuation frame with payload size > INT_MAX")
+            << QWebSocketProtocol::CC_GOING_AWAY;
+    QTest::newRow(QString("Continuation frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
             << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
-            << quint8(127)
-            << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+            << quint8(payloadCode)
+            << QByteArray(numBytesFollowing, quint8(1))
             << true
-            << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+            << QWebSocketProtocol::CC_GOING_AWAY;
 }
 
 QTEST_MAIN(tst_DataProcessor)