From 3f76f639b413e9156eca380bddce67b0fc8b59d6 Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
Date: Tue, 12 May 2015 10:10:09 +0900
Subject: [PATCH] Autotest: test the error conditions in the parser and the
 encoder

The encoder only supports two error conditions: out of memory (need more
buffer) and illegal simple types. It's possible for the encoder to
encode an array or map with a size the decoder can't parse (UINT32_MAX),
but that's not an error condition.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
---
 src/cbor.h                    |   1 -
 src/cborerrorstrings.c        |   3 -
 src/cborparser.c              |  12 +-
 tests/encoder/tst_encoder.cpp |  40 +++++
 tests/parser/tst_parser.cpp   | 267 +++++++++++++++++++++++++++++++---
 5 files changed, 293 insertions(+), 30 deletions(-)

diff --git a/src/cbor.h b/src/cbor.h
index 6db2bac..4d1ae4b 100644
--- a/src/cbor.h
+++ b/src/cbor.h
@@ -102,7 +102,6 @@ typedef enum CborError {
     /* parser errors streaming errors */
     CborErrorGarbageAtEnd = 256,
     CborErrorUnexpectedEOF,
-    CborErrorBreakMissingAtEOF,     /* special case of UnexpectedEOF */
     CborErrorUnexpectedBreak,
     CborErrorUnknownType,           /* can only heppen in major type 7 */
     CborErrorIllegalType,           /* type not allowed here */
diff --git a/src/cborerrorstrings.c b/src/cborerrorstrings.c
index 95ff0aa..25e6a58 100644
--- a/src/cborerrorstrings.c
+++ b/src/cborerrorstrings.c
@@ -52,9 +52,6 @@ const char *cbor_error_string(CborError error)
     case CborErrorUnexpectedEOF:
         return _("unexpected end of data");
 
-    case CborErrorBreakMissingAtEOF:
-        return _("'break' byte missing before end of document");
-
     case CborErrorUnexpectedBreak:
         return _("unexpected 'break' byte");
 
diff --git a/src/cborparser.c b/src/cborparser.c
index b7df8f1..03bb554 100644
--- a/src/cborparser.c
+++ b/src/cborparser.c
@@ -139,7 +139,7 @@ static CborError preparse_value(CborValue *it)
 
     if (descriptor > Value64Bit) {
         if (unlikely(descriptor != IndefiniteLength))
-            return CborErrorIllegalNumber;
+            return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
         if (likely(!is_fixed_type(type))) {
             // special case
             it->flags |= CborIteratorFlag_UnknownLength;
@@ -398,12 +398,18 @@ CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
         assert(err == CborNoError);
 
         recursed->remaining = len;
-        if (recursed->remaining != len || len == UINT32_MAX)
+        if (recursed->remaining != len || len == UINT32_MAX) {
+            // back track the pointer to indicate where the error occurred
+            recursed->ptr = it->ptr;
             return CborErrorDataTooLarge;
+        }
         if (recursed->type == CborMapType) {
             // maps have keys and values, so we need to multiply by 2
-            if (recursed->remaining > UINT32_MAX / 2)
+            if (recursed->remaining > UINT32_MAX / 2) {
+                // back track the pointer to indicate where the error occurred
+                recursed->ptr = it->ptr;
                 return CborErrorDataTooLarge;
+            }
             recursed->remaining *= 2;
         }
         if (len != 0)
diff --git a/tests/encoder/tst_encoder.cpp b/tests/encoder/tst_encoder.cpp
index 5b5805c..4f91880 100644
--- a/tests/encoder/tst_encoder.cpp
+++ b/tests/encoder/tst_encoder.cpp
@@ -43,6 +43,11 @@ private slots:
     void arrays();
     void maps_data() { tags_data(); }
     void maps();
+
+    void shortBuffer_data() { tags_data(); }
+    void shortBuffer();
+    void illegalSimpleType_data();
+    void illegalSimpleType();
 };
 
 template <size_t N> QByteArray raw(const char (&data)[N])
@@ -451,5 +456,40 @@ void tst_Encoder::maps()
     if (compareFailed) return;
 }
 
+void tst_Encoder::shortBuffer()
+{
+    QFETCH(QVariant, input);
+    QFETCH(QByteArray, output);
+    QByteArray buffer(output.length(), Qt::Uninitialized);
+
+    for (int len = 0; len < output.length() - 1; ++len) {
+        CborEncoder encoder;
+        cbor_encoder_init(&encoder, buffer.data(), len, 0);
+        QCOMPARE(int(encodeVariant(&encoder, input)), int(CborErrorOutOfMemory));
+    }
+}
+
+void tst_Encoder::illegalSimpleType_data()
+{
+    QTest::addColumn<int>("type");
+    QTest::newRow("half-float") << 25;
+    QTest::newRow("float") << 26;
+    QTest::newRow("double") << 27;
+    QTest::newRow("28") << 28;
+    QTest::newRow("29") << 29;
+    QTest::newRow("30") << 30;
+    QTest::newRow("31") << 31;
+}
+
+void tst_Encoder::illegalSimpleType()
+{
+    QFETCH(int, type);
+
+    char buf[2];
+    CborEncoder encoder;
+    cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
+    QCOMPARE(int(cbor_encode_simple_value(&encoder, type)), int(CborErrorIllegalSimpleType));
+}
+
 QTEST_MAIN(tst_Encoder)
 #include "tst_encoder.moc"
diff --git a/tests/parser/tst_parser.cpp b/tests/parser/tst_parser.cpp
index d235ec1..57e4642 100644
--- a/tests/parser/tst_parser.cpp
+++ b/tests/parser/tst_parser.cpp
@@ -57,7 +57,7 @@ private slots:
     void nestedMaps_data() { maps_data(); }
     void nestedMaps();
     void mapMixed_data();
-    void mapMixed();
+    void mapMixed() { fixed(); }
     void mapsAndArrays_data() { arrays_data(); }
     void mapsAndArrays();
 
@@ -68,6 +68,14 @@ private slots:
     void stringCompare();
     void mapFind_data();
     void mapFind();
+
+    // validation & errors
+    void validation_data();
+    void validation();
+    void resumeParsing_data();
+    void resumeParsing();
+    void endPointer_data();
+    void endPointer();
 };
 
 char toHexUpper(unsigned n)
@@ -140,11 +148,15 @@ CborError parseOne(CborValue *it, QString *parsed)
             *parsed += "_ ";
 
         err = cbor_value_enter_container(it, &recursed);
-        if (err)
+        if (err) {
+            it->ptr = recursed.ptr;
             return err;       // parse error
+        }
         err = parseContainer(&recursed, parsed, type);
-        if (err)
+        if (err) {
+            it->ptr = recursed.ptr;
             return err;       // parse error
+        }
         err = cbor_value_leave_container(it, &recursed);
         if (err)
             return err;       // parse error
@@ -745,15 +757,21 @@ void tst_Parser::nestedMaps()
 
 void addMapMixedData()
 {
-    // this is just the contents of the map, not including the map itself
-    // we do it like that so we can reuse the same data for multiple runs
-    QTest::newRow("map-0-24") << raw("\0\x18\x18") << "0: 24";
-    QTest::newRow("map-0*1-24") << raw("\x18\0\x18\x18") << "0: 24";
-    QTest::newRow("map-0*1-24*2") << raw("\x18\0\x19\0\x18") << "0: 24";
-    QTest::newRow("map-0*4-24*2") << raw("\x1a\0\0\0\0\x19\0\x18") << "0: 24";
-    QTest::newRow("map-24-0") << raw("\x18\x18\0") << "24: 0";
-    QTest::newRow("map-24-0*1") << raw("\x18\x18\0") << "24: 0";
-    QTest::newRow("map-255-65535") << raw("\x18\xff\x19\xff\xff") << "255: 65535";
+    QTest::newRow("map-0-24") << raw("\xa1\0\x18\x18") << "{0: 24}";
+    QTest::newRow("map-0*1-24") << raw("\xa1\x18\0\x18\x18") << "{0: 24}";
+    QTest::newRow("map-0*1-24*2") << raw("\xa1\x18\0\x19\0\x18") << "{0: 24}";
+    QTest::newRow("map-0*4-24*2") << raw("\xa1\x1a\0\0\0\0\x19\0\x18") << "{0: 24}";
+    QTest::newRow("map-24-0") << raw("\xa1\x18\x18\0") << "{24: 0}";
+    QTest::newRow("map-24-0*1") << raw("\xa1\x18\x18\0") << "{24: 0}";
+    QTest::newRow("map-255-65535") << raw("\xa1\x18\xff\x19\xff\xff") << "{255: 65535}";
+
+    QTest::newRow("_map-0-24") << raw("\xbf\0\x18\x18\xff") << "{_ 0: 24}";
+    QTest::newRow("_map-0*1-24") << raw("\xbf\x18\0\x18\x18\xff") << "{_ 0: 24}";
+    QTest::newRow("_map-0*1-24*2") << raw("\xbf\x18\0\x19\0\x18\xff") << "{_ 0: 24}";
+    QTest::newRow("_map-0*4-24*2") << raw("\xbf\x1a\0\0\0\0\x19\0\x18\xff") << "{_ 0: 24}";
+    QTest::newRow("_map-24-0") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}";
+    QTest::newRow("_map-24-0*1") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}";
+    QTest::newRow("_map-255-65535") << raw("\xbf\x18\xff\x19\xff\xff\xff") << "{_ 255: 65535}";
 }
 
 void tst_Parser::mapMixed_data()
@@ -762,17 +780,6 @@ void tst_Parser::mapMixed_data()
     addMapMixedData();
 }
 
-void tst_Parser::mapMixed()
-{
-    QFETCH(QByteArray, data);
-    QFETCH(QString, expected);
-
-    compareOne("\xa1" + data, '{' + expected + '}');
-    if (compareFailed) return;
-
-    compareOne("\xbf" + data + "\xff", "{_ " + expected + '}');
-}
-
 void tst_Parser::mapsAndArrays()
 {
     QFETCH(QByteArray, data);
@@ -1095,5 +1102,219 @@ void tst_Parser::mapFind()
     }
 }
 
+void tst_Parser::validation_data()
+{
+    QTest::addColumn<QByteArray>("data");
+    QTest::addColumn<int>("flags");     // future
+    QTest::addColumn<CborError>("expectedError");
+    QTest::addColumn<int>("offset");
+
+    // illegal numbers are future extension points
+    QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-unsigned-2") << raw("\x81\x1d") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-unsigned-3") << raw("\x81\x1e") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-unsigned-4") << raw("\x81\x1f") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-negative-1") << raw("\x81\x3c") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-negative-2") << raw("\x81\x3d") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-negative-3") << raw("\x81\x3e") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-negative-4") << raw("\x81\x3f") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-bytearray-length-1") << raw("\x81\x5c") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-bytearray-length-2") << raw("\x81\x5d") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-bytearray-length-3") << raw("\x81\x5e") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-string-length-1") << raw("\x81\x7c") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-string-length-2") << raw("\x81\x7d") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-string-length-3") << raw("\x81\x7e") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-array-length-1") << raw("\x81\x9c") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-array-length-2") << raw("\x81\x9d") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-array-length-3") << raw("\x81\x9e") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-map-length-1") << raw("\x81\xbc") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-map-length-2") << raw("\x81\xbd") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("illegal-number-in-map-length-3") << raw("\x81\xbe") << 0 << CborErrorIllegalNumber << 1;
+
+    QTest::newRow("number-too-short-1-0") << raw("\x81\x18") << 0 << CborErrorUnexpectedEOF << 1;   // requires 1 byte, 0 given
+    QTest::newRow("number-too-short-2-0") << raw("\x81\x19") << 0 << CborErrorUnexpectedEOF << 1;   // requires 2 bytes, 0 given
+    QTest::newRow("number-too-short-2-1") << raw("\x81\x19\x01") << 0 << CborErrorUnexpectedEOF << 1; // etc
+    QTest::newRow("number-too-short-4-0") << raw("\x81\x1a") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("number-too-short-4-3") << raw("\x81\x1a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("number-too-short-8-0") << raw("\x81\x1b") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("number-too-short-8-7") << raw("\x81\x1b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-1-0") << raw("\x81\x38") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-2-0") << raw("\x81\x39") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-2-1") << raw("\x81\x39\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-4-0") << raw("\x81\x3a") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-4-3") << raw("\x81\x3a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-8-0") << raw("\x81\x3b") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-length-too-short-8-7") << raw("\x81\x3b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-1-0") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-2-0") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-2-1") << raw("\x81\x59\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-4-0") << raw("\x81\x5a") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-4-3") << raw("\x81\x5a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-8-0") << raw("\x81\x5b") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-length-too-short-8-7") << raw("\x81\x5b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-1-0") << raw("\x81\x98") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-2-0") << raw("\x81\x99") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-2-1") << raw("\x81\x99\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-4-0") << raw("\x81\x9a") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-4-3") << raw("\x81\x9a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-8-0") << raw("\x81\x9b") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("array-length-too-short-8-7") << raw("\x81\x9b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-1-0") << raw("\x81\xb8") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-2-0") << raw("\x81\xb9") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-2-1") << raw("\x81\xb9\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-4-0") << raw("\x81\xba") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-4-3") << raw("\x81\xba\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-8-0") << raw("\x81\xbb") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("map-length-too-short-8-7") << raw("\x81\xbb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-1-0") << raw("\x81\xd8") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-2-0") << raw("\x81\xd9") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-2-1") << raw("\x81\xd9\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-4-0") << raw("\x81\xda") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-4-3") << raw("\x81\xda\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-8-0") << raw("\x81\xdb") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("tag-too-short-8-7") << raw("\x81\xdb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1;
+
+    QTest::newRow("bytearray-too-short1") << raw("\x81\x41") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short2") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short3") << raw("\x81\x58\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short4") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short5") << raw("\x81\x5a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short6") << raw("\x81\x5a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("bytearray-too-short7") << raw("\x81\x5b\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short1") << raw("\x81\x61") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short2") << raw("\x81\x78") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short3") << raw("\x81\x78\x01") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short4") << raw("\x81\x79") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short5") << raw("\x81\x7a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short6") << raw("\x81\x7a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("string-too-short7") << raw("\x81\x7b\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("fp16-too-short1") << raw("\x81\xf9") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("fp16-too-short2") << raw("\x81\xf9\x00") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("float-too-short1") << raw("\x81\xfa") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("float-too-short2") << raw("\x81\xfa\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("double-too-short1") << raw("\x81\xfb") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("double-too-short2") << raw("\x81\xfb\0\0\0\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1;
+
+    QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("eof-after-array-element") << raw("\x81\x82\x01") << 0 << CborErrorUnexpectedEOF << 3;
+    QTest::newRow("eof-after-object") << raw("\x81\xa1") << 0 << CborErrorUnexpectedEOF << 2;
+    QTest::newRow("eof-after-object2") << raw("\x81\xb8\x20") << 0 << CborErrorUnexpectedEOF << 3;
+    QTest::newRow("eof-after-object-key") << raw("\x81\xa1\x01") << 0 << CborErrorUnexpectedEOF << 3;
+    QTest::newRow("eof-after-object-value") << raw("\x81\xa2\x01\x01") << 0 << CborErrorUnexpectedEOF << 4;
+    QTest::newRow("eof-after-tag") << raw("\x81\xc0") << 0 << CborErrorUnexpectedEOF << 2;
+    QTest::newRow("eof-after-tag2") << raw("\x81\xd8\x20") << 0 << CborErrorUnexpectedEOF << 3;
+
+    // major type 7 has future types
+    QTest::newRow("future-type-28") << raw("\x81\xfc") << 0 << CborErrorUnknownType << 1;
+    QTest::newRow("future-type-29") << raw("\x81\xfd") << 0 << CborErrorUnknownType << 1;
+    QTest::newRow("future-type-30") << raw("\x81\xfe") << 0 << CborErrorUnknownType << 1;
+    QTest::newRow("unexpected-break") << raw("\x81\xff") << 0 << CborErrorUnexpectedBreak << 1;
+    QTest::newRow("illegal-simple-0") << raw("\x81\xf8\0") << 0 << CborErrorIllegalSimpleType << 1;
+    QTest::newRow("illegal-simple-31") << raw("\x81\xf8\x1f") << 0 << CborErrorIllegalSimpleType << 1;
+
+    // not only too big (UINT_MAX or UINT_MAX+1 in size), but also incomplete
+    if (sizeof(size_t) < sizeof(uint64_t)) {
+        QTest::newRow("bytearray-too-big1") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+        QTest::newRow("string-too-big1") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+    }
+    QTest::newRow("array-too-big1") << raw("\x81\x9a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+    QTest::newRow("array-too-big2") << raw("\x81\x9b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+    QTest::newRow("object-too-big1") << raw("\x81\xba\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+    QTest::newRow("object-too-big2") << raw("\x81\xbb\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1;
+
+    QTest::newRow("no-break-for-array0") << raw("\x81\x9f") << 0 << CborErrorUnexpectedEOF << 2;
+    QTest::newRow("no-break-for-array1") << raw("\x81\x9f\x01") << 0 << CborErrorUnexpectedEOF << 3;
+    QTest::newRow("no-break-string0") << raw("\x81\x7f") << 0 << CborErrorUnexpectedEOF << 1;
+    QTest::newRow("no-break-string1") << raw("\x81\x7f\x61Z") << 0 << CborErrorUnexpectedEOF << 1;
+
+    QTest::newRow("nested-indefinite-length-bytearrays") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1;
+    QTest::newRow("nested-indefinite-length-strings") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1;
+
+    QTest::newRow("string-chunk-unsigned") << raw("\x81\x7f\0\xff") << 0 << CborErrorIllegalType << 1;
+    QTest::newRow("string-chunk-bytearray") << raw("\x81\x7f\x40\xff") << 0 << CborErrorIllegalType << 1;
+    QTest::newRow("string-chunk-array") << raw("\x81\x7f\x80\xff") << 0 << CborErrorIllegalType << 1;
+    QTest::newRow("bytearray-chunk-unsigned") << raw("\x81\x5f\0\xff") << 0 << CborErrorIllegalType << 1;
+    QTest::newRow("bytearray-chunk-string") << raw("\x81\x5f\x60\xff") << 0 << CborErrorIllegalType << 1;
+    QTest::newRow("bytearray-chunk-array") << raw("\x81\x5f\x80\xff") << 0 << CborErrorIllegalType << 1;
+}
+
+void tst_Parser::validation()
+{
+    QFETCH(QByteArray, data);
+    QFETCH(int, flags);
+    QFETCH(CborError, expectedError);
+    QFETCH(int, offset);
+
+    QString decoded;
+    CborParser parser;
+    CborValue first;
+    CborError err = cbor_parser_init(data.constData(), data.length(), flags, &parser, &first);
+    QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
+
+    err = parseOne(&first, &decoded);
+    QCOMPARE(int(err), int(expectedError));
+    QCOMPARE(int(first.ptr - data.constBegin()), offset);
+}
+
+void tst_Parser::resumeParsing_data()
+{
+    addColumns();
+    addFixedData();
+    addStringsData();
+    addTagsData();
+    addMapMixedData();
+}
+
+void tst_Parser::resumeParsing()
+{
+    QFETCH(QByteArray, data);
+    QFETCH(QString, expected);
+
+    for (int len = 0; len < data.length() - 1; ++len) {
+        CborParser parser;
+        CborValue first;
+        CborError err = cbor_parser_init(data.constData(), len, 0, &parser, &first);
+        if (!err) {
+            QString decoded;
+            err = parseOne(&first, &decoded);
+        }
+        if (err != CborErrorUnexpectedEOF)
+            qDebug() << "Length is" << len;
+        QCOMPARE(int(err), int(CborErrorUnexpectedEOF));
+    }
+}
+
+void tst_Parser::endPointer_data()
+{
+    QTest::addColumn<QByteArray>("data");
+    QTest::addColumn<int>("offset");
+
+    QTest::newRow("number1") << raw("\x81\x01\x01") << 2;
+    QTest::newRow("number24") << raw("\x81\x18\x18\x01") << 3;
+    QTest::newRow("string") << raw("\x81\x61Z\x01") << 3;
+    QTest::newRow("indefinite-string") << raw("\x81\x7f\x61Z\xff\x01") << 5;
+    QTest::newRow("array") << raw("\x81\x02\x01") << 2;
+    QTest::newRow("indefinite-array") << raw("\x81\x9f\x02\xff\x01") << 4;
+    QTest::newRow("object") << raw("\x81\xa1\x03\x02\x01") << 4;
+    QTest::newRow("indefinite-object") << raw("\x81\xbf\x03\x02\xff\x01") << 5;
+}
+
+void tst_Parser::endPointer()
+{
+    QFETCH(QByteArray, data);
+    QFETCH(int, offset);
+
+    QString decoded;
+    CborParser parser;
+    CborValue first;
+    CborError err = cbor_parser_init(data.constData(), data.length(), 0, &parser, &first);
+    QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
+
+    err = parseOne(&first, &decoded);
+    QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
+    QCOMPARE(int(first.ptr - data.constBegin()), offset);
+}
+
 QTEST_MAIN(tst_Parser)
 #include "tst_parser.moc"
-- 
GitLab