Ver Fonte

[add] int type
[add] unit tests

isundil há 9 anos atrás
pai
commit
b8e8b3f698

+ 6 - 0
.gitignore

@@ -27,11 +27,17 @@
 *.exe
 *.out
 *.app
+*.swp
 
 # CMakeLists
 /CMakeCache.txt
 /CMakeFiles
+/CTestTestfile.cmake
+/Testing
 /bin
+/test/json_test
 /cmake_install.cmake
 /Makefile
+.fuse_hidden*
+/vgcore.10462
 

+ 7 - 2
CMakeLists.txt

@@ -1,11 +1,16 @@
 cmake_minimum_required(VERSION 2.8)
 
-add_executable(jsonstroll src/main.cpp src/params.cpp src/streamConsumer.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
+add_executable(jsonstroll src/main.cpp src/params.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
+add_executable(json_test test/src/main.cpp src/params.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
 
 set_property(TARGET jsonstroll PROPERTY RUNTIME_OUTPUT_DIRECTORY bin)
 
 add_definitions ("-Wall")
 add_definitions ("-g3")
 
-include_directories(src include)
+include_directories(include)
+
+enable_testing()
+set_property(TARGET json_test PROPERTY RUNTIME_OUTPUT_DIRECTORY test)
+add_test(json_test test/json_test)
 

+ 5 - 1
include/jsonArray.hh

@@ -1,7 +1,11 @@
 #pragma once
 
+#include <list>
 #include "jsonElement.hh"
 
-class JSonArray: public JSonElement
+class JSonArray: public JSonElement, public std::list<JSonElement *>
 {
+    public:
+        virtual ~JSonArray();
 };
+

+ 5 - 6
include/jsonObject.hh

@@ -5,15 +5,14 @@
 
 template<typename T> class JSonPrimitive;
 
-class JSonObject: public JSonElement
+class JSonObject: public JSonElement, public std::map<std::string, JSonElement*>
 {
     public:
-        JSonObject();
-        void push(const JSonPrimitive<std::string> &key, JSonElement *child);
+        virtual ~JSonObject();
 
-        bool contains(const JSonPrimitive<std::string> &) const;
+        void push(const std::string &key, JSonElement *child);
+        bool contains(const std::string &) const;
 
-    protected:
-        std::map<JSonPrimitive<std::string>, JSonElement *> *children;
+        const JSonElement* get(const std::string &) const;
 };
 

+ 16 - 0
include/jsonPrimitive.hh

@@ -9,7 +9,11 @@ class JSonPrimitive: public JSonElement
     public:
         JSonPrimitive(T const &v);
         virtual ~JSonPrimitive();
+
+        T getValue() const;
+
         bool operator<(const JSonPrimitive<T> &other) const;
+        bool operator==(const JSonPrimitive<T> &other) const;
 
     protected:
         const T value;
@@ -19,9 +23,21 @@ template<typename T>
 JSonPrimitive<T>::JSonPrimitive(T const &v): value(v)
 { }
 
+template<typename T>
+T JSonPrimitive<T>::getValue() const
+{
+    return value;
+}
+
 template<typename T>
 bool JSonPrimitive<T>::operator<(const JSonPrimitive<T> &other) const
 {
     return value < other.value;
 }
 
+template<typename T>
+bool JSonPrimitive<T>::operator==(const JSonPrimitive<T> &other) const
+{
+    return value == other.value;
+}
+

+ 2 - 0
include/streamConsumer.hh

@@ -8,6 +8,8 @@
 class StreamConsumer
 {
     public:
+        virtual ~StreamConsumer();
+
         static StreamConsumer *read(std::istream &stream);
         JSonElement * const getRoot() const;
 

+ 10 - 0
src/jsonArray.cpp

@@ -0,0 +1,10 @@
+#include "jsonArray.hh"
+
+JSonArray::~JSonArray()
+{
+    for (iterator i = begin(); i != end(); ++i)
+    {
+        delete *i;
+    }
+}
+

+ 15 - 6
src/jsonObject.cpp

@@ -1,18 +1,27 @@
 #include "jsonObject.hh"
 #include "jsonPrimitive.hh"
 
-JSonObject::JSonObject()
+JSonObject::~JSonObject()
 {
-    children = new std::map<JSonPrimitive<std::string>, JSonElement *>();
+    for (iterator i = begin(); i != end(); ++i)
+    {
+        delete (*i).second;
+    }
 }
 
-void JSonObject::push(const JSonPrimitive<std::string> &key, JSonElement *child)
+void JSonObject::push(const std::string &key, JSonElement *child)
 {
-    (*children)[key] = child;
+    (*this)[key] = child;
 }
 
-bool JSonObject::contains(const JSonPrimitive<std::string> &key) const
+bool JSonObject::contains(const std::string &key) const
 {
-    return children->find(key) != children->end();
+    return find(key) != end();
+}
+
+const JSonElement *JSonObject::get(const std::string &key) const
+{
+    const_iterator item = find(key);
+    return item == cend() ? nullptr : (*item).second;
 }
 

+ 2 - 0
src/jsonPrimitive.cpp

@@ -2,6 +2,8 @@
 
 template<> JSonPrimitive<float>::~JSonPrimitive() {}
 template<> JSonPrimitive<bool>::~JSonPrimitive() {}
+template<> JSonPrimitive<int>::~JSonPrimitive() {}
+
 template<> JSonPrimitive<long long>::~JSonPrimitive() {}
 template<> JSonPrimitive<std::string>::~JSonPrimitive() {}
 

+ 39 - 5
src/streamConsumer.cpp

@@ -6,6 +6,12 @@
 StreamConsumer::StreamConsumer(std::istream &s): stream(s)
 { }
 
+StreamConsumer::~StreamConsumer()
+{
+    if (root)
+        delete root;
+}
+
 StreamConsumer *StreamConsumer::read(std::istream &stream)
 {
     StreamConsumer *inst = new StreamConsumer(stream);
@@ -58,9 +64,9 @@ JSonObject *StreamConsumer::readObject()
         JSonElement *child = readNext();
         if (result == nullptr)
             result = new JSonObject();
-        else if (result->contains(*key))
+        else if (result->contains(key->getValue()))
             throw new JsonException(stream.tellg()); //Double key
-        result->push(*key, child);
+        result->push(key->getValue(), child);
         delete keyObj;
         keyObj = consumeToken(buf);
     } while (!keyObj && buf != "}");
@@ -69,8 +75,29 @@ JSonObject *StreamConsumer::readObject()
 
 JSonArray *StreamConsumer::readArray()
 {
-    //TODO
-    return nullptr;
+    JSonArray *result = nullptr;
+    JSonElement *child = readNext();
+    std::string buf;
+
+    if (child == nullptr && buf == "]")
+        return new JSonArray(); //Empty object
+    do
+    {
+        if (child == nullptr)
+            throw new JsonException(stream.tellg());
+        if (result == nullptr)
+            result = new JSonArray();
+        result->push_back(child);
+        child = consumeToken(buf);
+        if (child != nullptr)
+            throw new JsonException(stream.tellg());
+        else if (buf == "]")
+            break;
+        else if (buf != ",")
+            throw new JsonException(stream.tellg());
+        child = consumeToken(buf);
+    } while (true);
+    return result;
 }
 
 JSonElement *StreamConsumer::consumeToken(std::string &buf)
@@ -137,7 +164,14 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
                 stream.unget();
                 if (numberIsFloat)
                     return new JSonPrimitive<float>(std::stof(buf));
-                return new JSonPrimitive<long long int>(std::stol(buf));
+                try
+                {
+                    return new JSonPrimitive<int>(std::stoi(buf));
+                }
+                catch(std::out_of_range e)
+                {
+                    return new JSonPrimitive<long long>(std::stol(buf));
+                }
             }
         }
         else

+ 104 - 0
test/src/main.cpp

@@ -0,0 +1,104 @@
+#include <string>
+#include <sstream>
+#include <cassert>
+#include <climits>
+#include <stdlib.h>
+#include "jsonElement.hh"
+#include "streamConsumer.hh"
+
+StreamConsumer *toJson(std::string str)
+{
+    std::stringstream input(str);
+    return StreamConsumer::read(input);
+}
+
+void checkTypes()
+{
+    StreamConsumer *root = toJson("{\"test\":\"value\"}");
+    assert(dynamic_cast<JSonObject*>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("[\"test\",\"value\"]");
+    assert(dynamic_cast<JSonArray*>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("\"test\"");
+    assert(dynamic_cast<JSonPrimitive<std::string> *>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("42");
+    assert(dynamic_cast<JSonPrimitive<int> *>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("42.2");
+    assert(dynamic_cast<JSonPrimitive<float> *>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson(std::to_string((long long)LLONG_MAX));
+    assert(dynamic_cast<JSonPrimitive<long long> *>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("true");
+    assert(dynamic_cast<JSonPrimitive<bool> *>(root->getRoot()) != nullptr);
+    delete root;
+
+    root = toJson("[true, 42, \"coucou\", 12.34, false]");
+    JSonArray *arr = dynamic_cast<JSonArray *>(root->getRoot());
+    assert(arr != nullptr);
+    JSonArray::const_iterator it = arr->cbegin();
+    assert((dynamic_cast<JSonPrimitive<bool> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<bool> *)(*it))->getValue() == true);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<int> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<int> *)(*it))->getValue() == 42);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<std::string> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<std::string> *)(*it))->getValue() == "coucou");
+    it++;
+    assert((dynamic_cast<JSonPrimitive<float> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<float> *)(*it))->getValue() == 12.34f);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<bool> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<bool> *)(*it))->getValue() == false);
+    delete root;
+
+    root = toJson("{\"bool\":true, \"int\":42, \"str\":\"coucou\", \"float\":12.34, \"arrayOfInt\":[1, 2, 3, 4.5]}");
+    assert(dynamic_cast<JSonObject *>(root->getRoot()) != nullptr);
+    assert(((JSonObject *)(root->getRoot()))->size() == 5);
+    const JSonElement *tmp = ((JSonObject *)(root->getRoot()))->get("bool");
+    assert((dynamic_cast<const JSonPrimitive<bool> *> (tmp)) != nullptr);
+    assert((dynamic_cast<const JSonPrimitive<bool> *> (tmp))->getValue() == true);
+    tmp = ((JSonObject *)(root->getRoot()))->get("int");
+    assert((dynamic_cast<const JSonPrimitive<int> *> (tmp)) != nullptr);
+    assert((dynamic_cast<const JSonPrimitive<int> *> (tmp))->getValue() == 42);
+    tmp = ((JSonObject *)(root->getRoot()))->get("str");
+    assert((dynamic_cast<const JSonPrimitive<std::string> *> (tmp)) != nullptr);
+    assert((dynamic_cast<const JSonPrimitive<std::string> *> (tmp))->getValue() == "coucou");
+    tmp = ((JSonObject *)(root->getRoot()))->get("float");
+    assert((dynamic_cast<const JSonPrimitive<float> *> (tmp)) != nullptr);
+    assert((dynamic_cast<const JSonPrimitive<float> *> (tmp))->getValue() == 12.34f);
+    tmp = ((JSonObject *)(root->getRoot()))->get("arrayOfInt");
+    const JSonArray *arr2 = dynamic_cast<const JSonArray *> (tmp);
+    assert(arr2 != nullptr);
+    assert(arr2->size() == 4);
+    it = arr2->cbegin();
+    assert((dynamic_cast<JSonPrimitive<int> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<int> *)(*it))->getValue() == 1);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<int> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<int> *)(*it))->getValue() == 2);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<int> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<int> *)(*it))->getValue() == 3);
+    it++;
+    assert((dynamic_cast<JSonPrimitive<float> *> (*it)) != nullptr);
+    assert(((JSonPrimitive<float> *)(*it))->getValue() == 4.5f);
+    delete root;
+}
+
+int main(int ac, char **av)
+{
+    checkTypes();
+    exit(EXIT_SUCCESS);
+}
+