changeset 484:3ee3f3e53ee3

Json: add brand new Value::toJson to stringify a value
author David Demelier <markand@malikania.fr>
date Thu, 12 Nov 2015 11:46:04 +0100
parents 3f29e6c05983
children 898d8b29a4f1
files C++/modules/Json/Json.cpp C++/modules/Json/Json.h C++/tests/Json/main.cpp
diffstat 3 files changed, 170 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Json/Json.cpp	Thu Nov 12 08:57:21 2015 +0100
+++ b/C++/modules/Json/Json.cpp	Thu Nov 12 11:46:04 2015 +0100
@@ -16,10 +16,13 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "Json.h"
 
 #include <jansson.h>
 
+#include <sstream>
+
+#include "Json.h"
+
 namespace json {
 
 namespace {
@@ -107,6 +110,19 @@
 	return value;
 }
 
+std::string indent(int param, int level)
+{
+	std::string str;
+
+	if (param < 0) {
+		str = std::string(level, '\t');
+	} else if (param > 0) {
+		str = std::string(param * level, ' ');
+	}
+
+	return str;
+}
+
 } // !namespace
 
 void Value::copy(const Value &other)
@@ -255,6 +271,65 @@
 	*this = convert(json_load_file, file.path.c_str(), 0);
 }
 
+std::string Value::toJson(int level, int current) const
+{
+	std::ostringstream oss;
+
+	switch (m_type) {
+	case Type::Array: {
+		oss << '[' << (level != 0 ? "\n" : "");
+
+		unsigned total = m_array.size();
+		unsigned i = 0;
+		for (const auto &v : m_array) {
+			oss << indent(level, current + 1) << v.toJson(level, current + 1);
+			oss << (++i < total ? "," : "");
+			oss << (level != 0 ? "\n" : "");
+		}
+
+		oss << (level != 0 ? indent(level, current) : "") << ']';
+		break;
+	}
+	case Type::Boolean:
+		oss << (m_boolean ? true : false);
+		break;
+	case Type::Int:
+		oss << m_integer;
+		break;
+	case Type::Object: {
+		oss << '{' << (level != 0 ? "\n" : "");
+
+		unsigned total = m_object.size();
+		unsigned i = 0;
+		for (const auto &pair : m_object) {
+			oss << indent(level, current + 1);
+
+			/* Key and : */
+			oss << "\"" << pair.first << "\":" << (level != 0 ? " " : "");
+
+			/* Value */
+			oss << pair.second.toJson(level, current + 1);
+
+			/* Comma, new line if needed */
+			oss << (++i < total ? "," : "") << (level != 0 ? "\n" : "");
+		}
+
+		oss << (level != 0 ? indent(level, current) : "") << '}';
+		break;
+	}
+	case Type::Real:
+		oss << m_number;
+		break;
+	case Type::String:
+		oss << "\"" << escape(m_string) << "\"";
+		break;
+	default:
+		break;
+	}
+
+	return oss.str();
+}
+
 std::string escape(const std::string &value)
 {
 	std::string result;
--- a/C++/modules/Json/Json.h	Thu Nov 12 08:57:21 2015 +0100
+++ b/C++/modules/Json/Json.h	Thu Nov 12 11:46:04 2015 +0100
@@ -184,6 +184,7 @@
 
 	void copy(const Value &);
 	void move(Value &&);
+	std::string toJson(int indent, int current) const;
 
 	/**
 	 * @class BaseIterator
@@ -344,6 +345,7 @@
 		}
 	};
 
+public:
 	/**
 	 * Forward iterator.
 	 */
@@ -354,7 +356,6 @@
 	 */
 	using const_iterator = BaseIterator<const Value, typename std::deque<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>;
 
-public:
 	/**
 	 * Construct a null value.
 	 */
@@ -1111,6 +1112,18 @@
 
 		m_object.erase(key);
 	}
+
+	/**
+	 * Return this value as JSon representation.
+	 *
+	 * @param indent, the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces)
+	 * @param tabs, use tabs or not
+	 * @return the string
+	 */
+	inline std::string toJson(int indent = 2) const
+	{
+		return toJson(indent, 0);
+	}
 };
 
 /**
--- a/C++/tests/Json/main.cpp	Thu Nov 12 08:57:21 2015 +0100
+++ b/C++/tests/Json/main.cpp	Thu Nov 12 11:46:04 2015 +0100
@@ -780,6 +780,86 @@
 	}
 }
 
+/*
+ * Value::toJson
+ * ------------------------------------------------------------------
+ */
+
+TEST(ToJsonCompact, simpleObject)
+{
+	json::Value v = json::object({ { "x", 10 }, { "y", 20 } });
+	std::string result = v.toJson(0);
+	std::string expected = "{\"x\":10,\"y\":20}";
+
+	ASSERT_EQ(expected, result);
+}
+
+TEST(ToJsonCompact, deepObject)
+{
+	json::Value v = json::object({
+		{ "x", 10 },
+		{ "y", 20 },
+		{ "network", json::object({
+			{ "host", "localhost" }
+		})}
+	});
+
+	std::string result = v.toJson(0);
+	std::string expected = "{\"network\":{\"host\":\"localhost\"},\"x\":10,\"y\":20}";
+
+	ASSERT_EQ(expected, result);
+}
+
+TEST(ToJsonCompact, simpleArray)
+{
+	json::Value v = json::array({ 1, 2, 3 });
+	std::string result = v.toJson(0);
+	std::string expected = "[1,2,3]";
+
+	ASSERT_EQ(expected, result);
+}
+
+TEST(ToJsonCompact, deepArray)
+{
+	json::Value v = json::array({
+		1,
+		2,
+		json::array({ 4, 5, 6 })
+	});
+	std::string result = v.toJson(0);
+	std::string expected = "[1,2,[4,5,6]]";
+
+	ASSERT_EQ(expected, result);
+}
+
+TEST(ToJsonIndentSpaces, object)
+{
+	json::Value v = json::object({
+		{ "x", 10 },
+		{ "y", 20 },
+		{ "network", json::object({
+			{ "host", "localhost" }
+		})}
+	});
+	std::string result = v.toJson(2);
+	std::string expected = "{\n  \"network\": {\n    \"host\": \"localhost\"\n  },\n  \"x\": 10,\n  \"y\": 20\n}";
+
+	ASSERT_EQ(expected, result);
+}
+
+TEST(ToJsonIndentSpaces, array)
+{
+	json::Value v = json::array({
+		1,
+		2,
+		json::object({ { "x", 10 } })
+	});
+	std::string result = v.toJson();
+	std::string expected = "[\n  1,\n  2,\n  {\n    \"x\": 10\n  }\n]";
+
+	ASSERT_EQ(expected, result);
+}
+
 int main(int argc, char **argv)
 {
 	testing::InitGoogleTest(&argc, argv);