From 206e15dff7e89cf5297d69aa115de443aec3b450 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Thu, 4 Jul 2013 17:06:53 +0200
Subject: [PATCH] - fixed bugs and added test cases

---
 src/JSON.cc       | 101 ++++++++++++++++++++++++++++++++++------------
 test/JSON_test.cc |  47 +++++++++++++++++++++
 2 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/src/JSON.cc b/src/JSON.cc
index 4800a1e6..5cf949cd 100644
--- a/src/JSON.cc
+++ b/src/JSON.cc
@@ -93,28 +93,70 @@ JSON& JSON::operator=(JSON o) {
 }
 #else
 JSON& JSON::operator=(const JSON& o) {
+    // check for self-assignment
+    if (&o == this) {
+        return *this;
+    }
+
+    switch (_type) {
+        case (array): {
+            delete static_cast<std::vector<JSON>*>(_payload);
+            break;
+        }
+        case (object): {
+            delete static_cast<std::map<std::string, JSON>*>(_payload);
+            break;
+        }
+        case (string): {
+            delete static_cast<std::string*>(_payload);
+            break;
+        }
+        case (boolean): {
+            delete static_cast<bool*>(_payload);
+            break;
+        }
+        case (number_int): {
+            delete static_cast<int*>(_payload);
+            break;
+        }
+        case (number_float): {
+            delete static_cast<double*>(_payload);
+            break;
+        }
+        case (null): {
+            break;
+        }
+    }
+
     _type = o._type;
     switch (_type) {
-        case (array):
+        case (array): {
             _payload = new std::vector<JSON>(*static_cast<std::vector<JSON>*>(o._payload));
             break;
-        case (object):
+        }
+        case (object): {
             _payload = new std::map<std::string, JSON>(*static_cast<std::map<std::string, JSON>*>(o._payload));
             break;
-        case (string):
+        }
+        case (string): {
             _payload = new std::string(*static_cast<std::string*>(o._payload));
             break;
-        case (boolean):
+        }
+        case (boolean): {
             _payload = new bool(*static_cast<bool*>(o._payload));
             break;
-        case (number_int):
+        }
+        case (number_int): {
             _payload = new int(*static_cast<int*>(o._payload));
             break;
-        case (number_float):
+        }
+        case (number_float): {
             _payload = new double(*static_cast<double*>(o._payload));
             break;
-        case (null):
+        }
+        case (null): {
             break;
+        }
     }
 
     return *this;
@@ -124,26 +166,33 @@ JSON& JSON::operator=(const JSON& o) {
 /// destructor
 JSON::~JSON() {
     switch (_type) {
-        case (array):
+        case (array): {
             delete static_cast<std::vector<JSON>*>(_payload);
             break;
-        case (object):
+        }
+        case (object): {
             delete static_cast<std::map<std::string, JSON>*>(_payload);
             break;
-        case (string):
+        }
+        case (string): {
             delete static_cast<std::string*>(_payload);
             break;
-        case (boolean):
+        }
+        case (boolean): {
             delete static_cast<bool*>(_payload);
             break;
-        case (number_int):
+        }
+        case (number_int): {
             delete static_cast<int*>(_payload);
             break;
-        case (number_float):
+        }
+        case (number_float): {
             delete static_cast<double*>(_payload);
             break;
-        case (null):
+        }
+        case (null): {
             break;
+        }
     }
 }
 
@@ -567,10 +616,6 @@ void JSON::parser::error(std::string msg) {
 bool JSON::parser::next() {
     _current = _buffer[_pos++];
 
-    if (_buffer == nullptr) {
-        return false;
-    }
-
     // skip trailing whitespace
     while (std::isspace(_current)) {
         _current = _buffer[_pos++];
@@ -579,13 +624,21 @@ bool JSON::parser::next() {
     return true;
 }
 
-/// \todo: escaped strings
 std::string JSON::parser::parseString() {
-    // get position of closing quote
-    const char* p = strchr(_buffer + _pos, '\"');
+    // get position of closing quotes
+    char* p = strchr(_buffer + _pos, '\"');
 
-    // check if quotes were found
-    if (!p) {
+    // if the closing quotes are escaped (viz. *(p-1) is '\\'),
+    // we continue looking for the "right" quotes
+    while (p != nullptr and * (p - 1) == '\\') {
+        // length of the string so far
+        const size_t length = p - _buffer - _pos;
+        // continue checking after escaped quote
+        p = strchr(_buffer + _pos + length + 1, '\"');
+    }
+
+    // check if closing quotes were found
+    if (p == nullptr) {
         error("expected '\"'");
     }
 
@@ -654,8 +707,6 @@ void JSON::parser::parse(JSON& result) {
         error("unexpected end of file");
     }
 
-    //JSON result;
-
     switch (_current) {
         case ('{'): {
             // explicitly set result to object to cope with {}
diff --git a/test/JSON_test.cc b/test/JSON_test.cc
index 683a6f5d..3836ba12 100644
--- a/test/JSON_test.cc
+++ b/test/JSON_test.cc
@@ -74,6 +74,14 @@ void test_null() {
     }
 }
 
+
+void test_bool() {
+    JSON True = true;
+    JSON False = false;
+
+    bool x = True;
+}
+
 void test_string() {
     /* a string object */
 
@@ -135,6 +143,13 @@ void test_string() {
     } catch (const std::exception& ex) {
         assert(ex.what() == std::string("cannot cast string to JSON Boolean"));
     }
+
+    {
+        // get payload
+        std::string* s1 = static_cast<std::string*>(a.data());
+        std::string s2 = a;
+        assert(*s1 == s2);
+    }
 }
 
 void test_array() {
@@ -200,6 +215,13 @@ void test_array() {
         std::cerr << element << '\n';
     }
 #endif
+
+    {
+        // get payload
+        std::vector<JSON>* array = static_cast<std::vector<JSON>*>(a.data());
+        assert(array->size() == a.size());
+        assert(array->empty() == a.empty());
+    }
 }
 
 void test_streaming() {
@@ -224,10 +246,35 @@ void test_streaming() {
         o >> k;
         assert(j.toString() == k.toString());
     }
+
+    // check numbers
+    {
+        std::stringstream number_stream;
+        number_stream << "[0, -1, 1, 1.0, -1.0, 1.0e+1, 1.0e-1, 1.0E+1, 1.0E-1, -1.2345678e-12345678]";
+        JSON j;
+        j << number_stream;
+    }
+
+    // check Unicode
+    {
+        std::stringstream unicode_stream;
+        unicode_stream << "[\"öäüÖÄÜß\", \"ÀÁÂÃĀĂȦ\", \"★☆→➠♥︎♦︎☁︎\"]";
+        JSON j;
+        j << unicode_stream;
+    }
+
+    // check escaped strings
+    {
+        std::stringstream escaped_stream;
+        escaped_stream << "[\"\\\"Hallo\\\"\", \"\u0123\"]";
+        JSON j;
+        j << escaped_stream;
+    }
 }
 
 int main() {
     test_null();
+    test_bool();
     test_string();
     test_array();
     test_streaming();