| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 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 |  | 
| 29 | #include <QtCore/QCoreApplication> | 
| 30 | #include <QtNetwork/QtNetwork> | 
| 31 | #include <QtTest/QtTest> | 
| 32 |  | 
| 33 | #include "../../../network-settings.h" | 
| 34 |  | 
| 35 | class tst_QIODevice : public QObject | 
| 36 | { | 
| 37 |     Q_OBJECT | 
| 38 |  | 
| 39 | private slots: | 
| 40 |     void initTestCase(); | 
| 41 |     void cleanupTestCase(); | 
| 42 |     void getSetCheck(); | 
| 43 |     void constructing_QTcpSocket(); | 
| 44 |     void constructing_QFile(); | 
| 45 |     void read_QByteArray(); | 
| 46 |     void unget(); | 
| 47 |     void peek(); | 
| 48 |     void peekAndRead(); | 
| 49 |  | 
| 50 |     void readLine_data(); | 
| 51 |     void readLine(); | 
| 52 |  | 
| 53 |     void readLine2_data(); | 
| 54 |     void readLine2(); | 
| 55 |  | 
| 56 |     void readAllKeepPosition(); | 
| 57 |     void writeInTextMode(); | 
| 58 |     void skip_data(); | 
| 59 |     void skip(); | 
| 60 |     void skipAfterPeek_data(); | 
| 61 |     void skipAfterPeek(); | 
| 62 |  | 
| 63 |     void transaction_data(); | 
| 64 |     void transaction(); | 
| 65 |  | 
| 66 | private: | 
| 67 |     QSharedPointer<QTemporaryDir> m_tempDir; | 
| 68 |     QString m_previousCurrent; | 
| 69 | }; | 
| 70 |  | 
| 71 | void tst_QIODevice::initTestCase() | 
| 72 | { | 
| 73 | #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) | 
| 74 |     QVERIFY(QFileInfo(QStringLiteral("./tst_qiodevice.cpp" )).exists() | 
| 75 |             || QFile::copy(QStringLiteral(":/tst_qiodevice.cpp" ), QStringLiteral("./tst_qiodevice.cpp" ))); | 
| 76 | #endif | 
| 77 |     m_previousCurrent = QDir::currentPath(); | 
| 78 |     m_tempDir = QSharedPointer<QTemporaryDir>::create(); | 
| 79 |     QVERIFY2(!m_tempDir.isNull(), qPrintable("Could not create temporary directory." )); | 
| 80 |     QVERIFY2(QDir::setCurrent(m_tempDir->path()), qPrintable("Could not switch current directory" )); | 
| 81 | } | 
| 82 |  | 
| 83 | void tst_QIODevice::cleanupTestCase() | 
| 84 | { | 
| 85 |     QDir::setCurrent(m_previousCurrent); | 
| 86 | } | 
| 87 |  | 
| 88 | // Testing get/set functions | 
| 89 | void tst_QIODevice::getSetCheck() | 
| 90 | { | 
| 91 |     // OpenMode QIODevice::openMode() | 
| 92 |     // void QIODevice::setOpenMode(OpenMode) | 
| 93 |     class MyIODevice : public QTcpSocket { | 
| 94 |     public: | 
| 95 |         using QTcpSocket::setOpenMode; | 
| 96 |     }; | 
| 97 |     MyIODevice var1; | 
| 98 |     var1.setOpenMode(QIODevice::OpenMode(QIODevice::NotOpen)); | 
| 99 |     QCOMPARE(QIODevice::OpenMode(QIODevice::NotOpen), var1.openMode()); | 
| 100 |     var1.setOpenMode(QIODevice::OpenMode(QIODevice::ReadWrite)); | 
| 101 |     QCOMPARE(QIODevice::OpenMode(QIODevice::ReadWrite), var1.openMode()); | 
| 102 | } | 
| 103 |  | 
| 104 | //---------------------------------------------------------------------------------- | 
| 105 | void tst_QIODevice::constructing_QTcpSocket() | 
| 106 | { | 
| 107 | #if defined(Q_OS_WINRT) | 
| 108 |     QSKIP("Synchronous socket calls are broken on winrt. See QTBUG-40922" ); | 
| 109 | #endif | 
| 110 |     if (!QtNetworkSettings::verifyTestNetworkSettings()) | 
| 111 |         QSKIP("No network test server available" ); | 
| 112 |  | 
| 113 |     QTcpSocket socket; | 
| 114 |     QIODevice *device = &socket; | 
| 115 |  | 
| 116 |     QVERIFY(!device->isOpen()); | 
| 117 |  | 
| 118 |     socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: 143); | 
| 119 |     QVERIFY(socket.waitForConnected(30000)); | 
| 120 |     QVERIFY(device->isOpen()); | 
| 121 |     QCOMPARE(device->readChannelCount(), 1); | 
| 122 |     QCOMPARE(device->writeChannelCount(), 1); | 
| 123 |  | 
| 124 |     while (!device->canReadLine()) | 
| 125 |         QVERIFY(device->waitForReadyRead(30000)); | 
| 126 |  | 
| 127 |     char buf[1024]; | 
| 128 |     memset(s: buf, c: 0, n: sizeof(buf)); | 
| 129 |     qlonglong lineLength = device->readLine(data: buf, maxlen: sizeof(buf)); | 
| 130 |     QVERIFY(lineLength > 0); | 
| 131 |     QCOMPARE(socket.pos(), qlonglong(0)); | 
| 132 |  | 
| 133 |     socket.close(); | 
| 134 |     QCOMPARE(socket.readChannelCount(), 0); | 
| 135 |     QCOMPARE(socket.writeChannelCount(), 0); | 
| 136 |     socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: 143); | 
| 137 |     QVERIFY(socket.waitForConnected(30000)); | 
| 138 |     QVERIFY(device->isOpen()); | 
| 139 |  | 
| 140 |     while (!device->canReadLine()) | 
| 141 |         QVERIFY(device->waitForReadyRead(30000)); | 
| 142 |  | 
| 143 |     char buf2[1024]; | 
| 144 |     memset(s: buf2, c: 0, n: sizeof(buf2)); | 
| 145 |     QCOMPARE(socket.readLine(buf2, sizeof(buf2)), lineLength); | 
| 146 |  | 
| 147 |     char *c1 = buf; | 
| 148 |     char *c2 = buf2; | 
| 149 |     while (*c1 && *c2) { | 
| 150 |         QCOMPARE(*c1, *c2); | 
| 151 |         ++c1; | 
| 152 |         ++c2; | 
| 153 |     } | 
| 154 |     QCOMPARE(*c1, *c2); | 
| 155 | } | 
| 156 |  | 
| 157 | //---------------------------------------------------------------------------------- | 
| 158 | void tst_QIODevice::constructing_QFile() | 
| 159 | { | 
| 160 |     QFile file; | 
| 161 |     QIODevice *device = &file; | 
| 162 |  | 
| 163 |     QVERIFY(!device->isOpen()); | 
| 164 |  | 
| 165 |     file.setFileName(QFINDTESTDATA("tst_qiodevice.cpp" )); | 
| 166 |     QVERIFY(file.open(QFile::ReadOnly)); | 
| 167 |     QVERIFY(device->isOpen()); | 
| 168 |     QCOMPARE((int) device->openMode(), (int) QFile::ReadOnly); | 
| 169 |     QCOMPARE(device->readChannelCount(), 1); | 
| 170 |     QCOMPARE(device->writeChannelCount(), 0); | 
| 171 |  | 
| 172 |     char buf[1024]; | 
| 173 |     memset(s: buf, c: 0, n: sizeof(buf)); | 
| 174 |     qlonglong lineLength = device->readLine(data: buf, maxlen: sizeof(buf)); | 
| 175 |     QVERIFY(lineLength > 0); | 
| 176 |     QCOMPARE(file.pos(), lineLength); | 
| 177 |  | 
| 178 |     file.seek(offset: 0); | 
| 179 |     char buf2[1024]; | 
| 180 |     memset(s: buf2, c: 0, n: sizeof(buf2)); | 
| 181 |     QCOMPARE(file.readLine(buf2, sizeof(buf2)), lineLength); | 
| 182 |  | 
| 183 |     char *c1 = buf; | 
| 184 |     char *c2 = buf2; | 
| 185 |     while (*c1 && *c2) { | 
| 186 |         QCOMPARE(*c1, *c2); | 
| 187 |         ++c1; | 
| 188 |         ++c2; | 
| 189 |     } | 
| 190 |     QCOMPARE(*c1, *c2); | 
| 191 | } | 
| 192 |  | 
| 193 |  | 
| 194 | void tst_QIODevice::read_QByteArray() | 
| 195 | { | 
| 196 |     QFile f(QFINDTESTDATA("tst_qiodevice.cpp" )); | 
| 197 |     f.open(flags: QIODevice::ReadOnly); | 
| 198 |  | 
| 199 |     QByteArray b = f.read(maxlen: 10); | 
| 200 |     QCOMPARE(b.length(), 10); | 
| 201 |  | 
| 202 |     b = f.read(maxlen: 256); | 
| 203 |     QCOMPARE(b.length(), 256); | 
| 204 |  | 
| 205 |     b = f.read(maxlen: 0); | 
| 206 |     QCOMPARE(b.length(), 0); | 
| 207 | } | 
| 208 |  | 
| 209 | //-------------------------------------------------------------------- | 
| 210 | void tst_QIODevice::unget() | 
| 211 | { | 
| 212 |     QBuffer buffer; | 
| 213 |     buffer.open(openMode: QBuffer::ReadWrite); | 
| 214 |     buffer.write(data: "ZXCV" ); | 
| 215 |     buffer.seek(off: 0); | 
| 216 |     QCOMPARE(buffer.read(4), QByteArray("ZXCV" )); | 
| 217 |     QCOMPARE(buffer.pos(), qint64(4)); | 
| 218 |  | 
| 219 |     buffer.ungetChar(c: 'a'); | 
| 220 |     buffer.ungetChar(c: 'b'); | 
| 221 |     buffer.ungetChar(c: 'c'); | 
| 222 |     buffer.ungetChar(c: 'd'); | 
| 223 |  | 
| 224 |     QCOMPARE(buffer.pos(), qint64(0)); | 
| 225 |  | 
| 226 |     char buf[6]; | 
| 227 |     QCOMPARE(buffer.readLine(buf, 5), qint64(4)); | 
| 228 |     QCOMPARE(buffer.pos(), qint64(4)); | 
| 229 |     QCOMPARE(static_cast<const char*>(buf), "dcba" ); | 
| 230 |  | 
| 231 |     buffer.ungetChar(c: 'a'); | 
| 232 |     buffer.ungetChar(c: 'b'); | 
| 233 |     buffer.ungetChar(c: 'c'); | 
| 234 |     buffer.ungetChar(c: 'd'); | 
| 235 |  | 
| 236 |     QCOMPARE(buffer.pos(), qint64(0)); | 
| 237 |  | 
| 238 |     for (int i = 0; i < 5; ++i) { | 
| 239 |         buf[0] = '@'; | 
| 240 |         buf[1] = '@'; | 
| 241 |         QTest::ignoreMessage(type: QtWarningMsg, | 
| 242 |                               message: "QIODevice::readLine (QBuffer): Called with maxSize < 2" ); | 
| 243 |         QCOMPARE(buffer.readLine(buf, 1), qint64(-1)); | 
| 244 |         QCOMPARE(buffer.readLine(buf, 2), qint64(i < 4 ? 1 : -1)); | 
| 245 |         switch (i) { | 
| 246 |         case 0: QCOMPARE(buf[0], 'd'); break; | 
| 247 |         case 1: QCOMPARE(buf[0], 'c'); break; | 
| 248 |         case 2: QCOMPARE(buf[0], 'b'); break; | 
| 249 |         case 3: QCOMPARE(buf[0], 'a'); break; | 
| 250 |         case 4: QCOMPARE(buf[0], '\0'); break; | 
| 251 |         } | 
| 252 |         QCOMPARE(buf[1], i < 4 ? '\0' : '@'); | 
| 253 |     } | 
| 254 |  | 
| 255 |     buffer.ungetChar(c: '\n'); | 
| 256 |     QCOMPARE(buffer.readLine(), QByteArray("\n" )); | 
| 257 |  | 
| 258 |     buffer.seek(off: 1); | 
| 259 |     buffer.readLine(data: buf, maxlen: 3); | 
| 260 |     QCOMPARE(static_cast<const char*>(buf), "XC" ); | 
| 261 |  | 
| 262 |     buffer.seek(off: 4); | 
| 263 |     buffer.ungetChar(c: 'Q'); | 
| 264 |     QCOMPARE(buffer.readLine(buf, 3), qint64(1)); | 
| 265 |  | 
| 266 | #if defined(Q_OS_WINRT) | 
| 267 |     QSKIP("Synchronous socket calls are broken on winrt. See QTBUG-40922" ); | 
| 268 | #endif | 
| 269 |     for (int i = 0; i < 2; ++i) { | 
| 270 |         QTcpSocket socket; | 
| 271 |         QIODevice *dev; | 
| 272 |         QByteArray result; | 
| 273 |         const char *lineResult; | 
| 274 |         if (i == 0) { | 
| 275 |             dev = &buffer; | 
| 276 |             result = QByteArray("ZXCV" ); | 
| 277 |             lineResult = "ZXCV" ; | 
| 278 |         } else { | 
| 279 |             if (!QtNetworkSettings::verifyTestNetworkSettings()) | 
| 280 |                 QSKIP("No network test server available" ); | 
| 281 |             socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: 80); | 
| 282 |             socket.write(data: "GET / HTTP/1.0\r\n\r\n" ); | 
| 283 |             QVERIFY(socket.waitForReadyRead()); | 
| 284 |             dev = &socket; | 
| 285 |             result = QByteArray("HTTP" ); | 
| 286 |             lineResult = "Date" ; | 
| 287 |         } | 
| 288 |         char ch, ch2; | 
| 289 |         dev->seek(pos: 0); | 
| 290 |         dev->getChar(c: &ch); | 
| 291 |         dev->ungetChar(c: ch); | 
| 292 |         QCOMPARE(dev->peek(4), result); | 
| 293 |         dev->getChar(c: &ch); | 
| 294 |         dev->getChar(c: &ch2); | 
| 295 |         dev->ungetChar(c: ch2); | 
| 296 |         dev->ungetChar(c: ch); | 
| 297 |         QCOMPARE(dev->read(1), result.left(1)); | 
| 298 |         QCOMPARE(dev->read(3), result.right(3)); | 
| 299 |  | 
| 300 |         if (i == 0) | 
| 301 |             dev->seek(pos: 0); | 
| 302 |         else | 
| 303 |             dev->readLine(); | 
| 304 |         dev->getChar(c: &ch); | 
| 305 |         dev->ungetChar(c: ch); | 
| 306 |         dev->readLine(data: buf, maxlen: 5); | 
| 307 |         QCOMPARE(static_cast<const char*>(buf), lineResult); | 
| 308 |  | 
| 309 |         if (i == 1) | 
| 310 |             socket.close(); | 
| 311 |     } | 
| 312 | } | 
| 313 |  | 
| 314 | //-------------------------------------------------------------------- | 
| 315 | void tst_QIODevice::peek() | 
| 316 | { | 
| 317 |     QBuffer buffer; | 
| 318 |     QFile::remove(fileName: "peektestfile" ); | 
| 319 |     QFile file("peektestfile" ); | 
| 320 |  | 
| 321 |     for (int i = 0; i < 2; ++i) { | 
| 322 |         QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; | 
| 323 |  | 
| 324 |         device->open(mode: QBuffer::ReadWrite); | 
| 325 |         device->write(data: "ZXCV" ); | 
| 326 |  | 
| 327 |         device->seek(pos: 0); | 
| 328 |         QCOMPARE(device->peek(4), QByteArray("ZXCV" )); | 
| 329 |         QCOMPARE(device->pos(), qint64(0)); | 
| 330 |         device->write(data: "ABCDE" ); | 
| 331 |         device->seek(pos: 3); | 
| 332 |         QCOMPARE(device->peek(1), QByteArray("D" )); | 
| 333 |         QCOMPARE(device->peek(5), QByteArray("DE" )); | 
| 334 |         device->seek(pos: 0); | 
| 335 |         QCOMPARE(device->read(4), QByteArray("ABCD" )); | 
| 336 |         QCOMPARE(device->pos(), qint64(4)); | 
| 337 |  | 
| 338 |         device->seek(pos: 0); | 
| 339 |         device->write(data: "ZXCV" ); | 
| 340 |         device->seek(pos: 0); | 
| 341 |         char buf[5]; | 
| 342 |         buf[4] = 0; | 
| 343 |         device->peek(data: buf, maxlen: 4); | 
| 344 |         QCOMPARE(static_cast<const char *>(buf), "ZXCV" ); | 
| 345 |         QCOMPARE(device->pos(), qint64(0)); | 
| 346 |         device->read(data: buf, maxlen: 4); | 
| 347 |         QCOMPARE(static_cast<const char *>(buf), "ZXCV" ); | 
| 348 |         QCOMPARE(device->pos(), qint64(4)); | 
| 349 |     } | 
| 350 |     QFile::remove(fileName: "peektestfile" ); | 
| 351 | } | 
| 352 |  | 
| 353 | void tst_QIODevice::peekAndRead() | 
| 354 | { | 
| 355 |     QByteArray originalData; | 
| 356 |     for (int i=0;i<1000;i++) | 
| 357 |         originalData += "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; | 
| 358 |     QBuffer buffer; | 
| 359 |     QFile::remove(fileName: "peektestfile" ); | 
| 360 |     QFile file("peektestfile" ); | 
| 361 |  | 
| 362 |     for (int i = 0; i < 2; ++i) { | 
| 363 |         QByteArray readData; | 
| 364 |         QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; | 
| 365 |         device->open(mode: QBuffer::ReadWrite); | 
| 366 |         device->write(data: originalData); | 
| 367 |         device->seek(pos: 0); | 
| 368 |         while (!device->atEnd()) { | 
| 369 |             char peekIn[26]; | 
| 370 |             device->peek(data: peekIn, maxlen: 26); | 
| 371 |             readData += device->read(maxlen: 26); | 
| 372 |         } | 
| 373 |         QCOMPARE(readData, originalData); | 
| 374 |     } | 
| 375 |     QFile::remove(fileName: "peektestfile" ); | 
| 376 | } | 
| 377 |  | 
| 378 | void tst_QIODevice::readLine_data() | 
| 379 | { | 
| 380 |     QTest::addColumn<QByteArray>(name: "data" ); | 
| 381 |  | 
| 382 |     QTest::newRow(dataTag: "0" ) << QByteArray("\nAA" ); | 
| 383 |     QTest::newRow(dataTag: "1" ) << QByteArray("A\nAA" ); | 
| 384 |  | 
| 385 |     QByteArray data(9000, 'A'); | 
| 386 |     data[8193] = '\n'; | 
| 387 |     QTest::newRow(dataTag: "8194" ) << data; | 
| 388 |     data[8193] = 'A'; | 
| 389 |     data[8192] = '\n'; | 
| 390 |     QTest::newRow(dataTag: "8193" ) << data; | 
| 391 |     data[8192] = 'A'; | 
| 392 |     data[8191] = '\n'; | 
| 393 |     QTest::newRow(dataTag: "8192" ) << data; | 
| 394 |     data[8191] = 'A'; | 
| 395 |     data[8190] = '\n'; | 
| 396 |     QTest::newRow(dataTag: "8191" ) << data; | 
| 397 |  | 
| 398 |     data[5999] = '\n'; | 
| 399 |     QTest::newRow(dataTag: "6000" ) << data; | 
| 400 |  | 
| 401 |     data[4095] = '\n'; | 
| 402 |     QTest::newRow(dataTag: "4096" ) << data; | 
| 403 |  | 
| 404 |     data[4094] = '\n'; | 
| 405 |     data[4095] = 'A'; | 
| 406 |     QTest::newRow(dataTag: "4095" ) << data; | 
| 407 | } | 
| 408 |  | 
| 409 | void tst_QIODevice::readLine() | 
| 410 | { | 
| 411 |     QFETCH(QByteArray, data); | 
| 412 |     QBuffer buffer(&data); | 
| 413 |     QVERIFY(buffer.open(QIODevice::ReadWrite)); | 
| 414 |     QVERIFY(buffer.canReadLine()); | 
| 415 |  | 
| 416 |     int linelen = data.indexOf(c: '\n') + 1; | 
| 417 |     QByteArray line; | 
| 418 |     line.reserve(asize: linelen + 100); | 
| 419 |  | 
| 420 |     int result = buffer.readLine(data: line.data(), maxlen: linelen + 100); | 
| 421 |     QCOMPARE(result, linelen); | 
| 422 |  | 
| 423 |     // try the exact length of the line (plus terminating \0) | 
| 424 |     QVERIFY(buffer.seek(0)); | 
| 425 |     result = buffer.readLine(data: line.data(), maxlen: linelen + 1); | 
| 426 |     QCOMPARE(result, linelen); | 
| 427 |  | 
| 428 |     // try with a line length limit | 
| 429 |     QVERIFY(buffer.seek(0)); | 
| 430 |     line = buffer.readLine(maxlen: linelen + 100); | 
| 431 |     QCOMPARE(line.size(), linelen); | 
| 432 |  | 
| 433 |     // try without a length limit | 
| 434 |     QVERIFY(buffer.seek(0)); | 
| 435 |     line = buffer.readLine(); | 
| 436 |     QCOMPARE(line.size(), linelen); | 
| 437 | } | 
| 438 |  | 
| 439 | void tst_QIODevice::readLine2_data() | 
| 440 | { | 
| 441 |     QTest::addColumn<QByteArray>(name: "line" ); | 
| 442 |  | 
| 443 |     QTest::newRow(dataTag: "1024 - 4" ) << QByteArray(1024 - 4, 'x'); | 
| 444 |     QTest::newRow(dataTag: "1024 - 3" ) << QByteArray(1024 - 3, 'x'); | 
| 445 |     QTest::newRow(dataTag: "1024 - 2" ) << QByteArray(1024 - 2, 'x'); | 
| 446 |     QTest::newRow(dataTag: "1024 - 1" ) << QByteArray(1024 - 1, 'x'); | 
| 447 |     QTest::newRow(dataTag: "1024"     ) << QByteArray(1024    , 'x'); | 
| 448 |     QTest::newRow(dataTag: "1024 + 1" ) << QByteArray(1024 + 1, 'x'); | 
| 449 |     QTest::newRow(dataTag: "1024 + 2" ) << QByteArray(1024 + 2, 'x'); | 
| 450 |  | 
| 451 |     QTest::newRow(dataTag: "4096 - 4" ) << QByteArray(4096 - 4, 'x'); | 
| 452 |     QTest::newRow(dataTag: "4096 - 3" ) << QByteArray(4096 - 3, 'x'); | 
| 453 |     QTest::newRow(dataTag: "4096 - 2" ) << QByteArray(4096 - 2, 'x'); | 
| 454 |     QTest::newRow(dataTag: "4096 - 1" ) << QByteArray(4096 - 1, 'x'); | 
| 455 |     QTest::newRow(dataTag: "4096"     ) << QByteArray(4096    , 'x'); | 
| 456 |     QTest::newRow(dataTag: "4096 + 1" ) << QByteArray(4096 + 1, 'x'); | 
| 457 |     QTest::newRow(dataTag: "4096 + 2" ) << QByteArray(4096 + 2, 'x'); | 
| 458 |  | 
| 459 |     QTest::newRow(dataTag: "8192 - 4" ) << QByteArray(8192 - 4, 'x'); | 
| 460 |     QTest::newRow(dataTag: "8192 - 3" ) << QByteArray(8192 - 3, 'x'); | 
| 461 |     QTest::newRow(dataTag: "8192 - 2" ) << QByteArray(8192 - 2, 'x'); | 
| 462 |     QTest::newRow(dataTag: "8192 - 1" ) << QByteArray(8192 - 1, 'x'); | 
| 463 |     QTest::newRow(dataTag: "8192"     ) << QByteArray(8192    , 'x'); | 
| 464 |     QTest::newRow(dataTag: "8192 + 1" ) << QByteArray(8192 + 1, 'x'); | 
| 465 |     QTest::newRow(dataTag: "8192 + 2" ) << QByteArray(8192 + 2, 'x'); | 
| 466 |  | 
| 467 |     QTest::newRow(dataTag: "16384 - 4" ) << QByteArray(16384 - 4, 'x'); | 
| 468 |     QTest::newRow(dataTag: "16384 - 3" ) << QByteArray(16384 - 3, 'x'); | 
| 469 |     QTest::newRow(dataTag: "16384 - 2" ) << QByteArray(16384 - 2, 'x'); | 
| 470 |     QTest::newRow(dataTag: "16384 - 1" ) << QByteArray(16384 - 1, 'x'); | 
| 471 |     QTest::newRow(dataTag: "16384"     ) << QByteArray(16384    , 'x'); | 
| 472 |     QTest::newRow(dataTag: "16384 + 1" ) << QByteArray(16384 + 1, 'x'); | 
| 473 |     QTest::newRow(dataTag: "16384 + 2" ) << QByteArray(16384 + 2, 'x'); | 
| 474 |  | 
| 475 |     QTest::newRow(dataTag: "20000" ) << QByteArray(20000, 'x'); | 
| 476 |  | 
| 477 |     QTest::newRow(dataTag: "32768 - 4" ) << QByteArray(32768 - 4, 'x'); | 
| 478 |     QTest::newRow(dataTag: "32768 - 3" ) << QByteArray(32768 - 3, 'x'); | 
| 479 |     QTest::newRow(dataTag: "32768 - 2" ) << QByteArray(32768 - 2, 'x'); | 
| 480 |     QTest::newRow(dataTag: "32768 - 1" ) << QByteArray(32768 - 1, 'x'); | 
| 481 |     QTest::newRow(dataTag: "32768"     ) << QByteArray(32768    , 'x'); | 
| 482 |     QTest::newRow(dataTag: "32768 + 1" ) << QByteArray(32768 + 1, 'x'); | 
| 483 |     QTest::newRow(dataTag: "32768 + 2" ) << QByteArray(32768 + 2, 'x'); | 
| 484 |  | 
| 485 |     QTest::newRow(dataTag: "40000" ) << QByteArray(40000, 'x'); | 
| 486 | } | 
| 487 |  | 
| 488 | void tst_QIODevice::readLine2() | 
| 489 | { | 
| 490 |     QFETCH(QByteArray, line); | 
| 491 |  | 
| 492 |     int length = line.size(); | 
| 493 |  | 
| 494 |     QByteArray data("First line.\r\n" ); | 
| 495 |     data.append(a: line); | 
| 496 |     data.append(s: "\r\n" ); | 
| 497 |     data.append(a: line); | 
| 498 |     data.append(s: "\r\n" ); | 
| 499 |     data.append(s: "\r\n0123456789" ); | 
| 500 |  | 
| 501 |     { | 
| 502 |         QBuffer buffer(&data); | 
| 503 |         buffer.open(openMode: QIODevice::ReadOnly); | 
| 504 |  | 
| 505 |         buffer.seek(off: 0); | 
| 506 |         QByteArray temp; | 
| 507 |         temp.resize(size: 64536); | 
| 508 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(13)); | 
| 509 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); | 
| 510 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); | 
| 511 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(2)); | 
| 512 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); | 
| 513 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); | 
| 514 |  | 
| 515 |         buffer.seek(off: 0); | 
| 516 |         QCOMPARE(buffer.readLine().size(), 13); | 
| 517 |         QCOMPARE(buffer.readLine().size(), length + 2); | 
| 518 |         QCOMPARE(buffer.readLine().size(), length + 2); | 
| 519 |         QCOMPARE(buffer.readLine().size(), 2); | 
| 520 |         QCOMPARE(buffer.readLine().size(), 10); | 
| 521 |         QVERIFY(buffer.readLine().isNull()); | 
| 522 |     } | 
| 523 |  | 
| 524 |     { | 
| 525 |         QBuffer buffer(&data); | 
| 526 |         buffer.open(openMode: QIODevice::ReadOnly | QIODevice::Text); | 
| 527 |  | 
| 528 |         buffer.seek(off: 0); | 
| 529 |         QByteArray temp; | 
| 530 |         temp.resize(size: 64536); | 
| 531 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(12)); | 
| 532 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); | 
| 533 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); | 
| 534 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(1)); | 
| 535 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); | 
| 536 |         QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); | 
| 537 |  | 
| 538 |         buffer.seek(off: 0); | 
| 539 |         QCOMPARE(buffer.readLine().size(), 12); | 
| 540 |         QCOMPARE(buffer.readLine().size(), length + 1); | 
| 541 |         QCOMPARE(buffer.readLine().size(), length + 1); | 
| 542 |         QCOMPARE(buffer.readLine().size(), 1); | 
| 543 |         QCOMPARE(buffer.readLine().size(), 10); | 
| 544 |         QVERIFY(buffer.readLine().isNull()); | 
| 545 |     } | 
| 546 | } | 
| 547 |  | 
| 548 | class SequentialReadBuffer : public QIODevice | 
| 549 | { | 
| 550 | public: | 
| 551 |     SequentialReadBuffer(const char *data) | 
| 552 |         : QIODevice(), buf(new QByteArray(data)), offset(0), ownbuf(true) { } | 
| 553 |     SequentialReadBuffer(QByteArray *byteArray) | 
| 554 |         : QIODevice(), buf(byteArray), offset(0), ownbuf(false) { } | 
| 555 |     virtual ~SequentialReadBuffer() { if (ownbuf) delete buf; } | 
| 556 |  | 
| 557 |     bool isSequential() const override { return true; } | 
| 558 |     const QByteArray &buffer() const { return *buf; } | 
| 559 |  | 
| 560 | protected: | 
| 561 |     qint64 readData(char *data, qint64 maxSize) override | 
| 562 |     { | 
| 563 |         maxSize = qMin(a: maxSize, b: qint64(buf->size() - offset)); | 
| 564 |         if (maxSize > 0) | 
| 565 |             memcpy(dest: data, src: buf->constData() + offset, n: maxSize); | 
| 566 |         offset += maxSize; | 
| 567 |         return maxSize; | 
| 568 |     } | 
| 569 |     qint64 writeData(const char * /* data */, qint64 /* maxSize */) override | 
| 570 |     { | 
| 571 |         return -1; | 
| 572 |     } | 
| 573 |  | 
| 574 | private: | 
| 575 |     QByteArray *buf; | 
| 576 |     int offset; | 
| 577 |     bool ownbuf; | 
| 578 | }; | 
| 579 |  | 
| 580 | // Test readAll() on position change for sequential device | 
| 581 | void tst_QIODevice::readAllKeepPosition() | 
| 582 | { | 
| 583 |     SequentialReadBuffer buffer("Hello world!" ); | 
| 584 |     buffer.open(mode: QIODevice::ReadOnly); | 
| 585 |     char c; | 
| 586 |  | 
| 587 |     QCOMPARE(buffer.readChannelCount(), 1); | 
| 588 |     QCOMPARE(buffer.writeChannelCount(), 0); | 
| 589 |     QVERIFY(buffer.getChar(&c)); | 
| 590 |     QCOMPARE(buffer.pos(), qint64(0)); | 
| 591 |     buffer.ungetChar(c); | 
| 592 |     QCOMPARE(buffer.pos(), qint64(0)); | 
| 593 |  | 
| 594 |     QByteArray resultArray = buffer.readAll(); | 
| 595 |     QCOMPARE(buffer.pos(), qint64(0)); | 
| 596 |     QCOMPARE(resultArray, buffer.buffer()); | 
| 597 | } | 
| 598 |  | 
| 599 | class RandomAccessBuffer : public QIODevice | 
| 600 | { | 
| 601 | public: | 
| 602 |     RandomAccessBuffer(const char *data) : QIODevice(), buf(data) { } | 
| 603 |  | 
| 604 | protected: | 
| 605 |     qint64 readData(char *data, qint64 maxSize) override | 
| 606 |     { | 
| 607 |         maxSize = qMin(a: maxSize, b: qint64(buf.size() - pos())); | 
| 608 |         if (maxSize > 0) | 
| 609 |             memcpy(dest: data, src: buf.constData() + pos(), n: maxSize); | 
| 610 |         return maxSize; | 
| 611 |     } | 
| 612 |     qint64 writeData(const char *data, qint64 maxSize) override | 
| 613 |     { | 
| 614 |         maxSize = qMin(a: maxSize, b: qint64(buf.size() - pos())); | 
| 615 |         if (maxSize > 0) | 
| 616 |             memcpy(dest: buf.data() + pos(), src: data, n: maxSize); | 
| 617 |         return maxSize; | 
| 618 |     } | 
| 619 |  | 
| 620 | private: | 
| 621 |     QByteArray buf; | 
| 622 | }; | 
| 623 |  | 
| 624 | // Test write() on skipping correct number of bytes in read buffer | 
| 625 | void tst_QIODevice::writeInTextMode() | 
| 626 | { | 
| 627 |     // Unlike other platforms, Windows implementation expands '\n' into | 
| 628 |     // "\r\n" sequence in write(). Ensure that write() properly works with | 
| 629 |     // a read buffer on random-access devices. | 
| 630 | #ifndef Q_OS_WIN | 
| 631 |     QSKIP("This is a Windows-only test" ); | 
| 632 | #else | 
| 633 |     RandomAccessBuffer buffer("one\r\ntwo\r\nthree\r\n" ); | 
| 634 |     buffer.open(QBuffer::ReadWrite | QBuffer::Text); | 
| 635 |     QCOMPARE(buffer.readLine(), QByteArray("one\n" )); | 
| 636 |     QCOMPARE(buffer.write("two\n" ), 4); | 
| 637 |     QCOMPARE(buffer.readLine(), QByteArray("three\n" )); | 
| 638 | #endif | 
| 639 | } | 
| 640 |  | 
| 641 | void tst_QIODevice::skip_data() | 
| 642 | { | 
| 643 |     QTest::addColumn<bool>(name: "sequential" ); | 
| 644 |     QTest::addColumn<QByteArray>(name: "data" ); | 
| 645 |     QTest::addColumn<int>(name: "read" ); | 
| 646 |     QTest::addColumn<int>(name: "skip" ); | 
| 647 |     QTest::addColumn<int>(name: "skipped" ); | 
| 648 |     QTest::addColumn<char>(name: "expect" ); | 
| 649 |  | 
| 650 |     QByteArray bigData; | 
| 651 |     bigData.fill(c: 'a', size: 20000); | 
| 652 |     bigData[10001] = 'x'; | 
| 653 |  | 
| 654 |     bool sequential = true; | 
| 655 |     do { | 
| 656 |         QByteArray devName(sequential ? "sequential"  : "random-access" ); | 
| 657 |  | 
| 658 |         QTest::newRow(qPrintable(devName + "-small_data" )) << true  << QByteArray("abcdefghij" ) | 
| 659 |                                                            << 3 << 6 << 6 << 'j'; | 
| 660 |         QTest::newRow(qPrintable(devName + "-big_data" )) << true  << bigData | 
| 661 |                                                          << 1 << 10000 << 10000 << 'x'; | 
| 662 |         QTest::newRow(qPrintable(devName + "-beyond_the_end" )) << true  << bigData | 
| 663 |                                                                << 1 << 20000 << 19999 << '\0'; | 
| 664 |  | 
| 665 |         sequential = !sequential; | 
| 666 |     } while (!sequential); | 
| 667 | } | 
| 668 |  | 
| 669 | void tst_QIODevice::skip() | 
| 670 | { | 
| 671 |     QFETCH(bool, sequential); | 
| 672 |     QFETCH(QByteArray, data); | 
| 673 |     QFETCH(int, read); | 
| 674 |     QFETCH(int, skip); | 
| 675 |     QFETCH(int, skipped); | 
| 676 |     QFETCH(char, expect); | 
| 677 |     char lastChar = 0; | 
| 678 |  | 
| 679 |     QScopedPointer<QIODevice> dev(sequential ? (QIODevice *) new SequentialReadBuffer(&data) | 
| 680 |                                              : (QIODevice *) new QBuffer(&data)); | 
| 681 |     dev->open(mode: QIODevice::ReadOnly); | 
| 682 |  | 
| 683 |     for (int i = 0; i < read; ++i) | 
| 684 |         dev->getChar(c: nullptr); | 
| 685 |  | 
| 686 |     QCOMPARE(dev->skip(skip), skipped); | 
| 687 |     dev->getChar(c: &lastChar); | 
| 688 |     QCOMPARE(lastChar, expect); | 
| 689 | } | 
| 690 |  | 
| 691 | void tst_QIODevice::skipAfterPeek_data() | 
| 692 | { | 
| 693 |     QTest::addColumn<bool>(name: "sequential" ); | 
| 694 |     QTest::addColumn<QByteArray>(name: "data" ); | 
| 695 |  | 
| 696 |     QByteArray bigData; | 
| 697 |     for (int i = 0; i < 1000; ++i) | 
| 698 |         bigData += "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; | 
| 699 |  | 
| 700 |     QTest::newRow(dataTag: "sequential" ) << true  << bigData; | 
| 701 |     QTest::newRow(dataTag: "random-access" ) << false << bigData; | 
| 702 | } | 
| 703 |  | 
| 704 | void tst_QIODevice::skipAfterPeek() | 
| 705 | { | 
| 706 |     QFETCH(bool, sequential); | 
| 707 |     QFETCH(QByteArray, data); | 
| 708 |  | 
| 709 |     QScopedPointer<QIODevice> dev(sequential ? (QIODevice *) new SequentialReadBuffer(&data) | 
| 710 |                                              : (QIODevice *) new QBuffer(&data)); | 
| 711 |     int readSoFar = 0; | 
| 712 |     qint64 bytesToSkip = 1; | 
| 713 |  | 
| 714 |     dev->open(mode: QIODevice::ReadOnly); | 
| 715 |     forever { | 
| 716 |         QByteArray chunk = dev->peek(maxlen: bytesToSkip); | 
| 717 |         if (chunk.isEmpty()) | 
| 718 |             break; | 
| 719 |  | 
| 720 |         QCOMPARE(dev->skip(bytesToSkip), qint64(chunk.size())); | 
| 721 |         QCOMPARE(chunk, data.mid(readSoFar, chunk.size())); | 
| 722 |         readSoFar += chunk.size(); | 
| 723 |         bytesToSkip <<= 1; | 
| 724 |     } | 
| 725 |     QCOMPARE(readSoFar, data.size()); | 
| 726 | } | 
| 727 |  | 
| 728 | void tst_QIODevice::transaction_data() | 
| 729 | { | 
| 730 |     QTest::addColumn<bool>(name: "sequential" ); | 
| 731 |     QTest::addColumn<qint8>(name: "i8Data" ); | 
| 732 |     QTest::addColumn<qint16>(name: "i16Data" ); | 
| 733 |     QTest::addColumn<qint32>(name: "i32Data" ); | 
| 734 |     QTest::addColumn<qint64>(name: "i64Data" ); | 
| 735 |     QTest::addColumn<bool>(name: "bData" ); | 
| 736 |     QTest::addColumn<float>(name: "fData" ); | 
| 737 |     QTest::addColumn<double>(name: "dData" ); | 
| 738 |     QTest::addColumn<QByteArray>(name: "strData" ); | 
| 739 |  | 
| 740 |     bool sequential = true; | 
| 741 |     do { | 
| 742 |         QByteArray devName(sequential ? "sequential"  : "random-access" ); | 
| 743 |  | 
| 744 |         QTest::newRow(qPrintable(devName + '1')) << sequential << qint8(1) << qint16(2) | 
| 745 |                                                  << qint32(3) << qint64(4) << true | 
| 746 |                                                  << 5.0f << double(6.0) | 
| 747 |                                                  << QByteArray("Hello world!" ); | 
| 748 |         QTest::newRow(qPrintable(devName + '2')) << sequential << qint8(1 << 6) << qint16(1 << 14) | 
| 749 |                                                  << qint32(1 << 30) << (qint64(1) << 62) << false | 
| 750 |                                                  << 123.0f << double(234.0) | 
| 751 |                                                  << QByteArray("abcdefghijklmnopqrstuvwxyz" ); | 
| 752 |         QTest::newRow(qPrintable(devName + '3')) << sequential << qint8(-1) << qint16(-2) | 
| 753 |                                                  << qint32(-3) << qint64(-4) << true | 
| 754 |                                                  << -123.0f << double(-234.0) | 
| 755 |                                                  << QByteArray("Qt rocks!" ); | 
| 756 |         sequential = !sequential; | 
| 757 |     } while (!sequential); | 
| 758 | } | 
| 759 |  | 
| 760 | // Test transaction integrity | 
| 761 | void tst_QIODevice::transaction() | 
| 762 | { | 
| 763 |     QByteArray testBuffer; | 
| 764 |  | 
| 765 |     QFETCH(bool, sequential); | 
| 766 |     QFETCH(qint8, i8Data); | 
| 767 |     QFETCH(qint16, i16Data); | 
| 768 |     QFETCH(qint32, i32Data); | 
| 769 |     QFETCH(qint64, i64Data); | 
| 770 |     QFETCH(bool, bData); | 
| 771 |     QFETCH(float, fData); | 
| 772 |     QFETCH(double, dData); | 
| 773 |     QFETCH(QByteArray, strData); | 
| 774 |  | 
| 775 |     { | 
| 776 |         QDataStream stream(&testBuffer, QIODevice::WriteOnly); | 
| 777 |  | 
| 778 |         stream << i8Data << i16Data << i32Data << i64Data | 
| 779 |                << bData << fData << dData << strData.constData(); | 
| 780 |     } | 
| 781 |  | 
| 782 |     for (int splitPos = 0; splitPos <= testBuffer.size(); ++splitPos) { | 
| 783 |         QByteArray readBuffer(testBuffer.left(len: splitPos)); | 
| 784 |         QIODevice *dev = sequential ? (QIODevice *) new SequentialReadBuffer(&readBuffer) | 
| 785 |                                     : (QIODevice *) new QBuffer(&readBuffer); | 
| 786 |         dev->open(mode: QIODevice::ReadOnly); | 
| 787 |         QDataStream stream(dev); | 
| 788 |  | 
| 789 |         qint8 i8; | 
| 790 |         qint16 i16; | 
| 791 |         qint32 i32; | 
| 792 |         qint64 i64; | 
| 793 |         bool b; | 
| 794 |         float f; | 
| 795 |         double d; | 
| 796 |         char *str; | 
| 797 |  | 
| 798 |         forever { | 
| 799 |             QVERIFY(!dev->isTransactionStarted()); | 
| 800 |             dev->startTransaction(); | 
| 801 |             QVERIFY(dev->isTransactionStarted()); | 
| 802 |  | 
| 803 |             // Try to read all data in one go. If the status of the data stream | 
| 804 |             // indicates an unsuccessful operation, restart a read transaction | 
| 805 |             // on the completed buffer. | 
| 806 |             stream >> i8 >> i16 >> i32 >> i64 >> b >> f >> d >> str; | 
| 807 |  | 
| 808 |             QVERIFY(stream.atEnd()); | 
| 809 |             if (stream.status() == QDataStream::Ok) { | 
| 810 |                 dev->commitTransaction(); | 
| 811 |                 break; | 
| 812 |             } | 
| 813 |  | 
| 814 |             dev->rollbackTransaction(); | 
| 815 |             QVERIFY(splitPos == 0 || !stream.atEnd()); | 
| 816 |             QCOMPARE(dev->pos(), Q_INT64_C(0)); | 
| 817 |             QCOMPARE(dev->bytesAvailable(), qint64(readBuffer.size())); | 
| 818 |             QVERIFY(readBuffer.size() < testBuffer.size()); | 
| 819 |             delete [] str; | 
| 820 |             readBuffer.append(a: testBuffer.right(len: testBuffer.size() - splitPos)); | 
| 821 |             stream.resetStatus(); | 
| 822 |         } | 
| 823 |  | 
| 824 |         QVERIFY(!dev->isTransactionStarted()); | 
| 825 |         QVERIFY(stream.atEnd()); | 
| 826 |         QCOMPARE(i8, i8Data); | 
| 827 |         QCOMPARE(i16, i16Data); | 
| 828 |         QCOMPARE(i32, i32Data); | 
| 829 |         QCOMPARE(i64, i64Data); | 
| 830 |         QCOMPARE(b, bData); | 
| 831 |         QCOMPARE(f, fData); | 
| 832 |         QCOMPARE(d, dData); | 
| 833 |         QVERIFY(strData == str); | 
| 834 |         delete [] str; | 
| 835 |         stream.setDevice(0); | 
| 836 |         delete dev; | 
| 837 |     } | 
| 838 | } | 
| 839 |  | 
| 840 | QTEST_MAIN(tst_QIODevice) | 
| 841 | #include "tst_qiodevice.moc" | 
| 842 |  |