diff --git a/pom.xml b/pom.xml
index 1ae6f98..c0a61d6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,15 @@
github
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
diff --git a/src/test/java/info/ebenoit/ebul/reflection/ATest1.java b/src/test/java/info/ebenoit/ebul/reflection/ATest1.java
new file mode 100644
index 0000000..a22bf14
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/ATest1.java
@@ -0,0 +1,13 @@
+package info.ebenoit.ebul.reflection;
+
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+
+@Retention( RetentionPolicy.RUNTIME )
+public @interface ATest1
+{
+ // EMPTY
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/ATest2.java b/src/test/java/info/ebenoit/ebul/reflection/ATest2.java
new file mode 100644
index 0000000..2e356c6
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/ATest2.java
@@ -0,0 +1,13 @@
+package info.ebenoit.ebul.reflection;
+
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+
+@Retention( RetentionPolicy.RUNTIME )
+public @interface ATest2
+{
+ // EMPTY
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/ATest3.java b/src/test/java/info/ebenoit/ebul/reflection/ATest3.java
new file mode 100644
index 0000000..10098fc
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/ATest3.java
@@ -0,0 +1,15 @@
+package info.ebenoit.ebul.reflection;
+
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+
+@Inherited
+@Retention( RetentionPolicy.RUNTIME )
+public @interface ATest3
+{
+ // EMPTY
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/CTest1.java b/src/test/java/info/ebenoit/ebul/reflection/CTest1.java
new file mode 100644
index 0000000..1d89053
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/CTest1.java
@@ -0,0 +1,113 @@
+package info.ebenoit.ebul.reflection;
+
+
+@ATest3
+public class CTest1
+{
+ public int tf0;
+ @ATest1
+ public int tf1;
+ @ATest2
+ public int tf2;
+
+ int tdf0;
+ @ATest1
+ int tdf1;
+ @ATest2
+ int tdf2;
+
+ protected int tif0;
+ @ATest1
+ protected int tif1;
+ @ATest2
+ protected int tif2;
+
+ @SuppressWarnings( "unused" )
+ private int tpf0;
+ @ATest1
+ private int tpf1;
+ @ATest2
+ private int tpf2;
+
+
+ public void tm0( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest1
+ public void tm1( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest2
+ public void tm2( )
+ {
+ // EMPTY
+ }
+
+
+ void tdm0( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest1
+ void tdm1( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest2
+ void tdm2( )
+ {
+ // EMPTY
+ }
+
+
+ protected void tim0( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest1
+ protected void tim1( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest2
+ protected void tim2( )
+ {
+ // EMPTY
+ }
+
+
+ @SuppressWarnings( "unused" )
+ private void tpm0( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest1
+ private void tpm1( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest2
+ private void tpm2( )
+ {
+ // EMPTY
+ }
+
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/CTest2.java b/src/test/java/info/ebenoit/ebul/reflection/CTest2.java
new file mode 100644
index 0000000..bd78604
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/CTest2.java
@@ -0,0 +1,28 @@
+package info.ebenoit.ebul.reflection;
+
+
+@ATest1
+public class CTest2
+ extends CTest1
+{
+ @ATest2
+ public int tf1;
+
+ @ATest2
+ private int tpf1;
+
+ @ATest2
+ @Override
+ public void tm1( )
+ {
+ // EMPTY
+ }
+
+
+ @ATest2
+ private void tpm0( )
+ {
+ // EMPTY
+ }
+
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/CTest3.java b/src/test/java/info/ebenoit/ebul/reflection/CTest3.java
new file mode 100644
index 0000000..8739b2d
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/CTest3.java
@@ -0,0 +1,9 @@
+package info.ebenoit.ebul.reflection;
+
+
+@ATest1
+public class CTest3
+ extends CTest2
+{
+ // EMPTY
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/CTest4.java b/src/test/java/info/ebenoit/ebul/reflection/CTest4.java
new file mode 100644
index 0000000..c98b42b
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/CTest4.java
@@ -0,0 +1,8 @@
+package info.ebenoit.ebul.reflection;
+
+
+public class CTest4
+ extends CTest3
+{
+ // EMPTY
+}
diff --git a/src/test/java/info/ebenoit/ebul/reflection/TestAnnotations.java b/src/test/java/info/ebenoit/ebul/reflection/TestAnnotations.java
new file mode 100644
index 0000000..efac789
--- /dev/null
+++ b/src/test/java/info/ebenoit/ebul/reflection/TestAnnotations.java
@@ -0,0 +1,172 @@
+package info.ebenoit.ebul.reflection;
+
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+
+/**
+ * Tests for the helper methods in {@link Annotations}
+ *
+ * @author E. BenoƮt
+ */
+public class TestAnnotations
+{
+
+ /**
+ * Test: {@link Annotations#findAnnotatedMethods(Class, Class)} returns all matching annotated methods in a base
+ * class
+ */
+ @Test
+ public void testFindAnnotatedMethodsOnBaseClass( )
+ {
+ final ArrayList< Method > methods = Annotations.findAnnotatedMethods( CTest1.class , ATest1.class );
+ final List< String > mNames = methods.stream( )//
+ .map( ( final Method m ) -> m.getName( ) )//
+ .collect( Collectors.toList( ) );
+ mNames.sort( ( final String a , final String b ) -> a.compareTo( b ) );
+ Assert.assertArrayEquals( new String[] {
+ "tdm1" , "tim1" , "tm1" , "tpm1"
+ } , mNames.toArray( new String[] { } ) );
+ }
+
+
+ /** Test: {@link Annotations#findAnnotatedMethods(Class, Class)} returns no inherited methods in a child class */
+ @Test
+ public void testFindAnnotatedMethodsOnChildClassInheritance( )
+ {
+ final ArrayList< Method > methods = Annotations.findAnnotatedMethods( CTest2.class , ATest1.class );
+ Assert.assertTrue( methods.isEmpty( ) );
+ }
+
+
+ /** Test: {@link Annotations#findAnnotatedMethods(Class, Class)} returns new methods in a child class */
+ @Test
+ public void testFindAnnotatedMethodsOnChildClassNew( )
+ {
+ final ArrayList< Method > methods = Annotations.findAnnotatedMethods( CTest2.class , ATest2.class );
+ final List< String > mNames = methods.stream( )//
+ .map( ( final Method m ) -> m.getName( ) )//
+ .collect( Collectors.toList( ) );
+ mNames.sort( ( final String a , final String b ) -> a.compareTo( b ) );
+ Assert.assertArrayEquals( new String[] {
+ "tm1" , "tpm0"
+ } , mNames.toArray( new String[] { } ) );
+ }
+
+
+ /**
+ * Test: {@link Annotations#findAnnotatedFields(Class, Class)} returns all matching annotated fields in a base class
+ */
+ @Test
+ public void testFindAnnotatedFieldsOnBaseClass( )
+ {
+ final ArrayList< Field > fields = Annotations.findAnnotatedFields( CTest1.class , ATest1.class );
+ final List< String > fNames = fields.stream( )//
+ .map( ( final Field f ) -> f.getName( ) )//
+ .collect( Collectors.toList( ) );
+ fNames.sort( ( final String a , final String b ) -> a.compareTo( b ) );
+ Assert.assertArrayEquals( new String[] {
+ "tdf1" , "tf1" , "tif1" , "tpf1"
+ } , fNames.toArray( new String[] { } ) );
+ }
+
+
+ /**
+ * Test: {@link Annotations#findAnnotatedFields(Class, Class)} returns no inherited fields in a child class
+ */
+ @Test
+ public void testFindAnnotatedFieldsOnChildClassInheritance( )
+ {
+ final ArrayList< Field > fields = Annotations.findAnnotatedFields( CTest2.class , ATest1.class );
+ Assert.assertTrue( fields.isEmpty( ) );
+ }
+
+
+ /** Test: {@link Annotations#findAnnotatedFields(Class, Class)} returns new fields in a child class */
+ @Test
+ public void testFindAnnotatedFieldsOnChildClassNew( )
+ {
+ final ArrayList< Field > fields = Annotations.findAnnotatedFields( CTest2.class , ATest2.class );
+ final List< String > fNames = fields.stream( )//
+ .map( ( final Field m ) -> m.getName( ) )//
+ .collect( Collectors.toList( ) );
+ fNames.sort( ( final String a , final String b ) -> a.compareTo( b ) );
+ Assert.assertArrayEquals( new String[] {
+ "tf1" , "tpf1"
+ } , fNames.toArray( new String[] { } ) );
+ }
+
+
+ /** Test: {@link Annotations#findClosestClass(Class, Class)} finds first annotated parent */
+ @Test
+ public void testFindClosestClassParent( )
+ {
+ Assert.assertSame( CTest3.class , Annotations.findClosestClass( CTest4.class , ATest1.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findClosestClass(Class, Class)} finds directly annotated class */
+ @Test
+ public void testFindClosestClassSelf( )
+ {
+ Assert.assertSame( CTest3.class , Annotations.findClosestClass( CTest3.class , ATest1.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findClosestClass(Class, Class)} returns null
when no annotation exists */
+ @Test
+ public void testFindClosestClassNone( )
+ {
+ Assert.assertNull( Annotations.findClosestClass( CTest3.class , ATest2.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findClosestClass(Class, Class)} returns correct class even for inherited annotations */
+ @Test
+ public void testFindClosestClassInherited( )
+ {
+ Assert.assertSame( CTest1.class , Annotations.findClosestClass( CTest4.class , ATest3.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findFarthestClass(Class, Class)} finds last annotated ancestor */
+ @Test
+ public void testFindFarthestClassAncestor( )
+ {
+ Assert.assertSame( CTest2.class , Annotations.findFarthestClass( CTest4.class , ATest1.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findFarthestClass(Class, Class)} finds last annotated ancestor on annotated class */
+ @Test
+ public void testFindFarthestClassSelf( )
+ {
+ Assert.assertSame( CTest2.class , Annotations.findFarthestClass( CTest3.class , ATest1.class ) );
+ }
+
+
+ /** Test: {@link Annotations#findFarthestClass(Class, Class)} returns null
when no annotation exists */
+ @Test
+ public void testFindFarthestClassNone( )
+ {
+ Assert.assertNull( Annotations.findFarthestClass( CTest3.class , ATest2.class ) );
+ }
+
+
+ /**
+ * Test: {@link Annotations#findFarthestClass(Class, Class)} returns correct class even for inherited annotations
+ */
+ @Test
+ public void testFindFarthestClassInherited( )
+ {
+ Assert.assertSame( CTest1.class , Annotations.findFarthestClass( CTest4.class , ATest3.class ) );
+ }
+}