1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 Intel Corporation
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining a copy
6 ** of this software and associated documentation files (the "Software"), to deal
7 ** in the Software without restriction, including without limitation the rights
8 ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 ** copies of the Software, and to permit persons to whom the Software is
10 ** furnished to do so, subject to the following conditions:
11 **
12 ** The above copyright notice and this permission notice shall be included in
13 ** all copies or substantial portions of the Software.
14 **
15 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 ** THE SOFTWARE.
22 **
23 ****************************************************************************/
24 
25 #define _XOPEN_SOURCE 700
26 #define  _DARWIN_C_SOURCE 1         /* need MAP_ANON */
27 #include <QtTest>
28 #include "cbor.h"
29 #include <stdio.h>
30 #include <stdarg.h>
31 
32 #if defined(Q_OS_UNIX)
33 #  include <sys/mman.h>
34 #  include <unistd.h>
35 #elif defined(Q_OS_WIN)
36 #  define WIN32_LEAN_AND_MEAN 1
37 #  define NOMINMAX 1
38 #  include <windows.h>
39 #endif
40 
41 
42 namespace QTest {
toString(const CborError & err)43 template<> char *toString<CborError>(const CborError &err)
44 {
45     return qstrdup(cbor_error_string(err));
46 }
47 }
48 
49 class tst_Parser : public QObject
50 {
51     Q_OBJECT
52 private slots:
53     void initParserEmpty();
54 
55     // parsing API
56     void integers_data();
57     void integers();
58     void halfFloat_data();
59     void halfFloat();
60     void fixed_data();
61     void fixed();
62     void strings_data();
strings()63     void strings() { fixed(); }
64     void tags_data();
tags()65     void tags() { fixed(); }
tagTags_data()66     void tagTags_data() { tags_data(); }
67     void tagTags();
68     void emptyContainers_data();
69     void emptyContainers();
70     void arrays_data();
71     void arrays();
undefLengthArrays_data()72     void undefLengthArrays_data() { arrays_data(); }
73     void undefLengthArrays();
nestedArrays_data()74     void nestedArrays_data() { arrays_data(); }
75     void nestedArrays();
76     void maps_data();
77     void maps();
undefLengthMaps_data()78     void undefLengthMaps_data() { maps_data(); }
79     void undefLengthMaps();
nestedMaps_data()80     void nestedMaps_data() { maps_data(); }
81     void nestedMaps();
82     void mapMixed_data();
mapMixed()83     void mapMixed() { arrays(); }
mapsAndArrays_data()84     void mapsAndArrays_data() { arrays_data(); }
85     void mapsAndArrays();
86 
readerApi_data()87     void readerApi_data() { arrays_data(); }
88     void readerApi();
89     void reparse_data();
90     void reparse();
91 
92     // chunked string API
93     void chunkedString_data();
94     void chunkedString();
chunkedStringInUndefArray_data()95     void chunkedStringInUndefArray_data() { chunkedString_data(); }
96     void chunkedStringInUndefArray();
97 
98     // convenience API
99     void stringLength_data();
100     void stringLength();
101     void stringCompare_data();
102     void stringCompare();
103     void mapFind_data();
104     void mapFind();
105 
106     // validation & errors
107     void checkedIntegers_data();
108     void checkedIntegers();
109     void validation_data();
110     void validation();
111     void strictValidation_data();
112     void strictValidation();
113     void incompleteData_data();
114     void incompleteData();
115     void endPointer_data();
116     void endPointer();
117     void recursionLimit_data();
118     void recursionLimit();
119 };
120 
121 struct ParserWrapper
122 {
123     void *realdata = nullptr;
124     uint8_t *data;
125     size_t len;
126     CborParser parser;
127     CborValue first;
128 
~ParserWrapperParserWrapper129     ~ParserWrapper() { freeMemory(); }
130 
initParserWrapper131     CborError init(const QByteArray &ba, uint32_t flags = 0)
132     {
133         return init(ba.constData(), ba.size(), flags);
134     }
initParserWrapper135     CborError init(const char *ptr, int n, uint32_t flags = 0)
136     {
137         freeMemory();
138         data = allocateMemory(n);
139         memcpy(data, ptr, len);
140         return cbor_parser_init(data, len, flags, &parser, &first);
141     }
beginParserWrapper142     uint8_t *begin() { return data; }
endParserWrapper143     uint8_t *end()   { return data + len; }
144 
145     uint8_t *allocateMemory(size_t);
146     void freeMemory();
147 
148     static const size_t PageSize = 4096;
mmapAllocationParserWrapper149     static inline size_t mmapAllocation(size_t n)
150     {
151         // round up and add one page
152         return (n + 2*PageSize) & ~(PageSize - 1);
153     }
154     static bool shouldUseMmap();
155 };
156 
shouldUseMmap()157 bool ParserWrapper::shouldUseMmap()
158 {
159     static int v = qEnvironmentVariableIntValue("PARSER_NO_MMAP");
160     return !v;
161 }
162 
allocateMemory(size_t n)163 uint8_t *ParserWrapper::allocateMemory(size_t n)
164 {
165     len = n;
166     if (shouldUseMmap()) {
167         size_t alloc = mmapAllocation(n);
168 #if defined(Q_OS_UNIX)
169         realdata = mmap(nullptr, alloc, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
170         Q_ASSERT_X(realdata != MAP_FAILED, "allocateMemory", "mmap failed!");
171 
172         // mark last page inaccessible
173         uint8_t *ptr = static_cast<uint8_t *>(realdata);
174         ptr += alloc - PageSize;
175         mprotect(ptr, PageSize, PROT_NONE);
176 
177         ptr -= n;
178         return ptr;
179 #elif defined(Q_OS_WIN)
180         DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
181         DWORD flProtect = PAGE_READWRITE;
182         realdata = VirtualAlloc(nullptr, alloc, flAllocationType, flProtect);
183         Q_ASSERT_X(realdata, "allocateMemory", "VirtualAlloc failed!");
184 
185         // mark last page inaccessible
186         uint8_t *ptr = static_cast<uint8_t *>(realdata);
187         ptr += alloc - PageSize;
188         VirtualProtect(ptr, PageSize, PAGE_NOACCESS, nullptr);
189 
190         ptr -= n;
191         return ptr;
192 #endif
193     }
194     realdata = malloc(n);
195     return static_cast<uint8_t *>(realdata);
196 }
197 
freeMemory()198 void ParserWrapper::freeMemory()
199 {
200     if (shouldUseMmap()) {
201         if (realdata) {
202 #if defined(Q_OS_UNIX)
203             size_t alloc = mmapAllocation(len);
204             munmap(realdata, alloc);
205 #elif defined(Q_OS_WIN)
206             VirtualFree(realdata, 0, MEM_RELEASE);
207 #endif
208         }
209         return;
210     }
211 
212     free(realdata);
213 }
214 
qstring_printf(void * out,const char * fmt,...)215 static CborError qstring_printf(void *out, const char *fmt, ...)
216 {
217     auto str = static_cast<QString *>(out);
218     va_list va;
219     va_start(va, fmt);
220     *str += QString::vasprintf(fmt, va);
221     va_end(va);
222     return CborNoError;
223 };
224 
parseOne(CborValue * it,QString * parsed)225 CborError parseOne(CborValue *it, QString *parsed)
226 {
227     int flags = CborPrettyShowStringFragments | CborPrettyIndicateIndeterminateLength |
228                 CborPrettyIndicateOverlongNumbers;
229 
230     parsed->clear();
231     return cbor_value_to_pretty_stream(qstring_printf, parsed, it, flags);
232 }
233 
parseOneChunk(CborValue * it,QString * parsed)234 CborError parseOneChunk(CborValue *it, QString *parsed)
235 {
236     CborError err;
237     CborType ourType = cbor_value_get_type(it);
238     if (ourType == CborByteStringType) {
239         const uint8_t *bytes;
240         size_t len;
241         err = cbor_value_get_byte_string_chunk(it, &bytes, &len, it);
242         if (err)
243             return err;
244 
245         if (bytes)
246             *parsed = QString::fromLatin1("h'" +
247                                           QByteArray::fromRawData(reinterpret_cast<const char *>(bytes), len).toHex() +
248                                           '\'');
249     } else if (ourType == CborTextStringType) {
250         const char *text;
251         size_t len;
252         err = cbor_value_get_text_string_chunk(it, &text, &len, it);
253         if (err)
254             return err;
255 
256         if (text)
257             *parsed = '"' + QString::fromUtf8(text, len) + '"';
258     } else {
259         Q_ASSERT(false);
260     }
261     return err;
262 }
263 
initParserEmpty()264 void tst_Parser::initParserEmpty()
265 {
266     CborParser parser;
267     CborValue first;
268     CborError err = cbor_parser_init((const quint8 *)"", 0, 0, &parser, &first);
269     QCOMPARE(err, CborErrorUnexpectedEOF);
270 }
271 
272 bool compareFailed = true;
compareOne_real(const QByteArray & data,const QString & expected,int line,int n=-1)273 void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1)
274 {
275     compareFailed = true;
276     ParserWrapper w;
277     CborError err = w.init(data);
278     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
279 
280     if (cbor_value_get_type(&w.first) == CborArrayType) {
281         size_t len;
282         if (n >= 0) {
283             QVERIFY(cbor_value_is_length_known(&w.first));
284             QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborNoError);
285             QCOMPARE(len, size_t(len));
286         } else {
287             QVERIFY(!cbor_value_is_length_known(&w.first));
288             QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborErrorUnknownLength);
289         }
290     } else if (cbor_value_get_type(&w.first) == CborMapType) {
291         size_t len;
292         if (n >= 0) {
293             QVERIFY(cbor_value_is_length_known(&w.first));
294             QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborNoError);
295             QCOMPARE(len, size_t(len));
296         } else {
297             QVERIFY(!cbor_value_is_length_known(&w.first));
298             QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborErrorUnknownLength);
299         }
300     } else if (cbor_value_is_text_string(&w.first) || cbor_value_is_byte_string(&w.first)) {
301         size_t len;
302         QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError);
303         if (cbor_value_is_length_known(&w.first)) {
304             size_t len2;
305             QCOMPARE(cbor_value_get_string_length(&w.first, &len2), CborNoError);
306             QCOMPARE(len2, len);
307         } else {
308             QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborErrorUnknownLength);
309         }
310     }
311 
312     CborError err2 = cbor_value_validate_basic(&w.first);
313 
314     QString decoded;
315     err = parseOne(&w.first, &decoded);
316     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
317                    "\"; decoded stream:\n" + decoded.toLatin1());
318     QCOMPARE(decoded, expected);
319 
320     // check that the errors are the same
321     QCOMPARE(err2, err);
322 
323     // check that we consumed everything
324     QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end());
325 
326     compareFailed = false;
327 }
328 #define compareOne(data, expected) compareOne_real(data, expected, __LINE__)
329 #define compareOneSize(n, data, expected) compareOne_real(data, expected, __LINE__, n)
330 
331 #include "data.cpp"
332 
integers_data()333 void tst_Parser::integers_data()
334 {
335     addIntegers();
336 }
337 
integers()338 void tst_Parser::integers()
339 {
340     QFETCH(QByteArray, data);
341     QFETCH(bool, isNegative);
342     QFETCH(quint64, expectedRaw);
343     QFETCH(qint64, expectedValue);
344     QFETCH(bool, inInt64Range);
345 
346     ParserWrapper w;
347     CborError err = w.init(data);
348     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
349     QVERIFY(cbor_value_is_integer(&w.first));
350 
351     uint64_t raw;
352     cbor_value_get_raw_integer(&w.first, &raw);
353     QCOMPARE(quint64(raw), expectedRaw);
354 
355     if (isNegative) {
356         QVERIFY(cbor_value_is_negative_integer(&w.first));
357         QVERIFY(!cbor_value_is_unsigned_integer(&w.first));
358     } else {
359         QVERIFY(!cbor_value_is_negative_integer(&w.first));
360         QVERIFY(cbor_value_is_unsigned_integer(&w.first));
361     }
362 
363     int64_t value;
364     if (inInt64Range) {
365         cbor_value_get_int64(&w.first, &value);
366         QCOMPARE(qint64(value), expectedValue);
367     }
368 
369     err = cbor_value_get_int64_checked(&w.first, &value);
370     QCOMPARE(err, inInt64Range ? CborNoError : CborErrorDataTooLarge);
371 
372     int ivalue;
373     bool inIntRange = inInt64Range && (expectedValue == int(expectedValue));
374     err = cbor_value_get_int_checked(&w.first, &ivalue);
375     QCOMPARE(err, inIntRange ? CborNoError : CborErrorDataTooLarge);
376 }
377 
addHalfFloat()378 static void addHalfFloat()
379 {
380     QTest::addColumn<QByteArray>("data");
381     QTest::addColumn<unsigned>("expectedRaw");
382     QTest::addColumn<double>("expectedValue");
383 
384     QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0;
385     QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0;
386 
387     QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10);
388     QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10);
389 
390     QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10));
391     QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10));
392 
393     QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14);
394     QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14);
395 
396     QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0;
397     QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0;
398 
399     QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5;
400     QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5;
401 
402     QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10));
403     QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10));
404 
405     QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << double(INFINITY);
406     QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << double(-INFINITY);
407 
408     QTest::newRow("nan") << raw("\x7c\x01") << 0x7c01U << double(NAN);
409     QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << double(NAN);
410     QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << double(NAN);
411     QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << double(NAN);
412 }
413 
halfFloat_data()414 void tst_Parser::halfFloat_data()
415 {
416     addHalfFloat();
417 }
418 
halfFloat()419 void tst_Parser::halfFloat()
420 {
421     QFETCH(QByteArray, data);
422     QFETCH(unsigned, expectedRaw);
423     QFETCH(double, expectedValue);
424 
425     CborParser parser;
426     CborValue first;
427 
428     data.prepend('\xf9');
429 
430     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
431     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
432     QVERIFY(cbor_value_is_half_float(&first));
433 
434     uint16_t raw;
435     cbor_value_get_half_float(&first, &raw);
436     QCOMPARE(raw, uint16_t(expectedRaw));
437 
438     float value;
439     cbor_value_get_half_float_as_float(&first, &value);
440 
441     const double epsilon = ldexp(1.0, -25);
442 
443     if (qIsNaN(expectedValue)) {
444         QVERIFY(qIsNaN(value));
445     } else if (qIsInf(expectedValue)) {
446         QVERIFY(value == (float)expectedValue);
447     } else {
448         QVERIFY(qAbs(value - (float)expectedValue) < epsilon);
449     }
450 }
451 
fixed_data()452 void tst_Parser::fixed_data()
453 {
454     addColumns();
455     addFixedData();
456 }
457 
fixed()458 void tst_Parser::fixed()
459 {
460     QFETCH(QByteArray, data);
461     QFETCH(QString, expected);
462 
463     compareOne(data, expected);
464 }
465 
strings_data()466 void tst_Parser::strings_data()
467 {
468     addColumns();
469     addStringsData();
470 }
471 
tags_data()472 void tst_Parser::tags_data()
473 {
474     addColumns();
475     addTagsData();
476 }
477 
tagTags()478 void tst_Parser::tagTags()
479 {
480     QFETCH(QByteArray, data);
481     QFETCH(QString, expected);
482 
483     compareOne("\xd9\xd9\xf7" + data, "55799(" + expected + ')');
484     if (!compareFailed)
485         compareOne("\xd9\xd9\xf7" "\xd9\xd9\xf7" + data, "55799(55799(" + expected + "))");
486 }
487 
emptyContainers_data()488 void tst_Parser::emptyContainers_data()
489 {
490     addColumns();
491     addEmptyContainersData();
492 }
493 
emptyContainers()494 void tst_Parser::emptyContainers()
495 {
496     QFETCH(QByteArray, data);
497     QFETCH(QString, expected);
498     QFETCH(int, n);
499 
500     compareOneSize(n, data, expected);
501 }
502 
arrays_data()503 void tst_Parser::arrays_data()
504 {
505     addColumns();
506     addFixedData();
507     addStringsData();
508     addTagsData();
509 }
510 
arrays()511 void tst_Parser::arrays()
512 {
513     QFETCH(QByteArray, data);
514     QFETCH(QString, expected);
515 
516     compareOneSize(1, "\x81" + data, '[' + expected + ']');
517     if (compareFailed) return;
518 
519     compareOneSize(2, "\x82" + data + data, '[' + expected + ", " + expected + ']');
520     if (compareFailed) return;
521 
522     // overlong length
523     compareOneSize(1, "\x98\1" + data, "[_0 " + expected + ']');
524     if (compareFailed) return;
525     compareOneSize(1, raw("\x99\0\1") + data, "[_1 " + expected + ']');
526     if (compareFailed) return;
527     compareOneSize(1, raw("\x9a\0\0\0\1") + data, "[_2 " + expected + ']');
528     if (compareFailed) return;
529     compareOneSize(1, raw("\x9b\0\0\0\0\0\0\0\1") + data, "[_3 " + expected + ']');
530     if (compareFailed) return;
531 
532     // medium-sized array: 32 elements (1 << 5)
533     expected += ", ";
534     for (int i = 0; i < 5; ++i) {
535         data += data;
536         expected += expected;
537     }
538     expected.chop(2);   // remove the last ", "
539     compareOneSize(32, "\x98\x20" + data, '[' + expected + ']');
540     if (compareFailed) return;
541 
542     // large array: 256 elements (32 << 3)
543     expected += ", ";
544     for (int i = 0; i < 3; ++i) {
545         data += data;
546         expected += expected;
547     }
548     expected.chop(2);   // remove the last ", "
549     compareOneSize(256, raw("\x99\1\0") + data, '[' + expected + ']');
550     if (compareFailed) return;
551 }
552 
undefLengthArrays()553 void tst_Parser::undefLengthArrays()
554 {
555     QFETCH(QByteArray, data);
556     QFETCH(QString, expected);
557 
558     compareOne("\x9f" + data + "\xff", "[_ " + expected + ']');
559     if (compareFailed) return;
560 
561     compareOne("\x9f" + data + data + "\xff", "[_ " + expected + ", " + expected + ']');
562 }
563 
nestedArrays()564 void tst_Parser::nestedArrays()
565 {
566     QFETCH(QByteArray, data);
567     QFETCH(QString, expected);
568 
569     compareOneSize(1, "\x81\x81" + data, "[[" + expected + "]]");
570     if (compareFailed) return;
571 
572     compareOneSize(1, "\x81\x81\x81" + data, "[[[" + expected + "]]]");
573     if (compareFailed) return;
574 
575     compareOneSize(1, "\x81\x82" + data + data, "[[" + expected + ", " + expected + "]]");
576     if (compareFailed) return;
577 
578     compareOneSize(2, "\x82\x81" + data + data, "[[" + expected + "], " + expected + "]");
579     if (compareFailed) return;
580 
581     compareOneSize(2, "\x82\x81" + data + '\x81' + data, "[[" + expected + "], [" + expected + "]]");
582     if (compareFailed) return;
583 
584     // undefined length
585     compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\xff", "[_ [_ " + expected + ", " + expected + "]]");
586     if (compareFailed) return;
587 
588     compareOneSize(-1, "\x9f\x9f" + data + "\xff\x9f" + data + "\xff\xff", "[_ [_ " + expected + "], [_ " + expected + "]]");
589     if (compareFailed) return;
590 
591     compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\x9f" + data + "\xff\xff",
592                "[_ [_ " + expected + ", " + expected + "], [_ " + expected + "]]");
593     if (compareFailed) return;
594 
595     // mix them
596     compareOneSize(1, "\x81\x9f" + data + "\xff", "[[_ " + expected + "]]");
597     if (compareFailed) return;
598 
599     compareOneSize(-1, "\x9f\x81" + data + "\xff", "[_ [" + expected + "]]");
600 }
601 
maps_data()602 void tst_Parser::maps_data()
603 {
604     arrays_data();
605 }
606 
maps()607 void tst_Parser::maps()
608 {
609     QFETCH(QByteArray, data);
610     QFETCH(QString, expected);
611 
612     // integer key
613     compareOneSize(1, "\xa1\1" + data, "{1: " + expected + '}');
614     if (compareFailed) return;
615 
616     // string key
617     compareOneSize(1, "\xa1\x65" "Hello" + data, "{\"Hello\": " + expected + '}');
618     if (compareFailed) return;
619 
620     // map to self
621     compareOneSize(1, "\xa1" + data + data, '{' + expected + ": " + expected + '}');
622     if (compareFailed) return;
623 
624     // two integer keys
625     compareOneSize(2, "\xa2\1" + data + "\2" + data, "{1: " + expected + ", 2: " + expected + '}');
626     if (compareFailed) return;
627 
628     // OneSize integer and OneSize string key
629     compareOneSize(2, "\xa2\1" + data + "\x65" "Hello" + data, "{1: " + expected + ", \"Hello\": " + expected + '}');
630     if (compareFailed) return;
631 }
632 
undefLengthMaps()633 void tst_Parser::undefLengthMaps()
634 {
635     QFETCH(QByteArray, data);
636     QFETCH(QString, expected);
637 
638     // integer key
639     compareOne("\xbf\1" + data + '\xff', "{_ 1: " + expected + '}');
640     if (compareFailed) return;
641 
642     compareOne("\xbf\1" + data + '\2' + data + '\xff', "{_ 1: " + expected + ", 2: " + expected + '}');
643     if (compareFailed) return;
644 
645     compareOne("\xbf\1" + data + "\x65Hello" + data + '\xff', "{_ 1: " + expected + ", \"Hello\": " + expected + '}');
646     if (compareFailed) return;
647 
648     compareOne("\xbf\x65Hello" + data + '\1' + data + '\xff', "{_ \"Hello\": " + expected + ", 1: " + expected + '}');
649 }
650 
nestedMaps()651 void tst_Parser::nestedMaps()
652 {
653     QFETCH(QByteArray, data);
654     QFETCH(QString, expected);
655 
656     // nested maps as values
657     compareOneSize(1, "\xa1\1\xa1\2" + data, "{1: {2: " + expected + "}}");
658     if (compareFailed) return;
659 
660     compareOneSize(1, "\xa1\x65Hello\xa1\2" + data, "{\"Hello\": {2: " + expected + "}}");
661     if (compareFailed) return;
662 
663     compareOneSize(1, "\xa1\1\xa2\2" + data + '\x20' + data, "{1: {2: " + expected + ", -1: " + expected + "}}");
664     if (compareFailed) return;
665 
666     compareOneSize(2, "\xa2\1\xa1\2" + data + "\2\xa1\x20" + data, "{1: {2: " + expected + "}, 2: {-1: " + expected + "}}");
667     if (compareFailed) return;
668 
669     // nested maps as keys
670     compareOneSize(1, "\xa1\xa1\xf4" + data + "\xf5", "{{false: " + expected + "}: true}");
671     if (compareFailed) return;
672 
673     compareOneSize(1, "\xa1\xa1" + data + data + "\xa1" + data + data,
674                "{{" + expected + ": " + expected + "}: {" + expected + ": " + expected + "}}");
675     if (compareFailed) return;
676 
677     // undefined length
678     compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\xff", "{_ 1: {_ 2: " + expected + "}}");
679     if (compareFailed) return;
680 
681     compareOneSize(-1, "\xbf\1\xbf\2" + data + '\x20' + data + "\xff\xff", "{_ 1: {_ 2: " + expected + ", -1: " + expected + "}}");
682     if (compareFailed) return;
683 
684     compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\2\xbf\x20" + data + "\xff\xff",
685                "{_ 1: {_ 2: " + expected + "}, 2: {_ -1: " + expected + "}}");
686     if (compareFailed) return;
687 
688     compareOneSize(-1, "\xbf\xbf" + data + data + "\xff\xbf" + data + data + "\xff\xff",
689                "{_ {_ " + expected + ": " + expected + "}: {_ " + expected + ": " + expected + "}}");
690     if (compareFailed) return;
691 
692     // mix them
693     compareOneSize(1, "\xa1\1\xbf\2" + data + "\xff", "{1: {_ 2: " + expected + "}}");
694     if (compareFailed) return;
695 
696     compareOneSize(-1, "\xbf\1\xa1\2" + data + "\xff", "{_ 1: {2: " + expected + "}}");
697     if (compareFailed) return;
698 }
699 
mapMixed_data()700 void tst_Parser::mapMixed_data()
701 {
702     addColumns();
703     addMapMixedData();
704 }
705 
mapsAndArrays()706 void tst_Parser::mapsAndArrays()
707 {
708     QFETCH(QByteArray, data);
709     QFETCH(QString, expected);
710 
711     // arrays of maps
712     compareOneSize(1, "\x81\xa1\1" + data, "[{1: " + expected + "}]");
713     if (compareFailed) return;
714 
715     compareOneSize(2, "\x82\xa1\1" + data + "\xa1\2" + data, "[{1: " + expected + "}, {2: " + expected + "}]");
716     if (compareFailed) return;
717 
718     compareOneSize(1, "\x81\xa2\1" + data + "\2" + data, "[{1: " + expected + ", 2: " + expected + "}]");
719     if (compareFailed) return;
720 
721     compareOneSize(-1, "\x9f\xa1\1" + data + "\xff", "[_ {1: " + expected + "}]");
722     if (compareFailed) return;
723 
724     compareOneSize(1, "\x81\xbf\1" + data + "\xff", "[{_ 1: " + expected + "}]");
725     if (compareFailed) return;
726 
727     compareOneSize(-1, "\x9f\xbf\1" + data + "\xff\xff", "[_ {_ 1: " + expected + "}]");
728     if (compareFailed) return;
729 
730     // maps of arrays
731     compareOneSize(1, "\xa1\1\x81" + data, "{1: [" + expected + "]}");
732     if (compareFailed) return;
733 
734     compareOneSize(1, "\xa1\1\x82" + data + data, "{1: [" + expected + ", " + expected + "]}");
735     if (compareFailed) return;
736 
737     compareOneSize(2, "\xa2\1\x81" + data + "\x65Hello\x81" + data, "{1: [" + expected + "], \"Hello\": [" + expected + "]}");
738     if (compareFailed) return;
739 
740     compareOneSize(1, "\xa1\1\x9f" + data + "\xff", "{1: [_ " + expected + "]}");
741     if (compareFailed) return;
742 
743     compareOneSize(1, "\xa1\1\x9f" + data + data + "\xff", "{1: [_ " + expected + ", " + expected + "]}");
744     if (compareFailed) return;
745 
746     compareOneSize(-1, "\xbf\1\x81" + data + "\xff", "{_ 1: [" + expected + "]}");
747     if (compareFailed) return;
748 
749     compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\xff", "{_ 1: [_ " + expected + "]}");
750     if (compareFailed) return;
751 
752     compareOneSize(-1, "\xbf\1\x9f" + data + data + "\xff\xff", "{_ 1: [_ " + expected + ", " + expected + "]}");
753     if (compareFailed) return;
754 
755     // mixed with indeterminate length strings
756     compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\x65Hello\xbf" + data + "\x7f\xff\xff\xff",
757                    "{_ 1: [_ " + expected + "], \"Hello\": {_ " + expected + ": (_ )}}");
758 }
759 
760 struct Input {
761     QByteArray data;
762     int consumed;
763 };
764 
765 static const CborParserOperations byteArrayOps = {
__anon0518a6960102() 766     /* can_read_bytes = */ [](void *token, size_t len) {
767         auto input = static_cast<Input *>(token);
768         return input->data.size() - input->consumed >= int(len);
769     },
__anon0518a6960202() 770     /* read_bytes = */ [](void *token, void *dst, size_t offset, size_t len) {
771         auto input = static_cast<Input *>(token);
772         return memcpy(dst, input->data.constData() + input->consumed + offset, len);
773     },
__anon0518a6960302() 774     /* advance_bytes = */ [](void *token, size_t len) {
775         auto input = static_cast<Input *>(token);
776         input->consumed += int(len);
777     },
__anon0518a6960402() 778     /* transfer_string = */ [](void *token, const void **userptr, size_t offset, size_t len) {
779         // ###
780         auto input = static_cast<Input *>(token);
781         if (input->data.size() - input->consumed < int(len + offset))
782             return CborErrorUnexpectedEOF;
783         input->consumed += int(offset);
784         *userptr = input->data.constData() + input->consumed;
785         input->consumed += int(len);
786         return CborNoError;
787     }
788 };
789 
readerApi()790 void tst_Parser::readerApi()
791 {
792     QFETCH(QByteArray, data);
793     QFETCH(QString, expected);
794 
795     Input input = { data, 0 };
796 
797     CborParser parser;
798     CborValue first;
799     CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &input);
800     QCOMPARE(err, CborNoError);
801 
802     QString decoded;
803     err = parseOne(&first, &decoded);
804     QCOMPARE(err, CborNoError);
805     QCOMPARE(decoded, expected);
806 
807     // check we consumed everything
808     QCOMPARE(input.consumed, data.size());
809 }
810 
reparse_data()811 void tst_Parser::reparse_data()
812 {
813     // only one-item rows
814     addColumns();
815     addFixedData();
816 }
817 
reparse()818 void tst_Parser::reparse()
819 {
820     QFETCH(QByteArray, data);
821     QFETCH(QString, expected);
822 
823     Input input = { QByteArray(), 0 };
824     CborParser parser;
825     CborValue first;
826     CborError err = cbor_parser_init_reader(&byteArrayOps, &parser, &first, &input);
827     QCOMPARE(err, CborErrorUnexpectedEOF);
828 
829     for (int i = 0; i < data.size(); ++i) {
830         input.data = data.left(i);
831         err = cbor_value_reparse(&first);
832         if (err != CborErrorUnexpectedEOF)
833             qDebug() << "At" << i;
834         QCOMPARE(err, CborErrorUnexpectedEOF);
835         QCOMPARE(input.consumed, 0);
836     }
837 
838     // now it should work
839     input.data = data;
840     err = cbor_value_reparse(&first);
841     QCOMPARE(err, CborNoError);
842 
843     QString decoded;
844     err = parseOne(&first, &decoded);
845     QCOMPARE(err, CborNoError);
846     QCOMPARE(decoded, expected);
847 
848     // check we consumed everything
849     QCOMPARE(input.consumed, data.size());
850 }
851 
chunkedString_data()852 void tst_Parser::chunkedString_data()
853 {
854     addChunkedStringData();
855 }
856 
chunkedStringTest(const QByteArray & data,const QString & concatenated,QStringList & chunks,CborType ourType)857 static void chunkedStringTest(const QByteArray &data, const QString &concatenated,
858                               QStringList &chunks, CborType ourType)
859 {
860     ParserWrapper w;
861     CborError err = w.init(data);
862     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
863 
864     CborValue value;
865     QVERIFY(cbor_value_is_array(&w.first));
866     err = cbor_value_enter_container(&w.first, &value);
867     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
868     QVERIFY(cbor_value_is_byte_string(&value) || cbor_value_is_text_string(&value));
869 
870     CborValue copy = value;
871 
872     err = cbor_value_begin_string_iteration(&value);
873     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
874     forever {
875         QString decoded;
876         err = parseOneChunk(&value, &decoded);
877         if (err == CborErrorNoMoreStringChunks)
878             break;          // last chunk
879 
880         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
881 
882         QVERIFY2(!chunks.isEmpty(), "Too many chunks");
883         QString expected = chunks.takeFirst();
884         QCOMPARE(decoded, expected);
885     }
886 
887     err = cbor_value_finish_string_iteration(&value);
888     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
889     QVERIFY2(chunks.isEmpty(), "Too few chunks");
890 
891     // compare to the concatenated data
892     {
893         size_t n;
894         err = cbor_value_calculate_string_length(&copy, &n);
895         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
896 
897         QByteArray buffer(n, Qt::Uninitialized);
898         QString formatted;
899         if (cbor_value_is_byte_string(&copy)) {
900             err = cbor_value_copy_byte_string(&copy, (uint8_t *)buffer.data(), &n, nullptr);
901             QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
902             QCOMPARE(int(n), buffer.size());
903 
904             formatted = QString::fromLatin1("h'" + buffer.toHex() + '\'');
905         } else {
906             err = cbor_value_copy_text_string(&copy, buffer.data(), &n, nullptr);
907             QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
908             QCOMPARE(int(n), buffer.size());
909 
910             formatted = '"' + QString::fromUtf8(buffer.data(), n) + '"';
911         }
912         QCOMPARE(formatted, concatenated);
913     }
914 
915     // confirm that the extra string we appended is still here
916     QVERIFY(!cbor_value_at_end(&value));
917     QCOMPARE(cbor_value_get_type(&value), ourType);
918     size_t len;
919     err = cbor_value_get_string_length(&value, &len);
920     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
921     QCOMPARE(len, size_t(0));
922 
923     err = cbor_value_advance(&value);
924     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
925 
926     // confirm EOF
927     QVERIFY(cbor_value_at_end(&value));
928 
929     err = cbor_value_leave_container(&w.first, &value);
930     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
931     QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end());
932 }
933 
chunkedString()934 void tst_Parser::chunkedString()
935 {
936     QFETCH(QByteArray, data);
937     QFETCH(QString, concatenated);
938     QFETCH(QStringList, chunks);
939 
940     // Make this an array of two entries, with the second an empty byte or text string
941     CborType ourType = CborType(data.at(0) & 0xe0);
942     data.prepend(char(0x82));
943     data.append(ourType);
944 
945     chunkedStringTest(data, concatenated, chunks, ourType);
946 }
947 
chunkedStringInUndefArray()948 void tst_Parser::chunkedStringInUndefArray()
949 {
950     QFETCH(QByteArray, data);
951     QFETCH(QString, concatenated);
952     QFETCH(QStringList, chunks);
953 
954     // Make this an array of undefined length entries, with the second entry an empty byte or text string
955     CborType ourType = CborType(data.at(0) & 0xe0);
956     data.prepend(char(0x9f));
957     data.append(ourType);
958     data.append(char(0xff));
959 
960     chunkedStringTest(data, concatenated, chunks, ourType);
961 }
962 
stringLength_data()963 void tst_Parser::stringLength_data()
964 {
965     QTest::addColumn<QByteArray>("data");
966     QTest::addColumn<int>("expected");
967 
968     QTest::newRow("emptybytestring") << raw("\x40") << 0;
969     QTest::newRow("bytestring1") << raw("\x41 ") << 1;
970     QTest::newRow("bytestring1-nul") << raw("\x41\0") << 1;
971     QTest::newRow("bytestring5") << raw("\x45Hello") << 5;
972     QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234") << 24;
973     QTest::newRow("bytestring256") << raw("\x59\1\0") + QByteArray(256, '3') << 256;
974 
975     // text strings
976     QTest::newRow("emptytextstring") << raw("\x60") << 0;
977     QTest::newRow("textstring1") << raw("\x61 ") << 1;
978     QTest::newRow("textstring1-nul") << raw("\x61\0") << 1;
979     QTest::newRow("textstring5") << raw("\x65Hello") << 5;
980     QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234") << 24;
981     QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3') << 256;
982 
983     // strings with overlong length
984     QTest::newRow("emptybytestring*1") << raw("\x58\x00") << 0;
985     QTest::newRow("emptytextstring*1") << raw("\x78\x00") << 0;
986     QTest::newRow("emptybytestring*2") << raw("\x59\x00\x00") << 0;
987     QTest::newRow("emptytextstring*2") << raw("\x79\x00\x00") << 0;
988     QTest::newRow("emptybytestring*4") << raw("\x5a\0\0\0\0") << 0;
989     QTest::newRow("emptytextstring*4") << raw("\x7a\0\0\0\0") << 0;
990     QTest::newRow("emptybytestring*8") << raw("\x5b\0\0\0\0\0\0\0\0") << 0;
991     QTest::newRow("emptytextstring*8") << raw("\x7b\0\0\0\0\0\0\0\0") << 0;
992     QTest::newRow("bytestring5*1") << raw("\x58\x05Hello") << 5;
993     QTest::newRow("textstring5*1") << raw("\x78\x05Hello") << 5;
994     QTest::newRow("bytestring5*2") << raw("\x59\0\5Hello") << 5;
995     QTest::newRow("textstring5*2") << raw("\x79\0\x05Hello") << 5;
996     QTest::newRow("bytestring5*4") << raw("\x5a\0\0\0\5Hello") << 5;
997     QTest::newRow("textstring5*4") << raw("\x7a\0\0\0\x05Hello") << 5;
998     QTest::newRow("bytestring5*8") << raw("\x5b\0\0\0\0\0\0\0\5Hello") << 5;
999     QTest::newRow("textstring5*8") << raw("\x7b\0\0\0\0\0\0\0\x05Hello") << 5;
1000 
1001     // strings with undefined length
1002     QTest::newRow("_emptybytestring") << raw("\x5f\xff") << 0;
1003     QTest::newRow("_emptytextstring") << raw("\x7f\xff") << 0;
1004     QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << 0;
1005     QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << 0;
1006     QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << 0;
1007     QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << 0;
1008     QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << 5;
1009     QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << 5;
1010     QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << 5;
1011     QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << 5;
1012     QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << 5;
1013     QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << 5;
1014 }
1015 
stringLength()1016 void tst_Parser::stringLength()
1017 {
1018     QFETCH(QByteArray, data);
1019     QFETCH(int, expected);
1020 
1021     ParserWrapper w;
1022     CborError err = w.init(data);
1023     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1024 
1025     size_t result;
1026     err = cbor_value_calculate_string_length(&w.first, &result);
1027     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1028     QCOMPARE(result, size_t(expected));
1029 
1030     if (cbor_value_is_length_known(&w.first)) {
1031         QCOMPARE(cbor_value_get_string_length(&w.first, &result), CborNoError);
1032         QCOMPARE(result, size_t(expected));
1033     }
1034 
1035 }
1036 
stringCompare_data()1037 void tst_Parser::stringCompare_data()
1038 {
1039     QTest::addColumn<QByteArray>("data");
1040     QTest::addColumn<QString>("string");
1041     QTest::addColumn<bool>("expected");
1042 
1043     // compare empty to empty
1044     QTest::newRow("empty-empty") << raw("\x60") << QString() << true;
1045     QTest::newRow("_empty-empty") << raw("\x7f\xff") << QString() << true;
1046     QTest::newRow("_empty*1-empty") << raw("\x7f\x60\xff") << QString() << true;
1047     QTest::newRow("_empty*2-empty") << raw("\x7f\x60\x60\xff") << QString() << true;
1048 
1049     // compare empty to non-empty
1050     QTest::newRow("empty-nonempty") << raw("\x60") << "Hello" << false;
1051     QTest::newRow("_empty-nonempty") << raw("\x7f\xff") << "Hello" << false;
1052     QTest::newRow("_empty*1-nonempty") << raw("\x7f\x60\xff") << "Hello" << false;
1053     QTest::newRow("_empty*2-nonempty") << raw("\x7f\x60\x60\xff") << "Hello" << false;
1054 
1055     // compare same strings
1056     QTest::newRow("same-short-short") << raw("\x65Hello") << "Hello" << true;
1057     QTest::newRow("same-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello" << true;
1058     QTest::newRow("same-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello" << true;
1059     QTest::newRow("same-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello" << true;
1060     QTest::newRow("same-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello" << true;
1061     QTest::newRow("same-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
1062                                     << "Good morning, good afternoon and goodnight" << true;
1063     QTest::newRow("same-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
1064                                        << "Good morning, good afternoon and goodnight" << true;
1065     QTest::newRow("same-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
1066                                        << "Good morning, good afternoon and goodnight" << true;
1067 
1068     // compare different strings (same length)
1069     QTest::newRow("diff-same-length-short-short") << raw("\x65Hello") << "World" << false;
1070     QTest::newRow("diff-same-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "World" << false;
1071     QTest::newRow("diff-same-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "World" << false;
1072     QTest::newRow("diff-same-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "World" << false;
1073     QTest::newRow("diff-same-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "World" << false;
1074     QTest::newRow("diff-same-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
1075                                                 << "Good morning, good afternoon and goodnight, world" << false;
1076     QTest::newRow("diff-same-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
1077                                                    << "Good morning, good afternoon and goodnight, world" << false;
1078     QTest::newRow("diff-same-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
1079                                                    << "Good morning, good afternoon and goodnight, world" << false;
1080 
1081     // compare different strings (different length)
1082     QTest::newRow("diff-diff-length-short-short") << raw("\x65Hello") << "Hello World" << false;
1083     QTest::newRow("diff-diff-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello World" << false;
1084     QTest::newRow("diff-diff-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello World" << false;
1085     QTest::newRow("diff-diff-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello World" << false;
1086     QTest::newRow("diff-diff-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello World" << false;
1087     QTest::newRow("diff-diff-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
1088                                                 << "Good morning, good afternoon and goodnight World" << false;
1089     QTest::newRow("diff-diff-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
1090                                                    << "Good morning, good afternoon and goodnight World" << false;
1091     QTest::newRow("diff-diff-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
1092                                                    << "Good morning, good afternoon and goodnight World" << false;
1093 
1094     // compare against non-strings
1095     QTest::newRow("unsigned") << raw("\0") << "0" << false;
1096     QTest::newRow("negative") << raw("\x20") << "-1" << false;
1097     QTest::newRow("emptybytestring") << raw("\x40") << "" << false;
1098     QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "" << false;
1099     QTest::newRow("shortbytestring") << raw("\x45Hello") << "Hello" << false;
1100     QTest::newRow("longbytestring") << raw("\x58\x2aGood morning, good afternoon and goodnight")
1101                                     << "Good morning, good afternoon and goodnight" << false;
1102     QTest::newRow("emptyarray") << raw("\x80") << "" << false;
1103     QTest::newRow("emptymap") << raw("\xa0") << "" << false;
1104     QTest::newRow("array") << raw("\x81\x65Hello") << "Hello" << false;
1105     QTest::newRow("map") << raw("\xa1\x65Hello\x65World") << "Hello World" << false;
1106     QTest::newRow("false") << raw("\xf4") << "false" << false;
1107     QTest::newRow("true") << raw("\xf5") << "true" << false;
1108     QTest::newRow("null") << raw("\xf6") << "null" << false;
1109 }
1110 
compareOneString(const QByteArray & data,const QString & string,bool expected,int line)1111 void compareOneString(const QByteArray &data, const QString &string, bool expected, int line)
1112 {
1113     compareFailed = true;
1114 
1115     ParserWrapper w;
1116     CborError err = w.init(data);
1117     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
1118 
1119     bool result;
1120     QByteArray bastring = string.toUtf8();
1121     err = cbor_value_text_string_equals(&w.first, bastring.constData(), &result);
1122     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
1123     QCOMPARE(result, expected);
1124 
1125     if (expected) {
1126         size_t len;
1127         cbor_value_skip_tag(&w.first);
1128         if (cbor_value_is_length_known(&w.first)) {
1129             QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborNoError);
1130             QCOMPARE(int(len), bastring.size());
1131         }
1132         QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError);
1133         QCOMPARE(int(len), bastring.size());
1134     }
1135 
1136     compareFailed = false;
1137 }
1138 #define compareOneString(data, string, expected) compareOneString(data, string, expected, __LINE__)
1139 
stringCompare()1140 void tst_Parser::stringCompare()
1141 {
1142     QFETCH(QByteArray, data);
1143     QFETCH(QString, string);
1144     QFETCH(bool, expected);
1145 
1146     compareOneString(data, string, expected);
1147     if (compareFailed) return;
1148 
1149     // tag it
1150     compareOneString("\xc1" + data, string, expected);
1151     if (compareFailed) return;
1152 
1153     compareOneString("\xc1\xc2" + data, string, expected);
1154 }
1155 
mapFind_data()1156 void tst_Parser::mapFind_data()
1157 {
1158     // Rules:
1159     //  we are searching for string "needle"
1160     //  if present, the value should be the string "haystack" (with tag 42)
1161 
1162     QTest::addColumn<QByteArray>("data");
1163     QTest::addColumn<bool>("expected");
1164 
1165     QTest::newRow("emptymap") << raw("\xa0") << false;
1166     QTest::newRow("_emptymap") << raw("\xbf\xff") << false;
1167 
1168     // maps not containing our items
1169     QTest::newRow("absent-unsigned-unsigned") << raw("\xa1\0\0") << false;
1170     QTest::newRow("absent-taggedunsigned-unsigned") << raw("\xa1\xc0\0\0") << false;
1171     QTest::newRow("absent-unsigned-taggedunsigned") << raw("\xa1\0\xc0\0") << false;
1172     QTest::newRow("absent-taggedunsigned-taggedunsigned") << raw("\xa1\xc0\0\xc0\0") << false;
1173     QTest::newRow("absent-string-unsigned") << raw("\xa1\x68haystack\0") << false;
1174     QTest::newRow("absent-taggedstring-unsigned") << raw("\xa1\xc0\x68haystack\0") << false;
1175     QTest::newRow("absent-string-taggedunsigned") << raw("\xa1\x68haystack\xc0\0") << false;
1176     QTest::newRow("absent-taggedstring-taggedunsigned") << raw("\xa1\xc0\x68haystack\xc0\0") << false;
1177     QTest::newRow("absent-string-string") << raw("\xa1\x68haystack\x66needle") << false;
1178     QTest::newRow("absent-string-taggedstring") << raw("\xa1\x68haystack\xc0\x66needle") << false;
1179     QTest::newRow("absent-taggedstring-string") << raw("\xa1\xc0\x68haystack\x66needle") << false;
1180     QTest::newRow("absent-string-taggedstring") << raw("\xa1\xc0\x68haystack\xc0\x66needle") << false;
1181 
1182     QTest::newRow("absent-string-emptyarray") << raw("\xa1\x68haystack\x80") << false;
1183     QTest::newRow("absent-string-_emptyarray") << raw("\xa1\x68haystack\x9f\xff") << false;
1184     QTest::newRow("absent-string-array1") << raw("\xa1\x68haystack\x81\0") << false;
1185     QTest::newRow("absent-string-array2") << raw("\xa1\x68haystack\x85\0\1\2\3\4") << false;
1186     QTest::newRow("absent-string-array3") << raw("\xa1\x68haystack\x85\x63one\x63two\x65three\x64""four\x64""five") << false;
1187 
1188     QTest::newRow("absent-string-emptymap") << raw("\xa1\x68haystack\xa0") << false;
1189     QTest::newRow("absent-string-_emptymap") << raw("\xa1\x68haystack\xbf\xff") << false;
1190     QTest::newRow("absent-string-map") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle") << false;
1191     QTest::newRow("absent-string-map2") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle\61z\62yx") << false;
1192 
1193     // maps containing our items
1194     QTest::newRow("alone") << raw("\xa1\x66needle\xd8\x2a\x68haystack") << true;
1195     QTest::newRow("tagged") << raw("\xa1\xc1\x66needle\xd8\x2a\x68haystack") << true;
1196     QTest::newRow("doubletagged") << raw("\xa1\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true;
1197     QTest::newRow("chunked") << raw("\xa1\x7f\x66needle\xff\xd8\x2a\x68haystack") << true;
1198     QTest::newRow("chunked*2") << raw("\xa1\x7f\x60\x66needle\xff\xd8\x2a\x68haystack") << true;
1199     QTest::newRow("chunked*2bis") << raw("\xa1\x7f\x66needle\x60\xff\xd8\x2a\x68haystack") << true;
1200     QTest::newRow("chunked*3") << raw("\xa1\x7f\x62ne\x62""ed\x62le\xff\xd8\x2a\x68haystack") << true;
1201     QTest::newRow("chunked*8") << raw("\xa1\x7f\x61n\x61""e\x60\x61""e\x61""d\x60\x62le\x60\xff\xd8\x2a\x68haystack") << true;
1202 
1203     QTest::newRow("1before") << raw("\xa2\x68haystack\x66needle\x66needle\xd8\x2a\x68haystack") << true;
1204     QTest::newRow("tagged-1before") << raw("\xa2\xc1\x68haystack\x66needle\xc1\x66needle\xd8\x2a\x68haystack") << true;
1205     QTest::newRow("doubletagged-1before2") << raw("\xa2\xc1\xc2\x68haystack\x66needle\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true;
1206 
1207     QTest::newRow("arraybefore") << raw("\xa2\x61z\x80\x66needle\xd8\x2a\x68haystack") << true;
1208     QTest::newRow("nestedarraybefore") << raw("\xa2\x61z\x81\x81\0\x66needle\xd8\x2a\x68haystack") << true;
1209     QTest::newRow("arrayarraybefore") << raw("\xa2\x82\1\2\x80\x66needle\xd8\x2a\x68haystack") << true;
1210 
1211     QTest::newRow("mapbefore") << raw("\xa2\x61z\xa0\x66needle\xd8\x2a\x68haystack") << true;
1212     QTest::newRow("nestedmapbefore") << raw("\xa2\x61z\xa1\0\x81\0\x66needle\xd8\x2a\x68haystack") << true;
1213     QTest::newRow("mapmapbefore") << raw("\xa2\xa1\1\2\xa0\x66needle\xd8\x2a\x68haystack") << true;
1214 }
1215 
mapFind()1216 void tst_Parser::mapFind()
1217 {
1218     QFETCH(QByteArray, data);
1219     QFETCH(bool, expected);
1220 
1221     ParserWrapper w;
1222     CborError err = w.init(data);
1223     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1224 
1225     CborValue element;
1226     err = cbor_value_map_find_value(&w.first, "needle", &element);
1227     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1228 
1229     if (expected) {
1230         QCOMPARE(int(element.type), int(CborTagType));
1231 
1232         CborTag tag;
1233         err = cbor_value_get_tag(&element, &tag);
1234         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1235         QCOMPARE(int(tag), 42);
1236 
1237         bool equals;
1238         err = cbor_value_text_string_equals(&element, "haystack", &equals);
1239         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1240         QVERIFY(equals);
1241     } else {
1242         QCOMPARE(int(element.type), int(CborInvalidType));
1243     }
1244 }
1245 
checkedIntegers_data()1246 void tst_Parser::checkedIntegers_data()
1247 {
1248     QTest::addColumn<QByteArray>("data");
1249     QTest::addColumn<QVariant>("result");       // QVariant so we can note numbers out of int64_t range
1250 
1251     QTest::newRow("0") << raw("\x00") << QVariant(Q_INT64_C(0));
1252     QTest::newRow("1") << raw("\x01") << QVariant(Q_INT64_C(1));
1253     QTest::newRow("10") << raw("\x0a") << QVariant(Q_INT64_C(10));
1254     QTest::newRow("23") << raw("\x17") << QVariant(Q_INT64_C(23));
1255     QTest::newRow("24") << raw("\x18\x18") << QVariant(Q_INT64_C(24));
1256     QTest::newRow("UINT8_MAX") << raw("\x18\xff") << QVariant(Q_INT64_C(255));
1257     QTest::newRow("UINT8_MAX+1") << raw("\x19\x01\x00") << QVariant(Q_INT64_C(256));
1258     QTest::newRow("UINT16_MAX") << raw("\x19\xff\xff") << QVariant(Q_INT64_C(65535));
1259     QTest::newRow("UINT16_MAX+1") << raw("\x1a\0\1\x00\x00") << QVariant(Q_INT64_C(65536));
1260     QTest::newRow("INT32_MAX") << raw("\x1a\x7f\xff\xff\xff") << QVariant(Q_INT64_C(2147483647));
1261     QTest::newRow("INT32_MAX+1") << raw("\x1a\x80\x00\x00\x00") << QVariant(Q_INT64_C(2147483648));
1262     QTest::newRow("UINT32_MAX") << raw("\x1a\xff\xff\xff\xff") << QVariant(Q_INT64_C(4294967295));
1263     QTest::newRow("UINT32_MAX+1") << raw("\x1b\0\0\0\1\0\0\0\0") << QVariant(Q_INT64_C(4294967296));
1264     QTest::newRow("UINT64_MAX") << raw("\x1b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
1265                                 << QVariant();  // out of range
1266 
1267     // negative integers
1268     QTest::newRow("-1") << raw("\x20") << QVariant(Q_INT64_C(-1));
1269     QTest::newRow("-2") << raw("\x21") << QVariant(Q_INT64_C(-2));
1270     QTest::newRow("-24") << raw("\x37") << QVariant(Q_INT64_C(-24));
1271     QTest::newRow("-25") << raw("\x38\x18") << QVariant(Q_INT64_C(-25));
1272     QTest::newRow("-UINT8_MAX") << raw("\x38\xff") << QVariant(Q_INT64_C(-256));
1273     QTest::newRow("-UINT8_MAX-1") << raw("\x39\x01\x00") << QVariant(Q_INT64_C(-257));
1274     QTest::newRow("-UINT16_MAX") << raw("\x39\xff\xff") << QVariant(Q_INT64_C(-65536));
1275     QTest::newRow("-UINT16_MAX-1") << raw("\x3a\0\1\x00\x00") << QVariant(Q_INT64_C(-65537));
1276     QTest::newRow("INT32_MIN") << raw("\x3a\x7f\xff\xff\xff") << QVariant(Q_INT64_C(-2147483648));
1277     QTest::newRow("INT32_MIN-1") << raw("\x3a\x80\x00\x00\x00") << QVariant(Q_INT64_C(-2147483649));
1278     QTest::newRow("-UINT32_MAX") << raw("\x3a\xff\xff\xff\xff") << QVariant(Q_INT64_C(-4294967296));
1279     QTest::newRow("-UINT32_MAX-1") << raw("\x3b\0\0\0\1\0\0\0\0") << QVariant(Q_INT64_C(-4294967297));
1280     QTest::newRow("INT64_MIN+1") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xfe")
1281                                << QVariant(std::numeric_limits<qint64>::min() + 1);
1282     QTest::newRow("INT64_MIN") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xff")
1283                                << QVariant(std::numeric_limits<qint64>::min());
1284     QTest::newRow("INT64_MIN-1") << raw("\x3b\x80\0\0\0""\0\0\0\0") << QVariant();  // out of range
1285     QTest::newRow("-UINT64_MAX") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xfe")
1286                                    << QVariant();   // out of range
1287     QTest::newRow("-UINT64_MAX+1") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
1288                                    << QVariant();   // out of range
1289 }
1290 
checkedIntegers()1291 void tst_Parser::checkedIntegers()
1292 {
1293     QFETCH(QByteArray, data);
1294     QFETCH(QVariant, result);
1295     int64_t expected = result.toLongLong();
1296 
1297     ParserWrapper w;
1298     CborError err = w.init(data);
1299     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1300 
1301     int64_t v;
1302     err = cbor_value_get_int64_checked(&w.first, &v);
1303     if (result.isNull()) {
1304         QCOMPARE(err, CborErrorDataTooLarge);
1305     } else {
1306         QCOMPARE(v, expected);
1307     }
1308 
1309     int v2;
1310     err = cbor_value_get_int_checked(&w.first, &v2);
1311     if (result.isNull() || expected < std::numeric_limits<int>::min() || expected > std::numeric_limits<int>::max()) {
1312         QCOMPARE(err, CborErrorDataTooLarge);
1313     } else {
1314         QCOMPARE(int64_t(v2), expected);
1315     }
1316 }
1317 
validation_data()1318 void tst_Parser::validation_data()
1319 {
1320     addValidationColumns();
1321     addValidationData();
1322 }
1323 
validation()1324 void tst_Parser::validation()
1325 {
1326     QFETCH(QByteArray, data);
1327     QFETCH(int, flags);
1328     QFETCH(CborError, expectedError);
1329 
1330     QString decoded;
1331     ParserWrapper w;
1332     CborError err = w.init(data, uint32_t(flags));
1333     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1334 
1335     CborError err2 = cbor_value_validate_basic(&w.first);
1336     CborError err3 = cbor_value_validate(&w.first, CborValidateBasic);
1337     err = parseOne(&w.first, &decoded);
1338     QCOMPARE(err, expectedError);
1339     if (!QByteArray(QTest::currentDataTag()).contains("utf8")) {
1340         QCOMPARE(err2, expectedError);
1341         QCOMPARE(err3, expectedError);
1342     }
1343 }
1344 
strictValidation_data()1345 void tst_Parser::strictValidation_data()
1346 {
1347     addValidationColumns();
1348 
1349     // Canonical validation - fixed types
1350     QTest::newRow("unsigned-0") << raw("\x00") << int(CborValidateCanonicalFormat) << CborNoError;
1351     QTest::newRow("unsigned-24") << raw("\x18\x18") << int(CborValidateCanonicalFormat) << CborNoError;
1352     QTest::newRow("unsigned-256") << raw("\x19\1\0") << int(CborValidateCanonicalFormat) << CborNoError;
1353     QTest::newRow("unsigned-65536") << raw("\x1a\0\1\0\0") << int(CborValidateCanonicalFormat) << CborNoError;
1354     QTest::newRow("unsigned-4294967296") << raw("\x1b\0\0\0\1\0\0\0\0") << int(CborValidateCanonicalFormat) << CborNoError;
1355     QTest::newRow("overlong-unsigned-0*1") << raw("\x18\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1356     QTest::newRow("overlong-unsigned-0*2") << raw("\x19\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1357     QTest::newRow("overlong-unsigned-0*4") << raw("\x1a\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1358     QTest::newRow("overlong-unsigned-0*8") << raw("\x1b\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1359     QTest::newRow("overlong-unsigned-24*2") << raw("\x19\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1360     QTest::newRow("overlong-unsigned-24*4") << raw("\x1a\0\0\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1361     QTest::newRow("overlong-unsigned-24*8") << raw("\x1b\0\0\0\0\0\0\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1362     QTest::newRow("overlong-unsigned-256*4") << raw("\x1a\0\0\1\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1363     QTest::newRow("overlong-unsigned-256*8") << raw("\x1b\0\0\0\0\0\0\1\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1364     QTest::newRow("overlong-unsigned-65536*8") << raw("\x1b\0\0\0\0\0\1\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1365     QTest::newRow("negative-1") << raw("\x20") << int(CborValidateCanonicalFormat) << CborNoError;
1366     QTest::newRow("negative-25") << raw("\x38\x38") << int(CborValidateCanonicalFormat) << CborNoError;
1367     QTest::newRow("negative-257") << raw("\x39\1\0") << int(CborValidateCanonicalFormat) << CborNoError;
1368     QTest::newRow("negative-65537") << raw("\x3a\0\1\0\0") << int(CborValidateCanonicalFormat) << CborNoError;
1369     QTest::newRow("negative-4294967297") << raw("\x3b\0\0\0\1\0\0\0\0") << int(CborValidateCanonicalFormat) << CborNoError;
1370     QTest::newRow("overlong-negative-1*1") << raw("\x38\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1371     QTest::newRow("overlong-negative-1*2") << raw("\x39\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1372     QTest::newRow("overlong-negative-1*4") << raw("\x3a\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1373     QTest::newRow("overlong-negative-1*8") << raw("\x3b\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1374     QTest::newRow("overlong-negative-25*2") << raw("\x39\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1375     QTest::newRow("overlong-negative-25*4") << raw("\x3a\0\0\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1376     QTest::newRow("overlong-negative-25*8") << raw("\x3b\0\0\0\0\0\0\0\x18") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1377     QTest::newRow("overlong-negative-257*4") << raw("\x3a\0\0\1\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1378     QTest::newRow("overlong-negative-257*8") << raw("\x3b\0\0\0\0\0\0\1\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1379     QTest::newRow("overlong-negative-65537*8") << raw("\x3b\0\0\0\0\0\1\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1380     QTest::newRow("simple-0") << raw("\xe0") << int(CborValidateCanonicalFormat) << CborNoError;
1381     QTest::newRow("false") << raw("\xf4") << int(CborValidateCanonicalFormat) << CborNoError;
1382     QTest::newRow("true") << raw("\xf5") << int(CborValidateCanonicalFormat) << CborNoError;
1383     QTest::newRow("null") << raw("\xf6") << int(CborValidateCanonicalFormat) << CborNoError;
1384     QTest::newRow("undefined") << raw("\xf7") << int(CborValidateCanonicalFormat) << CborNoError;
1385     QTest::newRow("simple-32") << raw("\xf8\x20") << int(CborValidateCanonicalFormat) << CborNoError;
1386     QTest::newRow("fp-nan") << raw("\xf9\x7e\00") << int(CborValidateCanonicalFormat) << CborNoError;
1387     QTest::newRow("fp--inf") << raw("\xf9\xfc\00") << int(CborValidateCanonicalFormat) << CborNoError;
1388     QTest::newRow("fp-+inf") << raw("\xf9\x7c\00") << int(CborValidateCanonicalFormat) << CborNoError;
1389     QTest::newRow("overlong-fp-nan_f") << raw("\xfa\x7f\xc0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1390     QTest::newRow("overlong-fp--inf_f") << raw("\xfa\xff\x80\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1391     QTest::newRow("overlong-fp-+inf_f") << raw("\xfa\x7f\x80\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1392     QTest::newRow("overlong-fp-nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1393     QTest::newRow("overlong-fp--inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1394     QTest::newRow("overlong-fp-+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1395 
1396     // canonical - lengths
1397     QByteArray data24(24, 0x20);    // also decodes as -1
1398     QByteArray data256(256, 0x40);  // also decodes as h''
1399     QByteArray data65536(65536, 0x60);// also decodes as ""
1400     QTest::newRow("bytearray-0") << raw("\x40") << int(CborValidateCanonicalFormat) << CborNoError;
1401     QTest::newRow("bytearray-24") << (raw("\x58\x18") + data24) << int(CborValidateCanonicalFormat) << CborNoError;
1402     QTest::newRow("bytearray-256") << (raw("\x59\1\0") + data256) << int(CborValidateCanonicalFormat) << CborNoError;
1403     QTest::newRow("bytearray-65536") << (raw("\x5a\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborNoError;
1404     QTest::newRow("_bytearray-0") << raw("\x5f\xff") << int(CborValidateCanonicalFormat) << CborErrorUnknownLength;
1405     QTest::newRow("overlong-bytearray-0*1") << raw("\x58\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1406     QTest::newRow("overlong-bytearray-0*2") << raw("\x59\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1407     QTest::newRow("overlong-bytearray-0*4") << raw("\x5a\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1408     QTest::newRow("overlong-bytearray-0*8") << raw("\x5b\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1409     QTest::newRow("overlong-bytearray-24*2") << (raw("\x59\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1410     QTest::newRow("overlong-bytearray-24*4") << (raw("\x5a\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1411     QTest::newRow("overlong-bytearray-24*8") << (raw("\x5b\0\0\0\0\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1412     QTest::newRow("overlong-bytearray-256*4") << (raw("\x5a\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1413     QTest::newRow("overlong-bytearray-256*8") << (raw("\x5b\0\0\0\0\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1414     QTest::newRow("overlong-bytearray-65536*8") << (raw("\x5b\0\0\0\0\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1415     QTest::newRow("string-0") << raw("\x60") << int(CborValidateCanonicalFormat) << CborNoError;
1416     QTest::newRow("string-24") << (raw("\x78\x18") + data24) << int(CborValidateCanonicalFormat) << CborNoError;
1417     QTest::newRow("string-256") << (raw("\x79\1\0") + data256) << int(CborValidateCanonicalFormat) << CborNoError;
1418     QTest::newRow("string-65536") << (raw("\x7a\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborNoError;
1419     QTest::newRow("_string-0") << raw("\x7f\xff") << int(CborValidateCanonicalFormat) << CborErrorUnknownLength;
1420     QTest::newRow("overlong-string-0*1") << raw("\x78\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1421     QTest::newRow("overlong-string-0*2") << raw("\x79\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1422     QTest::newRow("overlong-string-0*4") << raw("\x7a\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1423     QTest::newRow("overlong-string-0*8") << raw("\x7b\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1424     QTest::newRow("overlong-string-24*2") << (raw("\x79\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1425     QTest::newRow("overlong-string-24*4") << (raw("\x7a\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1426     QTest::newRow("overlong-string-24*8") << (raw("\x7b\0\0\0\0\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1427     QTest::newRow("overlong-string-256*4") << (raw("\x7a\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1428     QTest::newRow("overlong-string-256*8") << (raw("\x7b\0\0\0\0\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1429     QTest::newRow("overlong-string-65536*8") << (raw("\x7b\0\0\0\0\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1430     QTest::newRow("array-0") << raw("\x80") << int(CborValidateCanonicalFormat) << CborNoError;
1431     QTest::newRow("array-24") << (raw("\x98\x18") + data24) << int(CborValidateCanonicalFormat) << CborNoError;
1432     QTest::newRow("array-256") << (raw("\x99\1\0") + data256) << int(CborValidateCanonicalFormat) << CborNoError;
1433     QTest::newRow("array-65536") << (raw("\x9a\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborNoError;
1434     QTest::newRow("_array-0") << raw("\x9f\xff") << int(CborValidateCanonicalFormat) << CborErrorUnknownLength;
1435     QTest::newRow("overlong-array-0*1") << raw("\x98\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1436     QTest::newRow("overlong-array-0*2") << raw("\x99\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1437     QTest::newRow("overlong-array-0*4") << raw("\x9a\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1438     QTest::newRow("overlong-array-0*8") << raw("\x9b\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1439     QTest::newRow("overlong-array-24*2") << (raw("\x99\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1440     QTest::newRow("overlong-array-24*4") << (raw("\x9a\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1441     QTest::newRow("overlong-array-24*8") << (raw("\x9b\0\0\0\0\0\0\0\x18") + data24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1442     QTest::newRow("overlong-array-256*4") << (raw("\x9a\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1443     QTest::newRow("overlong-array-256*8") << (raw("\x9b\0\0\0\0\0\0\1\0") + data256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1444     QTest::newRow("overlong-array-65536*8") << (raw("\x9b\0\0\0\0\0\1\0\0") + data65536) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1445 
1446     // we need unique, sorted, string keys for map
1447     // we'll make all key-value pairs a total of 4 bytes
1448     char mapentry[] = { 0x62, 0, 0, 0x20 };
1449     QByteArray mapdata24(24 * sizeof(mapentry), Qt::Uninitialized);
1450     QByteArray mapdata256(256 * sizeof(mapentry), Qt::Uninitialized);
1451     char *mapdata24ptr = mapdata24.data();
1452     char *mapdata256ptr = mapdata256.data();
1453     for (int i = 0; i < 256; ++i) {
1454         mapentry[1] = 'A' + (i >> 4);
1455         mapentry[2] = 'a' + (i & 0xf);
1456         memcpy(mapdata256ptr + i * sizeof(mapentry), mapentry, sizeof(mapentry));
1457         if (i < 24)
1458             memcpy(mapdata24ptr + i * sizeof(mapentry), mapentry, sizeof(mapentry));
1459     }
1460     QTest::newRow("map-0") << raw("\xa0") << int(CborValidateCanonicalFormat) << CborNoError;
1461     QTest::newRow("map-24") << (raw("\xb8\x18") + mapdata24) << int(CborValidateCanonicalFormat) << CborNoError;
1462     QTest::newRow("map-256") << (raw("\xb9\1\0") + mapdata256) << int(CborValidateCanonicalFormat) << CborNoError;
1463     QTest::newRow("_map-0") << raw("\xbf\xff") << int(CborValidateCanonicalFormat) << CborErrorUnknownLength;
1464     QTest::newRow("overlong-map-0*1") << raw("\xb8\x00") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1465     QTest::newRow("overlong-map-0*2") << raw("\xb9\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1466     QTest::newRow("overlong-map-0*4") << raw("\xba\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1467     QTest::newRow("overlong-map-0*8") << raw("\xbb\0\0\0\0\0\0\0\0") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1468     QTest::newRow("overlong-map-24*2") << (raw("\xb9\0\x18") + mapdata24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1469     QTest::newRow("overlong-map-24*4") << (raw("\xba\0\0\0\x18") + mapdata24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1470     QTest::newRow("overlong-map-24*8") << (raw("\xbb\0\0\0\0\0\0\0\x18") + mapdata24) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1471     QTest::newRow("overlong-map-256*4") << (raw("\xba\0\0\1\0") + mapdata256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1472     QTest::newRow("overlong-map-256*8") << (raw("\xbb\0\0\0\0\0\0\1\0") + mapdata256) << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1473     QTest::newRow("unsorted-length-map-UU") << raw("\xa2\1\1\0\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1474     QTest::newRow("unsorted-length-map-UUU") << raw("\xa3\1\1\1\1\0\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1475     QTest::newRow("unsorted-length-map-SS") << raw("\xa2\x61z\1\x60\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1476     QTest::newRow("unsorted-length-map-SSS") << raw("\xa3\x61z\1\x61z\2\x60\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1477     QTest::newRow("unsorted-length-map-SB") << raw("\xa2\x61z\1\x40\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1478     QTest::newRow("unsorted-length-map-AS") << raw("\xa2\x83\0\x20\x45Hello\1\x60\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1479     QTest::newRow("unsorted-content-map-SS") << raw("\xa2\x61z\1\x61y\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1480     QTest::newRow("unsorted-content-map-AS") << raw("\xa2\x81\x21\1\x61\x21\0") << int(CborValidateCanonicalFormat) << CborErrorMapNotSorted;
1481 
1482     QTest::newRow("tag-0") << raw("\xc0\x60") << int(CborValidateCanonicalFormat) << CborNoError;
1483     QTest::newRow("tag-24") << raw("\xd8\x18\x40") << int(CborValidateCanonicalFormat) << CborNoError;
1484     QTest::newRow("tag-65536") << raw("\xda\0\1\0\0\x60") << int(CborValidateCanonicalFormat) << CborNoError;
1485     QTest::newRow("tag-4294967296") << raw("\xdb\0\0\0\1\0\0\0\0\x60") << int(CborValidateCanonicalFormat) << CborNoError;
1486     QTest::newRow("overlong-tag-0*1") << raw("\xd8\x00\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1487     QTest::newRow("overlong-tag-0*2") << raw("\xd9\0\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1488     QTest::newRow("overlong-tag-0*4") << raw("\xda\0\0\0\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1489     QTest::newRow("overlong-tag-0*8") << raw("\xdb\0\0\0\0\0\0\0\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1490     QTest::newRow("overlong-tag-24*2") << raw("\xd9\0\x18\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1491     QTest::newRow("overlong-tag-24*4") << raw("\xda\0\0\0\x18\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1492     QTest::newRow("overlong-tag-24*8") << raw("\xdb\0\0\0\0\0\0\0\x18\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1493     QTest::newRow("overlong-tag-256*4") << raw("\xda\0\0\1\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1494     QTest::newRow("overlong-tag-256*8") << raw("\xdb\0\0\0\0\0\0\1\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1495     QTest::newRow("overlong-tag-65536*8") << raw("\xdb\0\0\0\0\0\1\0\0\x60") << int(CborValidateCanonicalFormat) << CborErrorOverlongEncoding;
1496 
1497     // non-canonical: string length in chunked transfer
1498     QTest::newRow("overlong-_bytearray-0*1") << raw("\x5f\x58\x00\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1499     QTest::newRow("overlong-_bytearray-0*2") << raw("\x5f\x59\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1500     QTest::newRow("overlong-_bytearray-0*4") << raw("\x5f\x5a\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1501     QTest::newRow("overlong-_bytearray-0*8") << raw("\x5f\x5b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1502     QTest::newRow("overlong-_bytearray-24*2") << (raw("\x5f\x59\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1503     QTest::newRow("overlong-_bytearray-24*4") << (raw("\x5f\x5a\0\0\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1504     QTest::newRow("overlong-_bytearray-24*8") << (raw("\x5f\x5b\0\0\0\0\0\0\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1505     QTest::newRow("overlong-_bytearray-256*4") << (raw("\x5f\x5a\0\0\1\0") + data256 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1506     QTest::newRow("overlong-_bytearray-256*8") << (raw("\x5f\x5b\0\0\0\0\0\0\1\0") + data256 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1507     QTest::newRow("overlong-_bytearray-65536*8") << (raw("\x5f\x5b\0\0\0\0\0\1\0\0") + data65536 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1508     QTest::newRow("overlong-_bytearrayx2-0*1") << raw("\x5f\x40\x58\x00\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1509     QTest::newRow("overlong-_bytearrayx2-0*2") << raw("\x5f\x40\x59\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1510     QTest::newRow("overlong-_bytearrayx2-0*4") << raw("\x5f\x40\x5a\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1511     QTest::newRow("overlong-_bytearrayx2-0*8") << raw("\x5f\x40\x5b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1512     QTest::newRow("overlong-_string-0*1") << raw("\x7f\x78\x00\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1513     QTest::newRow("overlong-_string-0*2") << raw("\x7f\x79\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1514     QTest::newRow("overlong-_string-0*4") << raw("\x7f\x7a\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1515     QTest::newRow("overlong-_string-0*8") << raw("\x7f\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1516     QTest::newRow("overlong-_string-24*2") << (raw("\x7f\x79\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1517     QTest::newRow("overlong-_string-24*4") << (raw("\x7f\x7a\0\0\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1518     QTest::newRow("overlong-_string-24*8") << (raw("\x7f\x7b\0\0\0\0\0\0\0\x18") + data24 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1519     QTest::newRow("overlong-_string-256*4") << (raw("\x7f\x7a\0\0\1\0") + data256 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1520     QTest::newRow("overlong-_string-256*8") << (raw("\x7f\x7b\0\0\0\0\0\0\1\0") + data256 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1521     QTest::newRow("overlong-_string-65536*8") << (raw("\x7f\x7b\0\0\0\0\0\1\0\0") + data65536 + '\xff') << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1522     QTest::newRow("overlong-_stringx2-0*1") << raw("\x7f\x60\x78\x00\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1523     QTest::newRow("overlong-_stringx2-0*2") << raw("\x7f\x60\x79\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1524     QTest::newRow("overlong-_stringx2-0*4") << raw("\x7f\x60\x7a\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1525     QTest::newRow("overlong-_stringx2-0*8") << raw("\x7f\x60\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
1526 
1527     // strict mode
1528     // UTF-8 sequences with invalid continuation bytes
1529     QTest::newRow("invalid-utf8-bad-continuation-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1530     QTest::newRow("invalid-utf8-bad-continuation-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1531     QTest::newRow("invalid-utf8-bad-continuation-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1532     QTest::newRow("invalid-utf8-bad-continuation-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1533     QTest::newRow("invalid-utf8-bad-continuation-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1534     QTest::newRow("invalid-utf8-bad-continuation-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1535     QTest::newRow("invalid-utf8-bad-continuation-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1536     QTest::newRow("invalid-utf8-bad-continuation-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1537     QTest::newRow("invalid-utf8-bad-continuation-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1538     // Too short UTF-8 sequences (in an array so there's a byte after that would make it valid UTF-8 if it were part of the string)
1539     QTest::newRow("invalid-utf8-too-short-2chars") << raw("\x82\x61\xc2\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1540     QTest::newRow("invalid-utf8-too-short-3chars-1") << raw("\x82\x61\xe0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1541     QTest::newRow("invalid-utf8-too-short-3chars-2") << raw("\x82\x62\xe0\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1542     QTest::newRow("invalid-utf8-too-short-4chars-1") << raw("\x82\x61\xf0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1543     QTest::newRow("invalid-utf8-too-short-4chars-2") << raw("\x82\x62\xf0\x90\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1544     QTest::newRow("invalid-utf8-too-short-4chars-3") << raw("\x82\x63\xf0\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1545     // UTF-16 surrogages encoded in UTF-8
1546     QTest::newRow("invalid-utf8-hi-surrogate") << raw("\x63\xed\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1547     QTest::newRow("invalid-utf8-lo-surrogate") << raw("\x63\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1548     QTest::newRow("invalid-utf8-surrogate-pair") << raw("\x66\xed\xa0\x80\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1549     // Non-Unicode UTF-8 sequences
1550     QTest::newRow("invalid-utf8-non-unicode-1") << raw("\x64\xf4\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1551     QTest::newRow("invalid-utf8-non-unicode-2") << raw("\x65\xf8\x88\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1552     QTest::newRow("invalid-utf8-non-unicode-3") << raw("\x66\xfc\x84\x80\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1553     QTest::newRow("invalid-utf8-non-unicode-4") << raw("\x66\xfd\xbf\xbf\xbf\xbf\xbf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1554     // invalid bytes in UTF-8
1555     QTest::newRow("invalid-utf8-fe") << raw("\x61\xfe") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1556     QTest::newRow("invalid-utf8-ff") << raw("\x61\xff") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1557     // Overlong sequences
1558     QTest::newRow("invalid-utf8-overlong-1-2") << raw("\x62\xc1\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1559     QTest::newRow("invalid-utf8-overlong-1-3") << raw("\x63\xe0\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1560     QTest::newRow("invalid-utf8-overlong-1-4") << raw("\x64\xf0\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1561     QTest::newRow("invalid-utf8-overlong-1-5") << raw("\x65\xf8\x80\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1562     QTest::newRow("invalid-utf8-overlong-1-6") << raw("\x66\xfc\x80\x80\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1563     QTest::newRow("invalid-utf8-overlong-2-3") << raw("\x63\xe0\x82\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1564     QTest::newRow("invalid-utf8-overlong-2-4") << raw("\x64\xf0\x80\x82\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1565     QTest::newRow("invalid-utf8-overlong-2-5") << raw("\x65\xf8\x80\x80\x82\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1566     QTest::newRow("invalid-utf8-overlong-2-6") << raw("\x66\xfc\x80\x80\x80\x82\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1567     QTest::newRow("invalid-utf8-overlong-3-4") << raw("\x64\xf0\x80\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1568     QTest::newRow("invalid-utf8-overlong-3-5") << raw("\x65\xf8\x80\x80\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1569     QTest::newRow("invalid-utf8-overlong-3-6") << raw("\x66\xfc\x80\x80\x80\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1570     QTest::newRow("invalid-utf8-overlong-4-5") << raw("\x65\xf8\x80\x84\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1571     QTest::newRow("invalid-utf8-overlong-4-6") << raw("\x66\xfc\x80\x80\x84\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
1572 
1573     QTest::newRow("nonunique-content-map-UU") << raw("\xa2\0\1\0\2") << int(CborValidateStrictMode) << CborErrorMapKeysNotUnique;
1574     QTest::newRow("nonunique-content-map-SS") << raw("\xa2\x61z\1\x61z\2") << int(CborValidateStrictMode) << CborErrorMapKeysNotUnique;
1575     QTest::newRow("nonunique-content-map-AA") << raw("\xa2\x81\x65Hello\1\x81\x65Hello\2") << int(CborValidateStrictMode) << CborErrorMapKeysNotUnique;
1576 
1577     QTest::newRow("tag-0-unsigned") << raw("\xc0\x00") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1578     QTest::newRow("tag-0-bytearray") << raw("\xc0\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1579     QTest::newRow("tag-0-string") << raw("\xc0\x60") << int(CborValidateStrictMode) << CborNoError;
1580     QTest::newRow("tag-0-tag-0-string") << raw("\xc0\xc0\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1581     QTest::newRow("tag-1-unsigned") << raw("\xc1\x00") << int(CborValidateStrictMode) << CborNoError;
1582     QTest::newRow("tag-1-negative") << raw("\xc1\x20") << int(CborValidateStrictMode) << CborNoError;
1583     QTest::newRow("tag-1-bytearray") << raw("\xc1\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1584     QTest::newRow("tag-2-bytearray") << raw("\xc2\x40") << int(CborValidateStrictMode) << CborNoError;
1585     QTest::newRow("tag-2-string") << raw("\xc2\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1586     QTest::newRow("tag-3-bytearray") << raw("\xc3\x40") << int(CborValidateStrictMode) << CborNoError;
1587     QTest::newRow("tag-3-string") << raw("\xc3\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1588     QTest::newRow("tag-4-string") << raw("\xc4\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1589     QTest::newRow("tag-4-array") << raw("\xc4\x82\0\1") << int(CborValidateStrictMode) << CborNoError;
1590     QTest::newRow("tag-5-string") << raw("\xc5\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1591     QTest::newRow("tag-5-array") << raw("\xc5\x82\0\1") << int(CborValidateStrictMode) << CborNoError;
1592     QTest::newRow("tag-21-bytearray") << raw("\xd5\x40") << int(CborValidateStrictMode) << CborNoError;
1593     QTest::newRow("tag-21-string") << raw("\xd5\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1594     QTest::newRow("tag-21-array") << raw("\xd5\x80") << int(CborValidateStrictMode) << CborNoError;
1595     QTest::newRow("tag-21-map") << raw("\xd5\xa0") << int(CborValidateStrictMode) << CborNoError;
1596     QTest::newRow("tag-22-bytearray") << raw("\xd6\x40") << int(CborValidateStrictMode) << CborNoError;
1597     QTest::newRow("tag-22-string") << raw("\xd6\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1598     QTest::newRow("tag-22-array") << raw("\xd6\x80") << int(CborValidateStrictMode) << CborNoError;
1599     QTest::newRow("tag-22-map") << raw("\xd6\xa0") << int(CborValidateStrictMode) << CborNoError;
1600     QTest::newRow("tag-23-bytearray") << raw("\xd7\x40") << int(CborValidateStrictMode) << CborNoError;
1601     QTest::newRow("tag-23-string") << raw("\xd7\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1602     QTest::newRow("tag-23-array") << raw("\xd7\x80") << int(CborValidateStrictMode) << CborNoError;
1603     QTest::newRow("tag-23-map") << raw("\xd7\xa0") << int(CborValidateStrictMode) << CborNoError;
1604     QTest::newRow("tag-24-bytearray") << raw("\xd8\x18\x40") << int(CborValidateStrictMode) << CborNoError;
1605     QTest::newRow("tag-24-string") << raw("\xd8\x18\x60") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1606     QTest::newRow("tag-32-bytearray") << raw("\xd8\x20\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1607     QTest::newRow("tag-32-string") << raw("\xd8\x20\x60") << int(CborValidateStrictMode) << CborNoError;
1608     QTest::newRow("tag-33-bytearray") << raw("\xd8\x21\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1609     QTest::newRow("tag-33-string") << raw("\xd8\x21\x60") << int(CborValidateStrictMode) << CborNoError;
1610     QTest::newRow("tag-34-bytearray") << raw("\xd8\x22\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1611     QTest::newRow("tag-34-string") << raw("\xd8\x22\x60") << int(CborValidateStrictMode) << CborNoError;
1612     QTest::newRow("tag-35-bytearray") << raw("\xd8\x23\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1613     QTest::newRow("tag-35-string") << raw("\xd8\x23\x60") << int(CborValidateStrictMode) << CborNoError;
1614     QTest::newRow("tag-36-bytearray") << raw("\xd8\x24\x40") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1615     QTest::newRow("tag-36-string") << raw("\xd8\x24\x60") << int(CborValidateStrictMode) << CborNoError;
1616     QTest::newRow("tag-55799-unsigned") << raw("\xd9\xd9\xf7\x00") << int(CborValidateStrictMode) << CborNoError;
1617     QTest::newRow("tag-55799-negative") << raw("\xd9\xd9\xf7\x20") << int(CborValidateStrictMode) << CborNoError;
1618     QTest::newRow("tag-55799-bytearray") << raw("\xd9\xd9\xf7\x40") << int(CborValidateStrictMode) << CborNoError;
1619     QTest::newRow("tag-55799-string") << raw("\xd9\xd9\xf7\x60") << int(CborValidateStrictMode) << CborNoError;
1620     QTest::newRow("tag-55799-array") << raw("\xd9\xd9\xf7\x80") << int(CborValidateStrictMode) << CborNoError;
1621     QTest::newRow("tag-55799-map") << raw("\xd9\xd9\xf7\xa0") << int(CborValidateStrictMode) << CborNoError;
1622     QTest::newRow("tag-55799-tag-0-unsigned") << raw("\xd9\xd9\xf7\xc0\x00") << int(CborValidateStrictMode) << CborErrorInappropriateTagForType;
1623     QTest::newRow("tag-55799-tag-0-string") << raw("\xd9\xd9\xf7\xc0\x60") << int(CborValidateStrictMode) << CborNoError;
1624     QTest::newRow("tag-55799-simple0") << raw("\xd9\xd9\xf7\xe0") << int(CborValidateStrictMode) << CborNoError;
1625     QTest::newRow("tag-55799-false") << raw("\xd9\xd9\xf7\xf4") << int(CborValidateStrictMode) << CborNoError;
1626     QTest::newRow("tag-55799-true") << raw("\xd9\xd9\xf7\xf5") << int(CborValidateStrictMode) << CborNoError;
1627     QTest::newRow("tag-55799-null") << raw("\xd9\xd9\xf7\xf6") << int(CborValidateStrictMode) << CborNoError;
1628     QTest::newRow("tag-55799-undefined") << raw("\xd9\xd9\xf7\xf7") << int(CborValidateStrictMode) << CborNoError;
1629     QTest::newRow("tag-55799-simple32") << raw("\xd9\xd9\xf7\xf8\x20") << int(CborValidateStrictMode) << CborNoError;
1630     QTest::newRow("tag-55799-half") << raw("\xd9\xd9\xf7\xf9\0\0") << int(CborValidateStrictMode) << CborNoError;
1631     QTest::newRow("tag-55799-float") << raw("\xd9\xd9\xf7\xfa\0\0\0\0") << int(CborValidateStrictMode) << CborNoError;
1632     QTest::newRow("tag-55799-double") << raw("\xd9\xd9\xf7\xfb\0\0\0\0\0\0\0\0") << int(CborValidateStrictMode) << CborNoError;
1633 
1634     // excluded non-finite
1635     QTest::newRow("excluded-fp-nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1636     QTest::newRow("excluded-fp-nan_f") << raw("\xfa\x7f\xc0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1637     QTest::newRow("excluded-fp--inf_f") << raw("\xfa\xff\x80\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1638     QTest::newRow("excluded-fp--inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1639     QTest::newRow("excluded-fp-+inf_f") << raw("\xfa\x7f\x80\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1640     QTest::newRow("excluded-fp-+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1641 
1642     // excluded undefined
1643     QTest::newRow("no-undefined") << raw("\xf7") << int(CborValidateNoUndefined) << CborErrorExcludedType;
1644 
1645     // exclude non-finite
1646     QTest::newRow("excluded-fp-nan_f16") << raw("\xf9\x7e\00") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1647     QTest::newRow("excluded-fp--inf_f16") << raw("\xf9\xfc\00") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1648     QTest::newRow("excluded-fp-+inf_f16") << raw("\xf9\x7c\00") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1649     QTest::newRow("excluded-fp-nan_f") << raw("\xfa\x7f\xc0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1650     QTest::newRow("excluded-fp--inf_f") << raw("\xfa\xff\x80\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1651     QTest::newRow("excluded-fp-+inf_f") << raw("\xfa\x7f\x80\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1652     QTest::newRow("excluded-fp-nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1653     QTest::newRow("excluded-fp--inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1654     QTest::newRow("excluded-fp-+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << int(CborValidateFiniteFloatingPoint) << CborErrorExcludedValue;
1655 
1656     // exclude non-string keys in maps
1657     QTest::newRow("excluded-map-unsigned") << raw("\xa1\x00\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1658     QTest::newRow("excluded-map-negative") << raw("\xa1\x20\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1659     QTest::newRow("excluded-map-bytearray") << raw("\xa1\x40\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1660     QTest::newRow("map-string") << raw("\xa1\x60\1") << int(CborValidateMapKeysAreString) << CborNoError;
1661     QTest::newRow("map-tag-0-string") << raw("\xa1\xc0\x60\1") << int(CborValidateMapKeysAreString) << CborNoError;
1662     QTest::newRow("excluded-map-array") << raw("\xa1\x80\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1663     QTest::newRow("excluded-map-map") << raw("\xa1\xa0\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1664     QTest::newRow("excluded-map-simple-0") << raw("\xa1\xe0\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1665     QTest::newRow("excluded-map-false") << raw("\xa1\xf4\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1666     QTest::newRow("excluded-map-true") << raw("\xa1\xf5\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1667     QTest::newRow("excluded-map-null") << raw("\xa1\xf6\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1668     QTest::newRow("excluded-map-undefined") << raw("\xa1\xf7\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1669     QTest::newRow("excluded-map-half") << raw("\xa1\xf9\0\0\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1670     QTest::newRow("excluded-map-float") << raw("\xa1\xfa\0\0\0\0\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1671     QTest::newRow("excluded-map-double") << raw("\xa1\xfb\0\0\0\0\0\0\0\0\1") << int(CborValidateMapKeysAreString) << CborErrorMapKeyNotString;
1672 
1673     // unknown simple types
1674     QTest::newRow("unknown-simple-type-0") << raw("\xe0") << int(CborValidateNoUnknownSimpleTypes) << CborErrorUnknownSimpleType;
1675     QTest::newRow("unknown-simple-type-32") << raw("\xf8\x20") << int(CborValidateNoUnknownSimpleTypes) << CborErrorUnknownSimpleType;
1676     QTest::newRow("allowed-simple-type-32") << raw("\xf8\x20") << int(CborValidateNoUnknownSimpleTypesSA) << CborNoError;
1677 
1678     // unknown tags
1679     QTest::newRow("unknown-tag-6") << raw("\xc6\x60") << int(CborValidateNoUnknownTags) << CborErrorUnknownTag;
1680     QTest::newRow("unknown-tag-31") << raw("\xd8\x1f\x60") << int(CborValidateNoUnknownTags) << CborErrorUnknownTag;
1681     QTest::newRow("unknown-tag-256") << raw("\xd9\1\0\x60") << int(CborValidateNoUnknownTags) << CborErrorUnknownTag;
1682     QTest::newRow("unknown-tag-65536") << raw("\xda\0\1\0\0\x60") << int(CborValidateNoUnknownTags) << CborErrorUnknownTag;
1683     QTest::newRow("unknown-tag-4294967296") << raw("\xdb\0\0\0\1\0\0\0\0\x60") << int(CborValidateNoUnknownTags) << CborErrorUnknownTag;
1684     QTest::newRow("allowed-tag-31") << raw("\xd8\x1f\x60") << int(CborValidateNoUnknownTagsSA) << CborNoError;
1685     QTest::newRow("allowed-tag-256") << raw("\xd9\1\0\x60") << int(CborValidateNoUnknownTagsSR) << CborNoError;
1686 
1687     // excluded tags
1688     QTest::newRow("excluded-tag-0") << raw("\xc0\x60") << int(CborValidateNoTags) << CborErrorExcludedType;
1689     QTest::newRow("excluded-tag-24") << raw("\xd8\x18\x40") << int(CborValidateNoTags) << CborErrorExcludedType;
1690     QTest::newRow("excluded-tag-55799") << raw("\xd9\xd9\xf7\x60") << int(CborValidateNoTags) << CborErrorExcludedType;
1691 
1692     // complete data
1693     QTest::newRow("garbage-data-0") << raw("\0\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1694     QTest::newRow("garbage-data-1") << raw("\x20\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1695     QTest::newRow("garbage-data-2") << raw("\x40\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1696     QTest::newRow("garbage-data-3") << raw("\x60\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1697     QTest::newRow("garbage-data-4") << raw("\x80\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1698     QTest::newRow("garbage-data-5") << raw("\xa0\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1699     QTest::newRow("garbage-data-6") << raw("\xc0\x60\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1700     QTest::newRow("garbage-data-7") << raw("\xf4\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1701     QTest::newRow("garbage-data-f16") << raw("\xf9\0\0\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1702     QTest::newRow("garbage-data-f32") << raw("\xfa\0\0\0\0\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1703     QTest::newRow("garbage-data-f64") << raw("\xfb\0\0\0\0\0\0\0\0\1") << int(CborValidateCompleteData) << CborErrorGarbageAtEnd;
1704 }
1705 
strictValidation()1706 void tst_Parser::strictValidation()
1707 {
1708     QFETCH(QByteArray, data);
1709     QFETCH(int, flags);
1710     QFETCH(CborError, expectedError);
1711 
1712     QString decoded;
1713     ParserWrapper w;
1714     CborError err = w.init(data);
1715     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1716 
1717     err = cbor_value_validate(&w.first, flags);
1718     QCOMPARE(err, expectedError);
1719 }
1720 
incompleteData_data()1721 void tst_Parser::incompleteData_data()
1722 {
1723     addColumns();
1724     addFixedData();
1725     addStringsData();
1726     addTagsData();
1727     addMapMixedData();
1728 }
1729 
incompleteData()1730 void tst_Parser::incompleteData()
1731 {
1732     QFETCH(QByteArray, data);
1733     QFETCH(QString, expected);
1734 
1735     for (int len = 0; len < data.length() - 1; ++len) {
1736         ParserWrapper w;
1737         CborError err = w.init(data.constData(), len);
1738         if (!err) {
1739             QString decoded;
1740             err = parseOne(&w.first, &decoded);
1741         }
1742         if (err != CborErrorUnexpectedEOF)
1743             qDebug() << "Length is" << len;
1744         QCOMPARE(err, CborErrorUnexpectedEOF);
1745     }
1746 }
1747 
endPointer_data()1748 void tst_Parser::endPointer_data()
1749 {
1750     QTest::addColumn<QByteArray>("data");
1751     QTest::addColumn<int>("offset");
1752 
1753     QTest::newRow("number1") << raw("\x81\x01\x01") << 2;
1754     QTest::newRow("number24") << raw("\x81\x18\x18\x01") << 3;
1755     QTest::newRow("string") << raw("\x81\x61Z\x01") << 3;
1756     QTest::newRow("indefinite-string") << raw("\x81\x7f\x61Z\xff\x01") << 5;
1757     QTest::newRow("array") << raw("\x81\x02\x01") << 2;
1758     QTest::newRow("indefinite-array") << raw("\x81\x9f\x02\xff\x01") << 4;
1759     QTest::newRow("object") << raw("\x81\xa1\x03\x02\x01") << 4;
1760     QTest::newRow("indefinite-object") << raw("\x81\xbf\x03\x02\xff\x01") << 5;
1761 }
1762 
endPointer()1763 void tst_Parser::endPointer()
1764 {
1765     QFETCH(QByteArray, data);
1766     QFETCH(int, offset);
1767 
1768     QString decoded;
1769     ParserWrapper w;
1770     CborError err = w.init(data);
1771     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1772 
1773     err = parseOne(&w.first, &decoded);
1774     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1775     QCOMPARE(int(cbor_value_get_next_byte(&w.first) - w.begin()), offset);
1776 }
1777 
recursionLimit_data()1778 void tst_Parser::recursionLimit_data()
1779 {
1780     static const int recursions = CBOR_PARSER_MAX_RECURSIONS + 2;
1781     QTest::addColumn<QByteArray>("data");
1782 
1783     QTest::newRow("array") << QByteArray(recursions, '\x81') + '\x20';
1784     QTest::newRow("_array") << QByteArray(recursions, '\x9f') + '\x20' + QByteArray(recursions, '\xff');
1785 
1786     QByteArray data;
1787     for (int i = 0; i < recursions; ++i)
1788         data += "\xa1\x65Hello";
1789     data += '\2';
1790     QTest::newRow("map-recursive-values") << data;
1791 
1792     data.clear();
1793     for (int i = 0; i < recursions; ++i)
1794         data += "\xbf\x65World";
1795     data += '\2';
1796     for (int i = 0; i < recursions; ++i)
1797         data += "\xff";
1798     QTest::newRow("_map-recursive-values") << data;
1799 
1800     data = QByteArray(recursions, '\xa1');
1801     data += '\2';
1802     for (int i = 0; i < recursions; ++i)
1803         data += "\x7f\x64quux\xff";
1804     QTest::newRow("map-recursive-keys") << data;
1805 
1806     data = QByteArray(recursions, '\xbf');
1807     data += '\2';
1808     for (int i = 0; i < recursions; ++i)
1809         data += "\1\xff";
1810     QTest::newRow("_map-recursive-keys") << data;
1811 
1812     data.clear();
1813     for (int i = 0; i < recursions / 2; ++i)
1814         data += "\x81\xa1\1";
1815     data += '\2';
1816     QTest::newRow("mixed") << data;
1817 }
1818 
recursionLimit()1819 void tst_Parser::recursionLimit()
1820 {
1821     QFETCH(QByteArray, data);
1822 
1823     ParserWrapper w;
1824     CborError err = w.init(data);
1825     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1826 
1827     // check that it is valid:
1828     CborValue it = w.first;
1829     {
1830         QString dummy;
1831         err = parseOne(&it, &dummy);
1832         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1833     }
1834 
1835     it = w.first;
1836     err = cbor_value_advance(&it);
1837     QCOMPARE(err, CborErrorNestingTooDeep);
1838 
1839     it = w.first;
1840     if (cbor_value_is_map(&it)) {
1841         CborValue dummy;
1842         err = cbor_value_map_find_value(&it, "foo", &dummy);
1843         QCOMPARE(err, CborErrorNestingTooDeep);
1844     }
1845 }
1846 
1847 QTEST_MAIN(tst_Parser)
1848 #include "tst_parser.moc"
1849