/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include "../../../network-settings.h" class tst_QIODevice : public QObject { Q_OBJECT private slots: void initTestCase(); void cleanupTestCase(); void getSetCheck(); void constructing_QTcpSocket(); void constructing_QFile(); void read_QByteArray(); void unget(); void peek(); void peekAndRead(); void readLine_data(); void readLine(); void readLine2_data(); void readLine2(); void readAllKeepPosition(); void writeInTextMode(); void skip_data(); void skip(); void skipAfterPeek_data(); void skipAfterPeek(); void transaction_data(); void transaction(); private: QSharedPointer m_tempDir; QString m_previousCurrent; }; void tst_QIODevice::initTestCase() { #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QVERIFY(QFileInfo(QStringLiteral("./tst_qiodevice.cpp")).exists() || QFile::copy(QStringLiteral(":/tst_qiodevice.cpp"), QStringLiteral("./tst_qiodevice.cpp"))); #endif m_previousCurrent = QDir::currentPath(); m_tempDir = QSharedPointer::create(); QVERIFY2(!m_tempDir.isNull(), qPrintable("Could not create temporary directory.")); QVERIFY2(QDir::setCurrent(m_tempDir->path()), qPrintable("Could not switch current directory")); } void tst_QIODevice::cleanupTestCase() { QDir::setCurrent(m_previousCurrent); } // Testing get/set functions void tst_QIODevice::getSetCheck() { // OpenMode QIODevice::openMode() // void QIODevice::setOpenMode(OpenMode) class MyIODevice : public QTcpSocket { public: using QTcpSocket::setOpenMode; }; MyIODevice var1; var1.setOpenMode(QIODevice::OpenMode(QIODevice::NotOpen)); QCOMPARE(QIODevice::OpenMode(QIODevice::NotOpen), var1.openMode()); var1.setOpenMode(QIODevice::OpenMode(QIODevice::ReadWrite)); QCOMPARE(QIODevice::OpenMode(QIODevice::ReadWrite), var1.openMode()); } //---------------------------------------------------------------------------------- void tst_QIODevice::constructing_QTcpSocket() { #if defined(Q_OS_WINRT) QSKIP("Synchronous socket calls are broken on winrt. See QTBUG-40922"); #endif if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); QTcpSocket socket; QIODevice *device = &socket; QVERIFY(!device->isOpen()); socket.connectToHost(QtNetworkSettings::serverName(), 143); QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); QCOMPARE(device->readChannelCount(), 1); QCOMPARE(device->writeChannelCount(), 1); while (!device->canReadLine()) QVERIFY(device->waitForReadyRead(30000)); char buf[1024]; memset(buf, 0, sizeof(buf)); qlonglong lineLength = device->readLine(buf, sizeof(buf)); QVERIFY(lineLength > 0); QCOMPARE(socket.pos(), qlonglong(0)); socket.close(); QCOMPARE(socket.readChannelCount(), 0); QCOMPARE(socket.writeChannelCount(), 0); socket.connectToHost(QtNetworkSettings::serverName(), 143); QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); while (!device->canReadLine()) QVERIFY(device->waitForReadyRead(30000)); char buf2[1024]; memset(buf2, 0, sizeof(buf2)); QCOMPARE(socket.readLine(buf2, sizeof(buf2)), lineLength); char *c1 = buf; char *c2 = buf2; while (*c1 && *c2) { QCOMPARE(*c1, *c2); ++c1; ++c2; } QCOMPARE(*c1, *c2); } //---------------------------------------------------------------------------------- void tst_QIODevice::constructing_QFile() { QFile file; QIODevice *device = &file; QVERIFY(!device->isOpen()); file.setFileName(QFINDTESTDATA("tst_qiodevice.cpp")); QVERIFY(file.open(QFile::ReadOnly)); QVERIFY(device->isOpen()); QCOMPARE((int) device->openMode(), (int) QFile::ReadOnly); QCOMPARE(device->readChannelCount(), 1); QCOMPARE(device->writeChannelCount(), 0); char buf[1024]; memset(buf, 0, sizeof(buf)); qlonglong lineLength = device->readLine(buf, sizeof(buf)); QVERIFY(lineLength > 0); QCOMPARE(file.pos(), lineLength); file.seek(0); char buf2[1024]; memset(buf2, 0, sizeof(buf2)); QCOMPARE(file.readLine(buf2, sizeof(buf2)), lineLength); char *c1 = buf; char *c2 = buf2; while (*c1 && *c2) { QCOMPARE(*c1, *c2); ++c1; ++c2; } QCOMPARE(*c1, *c2); } void tst_QIODevice::read_QByteArray() { QFile f(QFINDTESTDATA("tst_qiodevice.cpp")); f.open(QIODevice::ReadOnly); QByteArray b = f.read(10); QCOMPARE(b.length(), 10); b = f.read(256); QCOMPARE(b.length(), 256); b = f.read(0); QCOMPARE(b.length(), 0); } //-------------------------------------------------------------------- void tst_QIODevice::unget() { QBuffer buffer; buffer.open(QBuffer::ReadWrite); buffer.write("ZXCV"); buffer.seek(0); QCOMPARE(buffer.read(4), QByteArray("ZXCV")); QCOMPARE(buffer.pos(), qint64(4)); buffer.ungetChar('a'); buffer.ungetChar('b'); buffer.ungetChar('c'); buffer.ungetChar('d'); QCOMPARE(buffer.pos(), qint64(0)); char buf[6]; QCOMPARE(buffer.readLine(buf, 5), qint64(4)); QCOMPARE(buffer.pos(), qint64(4)); QCOMPARE(static_cast(buf), "dcba"); buffer.ungetChar('a'); buffer.ungetChar('b'); buffer.ungetChar('c'); buffer.ungetChar('d'); QCOMPARE(buffer.pos(), qint64(0)); for (int i = 0; i < 5; ++i) { buf[0] = '@'; buf[1] = '@'; QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QBuffer): Called with maxSize < 2"); QCOMPARE(buffer.readLine(buf, 1), qint64(-1)); QCOMPARE(buffer.readLine(buf, 2), qint64(i < 4 ? 1 : -1)); switch (i) { case 0: QCOMPARE(buf[0], 'd'); break; case 1: QCOMPARE(buf[0], 'c'); break; case 2: QCOMPARE(buf[0], 'b'); break; case 3: QCOMPARE(buf[0], 'a'); break; case 4: QCOMPARE(buf[0], '\0'); break; } QCOMPARE(buf[1], i < 4 ? '\0' : '@'); } buffer.ungetChar('\n'); QCOMPARE(buffer.readLine(), QByteArray("\n")); buffer.seek(1); buffer.readLine(buf, 3); QCOMPARE(static_cast(buf), "XC"); buffer.seek(4); buffer.ungetChar('Q'); QCOMPARE(buffer.readLine(buf, 3), qint64(1)); #if defined(Q_OS_WINRT) QSKIP("Synchronous socket calls are broken on winrt. See QTBUG-40922"); #endif for (int i = 0; i < 2; ++i) { QTcpSocket socket; QIODevice *dev; QByteArray result; const char *lineResult; if (i == 0) { dev = &buffer; result = QByteArray("ZXCV"); lineResult = "ZXCV"; } else { if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); socket.connectToHost(QtNetworkSettings::serverName(), 80); socket.write("GET / HTTP/1.0\r\n\r\n"); QVERIFY(socket.waitForReadyRead()); dev = &socket; result = QByteArray("HTTP"); lineResult = "Date"; } char ch, ch2; dev->seek(0); dev->getChar(&ch); dev->ungetChar(ch); QCOMPARE(dev->peek(4), result); dev->getChar(&ch); dev->getChar(&ch2); dev->ungetChar(ch2); dev->ungetChar(ch); QCOMPARE(dev->read(1), result.left(1)); QCOMPARE(dev->read(3), result.right(3)); if (i == 0) dev->seek(0); else dev->readLine(); dev->getChar(&ch); dev->ungetChar(ch); dev->readLine(buf, 5); QCOMPARE(static_cast(buf), lineResult); if (i == 1) socket.close(); } } //-------------------------------------------------------------------- void tst_QIODevice::peek() { QBuffer buffer; QFile::remove("peektestfile"); QFile file("peektestfile"); for (int i = 0; i < 2; ++i) { QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; device->open(QBuffer::ReadWrite); device->write("ZXCV"); device->seek(0); QCOMPARE(device->peek(4), QByteArray("ZXCV")); QCOMPARE(device->pos(), qint64(0)); device->write("ABCDE"); device->seek(3); QCOMPARE(device->peek(1), QByteArray("D")); QCOMPARE(device->peek(5), QByteArray("DE")); device->seek(0); QCOMPARE(device->read(4), QByteArray("ABCD")); QCOMPARE(device->pos(), qint64(4)); device->seek(0); device->write("ZXCV"); device->seek(0); char buf[5]; buf[4] = 0; device->peek(buf, 4); QCOMPARE(static_cast(buf), "ZXCV"); QCOMPARE(device->pos(), qint64(0)); device->read(buf, 4); QCOMPARE(static_cast(buf), "ZXCV"); QCOMPARE(device->pos(), qint64(4)); } QFile::remove("peektestfile"); } void tst_QIODevice::peekAndRead() { QByteArray originalData; for (int i=0;i<1000;i++) originalData += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; QBuffer buffer; QFile::remove("peektestfile"); QFile file("peektestfile"); for (int i = 0; i < 2; ++i) { QByteArray readData; QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; device->open(QBuffer::ReadWrite); device->write(originalData); device->seek(0); while (!device->atEnd()) { char peekIn[26]; device->peek(peekIn, 26); readData += device->read(26); } QCOMPARE(readData, originalData); } QFile::remove("peektestfile"); } void tst_QIODevice::readLine_data() { QTest::addColumn("data"); QTest::newRow("0") << QByteArray("\nAA"); QTest::newRow("1") << QByteArray("A\nAA"); QByteArray data(9000, 'A'); data[8193] = '\n'; QTest::newRow("8194") << data; data[8193] = 'A'; data[8192] = '\n'; QTest::newRow("8193") << data; data[8192] = 'A'; data[8191] = '\n'; QTest::newRow("8192") << data; data[8191] = 'A'; data[8190] = '\n'; QTest::newRow("8191") << data; data[5999] = '\n'; QTest::newRow("6000") << data; data[4095] = '\n'; QTest::newRow("4096") << data; data[4094] = '\n'; data[4095] = 'A'; QTest::newRow("4095") << data; } void tst_QIODevice::readLine() { QFETCH(QByteArray, data); QBuffer buffer(&data); QVERIFY(buffer.open(QIODevice::ReadWrite)); QVERIFY(buffer.canReadLine()); int linelen = data.indexOf('\n') + 1; QByteArray line; line.reserve(linelen + 100); int result = buffer.readLine(line.data(), linelen + 100); QCOMPARE(result, linelen); // try the exact length of the line (plus terminating \0) QVERIFY(buffer.seek(0)); result = buffer.readLine(line.data(), linelen + 1); QCOMPARE(result, linelen); // try with a line length limit QVERIFY(buffer.seek(0)); line = buffer.readLine(linelen + 100); QCOMPARE(line.size(), linelen); // try without a length limit QVERIFY(buffer.seek(0)); line = buffer.readLine(); QCOMPARE(line.size(), linelen); } void tst_QIODevice::readLine2_data() { QTest::addColumn("line"); QTest::newRow("1024 - 4") << QByteArray(1024 - 4, 'x'); QTest::newRow("1024 - 3") << QByteArray(1024 - 3, 'x'); QTest::newRow("1024 - 2") << QByteArray(1024 - 2, 'x'); QTest::newRow("1024 - 1") << QByteArray(1024 - 1, 'x'); QTest::newRow("1024" ) << QByteArray(1024 , 'x'); QTest::newRow("1024 + 1") << QByteArray(1024 + 1, 'x'); QTest::newRow("1024 + 2") << QByteArray(1024 + 2, 'x'); QTest::newRow("4096 - 4") << QByteArray(4096 - 4, 'x'); QTest::newRow("4096 - 3") << QByteArray(4096 - 3, 'x'); QTest::newRow("4096 - 2") << QByteArray(4096 - 2, 'x'); QTest::newRow("4096 - 1") << QByteArray(4096 - 1, 'x'); QTest::newRow("4096" ) << QByteArray(4096 , 'x'); QTest::newRow("4096 + 1") << QByteArray(4096 + 1, 'x'); QTest::newRow("4096 + 2") << QByteArray(4096 + 2, 'x'); QTest::newRow("8192 - 4") << QByteArray(8192 - 4, 'x'); QTest::newRow("8192 - 3") << QByteArray(8192 - 3, 'x'); QTest::newRow("8192 - 2") << QByteArray(8192 - 2, 'x'); QTest::newRow("8192 - 1") << QByteArray(8192 - 1, 'x'); QTest::newRow("8192" ) << QByteArray(8192 , 'x'); QTest::newRow("8192 + 1") << QByteArray(8192 + 1, 'x'); QTest::newRow("8192 + 2") << QByteArray(8192 + 2, 'x'); QTest::newRow("16384 - 4") << QByteArray(16384 - 4, 'x'); QTest::newRow("16384 - 3") << QByteArray(16384 - 3, 'x'); QTest::newRow("16384 - 2") << QByteArray(16384 - 2, 'x'); QTest::newRow("16384 - 1") << QByteArray(16384 - 1, 'x'); QTest::newRow("16384" ) << QByteArray(16384 , 'x'); QTest::newRow("16384 + 1") << QByteArray(16384 + 1, 'x'); QTest::newRow("16384 + 2") << QByteArray(16384 + 2, 'x'); QTest::newRow("20000") << QByteArray(20000, 'x'); QTest::newRow("32768 - 4") << QByteArray(32768 - 4, 'x'); QTest::newRow("32768 - 3") << QByteArray(32768 - 3, 'x'); QTest::newRow("32768 - 2") << QByteArray(32768 - 2, 'x'); QTest::newRow("32768 - 1") << QByteArray(32768 - 1, 'x'); QTest::newRow("32768" ) << QByteArray(32768 , 'x'); QTest::newRow("32768 + 1") << QByteArray(32768 + 1, 'x'); QTest::newRow("32768 + 2") << QByteArray(32768 + 2, 'x'); QTest::newRow("40000") << QByteArray(40000, 'x'); } void tst_QIODevice::readLine2() { QFETCH(QByteArray, line); int length = line.size(); QByteArray data("First line.\r\n"); data.append(line); data.append("\r\n"); data.append(line); data.append("\r\n"); data.append("\r\n0123456789"); { QBuffer buffer(&data); buffer.open(QIODevice::ReadOnly); buffer.seek(0); QByteArray temp; temp.resize(64536); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(13)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(2)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); buffer.seek(0); QCOMPARE(buffer.readLine().size(), 13); QCOMPARE(buffer.readLine().size(), length + 2); QCOMPARE(buffer.readLine().size(), length + 2); QCOMPARE(buffer.readLine().size(), 2); QCOMPARE(buffer.readLine().size(), 10); QVERIFY(buffer.readLine().isNull()); } { QBuffer buffer(&data); buffer.open(QIODevice::ReadOnly | QIODevice::Text); buffer.seek(0); QByteArray temp; temp.resize(64536); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(12)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(1)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); buffer.seek(0); QCOMPARE(buffer.readLine().size(), 12); QCOMPARE(buffer.readLine().size(), length + 1); QCOMPARE(buffer.readLine().size(), length + 1); QCOMPARE(buffer.readLine().size(), 1); QCOMPARE(buffer.readLine().size(), 10); QVERIFY(buffer.readLine().isNull()); } } class SequentialReadBuffer : public QIODevice { public: SequentialReadBuffer(const char *data) : QIODevice(), buf(new QByteArray(data)), offset(0), ownbuf(true) { } SequentialReadBuffer(QByteArray *byteArray) : QIODevice(), buf(byteArray), offset(0), ownbuf(false) { } virtual ~SequentialReadBuffer() { if (ownbuf) delete buf; } bool isSequential() const override { return true; } const QByteArray &buffer() const { return *buf; } protected: qint64 readData(char *data, qint64 maxSize) override { maxSize = qMin(maxSize, qint64(buf->size() - offset)); memcpy(data, buf->constData() + offset, maxSize); offset += maxSize; return maxSize; } qint64 writeData(const char * /* data */, qint64 /* maxSize */) override { return -1; } private: QByteArray *buf; int offset; bool ownbuf; }; // Test readAll() on position change for sequential device void tst_QIODevice::readAllKeepPosition() { SequentialReadBuffer buffer("Hello world!"); buffer.open(QIODevice::ReadOnly); char c; QCOMPARE(buffer.readChannelCount(), 1); QCOMPARE(buffer.writeChannelCount(), 0); QVERIFY(buffer.getChar(&c)); QCOMPARE(buffer.pos(), qint64(0)); buffer.ungetChar(c); QCOMPARE(buffer.pos(), qint64(0)); QByteArray resultArray = buffer.readAll(); QCOMPARE(buffer.pos(), qint64(0)); QCOMPARE(resultArray, buffer.buffer()); } class RandomAccessBuffer : public QIODevice { public: RandomAccessBuffer(const char *data) : QIODevice(), buf(data) { } protected: qint64 readData(char *data, qint64 maxSize) override { maxSize = qMin(maxSize, qint64(buf.size() - pos())); memcpy(data, buf.constData() + pos(), maxSize); return maxSize; } qint64 writeData(const char *data, qint64 maxSize) override { maxSize = qMin(maxSize, qint64(buf.size() - pos())); memcpy(buf.data() + pos(), data, maxSize); return maxSize; } private: QByteArray buf; }; // Test write() on skipping correct number of bytes in read buffer void tst_QIODevice::writeInTextMode() { // Unlike other platforms, Windows implementation expands '\n' into // "\r\n" sequence in write(). Ensure that write() properly works with // a read buffer on random-access devices. #ifndef Q_OS_WIN QSKIP("This is a Windows-only test"); #else RandomAccessBuffer buffer("one\r\ntwo\r\nthree\r\n"); buffer.open(QBuffer::ReadWrite | QBuffer::Text); QCOMPARE(buffer.readLine(), QByteArray("one\n")); QCOMPARE(buffer.write("two\n"), 4); QCOMPARE(buffer.readLine(), QByteArray("three\n")); #endif } void tst_QIODevice::skip_data() { QTest::addColumn("sequential"); QTest::addColumn("data"); QTest::addColumn("read"); QTest::addColumn("skip"); QTest::addColumn("skipped"); QTest::addColumn("expect"); QByteArray bigData; bigData.fill('a', 20000); bigData[10001] = 'x'; bool sequential = true; do { QByteArray devName(sequential ? "sequential" : "random-access"); QTest::newRow(qPrintable(devName + "-small_data")) << true << QByteArray("abcdefghij") << 3 << 6 << 6 << 'j'; QTest::newRow(qPrintable(devName + "-big_data")) << true << bigData << 1 << 10000 << 10000 << 'x'; QTest::newRow(qPrintable(devName + "-beyond_the_end")) << true << bigData << 1 << 20000 << 19999 << '\0'; sequential = !sequential; } while (!sequential); } void tst_QIODevice::skip() { QFETCH(bool, sequential); QFETCH(QByteArray, data); QFETCH(int, read); QFETCH(int, skip); QFETCH(int, skipped); QFETCH(char, expect); char lastChar = 0; QScopedPointer dev(sequential ? (QIODevice *) new SequentialReadBuffer(&data) : (QIODevice *) new QBuffer(&data)); dev->open(QIODevice::ReadOnly); for (int i = 0; i < read; ++i) dev->getChar(nullptr); QCOMPARE(dev->skip(skip), skipped); dev->getChar(&lastChar); QCOMPARE(lastChar, expect); } void tst_QIODevice::skipAfterPeek_data() { QTest::addColumn("sequential"); QTest::addColumn("data"); QByteArray bigData; for (int i = 0; i < 1000; ++i) bigData += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; QTest::newRow("sequential") << true << bigData; QTest::newRow("random-access") << false << bigData; } void tst_QIODevice::skipAfterPeek() { QFETCH(bool, sequential); QFETCH(QByteArray, data); QScopedPointer dev(sequential ? (QIODevice *) new SequentialReadBuffer(&data) : (QIODevice *) new QBuffer(&data)); int readSoFar = 0; qint64 bytesToSkip = 1; dev->open(QIODevice::ReadOnly); forever { QByteArray chunk = dev->peek(bytesToSkip); if (chunk.isEmpty()) break; QCOMPARE(dev->skip(bytesToSkip), qint64(chunk.size())); QCOMPARE(chunk, data.mid(readSoFar, chunk.size())); readSoFar += chunk.size(); bytesToSkip <<= 1; } QCOMPARE(readSoFar, data.size()); } void tst_QIODevice::transaction_data() { QTest::addColumn("sequential"); QTest::addColumn("i8Data"); QTest::addColumn("i16Data"); QTest::addColumn("i32Data"); QTest::addColumn("i64Data"); QTest::addColumn("bData"); QTest::addColumn("fData"); QTest::addColumn("dData"); QTest::addColumn("strData"); bool sequential = true; do { QByteArray devName(sequential ? "sequential" : "random-access"); QTest::newRow(qPrintable(devName + '1')) << sequential << qint8(1) << qint16(2) << qint32(3) << qint64(4) << true << 5.0f << double(6.0) << QByteArray("Hello world!"); QTest::newRow(qPrintable(devName + '2')) << sequential << qint8(1 << 6) << qint16(1 << 14) << qint32(1 << 30) << (qint64(1) << 62) << false << 123.0f << double(234.0) << QByteArray("abcdefghijklmnopqrstuvwxyz"); QTest::newRow(qPrintable(devName + '3')) << sequential << qint8(-1) << qint16(-2) << qint32(-3) << qint64(-4) << true << -123.0f << double(-234.0) << QByteArray("Qt rocks!"); sequential = !sequential; } while (!sequential); } // Test transaction integrity void tst_QIODevice::transaction() { QByteArray testBuffer; QFETCH(bool, sequential); QFETCH(qint8, i8Data); QFETCH(qint16, i16Data); QFETCH(qint32, i32Data); QFETCH(qint64, i64Data); QFETCH(bool, bData); QFETCH(float, fData); QFETCH(double, dData); QFETCH(QByteArray, strData); { QDataStream stream(&testBuffer, QIODevice::WriteOnly); stream << i8Data << i16Data << i32Data << i64Data << bData << fData << dData << strData.constData(); } for (int splitPos = 0; splitPos <= testBuffer.size(); ++splitPos) { QByteArray readBuffer(testBuffer.left(splitPos)); QIODevice *dev = sequential ? (QIODevice *) new SequentialReadBuffer(&readBuffer) : (QIODevice *) new QBuffer(&readBuffer); dev->open(QIODevice::ReadOnly); QDataStream stream(dev); qint8 i8; qint16 i16; qint32 i32; qint64 i64; bool b; float f; double d; char *str; forever { QVERIFY(!dev->isTransactionStarted()); dev->startTransaction(); QVERIFY(dev->isTransactionStarted()); // Try to read all data in one go. If the status of the data stream // indicates an unsuccessful operation, restart a read transaction // on the completed buffer. stream >> i8 >> i16 >> i32 >> i64 >> b >> f >> d >> str; QVERIFY(stream.atEnd()); if (stream.status() == QDataStream::Ok) { dev->commitTransaction(); break; } dev->rollbackTransaction(); QVERIFY(splitPos == 0 || !stream.atEnd()); QCOMPARE(dev->pos(), Q_INT64_C(0)); QCOMPARE(dev->bytesAvailable(), qint64(readBuffer.size())); QVERIFY(readBuffer.size() < testBuffer.size()); delete [] str; readBuffer.append(testBuffer.right(testBuffer.size() - splitPos)); stream.resetStatus(); } QVERIFY(!dev->isTransactionStarted()); QVERIFY(stream.atEnd()); QCOMPARE(i8, i8Data); QCOMPARE(i16, i16Data); QCOMPARE(i32, i32Data); QCOMPARE(i64, i64Data); QCOMPARE(b, bData); QCOMPARE(f, fData); QCOMPARE(d, dData); QVERIFY(strData == str); delete [] str; stream.setDevice(0); delete dev; } } QTEST_MAIN(tst_QIODevice) #include "tst_qiodevice.moc"