blob: da5327594c76a9e787bbcbe47d8f941291d7d542 [file] [log] [blame]
/****************************************************************************
**
** 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 <QtCore/QCoreApplication>
#include <QtNetwork/QtNetwork>
#include <QtTest/QtTest>
#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<QTemporaryDir> 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<QTemporaryDir>::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<const char*>(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<const char*>(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<const char*>(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<const char *>(buf), "ZXCV");
QCOMPARE(device->pos(), qint64(0));
device->read(buf, 4);
QCOMPARE(static_cast<const char *>(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<QByteArray>("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<QByteArray>("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<bool>("sequential");
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("read");
QTest::addColumn<int>("skip");
QTest::addColumn<int>("skipped");
QTest::addColumn<char>("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<QIODevice> 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<bool>("sequential");
QTest::addColumn<QByteArray>("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<QIODevice> 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<bool>("sequential");
QTest::addColumn<qint8>("i8Data");
QTest::addColumn<qint16>("i16Data");
QTest::addColumn<qint32>("i32Data");
QTest::addColumn<qint64>("i64Data");
QTest::addColumn<bool>("bData");
QTest::addColumn<float>("fData");
QTest::addColumn<double>("dData");
QTest::addColumn<QByteArray>("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"