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
35class tst_QIODevice : public QObject
36{
37 Q_OBJECT
38
39private 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
66private:
67 QSharedPointer<QTemporaryDir> m_tempDir;
68 QString m_previousCurrent;
69};
70
71void 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
83void tst_QIODevice::cleanupTestCase()
84{
85 QDir::setCurrent(m_previousCurrent);
86}
87
88// Testing get/set functions
89void 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//----------------------------------------------------------------------------------
105void 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//----------------------------------------------------------------------------------
158void 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
194void 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//--------------------------------------------------------------------
210void 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//--------------------------------------------------------------------
315void 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
353void 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
378void 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
409void 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
439void 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
488void 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
548class SequentialReadBuffer : public QIODevice
549{
550public:
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
560protected:
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
574private:
575 QByteArray *buf;
576 int offset;
577 bool ownbuf;
578};
579
580// Test readAll() on position change for sequential device
581void 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
599class RandomAccessBuffer : public QIODevice
600{
601public:
602 RandomAccessBuffer(const char *data) : QIODevice(), buf(data) { }
603
604protected:
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
620private:
621 QByteArray buf;
622};
623
624// Test write() on skipping correct number of bytes in read buffer
625void 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
641void 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
669void 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
691void 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
704void 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
728void 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
761void 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
840QTEST_MAIN(tst_QIODevice)
841#include "tst_qiodevice.moc"
842

source code of qtbase/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp