From 41673e8fed46aff58952604154ef05a28f587dca Mon Sep 17 00:00:00 2001
From: Niels Lohmann <niels.lohmann@gmail.com>
Date: Sat, 10 Dec 2016 23:12:57 +0100
Subject: [PATCH] :bug: fixed CBOR code and added test cases

---
 src/json.hpp           |   8 +--
 src/json.hpp.re2c      |   8 +--
 test/src/unit-cbor.cpp | 112 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 118 insertions(+), 10 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index fbab3fc6..436c91be 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7085,25 +7085,25 @@ class basic_json
             {
                 idx += 1; // skip content byte
                 // must be uint8_t !
-                return -1 - get_from_vector<uint8_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
             }
 
             case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
             {
                 idx += 2; // skip 2 content bytes
-                return -1 - get_from_vector<int16_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
             }
 
             case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
             {
                 idx += 4; // skip 4 content bytes
-                return -1 - get_from_vector<int32_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
             }
 
             case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
             {
                 idx += 8; // skip 8 content bytes
-                return -1 - get_from_vector<int64_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint64_t>(v, current_idx);
             }
 
             // UTF-8 string (0x00..0x17 bytes follow)
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index e6c74fcc..c3f85dcd 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -7085,25 +7085,25 @@ class basic_json
             {
                 idx += 1; // skip content byte
                 // must be uint8_t !
-                return -1 - get_from_vector<uint8_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
             }
 
             case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
             {
                 idx += 2; // skip 2 content bytes
-                return -1 - get_from_vector<int16_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
             }
 
             case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
             {
                 idx += 4; // skip 4 content bytes
-                return -1 - get_from_vector<int32_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
             }
 
             case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
             {
                 idx += 8; // skip 8 content bytes
-                return -1 - get_from_vector<int64_t>(v, current_idx);
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint64_t>(v, current_idx);
             }
 
             // UTF-8 string (0x00..0x17 bytes follow)
diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp
index 28b0ecad..9c5f76e7 100644
--- a/test/src/unit-cbor.cpp
+++ b/test/src/unit-cbor.cpp
@@ -85,9 +85,117 @@ TEST_CASE("CBOR")
         {
             SECTION("signed")
             {
-                SECTION("-65535..-257")
+                SECTION("-9223372036854775808..-4294967297")
                 {
-                    for (int16_t i = -65535; i <= -257; ++i)
+                    std::vector<int64_t> numbers;
+                    numbers.push_back(INT64_MIN);
+                    numbers.push_back(-1000000000000000000);
+                    numbers.push_back(-100000000000000000);
+                    numbers.push_back(-10000000000000000);
+                    numbers.push_back(-1000000000000000);
+                    numbers.push_back(-100000000000000);
+                    numbers.push_back(-10000000000000);
+                    numbers.push_back(-1000000000000);
+                    numbers.push_back(-100000000000);
+                    numbers.push_back(-10000000000);
+                    numbers.push_back(-4294967297);
+                    for (auto i : numbers)
+                    {
+                        CAPTURE(i);
+
+                        // create JSON value with integer number
+                        json j = i;
+
+                        // check type
+                        CHECK(j.is_number_integer());
+
+                        // create expected byte vector
+                        std::vector<uint8_t> expected;
+                        expected.push_back(static_cast<uint8_t>(0x3b));
+                        uint64_t positive = static_cast<uint64_t>(-1 - i);
+                        expected.push_back(static_cast<uint8_t>((positive >> 56) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 48) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 40) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 32) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 24) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 16) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 8) & 0xff));
+                        expected.push_back(static_cast<uint8_t>(positive & 0xff));
+
+                        // compare result + size
+                        const auto result = json::to_cbor(j);
+                        CHECK(result == expected);
+                        CHECK(result.size() == 9);
+
+                        // check individual bytes
+                        CHECK(result[0] == 0x3b);
+                        uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) +
+                                            (static_cast<uint64_t>(result[2]) << 060) +
+                                            (static_cast<uint64_t>(result[3]) << 050) +
+                                            (static_cast<uint64_t>(result[4]) << 040) +
+                                            (static_cast<uint64_t>(result[5]) << 030) +
+                                            (static_cast<uint64_t>(result[6]) << 020) +
+                                            (static_cast<uint64_t>(result[7]) << 010) +
+                                            static_cast<uint64_t>(result[8]));
+                        CHECK(restored == positive);
+                        CHECK(-1 - restored == i);
+
+                        // roundtrip
+                        CHECK(json::from_cbor(result) == j);
+                    }
+                }
+
+                SECTION("-4294967296..-65537")
+                {
+                    std::vector<int64_t> numbers;
+                    numbers.push_back(-65537);
+                    numbers.push_back(-100000);
+                    numbers.push_back(-1000000);
+                    numbers.push_back(-10000000);
+                    numbers.push_back(-100000000);
+                    numbers.push_back(-1000000000);
+                    numbers.push_back(-4294967296);
+                    for (auto i : numbers)
+                    {
+                        CAPTURE(i);
+
+                        // create JSON value with integer number
+                        json j = i;
+
+                        // check type
+                        CHECK(j.is_number_integer());
+
+                        // create expected byte vector
+                        std::vector<uint8_t> expected;
+                        expected.push_back(static_cast<uint8_t>(0x3a));
+                        uint32_t positive = static_cast<uint32_t>(static_cast<uint64_t>(-1 - i) & 0x00000000ffffffff);
+                        expected.push_back(static_cast<uint8_t>((positive >> 24) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 16) & 0xff));
+                        expected.push_back(static_cast<uint8_t>((positive >> 8) & 0xff));
+                        expected.push_back(static_cast<uint8_t>(positive & 0xff));
+
+                        // compare result + size
+                        const auto result = json::to_cbor(j);
+                        CHECK(result == expected);
+                        CHECK(result.size() == 5);
+
+                        // check individual bytes
+                        CHECK(result[0] == 0x3a);
+                        uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) +
+                                            (static_cast<uint32_t>(result[2]) << 020) +
+                                            (static_cast<uint32_t>(result[3]) << 010) +
+                                            static_cast<uint32_t>(result[4]));
+                        CHECK(restored == positive);
+                        CHECK(-1ll - restored == i);
+
+                        // roundtrip
+                        CHECK(json::from_cbor(result) == j);
+                    }
+                }
+
+                SECTION("-65536..-257")
+                {
+                    for (int32_t i = -65536; i <= -257; ++i)
                     {
                         CAPTURE(i);