#include "JsonWriter.h"

#include <iostream>
#include <stdexcept>
#include <string>

namespace
{
int gFailures = 0;

void Expect(bool condition, const std::string& message)
{
	if (condition)
		return;

	++gFailures;
	std::cerr << "FAILED: " << message << "\n";
}

void ExpectEquals(const std::string& actual, const std::string& expected, const std::string& message)
{
	if (actual == expected)
		return;

	++gFailures;
	std::cerr << "FAILED: " << message << "\n"
		<< "expected: " << expected << "\n"
		<< "actual:   " << actual << "\n";
}

void TestEscapesStrings()
{
	using RenderCadenceCompositor::JsonWriter;

	ExpectEquals(
		JsonWriter::EscapeString("quote\" slash\\ newline\n tab\t"),
		"quote\\\" slash\\\\ newline\\n tab\\t",
		"string escape handles common escaped characters");

	std::string control;
	control.push_back(static_cast<char>(0x01));
	ExpectEquals(JsonWriter::EscapeString(control), "\\u0001", "string escape handles control characters");
}

void TestObjectSerialization()
{
	using RenderCadenceCompositor::JsonWriter;

	JsonWriter writer;
	writer.BeginObject();
	writer.KeyString("name", "cadence");
	writer.KeyDouble("renderFps", 59.94);
	writer.KeyBool("healthy", true);
	writer.KeyNull("error");
	writer.EndObject();

	ExpectEquals(
		writer.StringValue(),
		"{\"name\":\"cadence\",\"renderFps\":59.94,\"healthy\":true,\"error\":null}",
		"object serialization is compact and ordered");
}

void TestNestedArrays()
{
	using RenderCadenceCompositor::JsonWriter;

	JsonWriter writer;
	writer.BeginObject();
	writer.Key("levels");
	writer.BeginArray();
	writer.String("log");
	writer.String("warning");
	writer.String("error");
	writer.EndArray();
	writer.Key("counts");
	writer.BeginObject();
	writer.KeyUInt("queued", 3);
	writer.KeyInt("delta", -1);
	writer.EndObject();
	writer.EndObject();

	ExpectEquals(
		writer.StringValue(),
		"{\"levels\":[\"log\",\"warning\",\"error\"],\"counts\":{\"queued\":3,\"delta\":-1}}",
		"nested arrays and objects serialize correctly");
}

void TestMisuseThrows()
{
	using RenderCadenceCompositor::JsonWriter;

	JsonWriter writer;
	bool threw = false;
	try
	{
		writer.BeginObject();
		writer.Key("missing");
		writer.EndObject();
	}
	catch (const std::logic_error&)
	{
		threw = true;
	}
	Expect(threw, "ending an object with a key missing a value throws");
}
}

int main()
{
	TestEscapesStrings();
	TestObjectSerialization();
	TestNestedArrays();
	TestMisuseThrows();

	if (gFailures != 0)
	{
		std::cerr << gFailures << " RenderCadenceCompositorJsonWriter test failure(s).\n";
		return 1;
	}

	std::cout << "RenderCadenceCompositorJsonWriter tests passed.\n";
	return 0;
}
