
package com.laytonsmith.PureUtilities.ClassLoading;

import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.FieldMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.MethodMirror;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.junit.After;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 *
 */
@GeneralTest.TestAnnotation("value")
public class GeneralTest {
	
	@Retention(RetentionPolicy.RUNTIME)
	public static @interface TestAnnotation {
		String value();
	}
	
	@TestAnnotation("field")
	private final String field = "field";
	
	@TestAnnotation("method")
	private String method(){
		return "";
	}

	public GeneralTest() {
    }

    @BeforeClass
    public static void setUpClass(){
		ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(GeneralTest.class));
    }
    @Before
    public void setUp() throws Exception {        
        
    }
    @After
    public void tearDown(){
        
    }
	
	@Test
	public void testEquals() throws Exception {
		// Test that the same class, loaded two different ways, are still equal
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertTrue(c1.equals(c2));
	}
	
	@Test
	public void testHashCode() throws Exception {
		// Test that the same class, loaded two different ways, have the same hash code
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertEquals(c1.hashCode(), c2.hashCode());
	}
	
	@Test
	public void testClassReferenceMirrorName() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertEquals(c1.getClassReference(), c2.getClassReference());
	}
	
	@Test
	public void testClassReferenceAnnotation() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertEquals(c1.getAnnotations(), c2.getAnnotations());
	}
	
	@Test
	public void testClassFieldReferences() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertArrayEquals(c1.getFields(), c2.getFields());
	}
	
	@Test
	public void testClassMethodReferences() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		List<MethodMirror> m1 = Arrays.asList(c1.getMethods());
		List<MethodMirror> m2 = Arrays.asList(c1.getMethods());
		Comparator<MethodMirror> c = new Comparator<MethodMirror>() {

			@Override
			public int compare(MethodMirror o1, MethodMirror o2) {
				return o1.getName().compareTo(o2.getName());
			}
		};
		Collections.sort(m1, c);
		Collections.sort(m2, c);
		assertEquals(m1, m2);
	}
	
	@Test
	public void testPackageReferences() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		assertEquals(c1.getPackage(), c2.getPackage());
	}
	
	@Test
	public void testAnnotationValue() throws Exception {
		ClassMirror<GeneralTest> c1 = ClassDiscovery.getDefaultInstance().forName(GeneralTest.class.getName());
		ClassMirror<GeneralTest> c2 = new ClassMirror<>(GeneralTest.class);
		FieldMirror f1 = c1.getField("field");
		FieldMirror f2 = c1.getField("field");
		MethodMirror m1 = c1.getMethod("method", new Class[]{});
		MethodMirror m2 = c2.getMethod("method", new Class[]{});
		assertEquals(c1.loadAnnotation(TestAnnotation.class).value(), "value");
		assertEquals(c2.loadAnnotation(TestAnnotation.class).value(), "value");
		assertEquals(f1.loadAnnotation(TestAnnotation.class).value(), "field");
		assertEquals(f2.loadAnnotation(TestAnnotation.class).value(), "field");
		assertEquals(m1.loadAnnotation(TestAnnotation.class).value(), "method");
		assertEquals(m2.loadAnnotation(TestAnnotation.class).value(), "method");
	}
}

@@ -357,16 +357,44 @@
 Policy;%0A
+import java.util.ArrayList;%0A
 import j
@@ -465,24 +465,51 @@
 Comparator;%0A
+import java.util.Iterator;%0A
 import java.
@@ -2986,28 +2986,138 @@
 ;%0A%09%09
-assertArrayEquals(c1
+List%3CFieldMirror%3E c1l = new ArrayList%3C%3E(Arrays.asList(c1.getFields()));%0A%09%09List%3CFieldMirror%3E c2l = new ArrayList%3C%3E(Arrays.asList(c2
 .get
@@ -3128,24 +3128,402 @@
 ds()
-, c2.getFields()
+));%0A%09%09for(List%3CFieldMirror%3E f : new List%5B%5D%7Bc1l, c2l%7D)%7B%0A%09%09%09Iterator%3CFieldMirror%3E it = f.iterator();%0A%09%09%09while(it.hasNext())%7B%0A%09%09%09%09// Jacoco adds synthetic fields to this class (as could other instrumentation suites)%0A%09%09%09%09// so we want to ignore any synthetic fields for the purposes of this test.%0A%09%09%09%09if(it.next().getName().startsWith(%22$%22))%7B%0A%09%09%09%09%09it.remove();%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%09assertEquals(c1l, c2l
 );%0A%09

Fix a failing unit test due to jacoco adding synthetic fields