import static org.junit.jupiter.api.Assertions.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

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

class Lab6Part1Test {

	private String wolfName = "Fuzzy";
	private int wolfAge = 8;	
	
	private String parrotName = "Squarker";
	private int parrotAge = 5;	
	
	@Test
	@DisplayName("Test wolf constructor and getters")
	void wolfTest() {
		
		Wolf wolf = new Wolf(wolfName, wolfAge);
		
		assertEquals(wolf.getName(), wolfName, "Testing that the wolf gets his assigned name");
		assertEquals(wolf.getAge(), wolfAge, "Testing that the wolf gets his assigned age");
	}
	
	
	@Test
	@DisplayName("Test wolf makeNoise method")
	void wolfMakeNoiseTest() {
		
		Wolf wolf = new Wolf(wolfName, wolfAge);

    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
    	PrintStream ps = new PrintStream(baos);
    	PrintStream old = System.out;
    	System.setOut(ps);
    	wolf.makeNoise();
    	System.out.flush();
    	System.setOut(old);
    	
		assertTrue(baos.toString().length()>0, "Testing that noise is printed");
		
	}
		
	@Test
	@DisplayName("Test wolf inhertience")
	void wolfInhertienceTest() {
		
		Wolf wolf = new Wolf(wolfName, wolfAge);
	
		assertEquals(wolf.getClass().getSuperclass().toString(), "class Animal", "Testing that the Animal class is the super class of Wolf");
		
		List<String> cm = new ArrayList<String> ();
		Method[] classmethods = wolf.getClass().getDeclaredMethods();
		for(int i = 0; i<classmethods.length; i++) {
			cm.add(classmethods[i].getName());
		}
		
		assertFalse(cm.contains("getName"), "Testing that the getName mehthod is not in the Wolf class");
		assertFalse(cm.contains("getAge"), "Testing that the getAge mehthod is not in the Wolf class");
		assertTrue(cm.contains("makeNoise"), "Testing that the makeNoise mehthod is in the Wolf class");
		
		
		List<String> scm = new ArrayList<String> ();
		Method[] superclassmethods = wolf.getClass().getSuperclass().getDeclaredMethods();
		for(int i = 0; i<superclassmethods.length; i++) {
			scm.add(superclassmethods[i].getName());
		}
		
		assertTrue(scm.contains("getName"), "Testing that the getName mehthod is in the Animal class");
		assertTrue(scm.contains("getAge"), "Testing that the getAge mehthod is in the Animal class");
		assertFalse(scm.contains("makeNoise"), "Testing that the makeNoise mehthod is not in the Animal class");
		
		
		List<String> cf = new ArrayList<String> ();
		Field[] classfields = wolf.getClass().getDeclaredFields();
		for(int i = 0; i<classfields.length; i++) {
			cf.add(classfields[i].getName());
		}

		List<String> f = new ArrayList<String> ();
		Field[] fields = wolf.getClass().getSuperclass().getDeclaredFields();
		for(int i = 0; i<fields.length; i++) {
			f.add(fields[i].getName());
		}
		
		assertEquals(classfields.length, 0, "Testing that there are no class fields in the Wolf class");
		assertTrue(fields.length>0, "Testing that there are class fields in the Animal class");
	
	}	
	
	@Test
	@DisplayName("Test parrot constructor and getters")
	void parrotTest() {
		
		Parrot parrot = new Parrot(parrotName, parrotAge);
		
		assertEquals(parrot.getName(), parrotName, "Testing that the parrot gets his assigned name");
		assertEquals(parrot.getAge(), parrotAge, "Testing that the parrot gets his assigned age");
	}
	
	
	@Test
	@DisplayName("Test parrot makeNoise method")
	void parrotMakeNoiseTest() {
		
		Parrot parrot = new Parrot(parrotName, parrotAge);

    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
    	PrintStream ps = new PrintStream(baos);
    	PrintStream old = System.out;
    	System.setOut(ps);
    	parrot.makeNoise();
    	System.out.flush();
    	System.setOut(old);
    	
		assertTrue(baos.toString().length()>0, "Testing that noise is printed");
		
	}
		
	@Test
	@DisplayName("Test parrot inhertience")
	void parrotInhertienceTest() {
		
		Parrot parrot = new Parrot(parrotName, parrotAge);
	
		assertEquals(parrot.getClass().getSuperclass().toString(), "class Animal", "Testing that the Animal class is the super class of Parrot");
		
		List<String> cm = new ArrayList<String> ();
		Method[] classmethods = parrot.getClass().getDeclaredMethods();
		for(int i = 0; i<classmethods.length; i++) {
			cm.add(classmethods[i].getName());
		}
		
		assertFalse(cm.contains("getName"), "Testing that the getName mehthod is not in the Parrot class");
		assertFalse(cm.contains("getAge"), "Testing that the getAge mehthod is not in the Parrot class");
		assertTrue(cm.contains("makeNoise"), "Testing that the makeNoise mehthod is in the Parrot class");
		
		
		List<String> scm = new ArrayList<String> ();
		Method[] superclassmethods = parrot.getClass().getSuperclass().getDeclaredMethods();
		for(int i = 0; i<superclassmethods.length; i++) {
			scm.add(superclassmethods[i].getName());
		}
		
		assertTrue(scm.contains("getName"), "Testing that the getName mehthod is in the Animal class");
		assertTrue(scm.contains("getAge"), "Testing that the getAge mehthod is in the Animal class");
		assertFalse(scm.contains("makeNoise"), "Testing that the makeNoise mehthod is not in the Animal class");
		
		
		List<String> cf = new ArrayList<String> ();
		Field[] classfields = parrot.getClass().getDeclaredFields();
		for(int i = 0; i<classfields.length; i++) {
			cf.add(classfields[i].getName());
		}

		List<String> f = new ArrayList<String> ();
		Field[] fields = parrot.getClass().getSuperclass().getDeclaredFields();
		for(int i = 0; i<fields.length; i++) {
			f.add(fields[i].getName());
		}
		
		assertEquals(classfields.length, 0, "Testing that there are no class fields in the Parrot class");
		assertTrue(fields.length>0, "Testing that there are class fields in the Animal class");
	
	}
	
	@Test
	@DisplayName("Test Meat inhertience")
	void Meattest() {
		Meat meat = new Meat("meat");
		assertEquals(meat.getClass().getSuperclass().toString(), "class Food", "Testing that the Food class is the super class of Meat");
	}
	
	@Test
	@DisplayName("Test Plant inhertience")
	void Planttest() {
		Plant plant = new Plant("plant");
		assertEquals(plant.getClass().getSuperclass().toString(), "class Food", "Testing that the Food class is the super class of Plant");
	}
}