1 changed files with 570 additions and 0 deletions
			
			
		@ -0,0 +1,570 @@ | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2022 Riyyi | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * SPDX-License-Identifier: MIT | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstddef>    // nullptr_t | 
				
			||||||
 | 
					#include <cstdint>    // uint32_t | 
				
			||||||
 | 
					#include <functional> // function | 
				
			||||||
 | 
					#include <map> | 
				
			||||||
 | 
					#include <string> | 
				
			||||||
 | 
					#include <unordered_map> | 
				
			||||||
 | 
					#include <vector> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "macro.h" | 
				
			||||||
 | 
					#include "testcase.h" | 
				
			||||||
 | 
					#include "testsuite.h" | 
				
			||||||
 | 
					#include "util/json/array.h" | 
				
			||||||
 | 
					#include "util/json/job.h" | 
				
			||||||
 | 
					#include "util/json/lexer.h" | 
				
			||||||
 | 
					#include "util/json/parser.h" | 
				
			||||||
 | 
					#include "util/json/serializer.h" | 
				
			||||||
 | 
					#include "util/json/value.h" | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DONT_PRINT_PARSER_ERRORS | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DONT_PRINT_PARSER_ERRORS | 
				
			||||||
 | 
					#define EXEC(x) x | 
				
			||||||
 | 
					#else | 
				
			||||||
 | 
					#define EXEC(x)                                   \ | 
				
			||||||
 | 
						stdout = Test::TestSuite::the().outputNull(); \
 | 
				
			||||||
 | 
						x;                                            \
 | 
				
			||||||
 | 
						stdout = Test::TestSuite::the().outputStd(); | 
				
			||||||
 | 
					#endif | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Json::Token> lex(const std::string& input) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						EXEC( | 
				
			||||||
 | 
							Json::Job job(input); | 
				
			||||||
 | 
							Json::Lexer lexer(&job); | 
				
			||||||
 | 
							lexer.analyze();); | 
				
			||||||
 | 
						return *job.tokens(); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Json::Value parse(const std::string& input) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						EXEC( | 
				
			||||||
 | 
							Json::Job job(input); | 
				
			||||||
 | 
							Json::Lexer lexer(&job); | 
				
			||||||
 | 
							lexer.analyze();); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!job.success()) { | 
				
			||||||
 | 
							return nullptr; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EXEC( | 
				
			||||||
 | 
							Json::Parser parser(&job); | 
				
			||||||
 | 
							Json::Value json = parser.parse();); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!job.success()) { | 
				
			||||||
 | 
							return nullptr; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return json; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string serialize(const std::string& input, uint32_t indent = 0) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						EXEC( | 
				
			||||||
 | 
							auto json = Json::Value::parse(input);); | 
				
			||||||
 | 
						return json.dump(indent); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonLexer) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						std::vector<Json::Token> tokens; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Literal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("true"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "true"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::Literal); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("false"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "false"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::Literal); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("null"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "null"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::Literal); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("3.14"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "3.14"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::Number); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("-3.14e+2"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "-3.14e+2"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::Number); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("+3.14"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "+"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::None); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex(R"("a string")"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "a string"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex(R"("a string""another string")"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "a string"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[1].symbol, "another string"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("\"a string\nwill break on the newline symbol\""); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "a string"); | 
				
			||||||
 | 
						EXPECT(tokens[0].type == Json::Token::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("[]"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "["); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[1].symbol, "]"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("[\n\n\n]"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "["); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[1].symbol, "]"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("{}"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "{"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[1].symbol, "}"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokens = lex("{\n\n\n}"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[0].symbol, "{"); | 
				
			||||||
 | 
						EXPECT_EQ(tokens[1].symbol, "}"); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonParser) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Json::Value json; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("null"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("true"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Bool); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("false"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Bool); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("3.14"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Number); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"("a string")"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("["); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("[ 123"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("[ 123,"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("[ 123, ]"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("[ 123 456 ]"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("[]"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"([ "element", 3.14 ])"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("{"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name")"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name":)"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name":,)"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name":"value")"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name":"value",)"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name":"value", })"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name" "value" })"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ 123 })"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("{}"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse(R"({ "name": "value", "name2": 3.14 })"); | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Multiple root elements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("54 false"); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("3.14, 666"); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = parse("true\nfalse"); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonToJsonValue) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Json::Value json; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = {}; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = nullptr; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 0); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Null); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = true; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Bool); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = false; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Bool); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = 666; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Number); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = 3.14; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Number); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char* characters = "my string"; | 
				
			||||||
 | 
						json = characters; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string string = "my string"; | 
				
			||||||
 | 
						json = string; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::String); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Nested Array with multiple types
 | 
				
			||||||
 | 
						json = { "element", 3.14, true, nullptr, { "nested element", { "more nesting", { 1, 2, 3, "yes" } } } }; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 5); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Nested Object with multiple types
 | 
				
			||||||
 | 
						json = { { "name", "value" }, { "name2", 3.14 }, { "name3", true }, { "name4", nullptr }, { "name5", { { "nested name", "value" } } } }; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 5); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Array with singular type
 | 
				
			||||||
 | 
						std::vector<std::string> vector = { "element", "element2", "element3" }; | 
				
			||||||
 | 
						json = vector; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 3); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object with singular type
 | 
				
			||||||
 | 
						std::map<std::string, std::string> map = { { "name", "value" }, { "name2", "value2" } }; | 
				
			||||||
 | 
						json = map; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object with singular type
 | 
				
			||||||
 | 
						std::unordered_map<std::string, std::string> unorderedMap = { { "name", "value" }, { "name2", "value2" } }; | 
				
			||||||
 | 
						json = unorderedMap; | 
				
			||||||
 | 
						EXPECT_EQ(json.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(json.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonFromJsonValue) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Json::Value json; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = nullptr; | 
				
			||||||
 | 
						EXPECT_EQ(json.get<std::nullptr_t>(), nullptr); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = true; | 
				
			||||||
 | 
						EXPECT_EQ(json.get<bool>(), true); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = false; | 
				
			||||||
 | 
						EXPECT_EQ(json.get<bool>(), false); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = 666; | 
				
			||||||
 | 
						EXPECT_EQ(json.get<int>(), 666); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						json = 3.14; | 
				
			||||||
 | 
						EXPECT_EQ(json.get<double>(), 3.14); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string string; | 
				
			||||||
 | 
						json = "my string"; | 
				
			||||||
 | 
						json.getTo(string); | 
				
			||||||
 | 
						EXPECT_EQ(string, "my string"); | 
				
			||||||
 | 
						EXPECT_EQ(json.get<std::string>(), "my string"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Array with singular type
 | 
				
			||||||
 | 
						json = { "element", "element2" }; | 
				
			||||||
 | 
						EXPECT_EQ(json[0].get<std::string>(), "element"); | 
				
			||||||
 | 
						EXPECT_EQ(json.at(1).get<std::string>(), "element2"); | 
				
			||||||
 | 
						auto array = json.get<std::vector<std::string>>(); | 
				
			||||||
 | 
						EXPECT_EQ(array.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(array[0], "element"); | 
				
			||||||
 | 
						EXPECT_EQ(array[1], "element2"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Array with multiple types
 | 
				
			||||||
 | 
						json = { "string", 3.14, true, nullptr }; | 
				
			||||||
 | 
						EXPECT_EQ(json[0].get<std::string>(), "string"); | 
				
			||||||
 | 
						EXPECT_EQ(json.at(1).get<double>(), 3.14); | 
				
			||||||
 | 
						EXPECT_EQ(json[2].get<bool>(), true); | 
				
			||||||
 | 
						EXPECT_EQ(json[3].get<std::nullptr_t>(), nullptr); | 
				
			||||||
 | 
						auto valueArray = json.get<std::vector<Json::Value>>(); | 
				
			||||||
 | 
						EXPECT_EQ(valueArray.size(), 4); | 
				
			||||||
 | 
						EXPECT_EQ(valueArray[0].get<std::string>(), "string"); | 
				
			||||||
 | 
						EXPECT_EQ(valueArray[1].get<double>(), 3.14); | 
				
			||||||
 | 
						EXPECT_EQ(valueArray[2].get<bool>(), true); | 
				
			||||||
 | 
						EXPECT_EQ(valueArray[3].get<std::nullptr_t>(), nullptr); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Nested Array with multiple types
 | 
				
			||||||
 | 
						json = { | 
				
			||||||
 | 
							"value", | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								"thing", | 
				
			||||||
 | 
								666, | 
				
			||||||
 | 
							}, | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								{ | 
				
			||||||
 | 
									3.14, | 
				
			||||||
 | 
								}, | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						}; | 
				
			||||||
 | 
						EXPECT_EQ(json[0].get<std::string>(), "value"); | 
				
			||||||
 | 
						EXPECT_EQ(json.at(1)[0].get<std::string>(), "thing"); | 
				
			||||||
 | 
						EXPECT_EQ(json[1].at(1).get<int>(), 666); | 
				
			||||||
 | 
						EXPECT_EQ(json[2][0][0].get<double>(), 3.14); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object with singular type
 | 
				
			||||||
 | 
						json = { { "name", "value" }, { "name2", "value2" } }; | 
				
			||||||
 | 
						EXPECT_EQ(json["name"].get<std::string>(), "value"); | 
				
			||||||
 | 
						EXPECT_EQ(json.at("name2").get<std::string>(), "value2"); | 
				
			||||||
 | 
						auto object = json.get<std::map<std::string, std::string>>(); | 
				
			||||||
 | 
						EXPECT_EQ(object.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(object["name"], "value"); | 
				
			||||||
 | 
						EXPECT_EQ(object["name2"], "value2"); | 
				
			||||||
 | 
						auto unorderedObject = json.get<std::unordered_map<std::string, std::string>>(); | 
				
			||||||
 | 
						EXPECT_EQ(unorderedObject.size(), 2); | 
				
			||||||
 | 
						EXPECT_EQ(unorderedObject["name"], "value"); | 
				
			||||||
 | 
						EXPECT_EQ(unorderedObject["name2"], "value2"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Object with multiple types
 | 
				
			||||||
 | 
						json = { { "name", "value" }, { "name2", 3.14 }, { "name3", true }, { "name4", nullptr } }; | 
				
			||||||
 | 
						EXPECT_EQ(json["name"].get<std::string>(), "value"); | 
				
			||||||
 | 
						EXPECT_EQ(json.at("name2").get<double>(), 3.14); | 
				
			||||||
 | 
						EXPECT_EQ(json["name3"].get<bool>(), true); | 
				
			||||||
 | 
						EXPECT_EQ(json["name4"].get<std::nullptr_t>(), nullptr); | 
				
			||||||
 | 
						auto valueObject = json.get<std::map<std::string, Json::Value>>(); | 
				
			||||||
 | 
						EXPECT_EQ(valueObject.size(), 4); | 
				
			||||||
 | 
						EXPECT_EQ(valueObject["name"].get<std::string>(), "value"); | 
				
			||||||
 | 
						EXPECT_EQ(valueObject["name2"].get<double>(), 3.14); | 
				
			||||||
 | 
						EXPECT_EQ(valueObject["name3"].get<bool>(), true); | 
				
			||||||
 | 
						EXPECT_EQ(valueObject["name4"].get<std::nullptr_t>(), nullptr); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Nested Object with multiple types
 | 
				
			||||||
 | 
						json = { | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								"name", | 
				
			||||||
 | 
								"value", | 
				
			||||||
 | 
							}, | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								"nest 1-deep", | 
				
			||||||
 | 
								{ { | 
				
			||||||
 | 
									"number", | 
				
			||||||
 | 
									1, | 
				
			||||||
 | 
								} }, | 
				
			||||||
 | 
							}, | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								"nest 2-deep", | 
				
			||||||
 | 
								{ { | 
				
			||||||
 | 
									"nest 1-deep", | 
				
			||||||
 | 
									{ { | 
				
			||||||
 | 
										"bool", | 
				
			||||||
 | 
										true, | 
				
			||||||
 | 
									} }, | 
				
			||||||
 | 
								} }, | 
				
			||||||
 | 
							}, | 
				
			||||||
 | 
						}; | 
				
			||||||
 | 
						EXPECT_EQ(json["name"].get<std::string>(), "value"); | 
				
			||||||
 | 
						EXPECT_EQ(json["nest 1-deep"]["number"].get<int>(), 1); | 
				
			||||||
 | 
						EXPECT_EQ(json["nest 2-deep"]["nest 1-deep"]["bool"].get<bool>(), true); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonImplicitConversion) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						Json::Value array; | 
				
			||||||
 | 
						array[0]; | 
				
			||||||
 | 
						EXPECT_EQ(array.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Json::Value arrayEmplace; | 
				
			||||||
 | 
						arrayEmplace.emplace_back("element"); | 
				
			||||||
 | 
						arrayEmplace.emplace_back({ "nested element" }); | 
				
			||||||
 | 
						EXPECT_EQ(arrayEmplace.type(), Json::Value::Type::Array); | 
				
			||||||
 | 
						EXPECT_EQ(arrayEmplace[1].type(), Json::Value::Type::Array); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Json::Value object; | 
				
			||||||
 | 
						object[""]; | 
				
			||||||
 | 
						EXPECT_EQ(object.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Json::Value objectEmplace; | 
				
			||||||
 | 
						objectEmplace.emplace("name", "value"); | 
				
			||||||
 | 
						objectEmplace.emplace("name2", { { "nested name", "value" } }); | 
				
			||||||
 | 
						EXPECT_EQ(objectEmplace.type(), Json::Value::Type::Object); | 
				
			||||||
 | 
						EXPECT_EQ(objectEmplace["name2"].type(), Json::Value::Type::Object); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE(JsonSerializer) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						EXPECT_EQ(serialize(""), "null"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("null"), "null"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("true"), "true"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("false"), "false"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("3.14"), "3.14"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"("string")"), R"("string")"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize("\n\n\n"), "null"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("null\n"), "null"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("true\n"), "true"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("false\n"), "false"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("3.14\n"), "3.14"); | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"("string")" "\n"), R"("string")"); | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[\n\n\n]"), "[]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[null]"), "[null]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[true]"), "[true]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[false]"), "[false]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[3.14]"), "[3.14]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"(["string"])"), R"(["string"])"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[\n\n\n]", 4), "[\n]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[null]", 4), "[\n    null\n]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[true]", 4), "[\n    true\n]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[false]", 4), "[\n    false\n]"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize("[3.14]", 4), "[\n    3.14\n]"); | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"(["string"])", 4), "[\n    " R"("string")" "\n]"); | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check for trailing comma on last array element
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"([1])"), R"([1])"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"([1,2])"), R"([1,2])"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"([1,2,3])"), R"([1,2,3])"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check for trailing comma on last object member
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"({"n1":"v1"})"), R"({"n1":"v1"})"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"({"n1":"v1", "n2":"v2"})"), R"({"n1":"v1","n2":"v2"})"); | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"({"n1":"v1", "n2":"v2", "n3":"v3"})"), R"({"n1":"v1","n2":"v2","n3":"v3"})"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						EXPECT_EQ(serialize(R"({ | 
				
			||||||
 | 
						"object member one": [ | 
				
			||||||
 | 
							"array element one" | 
				
			||||||
 | 
						], | 
				
			||||||
 | 
						"object member two": [ | 
				
			||||||
 | 
							"array element one", | 
				
			||||||
 | 
							"array element two" | 
				
			||||||
 | 
						], | 
				
			||||||
 | 
						"object member three": [ | 
				
			||||||
 | 
							"array element one", | 
				
			||||||
 | 
							2, | 
				
			||||||
 | 
							3.0, | 
				
			||||||
 | 
							4.56, | 
				
			||||||
 | 
							true, | 
				
			||||||
 | 
							false, | 
				
			||||||
 | 
							null | 
				
			||||||
 | 
						], | 
				
			||||||
 | 
						"object member four": 3.14, | 
				
			||||||
 | 
						"object member five": "value five", | 
				
			||||||
 | 
						"object member six": null, | 
				
			||||||
 | 
						"object member seven": { "no": 0 } | 
				
			||||||
 | 
					})", 4), R"({ | 
				
			||||||
 | 
					    "object member five": "value five", | 
				
			||||||
 | 
					    "object member four": 3.14, | 
				
			||||||
 | 
					    "object member one": [ | 
				
			||||||
 | 
					        "array element one" | 
				
			||||||
 | 
					    ], | 
				
			||||||
 | 
					    "object member seven": { | 
				
			||||||
 | 
					        "no": 0 | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    "object member six": null, | 
				
			||||||
 | 
					    "object member three": [ | 
				
			||||||
 | 
					        "array element one", | 
				
			||||||
 | 
					        2, | 
				
			||||||
 | 
					        3, | 
				
			||||||
 | 
					        4.56, | 
				
			||||||
 | 
					        true, | 
				
			||||||
 | 
					        false, | 
				
			||||||
 | 
					        null | 
				
			||||||
 | 
					    ], | 
				
			||||||
 | 
					    "object member two": [ | 
				
			||||||
 | 
					        "array element one", | 
				
			||||||
 | 
					        "array element two" | 
				
			||||||
 | 
					    ] | 
				
			||||||
 | 
					})"); | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue