Merge branch 'upstream' into tizen
[platform/upstream/iotivity.git] / extlibs / tinycbor / tinycbor / tests / parser / tst_parser.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 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 #include <QtTest>
27 #include "cbor.h"
28 #include <locale.h>
29 #include <stdio.h>
30
31 extern "C" FILE *open_memstream(char **bufptr, size_t *sizeptr);
32
33 Q_DECLARE_METATYPE(CborError)
34
35 class tst_Parser : public QObject
36 {
37     Q_OBJECT
38 private slots:
39     void initParserEmpty();
40
41     // parsing API
42     void fixed_data();
43     void fixed();
44     void strings_data();
45     void strings() { fixed(); }
46     void tags_data();
47     void tags() { fixed(); }
48     void tagTags_data() { tags_data(); }
49     void tagTags();
50     void emptyContainers_data();
51     void emptyContainers();
52     void arrays_data();
53     void arrays();
54     void undefLengthArrays_data() { arrays_data(); }
55     void undefLengthArrays();
56     void nestedArrays_data() { arrays_data(); }
57     void nestedArrays();
58     void maps_data();
59     void maps();
60     void undefLengthMaps_data() { maps_data(); }
61     void undefLengthMaps();
62     void nestedMaps_data() { maps_data(); }
63     void nestedMaps();
64     void mapMixed_data();
65     void mapMixed() { arrays(); }
66     void mapsAndArrays_data() { arrays_data(); }
67     void mapsAndArrays();
68
69     // convenience API
70     void stringLength_data();
71     void stringLength();
72     void stringCompare_data();
73     void stringCompare();
74     void mapFind_data();
75     void mapFind();
76
77     // validation & errors
78     void validation_data();
79     void validation();
80     void resumeParsing_data();
81     void resumeParsing();
82     void endPointer_data();
83     void endPointer();
84     void recursionLimit_data();
85     void recursionLimit();
86 };
87
88 CborError parseOne(CborValue *it, QString *parsed)
89 {
90     CborError err;
91     char *buffer;
92     size_t size;
93
94     setlocale(LC_ALL, "C");
95     FILE *f = open_memstream(&buffer, &size);
96     err = cbor_value_to_pretty_advance(f, it);
97     fclose(f);
98
99     *parsed = QString::fromLatin1(buffer, size);
100     free(buffer);
101     return err;
102 }
103
104 template <size_t N> QByteArray raw(const char (&data)[N])
105 {
106     return QByteArray::fromRawData(data, N - 1);
107 }
108
109 void tst_Parser::initParserEmpty()
110 {
111     CborParser parser;
112     CborValue first;
113     CborError err = cbor_parser_init((const quint8 *)"", 0, 0, &parser, &first);
114     QCOMPARE(err, CborErrorUnexpectedEOF);
115 }
116
117 void addColumns()
118 {
119     QTest::addColumn<QByteArray>("data");
120     QTest::addColumn<QString>("expected");
121     QTest::addColumn<int>("n");         // some aux integer, not added in all columns
122 }
123
124 bool compareFailed = true;
125 void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1)
126 {
127     compareFailed = true;
128     CborParser parser;
129     CborValue first;
130     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
131     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
132
133     if (cbor_value_get_type(&first) == CborArrayType) {
134         size_t len;
135         if (n >= 0) {
136             QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError);
137             QCOMPARE(len, size_t(len));
138         } else {
139             QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength);
140         }
141     } else if (cbor_value_get_type(&first) == CborMapType) {
142         size_t len;
143         if (n >= 0) {
144             QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError);
145             QCOMPARE(len, size_t(len));
146         } else {
147             QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength);
148         }
149     }
150
151     QString decoded;
152     err = parseOne(&first, &decoded);
153     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
154                    "\"; decoded stream:\n" + decoded.toLatin1());
155     QCOMPARE(decoded, expected);
156
157     // check that we consumed everything
158     QCOMPARE((void*)first.ptr, (void*)data.constEnd());
159
160     compareFailed = false;
161 }
162 #define compareOne(data, expected) compareOne_real(data, expected, __LINE__)
163 #define compareOneSize(n, data, expected) compareOne_real(data, expected, __LINE__, n)
164
165 void addFixedData()
166 {
167     // unsigned integers
168     QTest::newRow("0") << raw("\x00") << "0";
169     QTest::newRow("1") << raw("\x01") << "1";
170     QTest::newRow("10") << raw("\x0a") << "10";
171     QTest::newRow("23") << raw("\x17") << "23";
172     QTest::newRow("24") << raw("\x18\x18") << "24";
173     QTest::newRow("UINT8_MAX") << raw("\x18\xff") << "255";
174     QTest::newRow("UINT8_MAX+1") << raw("\x19\x01\x00") << "256";
175     QTest::newRow("UINT16_MAX") << raw("\x19\xff\xff") << "65535";
176     QTest::newRow("UINT16_MAX+1") << raw("\x1a\0\1\x00\x00") << "65536";
177     QTest::newRow("UINT32_MAX") << raw("\x1a\xff\xff\xff\xff") << "4294967295";
178     QTest::newRow("UINT32_MAX+1") << raw("\x1b\0\0\0\1\0\0\0\0") << "4294967296";
179     QTest::newRow("UINT64_MAX") << raw("\x1b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
180                                 << QString::number(std::numeric_limits<uint64_t>::max());
181
182     // negative integers
183     QTest::newRow("-1") << raw("\x20") << "-1";
184     QTest::newRow("-2") << raw("\x21") << "-2";
185     QTest::newRow("-24") << raw("\x37") << "-24";
186     QTest::newRow("-25") << raw("\x38\x18") << "-25";
187     QTest::newRow("-UINT8_MAX") << raw("\x38\xff") << "-256";
188     QTest::newRow("-UINT8_MAX-1") << raw("\x39\x01\x00") << "-257";
189     QTest::newRow("-UINT16_MAX") << raw("\x39\xff\xff") << "-65536";
190     QTest::newRow("-UINT16_MAX-1") << raw("\x3a\0\1\x00\x00") << "-65537";
191     QTest::newRow("-UINT32_MAX") << raw("\x3a\xff\xff\xff\xff") << "-4294967296";
192     QTest::newRow("-UINT32_MAX-1") << raw("\x3b\0\0\0\1\0\0\0\0") << "-4294967297";
193     QTest::newRow("INT64_MIN+1") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xfe")
194                                << QString::number(std::numeric_limits<int64_t>::min() + 1);
195     QTest::newRow("INT64_MIN") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xff")
196                                << QString::number(std::numeric_limits<int64_t>::min());
197     QTest::newRow("INT64_MIN-1") << raw("\x3b\x80\0\0\0""\0\0\0\0") << "-9223372036854775809";
198     QTest::newRow("-UINT64_MAX") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xfe")
199                                    << '-' + QString::number(std::numeric_limits<uint64_t>::max());
200     QTest::newRow("-UINT64_MAX+1") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
201                                    << "-18446744073709551616";
202
203     // overlongs
204     QTest::newRow("0*1") << raw("\x18\x00") << "0";
205     QTest::newRow("0*2") << raw("\x19\x00\x00") << "0";
206     QTest::newRow("0*4") << raw("\x1a\0\0\0\0") << "0";
207     QTest::newRow("0*8") << raw("\x1b\0\0\0\0\0\0\0\0") << "0";
208     QTest::newRow("-1*1") << raw("\x38\x00") << "-1";
209     QTest::newRow("-1*2") << raw("\x39\x00\x00") << "-1";
210     QTest::newRow("-1*4") << raw("\x3a\0\0\0\0") << "-1";
211     QTest::newRow("-1*8") << raw("\x3b\0\0\0\0\0\0\0\0") << "-1";
212
213     QTest::newRow("simple0") << raw("\xe0") << "simple(0)";
214     QTest::newRow("simple19") << raw("\xf3") << "simple(19)";
215     QTest::newRow("false") << raw("\xf4") << "false";
216     QTest::newRow("true") << raw("\xf5") << "true";
217     QTest::newRow("null") << raw("\xf6") << "null";
218     QTest::newRow("undefined") << raw("\xf7") << "undefined";
219     QTest::newRow("simple32") << raw("\xf8\x20") << "simple(32)";
220     QTest::newRow("simple255") << raw("\xf8\xff") << "simple(255)";
221
222     // floating point
223
224     QTest::newRow("0.f16") << raw("\xf9\0\0") << "0.f16";
225     QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << "0.f";
226     QTest::newRow("0.")  << raw("\xfb\0\0\0\0\0\0\0\0") << "0.";
227     QTest::newRow("-1.f16") << raw("\xf9\xbc\x00") << "-1.f16";
228     QTest::newRow("-1.f") << raw("\xfa\xbf\x80\0\0") << "-1.f";
229     QTest::newRow("-1.") << raw("\xfb\xbf\xf0\0\0\0\0\0\0") << "-1.";
230     QTest::newRow("65504.f16") << raw("\xf9\x7b\xff") << "65504.f16";
231     QTest::newRow("16777215.f") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f";
232     QTest::newRow("16777215.") << raw("\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "16777215.";
233     QTest::newRow("-16777215.f") << raw("\xfa\xcb\x7f\xff\xff") << "-16777215.f";
234     QTest::newRow("-16777215.") << raw("\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "-16777215.";
235
236     QTest::newRow("0.5f16") << raw("\xf9\x38\0") << "0.5f16";
237     QTest::newRow("0.5f") << raw("\xfa\x3f\0\0\0") << "0.5f";
238     QTest::newRow("0.5") << raw("\xfb\x3f\xe0\0\0\0\0\0\0") << "0.5";
239     QTest::newRow("2.f16^11-1") << raw("\xf9\x67\xff") << "2047.f16";
240     QTest::newRow("2.f^24-1") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f";
241     QTest::newRow("2.^53-1") << raw("\xfb\x43\x3f\xff\xff""\xff\xff\xff\xff") << "9007199254740991.";
242     QTest::newRow("2.f^64-epsilon") << raw("\xfa\x5f\x7f\xff\xff") << "18446742974197923840.f";
243     QTest::newRow("2.^64-epsilon") << raw("\xfb\x43\xef\xff\xff""\xff\xff\xff\xff") << "18446744073709549568.";
244     QTest::newRow("2.f^64") << raw("\xfa\x5f\x80\0\0") << "1.8446744073709552e+19f";
245     QTest::newRow("2.^64") << raw("\xfb\x43\xf0\0\0\0\0\0\0") << "1.8446744073709552e+19";
246
247     QTest::newRow("nan_f16") << raw("\xf9\x7e\x00") << "nan";
248     QTest::newRow("nan_f") << raw("\xfa\x7f\xc0\0\0") << "nan";
249     QTest::newRow("nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << "nan";
250     QTest::newRow("-inf_f16") << raw("\xf9\xfc\x00") << "-inf";
251     QTest::newRow("-inf_f") << raw("\xfa\xff\x80\0\0") << "-inf";
252     QTest::newRow("-inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << "-inf";
253     QTest::newRow("+inf_f16") << raw("\xf9\x7c\x00") << "inf";
254     QTest::newRow("+inf_f") << raw("\xfa\x7f\x80\0\0") << "inf";
255     QTest::newRow("+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << "inf";
256
257 }
258
259 void tst_Parser::fixed_data()
260 {
261     addColumns();
262     addFixedData();
263 }
264
265 void tst_Parser::fixed()
266 {
267     QFETCH(QByteArray, data);
268     QFETCH(QString, expected);
269
270     compareOne(data, expected);
271 }
272
273 void addStringsData()
274 {
275     // byte strings
276     QTest::newRow("emptybytestring") << raw("\x40") << "h''";
277     QTest::newRow("bytestring1") << raw("\x41 ") << "h'20'";
278     QTest::newRow("bytestring1-nul") << raw("\x41\0") << "h'00'";
279     QTest::newRow("bytestring5") << raw("\x45Hello") << "h'48656c6c6f'";
280     QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234")
281                                   << "h'313233343536373839303132333435363738393031323334'";
282     QTest::newRow("bytestring256") << raw("\x59\1\0") + QByteArray(256, '3')
283                                    << "h'" + QString(256 * 2, '3') + '\'';
284
285     // text strings
286     QTest::newRow("emptytextstring") << raw("\x60") << "\"\"";
287     QTest::newRow("textstring1") << raw("\x61 ") << "\" \"";
288     QTest::newRow("textstring1-nul") << raw("\x61\0") << "\"\\u0000\"";
289     QTest::newRow("textstring5") << raw("\x65Hello") << "\"Hello\"";
290     QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234")
291                                   << "\"123456789012345678901234\"";
292     QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3')
293                                    << '"' + QString(256, '3') + '"';
294
295     // strings with overlong length
296     QTest::newRow("emptybytestring*1") << raw("\x58\x00") << "h''";
297     QTest::newRow("emptytextstring*1") << raw("\x78\x00") << "\"\"";
298     QTest::newRow("emptybytestring*2") << raw("\x59\x00\x00") << "h''";
299     QTest::newRow("emptytextstring*2") << raw("\x79\x00\x00") << "\"\"";
300     QTest::newRow("emptybytestring*4") << raw("\x5a\0\0\0\0") << "h''";
301     QTest::newRow("emptytextstring*4") << raw("\x7a\0\0\0\0") << "\"\"";
302     QTest::newRow("emptybytestring*8") << raw("\x5b\0\0\0\0\0\0\0\0") << "h''";
303     QTest::newRow("emptytextstring*8") << raw("\x7b\0\0\0\0\0\0\0\0") << "\"\"";
304     QTest::newRow("bytestring5*1") << raw("\x58\x05Hello") << "h'48656c6c6f'";
305     QTest::newRow("textstring5*1") << raw("\x78\x05Hello") << "\"Hello\"";
306     QTest::newRow("bytestring5*2") << raw("\x59\0\5Hello") << "h'48656c6c6f'";
307     QTest::newRow("textstring5*2") << raw("\x79\0\x05Hello") << "\"Hello\"";
308     QTest::newRow("bytestring5*4") << raw("\x5a\0\0\0\5Hello") << "h'48656c6c6f'";
309     QTest::newRow("textstring5*4") << raw("\x7a\0\0\0\x05Hello") << "\"Hello\"";
310     QTest::newRow("bytestring5*8") << raw("\x5b\0\0\0\0\0\0\0\5Hello") << "h'48656c6c6f'";
311     QTest::newRow("textstring5*8") << raw("\x7b\0\0\0\0\0\0\0\x05Hello") << "\"Hello\"";
312
313     // strings with undefined length
314     QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "h''";
315     QTest::newRow("_emptytextstring") << raw("\x7f\xff") << "\"\"";
316     QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << "h''";
317     QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << "\"\"";
318     QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << "h''";
319     QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << "\"\"";
320     QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << "h'48656c6c6f'";
321     QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << "\"Hello\"";
322     QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << "h'48656c6c6f'";
323     QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "\"Hello\"";
324     QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << "h'48656c6c6f'";
325     QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << "\"Hello\"";
326 }
327
328 void tst_Parser::strings_data()
329 {
330     addColumns();
331     addStringsData();
332 }
333
334 void addTagsData()
335 {
336     // since parseOne() works recursively for tags, we can't test lone tags
337     QTest::newRow("tag0") << raw("\xc0\x00") << "0(0)";
338     QTest::newRow("tag1") << raw("\xc1\x00") << "1(0)";
339     QTest::newRow("tag24") << raw("\xd8\x18\x00") << "24(0)";
340     QTest::newRow("tag255") << raw("\xd8\xff\x00") << "255(0)";
341     QTest::newRow("tag256") << raw("\xd9\1\0\x00") << "256(0)";
342     QTest::newRow("tag65535") << raw("\xd9\xff\xff\x00") << "65535(0)";
343     QTest::newRow("tag65536") << raw("\xda\0\1\0\0\x00") << "65536(0)";
344     QTest::newRow("tagUINT32_MAX-1") << raw("\xda\xff\xff\xff\xff\x00") << "4294967295(0)";
345     QTest::newRow("tagUINT32_MAX") << raw("\xdb\0\0\0\1\0\0\0\0\x00") << "4294967296(0)";
346     QTest::newRow("tagUINT64_MAX") << raw("\xdb" "\xff\xff\xff\xff" "\xff\xff\xff\xff" "\x00")
347                                 << QString::number(std::numeric_limits<uint64_t>::max()) + "(0)";
348
349     // overlong tags
350     QTest::newRow("tag0*1") << raw("\xd8\0\x00") << "0(0)";
351     QTest::newRow("tag0*2") << raw("\xd9\0\0\x00") << "0(0)";
352     QTest::newRow("tag0*4") << raw("\xda\0\0\0\0\x00") << "0(0)";
353     QTest::newRow("tag0*8") << raw("\xdb\0\0\0\0\0\0\0\0\x00") << "0(0)";
354
355     // tag other things
356     QTest::newRow("unixtime") << raw("\xc1\x1a\x55\x4b\xbf\xd3") << "1(1431027667)";
357     QTest::newRow("rfc3339date") << raw("\xc0\x78\x19" "2015-05-07 12:41:07-07:00")
358                                  << "0(\"2015-05-07 12:41:07-07:00\")";
359     QTest::newRow("tag6+false") << raw("\xc6\xf4") << "6(false)";
360     QTest::newRow("tag25+true") << raw("\xd8\x19\xf5") << "25(true)";
361     QTest::newRow("tag256+null") << raw("\xd9\1\0\xf6") << "256(null)";
362     QTest::newRow("tag65536+simple32") << raw("\xda\0\1\0\0\xf8\x20") << "65536(simple(32))";
363     QTest::newRow("float+unixtime") << raw("\xc1\xfa\x4e\xaa\x97\x80") << "1(1431027712.f)";
364     QTest::newRow("double+unixtime") << raw("\xc1\xfb" "\x41\xd5\x52\xef" "\xf4\xc7\xce\xfe")
365                                      << "1(1431027667.1220088)";
366 }
367
368 void tst_Parser::tags_data()
369 {
370     addColumns();
371     addTagsData();
372 }
373
374 void tst_Parser::tagTags()
375 {
376     QFETCH(QByteArray, data);
377     QFETCH(QString, expected);
378
379     compareOne("\xd9\xd9\xf7" + data, "55799(" + expected + ')');
380     if (!compareFailed)
381         compareOne("\xd9\xd9\xf7" "\xd9\xd9\xf7" + data, "55799(55799(" + expected + "))");
382 }
383
384 void addEmptyContainersData()
385 {
386     QTest::newRow("emptyarray") << raw("\x80") << "[]" << 0;
387     QTest::newRow("emptymap") << raw("\xa0") << "{}" << 0;
388     QTest::newRow("_emptyarray") << raw("\x9f\xff") << "[_ ]" << -1;
389     QTest::newRow("_emptymap") << raw("\xbf\xff") << "{_ }" << -1;
390 }
391
392 void tst_Parser::emptyContainers_data()
393 {
394     addColumns();
395     addEmptyContainersData();
396 }
397
398 void tst_Parser::emptyContainers()
399 {
400     QFETCH(QByteArray, data);
401     QFETCH(QString, expected);
402     QFETCH(int, n);
403
404     compareOneSize(n, data, expected);
405 }
406
407 void tst_Parser::arrays_data()
408 {
409     addColumns();
410     addFixedData();
411     addStringsData();
412     addTagsData();
413 }
414
415 void tst_Parser::arrays()
416 {
417     QFETCH(QByteArray, data);
418     QFETCH(QString, expected);
419
420     compareOneSize(1, "\x81" + data, '[' + expected + ']');
421     if (compareFailed) return;
422
423     compareOneSize(2, "\x82" + data + data, '[' + expected + ", " + expected + ']');
424     if (compareFailed) return;
425
426     // overlong length
427     compareOneSize(1, "\x98\1" + data, '[' + expected + ']');
428     if (compareFailed) return;
429     compareOneSize(1, raw("\x99\0\1") + data, '[' + expected + ']');
430     if (compareFailed) return;
431     compareOneSize(1, raw("\x9a\0\0\0\1") + data, '[' + expected + ']');
432     if (compareFailed) return;
433     compareOneSize(1, raw("\x9b\0\0\0\0\0\0\0\1") + data, '[' + expected + ']');
434     if (compareFailed) return;
435
436     // medium-sized array: 32 elements (1 << 5)
437     expected += ", ";
438     for (int i = 0; i < 5; ++i) {
439         data += data;
440         expected += expected;
441     }
442     expected.chop(2);   // remove the last ", "
443     compareOneSize(32, "\x98\x20" + data, '[' + expected + ']');
444     if (compareFailed) return;
445
446     // large array: 256 elements (32 << 3)
447     expected += ", ";
448     for (int i = 0; i < 3; ++i) {
449         data += data;
450         expected += expected;
451     }
452     expected.chop(2);   // remove the last ", "
453     compareOneSize(256, raw("\x99\1\0") + data, '[' + expected + ']');
454     if (compareFailed) return;
455 }
456
457 void tst_Parser::undefLengthArrays()
458 {
459     QFETCH(QByteArray, data);
460     QFETCH(QString, expected);
461
462     compareOne("\x9f" + data + "\xff", "[_ " + expected + ']');
463     if (compareFailed) return;
464
465     compareOne("\x9f" + data + data + "\xff", "[_ " + expected + ", " + expected + ']');
466 }
467
468 void tst_Parser::nestedArrays()
469 {
470     QFETCH(QByteArray, data);
471     QFETCH(QString, expected);
472
473     compareOneSize(1, "\x81\x81" + data, "[[" + expected + "]]");
474     if (compareFailed) return;
475
476     compareOneSize(1, "\x81\x81\x81" + data, "[[[" + expected + "]]]");
477     if (compareFailed) return;
478
479     compareOneSize(1, "\x81\x82" + data + data, "[[" + expected + ", " + expected + "]]");
480     if (compareFailed) return;
481
482     compareOneSize(2, "\x82\x81" + data + data, "[[" + expected + "], " + expected + "]");
483     if (compareFailed) return;
484
485     compareOneSize(2, "\x82\x81" + data + '\x81' + data, "[[" + expected + "], [" + expected + "]]");
486     if (compareFailed) return;
487
488     // undefined length
489     compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\xff", "[_ [_ " + expected + ", " + expected + "]]");
490     if (compareFailed) return;
491
492     compareOneSize(-1, "\x9f\x9f" + data + "\xff\x9f" + data + "\xff\xff", "[_ [_ " + expected + "], [_ " + expected + "]]");
493     if (compareFailed) return;
494
495     compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\x9f" + data + "\xff\xff",
496                "[_ [_ " + expected + ", " + expected + "], [_ " + expected + "]]");
497     if (compareFailed) return;
498
499     // mix them
500     compareOneSize(1, "\x81\x9f" + data + "\xff", "[[_ " + expected + "]]");
501     if (compareFailed) return;
502
503     compareOneSize(-1, "\x9f\x81" + data + "\xff", "[_ [" + expected + "]]");
504 }
505
506 void tst_Parser::maps_data()
507 {
508     arrays_data();
509 }
510
511 void tst_Parser::maps()
512 {
513     QFETCH(QByteArray, data);
514     QFETCH(QString, expected);
515
516     // integer key
517     compareOneSize(1, "\xa1\1" + data, "{1: " + expected + '}');
518     if (compareFailed) return;
519
520     // string key
521     compareOneSize(1, "\xa1\x65" "Hello" + data, "{\"Hello\": " + expected + '}');
522     if (compareFailed) return;
523
524     // map to self
525     compareOneSize(1, "\xa1" + data + data, '{' + expected + ": " + expected + '}');
526     if (compareFailed) return;
527
528     // two integer keys
529     compareOneSize(2, "\xa2\1" + data + "\2" + data, "{1: " + expected + ", 2: " + expected + '}');
530     if (compareFailed) return;
531
532     // OneSize integer and OneSize string key
533     compareOneSize(2, "\xa2\1" + data + "\x65" "Hello" + data, "{1: " + expected + ", \"Hello\": " + expected + '}');
534     if (compareFailed) return;
535 }
536
537 void tst_Parser::undefLengthMaps()
538 {
539     QFETCH(QByteArray, data);
540     QFETCH(QString, expected);
541
542     // integer key
543     compareOne("\xbf\1" + data + '\xff', "{_ 1: " + expected + '}');
544     if (compareFailed) return;
545
546     compareOne("\xbf\1" + data + '\2' + data + '\xff', "{_ 1: " + expected + ", 2: " + expected + '}');
547     if (compareFailed) return;
548
549     compareOne("\xbf\1" + data + "\x65Hello" + data + '\xff', "{_ 1: " + expected + ", \"Hello\": " + expected + '}');
550     if (compareFailed) return;
551
552     compareOne("\xbf\x65Hello" + data + '\1' + data + '\xff', "{_ \"Hello\": " + expected + ", 1: " + expected + '}');
553 }
554
555 void tst_Parser::nestedMaps()
556 {
557     QFETCH(QByteArray, data);
558     QFETCH(QString, expected);
559
560     // nested maps as values
561     compareOneSize(1, "\xa1\1\xa1\2" + data, "{1: {2: " + expected + "}}");
562     if (compareFailed) return;
563
564     compareOneSize(1, "\xa1\x65Hello\xa1\2" + data, "{\"Hello\": {2: " + expected + "}}");
565     if (compareFailed) return;
566
567     compareOneSize(1, "\xa1\1\xa2\2" + data + '\x20' + data, "{1: {2: " + expected + ", -1: " + expected + "}}");
568     if (compareFailed) return;
569
570     compareOneSize(2, "\xa2\1\xa1\2" + data + "\2\xa1\x20" + data, "{1: {2: " + expected + "}, 2: {-1: " + expected + "}}");
571     if (compareFailed) return;
572
573     // nested maps as keys
574     compareOneSize(1, "\xa1\xa1\xf4" + data + "\xf5", "{{false: " + expected + "}: true}");
575     if (compareFailed) return;
576
577     compareOneSize(1, "\xa1\xa1" + data + data + "\xa1" + data + data,
578                "{{" + expected + ": " + expected + "}: {" + expected + ": " + expected + "}}");
579     if (compareFailed) return;
580
581     // undefined length
582     compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\xff", "{_ 1: {_ 2: " + expected + "}}");
583     if (compareFailed) return;
584
585     compareOneSize(-1, "\xbf\1\xbf\2" + data + '\x20' + data + "\xff\xff", "{_ 1: {_ 2: " + expected + ", -1: " + expected + "}}");
586     if (compareFailed) return;
587
588     compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\2\xbf\x20" + data + "\xff\xff",
589                "{_ 1: {_ 2: " + expected + "}, 2: {_ -1: " + expected + "}}");
590     if (compareFailed) return;
591
592     compareOneSize(-1, "\xbf\xbf" + data + data + "\xff\xbf" + data + data + "\xff\xff",
593                "{_ {_ " + expected + ": " + expected + "}: {_ " + expected + ": " + expected + "}}");
594     if (compareFailed) return;
595
596     // mix them
597     compareOneSize(1, "\xa1\1\xbf\2" + data + "\xff", "{1: {_ 2: " + expected + "}}");
598     if (compareFailed) return;
599
600     compareOneSize(-1, "\xbf\1\xa1\2" + data + "\xff", "{_ 1: {2: " + expected + "}}");
601     if (compareFailed) return;
602 }
603
604 void addMapMixedData()
605 {
606     QTest::newRow("map-0-24") << raw("\xa1\0\x18\x18") << "{0: 24}" << 1;
607     QTest::newRow("map-0*1-24") << raw("\xa1\x18\0\x18\x18") << "{0: 24}" << 1;
608     QTest::newRow("map-0*1-24*2") << raw("\xa1\x18\0\x19\0\x18") << "{0: 24}" << 1;
609     QTest::newRow("map-0*4-24*2") << raw("\xa1\x1a\0\0\0\0\x19\0\x18") << "{0: 24}" << 1;
610     QTest::newRow("map-24-0") << raw("\xa1\x18\x18\0") << "{24: 0}" << 1;
611     QTest::newRow("map-24-0*1") << raw("\xa1\x18\x18\0") << "{24: 0}" << 1;
612     QTest::newRow("map-255-65535") << raw("\xa1\x18\xff\x19\xff\xff") << "{255: 65535}" << 1;
613
614     QTest::newRow("_map-0-24") << raw("\xbf\0\x18\x18\xff") << "{_ 0: 24}" << 1;
615     QTest::newRow("_map-0*1-24") << raw("\xbf\x18\0\x18\x18\xff") << "{_ 0: 24}" << 1;
616     QTest::newRow("_map-0*1-24*2") << raw("\xbf\x18\0\x19\0\x18\xff") << "{_ 0: 24}" << 1;
617     QTest::newRow("_map-0*4-24*2") << raw("\xbf\x1a\0\0\0\0\x19\0\x18\xff") << "{_ 0: 24}" << 1;
618     QTest::newRow("_map-24-0") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}" << 1;
619     QTest::newRow("_map-24-0*1") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}" << 1;
620     QTest::newRow("_map-255-65535") << raw("\xbf\x18\xff\x19\xff\xff\xff") << "{_ 255: 65535}" << 1;
621 }
622
623 void tst_Parser::mapMixed_data()
624 {
625     addColumns();
626     addMapMixedData();
627 }
628
629 void tst_Parser::mapsAndArrays()
630 {
631     QFETCH(QByteArray, data);
632     QFETCH(QString, expected);
633
634     // arrays of maps
635     compareOneSize(1, "\x81\xa1\1" + data, "[{1: " + expected + "}]");
636     if (compareFailed) return;
637
638     compareOneSize(2, "\x82\xa1\1" + data + "\xa1\2" + data, "[{1: " + expected + "}, {2: " + expected + "}]");
639     if (compareFailed) return;
640
641     compareOneSize(1, "\x81\xa2\1" + data + "\2" + data, "[{1: " + expected + ", 2: " + expected + "}]");
642     if (compareFailed) return;
643
644     compareOneSize(-1, "\x9f\xa1\1" + data + "\xff", "[_ {1: " + expected + "}]");
645     if (compareFailed) return;
646
647     compareOneSize(1, "\x81\xbf\1" + data + "\xff", "[{_ 1: " + expected + "}]");
648     if (compareFailed) return;
649
650     compareOneSize(-1, "\x9f\xbf\1" + data + "\xff\xff", "[_ {_ 1: " + expected + "}]");
651     if (compareFailed) return;
652
653     // maps of arrays
654     compareOneSize(1, "\xa1\1\x81" + data, "{1: [" + expected + "]}");
655     if (compareFailed) return;
656
657     compareOneSize(1, "\xa1\1\x82" + data + data, "{1: [" + expected + ", " + expected + "]}");
658     if (compareFailed) return;
659
660     compareOneSize(2, "\xa2\1\x81" + data + "\x65Hello\x81" + data, "{1: [" + expected + "], \"Hello\": [" + expected + "]}");
661     if (compareFailed) return;
662
663     compareOneSize(1, "\xa1\1\x9f" + data + "\xff", "{1: [_ " + expected + "]}");
664     if (compareFailed) return;
665
666     compareOneSize(1, "\xa1\1\x9f" + data + data + "\xff", "{1: [_ " + expected + ", " + expected + "]}");
667     if (compareFailed) return;
668
669     compareOneSize(-1, "\xbf\1\x81" + data + "\xff", "{_ 1: [" + expected + "]}");
670     if (compareFailed) return;
671
672     compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\xff", "{_ 1: [_ " + expected + "]}");
673     if (compareFailed) return;
674
675     compareOneSize(-1, "\xbf\1\x9f" + data + data + "\xff\xff", "{_ 1: [_ " + expected + ", " + expected + "]}");
676     if (compareFailed) return;
677
678     // mixed with indeterminate length strings
679     compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\x65Hello\xbf" + data + "\x7f\xff\xff\xff",
680                    "{_ 1: [_ " + expected + "], \"Hello\": {_ " + expected + ": \"\"}}");
681 }
682
683 void tst_Parser::stringLength_data()
684 {
685     QTest::addColumn<QByteArray>("data");
686     QTest::addColumn<int>("expected");
687
688     QTest::newRow("emptybytestring") << raw("\x40") << 0;
689     QTest::newRow("bytestring1") << raw("\x41 ") << 1;
690     QTest::newRow("bytestring1-nul") << raw("\x41\0") << 1;
691     QTest::newRow("bytestring5") << raw("\x45Hello") << 5;
692     QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234") << 24;
693     QTest::newRow("bytestring256") << raw("\x59\1\0") + QByteArray(256, '3') << 256;
694
695     // text strings
696     QTest::newRow("emptytextstring") << raw("\x60") << 0;
697     QTest::newRow("textstring1") << raw("\x61 ") << 1;
698     QTest::newRow("textstring1-nul") << raw("\x61\0") << 1;
699     QTest::newRow("textstring5") << raw("\x65Hello") << 5;
700     QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234") << 24;
701     QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3') << 256;
702
703     // strings with overlong length
704     QTest::newRow("emptybytestring*1") << raw("\x58\x00") << 0;
705     QTest::newRow("emptytextstring*1") << raw("\x78\x00") << 0;
706     QTest::newRow("emptybytestring*2") << raw("\x59\x00\x00") << 0;
707     QTest::newRow("emptytextstring*2") << raw("\x79\x00\x00") << 0;
708     QTest::newRow("emptybytestring*4") << raw("\x5a\0\0\0\0") << 0;
709     QTest::newRow("emptytextstring*4") << raw("\x7a\0\0\0\0") << 0;
710     QTest::newRow("emptybytestring*8") << raw("\x5b\0\0\0\0\0\0\0\0") << 0;
711     QTest::newRow("emptytextstring*8") << raw("\x7b\0\0\0\0\0\0\0\0") << 0;
712     QTest::newRow("bytestring5*1") << raw("\x58\x05Hello") << 5;
713     QTest::newRow("textstring5*1") << raw("\x78\x05Hello") << 5;
714     QTest::newRow("bytestring5*2") << raw("\x59\0\5Hello") << 5;
715     QTest::newRow("textstring5*2") << raw("\x79\0\x05Hello") << 5;
716     QTest::newRow("bytestring5*4") << raw("\x5a\0\0\0\5Hello") << 5;
717     QTest::newRow("textstring5*4") << raw("\x7a\0\0\0\x05Hello") << 5;
718     QTest::newRow("bytestring5*8") << raw("\x5b\0\0\0\0\0\0\0\5Hello") << 5;
719     QTest::newRow("textstring5*8") << raw("\x7b\0\0\0\0\0\0\0\x05Hello") << 5;
720
721     // strings with undefined length
722     QTest::newRow("_emptybytestring") << raw("\x5f\xff") << 0;
723     QTest::newRow("_emptytextstring") << raw("\x7f\xff") << 0;
724     QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << 0;
725     QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << 0;
726     QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << 0;
727     QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << 0;
728     QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << 5;
729     QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << 5;
730     QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << 5;
731     QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << 5;
732     QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << 5;
733     QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << 5;
734 }
735
736 void tst_Parser::stringLength()
737 {
738     QFETCH(QByteArray, data);
739     QFETCH(int, expected);
740
741     CborParser parser;
742     CborValue value;
743     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
744     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
745
746     size_t result;
747     err = cbor_value_calculate_string_length(&value, &result);
748     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
749     QCOMPARE(result, size_t(expected));
750 }
751
752 void tst_Parser::stringCompare_data()
753 {
754     QTest::addColumn<QByteArray>("data");
755     QTest::addColumn<QString>("string");
756     QTest::addColumn<bool>("expected");
757
758     // compare empty to empty
759     QTest::newRow("empty-empty") << raw("\x60") << QString() << true;
760     QTest::newRow("_empty-empty") << raw("\x7f\xff") << QString() << true;
761     QTest::newRow("_empty*1-empty") << raw("\x7f\x60\xff") << QString() << true;
762     QTest::newRow("_empty*2-empty") << raw("\x7f\x60\x60\xff") << QString() << true;
763
764     // compare empty to non-empty
765     QTest::newRow("empty-nonempty") << raw("\x60") << "Hello" << false;
766     QTest::newRow("_empty-nonempty") << raw("\x7f\xff") << "Hello" << false;
767     QTest::newRow("_empty*1-nonempty") << raw("\x7f\x60\xff") << "Hello" << false;
768     QTest::newRow("_empty*2-nonempty") << raw("\x7f\x60\x60\xff") << "Hello" << false;
769
770     // compare same strings
771     QTest::newRow("same-short-short") << raw("\x65Hello") << "Hello" << true;
772     QTest::newRow("same-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello" << true;
773     QTest::newRow("same-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello" << true;
774     QTest::newRow("same-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello" << true;
775     QTest::newRow("same-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello" << true;
776     QTest::newRow("same-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
777                                     << "Good morning, good afternoon and goodnight" << true;
778     QTest::newRow("same-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
779                                        << "Good morning, good afternoon and goodnight" << true;
780     QTest::newRow("same-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
781                                        << "Good morning, good afternoon and goodnight" << true;
782
783     // compare different strings (same length)
784     QTest::newRow("diff-same-length-short-short") << raw("\x65Hello") << "World" << false;
785     QTest::newRow("diff-same-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "World" << false;
786     QTest::newRow("diff-same-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "World" << false;
787     QTest::newRow("diff-same-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "World" << false;
788     QTest::newRow("diff-same-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "World" << false;
789     QTest::newRow("diff-same-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
790                                                 << "Good morning, good afternoon and goodnight, world" << false;
791     QTest::newRow("diff-same-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
792                                                    << "Good morning, good afternoon and goodnight, world" << false;
793     QTest::newRow("diff-same-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
794                                                    << "Good morning, good afternoon and goodnight, world" << false;
795
796     // compare different strings (different length)
797     QTest::newRow("diff-diff-length-short-short") << raw("\x65Hello") << "Hello World" << false;
798     QTest::newRow("diff-diff-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello World" << false;
799     QTest::newRow("diff-diff-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello World" << false;
800     QTest::newRow("diff-diff-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello World" << false;
801     QTest::newRow("diff-diff-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello World" << false;
802     QTest::newRow("diff-diff-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight")
803                                                 << "Good morning, good afternoon and goodnight World" << false;
804     QTest::newRow("diff-diff-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff")
805                                                    << "Good morning, good afternoon and goodnight World" << false;
806     QTest::newRow("diff-diff-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff")
807                                                    << "Good morning, good afternoon and goodnight World" << false;
808
809     // compare against non-strings
810     QTest::newRow("unsigned") << raw("\0") << "0" << false;
811     QTest::newRow("negative") << raw("\x20") << "-1" << false;
812     QTest::newRow("emptybytestring") << raw("\x40") << "" << false;
813     QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "" << false;
814     QTest::newRow("shortbytestring") << raw("\x45Hello") << "Hello" << false;
815     QTest::newRow("longbytestring") << raw("\x58\x2aGood morning, good afternoon and goodnight")
816                                     << "Good morning, good afternoon and goodnight" << false;
817     QTest::newRow("emptyarray") << raw("\x80") << "" << false;
818     QTest::newRow("emptymap") << raw("\xa0") << "" << false;
819     QTest::newRow("array") << raw("\x81\x65Hello") << "Hello" << false;
820     QTest::newRow("map") << raw("\xa1\x65Hello\x65World") << "Hello World" << false;
821     QTest::newRow("false") << raw("\xf4") << "false" << false;
822     QTest::newRow("true") << raw("\xf5") << "true" << false;
823     QTest::newRow("null") << raw("\xf6") << "null" << false;
824 }
825
826 void compareOneString(const QByteArray &data, const QString &string, bool expected, int line)
827 {
828     compareFailed = true;
829
830     CborParser parser;
831     CborValue value;
832     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
833     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
834
835     bool result;
836     err = cbor_value_text_string_equals(&value, string.toUtf8().constData(), &result);
837     QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
838     QCOMPARE(result, expected);
839
840     compareFailed = false;
841 }
842 #define compareOneString(data, string, expected) compareOneString(data, string, expected, __LINE__)
843
844 void tst_Parser::stringCompare()
845 {
846     QFETCH(QByteArray, data);
847     QFETCH(QString, string);
848     QFETCH(bool, expected);
849
850     compareOneString(data, string, expected);
851     if (compareFailed) return;
852
853     // tag it
854     compareOneString("\xc1" + data, string, expected);
855     if (compareFailed) return;
856
857     compareOneString("\xc1\xc2" + data, string, expected);
858 }
859
860 void tst_Parser::mapFind_data()
861 {
862     // Rules:
863     //  we are searching for string "needle"
864     //  if present, the value should be the string "haystack" (with tag 42)
865
866     QTest::addColumn<QByteArray>("data");
867     QTest::addColumn<bool>("expected");
868
869     QTest::newRow("emptymap") << raw("\xa0") << false;
870     QTest::newRow("_emptymap") << raw("\xbf\xff") << false;
871
872     // maps not containing our items
873     QTest::newRow("absent-unsigned-unsigned") << raw("\xa1\0\0") << false;
874     QTest::newRow("absent-taggedunsigned-unsigned") << raw("\xa1\xc0\0\0") << false;
875     QTest::newRow("absent-unsigned-taggedunsigned") << raw("\xa1\0\xc0\0") << false;
876     QTest::newRow("absent-taggedunsigned-taggedunsigned") << raw("\xa1\xc0\0\xc0\0") << false;
877     QTest::newRow("absent-string-unsigned") << raw("\xa1\x68haystack\0") << false;
878     QTest::newRow("absent-taggedstring-unsigned") << raw("\xa1\xc0\x68haystack\0") << false;
879     QTest::newRow("absent-string-taggedunsigned") << raw("\xa1\x68haystack\xc0\0") << false;
880     QTest::newRow("absent-taggedstring-taggedunsigned") << raw("\xa1\xc0\x68haystack\xc0\0") << false;
881     QTest::newRow("absent-string-string") << raw("\xa1\x68haystack\x66needle") << false;
882     QTest::newRow("absent-string-taggedstring") << raw("\xa1\x68haystack\xc0\x66needle") << false;
883     QTest::newRow("absent-taggedstring-string") << raw("\xa1\xc0\x68haystack\x66needle") << false;
884     QTest::newRow("absent-string-taggedstring") << raw("\xa1\xc0\x68haystack\xc0\x66needle") << false;
885
886     QTest::newRow("absent-string-emptyarray") << raw("\xa1\x68haystack\x80") << false;
887     QTest::newRow("absent-string-_emptyarray") << raw("\xa1\x68haystack\x9f\xff") << false;
888     QTest::newRow("absent-string-array1") << raw("\xa1\x68haystack\x81\0") << false;
889     QTest::newRow("absent-string-array2") << raw("\xa1\x68haystack\x85\0\1\2\3\4") << false;
890     QTest::newRow("absent-string-array3") << raw("\xa1\x68haystack\x85\x63one\x63two\x65three\x64""four\x64""five") << false;
891
892     QTest::newRow("absent-string-emptymap") << raw("\xa1\x68haystack\xa0") << false;
893     QTest::newRow("absent-string-_emptymap") << raw("\xa1\x68haystack\xbf\xff") << false;
894     QTest::newRow("absent-string-map") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle") << false;
895     QTest::newRow("absent-string-map2") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle\61z\62yx") << false;
896
897     // maps containing our items
898     QTest::newRow("alone") << raw("\xa1\x66needle\xd8\x2a\x68haystack") << true;
899     QTest::newRow("tagged") << raw("\xa1\xc1\x66needle\xd8\x2a\x68haystack") << true;
900     QTest::newRow("doubletagged") << raw("\xa1\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true;
901     QTest::newRow("chunked") << raw("\xa1\x7f\x66needle\xff\xd8\x2a\x68haystack") << true;
902     QTest::newRow("chunked*2") << raw("\xa1\x7f\x60\x66needle\xff\xd8\x2a\x68haystack") << true;
903     QTest::newRow("chunked*2bis") << raw("\xa1\x7f\x66needle\x60\xff\xd8\x2a\x68haystack") << true;
904     QTest::newRow("chunked*3") << raw("\xa1\x7f\x62ne\x62""ed\x62le\xff\xd8\x2a\x68haystack") << true;
905     QTest::newRow("chunked*8") << raw("\xa1\x7f\x61n\x61""e\x60\x61""e\x61""d\x60\x62le\x60\xff\xd8\x2a\x68haystack") << true;
906
907     QTest::newRow("1before") << raw("\xa2\x68haystack\x66needle\x66needle\xd8\x2a\x68haystack") << true;
908     QTest::newRow("tagged-1before") << raw("\xa2\xc1\x68haystack\x66needle\xc1\x66needle\xd8\x2a\x68haystack") << true;
909     QTest::newRow("doubletagged-1before2") << raw("\xa2\xc1\xc2\x68haystack\x66needle\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true;
910
911     QTest::newRow("arraybefore") << raw("\xa2\x61z\x80\x66needle\xd8\x2a\x68haystack") << true;
912     QTest::newRow("nestedarraybefore") << raw("\xa2\x61z\x81\x81\0\x66needle\xd8\x2a\x68haystack") << true;
913     QTest::newRow("arrayarraybefore") << raw("\xa2\x82\1\2\x80\x66needle\xd8\x2a\x68haystack") << true;
914
915     QTest::newRow("mapbefore") << raw("\xa2\x61z\xa0\x66needle\xd8\x2a\x68haystack") << true;
916     QTest::newRow("nestedmapbefore") << raw("\xa2\x61z\xa1\0\x81\0\x66needle\xd8\x2a\x68haystack") << true;
917     QTest::newRow("mapmapbefore") << raw("\xa2\xa1\1\2\xa0\x66needle\xd8\x2a\x68haystack") << true;
918 }
919
920 void tst_Parser::mapFind()
921 {
922     QFETCH(QByteArray, data);
923     QFETCH(bool, expected);
924
925     CborParser parser;
926     CborValue value;
927     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
928     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
929
930     CborValue element;
931     err = cbor_value_map_find_value(&value, "needle", &element);
932     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
933
934     if (expected) {
935         QCOMPARE(int(element.type), int(CborTagType));
936
937         CborTag tag;
938         err = cbor_value_get_tag(&element, &tag);
939         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
940         QCOMPARE(int(tag), 42);
941
942         bool equals;
943         err = cbor_value_text_string_equals(&element, "haystack", &equals);
944         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
945         QVERIFY(equals);
946     } else {
947         QCOMPARE(int(element.type), int(CborInvalidType));
948     }
949 }
950
951 void tst_Parser::validation_data()
952 {
953     QTest::addColumn<QByteArray>("data");
954     QTest::addColumn<int>("flags");     // future
955     QTest::addColumn<CborError>("expectedError");
956     QTest::addColumn<int>("offset");
957
958     // illegal numbers are future extension points
959     QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber << 1;
960     QTest::newRow("illegal-number-in-unsigned-2") << raw("\x81\x1d") << 0 << CborErrorIllegalNumber << 1;
961     QTest::newRow("illegal-number-in-unsigned-3") << raw("\x81\x1e") << 0 << CborErrorIllegalNumber << 1;
962     QTest::newRow("illegal-number-in-unsigned-4") << raw("\x81\x1f") << 0 << CborErrorIllegalNumber << 1;
963     QTest::newRow("illegal-number-in-negative-1") << raw("\x81\x3c") << 0 << CborErrorIllegalNumber << 1;
964     QTest::newRow("illegal-number-in-negative-2") << raw("\x81\x3d") << 0 << CborErrorIllegalNumber << 1;
965     QTest::newRow("illegal-number-in-negative-3") << raw("\x81\x3e") << 0 << CborErrorIllegalNumber << 1;
966     QTest::newRow("illegal-number-in-negative-4") << raw("\x81\x3f") << 0 << CborErrorIllegalNumber << 1;
967     QTest::newRow("illegal-number-in-bytearray-length-1") << raw("\x81\x5c") << 0 << CborErrorIllegalNumber << 1;
968     QTest::newRow("illegal-number-in-bytearray-length-2") << raw("\x81\x5d") << 0 << CborErrorIllegalNumber << 1;
969     QTest::newRow("illegal-number-in-bytearray-length-3") << raw("\x81\x5e") << 0 << CborErrorIllegalNumber << 1;
970     QTest::newRow("illegal-number-in-string-length-1") << raw("\x81\x7c") << 0 << CborErrorIllegalNumber << 1;
971     QTest::newRow("illegal-number-in-string-length-2") << raw("\x81\x7d") << 0 << CborErrorIllegalNumber << 1;
972     QTest::newRow("illegal-number-in-string-length-3") << raw("\x81\x7e") << 0 << CborErrorIllegalNumber << 1;
973     QTest::newRow("illegal-number-in-array-length-1") << raw("\x81\x9c") << 0 << CborErrorIllegalNumber << 1;
974     QTest::newRow("illegal-number-in-array-length-2") << raw("\x81\x9d") << 0 << CborErrorIllegalNumber << 1;
975     QTest::newRow("illegal-number-in-array-length-3") << raw("\x81\x9e") << 0 << CborErrorIllegalNumber << 1;
976     QTest::newRow("illegal-number-in-map-length-1") << raw("\x81\xbc") << 0 << CborErrorIllegalNumber << 1;
977     QTest::newRow("illegal-number-in-map-length-2") << raw("\x81\xbd") << 0 << CborErrorIllegalNumber << 1;
978     QTest::newRow("illegal-number-in-map-length-3") << raw("\x81\xbe") << 0 << CborErrorIllegalNumber << 1;
979
980     QTest::newRow("number-too-short-1-0") << raw("\x81\x18") << 0 << CborErrorUnexpectedEOF << 1;   // requires 1 byte, 0 given
981     QTest::newRow("number-too-short-2-0") << raw("\x81\x19") << 0 << CborErrorUnexpectedEOF << 1;   // requires 2 bytes, 0 given
982     QTest::newRow("number-too-short-2-1") << raw("\x81\x19\x01") << 0 << CborErrorUnexpectedEOF << 1; // etc
983     QTest::newRow("number-too-short-4-0") << raw("\x81\x1a") << 0 << CborErrorUnexpectedEOF << 1;
984     QTest::newRow("number-too-short-4-3") << raw("\x81\x1a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
985     QTest::newRow("number-too-short-8-0") << raw("\x81\x1b") << 0 << CborErrorUnexpectedEOF << 1;
986     QTest::newRow("number-too-short-8-7") << raw("\x81\x1b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
987     QTest::newRow("bytearray-length-too-short-1-0") << raw("\x81\x38") << 0 << CborErrorUnexpectedEOF << 1;
988     QTest::newRow("bytearray-length-too-short-2-0") << raw("\x81\x39") << 0 << CborErrorUnexpectedEOF << 1;
989     QTest::newRow("bytearray-length-too-short-2-1") << raw("\x81\x39\x01") << 0 << CborErrorUnexpectedEOF << 1;
990     QTest::newRow("bytearray-length-too-short-4-0") << raw("\x81\x3a") << 0 << CborErrorUnexpectedEOF << 1;
991     QTest::newRow("bytearray-length-too-short-4-3") << raw("\x81\x3a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
992     QTest::newRow("bytearray-length-too-short-8-0") << raw("\x81\x3b") << 0 << CborErrorUnexpectedEOF << 1;
993     QTest::newRow("bytearray-length-too-short-8-7") << raw("\x81\x3b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
994     QTest::newRow("string-length-too-short-1-0") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1;
995     QTest::newRow("string-length-too-short-2-0") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1;
996     QTest::newRow("string-length-too-short-2-1") << raw("\x81\x59\x01") << 0 << CborErrorUnexpectedEOF << 1;
997     QTest::newRow("string-length-too-short-4-0") << raw("\x81\x5a") << 0 << CborErrorUnexpectedEOF << 1;
998     QTest::newRow("string-length-too-short-4-3") << raw("\x81\x5a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
999     QTest::newRow("string-length-too-short-8-0") << raw("\x81\x5b") << 0 << CborErrorUnexpectedEOF << 1;
1000     QTest::newRow("string-length-too-short-8-7") << raw("\x81\x5b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
1001     QTest::newRow("array-length-too-short-1-0") << raw("\x81\x98") << 0 << CborErrorUnexpectedEOF << 1;
1002     QTest::newRow("array-length-too-short-2-0") << raw("\x81\x99") << 0 << CborErrorUnexpectedEOF << 1;
1003     QTest::newRow("array-length-too-short-2-1") << raw("\x81\x99\x01") << 0 << CborErrorUnexpectedEOF << 1;
1004     QTest::newRow("array-length-too-short-4-0") << raw("\x81\x9a") << 0 << CborErrorUnexpectedEOF << 1;
1005     QTest::newRow("array-length-too-short-4-3") << raw("\x81\x9a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
1006     QTest::newRow("array-length-too-short-8-0") << raw("\x81\x9b") << 0 << CborErrorUnexpectedEOF << 1;
1007     QTest::newRow("array-length-too-short-8-7") << raw("\x81\x9b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
1008     QTest::newRow("map-length-too-short-1-0") << raw("\x81\xb8") << 0 << CborErrorUnexpectedEOF << 1;
1009     QTest::newRow("map-length-too-short-2-0") << raw("\x81\xb9") << 0 << CborErrorUnexpectedEOF << 1;
1010     QTest::newRow("map-length-too-short-2-1") << raw("\x81\xb9\x01") << 0 << CborErrorUnexpectedEOF << 1;
1011     QTest::newRow("map-length-too-short-4-0") << raw("\x81\xba") << 0 << CborErrorUnexpectedEOF << 1;
1012     QTest::newRow("map-length-too-short-4-3") << raw("\x81\xba\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
1013     QTest::newRow("map-length-too-short-8-0") << raw("\x81\xbb") << 0 << CborErrorUnexpectedEOF << 1;
1014     QTest::newRow("map-length-too-short-8-7") << raw("\x81\xbb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
1015     QTest::newRow("tag-too-short-1-0") << raw("\x81\xd8") << 0 << CborErrorUnexpectedEOF << 1;
1016     QTest::newRow("tag-too-short-2-0") << raw("\x81\xd9") << 0 << CborErrorUnexpectedEOF << 1;
1017     QTest::newRow("tag-too-short-2-1") << raw("\x81\xd9\x01") << 0 << CborErrorUnexpectedEOF << 1;
1018     QTest::newRow("tag-too-short-4-0") << raw("\x81\xda") << 0 << CborErrorUnexpectedEOF << 1;
1019     QTest::newRow("tag-too-short-4-3") << raw("\x81\xda\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
1020     QTest::newRow("tag-too-short-8-0") << raw("\x81\xdb") << 0 << CborErrorUnexpectedEOF << 1;
1021     QTest::newRow("tag-too-short-8-7") << raw("\x81\xdb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
1022
1023     QTest::newRow("bytearray-too-short1") << raw("\x81\x41") << 0 << CborErrorUnexpectedEOF << 1;
1024     QTest::newRow("bytearray-too-short2") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1;
1025     QTest::newRow("bytearray-too-short3") << raw("\x81\x58\x01") << 0 << CborErrorUnexpectedEOF << 1;
1026     QTest::newRow("bytearray-too-short4") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1;
1027     QTest::newRow("bytearray-too-short5") << raw("\x81\x5a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
1028     QTest::newRow("bytearray-too-short6") << raw("\x81\x5b\0\0\0\0\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
1029     QTest::newRow("string-too-short1") << raw("\x81\x61") << 0 << CborErrorUnexpectedEOF << 1;
1030     QTest::newRow("string-too-short2") << raw("\x81\x78") << 0 << CborErrorUnexpectedEOF << 1;
1031     QTest::newRow("string-too-short3") << raw("\x81\x78\x01") << 0 << CborErrorUnexpectedEOF << 1;
1032     QTest::newRow("string-too-short4") << raw("\x81\x79") << 0 << CborErrorUnexpectedEOF << 1;
1033     QTest::newRow("string-too-short5") << raw("\x81\x7a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
1034     QTest::newRow("string-too-short6") << raw("\x81\x7b\0\0\0\0\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
1035     QTest::newRow("fp16-too-short1") << raw("\x81\xf9") << 0 << CborErrorUnexpectedEOF << 1;
1036     QTest::newRow("fp16-too-short2") << raw("\x81\xf9\x00") << 0 << CborErrorUnexpectedEOF << 1;
1037     QTest::newRow("float-too-short1") << raw("\x81\xfa") << 0 << CborErrorUnexpectedEOF << 1;
1038     QTest::newRow("float-too-short2") << raw("\x81\xfa\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
1039     QTest::newRow("double-too-short1") << raw("\x81\xfb") << 0 << CborErrorUnexpectedEOF << 1;
1040     QTest::newRow("double-too-short2") << raw("\x81\xfb\0\0\0\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
1041
1042     // check for pointer additions wrapping over the limit of the address space
1043     CborError tooLargeOn32bit = (sizeof(void *) == 4) ? CborErrorDataTooLarge : CborErrorUnexpectedEOF;
1044     // on 32-bit systems, this is a -1
1045     QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1;
1046     QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1;
1047     // on 32-bit systems, a 4GB addition could be dropped
1048     QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1;
1049     QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1;
1050     // on 64-bit systems, this could be a -1
1051     QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1;
1052     QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1;
1053
1054     // ditto on chunks
1055     QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1;
1056     QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1;
1057     // on 32-bit systems, a 4GB addition could be dropped
1058     QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1;
1059     QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1;
1060     // on 64-bit systems, this could be a -1
1061     QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1;
1062     QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1;
1063
1064     QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF << 1;
1065     QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF << 1;
1066     QTest::newRow("eof-after-array-element") << raw("\x81\x82\x01") << 0 << CborErrorUnexpectedEOF << 3;
1067     QTest::newRow("eof-after-object") << raw("\x81\xa1") << 0 << CborErrorUnexpectedEOF << 2;
1068     QTest::newRow("eof-after-object2") << raw("\x81\xb8\x20") << 0 << CborErrorUnexpectedEOF << 3;
1069     QTest::newRow("eof-after-object-key") << raw("\x81\xa1\x01") << 0 << CborErrorUnexpectedEOF << 3;
1070     QTest::newRow("eof-after-object-value") << raw("\x81\xa2\x01\x01") << 0 << CborErrorUnexpectedEOF << 4;
1071     QTest::newRow("eof-after-tag") << raw("\x81\xc0") << 0 << CborErrorUnexpectedEOF << 2;
1072     QTest::newRow("eof-after-tag2") << raw("\x81\xd8\x20") << 0 << CborErrorUnexpectedEOF << 3;
1073
1074     // major type 7 has future types
1075     QTest::newRow("future-type-28") << raw("\x81\xfc") << 0 << CborErrorUnknownType << 1;
1076     QTest::newRow("future-type-29") << raw("\x81\xfd") << 0 << CborErrorUnknownType << 1;
1077     QTest::newRow("future-type-30") << raw("\x81\xfe") << 0 << CborErrorUnknownType << 1;
1078     QTest::newRow("unexpected-break") << raw("\x81\xff") << 0 << CborErrorUnexpectedBreak << 1;
1079     QTest::newRow("illegal-simple-0") << raw("\x81\xf8\0") << 0 << CborErrorIllegalSimpleType << 1;
1080     QTest::newRow("illegal-simple-31") << raw("\x81\xf8\x1f") << 0 << CborErrorIllegalSimpleType << 1;
1081
1082     // not only too big (UINT_MAX or UINT_MAX+1 in size), but also incomplete
1083     if (sizeof(size_t) < sizeof(uint64_t)) {
1084         QTest::newRow("bytearray-too-big1") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1085         QTest::newRow("string-too-big1") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1086     }
1087     QTest::newRow("array-too-big1") << raw("\x81\x9a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1088     QTest::newRow("array-too-big2") << raw("\x81\x9b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1089     QTest::newRow("object-too-big1") << raw("\x81\xba\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1090     QTest::newRow("object-too-big2") << raw("\x81\xbb\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
1091
1092     QTest::newRow("no-break-for-array0") << raw("\x81\x9f") << 0 << CborErrorUnexpectedEOF << 2;
1093     QTest::newRow("no-break-for-array1") << raw("\x81\x9f\x01") << 0 << CborErrorUnexpectedEOF << 3;
1094     QTest::newRow("no-break-string0") << raw("\x81\x7f") << 0 << CborErrorUnexpectedEOF << 1;
1095     QTest::newRow("no-break-string1") << raw("\x81\x7f\x61Z") << 0 << CborErrorUnexpectedEOF << 1;
1096
1097     QTest::newRow("nested-indefinite-length-bytearrays") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1;
1098     QTest::newRow("nested-indefinite-length-strings") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1;
1099
1100     QTest::newRow("string-chunk-unsigned") << raw("\x81\x7f\0\xff") << 0 << CborErrorIllegalType << 1;
1101     QTest::newRow("string-chunk-bytearray") << raw("\x81\x7f\x40\xff") << 0 << CborErrorIllegalType << 1;
1102     QTest::newRow("string-chunk-array") << raw("\x81\x7f\x80\xff") << 0 << CborErrorIllegalType << 1;
1103     QTest::newRow("bytearray-chunk-unsigned") << raw("\x81\x5f\0\xff") << 0 << CborErrorIllegalType << 1;
1104     QTest::newRow("bytearray-chunk-string") << raw("\x81\x5f\x60\xff") << 0 << CborErrorIllegalType << 1;
1105     QTest::newRow("bytearray-chunk-array") << raw("\x81\x5f\x80\xff") << 0 << CborErrorIllegalType << 1;
1106 }
1107
1108 void tst_Parser::validation()
1109 {
1110     QFETCH(QByteArray, data);
1111     QFETCH(int, flags);
1112     QFETCH(CborError, expectedError);
1113     QFETCH(int, offset);
1114
1115     QString decoded;
1116     CborParser parser;
1117     CborValue first;
1118     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), flags, &parser, &first);
1119     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1120
1121     err = parseOne(&first, &decoded);
1122     QCOMPARE(int(err), int(expectedError));
1123     QCOMPARE(int(first.ptr - reinterpret_cast<const quint8 *>(data.constBegin())), offset);
1124 }
1125
1126 void tst_Parser::resumeParsing_data()
1127 {
1128     addColumns();
1129     addFixedData();
1130     addStringsData();
1131     addTagsData();
1132     addMapMixedData();
1133 }
1134
1135 void tst_Parser::resumeParsing()
1136 {
1137     QFETCH(QByteArray, data);
1138     QFETCH(QString, expected);
1139
1140     for (int len = 0; len < data.length() - 1; ++len) {
1141         CborParser parser;
1142         CborValue first;
1143         CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), len, 0, &parser, &first);
1144         if (!err) {
1145             QString decoded;
1146             err = parseOne(&first, &decoded);
1147         }
1148         if (err != CborErrorUnexpectedEOF)
1149             qDebug() << "Length is" << len;
1150         QCOMPARE(int(err), int(CborErrorUnexpectedEOF));
1151     }
1152 }
1153
1154 void tst_Parser::endPointer_data()
1155 {
1156     QTest::addColumn<QByteArray>("data");
1157     QTest::addColumn<int>("offset");
1158
1159     QTest::newRow("number1") << raw("\x81\x01\x01") << 2;
1160     QTest::newRow("number24") << raw("\x81\x18\x18\x01") << 3;
1161     QTest::newRow("string") << raw("\x81\x61Z\x01") << 3;
1162     QTest::newRow("indefinite-string") << raw("\x81\x7f\x61Z\xff\x01") << 5;
1163     QTest::newRow("array") << raw("\x81\x02\x01") << 2;
1164     QTest::newRow("indefinite-array") << raw("\x81\x9f\x02\xff\x01") << 4;
1165     QTest::newRow("object") << raw("\x81\xa1\x03\x02\x01") << 4;
1166     QTest::newRow("indefinite-object") << raw("\x81\xbf\x03\x02\xff\x01") << 5;
1167 }
1168
1169 void tst_Parser::endPointer()
1170 {
1171     QFETCH(QByteArray, data);
1172     QFETCH(int, offset);
1173
1174     QString decoded;
1175     CborParser parser;
1176     CborValue first;
1177     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
1178     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1179
1180     err = parseOne(&first, &decoded);
1181     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1182     QCOMPARE(int(first.ptr - reinterpret_cast<const quint8 *>(data.constBegin())), offset);
1183 }
1184
1185 void tst_Parser::recursionLimit_data()
1186 {
1187     static const int recursions = CBOR_PARSER_MAX_RECURSIONS + 2;
1188     QTest::addColumn<QByteArray>("data");
1189
1190     QTest::newRow("array") << QByteArray(recursions, '\x81') + '\x20';
1191     QTest::newRow("_array") << QByteArray(recursions, '\x9f') + '\x20' + QByteArray(recursions, '\xff');
1192
1193     QByteArray data;
1194     for (int i = 0; i < recursions; ++i)
1195         data += "\xa1\x65Hello";
1196     data += '\2';
1197     QTest::newRow("map-recursive-values") << data;
1198
1199     data.clear();
1200     for (int i = 0; i < recursions; ++i)
1201         data += "\xbf\x65World";
1202     data += '\2';
1203     for (int i = 0; i < recursions; ++i)
1204         data += "\xff";
1205     QTest::newRow("_map-recursive-values") << data;
1206
1207     data = QByteArray(recursions, '\xa1');
1208     data += '\2';
1209     for (int i = 0; i < recursions; ++i)
1210         data += "\x7f\x64quux\xff";
1211     QTest::newRow("map-recursive-keys") << data;
1212
1213     data = QByteArray(recursions, '\xbf');
1214     data += '\2';
1215     for (int i = 0; i < recursions; ++i)
1216         data += "\1\xff";
1217     QTest::newRow("_map-recursive-keys") << data;
1218
1219     data.clear();
1220     for (int i = 0; i < recursions / 2; ++i)
1221         data += "\x81\xa1\1";
1222     data += '\2';
1223     QTest::newRow("mixed") << data;
1224 }
1225
1226 void tst_Parser::recursionLimit()
1227 {
1228     QFETCH(QByteArray, data);
1229
1230     CborParser parser;
1231     CborValue first;
1232     CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
1233     QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1234
1235     // check that it is valid:
1236     CborValue it = first;
1237     {
1238         QString dummy;
1239         err = parseOne(&it, &dummy);
1240         QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
1241     }
1242
1243     it = first;
1244     err = cbor_value_advance(&it);
1245     QCOMPARE(int(err), int(CborErrorNestingTooDeep));
1246
1247     it = first;
1248     if (cbor_value_is_map(&it)) {
1249         CborValue dummy;
1250         err = cbor_value_map_find_value(&it, "foo", &dummy);
1251         QCOMPARE(int(err), int(CborErrorNestingTooDeep));
1252     }
1253 }
1254
1255 QTEST_MAIN(tst_Parser)
1256 #include "tst_parser.moc"