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 <QtTest/QtTest> |
30 | |
31 | #include <QBuffer> |
32 | #include <QByteArray> |
33 | |
34 | class tst_QBuffer : public QObject |
35 | { |
36 | Q_OBJECT |
37 | private slots: |
38 | void open(); |
39 | void getSetCheck(); |
40 | void readBlock(); |
41 | void readBlockPastEnd(); |
42 | void writeBlock_data(); |
43 | void writeBlock(); |
44 | void seek(); |
45 | void seekTest_data(); |
46 | void seekTest(); |
47 | void read_rawdata(); |
48 | void isSequential(); |
49 | void signalTest_data(); |
50 | void signalTest(); |
51 | void isClosedAfterClose(); |
52 | void readLine_data(); |
53 | void readLine(); |
54 | void canReadLine_data(); |
55 | void canReadLine(); |
56 | void atEnd(); |
57 | void readLineBoundaries(); |
58 | void getAndUngetChar(); |
59 | void writeAfterQByteArrayResize(); |
60 | void read_null(); |
61 | |
62 | protected slots: |
63 | void readyReadSlot(); |
64 | void bytesWrittenSlot(qint64 written); |
65 | |
66 | private: |
67 | qint64 totalBytesWritten; |
68 | bool gotReadyRead; |
69 | }; |
70 | |
71 | // Testing get/set functions |
72 | void tst_QBuffer::getSetCheck() |
73 | { |
74 | QBuffer obj1; |
75 | // const QByteArray & QBuffer::data() |
76 | // void QBuffer::setData(const QByteArray &) |
77 | QByteArray var1("Bogus data" ); |
78 | obj1.setData(var1); |
79 | QCOMPARE(var1, obj1.data()); |
80 | obj1.setData(QByteArray()); |
81 | QCOMPARE(QByteArray(), obj1.data()); |
82 | } |
83 | |
84 | void tst_QBuffer::open() |
85 | { |
86 | QByteArray data(10, 'f'); |
87 | |
88 | QBuffer b; |
89 | |
90 | QTest::ignoreMessage(type: QtWarningMsg, message: "QBuffer::open: Buffer access not specified" ); |
91 | QVERIFY(!b.open(QIODevice::NotOpen)); |
92 | QVERIFY(!b.isOpen()); |
93 | b.close(); |
94 | |
95 | QTest::ignoreMessage(type: QtWarningMsg, message: "QBuffer::open: Buffer access not specified" ); |
96 | QVERIFY(!b.open(QIODevice::Text)); |
97 | QVERIFY(!b.isOpen()); |
98 | b.close(); |
99 | |
100 | QTest::ignoreMessage(type: QtWarningMsg, message: "QBuffer::open: Buffer access not specified" ); |
101 | QVERIFY(!b.open(QIODevice::Unbuffered)); |
102 | QVERIFY(!b.isOpen()); |
103 | b.close(); |
104 | |
105 | QVERIFY(b.open(QIODevice::ReadOnly)); |
106 | QVERIFY(b.isReadable()); |
107 | b.close(); |
108 | |
109 | QVERIFY(b.open(QIODevice::WriteOnly)); |
110 | QVERIFY(b.isWritable()); |
111 | b.close(); |
112 | |
113 | b.setData(data); |
114 | QVERIFY(b.open(QIODevice::Append)); |
115 | QVERIFY(b.isWritable()); |
116 | QCOMPARE(b.size(), qint64(10)); |
117 | QCOMPARE(b.pos(), b.size()); |
118 | b.close(); |
119 | |
120 | b.setData(data); |
121 | QVERIFY(b.open(QIODevice::Truncate)); |
122 | QVERIFY(b.isWritable()); |
123 | QCOMPARE(b.size(), qint64(0)); |
124 | QCOMPARE(b.pos(), qint64(0)); |
125 | b.close(); |
126 | |
127 | QVERIFY(b.open(QIODevice::ReadWrite)); |
128 | QVERIFY(b.isReadable()); |
129 | QVERIFY(b.isWritable()); |
130 | b.close(); |
131 | } |
132 | |
133 | // some status() tests, too |
134 | void tst_QBuffer::readBlock() |
135 | { |
136 | const int arraySize = 10; |
137 | char a[arraySize]; |
138 | QBuffer b; |
139 | QCOMPARE(b.bytesAvailable(), (qint64) 0); // no data |
140 | QCOMPARE(b.read(a, arraySize), (qint64) -1); // not opened |
141 | QVERIFY(b.atEnd()); |
142 | |
143 | QByteArray ba; |
144 | ba.resize(size: arraySize); |
145 | b.setBuffer(&ba); |
146 | QCOMPARE(b.bytesAvailable(), (qint64) arraySize); |
147 | b.open(openMode: QIODevice::WriteOnly); |
148 | QCOMPARE(b.bytesAvailable(), (qint64) arraySize); |
149 | QTest::ignoreMessage(type: QtWarningMsg, message: "QIODevice::read (QBuffer): WriteOnly device" ); |
150 | QCOMPARE(b.read(a, arraySize), (qint64) -1); // no read access |
151 | b.close(); |
152 | |
153 | b.open(openMode: QIODevice::ReadOnly); |
154 | QCOMPARE(b.bytesAvailable(), (qint64) arraySize); |
155 | QCOMPARE(b.read(a, arraySize), (qint64) arraySize); |
156 | QVERIFY(b.atEnd()); |
157 | QCOMPARE(b.bytesAvailable(), (qint64) 0); |
158 | |
159 | // up to 3.0.x reading beyond the end was an error while ok |
160 | // this has been made consistent with other QIODevice sub classes in 3.1 |
161 | QCOMPARE(b.read(a, 1), qint64(0)); |
162 | QVERIFY(b.atEnd()); |
163 | |
164 | // read in two chunks |
165 | b.close(); |
166 | b.open(openMode: QIODevice::ReadOnly); |
167 | QCOMPARE(b.bytesAvailable(), (qint64) arraySize); |
168 | QCOMPARE(b.read(a, arraySize/2), (qint64) arraySize/2); |
169 | QCOMPARE(b.bytesAvailable(), (qint64) arraySize/2); |
170 | QCOMPARE(b.read(a + arraySize/2, arraySize - arraySize/2), |
171 | (qint64)(arraySize - arraySize/2)); |
172 | QVERIFY(b.atEnd()); |
173 | QCOMPARE(b.bytesAvailable(), (qint64) 0); |
174 | } |
175 | |
176 | void tst_QBuffer::readBlockPastEnd() |
177 | { |
178 | QByteArray arr(4096 + 3616, 'd'); |
179 | QBuffer buf(&arr); |
180 | |
181 | buf.open(openMode: QIODevice::ReadOnly); |
182 | char dummy[4096]; |
183 | |
184 | buf.read(maxlen: 1); |
185 | |
186 | QCOMPARE(buf.read(dummy, 4096), qint64(4096)); |
187 | QCOMPARE(buf.read(dummy, 4096), qint64(3615)); |
188 | QVERIFY(buf.atEnd()); |
189 | } |
190 | |
191 | void tst_QBuffer::writeBlock_data() |
192 | { |
193 | QTest::addColumn<QString>(name: "str" ); |
194 | |
195 | QTest::newRow( dataTag: "small_bytearray" ) << QString("Test" ); |
196 | QTest::newRow( dataTag: "large_bytearray" ) << QString( |
197 | "The QBuffer class is an I/O device that operates on a QByteArray.\n" |
198 | "QBuffer is used to read and write to a memory buffer. It is normally " |
199 | "used with a QTextStream or a QDataStream. QBuffer has an associated " |
200 | "QByteArray which holds the buffer data. The size() of the buffer is " |
201 | "automatically adjusted as data is written.\n" |
202 | "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " |
203 | "byte array. The byte array can also be set with setBuffer(). Writing to " |
204 | "the QBuffer will modify the original byte array because QByteArray is " |
205 | "explicitly shared.\n" |
206 | "Use open() to open the buffer before use and to set the mode (read-only, " |
207 | "write-only, etc.). close() closes the buffer. The buffer must be closed " |
208 | "before reopening or calling setBuffer().\n" |
209 | "A common way to use QBuffer is through QDataStream or QTextStream, which " |
210 | "have constructors that take a QBuffer parameter. For convenience, there " |
211 | "are also QDataStream and QTextStream constructors that take a QByteArray " |
212 | "parameter. These constructors create and open an internal QBuffer.\n" |
213 | "Note that QTextStream can also operate on a QString (a Unicode string); a " |
214 | "QBuffer cannot.\n" |
215 | "You can also use QBuffer directly through the standard QIODevice functions " |
216 | "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" |
217 | "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " |
218 | "Classes and Input/Output and Networking.\n\n" |
219 | "The QBuffer class is an I/O device that operates on a QByteArray.\n" |
220 | "QBuffer is used to read and write to a memory buffer. It is normally " |
221 | "used with a QTextStream or a QDataStream. QBuffer has an associated " |
222 | "QByteArray which holds the buffer data. The size() of the buffer is " |
223 | "automatically adjusted as data is written.\n" |
224 | "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " |
225 | "byte array. The byte array can also be set with setBuffer(). Writing to " |
226 | "the QBuffer will modify the original byte array because QByteArray is " |
227 | "explicitly shared.\n" |
228 | "Use open() to open the buffer before use and to set the mode (read-only, " |
229 | "write-only, etc.). close() closes the buffer. The buffer must be closed " |
230 | "before reopening or calling setBuffer().\n" |
231 | "A common way to use QBuffer is through QDataStream or QTextStream, which " |
232 | "have constructors that take a QBuffer parameter. For convenience, there " |
233 | "are also QDataStream and QTextStream constructors that take a QByteArray " |
234 | "parameter. These constructors create and open an internal QBuffer.\n" |
235 | "Note that QTextStream can also operate on a QString (a Unicode string); a " |
236 | "QBuffer cannot.\n" |
237 | "You can also use QBuffer directly through the standard QIODevice functions " |
238 | "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" |
239 | "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " |
240 | "Classes and Input/Output and Networking.\n\n" |
241 | "The QBuffer class is an I/O device that operates on a QByteArray.\n" |
242 | "QBuffer is used to read and write to a memory buffer. It is normally " |
243 | "used with a QTextStream or a QDataStream. QBuffer has an associated " |
244 | "QByteArray which holds the buffer data. The size() of the buffer is " |
245 | "automatically adjusted as data is written.\n" |
246 | "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " |
247 | "byte array. The byte array can also be set with setBuffer(). Writing to " |
248 | "the QBuffer will modify the original byte array because QByteArray is " |
249 | "explicitly shared.\n" |
250 | "Use open() to open the buffer before use and to set the mode (read-only, " |
251 | "write-only, etc.). close() closes the buffer. The buffer must be closed " |
252 | "before reopening or calling setBuffer().\n" |
253 | "A common way to use QBuffer is through QDataStream or QTextStream, which " |
254 | "have constructors that take a QBuffer parameter. For convenience, there " |
255 | "are also QDataStream and QTextStream constructors that take a QByteArray " |
256 | "parameter. These constructors create and open an internal QBuffer.\n" |
257 | "Note that QTextStream can also operate on a QString (a Unicode string); a " |
258 | "QBuffer cannot.\n" |
259 | "You can also use QBuffer directly through the standard QIODevice functions " |
260 | "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" |
261 | "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " |
262 | "Classes and Input/Output and Networking." ); |
263 | } |
264 | |
265 | void tst_QBuffer::writeBlock() |
266 | { |
267 | QFETCH( QString, str ); |
268 | |
269 | QByteArray ba; |
270 | QBuffer buf( &ba ); |
271 | buf.open(openMode: QIODevice::ReadWrite); |
272 | QByteArray data = str.toLatin1(); |
273 | QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size())); |
274 | |
275 | QCOMPARE(buf.data(), str.toLatin1()); |
276 | } |
277 | |
278 | void tst_QBuffer::seek() |
279 | { |
280 | QBuffer buffer; |
281 | buffer.open(openMode: QIODevice::WriteOnly); |
282 | QCOMPARE(buffer.size(), qint64(0)); |
283 | QCOMPARE(buffer.pos(), qint64(0)); |
284 | const qint64 pos = 10; |
285 | QVERIFY(buffer.seek(pos)); |
286 | QCOMPARE(buffer.size(), pos); |
287 | } |
288 | |
289 | void tst_QBuffer::seekTest_data() |
290 | { |
291 | writeBlock_data(); |
292 | } |
293 | |
294 | #define DO_VALID_SEEK(position) { \ |
295 | char c; \ |
296 | QVERIFY(buf.seek(qint64(position))); \ |
297 | QCOMPARE(buf.pos(), qint64(position)); \ |
298 | QVERIFY(buf.getChar(&c)); \ |
299 | QCOMPARE(QChar(c), str.at(qint64(position))); \ |
300 | } |
301 | #define DO_INVALID_SEEK(position) { \ |
302 | qint64 prev_pos = buf.pos(); \ |
303 | QVERIFY(!buf.seek(qint64(position))); \ |
304 | QCOMPARE(buf.pos(), prev_pos); /* position should not be changed */ \ |
305 | } |
306 | |
307 | void tst_QBuffer::seekTest() |
308 | { |
309 | QFETCH(QString, str); |
310 | |
311 | QByteArray ba; |
312 | QBuffer buf(&ba); |
313 | QCOMPARE(buf.pos(), qint64(0)); |
314 | |
315 | buf.open(openMode: QIODevice::ReadWrite); |
316 | QCOMPARE(buf.pos(), qint64(0)); |
317 | QCOMPARE(buf.bytesAvailable(), qint64(0)); |
318 | |
319 | QByteArray data = str.toLatin1(); |
320 | QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size())); |
321 | QCOMPARE(buf.bytesAvailable(), qint64(0)); // we're at the end |
322 | QCOMPARE(buf.size(), qint64(data.size())); |
323 | |
324 | QTest::ignoreMessage(type: QtWarningMsg, message: "QBuffer::seek: Invalid pos: -1" ); |
325 | DO_INVALID_SEEK(-1); |
326 | |
327 | DO_VALID_SEEK(0); |
328 | DO_VALID_SEEK(str.size() - 1); |
329 | QVERIFY(buf.atEnd()); |
330 | DO_VALID_SEEK(str.size() / 2); |
331 | |
332 | // Special case: valid to seek one position past the buffer. |
333 | // Its then legal to write, but not read. |
334 | { |
335 | char c = 'a'; |
336 | QVERIFY(buf.seek(qint64(str.size()))); |
337 | QCOMPARE(buf.bytesAvailable(), qint64(0)); |
338 | QCOMPARE(buf.read(&c, qint64(1)), qint64(0)); |
339 | QCOMPARE(c, 'a'); |
340 | QCOMPARE(buf.write(&c, qint64(1)), qint64(1)); |
341 | } |
342 | |
343 | // Special case 2: seeking to an arbitrary position beyond the buffer auto-expands it |
344 | { |
345 | char c; |
346 | const int offset = 1; // any positive integer will do |
347 | const qint64 pos = buf.size() + offset; |
348 | QVERIFY(buf.seek(pos)); |
349 | QCOMPARE(buf.bytesAvailable(), qint64(0)); |
350 | QCOMPARE(buf.pos(), pos); |
351 | QVERIFY(!buf.getChar(&c)); |
352 | QVERIFY(buf.seek(pos - 1)); |
353 | QVERIFY(buf.getChar(&c)); |
354 | QCOMPARE(c, buf.data().at(pos - 1)); |
355 | QVERIFY(buf.seek(pos)); |
356 | QVERIFY(buf.putChar(c)); |
357 | } |
358 | } |
359 | |
360 | void tst_QBuffer::read_rawdata() |
361 | { |
362 | static const unsigned char mydata[] = { |
363 | 0x01, 0x00, 0x03, 0x84, 0x78, 0x9c, 0x3b, 0x76, |
364 | 0xec, 0x18, 0xc3, 0x31, 0x0a, 0xf1, 0xcc, 0x99, |
365 | 0x6d, 0x5b |
366 | }; |
367 | |
368 | QByteArray data = QByteArray::fromRawData((const char *)mydata, size: sizeof(mydata)); |
369 | QBuffer buffer(&data); |
370 | buffer.open(openMode: QIODevice::ReadOnly); |
371 | QDataStream in(&buffer); |
372 | quint8 ch; |
373 | for (int i = 0; i < (int)sizeof(mydata); ++i) { |
374 | QVERIFY(!buffer.atEnd()); |
375 | in >> ch; |
376 | QCOMPARE(ch, (quint8)mydata[i]); |
377 | } |
378 | QVERIFY(buffer.atEnd()); |
379 | } |
380 | |
381 | void tst_QBuffer::isSequential() |
382 | { |
383 | QBuffer buf; |
384 | QVERIFY(!buf.isSequential()); |
385 | } |
386 | |
387 | void tst_QBuffer::signalTest_data() |
388 | { |
389 | QTest::addColumn<QByteArray>(name: "sample" ); |
390 | |
391 | QTest::newRow(dataTag: "empty" ) << QByteArray(); |
392 | QTest::newRow(dataTag: "size 1" ) << QByteArray("1" ); |
393 | QTest::newRow(dataTag: "size 2" ) << QByteArray("11" ); |
394 | QTest::newRow(dataTag: "size 100" ) << QByteArray(100, '1'); |
395 | } |
396 | |
397 | void tst_QBuffer::signalTest() |
398 | { |
399 | QFETCH(QByteArray, sample); |
400 | |
401 | totalBytesWritten = 0; |
402 | |
403 | QBuffer buf; |
404 | buf.open(openMode: QIODevice::WriteOnly); |
405 | |
406 | buf.buffer().resize(size: sample.size() * 10); |
407 | connect(sender: &buf, SIGNAL(readyRead()), receiver: this, SLOT(readyReadSlot())); |
408 | connect(sender: &buf, SIGNAL(bytesWritten(qint64)), receiver: this, SLOT(bytesWrittenSlot(qint64))); |
409 | |
410 | for (int i = 0; i < 10; ++i) { |
411 | gotReadyRead = false; |
412 | QCOMPARE(buf.write(sample), qint64(sample.size())); |
413 | if (sample.size() > 0) { |
414 | QTestEventLoop::instance().enterLoop(secs: 5); |
415 | if (QTestEventLoop::instance().timeout()) |
416 | QFAIL("Timed out when waiting for readyRead()" ); |
417 | QCOMPARE(totalBytesWritten, qint64(sample.size() * (i + 1))); |
418 | QVERIFY(gotReadyRead); |
419 | } else { |
420 | QCOMPARE(totalBytesWritten, qint64(0)); |
421 | QVERIFY(!gotReadyRead); |
422 | } |
423 | } |
424 | } |
425 | |
426 | void tst_QBuffer::readyReadSlot() |
427 | { |
428 | gotReadyRead = true; |
429 | QTestEventLoop::instance().exitLoop(); |
430 | } |
431 | |
432 | void tst_QBuffer::bytesWrittenSlot(qint64 written) |
433 | { |
434 | totalBytesWritten += written; |
435 | } |
436 | |
437 | void tst_QBuffer::isClosedAfterClose() |
438 | { |
439 | QBuffer buffer; |
440 | buffer.open(openMode: QBuffer::ReadOnly); |
441 | QVERIFY(buffer.isOpen()); |
442 | buffer.close(); |
443 | QVERIFY(!buffer.isOpen()); |
444 | } |
445 | |
446 | void tst_QBuffer::readLine_data() |
447 | { |
448 | QTest::addColumn<QByteArray>(name: "src" ); |
449 | QTest::addColumn<int>(name: "maxlen" ); |
450 | QTest::addColumn<QByteArray>(name: "expected" ); |
451 | |
452 | QTest::newRow(dataTag: "1" ) << QByteArray("line1\nline2\n" ) << 1024 |
453 | << QByteArray("line1\n" ); |
454 | QTest::newRow(dataTag: "2" ) << QByteArray("hi there" ) << 1024 |
455 | << QByteArray("hi there" ); |
456 | QTest::newRow(dataTag: "3" ) << QByteArray("l\n" ) << 3 << QByteArray("l\n" ); |
457 | QTest::newRow(dataTag: "4" ) << QByteArray("l\n" ) << 2 << QByteArray("l" ); |
458 | } |
459 | |
460 | void tst_QBuffer::readLine() |
461 | { |
462 | QFETCH(QByteArray, src); |
463 | QFETCH(int, maxlen); |
464 | QFETCH(QByteArray, expected); |
465 | |
466 | QBuffer buf; |
467 | buf.setBuffer(&src); |
468 | char *result = new char[maxlen + 1]; |
469 | result[maxlen] = '\0'; |
470 | |
471 | QVERIFY(buf.open(QIODevice::ReadOnly)); |
472 | |
473 | qint64 bytes_read = buf.readLine(data: result, maxlen); |
474 | |
475 | QCOMPARE(bytes_read, qint64(expected.size())); |
476 | QCOMPARE(QByteArray(result), expected); |
477 | |
478 | buf.close(); |
479 | delete[] result; |
480 | |
481 | } |
482 | |
483 | void tst_QBuffer::canReadLine_data() |
484 | { |
485 | QTest::addColumn<QByteArray>(name: "src" ); |
486 | QTest::addColumn<bool>(name: "expected" ); |
487 | |
488 | QTest::newRow(dataTag: "1" ) << QByteArray("no newline" ) << false; |
489 | QTest::newRow(dataTag: "2" ) << QByteArray("two \n lines\n" ) << true; |
490 | QTest::newRow(dataTag: "3" ) << QByteArray("\n" ) << true; |
491 | QTest::newRow(dataTag: "4" ) << QByteArray() << false; |
492 | } |
493 | |
494 | void tst_QBuffer::canReadLine() |
495 | { |
496 | QFETCH(QByteArray, src); |
497 | QFETCH(bool, expected); |
498 | |
499 | QBuffer buf; |
500 | buf.setBuffer(&src); |
501 | QVERIFY(!buf.canReadLine()); |
502 | QVERIFY(buf.open(QIODevice::ReadOnly)); |
503 | QCOMPARE(buf.canReadLine(), expected); |
504 | } |
505 | |
506 | void tst_QBuffer::atEnd() |
507 | { |
508 | QBuffer buffer; |
509 | buffer.open(openMode: QBuffer::Append); |
510 | buffer.write(data: "heisann" ); |
511 | buffer.close(); |
512 | |
513 | buffer.open(openMode: QBuffer::ReadOnly); |
514 | buffer.seek(off: buffer.size()); |
515 | char c; |
516 | QVERIFY(!buffer.getChar(&c)); |
517 | QCOMPARE(buffer.read(&c, 1), qint64(0)); |
518 | } |
519 | |
520 | // Test that reading data out of a QBuffer a line at a time gives the same |
521 | // result as reading the whole buffer at once. |
522 | void tst_QBuffer::readLineBoundaries() |
523 | { |
524 | QByteArray line = "This is a line\n" ; |
525 | QBuffer buffer; |
526 | buffer.open(openMode: QIODevice::ReadWrite); |
527 | while (buffer.size() < 16384) |
528 | buffer.write(data: line); |
529 | |
530 | buffer.seek(off: 0); |
531 | QByteArray lineByLine; |
532 | while (!buffer.atEnd()) |
533 | lineByLine.append(a: buffer.readLine()); |
534 | |
535 | buffer.seek(off: 0); |
536 | QCOMPARE(buffer.bytesAvailable(), lineByLine.size()); |
537 | |
538 | QByteArray all = buffer.readAll(); |
539 | QCOMPARE(all.size(), lineByLine.size()); |
540 | QCOMPARE(all, lineByLine); |
541 | } |
542 | |
543 | // Test that any character in a buffer can be read and pushed back. |
544 | void tst_QBuffer::getAndUngetChar() |
545 | { |
546 | // Create some data in a buffer |
547 | QByteArray line = "This is a line\n" ; |
548 | QBuffer buffer; |
549 | buffer.open(openMode: QIODevice::ReadWrite); |
550 | while (buffer.size() < 16384) |
551 | buffer.write(data: line); |
552 | |
553 | // Take a copy of the data held in the buffer |
554 | buffer.seek(off: 0); |
555 | QCOMPARE(buffer.bytesAvailable(), buffer.size()); |
556 | QByteArray data = buffer.readAll(); |
557 | QCOMPARE(buffer.bytesAvailable(), qint64(0)); |
558 | |
559 | // Get and unget each character in order |
560 | for (qint64 i = 0; i < buffer.size(); ++i) { |
561 | buffer.seek(off: i); |
562 | char c; |
563 | QVERIFY(buffer.getChar(&c)); |
564 | QCOMPARE(c, data.at((uint)i)); |
565 | buffer.ungetChar(c); |
566 | } |
567 | |
568 | // Get and unget each character in reverse order |
569 | for (qint64 i = buffer.size() - 1; i >= 0; --i) { |
570 | buffer.seek(off: i); |
571 | char c; |
572 | QVERIFY(buffer.getChar(&c)); |
573 | QCOMPARE(c, data.at((uint)i)); |
574 | buffer.ungetChar(c); |
575 | } |
576 | |
577 | // Verify that the state of the buffer still matches the original data. |
578 | buffer.seek(off: 0); |
579 | QCOMPARE(buffer.bytesAvailable(), data.size()); |
580 | QCOMPARE(buffer.readAll(), data); |
581 | QCOMPARE(buffer.bytesAvailable(), qint64(0)); |
582 | } |
583 | |
584 | void tst_QBuffer::writeAfterQByteArrayResize() |
585 | { |
586 | QBuffer buffer; |
587 | QVERIFY(buffer.open(QIODevice::WriteOnly)); |
588 | |
589 | buffer.write(data: QByteArray().fill(c: 'a', size: 1000)); |
590 | QCOMPARE(buffer.buffer().size(), 1000); |
591 | |
592 | // resize the QByteArray behind QBuffer's back |
593 | buffer.buffer().clear(); |
594 | buffer.seek(off: 0); |
595 | QCOMPARE(buffer.buffer().size(), 0); |
596 | |
597 | buffer.write(data: QByteArray().fill(c: 'b', size: 1000)); |
598 | QCOMPARE(buffer.buffer().size(), 1000); |
599 | } |
600 | |
601 | void tst_QBuffer::read_null() |
602 | { |
603 | QByteArray buffer; |
604 | buffer.resize(size: 32000); |
605 | for (int i = 0; i < buffer.size(); ++i) |
606 | buffer[i] = char(i & 0xff); |
607 | |
608 | QBuffer in(&buffer); |
609 | in.open(openMode: QIODevice::ReadOnly); |
610 | |
611 | QByteArray chunk; |
612 | |
613 | chunk.resize(size: 16380); |
614 | in.read(data: chunk.data(), maxlen: 16380); |
615 | |
616 | QCOMPARE(chunk, buffer.mid(0, chunk.size())); |
617 | |
618 | in.read(data: chunk.data(), maxlen: 0); |
619 | |
620 | chunk.resize(size: 8); |
621 | in.read(data: chunk.data(), maxlen: chunk.size()); |
622 | |
623 | QCOMPARE(chunk, buffer.mid(16380, chunk.size())); |
624 | } |
625 | |
626 | QTEST_MAIN(tst_QBuffer) |
627 | #include "tst_qbuffer.moc" |
628 | |