view C++/tests/Json/main.cpp @ 389:e292f0fa5395

Socket: resurrect SSL
author David Demelier <markand@malikania.fr>
date Tue, 30 Jun 2015 15:17:01 +0200
parents 0b576ee64d45
children d5ec1174b707
line wrap: on
line source

/*
 * main.cpp -- test the jansson wrapper
 *
 * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <set>
#include <unordered_map>

#include <gtest/gtest.h>

#include "Json.h"

/* --------------------------------------------------------
 * Miscellaneous
 * -------------------------------------------------------- */

TEST(Misc, copy)
{
	JsonObject object;

	object.set("integer", 123);
	object.set("true", true);

	JsonObject object2{object};

	ASSERT_TRUE(object2.isObject());
	ASSERT_EQ(123, object2["integer"].toInteger());
	ASSERT_TRUE(object2["true"].isTrue());
}

TEST(Misc, copyAssign)
{
	JsonObject object;

	{
		JsonObject tmp;

		tmp.set("integer", 123);
		tmp.set("true", true);

		object = tmp;
	}

	ASSERT_TRUE(object.isObject());
	ASSERT_EQ(123, object["integer"].toInteger());
	ASSERT_TRUE(object["true"].isTrue());
}

TEST(Misc, move)
{
	JsonObject object(123);
	JsonObject object2(std::move(object));

	ASSERT_TRUE(object.isNull());
	ASSERT_TRUE(object2.isInteger());
	ASSERT_EQ(123, object2.toInteger());
}

TEST(Misc, moveAssign)
{
	JsonObject object(123);
	JsonObject object2;

	object2 = std::move(object);

	ASSERT_TRUE(object.isNull());
	ASSERT_TRUE(object2.isInteger());
	ASSERT_EQ(123, object2.toInteger());
}

/* --------------------------------------------------------
 * JsonValue constructors
 * -------------------------------------------------------- */

TEST(Constructors, null)
{
	try {
		JsonValue value;

		ASSERT_TRUE(value.isNull());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Constructors, boolean)
{
	try {
		JsonValue value{true};

		ASSERT_TRUE(value.isTrue());
		ASSERT_TRUE(value.isBoolean());
		ASSERT_FALSE(value.isFalse());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Constructors, integer)
{
	try {
		JsonValue value{123};

		ASSERT_TRUE(value.isInteger());
		ASSERT_TRUE(value.isNumber());
		ASSERT_FALSE(value.isReal());
		ASSERT_EQ(123, value.toInteger());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Constructors, real)
{
	try {
		JsonValue value{9.2};

		ASSERT_TRUE(value.isReal());
		ASSERT_TRUE(value.isNumber());
		ASSERT_FALSE(value.isInteger());
		ASSERT_EQ(9.2, value.toReal());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Constructors, string)
{
	try {
		JsonValue value("hello");

		ASSERT_TRUE(value.isString());
		ASSERT_EQ("hello", value.toString());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * Object
 * -------------------------------------------------------- */

TEST(Object, set)
{
	try {
		JsonObject object;

		object.set("integer", 123);
		object.set("string", "hello");
		object.set("true", true);

		ASSERT_EQ(123, object["integer"].toInteger());
		ASSERT_EQ("hello", object["string"].toString());
		ASSERT_TRUE(object["true"].isTrue());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Object, clear)
{
	try {
		JsonObject object;

		object.set("integer", 123);
		object.set("string", "hello");
		object.set("true", true);

		object.clear();

		ASSERT_EQ(0, static_cast<int>(object.size()));
		ASSERT_FALSE(object.contains("integer"));
		ASSERT_FALSE(object.contains("string"));
		ASSERT_FALSE(object.contains("true"));
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Object, erase)
{
	try {
		JsonObject object;

		object.set("integer", 123);
		object.set("string", "hello");
		object.set("true", true);

		object.erase("integer");

		ASSERT_EQ(2, static_cast<int>(object.size()));
		ASSERT_FALSE(object.contains("integer"));
		ASSERT_TRUE(object.contains("string"));
		ASSERT_TRUE(object.contains("true"));
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(ObjectInitializer, simple)
{
	try {
		JsonObject object{
			{ "username", "jean" },
			{ "age", 99 }
		};

		ASSERT_EQ(2, static_cast<int>(object.size()));
		ASSERT_EQ("jean", object["username"].toString());
		ASSERT_EQ(99, object["age"].toInteger());
	} catch (const std::exception &ex) {
		FAIL() << ex.what();
	}
}

TEST(ObjectInitializer, deep)
{
	try {
		JsonObject object{
			{ "username", "jean"		},
			{ "age", 99			},
			{ "network", JsonObject{
					{ "port", 9999 		},
					{ "host", "localhost"	}
				}
			}
		};

		// First
		ASSERT_EQ(3, static_cast<int>(object.size()));
		ASSERT_EQ("jean", object["username"].toString());
		ASSERT_EQ(99, object["age"].toInteger());

		// Second
		JsonObject network = object["network"].toObject();
		ASSERT_TRUE(network.isObject());
		ASSERT_EQ(2, static_cast<int>(network.size()));
		ASSERT_EQ(9999, network["port"].toInteger());
		ASSERT_EQ("localhost", network["host"].toString());
	} catch (const std::exception &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * Array
 * -------------------------------------------------------- */

TEST(Array, push)
{
	try {
		JsonArray array;

		ASSERT_TRUE(array.isArray());

		array.push(1);
		array.push("hello");
		array.push(true);

		ASSERT_EQ(3, static_cast<int>(array.size()));
		ASSERT_TRUE(array[0].isTrue());
		ASSERT_EQ("hello", array[1].toString());
		ASSERT_EQ(1, array[2].toInteger());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, append)
{
	try {
		JsonArray array;

		ASSERT_TRUE(array.isArray());

		array.append(1);
		array.append("hello");
		array.append(true);

		ASSERT_EQ(3, static_cast<int>(array.size()));
		ASSERT_EQ(1, array[0].toInteger());
		ASSERT_EQ("hello", array[1].toString());
		ASSERT_TRUE(array[2].isTrue());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, insert)
{
	try {
		JsonArray array;

		ASSERT_TRUE(array.isArray());

		array.insert(1, 0);
		array.insert("hello", 1);
		array.insert(true, 0);

		ASSERT_EQ(3, static_cast<int>(array.size()));
		ASSERT_TRUE(array[0].isTrue());
		ASSERT_EQ(1, array[1].toInteger());
		ASSERT_EQ("hello", array[2].toString());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, clear)
{
	try {
		JsonArray array;

		array.append(1);
		array.append("hello");
		array.append(true);

		array.clear();

		ASSERT_EQ(0, static_cast<int>(array.size()));
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, erase)
{
	try {
		JsonArray array;

		array.append(1);
		array.append("hello");
		array.append(true);

		array.erase(0);

		ASSERT_EQ(2, static_cast<int>(array.size()));
		ASSERT_EQ("hello", array[0].toString());
		ASSERT_TRUE(array[1].isTrue());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, eraseIterator)
{
	try {
		JsonArray array;

		array.append(1);
		array.append("hello");
		array.append(true);

		array.erase(array.begin());

		ASSERT_EQ(2, static_cast<int>(array.size()));
		ASSERT_EQ("hello", array[0].toString());
		ASSERT_TRUE(array[1].isTrue());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(Array, eraseConstIterator)
{
	try {
		JsonArray array;

		array.append(1);
		array.append("hello");
		array.append(true);

		array.erase(array.cbegin());

		ASSERT_EQ(2, static_cast<int>(array.size()));
		ASSERT_EQ("hello", array[0].toString());
		ASSERT_TRUE(array[1].isTrue());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(ArrayInitializer, simple)
{
	try {
		JsonArray array{123, true, "hello"};

		ASSERT_EQ(3, static_cast<int>(array.size()));
		ASSERT_EQ(123, array[0].toInteger());
		ASSERT_TRUE(array[1].isTrue());
		ASSERT_EQ("hello", array[2].toString());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(ArrayInitializer, deep)
{
	try {
		JsonArray array{
			123,
			true,
			"hello",
			JsonArray{
				321,
				false,
				"olleh"
			}
		};

		// First
		ASSERT_EQ(4, static_cast<int>(array.size()));
		ASSERT_EQ(123, array[0].toInteger());
		ASSERT_TRUE(array[1].isTrue());
		ASSERT_EQ("hello", array[2].toString());

		// Second
		JsonArray array2 = array[3].toArray();
		ASSERT_TRUE(array.isArray());
		ASSERT_EQ(3, static_cast<int>(array2.size()));
		ASSERT_EQ(321, array2[0].toInteger());
		ASSERT_TRUE(array2[1].isFalse());
		ASSERT_EQ("olleh", array2[2].toString());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * I/O
 * -------------------------------------------------------- */

TEST(FileRead, simple)
{
	try {
		JsonDocument doc(std::ifstream("Json/simple.json"));

		ASSERT_TRUE(doc.isObject());
		ASSERT_FALSE(doc.isArray());

		JsonObject object = doc.toObject();
		JsonArray array = doc.toArray();

		ASSERT_TRUE(object.isObject());
		ASSERT_FALSE(array.isArray());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(FileRead, fail)
{
	try {
		JsonDocument(std::ifstream("Json/notexist.json"));

		FAIL() << "Exception expected";
	} catch (const JsonError &) {
	}
}

TEST(FileWrite, simple)
{
	try {
		JsonObject object{
			{ "name", "jean" },
			{ "age", 99 }
		};

		object.write(std::ofstream("object-write.json"));

		JsonObject object2 = JsonDocument(std::ifstream("object-write.json")).toObject();

		ASSERT_EQ(object2, object);
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(StringRead, simple)
{
	try {
		JsonDocument doc("{ \"license\": \"ISC\" }");

		ASSERT_TRUE(doc.isObject());
		ASSERT_FALSE(doc.isArray());

		JsonObject object = doc.toObject();
		JsonArray array = doc.toArray();

		ASSERT_TRUE(object.isObject());
		ASSERT_FALSE(array.isArray());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST(StringRead, fail)
{
	try {
		JsonDocument("{ \"license\": ISC }");

		FAIL() << "Exception expected";
	} catch (const JsonError &ex) {
	}
}

TEST(StringWrite, simple)
{
	try {
		JsonObject object{
			{ "name", "jean" },
			{ "age", 99 }
		};

		JsonObject object2 = JsonDocument(object.dump()).toObject();

		ASSERT_EQ(object2, object);
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * Object read
 * -------------------------------------------------------- */

class ObjectRead : public testing::Test {
protected:
	JsonObject m_object;
	JsonObject m_objectAll;

public:
	ObjectRead()
	{
		m_object = JsonDocument(std::ifstream("Json/object.json")).toObject();
		m_objectAll = JsonDocument(std::ifstream("Json/object-all.json")).toObject();
	}
};

TEST_F(ObjectRead, simple)
{
	try {
		JsonValue name = m_object["name"];
		JsonValue description = m_object["description"];

		ASSERT_TRUE(name.isString());
		ASSERT_TRUE(description.isString());
		ASSERT_EQ("simple", name.toString());
		ASSERT_EQ("basic JSON file", description.toString());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST_F(ObjectRead, all)
{
	try {
		ASSERT_TRUE(m_objectAll.contains("integer"));
		ASSERT_FALSE(m_objectAll.contains("unexistant"));

		ASSERT_TRUE(m_objectAll["integer"].isInteger());
		ASSERT_TRUE(m_objectAll["integer"].isNumber());
		ASSERT_EQ(123, m_objectAll["integer"].toInteger());

		ASSERT_TRUE(m_objectAll["real"].isReal());
		ASSERT_TRUE(m_objectAll["real"].isNumber());
		ASSERT_EQ(9.2, m_objectAll["real"].toReal());

		ASSERT_TRUE(m_objectAll["false"].isBoolean());
		ASSERT_TRUE(m_objectAll["false"].isFalse());
		ASSERT_FALSE(m_objectAll["false"].isTrue());

		ASSERT_TRUE(m_objectAll["true"].isBoolean());
		ASSERT_TRUE(m_objectAll["true"].isTrue());
		ASSERT_FALSE(m_objectAll["true"].isFalse());

		ASSERT_TRUE(m_objectAll["null"].isNull());

		ASSERT_TRUE(m_objectAll["object"].isObject());
		ASSERT_TRUE(m_objectAll["array"].isArray());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * Array read
 * -------------------------------------------------------- */

class ArrayRead : public testing::Test {
protected:
	JsonArray m_array;
	JsonArray m_arrayAll;

public:
	ArrayRead()
	{
		m_array = JsonDocument(std::ifstream("Json/array.json")).toArray();
		m_arrayAll = JsonDocument(std::ifstream("Json/array-all.json")).toArray();
	}
};

TEST_F(ArrayRead, simple)
{
	try {
		ASSERT_EQ(3, static_cast<int>(m_array.size()));
		ASSERT_EQ(1, m_array[0].toInteger());
		ASSERT_EQ(2, m_array[1].toInteger());
		ASSERT_EQ(3, m_array[2].toInteger());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

TEST_F(ArrayRead, all)
{
	try {
		ASSERT_TRUE(m_arrayAll[0].isInteger());
		ASSERT_TRUE(m_arrayAll[0].isNumber());
		ASSERT_EQ(123, m_arrayAll[0].toInteger());

		ASSERT_TRUE(m_arrayAll[1].isReal());
		ASSERT_TRUE(m_arrayAll[1].isNumber());
		ASSERT_EQ(9.2, m_arrayAll[1].toReal());

		ASSERT_TRUE(m_arrayAll[2].isBoolean());
		ASSERT_TRUE(m_arrayAll[2].isFalse());
		ASSERT_FALSE(m_arrayAll[2].isTrue());

		ASSERT_TRUE(m_arrayAll[3].isBoolean());
		ASSERT_TRUE(m_arrayAll[3].isTrue());
		ASSERT_FALSE(m_arrayAll[3].isFalse());

		ASSERT_TRUE(m_arrayAll[4].isNull());

		ASSERT_TRUE(m_arrayAll[5].isObject());
		ASSERT_TRUE(m_arrayAll[6].isArray());
	} catch (const JsonError &ex) {
		FAIL() << ex.what();
	}
}

/* --------------------------------------------------------
 * Object iterators
 * -------------------------------------------------------- */

class ObjectIteratorsTest : public testing::Test {
protected:
	JsonObject m_object;

public:
	ObjectIteratorsTest()
	{
		m_object.set("integer", 1);
		m_object.set("string", "hello");
		m_object.set("boolean", true);
	}
};

TEST_F(ObjectIteratorsTest, operators)
{
	// Read only (non const)
	{
		std::set<std::string> expected{"boolean", "integer", "string"};
		std::set<std::string> result;
		std::unordered_map<std::string, JsonValue> values;
		JsonObject::iterator it = m_object.begin();
		JsonObject::iterator end = m_object.end();

		while (it != end) {
			values.insert({it->first, it->second});
			result.insert((*it++).first);
		}

		ASSERT_EQ(expected, result);
		ASSERT_EQ(1, values["integer"].toInteger());
		ASSERT_EQ("hello", values["string"].toString());
		ASSERT_TRUE(values["boolean"].isTrue());
	}

	// Read only (const)
	{
		std::set<std::string> expected{"boolean", "integer", "string"};
		std::set<std::string> result;
		std::unordered_map<std::string, JsonValue> values;
		JsonObject::const_iterator it = m_object.cbegin();
		JsonObject::const_iterator end = m_object.cend();

		while (it != end) {
			values.insert({it->first, it->second});
			result.insert((*it++).first);
		}

		ASSERT_EQ(expected, result);
		ASSERT_EQ(1, values["integer"].toInteger());
		ASSERT_EQ("hello", values["string"].toString());
		ASSERT_TRUE(values["boolean"].isTrue());
	}
}

TEST_F(ObjectIteratorsTest, assign)
{
	// Assign (non const)
	{
		JsonObject::iterator it = m_object.begin();
		std::string key = it->first;

		it->second = JsonValue("CHANGED");

		ASSERT_EQ("CHANGED", m_object[key].toString());
		ASSERT_EQ("CHANGED", it->second.toString());
		ASSERT_EQ(3, static_cast<int>(m_object.size()));
	}
}

TEST_F(ObjectIteratorsTest, assignConst)
{
	// Assign (const)
	{
		JsonObject::const_iterator it = m_object.cbegin();
		std::string key = it->first;
		JsonValue orig = it->second;

		it->second = JsonValue("CHANGED");

		ASSERT_TRUE(m_object.contains(key));
		ASSERT_EQ(orig, m_object[key]);
		ASSERT_EQ(3, static_cast<int>(m_object.size()));
	}
}

/* --------------------------------------------------------
 * Array iterators
 * -------------------------------------------------------- */

class ArrayIteratorsTest : public testing::Test {
protected:
	JsonArray m_array;

public:
	ArrayIteratorsTest()
	{
		m_array.append(1);
		m_array.append("hello");
		m_array.append(true);
	}
};

TEST_F(ArrayIteratorsTest, operators)
{
	// Read only (non const)
	{
		JsonArray::iterator it = m_array.begin();

		ASSERT_EQ(1, (*it).toInteger());
		ASSERT_EQ(1, it->toInteger());
		ASSERT_EQ("hello", it[1].toString());
		ASSERT_TRUE(it[2].isTrue());

		JsonArray::iterator it2 = it + 1;
		ASSERT_EQ(1, it2[-1].toInteger());
		ASSERT_EQ("hello", it2->toString());
		ASSERT_TRUE(it2[1].isTrue());

		JsonArray::iterator it3 = it;
		ASSERT_TRUE(it2 != it);
		ASSERT_FALSE(it3 != it);

		ASSERT_FALSE(it2 == it);
		ASSERT_TRUE(it3 == it);

		ASSERT_TRUE(it3 >= it);
		ASSERT_TRUE(it2 >= it);

		ASSERT_TRUE(it2 > it);
		ASSERT_FALSE(it3 > it);

		ASSERT_FALSE(it2 <= it);
		ASSERT_TRUE(it3 <= it);

		ASSERT_FALSE(it2 < it);
		ASSERT_FALSE(it3 < it);
	}

	// Read only (const)
	{
		JsonArray::const_iterator it = m_array.cbegin();

		ASSERT_EQ(1, (*it).toInteger());
		ASSERT_EQ(1, it->toInteger());
		ASSERT_EQ("hello", it[1].toString());
		ASSERT_TRUE(it[2].isTrue());

		JsonArray::const_iterator it2 = it + 1;
		ASSERT_EQ(1, it2[-1].toInteger());
		ASSERT_EQ("hello", it2->toString());
		ASSERT_TRUE(it2[1].isTrue());

		JsonArray::const_iterator it3 = it;
		ASSERT_TRUE(it2 != it);
		ASSERT_FALSE(it3 != it);

		ASSERT_FALSE(it2 == it);
		ASSERT_TRUE(it3 == it);

		ASSERT_TRUE(it3 >= it);
		ASSERT_TRUE(it2 >= it);

		ASSERT_TRUE(it2 > it);
		ASSERT_FALSE(it3 > it);

		ASSERT_FALSE(it2 <= it);
		ASSERT_TRUE(it3 <= it);

		ASSERT_FALSE(it2 < it);
		ASSERT_FALSE(it3 < it);
	}
}

TEST_F(ArrayIteratorsTest, assign)
{
	// Assign (non const)
	{
		JsonArray::iterator it = m_array.begin();

		*it = JsonValue(9999);

		ASSERT_EQ(3, static_cast<int>(m_array.size()));
		ASSERT_EQ(9999, it->toInteger());
		ASSERT_EQ(9999, m_array[0].toInteger());
	}
}

TEST_F(ArrayIteratorsTest, assignConst)
{
	// Assign (const)
	{
		JsonArray::const_iterator it = m_array.cbegin();

		*it = JsonValue(9999);

		ASSERT_EQ(3, static_cast<int>(m_array.size()));
		ASSERT_EQ(1, it->toInteger());
		ASSERT_EQ(1, m_array[0].toInteger());
	}
}

TEST_F(ArrayIteratorsTest, castToRef)
{
	JsonArray array{1, 2, 3};
	int i = 1;

	for (const JsonValue &v : array)
	{
		ASSERT_EQ(i++, v.toInteger());
	}
}

int main(int argc, char **argv)
{
	testing::InitGoogleTest(&argc, argv);

	return RUN_ALL_TESTS();
}