1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #include <QtTest/QtTest> |
29 | #include <QtTest/qtestcase.h> |
30 | #include <QtEndian> |
31 | |
32 | #include <QDebug> |
33 | |
34 | #include "QtWebSockets/qwebsocketprotocol.h" |
35 | #include "private/qwebsocketprotocol_p.h" |
36 | |
37 | QT_USE_NAMESPACE |
38 | |
39 | Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) |
40 | Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) |
41 | Q_DECLARE_METATYPE(QWebSocketProtocol::Version) |
42 | |
43 | class tst_WebSocketProtocol : public QObject |
44 | { |
45 | Q_OBJECT |
46 | |
47 | public: |
48 | tst_WebSocketProtocol(); |
49 | |
50 | private Q_SLOTS: |
51 | void initTestCase(); |
52 | void cleanupTestCase(); |
53 | void init(); |
54 | void cleanup(); |
55 | |
56 | void tst_validMasks_data(); |
57 | void tst_validMasks(); |
58 | |
59 | void tst_opCodes_data(); |
60 | void tst_opCodes(); |
61 | |
62 | void tst_closeCodes_data(); |
63 | void tst_closeCodes(); |
64 | |
65 | void tst_versionFromString_data(); |
66 | void tst_versionFromString(); |
67 | }; |
68 | |
69 | tst_WebSocketProtocol::tst_WebSocketProtocol() |
70 | {} |
71 | |
72 | void tst_WebSocketProtocol::initTestCase() |
73 | { |
74 | } |
75 | |
76 | void tst_WebSocketProtocol::cleanupTestCase() |
77 | {} |
78 | |
79 | void tst_WebSocketProtocol::init() |
80 | { |
81 | qRegisterMetaType<QWebSocketProtocol::OpCode>(typeName: "QWebSocketProtocol::OpCode" ); |
82 | qRegisterMetaType<QWebSocketProtocol::CloseCode>(typeName: "QWebSocketProtocol::CloseCode" ); |
83 | } |
84 | |
85 | void tst_WebSocketProtocol::cleanup() |
86 | { |
87 | } |
88 | |
89 | void tst_WebSocketProtocol::tst_validMasks_data() |
90 | { |
91 | QTest::addColumn<quint32>(name: "mask" ); |
92 | QTest::addColumn<QString>(name: "inputdata" ); |
93 | QTest::addColumn<QByteArray>(name: "result" ); |
94 | |
95 | QTest::newRow(dataTag: "Empty payload" ) << 0x12345678u << QString() << QByteArray(); |
96 | QTest::newRow(dataTag: "ASCII payload of 8 characters" ) |
97 | << 0x12345678u |
98 | << QStringLiteral("abcdefgh" ) |
99 | << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10" ); |
100 | QTest::newRow(dataTag: "ASCII payload of 9 characters" ) |
101 | << 0x12345678u |
102 | << QStringLiteral("abcdefghi" ) |
103 | << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10\x7B" ); |
104 | //MSVC doesn't like UTF-8 in source code; |
105 | //the following text is represented in the string below: ∫∂ƒ©øØ |
106 | QTest::newRow(dataTag: "UTF-8 payload" ) |
107 | << 0x12345678u |
108 | << QString::fromUtf8(str: "\xE2\x88\xAB\xE2\x88\x82\xC6\x92\xC2\xA9\xC3\xB8\xC3\x98" ) |
109 | << QByteArrayLiteral("\x2D\x0B\x69\xD1\xEA\xEC" ); |
110 | } |
111 | |
112 | void tst_WebSocketProtocol::tst_validMasks() |
113 | { |
114 | QFETCH(quint32, mask); |
115 | QFETCH(QString, inputdata); |
116 | QFETCH(QByteArray, result); |
117 | |
118 | //put latin1 into an explicit array |
119 | //otherwise, the intermediate object is deleted and the data pointer becomes invalid |
120 | QByteArray latin1 = inputdata.toLatin1(); |
121 | char *data = latin1.data(); |
122 | |
123 | QWebSocketProtocol::mask(payload: data, size: inputdata.size(), maskingKey: mask); |
124 | QCOMPARE(QByteArray::fromRawData(data, inputdata.size()), result); |
125 | } |
126 | |
127 | void tst_WebSocketProtocol::tst_opCodes_data() |
128 | { |
129 | QTest::addColumn<QWebSocketProtocol::OpCode>(name: "opCode" ); |
130 | QTest::addColumn<bool>(name: "isReserved" ); |
131 | |
132 | QTest::newRow(dataTag: "OpCodeBinary" ) << QWebSocketProtocol::OpCodeBinary << false; |
133 | QTest::newRow(dataTag: "OpCodeClose" ) << QWebSocketProtocol::OpCodeClose << false; |
134 | QTest::newRow(dataTag: "OpCodeContinue" ) << QWebSocketProtocol::OpCodeContinue << false; |
135 | QTest::newRow(dataTag: "OpCodePing" ) << QWebSocketProtocol::OpCodePing << false; |
136 | QTest::newRow(dataTag: "OpCodePong" ) << QWebSocketProtocol::OpCodePong << false; |
137 | QTest::newRow(dataTag: "OpCodeReserved3" ) << QWebSocketProtocol::OpCodeReserved3 << true; |
138 | QTest::newRow(dataTag: "OpCodeReserved4" ) << QWebSocketProtocol::OpCodeReserved4 << true; |
139 | QTest::newRow(dataTag: "OpCodeReserved5" ) << QWebSocketProtocol::OpCodeReserved5 << true; |
140 | QTest::newRow(dataTag: "OpCodeReserved6" ) << QWebSocketProtocol::OpCodeReserved6 << true; |
141 | QTest::newRow(dataTag: "OpCodeReserved7" ) << QWebSocketProtocol::OpCodeReserved7 << true; |
142 | QTest::newRow(dataTag: "OpCodeReserved8" ) << QWebSocketProtocol::OpCodeReservedB << true; |
143 | QTest::newRow(dataTag: "OpCodeReservedC" ) << QWebSocketProtocol::OpCodeReservedC << true; |
144 | QTest::newRow(dataTag: "OpCodeReservedD" ) << QWebSocketProtocol::OpCodeReservedD << true; |
145 | QTest::newRow(dataTag: "OpCodeReservedE" ) << QWebSocketProtocol::OpCodeReservedE << true; |
146 | QTest::newRow(dataTag: "OpCodeReservedF" ) << QWebSocketProtocol::OpCodeReservedF << true; |
147 | QTest::newRow(dataTag: "OpCodeText" ) << QWebSocketProtocol::OpCodeText << false; |
148 | } |
149 | |
150 | void tst_WebSocketProtocol::tst_opCodes() |
151 | { |
152 | QFETCH(QWebSocketProtocol::OpCode, opCode); |
153 | QFETCH(bool, isReserved); |
154 | |
155 | bool result = QWebSocketProtocol::isOpCodeReserved(code: opCode); |
156 | |
157 | QCOMPARE(result, isReserved); |
158 | } |
159 | |
160 | void tst_WebSocketProtocol::tst_closeCodes_data() |
161 | { |
162 | QTest::addColumn<int>(name: "closeCode" ); |
163 | QTest::addColumn<bool>(name: "isValid" ); |
164 | |
165 | for (int i = 0; i < 1000; ++i) |
166 | { |
167 | QTest::newRow(QStringLiteral("Close code %1" ).arg(a: i).toLatin1().constData()) << i << false; |
168 | } |
169 | |
170 | for (int i = 1000; i < 1004; ++i) |
171 | { |
172 | QTest::newRow(QStringLiteral("Close code %1" ).arg(a: i).toLatin1().constData()) << i << true; |
173 | } |
174 | |
175 | QTest::newRow(dataTag: "Close code 1004" ) << 1004 << false; |
176 | QTest::newRow(dataTag: "Close code 1005" ) << 1005 << false; |
177 | QTest::newRow(dataTag: "Close code 1006" ) << 1006 << false; |
178 | |
179 | for (int i = 1007; i < 1012; ++i) |
180 | { |
181 | QTest::newRow(QStringLiteral("Close code %1" ).arg(a: i).toLatin1().constData()) << i << true; |
182 | } |
183 | |
184 | for (int i = 1013; i < 3000; ++i) |
185 | { |
186 | QTest::newRow(QStringLiteral("Close code %1" ).arg(a: i).toLatin1().constData()) << i << false; |
187 | } |
188 | |
189 | for (int i = 3000; i < 5000; ++i) |
190 | { |
191 | QTest::newRow(QStringLiteral("Close code %1" ).arg(a: i).toLatin1().constData()) << i << true; |
192 | } |
193 | |
194 | QTest::newRow(dataTag: "Close code 5000" ) << 1004 << false; |
195 | QTest::newRow(dataTag: "Close code 6000" ) << 1004 << false; |
196 | QTest::newRow(dataTag: "Close code 7000" ) << 1004 << false; |
197 | } |
198 | |
199 | void tst_WebSocketProtocol::tst_closeCodes() |
200 | { |
201 | QFETCH(int, closeCode); |
202 | QFETCH(bool, isValid); |
203 | |
204 | bool result = QWebSocketProtocol::isCloseCodeValid(closeCode); |
205 | |
206 | QCOMPARE(result, isValid); |
207 | } |
208 | |
209 | void tst_WebSocketProtocol::tst_versionFromString_data() |
210 | { |
211 | QTest::addColumn<QWebSocketProtocol::Version>(name: "version" ); |
212 | QTest::addColumn<QString>(name: "versionString" ); |
213 | |
214 | //happy flow; good data |
215 | QTest::newRow(dataTag: "Version 0" ) |
216 | << QWebSocketProtocol::Version0 |
217 | << QStringLiteral("0" ); |
218 | QTest::newRow(dataTag: "Version 4" ) |
219 | << QWebSocketProtocol::Version4 |
220 | << QStringLiteral("4" ); |
221 | QTest::newRow(dataTag: "Version 5" ) |
222 | << QWebSocketProtocol::Version5 |
223 | << QStringLiteral("5" ); |
224 | QTest::newRow(dataTag: "Version 6" ) |
225 | << QWebSocketProtocol::Version6 |
226 | << QStringLiteral("6" ); |
227 | QTest::newRow(dataTag: "Version 7" ) |
228 | << QWebSocketProtocol::Version7 |
229 | << QStringLiteral("7" ); |
230 | QTest::newRow(dataTag: "Version 8" ) |
231 | << QWebSocketProtocol::Version8 |
232 | << QStringLiteral("8" ); |
233 | QTest::newRow(dataTag: "Version 13" ) |
234 | << QWebSocketProtocol::Version13 |
235 | << QStringLiteral("13" ); |
236 | |
237 | //rainy flow; invalid data |
238 | QTest::newRow(dataTag: "Version -1" ) |
239 | << QWebSocketProtocol::VersionUnknown |
240 | << QStringLiteral("-1" ); |
241 | QTest::newRow(dataTag: "Version 1" ) |
242 | << QWebSocketProtocol::VersionUnknown |
243 | << QStringLiteral("1" ); |
244 | QTest::newRow(dataTag: "Version 2" ) |
245 | << QWebSocketProtocol::VersionUnknown |
246 | << QStringLiteral("2" ); |
247 | QTest::newRow(dataTag: "Version 3" ) |
248 | << QWebSocketProtocol::VersionUnknown |
249 | << QStringLiteral("3" ); |
250 | QTest::newRow(dataTag: "Version 9" ) |
251 | << QWebSocketProtocol::VersionUnknown |
252 | << QStringLiteral("9" ); |
253 | QTest::newRow(dataTag: "Version 10" ) |
254 | << QWebSocketProtocol::VersionUnknown |
255 | << QStringLiteral("10" ); |
256 | QTest::newRow(dataTag: "Version 11" ) |
257 | << QWebSocketProtocol::VersionUnknown |
258 | << QStringLiteral("11" ); |
259 | QTest::newRow(dataTag: "Version 12" ) |
260 | << QWebSocketProtocol::VersionUnknown |
261 | << QStringLiteral("12" ); |
262 | QTest::newRow(dataTag: "Version abcd" ) |
263 | << QWebSocketProtocol::VersionUnknown |
264 | << QStringLiteral("abcd" ); |
265 | QTest::newRow(dataTag: "Version 1.6" ) |
266 | << QWebSocketProtocol::VersionUnknown |
267 | << QStringLiteral("1.6" ); |
268 | QTest::newRow(dataTag: "Version empty" ) |
269 | << QWebSocketProtocol::VersionUnknown |
270 | << QString(); |
271 | } |
272 | |
273 | void tst_WebSocketProtocol::tst_versionFromString() |
274 | { |
275 | QFETCH(QWebSocketProtocol::Version, version); |
276 | QFETCH(QString, versionString); |
277 | |
278 | QCOMPARE(QWebSocketProtocol::versionFromString(versionString), version); |
279 | } |
280 | |
281 | QTEST_MAIN(tst_WebSocketProtocol) |
282 | |
283 | #include "tst_websocketprotocol.moc" |
284 | |
285 | |