package fr.umlv.json;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.Map;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@SuppressWarnings("static-method")
public class JSONPrinterTest {
	@Test @Tag("Q1")
	public void testToJSONPersonPartial() {
		var person = new Person("John", "Doe");
		var personJSON = JSONPrinter.toJSON(person);
    assertEquals("John", IncompleteJSONParser.parse(personJSON).get("firstName"));
	}
	@Test @Tag("Q1")
	public void testToJSONAlienPartial() {
		var alien = new Alien(100, "saturn");
		var alienJSON = JSONPrinter.toJSON(alien);
		assertEquals("saturn", IncompleteJSONParser.parse(alienJSON).get("planet"));
		assertEquals(100, IncompleteJSONParser.parse(alienJSON).get("age"));
	}
	
	
	
	public static class Oops1 {
		@JSONProperty
		public Object getFoo() {
			Object o = null;
			return o.getClass();
		}
	}
	@Test @Tag("Q2")
	public void testToJSONOops1() {
		var oops = new Oops1();
		assertThrows(NullPointerException.class, () -> JSONPrinter.toJSON(oops));
	}
	
	public static class Oops2 {
		@JSONProperty
		public String getFoo() {
			throw new OutOfMemoryError();
		}
	}
	@Test @Tag("Q2")
	public void testToJSONOops2() {
		var oops = new Oops2();
		assertThrows(OutOfMemoryError.class, () -> JSONPrinter.toJSON(oops));
	}
	
	public static class Oops3 {
		@JSONProperty
		public String getFoo() throws Throwable {
			throw new Throwable();
		}
	}
	@Test @Tag("Q2")
	public void testToJSONOops3() {
		var oops = new Oops3();
		assertThrows(UndeclaredThrowableException.class, () -> JSONPrinter.toJSON(oops));
	}

	@Test  @Tag("Q2")
	public void testToJSONPersonNoClass() {
		var person = new Person("John", "Doe");
		var personJSON = JSONPrinter.toJSON(person);
		assertFalse(IncompleteJSONParser.parse(personJSON).containsKey("class"));
	}
	@Test  @Tag("Q2")
	public void testToJSONAlienNoClass() {
		var alien = new Alien(100, "saturn");
		var alienJSON = JSONPrinter.toJSON(alien);
		assertFalse(IncompleteJSONParser.parse(alienJSON).containsKey("class"));
	}
	
	@Test
	public void testToJSONPerson() {
		var person = new Person("John", "Doe");
		var personJSON = JSONPrinter.toJSON(person);
		assertEquals(Map.of("firstName", "John", "last-name", "Doe"), IncompleteJSONParser.parse(personJSON));
	}
	@Test
	public void testToJSONAlien() {
		var alien = new Alien(100, "saturn");
		var alienJSON = JSONPrinter.toJSON(alien);
		assertEquals(Map.of("age", 100, "planet", "saturn"), IncompleteJSONParser.parse(alienJSON));
	}
}
