package com.digistratum.microhost;

import com.digistratum.microhost.Json.JsonBuilder;
import com.digistratum.microhost.Json.JsonClass;
import com.google.gson.Gson;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class JsonBuilderTest {
	private Gson gson;

	private JsonBuilder sut;

	@BeforeEach
	public void setup() throws Exception {
		sut = new JsonBuilder();
		gson = new Gson();
	}

	@Test
	public void testThat_toJson_encodesStrings() {
		String test = "AmanaplanacanalpanamA";
		assertEquals("\"" + test + "\"", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesIntegers() {
		int test = 333;
		assertEquals(((Integer) test).toString(), sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesFloats() {
		float test = (float) 333.3;
		assertTrue(Math.abs((Float.parseFloat(sut.toJson(test))) - test) < 0.01);
	}

	@Test
	public void testThat_toJson_encodesDoubles() {
		double test = (double) 333.3;
		assertTrue(Math.abs((Double.parseDouble(sut.toJson(test))) - test) < 0.0001);
	}

	@Test
	public void testThat_toJson_encodesBooleans() {
		boolean test = true;
		assertEquals(test, Boolean.parseBoolean(sut.toJson(test)));
	}

	@Test
	public void testThat_toJson_encodesJsonClassInstances() {
		JsonClassObject test = new JsonClassObject();
		assertEquals("\"JSON!\"", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesEmptyArrays() {
		List<Object> test = new ArrayList<>();
		assertEquals("[]", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesArraysWithSingleElement() {
		List<Object> test = new ArrayList<>();
		String str = "Strings are objects too!";
		test.add(str);
		assertEquals("[\"" + str + "\"]", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesArraysWithMultipleMixedElements() {
		List<Object> test = new ArrayList<>();
		test.add("abc");
		test.add(123);
		test.add(true);
		assertEquals("[\"abc\",123,true]", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesEmptyObjects() {
		EmptyObject test = new EmptyObject();
		assertEquals("{}", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesObjectsWithSingleProperty() {
		SingleObject test = new SingleObject();
		assertEquals("{\"publicProperty\":\"public\"}", sut.toJson(test));
	}

	@Test
	public void testThat_toJson_encodesObjectsWithMixedProperties() {
		MixedObject test = new MixedObject();
		String json = sut.toJson(test);
		MixedObject res = gson.fromJson(json, MixedObject.class);
		assertEquals(res.strProp, test.strProp);
		assertEquals(res.intProp, test.intProp);
		assertEquals(res.integerProp, test.integerProp);
		assertEquals(res.booleanProp, test.booleanProp);
		assertEquals(res.bigBooleanProp, test.bigBooleanProp);
		assertTrue(Math.abs(res.floatProp - test.floatProp) < 0.01);
		assertTrue(Math.abs(res.bigFloatProp - test.bigFloatProp) < 0.01);
		assertTrue(Math.abs(res.doubleProp - test.doubleProp) < 0.0001);
		assertTrue(Math.abs(res.bigDoubleProp - test.bigDoubleProp) < 0.0001);
	}

	// TODO: Add a test to cover objects with mixed, nested properties (such as other objects, arrays of objects, etc)

	protected class JsonClassObject implements JsonClass {
		@Override
		public String toJson() {
			return "\"JSON!\"";
		}
	}

	protected class EmptyObject {}

	protected class SingleObject {
		public String publicProperty = "public";
	}

	protected class MixedObject {
		public String strProp = "prop1";
		public int intProp = 3;
		public Integer integerProp = 33;
		public boolean booleanProp = true;
		public Boolean bigBooleanProp = false;
		public float floatProp = (float) 33.3;
		public Float bigFloatProp = (float) 333.3;
		public double doubleProp = 3.14159;
		public Double bigDoubleProp = 26.2;
	}
}

@@ -653,46 +653,507 @@
 %7B%0A%09%09
-String test = %22AmanaplanacanalpanamA%22;
+// A string is always encoded as a JavaString, encapsulated in a set of quotes; so the outermost%0A%09%09// characters are always double-quotes. Within that, other characters may be literal or escaped%0A%09%09// as needed. If, for example, our test string itself has quotes within it, then those quotes will%0A%09%09// be escaped. And to check this in Java here, we must escape the outermost quote, escape the escape,%0A%09%09// AND escape the inner quote as Json and Java strings have the same escaping requirements. eek!%0A
 %0A%09%09a
@@ -1171,19 +1171,19 @@
 (%22%5C%22
-%22 + 
+%5C%5C%5C%22
 test
- + 
+%5C%5C%5C
 %22%5C%22%22
@@ -1187,36 +1187,42 @@
 %5C%22%22, sut.toJson(
+%22%5C%22
 test
+%5C%22%22
 ));%0A%09%7D%0A%0A%09@Test%0A%09

Add checking for special character escaping in JsonBuilder String unit test