From 0f1362131caf1802e86b2278d7a1251650b21e70 Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 13:53:14 -0500 Subject: [PATCH 01/17] initial commit --- .gitignore | 56 ++++++++++++++++++++++++++++++++++++++++++++++++------ pom.xml | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore index 32858aa..3b5361d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,56 @@ +# Compiled source # +################### +*.com *.class +*.dll +*.exe +*.o +*.so -# Mobile Tools for Java (J2ME) +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# intellij files # +################## +.idea/ +*.iml + +# Compiled java # +################# +target/ +*.class + +# Mobile Tools for Java (J2ME) # +################################ .mtj.tmp/ -# Package Files # -*.jar -*.war -*.ear -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # +########################################################################################## hs_err_pid* diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d51dcd0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + squier.john + TypeInformation + 1.0-SNAPSHOT + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + + + junit + junit + 4.12 + + + + \ No newline at end of file From f44f47a915982fe5f6c4858c8c252b56ae80a783 Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 15:08:01 -0500 Subject: [PATCH 02/17] Reflector.classImplementsInterface() implemented and tested --- .../john/typeInformation/Reflector.java | 44 +++++++++ .../john/typeInformation/ReflectorTest.java | 92 +++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 src/main/java/squier/john/typeInformation/Reflector.java create mode 100644 src/test/java/squier/john/typeInformation/ReflectorTest.java diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java new file mode 100644 index 0000000..324c756 --- /dev/null +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -0,0 +1,44 @@ +package squier.john.typeInformation; + +/** + * Created by johnsquier on 2/15/17. + */ +public class Reflector { + + public boolean classImplementsInterface(String theClassName, String theInterface) { + try { + Class theClass = Class.forName(theClassName); + return classImplementsInterface(theClass, theInterface); + } + catch ( ClassNotFoundException e ) { + return classImplementsInterface((Object)theClassName, theInterface); + } + } + + // classImplementsInterface(String, String) && classImplementsInterface(Object, String) + // call this method. + public boolean classImplementsInterface(Class theClass, String theInterface) { + Class[] implementedInterfaces = theClass.getInterfaces(); + Class theInterfaceClass; + + try { + theInterfaceClass = Class.forName(theInterface); + } + catch ( ClassNotFoundException e ) { + System.err.println("Interface: " + theInterface + " not found"); + return false; + } + + for ( Class c : implementedInterfaces ) { + if ( c.getName().equals(theInterfaceClass.getName()) ) { + return true; + } + } + + return false; + } + + public boolean classImplementsInterface(Object o, String theInterface) { + return classImplementsInterface(o.getClass(), theInterface); + } +} diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectorTest.java new file mode 100644 index 0000000..50a90ff --- /dev/null +++ b/src/test/java/squier/john/typeInformation/ReflectorTest.java @@ -0,0 +1,92 @@ +package squier.john.typeInformation; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Scanner; + +/** + * Created by johnsquier on 2/15/17. + */ +public class ReflectorTest { + + Reflector reflector; + + @Before + public void setup() { + reflector = new Reflector(); + } + + @Test + public void objectDoesImplementInterfaceTest() { + boolean expected = true; + + boolean actual = reflector.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void objectDoesNotImplementInterfaceTest() { + boolean expected = false; + + boolean actual = reflector.classImplementsInterface(new Integer(10), "java.lang.Iterable"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void classObjectDoesImplementInterfaceTest() { + boolean expected = true; + + boolean actual = reflector.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void classObjectDoesNotImplementInterfaceTest() { + boolean expected = false; + + boolean actual = reflector.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void classNameDoesImplementInterfaceTest() { + boolean expected = true; + + boolean actual = reflector.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void classNameDoesNotImplementInterfaceTest() { + boolean expected = false; + + boolean actual = reflector.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void stringIsNotAClassNameButAStringLiteralTest() { + boolean expected = true; + + boolean actual = reflector.classImplementsInterface(" ", "java.lang.CharSequence"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void tryToCompareObjectToNonExistantInterface() { + boolean expected = false; + + boolean actual = reflector.classImplementsInterface(new Object(), "java.lang.HocusPocus"); + + Assert.assertEquals(expected, actual); + } +} From 39e7b86f92feb5b0a64ac338bcbb7a32a1c4fdff Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 17:20:12 -0500 Subject: [PATCH 03/17] listAllMembers() implemented and tested --- .../john/typeInformation/Reflector.java | 101 +++++++++++++++++- .../john/typeInformation/ReflectorTest.java | 101 +++++++++++++++++- 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java index 324c756..7b1b0dd 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -1,5 +1,13 @@ package squier.john.typeInformation; +import com.sun.tools.internal.jxc.ap.Const; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + /** * Created by johnsquier on 2/15/17. */ @@ -15,8 +23,6 @@ public boolean classImplementsInterface(String theClassName, String theInterface } } - // classImplementsInterface(String, String) && classImplementsInterface(Object, String) - // call this method. public boolean classImplementsInterface(Class theClass, String theInterface) { Class[] implementedInterfaces = theClass.getInterfaces(); Class theInterfaceClass; @@ -41,4 +47,95 @@ public boolean classImplementsInterface(Class theClass, String theInterface) public boolean classImplementsInterface(Object o, String theInterface) { return classImplementsInterface(o.getClass(), theInterface); } + + public String listAllMembers(Object o) { + StringBuilder sb = new StringBuilder(); + + Class theClass = o.getClass(); + + sb.append(generateClassInfoString(theClass)); + + while ( !theClass.getSimpleName().equals("Object")) { + theClass = theClass.getSuperclass(); + sb.append(generateClassInfoString(theClass)); + } + + return sb.toString(); + } + + private String generateClassInfoString(Class theClass) { + Field[] fields = theClass.getFields(); + Constructor[] constructors = theClass.getConstructors(); + Method[] methods = theClass.getMethods(); + + StringBuilder sb = new StringBuilder(); + + sb.append("Fields\n"); + for ( Field f : fields ) { + sb.append(theClass.getSimpleName()).append(" : "); + sb.append(Modifier.toString(f.getModifiers())).append(" "); + sb.append(f.getType().getSimpleName()).append(" "); + sb.append(f.getName()).append("\n"); + } + + sb.append("Constructors\n"); + for ( Constructor c : constructors ) { + sb.append(theClass.getSimpleName()).append(" : "); + sb.append(Modifier.toString(c.getModifiers())).append(" "); + sb.append(c.getName()).append("("); + + Class[] params = c.getParameterTypes(); + if ( params.length == 0 ) { + sb.append(")"); + } + else { + for ( int i = 0; i < params.length; i++ ) { + sb.append(params[i].getName()); + if (i < params.length - 1) { + sb.append(", "); + } else { + sb.append(")"); + } + } + } + + sb.append("\n"); + } + + Arrays.sort(methods, new Comparator() { + @Override + public int compare(Method o1, Method o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + + sb.append("Methods\n"); + for ( Method m : methods ) + if ( m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()) ) { + sb.append(theClass.getSimpleName()).append(" : "); + sb.append(Modifier.toString(m.getModifiers())).append(" "); + sb.append(m.getReturnType()).append(" "); + sb.append(m.getName()).append("("); + + Class[] params = m.getParameterTypes(); + if ( params.length == 0 ) { + sb.append(")"); + } + else { + for ( int i = 0; i < params.length; i++ ) { + sb.append(params[i].getName()); + if (i < params.length - 1) { + sb.append(", "); + } else { + sb.append(")"); + } + } + } + + sb.append("\n"); + } + + + return sb.toString(); + } } diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectorTest.java index 50a90ff..051379b 100644 --- a/src/test/java/squier/john/typeInformation/ReflectorTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectorTest.java @@ -4,6 +4,8 @@ import org.junit.Before; import org.junit.Test; +import java.io.BufferedWriter; +import java.io.FileWriter; import java.util.Scanner; /** @@ -82,10 +84,105 @@ public void stringIsNotAClassNameButAStringLiteralTest() { } @Test - public void tryToCompareObjectToNonExistantInterface() { + public void tryToCompareObjectToNonExistentInterface() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Object(), "java.lang.HocusPocus"); + boolean actual = reflector.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); + + Assert.assertEquals(expected, actual); + } + + @Test + public void listAllMembersBufferedWriter() { + String expected = "Fields\n" + + "Constructors\n" + + "BufferedWriter : public java.io.BufferedWriter(java.io.Writer)\n" + + "BufferedWriter : public java.io.BufferedWriter(java.io.Writer, int)\n" + + "Methods\n" + + "BufferedWriter : public void close()\n" + + "BufferedWriter : public void flush()\n" + + "BufferedWriter : public void newLine()\n" + + "BufferedWriter : public void write([C, int, int)\n" + + "BufferedWriter : public void write(int)\n" + + "BufferedWriter : public void write(java.lang.String, int, int)\n" + + "Fields\n" + + "Constructors\n" + + "Methods\n" + + "Writer : public class java.io.Writer append(java.lang.CharSequence, int, int)\n" + + "Writer : public class java.io.Writer append(char)\n" + + "Writer : public class java.io.Writer append(java.lang.CharSequence)\n" + + "Writer : public volatile interface java.lang.Appendable append(char)\n" + + "Writer : public volatile interface java.lang.Appendable append(java.lang.CharSequence, int, int)\n" + + "Writer : public volatile interface java.lang.Appendable append(java.lang.CharSequence)\n" + + "Writer : public abstract void close()\n" + + "Writer : public abstract void flush()\n" + + "Writer : public void write([C)\n" + + "Writer : public abstract void write([C, int, int)\n" + + "Writer : public void write(int)\n" + + "Writer : public void write(java.lang.String, int, int)\n" + + "Writer : public void write(java.lang.String)\n" + + "Fields\n" + + "Constructors\n" + + "Object : public java.lang.Object()\n" + + "Methods\n" + + "Object : public boolean equals(java.lang.Object)\n" + + "Object : public final native class java.lang.Class getClass()\n" + + "Object : public native int hashCode()\n" + + "Object : public final native void notify()\n" + + "Object : public final native void notifyAll()\n" + + "Object : public class java.lang.String toString()\n" + + "Object : public final void wait(long, int)\n" + + "Object : public final native void wait(long)\n" + + "Object : public final void wait()\n"; + + String actual = null; + try { actual = reflector.listAllMembers(new BufferedWriter(new FileWriter(" "))); } + catch ( Exception e ) { } + + Assert.assertEquals(expected, actual); + } + + @Test + public void listAllMembersBoolean() { + String expected = "Fields\n" + + "Boolean : public static final Boolean TRUE\n" + + "Boolean : public static final Boolean FALSE\n" + + "Boolean : public static final Class TYPE\n" + + "Constructors\n" + + "Boolean : public java.lang.Boolean(boolean)\n" + + "Boolean : public java.lang.Boolean(java.lang.String)\n" + + "Methods\n" + + "Boolean : public boolean booleanValue()\n" + + "Boolean : public static int compare(boolean, boolean)\n" + + "Boolean : public int compareTo(java.lang.Boolean)\n" + + "Boolean : public volatile int compareTo(java.lang.Object)\n" + + "Boolean : public boolean equals(java.lang.Object)\n" + + "Boolean : public static boolean getBoolean(java.lang.String)\n" + + "Boolean : public static int hashCode(boolean)\n" + + "Boolean : public int hashCode()\n" + + "Boolean : public static boolean logicalAnd(boolean, boolean)\n" + + "Boolean : public static boolean logicalOr(boolean, boolean)\n" + + "Boolean : public static boolean logicalXor(boolean, boolean)\n" + + "Boolean : public static boolean parseBoolean(java.lang.String)\n" + + "Boolean : public class java.lang.String toString()\n" + + "Boolean : public static class java.lang.String toString(boolean)\n" + + "Boolean : public static class java.lang.Boolean valueOf(java.lang.String)\n" + + "Boolean : public static class java.lang.Boolean valueOf(boolean)\n" + + "Fields\n" + + "Constructors\n" + + "Object : public java.lang.Object()\n" + + "Methods\n" + + "Object : public boolean equals(java.lang.Object)\n" + + "Object : public final native class java.lang.Class getClass()\n" + + "Object : public native int hashCode()\n" + + "Object : public final native void notify()\n" + + "Object : public final native void notifyAll()\n" + + "Object : public class java.lang.String toString()\n" + + "Object : public final void wait(long, int)\n" + + "Object : public final native void wait(long)\n" + + "Object : public final void wait()\n"; + + String actual = reflector.listAllMembers(new Boolean(true)); Assert.assertEquals(expected, actual); } From 2e13c2a12db96e97d2a8c1e966fa56729025359b Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 17:31:10 -0500 Subject: [PATCH 04/17] refactored listAllMembers into private helper methods --- | 0 .gitignore | 4 + .../john/typeInformation/Reflector.java | 85 ++++++++++++------- .../john/typeInformation/ReflectorTest.java | 2 +- 4 files changed, 58 insertions(+), 33 deletions(-) create mode 100644 diff --git a/ b/ new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index 3b5361d..c3106dd 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,7 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # ########################################################################################## hs_err_pid* + +# junk files # +############## +test.txt diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java index 7b1b0dd..3848511 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -1,7 +1,5 @@ package squier.john.typeInformation; -import com.sun.tools.internal.jxc.ap.Const; - import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -27,6 +25,7 @@ public boolean classImplementsInterface(Class theClass, String theInterface) Class[] implementedInterfaces = theClass.getInterfaces(); Class theInterfaceClass; + // extract into getClassFromInterface method try { theInterfaceClass = Class.forName(theInterface); } @@ -64,13 +63,22 @@ public String listAllMembers(Object o) { } private String generateClassInfoString(Class theClass) { - Field[] fields = theClass.getFields(); - Constructor[] constructors = theClass.getConstructors(); - Method[] methods = theClass.getMethods(); + StringBuilder sb = new StringBuilder(); + + sb.append(generateFieldsInfoString(theClass)); + sb.append(generateConstructorInfoString(theClass)); + sb.append(generateMethodsInfoString(theClass)); + return sb.toString(); + } + + private String generateFieldsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); + Field[] fields = theClass.getFields(); + sb.append("Fields\n"); + for ( Field f : fields ) { sb.append(theClass.getSimpleName()).append(" : "); sb.append(Modifier.toString(f.getModifiers())).append(" "); @@ -78,30 +86,35 @@ private String generateClassInfoString(Class theClass) { sb.append(f.getName()).append("\n"); } + return sb.toString(); + } + + private String generateConstructorInfoString(Class theClass) { + StringBuilder sb = new StringBuilder(); + + Constructor[] constructors = theClass.getConstructors(); + sb.append("Constructors\n"); + for ( Constructor c : constructors ) { sb.append(theClass.getSimpleName()).append(" : "); sb.append(Modifier.toString(c.getModifiers())).append(" "); sb.append(c.getName()).append("("); Class[] params = c.getParameterTypes(); - if ( params.length == 0 ) { - sb.append(")"); - } - else { - for ( int i = 0; i < params.length; i++ ) { - sb.append(params[i].getName()); - if (i < params.length - 1) { - sb.append(", "); - } else { - sb.append(")"); - } - } - } + sb.append(generateParamsInfoString(params)); sb.append("\n"); } + return sb.toString(); + } + + private String generateMethodsInfoString(Class theClass) { + StringBuilder sb = new StringBuilder(); + + Method[] methods = theClass.getMethods(); + Arrays.sort(methods, new Comparator() { @Override public int compare(Method o1, Method o2) { @@ -110,7 +123,7 @@ public int compare(Method o1, Method o2) { }); sb.append("Methods\n"); - for ( Method m : methods ) + for ( Method m : methods ) { if ( m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()) ) { sb.append(theClass.getSimpleName()).append(" : "); sb.append(Modifier.toString(m.getModifiers())).append(" "); @@ -118,23 +131,31 @@ public int compare(Method o1, Method o2) { sb.append(m.getName()).append("("); Class[] params = m.getParameterTypes(); - if ( params.length == 0 ) { - sb.append(")"); - } - else { - for ( int i = 0; i < params.length; i++ ) { - sb.append(params[i].getName()); - if (i < params.length - 1) { - sb.append(", "); - } else { - sb.append(")"); - } - } - } + sb.append(generateParamsInfoString(params)); sb.append("\n"); } + } + + return sb.toString(); + } + + private String generateParamsInfoString(Class[] params) { + StringBuilder sb = new StringBuilder(); + if ( params.length == 0 ) { + sb.append(")"); + } + else { + for ( int i = 0; i < params.length; i++ ) { + sb.append(params[i].getName()); + if (i < params.length - 1) { + sb.append(", "); + } else { + sb.append(")"); + } + } + } return sb.toString(); } diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectorTest.java index 051379b..e449648 100644 --- a/src/test/java/squier/john/typeInformation/ReflectorTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectorTest.java @@ -136,7 +136,7 @@ public void listAllMembersBufferedWriter() { "Object : public final void wait()\n"; String actual = null; - try { actual = reflector.listAllMembers(new BufferedWriter(new FileWriter(" "))); } + try { actual = reflector.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } catch ( Exception e ) { } Assert.assertEquals(expected, actual); From ab9f4efa7d37a942a46310d1edba01faf567dfbc Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 17:55:16 -0500 Subject: [PATCH 05/17] getClassHierarchy(Object) implemented and tested but in need of refactor, end of class push --- .../john/typeInformation/Reflector.java | 56 ++++++++++++++++--- .../john/typeInformation/ReflectorTest.java | 26 ++++++++- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java index 3848511..4a13e7a 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -8,6 +8,7 @@ /** * Created by johnsquier on 2/15/17. + * @@@ Refactor getClassHierarchy(Object) */ public class Reflector { @@ -23,14 +24,10 @@ public boolean classImplementsInterface(String theClassName, String theInterface public boolean classImplementsInterface(Class theClass, String theInterface) { Class[] implementedInterfaces = theClass.getInterfaces(); - Class theInterfaceClass; + Class theInterfaceClass = getClassFromInterface(theInterface); - // extract into getClassFromInterface method - try { - theInterfaceClass = Class.forName(theInterface); - } - catch ( ClassNotFoundException e ) { - System.err.println("Interface: " + theInterface + " not found"); + // uncle bob says no null's but I think it makes the code more readable than a try catch + if ( theInterfaceClass == null ) { return false; } @@ -54,7 +51,7 @@ public String listAllMembers(Object o) { sb.append(generateClassInfoString(theClass)); - while ( !theClass.getSimpleName().equals("Object")) { + while ( !theClass.getSimpleName().equals("Object") ) { theClass = theClass.getSuperclass(); sb.append(generateClassInfoString(theClass)); } @@ -62,6 +59,49 @@ public String listAllMembers(Object o) { return sb.toString(); } + // @@@ refactor + public String getClassHierarchy(Object o) { + List> classHierarchyInReverse = new ArrayList<>(); + Class theClass = o.getClass(); + + classHierarchyInReverse.add(theClass); + + while( !theClass.getSimpleName().equals("Object") ) { + theClass = theClass.getSuperclass(); + classHierarchyInReverse.add(theClass); + } + + StringBuilder sb = new StringBuilder(); + int numSpaces = 0; + + for ( int i = classHierarchyInReverse.size()-1; i >= 0; i-- ) { + for ( int j = 0; j < numSpaces; j++ ) { + sb.append(" "); + } + numSpaces += 2; + sb.append(classHierarchyInReverse.get(i).getName()); + sb.append("\n"); + } + + return sb.toString(); + } + + public List instantiateClassHierarcy(Object o) { + return null; + } + + private Class getClassFromInterface(String theInterface) { + Class theInterfaceClass; + try { + theInterfaceClass = Class.forName(theInterface); + } + catch ( ClassNotFoundException e ) { + System.err.println("Interface: " + theInterface + " not found"); + return null; + } + return theInterfaceClass; + } + private String generateClassInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectorTest.java index e449648..d5a8926 100644 --- a/src/test/java/squier/john/typeInformation/ReflectorTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectorTest.java @@ -7,6 +7,7 @@ import java.io.BufferedWriter; import java.io.FileWriter; import java.util.Scanner; +import java.util.TreeMap; /** * Created by johnsquier on 2/15/17. @@ -84,7 +85,7 @@ public void stringIsNotAClassNameButAStringLiteralTest() { } @Test - public void tryToCompareObjectToNonExistentInterface() { + public void tryToCompareObjectToNonExistentInterfaceTest() { boolean expected = false; boolean actual = reflector.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); @@ -93,7 +94,7 @@ public void tryToCompareObjectToNonExistentInterface() { } @Test - public void listAllMembersBufferedWriter() { + public void listAllMembersBufferedWriterTest() { String expected = "Fields\n" + "Constructors\n" + "BufferedWriter : public java.io.BufferedWriter(java.io.Writer)\n" + @@ -143,7 +144,7 @@ public void listAllMembersBufferedWriter() { } @Test - public void listAllMembersBoolean() { + public void listAllMembersBooleanTest() { String expected = "Fields\n" + "Boolean : public static final Boolean TRUE\n" + "Boolean : public static final Boolean FALSE\n" + @@ -186,4 +187,23 @@ public void listAllMembersBoolean() { Assert.assertEquals(expected, actual); } + + @Test + public void getClassHierarchyBooleanTest() { + String expected = "java.lang.Object\n java.lang.Boolean\n"; + + String actual = reflector.getClassHierarchy(new Boolean(true)); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getClassHierarchyTreeMapTest() { + String expected = "java.lang.Object\n java.util.AbstractMap\n java.util.TreeMap\n"; + + String actual = reflector.getClassHierarchy(new TreeMap()); + + Assert.assertEquals(expected, actual); + } + } From ce70a1085e2c724aebc3465185d4f4e4aaa3d3e4 Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 22:06:55 -0500 Subject: [PATCH 06/17] major refactor to Reflector(), final task of part 1 still unfinished --- | 0 .../john/typeInformation/Reflector.java | 236 +++++++++++------- .../john/typeInformation/ReflectorTest.java | 35 ++- 3 files changed, 159 insertions(+), 112 deletions(-) delete mode 100644 diff --git a/ b/ deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java index 4a13e7a..b80198d 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -8,36 +8,26 @@ /** * Created by johnsquier on 2/15/17. - * @@@ Refactor getClassHierarchy(Object) */ public class Reflector { - public boolean classImplementsInterface(String theClassName, String theInterface) { - try { - Class theClass = Class.forName(theClassName); - return classImplementsInterface(theClass, theInterface); - } - catch ( ClassNotFoundException e ) { - return classImplementsInterface((Object)theClassName, theInterface); + public boolean classImplementsInterface(String aClassName, String anInterfaceName) { + Class theClass = getClassName(aClassName); + + if ( theClass == null ) { // more readable than try-catch? + return classImplementsInterface((Object) aClassName, anInterfaceName); + } else { + return classImplementsInterface(theClass, anInterfaceName); } } - public boolean classImplementsInterface(Class theClass, String theInterface) { - Class[] implementedInterfaces = theClass.getInterfaces(); - Class theInterfaceClass = getClassFromInterface(theInterface); + public boolean classImplementsInterface(Class theClass, String anInterface) { + Class theInterfaceClass = getClassName(anInterface); - // uncle bob says no null's but I think it makes the code more readable than a try catch - if ( theInterfaceClass == null ) { + if ( theInterfaceClass == null ) { // same here? return false; } - - for ( Class c : implementedInterfaces ) { - if ( c.getName().equals(theInterfaceClass.getName()) ) { - return true; - } - } - - return false; + return checkClassForInterface(theClass, theInterfaceClass); } public boolean classImplementsInterface(Object o, String theInterface) { @@ -48,146 +38,169 @@ public String listAllMembers(Object o) { StringBuilder sb = new StringBuilder(); Class theClass = o.getClass(); + sb.append(classInfoString(theClass)); - sb.append(generateClassInfoString(theClass)); - - while ( !theClass.getSimpleName().equals("Object") ) { + while ( hasASuperClass(theClass) ) { theClass = theClass.getSuperclass(); - sb.append(generateClassInfoString(theClass)); + sb.append(classInfoString(theClass)); } - return sb.toString(); } - // @@@ refactor public String getClassHierarchy(Object o) { List> classHierarchyInReverse = new ArrayList<>(); - Class theClass = o.getClass(); + Class theClass = o.getClass(); classHierarchyInReverse.add(theClass); - while( !theClass.getSimpleName().equals("Object") ) { + while ( hasASuperClass(theClass) ) { theClass = theClass.getSuperclass(); classHierarchyInReverse.add(theClass); } - - StringBuilder sb = new StringBuilder(); - int numSpaces = 0; - - for ( int i = classHierarchyInReverse.size()-1; i >= 0; i-- ) { - for ( int j = 0; j < numSpaces; j++ ) { - sb.append(" "); - } - numSpaces += 2; - sb.append(classHierarchyInReverse.get(i).getName()); - sb.append("\n"); - } - - return sb.toString(); + return generateClassHierarchyString(classHierarchyInReverse); } + // 6 public List instantiateClassHierarcy(Object o) { return null; } - private Class getClassFromInterface(String theInterface) { + private Class getClassName(String aClassName) { Class theInterfaceClass; try { - theInterfaceClass = Class.forName(theInterface); - } - catch ( ClassNotFoundException e ) { - System.err.println("Interface: " + theInterface + " not found"); + theInterfaceClass = Class.forName(aClassName); + } catch (ClassNotFoundException e) { + System.err.println("Class: " + aClassName + " not found"); return null; } return theInterfaceClass; } - private String generateClassInfoString(Class theClass) { + private boolean checkClassForInterface(Class theClass, Class theInterfaceClass) { + Class[] implementedInterfaces = theClass.getInterfaces(); + + for ( Class c : implementedInterfaces ) { + if ( c.getName().equals(theInterfaceClass.getName()) ) { + return true; + } + } + return false; + } + + private String classInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); - sb.append(generateFieldsInfoString(theClass)); - sb.append(generateConstructorInfoString(theClass)); - sb.append(generateMethodsInfoString(theClass)); + sb.append(fieldsInfoString(theClass)); + sb.append(constructorInfoString(theClass)); + sb.append(methodsInfoString(theClass)); return sb.toString(); } - private String generateFieldsInfoString(Class theClass) { + private String fieldsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); Field[] fields = theClass.getFields(); - sb.append("Fields\n"); - for ( Field f : fields ) { - sb.append(theClass.getSimpleName()).append(" : "); - sb.append(Modifier.toString(f.getModifiers())).append(" "); - sb.append(f.getType().getSimpleName()).append(" "); - sb.append(f.getName()).append("\n"); + for (Field f : fields) { + sb.append(classNameAndColon(theClass)); + sb.append(modifiers(f)); + sb.append(fieldType(f)); + sb.append(fieldName(f)); } - return sb.toString(); } - private String generateConstructorInfoString(Class theClass) { + private String constructorInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); Constructor[] constructors = theClass.getConstructors(); - sb.append("Constructors\n"); - for ( Constructor c : constructors ) { - sb.append(theClass.getSimpleName()).append(" : "); - sb.append(Modifier.toString(c.getModifiers())).append(" "); - sb.append(c.getName()).append("("); - - Class[] params = c.getParameterTypes(); - sb.append(generateParamsInfoString(params)); - + for (Constructor c : constructors) { + sb.append(classNameAndColon(theClass)); + sb.append(modifiers(c)); + sb.append(constructorName(c)); + sb.append(params(c)); sb.append("\n"); } - return sb.toString(); } - private String generateMethodsInfoString(Class theClass) { + private String methodsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); Method[] methods = theClass.getMethods(); - - Arrays.sort(methods, new Comparator() { - @Override - public int compare(Method o1, Method o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - sb.append("Methods\n"); - for ( Method m : methods ) { - if ( m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()) ) { - sb.append(theClass.getSimpleName()).append(" : "); - sb.append(Modifier.toString(m.getModifiers())).append(" "); - sb.append(m.getReturnType()).append(" "); - sb.append(m.getName()).append("("); - Class[] params = m.getParameterTypes(); - sb.append(generateParamsInfoString(params)); + methods = sortMethodArray(methods); + for (Method m : methods) { + if ( methodIsDeclaredInThisClass(m, theClass) ) { + sb.append(classNameAndColon(theClass)); + sb.append(modifiers(m)); + sb.append(methodReturnType(m)); + sb.append(methodName(m)); + sb.append(params(m)); sb.append("\n"); } } - return sb.toString(); } - private String generateParamsInfoString(Class[] params) { + private String classNameAndColon(Class theClass) { + return theClass.getSimpleName() + " : "; + } + + private String modifiers(Field f) { + return Modifier.toString(f.getModifiers()) + " "; + } + + private String modifiers(Constructor c) { + return Modifier.toString(c.getModifiers()) + " "; + } + + private String modifiers(Method m) { + return Modifier.toString((m.getModifiers())) + " "; + } + + private String fieldType(Field f) { + return f.getType().getSimpleName() + " "; + } + + private String fieldName(Field f) { + return f.getName() + "\n"; + } + + private String constructorName(Constructor c) { + return c.getName() + "("; + } + + private String methodReturnType(Method m) { + return m.getReturnType() + " "; + } + + private String methodName(Method m) { + return m.getName() + "("; + } + + private String params(Constructor c) { + return paramsInfoString(c.getParameterTypes()); + } + + private String params(Method m) { + return paramsInfoString(m.getParameterTypes()); + } + + // @@@ Refactor + private String paramsInfoString(Class[] params) { StringBuilder sb = new StringBuilder(); - if ( params.length == 0 ) { + if (params.length == 0) { sb.append(")"); - } - else { - for ( int i = 0; i < params.length; i++ ) { + } else { + for (int i = 0; i < params.length; i++) { sb.append(params[i].getName()); if (i < params.length - 1) { sb.append(", "); @@ -196,7 +209,42 @@ private String generateParamsInfoString(Class[] params) { } } } + return sb.toString(); + } + + private Method[] sortMethodArray(Method[] m) { + Arrays.sort(m, new Comparator() { + @Override + public int compare(Method o1, Method o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return m; + } + + private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { + return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); + } + // p4.2 + private boolean hasASuperClass(Class theClass) { + return !theClass.getSimpleName().equals("Object"); + } + + // p5.1 @@@ Refactor + private String generateClassHierarchyString(List> classHierarchyInReverse) { + StringBuilder sb = new StringBuilder(); + + int numSpaces = 0; + for (int i = classHierarchyInReverse.size() - 1; i >= 0; i--) { + for (int j = 0; j < numSpaces; j++) { + sb.append(" "); + } + numSpaces += 2; + sb.append(classHierarchyInReverse.get(i).getName()); + sb.append("\n"); + } return sb.toString(); } } + diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectorTest.java index d5a8926..66b42a6 100644 --- a/src/test/java/squier/john/typeInformation/ReflectorTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectorTest.java @@ -24,73 +24,73 @@ public void setup() { @Test public void objectDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I expect Scanner(System.in) to implement \"java.io.Closeable\"", + expected, actual); } @Test public void objectDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Integer(10), "java.lang.Iterable"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I don't expect Integer(10) to implement \"java.lang.Iterable\"", + expected, actual); } @Test public void classObjectDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I expect String.class to implement \"java.lang.CharSequence\"", + expected, actual); } @Test public void classObjectDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I don't expect Integer.class to implement \"java.lang.Iterable\"", + expected, actual); } @Test public void classNameDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I expect \"java.lang.String\" to implement \"java.lang.CharSequence\"", + expected, actual); } @Test public void classNameDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement\"java.lang.Iterable\"", + expected, actual); } @Test public void stringIsNotAClassNameButAStringLiteralTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface(" ", "java.lang.CharSequence"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I expect \" \" to implement \"java.lang.CharSequence\"", + expected, actual); } @Test public void tryToCompareObjectToNonExistentInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); - Assert.assertEquals(expected, actual); + Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", + expected, actual); } @Test @@ -137,6 +137,7 @@ public void listAllMembersBufferedWriterTest() { "Object : public final void wait()\n"; String actual = null; + try { actual = reflector.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } catch ( Exception e ) { } @@ -191,7 +192,6 @@ public void listAllMembersBooleanTest() { @Test public void getClassHierarchyBooleanTest() { String expected = "java.lang.Object\n java.lang.Boolean\n"; - String actual = reflector.getClassHierarchy(new Boolean(true)); Assert.assertEquals(expected, actual); @@ -200,7 +200,6 @@ public void getClassHierarchyBooleanTest() { @Test public void getClassHierarchyTreeMapTest() { String expected = "java.lang.Object\n java.util.AbstractMap\n java.util.TreeMap\n"; - String actual = reflector.getClassHierarchy(new TreeMap()); Assert.assertEquals(expected, actual); From 728a2bee1f0cfc2fce1aa94391b1f455c885ff3f Mon Sep 17 00:00:00 2001 From: John Squier Date: Wed, 15 Feb 2017 22:13:38 -0500 Subject: [PATCH 07/17] moved methods around, trying to decide on method order --- .../john/typeInformation/Reflector.java | 99 +++++++++---------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/Reflector.java index b80198d..dfe9a52 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/Reflector.java @@ -34,37 +34,6 @@ public boolean classImplementsInterface(Object o, String theInterface) { return classImplementsInterface(o.getClass(), theInterface); } - public String listAllMembers(Object o) { - StringBuilder sb = new StringBuilder(); - - Class theClass = o.getClass(); - sb.append(classInfoString(theClass)); - - while ( hasASuperClass(theClass) ) { - theClass = theClass.getSuperclass(); - sb.append(classInfoString(theClass)); - } - return sb.toString(); - } - - public String getClassHierarchy(Object o) { - List> classHierarchyInReverse = new ArrayList<>(); - - Class theClass = o.getClass(); - classHierarchyInReverse.add(theClass); - - while ( hasASuperClass(theClass) ) { - theClass = theClass.getSuperclass(); - classHierarchyInReverse.add(theClass); - } - return generateClassHierarchyString(classHierarchyInReverse); - } - - // 6 - public List instantiateClassHierarcy(Object o) { - return null; - } - private Class getClassName(String aClassName) { Class theInterfaceClass; try { @@ -87,6 +56,19 @@ private boolean checkClassForInterface(Class theClass, Class theInterfaceC return false; } + public String listAllMembers(Object o) { + StringBuilder sb = new StringBuilder(); + + Class theClass = o.getClass(); + sb.append(classInfoString(theClass)); + + while ( hasASuperClass(theClass) ) { + theClass = theClass.getSuperclass(); + sb.append(classInfoString(theClass)); + } + return sb.toString(); + } + private String classInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); @@ -97,6 +79,10 @@ private String classInfoString(Class theClass) { return sb.toString(); } + private boolean hasASuperClass(Class theClass) { + return !theClass.getSimpleName().equals("Object"); + } + private String fieldsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); @@ -149,6 +135,20 @@ private String methodsInfoString(Class theClass) { return sb.toString(); } + private Method[] sortMethodArray(Method[] m) { + Arrays.sort(m, new Comparator() { + @Override + public int compare(Method o1, Method o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return m; + } + + private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { + return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); + } + private String classNameAndColon(Class theClass) { return theClass.getSimpleName() + " : "; } @@ -169,6 +169,10 @@ private String fieldType(Field f) { return f.getType().getSimpleName() + " "; } + private String methodReturnType(Method m) { + return m.getReturnType() + " "; + } + private String fieldName(Field f) { return f.getName() + "\n"; } @@ -177,10 +181,6 @@ private String constructorName(Constructor c) { return c.getName() + "("; } - private String methodReturnType(Method m) { - return m.getReturnType() + " "; - } - private String methodName(Method m) { return m.getName() + "("; } @@ -212,23 +212,17 @@ private String paramsInfoString(Class[] params) { return sb.toString(); } - private Method[] sortMethodArray(Method[] m) { - Arrays.sort(m, new Comparator() { - @Override - public int compare(Method o1, Method o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - return m; - } + public String getClassHierarchy(Object o) { + List> classHierarchyInReverse = new ArrayList<>(); - private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { - return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); - } + Class theClass = o.getClass(); + classHierarchyInReverse.add(theClass); - // p4.2 - private boolean hasASuperClass(Class theClass) { - return !theClass.getSimpleName().equals("Object"); + while ( hasASuperClass(theClass) ) { + theClass = theClass.getSuperclass(); + classHierarchyInReverse.add(theClass); + } + return generateClassHierarchyString(classHierarchyInReverse); } // p5.1 @@@ Refactor @@ -246,5 +240,10 @@ private String generateClassHierarchyString(List> classHierarchyInRever } return sb.toString(); } + + // 6 + public List instantiateClassHierarcy(Object o) { + return null; + } } From 6a89de70cb9bc08d3d1d2cd0db6beff3945792a8 Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 16 Feb 2017 07:57:19 -0500 Subject: [PATCH 08/17] minor refactors and changed class name to ReflectionUtils --- .../{Reflector.java => ReflectionUtils.java} | 115 +++++++++++------- ...ctorTest.java => ReflectionUtilsTest.java} | 32 ++--- 2 files changed, 88 insertions(+), 59 deletions(-) rename src/main/java/squier/john/typeInformation/{Reflector.java => ReflectionUtils.java} (83%) rename src/test/java/squier/john/typeInformation/{ReflectorTest.java => ReflectionUtilsTest.java} (85%) diff --git a/src/main/java/squier/john/typeInformation/Reflector.java b/src/main/java/squier/john/typeInformation/ReflectionUtils.java similarity index 83% rename from src/main/java/squier/john/typeInformation/Reflector.java rename to src/main/java/squier/john/typeInformation/ReflectionUtils.java index dfe9a52..7a4bf47 100644 --- a/src/main/java/squier/john/typeInformation/Reflector.java +++ b/src/main/java/squier/john/typeInformation/ReflectionUtils.java @@ -9,7 +9,7 @@ /** * Created by johnsquier on 2/15/17. */ -public class Reflector { +public class ReflectionUtils { public boolean classImplementsInterface(String aClassName, String anInterfaceName) { Class theClass = getClassName(aClassName); @@ -34,6 +34,32 @@ public boolean classImplementsInterface(Object o, String theInterface) { return classImplementsInterface(o.getClass(), theInterface); } + public String listAllMembers(Object o) { + StringBuilder sb = new StringBuilder(); + + Class theClass = o.getClass(); + sb.append(classInfoString(theClass)); + + while ( hasASuperClass(theClass) ) { + theClass = theClass.getSuperclass(); + sb.append(classInfoString(theClass)); + } + return sb.toString(); + } + + public String getClassHierarchy(Object o) { + List> classHierarchyInReverse = new ArrayList<>(); + + Class theClass = o.getClass(); + classHierarchyInReverse.add(theClass); + + while ( hasASuperClass(theClass) ) { + theClass = theClass.getSuperclass(); + classHierarchyInReverse.add(theClass); + } + return generateClassHierarchyString(classHierarchyInReverse); + } + private Class getClassName(String aClassName) { Class theInterfaceClass; try { @@ -56,19 +82,6 @@ private boolean checkClassForInterface(Class theClass, Class theInterfaceC return false; } - public String listAllMembers(Object o) { - StringBuilder sb = new StringBuilder(); - - Class theClass = o.getClass(); - sb.append(classInfoString(theClass)); - - while ( hasASuperClass(theClass) ) { - theClass = theClass.getSuperclass(); - sb.append(classInfoString(theClass)); - } - return sb.toString(); - } - private String classInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); @@ -79,18 +92,16 @@ private String classInfoString(Class theClass) { return sb.toString(); } - private boolean hasASuperClass(Class theClass) { - return !theClass.getSimpleName().equals("Object"); - } - private String fieldsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); Field[] fields = theClass.getFields(); sb.append("Fields\n"); + fields = sortMemberArray(fields); + for (Field f : fields) { - sb.append(classNameAndColon(theClass)); + sb.append(classNameHeader(theClass)); sb.append(modifiers(f)); sb.append(fieldType(f)); sb.append(fieldName(f)); @@ -104,8 +115,10 @@ private String constructorInfoString(Class theClass) { Constructor[] constructors = theClass.getConstructors(); sb.append("Constructors\n"); + // sort constructors by name? + for (Constructor c : constructors) { - sb.append(classNameAndColon(theClass)); + sb.append(classNameHeader(theClass)); sb.append(modifiers(c)); sb.append(constructorName(c)); sb.append(params(c)); @@ -120,11 +133,11 @@ private String methodsInfoString(Class theClass) { Method[] methods = theClass.getMethods(); sb.append("Methods\n"); - methods = sortMethodArray(methods); + methods = sortMemberArray(methods); for (Method m : methods) { if ( methodIsDeclaredInThisClass(m, theClass) ) { - sb.append(classNameAndColon(theClass)); + sb.append(classNameHeader(theClass)); sb.append(modifiers(m)); sb.append(methodReturnType(m)); sb.append(methodName(m)); @@ -135,7 +148,17 @@ private String methodsInfoString(Class theClass) { return sb.toString(); } - private Method[] sortMethodArray(Method[] m) { + private Field[] sortMemberArray(Field[] f) { + Arrays.sort(f, new Comparator() { + @Override + public int compare(Field o1, Field o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return f; + } + + private Method[] sortMemberArray(Method[] m) { Arrays.sort(m, new Comparator() { @Override public int compare(Method o1, Method o2) { @@ -149,7 +172,11 @@ private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); } - private String classNameAndColon(Class theClass) { + private boolean hasASuperClass(Class theClass) { + return !theClass.getSimpleName().equals("Object"); + } + + private String classNameHeader(Class theClass) { return theClass.getSimpleName() + " : "; } @@ -193,39 +220,41 @@ private String params(Method m) { return paramsInfoString(m.getParameterTypes()); } - // @@@ Refactor private String paramsInfoString(Class[] params) { StringBuilder sb = new StringBuilder(); - if (params.length == 0) { + if ( empty(params) ) { sb.append(")"); } else { - for (int i = 0; i < params.length; i++) { - sb.append(params[i].getName()); - if (i < params.length - 1) { - sb.append(", "); - } else { - sb.append(")"); - } - } + sb.append(allParams(params)); } return sb.toString(); } - public String getClassHierarchy(Object o) { - List> classHierarchyInReverse = new ArrayList<>(); + private boolean empty(Class[] params) { + return params.length == 0; + } - Class theClass = o.getClass(); - classHierarchyInReverse.add(theClass); + private String allParams(Class[] params) { + StringBuilder sb = new StringBuilder(); - while ( hasASuperClass(theClass) ) { - theClass = theClass.getSuperclass(); - classHierarchyInReverse.add(theClass); + for (int i = 0; i < params.length; i++) { + sb.append(params[i].getName()); + + if (iIsTheLastParam(i, params.length)) { + sb.append(")"); + } else { + sb.append(", "); + } } - return generateClassHierarchyString(classHierarchyInReverse); + return sb.toString(); + } + + private boolean iIsTheLastParam(int i, int n) { + return i == n-1; } - // p5.1 @@@ Refactor + // @@@ Refactor private String generateClassHierarchyString(List> classHierarchyInReverse) { StringBuilder sb = new StringBuilder(); diff --git a/src/test/java/squier/john/typeInformation/ReflectorTest.java b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java similarity index 85% rename from src/test/java/squier/john/typeInformation/ReflectorTest.java rename to src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java index 66b42a6..117fe25 100644 --- a/src/test/java/squier/john/typeInformation/ReflectorTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java @@ -12,19 +12,19 @@ /** * Created by johnsquier on 2/15/17. */ -public class ReflectorTest { +public class ReflectionUtilsTest { - Reflector reflector; + ReflectionUtils reflectionUtils; @Before public void setup() { - reflector = new Reflector(); + reflectionUtils = new ReflectionUtils(); } @Test public void objectDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); + boolean actual = reflectionUtils.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); Assert.assertEquals("I expect Scanner(System.in) to implement \"java.io.Closeable\"", expected, actual); @@ -33,7 +33,7 @@ public void objectDoesImplementInterfaceTest() { @Test public void objectDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Integer(10), "java.lang.Iterable"); + boolean actual = reflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); Assert.assertEquals("I don't expect Integer(10) to implement \"java.lang.Iterable\"", expected, actual); @@ -42,7 +42,7 @@ public void objectDoesNotImplementInterfaceTest() { @Test public void classObjectDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); + boolean actual = reflectionUtils.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); Assert.assertEquals("I expect String.class to implement \"java.lang.CharSequence\"", expected, actual); @@ -51,7 +51,7 @@ public void classObjectDoesImplementInterfaceTest() { @Test public void classObjectDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); + boolean actual = reflectionUtils.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); Assert.assertEquals("I don't expect Integer.class to implement \"java.lang.Iterable\"", expected, actual); @@ -60,7 +60,7 @@ public void classObjectDoesNotImplementInterfaceTest() { @Test public void classNameDoesImplementInterfaceTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); + boolean actual = reflectionUtils.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); Assert.assertEquals("I expect \"java.lang.String\" to implement \"java.lang.CharSequence\"", expected, actual); @@ -69,7 +69,7 @@ public void classNameDoesImplementInterfaceTest() { @Test public void classNameDoesNotImplementInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); + boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement\"java.lang.Iterable\"", expected, actual); @@ -78,7 +78,7 @@ public void classNameDoesNotImplementInterfaceTest() { @Test public void stringIsNotAClassNameButAStringLiteralTest() { boolean expected = true; - boolean actual = reflector.classImplementsInterface(" ", "java.lang.CharSequence"); + boolean actual = reflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); Assert.assertEquals("I expect \" \" to implement \"java.lang.CharSequence\"", expected, actual); @@ -87,7 +87,7 @@ public void stringIsNotAClassNameButAStringLiteralTest() { @Test public void tryToCompareObjectToNonExistentInterfaceTest() { boolean expected = false; - boolean actual = reflector.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); + boolean actual = reflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", expected, actual); @@ -138,7 +138,7 @@ public void listAllMembersBufferedWriterTest() { String actual = null; - try { actual = reflector.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } + try { actual = reflectionUtils.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } catch ( Exception e ) { } Assert.assertEquals(expected, actual); @@ -147,8 +147,8 @@ public void listAllMembersBufferedWriterTest() { @Test public void listAllMembersBooleanTest() { String expected = "Fields\n" + - "Boolean : public static final Boolean TRUE\n" + "Boolean : public static final Boolean FALSE\n" + + "Boolean : public static final Boolean TRUE\n" + "Boolean : public static final Class TYPE\n" + "Constructors\n" + "Boolean : public java.lang.Boolean(boolean)\n" + @@ -184,7 +184,7 @@ public void listAllMembersBooleanTest() { "Object : public final native void wait(long)\n" + "Object : public final void wait()\n"; - String actual = reflector.listAllMembers(new Boolean(true)); + String actual = reflectionUtils.listAllMembers(new Boolean(true)); Assert.assertEquals(expected, actual); } @@ -192,7 +192,7 @@ public void listAllMembersBooleanTest() { @Test public void getClassHierarchyBooleanTest() { String expected = "java.lang.Object\n java.lang.Boolean\n"; - String actual = reflector.getClassHierarchy(new Boolean(true)); + String actual = reflectionUtils.getClassHierarchy(new Boolean(true)); Assert.assertEquals(expected, actual); } @@ -200,7 +200,7 @@ public void getClassHierarchyBooleanTest() { @Test public void getClassHierarchyTreeMapTest() { String expected = "java.lang.Object\n java.util.AbstractMap\n java.util.TreeMap\n"; - String actual = reflector.getClassHierarchy(new TreeMap()); + String actual = reflectionUtils.getClassHierarchy(new TreeMap()); Assert.assertEquals(expected, actual); } From 1d7a825bc6e8fb28d8192379f31e4dc70d821a31 Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 16 Feb 2017 08:16:04 -0500 Subject: [PATCH 09/17] moved methods around again --- .../john/typeInformation/ReflectionUtils.java | 138 +++++++++--------- .../typeInformation/ReflectionUtilsTest.java | 61 +++++++- 2 files changed, 124 insertions(+), 75 deletions(-) diff --git a/src/main/java/squier/john/typeInformation/ReflectionUtils.java b/src/main/java/squier/john/typeInformation/ReflectionUtils.java index 7a4bf47..7aceb24 100644 --- a/src/main/java/squier/john/typeInformation/ReflectionUtils.java +++ b/src/main/java/squier/john/typeInformation/ReflectionUtils.java @@ -60,8 +60,17 @@ public String getClassHierarchy(Object o) { return generateClassHierarchyString(classHierarchyInReverse); } + // 6 + public List instantiateClassHierarcy(Object o) { + return null; + } + private Class getClassName(String aClassName) { Class theInterfaceClass; + + if ( aClassName == null ) { + return null; + } try { theInterfaceClass = Class.forName(aClassName); } catch (ClassNotFoundException e) { @@ -148,32 +157,54 @@ private String methodsInfoString(Class theClass) { return sb.toString(); } - private Field[] sortMemberArray(Field[] f) { - Arrays.sort(f, new Comparator() { - @Override - public int compare(Field o1, Field o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - return f; + private String paramsInfoString(Class[] params) { + StringBuilder sb = new StringBuilder(); + + if ( empty(params) ) { + sb.append(")"); + } else { + sb.append(allParams(params)); + } + return sb.toString(); } - private Method[] sortMemberArray(Method[] m) { - Arrays.sort(m, new Comparator() { - @Override - public int compare(Method o1, Method o2) { - return o1.getName().compareTo(o2.getName()); + // @@@ Refactor + private String generateClassHierarchyString(List> classHierarchyInReverse) { + StringBuilder sb = new StringBuilder(); + + int numSpaces = 0; + for (int i = classHierarchyInReverse.size() - 1; i >= 0; i--) { + for (int j = 0; j < numSpaces; j++) { + sb.append(" "); } - }); - return m; + numSpaces += 2; + sb.append(classHierarchyInReverse.get(i).getName()); + sb.append("\n"); + } + return sb.toString(); } - private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { - return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); + private String params(Constructor c) { + return paramsInfoString(c.getParameterTypes()); } - private boolean hasASuperClass(Class theClass) { - return !theClass.getSimpleName().equals("Object"); + private String params(Method m) { + return paramsInfoString(m.getParameterTypes()); + } + + private String allParams(Class[] params) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < params.length; i++) { + sb.append(params[i].getName()); + + if (iIsTheLastParam(i, params.length)) { + sb.append(")"); + } else { + sb.append(", "); + } + } + return sb.toString(); } private String classNameHeader(Class theClass) { @@ -212,67 +243,40 @@ private String methodName(Method m) { return m.getName() + "("; } - private String params(Constructor c) { - return paramsInfoString(c.getParameterTypes()); + private Method[] sortMemberArray(Method[] m) { + Arrays.sort(m, new Comparator() { + @Override + public int compare(Method o1, Method o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return m; } - private String params(Method m) { - return paramsInfoString(m.getParameterTypes()); + private Field[] sortMemberArray(Field[] f) { + Arrays.sort(f, new Comparator() { + @Override + public int compare(Field o1, Field o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return f; } - private String paramsInfoString(Class[] params) { - StringBuilder sb = new StringBuilder(); + private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { + return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); + } - if ( empty(params) ) { - sb.append(")"); - } else { - sb.append(allParams(params)); - } - return sb.toString(); + private boolean hasASuperClass(Class theClass) { + return !theClass.getSimpleName().equals("Object"); } private boolean empty(Class[] params) { return params.length == 0; } - private String allParams(Class[] params) { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < params.length; i++) { - sb.append(params[i].getName()); - - if (iIsTheLastParam(i, params.length)) { - sb.append(")"); - } else { - sb.append(", "); - } - } - return sb.toString(); - } - private boolean iIsTheLastParam(int i, int n) { return i == n-1; } - - // @@@ Refactor - private String generateClassHierarchyString(List> classHierarchyInReverse) { - StringBuilder sb = new StringBuilder(); - - int numSpaces = 0; - for (int i = classHierarchyInReverse.size() - 1; i >= 0; i--) { - for (int j = 0; j < numSpaces; j++) { - sb.append(" "); - } - numSpaces += 2; - sb.append(classHierarchyInReverse.get(i).getName()); - sb.append("\n"); - } - return sb.toString(); - } - - // 6 - public List instantiateClassHierarcy(Object o) { - return null; - } } diff --git a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java index 117fe25..4dd89a8 100644 --- a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java @@ -35,7 +35,7 @@ public void objectDoesNotImplementInterfaceTest() { boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); - Assert.assertEquals("I don't expect Integer(10) to implement \"java.lang.Iterable\"", + Assert.assertEquals("I don't expect Integer() to implement \"java.lang.Iterable\"", expected, actual); } @@ -76,20 +76,65 @@ public void classNameDoesNotImplementInterfaceTest() { } @Test - public void stringIsNotAClassNameButAStringLiteralTest() { - boolean expected = true; - boolean actual = reflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); + public void tryToCompareObjectToNonExistentInterfaceTest() { + boolean expected = false; + boolean actual = reflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); - Assert.assertEquals("I expect \" \" to implement \"java.lang.CharSequence\"", + Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", expected, actual); } @Test - public void tryToCompareObjectToNonExistentInterfaceTest() { + public void tryToCompareClassObjectToNonExistentInterfaceTest() { boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); + boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), "abra.kadabra.Allakhazham"); - Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", + Assert.assertEquals("I don't expect Object.class to implement \"abra.kadabra.Allakhazham\"", + expected, actual); + } + + @Test + public void tryToCompareClassNameToNonExistentInterfaceTest() { + boolean expected = false; + boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "abra.kadabra.Allakhazham"); + + Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement \"abra.kadabra.Allakhazham\"", + expected, actual); + } + + @Test + public void tryToCompareObjectToNullInterface() { + boolean expected = false; + boolean actual = reflectionUtils.classImplementsInterface(new Object(), null); + + Assert.assertEquals("I don't expect Object() to implement null", + expected, actual); + } + + @Test + public void tryToCompareClassObjectToNullInterface() { + boolean expected = false; + boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), null); + + Assert.assertEquals("I don't expect Object.class to implement null", + expected, actual); + } + + @Test + public void tryToCompareClassNameToNullInterface() { + boolean expected = false; + boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", null); + + Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement null", + expected, actual); + } + + @Test + public void stringIsNotAClassNameButAStringLiteralTest() { + boolean expected = true; + boolean actual = reflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); + + Assert.assertEquals("I expect \" \" to implement \"java.lang.CharSequence\"", expected, actual); } From a17f1c3d763b69c43b69fb0e2f8dfe0fc39461e9 Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 16 Feb 2017 10:53:46 -0500 Subject: [PATCH 10/17] implemented and partially tested instantiateClassHierarchy() as well as refactored a few methods --- ...ClassInHierarchyLacksNoArgConstructor.java | 6 + .../john/typeInformation/ReflectionUtils.java | 185 ++++++++++++------ .../typeInformation/ReflectionUtilsTest.java | 75 ++++++- 3 files changed, 205 insertions(+), 61 deletions(-) create mode 100644 src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java diff --git a/src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java b/src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java new file mode 100644 index 0000000..d7e3065 --- /dev/null +++ b/src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java @@ -0,0 +1,6 @@ +package squier.john.typeInformation; + +/** + * Created by johnsquier on 2/16/17. + */ +public class ClassInHierarchyLacksNoArgConstructor extends Exception { } diff --git a/src/main/java/squier/john/typeInformation/ReflectionUtils.java b/src/main/java/squier/john/typeInformation/ReflectionUtils.java index 7aceb24..76c4ada 100644 --- a/src/main/java/squier/john/typeInformation/ReflectionUtils.java +++ b/src/main/java/squier/john/typeInformation/ReflectionUtils.java @@ -7,7 +7,8 @@ import java.util.*; /** - * Created by johnsquier on 2/15/17. + * Created by John A. Squier on 2/15/17. + * @@@ multiple refactor spots in src */ public class ReflectionUtils { @@ -60,11 +61,28 @@ public String getClassHierarchy(Object o) { return generateClassHierarchyString(classHierarchyInReverse); } - // 6 - public List instantiateClassHierarcy(Object o) { - return null; + // @@@ refactor + public List instantiateClassHierarchy(Object o) + throws ClassInHierarchyLacksNoArgConstructor, InstantiationException, IllegalAccessException { + List theHierarchy = new ArrayList<>(); + + while ( hasASuperClass(o.getClass()) || isObjectClass(o) ) { + if ( OHasANoArgConstructor(o) ) { + theHierarchy.add(instantiate(o)); + } else { + throw new ClassInHierarchyLacksNoArgConstructor(); + } + if ( !isObjectClass(o) ) { + o = getNextConcreteClass(o); + } + else { + break; + } + } + return theHierarchy; } + // @@@ refactor private Class getClassName(String aClassName) { Class theInterfaceClass; @@ -83,12 +101,13 @@ private Class getClassName(String aClassName) { private boolean checkClassForInterface(Class theClass, Class theInterfaceClass) { Class[] implementedInterfaces = theClass.getInterfaces(); + boolean result = false; for ( Class c : implementedInterfaces ) { if ( c.getName().equals(theInterfaceClass.getName()) ) { - return true; + result = true; } } - return false; + return result; } private String classInfoString(Class theClass) { @@ -136,6 +155,7 @@ private String constructorInfoString(Class theClass) { return sb.toString(); } + // @@@ refactor loop body into sb.append(methodInfoString(m)) private String methodsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); @@ -168,45 +188,6 @@ private String paramsInfoString(Class[] params) { return sb.toString(); } - // @@@ Refactor - private String generateClassHierarchyString(List> classHierarchyInReverse) { - StringBuilder sb = new StringBuilder(); - - int numSpaces = 0; - for (int i = classHierarchyInReverse.size() - 1; i >= 0; i--) { - for (int j = 0; j < numSpaces; j++) { - sb.append(" "); - } - numSpaces += 2; - sb.append(classHierarchyInReverse.get(i).getName()); - sb.append("\n"); - } - return sb.toString(); - } - - private String params(Constructor c) { - return paramsInfoString(c.getParameterTypes()); - } - - private String params(Method m) { - return paramsInfoString(m.getParameterTypes()); - } - - private String allParams(Class[] params) { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < params.length; i++) { - sb.append(params[i].getName()); - - if (iIsTheLastParam(i, params.length)) { - sb.append(")"); - } else { - sb.append(", "); - } - } - return sb.toString(); - } - private String classNameHeader(Class theClass) { return theClass.getSimpleName() + " : "; } @@ -243,6 +224,44 @@ private String methodName(Method m) { return m.getName() + "("; } + private String params(Constructor c) { + return paramsInfoString(c.getParameterTypes()); + } + + private String params(Method m) { + return paramsInfoString(m.getParameterTypes()); + } + + private String allParams(Class[] params) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < params.length; i++) { + sb.append(params[i].getName()); + sb.append(paramDelimiter(i, params)); + } + return sb.toString(); + } + + private String paramDelimiter(int i, Class[] a) { + String result; + if (iIsTheLastParam(i, a.length)) { + result = ")"; + } else { + result = ", "; + } + return result; + } + + private Field[] sortMemberArray(Field[] f) { + Arrays.sort(f, new Comparator() { + @Override + public int compare(Field o1, Field o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return f; + } + private Method[] sortMemberArray(Method[] m) { Arrays.sort(m, new Comparator() { @Override @@ -253,30 +272,78 @@ public int compare(Method o1, Method o2) { return m; } - private Field[] sortMemberArray(Field[] f) { - Arrays.sort(f, new Comparator() { - @Override - public int compare(Field o1, Field o2) { - return o1.getName().compareTo(o2.getName()); + // @@@ Refactor + private String generateClassHierarchyString(List> classHierarchyInReverse) { + StringBuilder sb = new StringBuilder(); + + int numSpaces = 0; + for (int i = classHierarchyInReverse.size() - 1; i >= 0; i--) { + for (int j = 0; j < numSpaces; j++) { + sb.append(" "); } - }); - return f; + numSpaces += 2; + sb.append(classHierarchyInReverse.get(i).getName()); + sb.append("\n"); + } + return sb.toString(); } - private boolean methodIsDeclaredInThisClass(Method m, Class theClass) { - return m.getDeclaringClass().getSimpleName().equals(theClass.getSimpleName()); + // @@@ refactor + private Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { + Class theClass = o.getClass(); + Class theSuperClass = theClass.getSuperclass(); + + if ( isConcrete(theSuperClass) ) { + return theSuperClass.newInstance(); + } + else { + while ( hasASuperClass(theSuperClass) ) { + if ( isConcrete(theSuperClass) ) { + return theSuperClass; + } + theSuperClass = theSuperClass.getSuperclass(); + } + } + return theSuperClass.newInstance(); } - private boolean hasASuperClass(Class theClass) { - return !theClass.getSimpleName().equals("Object"); + private Object instantiate(Object o) throws IllegalAccessException, InstantiationException { + Class theClass = o.getClass(); + return theClass.newInstance(); } - private boolean empty(Class[] params) { - return params.length == 0; + private boolean hasASuperClass(Class c) { + return !c.getSimpleName().equals("Object"); + } + + private boolean methodIsDeclaredInThisClass(Method m, Class c) { + return m.getDeclaringClass().getSimpleName().equals(c.getSimpleName()); } private boolean iIsTheLastParam(int i, int n) { return i == n-1; } -} + private boolean empty(Class[] a) { + return a.length == 0; + } + + private boolean OHasANoArgConstructor(Object o) { + Constructor[] constructors = o.getClass().getConstructors(); + + for (Constructor c : constructors ) { + if ( c.getParameterTypes().length == 0 ) { + return true; + } + } + return false; + } + + private boolean isConcrete(Class c) { + return false; + } + + private boolean isObjectClass(Object o) { + return o.getClass().getSimpleName().equals("Object"); + } +} \ No newline at end of file diff --git a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java index 4dd89a8..838bb19 100644 --- a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java @@ -6,8 +6,7 @@ import java.io.BufferedWriter; import java.io.FileWriter; -import java.util.Scanner; -import java.util.TreeMap; +import java.util.*; /** * Created by johnsquier on 2/15/17. @@ -250,4 +249,76 @@ public void getClassHierarchyTreeMapTest() { Assert.assertEquals(expected, actual); } + @Test + public void instantiateClassHierarchyObject() { + List expected = new ArrayList<>(); + expected.add(new Object()); + + List actual = null; + try { + actual = reflectionUtils.instantiateClassHierarchy(new Object()); + } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { + classInHierarchyLacksNoArgConstructor.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Assert.assertTrue(actual.size() == 1); + Assert.assertTrue(actual.get(0).getClass().getSimpleName().equals(expected.get(0).getClass().getSimpleName())); + } + + @Test + public void instantiateClassHierarchyString() { + List expected = new ArrayList<>(); + expected.add(new String()); + expected.add(new Object()); + + List actual = null; + try { + actual = reflectionUtils.instantiateClassHierarchy(new String()); + } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { + classInHierarchyLacksNoArgConstructor.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Assert.assertTrue(actual.size() == 2); + Assert.assertEquals(expected.get(0).getClass().getSimpleName(), actual.get(0).getClass().getSimpleName()); + Assert.assertEquals(expected.get(1).getClass().getSimpleName(), actual.get(1).getClass().getSimpleName()); + } + + @Test + public void instantiateClassHierarchyArrayList() { + List expected = new ArrayList<>(); + expected.add(new ArrayList<>()); + // two abstract classes between ArrayList() and Object() + expected.add(new Object()); + + List actual = null; + try { + actual = reflectionUtils.instantiateClassHierarchy(new ArrayList<>()); + } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { + classInHierarchyLacksNoArgConstructor.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Assert.assertTrue(actual.size() == 2); + Assert.assertEquals(expected.get(0).getClass().getSimpleName(), actual.get(0).getClass().getSimpleName()); + Assert.assertEquals(expected.get(1).getClass().getSimpleName(), actual.get(1).getClass().getSimpleName()); + } + + @Test(expected = ClassInHierarchyLacksNoArgConstructor.class) + public void instantiateClassHierarchyBoolean() + throws IllegalAccessException, ClassInHierarchyLacksNoArgConstructor, InstantiationException { + reflectionUtils.instantiateClassHierarchy(new Boolean(true)); + } + + // @@@ add tests for the other exceptions } From 5ab38bec99c1c9fd71ac6b69996ba612ab124201 Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 16 Feb 2017 11:44:52 -0500 Subject: [PATCH 11/17] fully implemented and nearly completed testing of instantiateClassHierarchy(), had to fix bugs where abstract classes in the hierarchy were being instantiated and throwing an exception --- .../john/typeInformation/ReflectionUtils.java | 13 +++++---- ...sInHierarchyLacksNoArgConstructorTest.java | 16 ++++++++++ .../typeInformation/ReflectionUtilsTest.java | 29 ++++++++++++++++++- 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java diff --git a/src/main/java/squier/john/typeInformation/ReflectionUtils.java b/src/main/java/squier/john/typeInformation/ReflectionUtils.java index 76c4ada..3b1e0dc 100644 --- a/src/main/java/squier/john/typeInformation/ReflectionUtils.java +++ b/src/main/java/squier/john/typeInformation/ReflectionUtils.java @@ -290,16 +290,15 @@ private String generateClassHierarchyString(List> classHierarchyInRever // @@@ refactor private Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { - Class theClass = o.getClass(); - Class theSuperClass = theClass.getSuperclass(); + Class theSuperClass = o.getClass().getSuperclass(); - if ( isConcrete(theSuperClass) ) { + if ( hasASuperClass(o.getClass()) && isConcrete(theSuperClass) ) { return theSuperClass.newInstance(); } else { while ( hasASuperClass(theSuperClass) ) { if ( isConcrete(theSuperClass) ) { - return theSuperClass; + return theSuperClass.newInstance(); } theSuperClass = theSuperClass.getSuperclass(); } @@ -340,7 +339,11 @@ private boolean OHasANoArgConstructor(Object o) { } private boolean isConcrete(Class c) { - return false; + boolean result = true; + if ( Modifier.isAbstract(c.getModifiers()) ) { + result = false; + } + return result; } private boolean isObjectClass(Object o) { diff --git a/src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java b/src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java new file mode 100644 index 0000000..ab5738b --- /dev/null +++ b/src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java @@ -0,0 +1,16 @@ +package squier.john.typeInformation; + +import org.junit.Before; + +/** + * Created by johnsquier on 2/16/17. + */ +public class ClassInHierarchyLacksNoArgConstructorTest { + + ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor; + + @Before + public void setup() { + classInHierarchyLacksNoArgConstructor = new ClassInHierarchyLacksNoArgConstructor(); + } +} diff --git a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java index 838bb19..5ba53b1 100644 --- a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java @@ -4,9 +4,13 @@ import org.junit.Before; import org.junit.Test; +import javax.swing.*; +import java.awt.*; import java.io.BufferedWriter; import java.io.FileWriter; +import java.nio.file.OpenOption; import java.util.*; +import java.util.List; /** * Created by johnsquier on 2/15/17. @@ -295,7 +299,6 @@ public void instantiateClassHierarchyString() { public void instantiateClassHierarchyArrayList() { List expected = new ArrayList<>(); expected.add(new ArrayList<>()); - // two abstract classes between ArrayList() and Object() expected.add(new Object()); List actual = null; @@ -314,6 +317,30 @@ public void instantiateClassHierarchyArrayList() { Assert.assertEquals(expected.get(1).getClass().getSimpleName(), actual.get(1).getClass().getSimpleName()); } + @Test + public void instantiateClassHierarchyJPanel() { + List expected = new ArrayList<>(); + expected.add(new JPanel()); + expected.add(new Container()); + expected.add(new Object()); + + List actual = null; + try { + actual = reflectionUtils.instantiateClassHierarchy(new JPanel()); + } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { + classInHierarchyLacksNoArgConstructor.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Assert.assertTrue(actual.size() == 3); + Assert.assertEquals(expected.get(0).getClass().getSimpleName(), actual.get(0).getClass().getSimpleName()); + Assert.assertEquals(expected.get(1).getClass().getSimpleName(), actual.get(1).getClass().getSimpleName()); + Assert.assertEquals(expected.get(2).getClass().getSimpleName(), actual.get(2).getClass().getSimpleName()); + } + @Test(expected = ClassInHierarchyLacksNoArgConstructor.class) public void instantiateClassHierarchyBoolean() throws IllegalAccessException, ClassInHierarchyLacksNoArgConstructor, InstantiationException { From ccb29e30c612d5fcd5eb3190bd137d2514355b16 Mon Sep 17 00:00:00 2001 From: John Squier Date: Fri, 17 Feb 2017 12:22:35 -0500 Subject: [PATCH 12/17] UnitCornTestRunner runTest(class, string) working with one test --- ...ClassInHierarchyLacksNoArgConstructor.java | 2 +- .../ReflectionUtils.java | 79 ++++++++++------- .../java/squier/john/unitcorn/Result.java | 21 +++++ .../java/squier/john/unitcorn/TestStatus.java | 6 ++ .../john/unitcorn/UnitCornTestRunner.java | 87 +++++++++++++++++++ ...sInHierarchyLacksNoArgConstructorTest.java | 2 +- .../ReflectionUtilsTest.java | 33 ++++--- .../java/squier/john/unitcorn/ResultTest.java | 31 +++++++ .../squier/john/unitcorn/TestStatusTest.java | 18 ++++ .../john/unitcorn/UnitCornTestRunnerTest.java | 28 ++++++ 10 files changed, 265 insertions(+), 42 deletions(-) rename src/main/java/squier/john/{typeInformation => unitcorn}/ClassInHierarchyLacksNoArgConstructor.java (76%) rename src/main/java/squier/john/{typeInformation => unitcorn}/ReflectionUtils.java (83%) create mode 100644 src/main/java/squier/john/unitcorn/Result.java create mode 100644 src/main/java/squier/john/unitcorn/TestStatus.java create mode 100644 src/main/java/squier/john/unitcorn/UnitCornTestRunner.java rename src/test/java/squier/john/{typeInformation => unitcorn}/ClassInHierarchyLacksNoArgConstructorTest.java (90%) rename src/test/java/squier/john/{typeInformation => unitcorn}/ReflectionUtilsTest.java (91%) create mode 100644 src/test/java/squier/john/unitcorn/ResultTest.java create mode 100644 src/test/java/squier/john/unitcorn/TestStatusTest.java create mode 100644 src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java diff --git a/src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java similarity index 76% rename from src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java rename to src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java index d7e3065..5d8c7ea 100644 --- a/src/main/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructor.java +++ b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java @@ -1,4 +1,4 @@ -package squier.john.typeInformation; +package squier.john.unitcorn; /** * Created by johnsquier on 2/16/17. diff --git a/src/main/java/squier/john/typeInformation/ReflectionUtils.java b/src/main/java/squier/john/unitcorn/ReflectionUtils.java similarity index 83% rename from src/main/java/squier/john/typeInformation/ReflectionUtils.java rename to src/main/java/squier/john/unitcorn/ReflectionUtils.java index 3b1e0dc..c94976b 100644 --- a/src/main/java/squier/john/typeInformation/ReflectionUtils.java +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -1,4 +1,4 @@ -package squier.john.typeInformation; +package squier.john.unitcorn; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -9,6 +9,7 @@ /** * Created by John A. Squier on 2/15/17. * @@@ multiple refactor spots in src + * should I make everything in here static? */ public class ReflectionUtils { @@ -72,6 +73,7 @@ public List instantiateClassHierarchy(Object o) } else { throw new ClassInHierarchyLacksNoArgConstructor(); } + if ( !isObjectClass(o) ) { o = getNextConcreteClass(o); } @@ -82,13 +84,13 @@ public List instantiateClassHierarchy(Object o) return theHierarchy; } - // @@@ refactor + // @@@ refactor? private Class getClassName(String aClassName) { - Class theInterfaceClass; - if ( aClassName == null ) { return null; } + + Class theInterfaceClass; try { theInterfaceClass = Class.forName(aClassName); } catch (ClassNotFoundException e) { @@ -129,10 +131,7 @@ private String fieldsInfoString(Class theClass) { fields = sortMemberArray(fields); for (Field f : fields) { - sb.append(classNameHeader(theClass)); - sb.append(modifiers(f)); - sb.append(fieldType(f)); - sb.append(fieldName(f)); + sb.append(generateFieldInfo(f, theClass)); } return sb.toString(); } @@ -146,16 +145,11 @@ private String constructorInfoString(Class theClass) { // sort constructors by name? for (Constructor c : constructors) { - sb.append(classNameHeader(theClass)); - sb.append(modifiers(c)); - sb.append(constructorName(c)); - sb.append(params(c)); - sb.append("\n"); + sb.append(generateConstructorInfo(c, theClass)); } return sb.toString(); } - // @@@ refactor loop body into sb.append(methodInfoString(m)) private String methodsInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); @@ -166,17 +160,42 @@ private String methodsInfoString(Class theClass) { for (Method m : methods) { if ( methodIsDeclaredInThisClass(m, theClass) ) { - sb.append(classNameHeader(theClass)); - sb.append(modifiers(m)); - sb.append(methodReturnType(m)); - sb.append(methodName(m)); - sb.append(params(m)); - sb.append("\n"); + sb.append(generateMethodInfo(m, theClass)); } } return sb.toString(); } + private String generateFieldInfo(Field f, Class theClass) { + StringBuilder sb = new StringBuilder(); + sb.append(classNameHeader(theClass)); + sb.append(modifiers(f)); + sb.append(fieldType(f)); + sb.append(fieldName(f)); + return sb.toString(); + } + + private String generateConstructorInfo(Constructor c, Class theClass) { + StringBuilder sb = new StringBuilder(); + sb.append(classNameHeader(theClass)); + sb.append(modifiers(c)); + sb.append(constructorName(c)); + sb.append(params(c)); + sb.append("\n"); + return sb.toString(); + } + + private String generateMethodInfo(Method m, Class theClass) { + StringBuilder sb = new StringBuilder(); + sb.append(classNameHeader(theClass)); + sb.append(modifiers(m)); + sb.append(methodReturnType(m)); + sb.append(methodName(m)); + sb.append(params(m)); + sb.append("\n"); + return sb.toString(); + } + private String paramsInfoString(Class[] params) { StringBuilder sb = new StringBuilder(); @@ -290,25 +309,25 @@ private String generateClassHierarchyString(List> classHierarchyInRever // @@@ refactor private Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { - Class theSuperClass = o.getClass().getSuperclass(); + Class superClass = o.getClass().getSuperclass(); - if ( hasASuperClass(o.getClass()) && isConcrete(theSuperClass) ) { - return theSuperClass.newInstance(); + if ( hasASuperClass(o.getClass()) && isConcrete(superClass) ) { + return superClass.newInstance(); } else { - while ( hasASuperClass(theSuperClass) ) { - if ( isConcrete(theSuperClass) ) { - return theSuperClass.newInstance(); + while ( hasASuperClass(superClass) ) { + if ( isConcrete(superClass) ) { + return superClass.newInstance(); } - theSuperClass = theSuperClass.getSuperclass(); + superClass = superClass.getSuperclass(); } } - return theSuperClass.newInstance(); + return superClass.newInstance(); } private Object instantiate(Object o) throws IllegalAccessException, InstantiationException { - Class theClass = o.getClass(); - return theClass.newInstance(); + Class c = o.getClass(); + return c.newInstance(); } private boolean hasASuperClass(Class c) { diff --git a/src/main/java/squier/john/unitcorn/Result.java b/src/main/java/squier/john/unitcorn/Result.java new file mode 100644 index 0000000..ae37cb6 --- /dev/null +++ b/src/main/java/squier/john/unitcorn/Result.java @@ -0,0 +1,21 @@ +package squier.john.unitcorn; + +/** + * Created by johnsquier on 2/16/17. + */ +public class Result { + + private TestStatus status; + + public Result(TestStatus status) { + this.status = status; + } + + public TestStatus getStatus() { + return status; + } + + public boolean equals(Result other) { + return status.equals(other.status); + } +} diff --git a/src/main/java/squier/john/unitcorn/TestStatus.java b/src/main/java/squier/john/unitcorn/TestStatus.java new file mode 100644 index 0000000..4dc3d8c --- /dev/null +++ b/src/main/java/squier/john/unitcorn/TestStatus.java @@ -0,0 +1,6 @@ +package squier.john.unitcorn; + +/** + * Created by johnsquier on 2/16/17. + */ +public enum TestStatus { SUCCESS, FAILURE, NON_EXISTENT_METHOD, CLASS_INSTANTIATION_FAILURE } diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java new file mode 100644 index 0000000..94b03cd --- /dev/null +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -0,0 +1,87 @@ +package squier.john.unitcorn; + +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.InitializationError; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Created by johnsquier on 2/16/17. + */ +public class UnitCornTestRunner { + + public UnitCornTestRunner() { } + + // takes a class object, finds all methods declared in the class with the org.junit.Test anno. + // passes those names to runTest(class, string) and handles the results + // pretty prints results + public String runTests(Class c) { + return null; + } + + // runs a testMethod in a class and returns a result; + public Result runTest(Class c, String methodName) { + Result result; + if ( classHasMethod(c, methodName) ) { + result = runMethod(c, methodName); + } + else { + result = new Result(TestStatus.NON_EXISTENT_METHOD); + } + return result; + } + + private boolean classHasMethod(Class c, String methodName) { + boolean classHasMethod = true; + if ( methodName == null ) { + classHasMethod = false; + } + else { + try { + c.getMethod(methodName); + } catch (NoSuchMethodException e) { + classHasMethod = false; + } + } + return classHasMethod; + } + + // gotta catch errors thrown by Junit test methods + private Result runMethod(Class c, String methodName) { + Method method = null; + try { + method = c.getMethod(methodName); + } catch (NoSuchMethodException e) { + e.printStackTrace(); // should never happen + } + + Result result = null; + + Object ofClassC = null; + try { + ofClassC = instantiateObjectFromClass(c); + } catch (IllegalAccessException | InstantiationException e) { + result = new Result(TestStatus.CLASS_INSTANTIATION_FAILURE); + } + + if ( method != null && ofClassC != null ) { + try { + method.invoke(ofClassC); + result = new Result(TestStatus.SUCCESS); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + // Test Failure + // Look at e for useful information including Assert messages + // System.out.println(e.getCause()); + } + } + return result; + } + + private Object instantiateObjectFromClass(Class c) throws IllegalAccessException, InstantiationException { + Object o = c.newInstance(); + return o; + } +} diff --git a/src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java b/src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java similarity index 90% rename from src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java rename to src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java index ab5738b..32ac9f8 100644 --- a/src/test/java/squier/john/typeInformation/ClassInHierarchyLacksNoArgConstructorTest.java +++ b/src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java @@ -1,4 +1,4 @@ -package squier.john.typeInformation; +package squier.john.unitcorn; import org.junit.Before; diff --git a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java similarity index 91% rename from src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java rename to src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java index 5ba53b1..a8bb19e 100644 --- a/src/test/java/squier/john/typeInformation/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java @@ -1,14 +1,12 @@ -package squier.john.typeInformation; +package squier.john.unitcorn; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import javax.swing.*; import java.awt.*; import java.io.BufferedWriter; import java.io.FileWriter; -import java.nio.file.OpenOption; import java.util.*; import java.util.List; @@ -17,15 +15,9 @@ */ public class ReflectionUtilsTest { - ReflectionUtils reflectionUtils; - - @Before - public void setup() { - reflectionUtils = new ReflectionUtils(); - } - @Test public void objectDoesImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; boolean actual = reflectionUtils.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); @@ -35,6 +27,7 @@ public void objectDoesImplementInterfaceTest() { @Test public void objectDoesNotImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); @@ -44,6 +37,7 @@ public void objectDoesNotImplementInterfaceTest() { @Test public void classObjectDoesImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; boolean actual = reflectionUtils.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); @@ -53,6 +47,7 @@ public void classObjectDoesImplementInterfaceTest() { @Test public void classObjectDoesNotImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); @@ -62,6 +57,7 @@ public void classObjectDoesNotImplementInterfaceTest() { @Test public void classNameDoesImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; boolean actual = reflectionUtils.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); @@ -71,6 +67,7 @@ public void classNameDoesImplementInterfaceTest() { @Test public void classNameDoesNotImplementInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); @@ -80,6 +77,7 @@ public void classNameDoesNotImplementInterfaceTest() { @Test public void tryToCompareObjectToNonExistentInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); @@ -89,6 +87,7 @@ public void tryToCompareObjectToNonExistentInterfaceTest() { @Test public void tryToCompareClassObjectToNonExistentInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), "abra.kadabra.Allakhazham"); @@ -98,6 +97,7 @@ public void tryToCompareClassObjectToNonExistentInterfaceTest() { @Test public void tryToCompareClassNameToNonExistentInterfaceTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "abra.kadabra.Allakhazham"); @@ -107,6 +107,7 @@ public void tryToCompareClassNameToNonExistentInterfaceTest() { @Test public void tryToCompareObjectToNullInterface() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object(), null); @@ -116,6 +117,7 @@ public void tryToCompareObjectToNullInterface() { @Test public void tryToCompareClassObjectToNullInterface() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), null); @@ -125,6 +127,7 @@ public void tryToCompareClassObjectToNullInterface() { @Test public void tryToCompareClassNameToNullInterface() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", null); @@ -134,6 +137,7 @@ public void tryToCompareClassNameToNullInterface() { @Test public void stringIsNotAClassNameButAStringLiteralTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; boolean actual = reflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); @@ -143,6 +147,7 @@ public void stringIsNotAClassNameButAStringLiteralTest() { @Test public void listAllMembersBufferedWriterTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "Fields\n" + "Constructors\n" + "BufferedWriter : public java.io.BufferedWriter(java.io.Writer)\n" + @@ -194,6 +199,7 @@ public void listAllMembersBufferedWriterTest() { @Test public void listAllMembersBooleanTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "Fields\n" + "Boolean : public static final Boolean FALSE\n" + "Boolean : public static final Boolean TRUE\n" + @@ -239,6 +245,7 @@ public void listAllMembersBooleanTest() { @Test public void getClassHierarchyBooleanTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "java.lang.Object\n java.lang.Boolean\n"; String actual = reflectionUtils.getClassHierarchy(new Boolean(true)); @@ -247,6 +254,7 @@ public void getClassHierarchyBooleanTest() { @Test public void getClassHierarchyTreeMapTest() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "java.lang.Object\n java.util.AbstractMap\n java.util.TreeMap\n"; String actual = reflectionUtils.getClassHierarchy(new TreeMap()); @@ -255,6 +263,7 @@ public void getClassHierarchyTreeMapTest() { @Test public void instantiateClassHierarchyObject() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new Object()); @@ -275,6 +284,7 @@ public void instantiateClassHierarchyObject() { @Test public void instantiateClassHierarchyString() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new String()); expected.add(new Object()); @@ -297,6 +307,7 @@ public void instantiateClassHierarchyString() { @Test public void instantiateClassHierarchyArrayList() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new ArrayList<>()); expected.add(new Object()); @@ -319,6 +330,7 @@ public void instantiateClassHierarchyArrayList() { @Test public void instantiateClassHierarchyJPanel() { + ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new JPanel()); expected.add(new Container()); @@ -344,6 +356,7 @@ public void instantiateClassHierarchyJPanel() { @Test(expected = ClassInHierarchyLacksNoArgConstructor.class) public void instantiateClassHierarchyBoolean() throws IllegalAccessException, ClassInHierarchyLacksNoArgConstructor, InstantiationException { + ReflectionUtils reflectionUtils = new ReflectionUtils(); reflectionUtils.instantiateClassHierarchy(new Boolean(true)); } diff --git a/src/test/java/squier/john/unitcorn/ResultTest.java b/src/test/java/squier/john/unitcorn/ResultTest.java new file mode 100644 index 0000000..a78c932 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/ResultTest.java @@ -0,0 +1,31 @@ +package squier.john.unitcorn; + +import org.junit.Before; +import org.junit.Test; + +/** + * Created by johnsquier on 2/17/17. + */ +public class ResultTest { + + Result success1, success2, failure; + + @Before + public void setup() { + success1 = new Result(TestStatus.SUCCESS); + success2 = new Result(TestStatus.SUCCESS); + failure = new Result(TestStatus.FAILURE); + } + + @Test + public void resultsEqualTest() { + boolean expected = true; + boolean actual = success1.equals(success2); + } + + @Test + public void resultsNoTEqualTest() { + boolean expected = true; + boolean actual = success1.equals(failure); + } +} diff --git a/src/test/java/squier/john/unitcorn/TestStatusTest.java b/src/test/java/squier/john/unitcorn/TestStatusTest.java new file mode 100644 index 0000000..8367956 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/TestStatusTest.java @@ -0,0 +1,18 @@ +package squier.john.unitcorn; + +import org.junit.Before; + +/** + * Created by johnsquier on 2/17/17. + */ +public class TestStatusTest { + + TestStatus success, failure, nonexistant; + + @Before + public void setup() { + success = TestStatus.SUCCESS; + failure = TestStatus.FAILURE; + nonexistant = TestStatus.NON_EXISTENT_METHOD; + } +} diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java new file mode 100644 index 0000000..51e7a87 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -0,0 +1,28 @@ +package squier.john.unitcorn; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runners.model.InitializationError; + +/** + * Created by johnsquier on 2/16/17. + */ +public class UnitCornTestRunnerTest { + + UnitCornTestRunner unitCornTestRunner; + + @Before + public void setup() throws InitializationError { + unitCornTestRunner = new UnitCornTestRunner(); + } + + @Test + public void runTestMethodFromClassReflectionUtilsTest() { + Result expected = new Result(TestStatus.SUCCESS); + + Result actual = unitCornTestRunner.runTest(ReflectionUtilsTest.class, "objectDoesImplementInterfaceTest"); + + Assert.assertTrue(expected.equals(actual)); + } +} From 39f8ed4f70133171891af79ece5d6eff5070a50d Mon Sep 17 00:00:00 2001 From: John Squier Date: Fri, 17 Feb 2017 13:13:00 -0500 Subject: [PATCH 13/17] refactor in UnitCornTestRunner and add fields to Result, DummyTests created --- .../java/squier/john/unitcorn/Result.java | 13 ++++- .../john/unitcorn/UnitCornTestRunner.java | 47 +++++-------------- .../java/squier/john/unitcorn/DummyTests.java | 21 +++++++++ .../java/squier/john/unitcorn/ResultTest.java | 6 +-- .../john/unitcorn/UnitCornTestRunnerTest.java | 39 ++++++++++++++- 5 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 src/test/java/squier/john/unitcorn/DummyTests.java diff --git a/src/main/java/squier/john/unitcorn/Result.java b/src/main/java/squier/john/unitcorn/Result.java index ae37cb6..7116faa 100644 --- a/src/main/java/squier/john/unitcorn/Result.java +++ b/src/main/java/squier/john/unitcorn/Result.java @@ -5,17 +5,26 @@ */ public class Result { + private String methodRun; private TestStatus status; + private Throwable thrownDuringInvoke = null; - public Result(TestStatus status) { + public Result(String methodRun, TestStatus status) { + this.methodRun = methodRun; this.status = status; } + public Result(String methodRun, TestStatus status, Throwable thrownDuringInvoke) { + this.methodRun = methodRun; + this.status = status; + this.thrownDuringInvoke = thrownDuringInvoke; + } + public TestStatus getStatus() { return status; } public boolean equals(Result other) { - return status.equals(other.status); + return status.equals(other.status) && methodRun.equalsIgnoreCase(other.methodRun); } } diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java index 94b03cd..7567cb3 100644 --- a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -1,8 +1,5 @@ package squier.john.unitcorn; -import org.junit.runners.BlockJUnit4ClassRunner; -import org.junit.runners.model.InitializationError; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -17,19 +14,12 @@ public UnitCornTestRunner() { } // passes those names to runTest(class, string) and handles the results // pretty prints results public String runTests(Class c) { + // build up a list of test results return null; } - // runs a testMethod in a class and returns a result; public Result runTest(Class c, String methodName) { - Result result; - if ( classHasMethod(c, methodName) ) { - result = runMethod(c, methodName); - } - else { - result = new Result(TestStatus.NON_EXISTENT_METHOD); - } - return result; + return runMethod(c, methodName); } private boolean classHasMethod(Class c, String methodName) { @@ -47,36 +37,23 @@ private boolean classHasMethod(Class c, String methodName) { return classHasMethod; } - // gotta catch errors thrown by Junit test methods private Result runMethod(Class c, String methodName) { - Method method = null; - try { - method = c.getMethod(methodName); - } catch (NoSuchMethodException e) { - e.printStackTrace(); // should never happen - } - - Result result = null; - - Object ofClassC = null; - try { - ofClassC = instantiateObjectFromClass(c); - } catch (IllegalAccessException | InstantiationException e) { - result = new Result(TestStatus.CLASS_INSTANTIATION_FAILURE); - } - - if ( method != null && ofClassC != null ) { + Result result; try { - method.invoke(ofClassC); - result = new Result(TestStatus.SUCCESS); - } catch (IllegalAccessException e) { - e.printStackTrace(); + Method method = c.getMethod(methodName); + Object object = instantiateObjectFromClass(c); + Object theResult = method.invoke(object); + result = new Result(methodName, TestStatus.SUCCESS); + } catch (NoSuchMethodException e) { + result = new Result(methodName, TestStatus.NON_EXISTENT_METHOD); + } catch (IllegalAccessException | InstantiationException e) { + result = new Result(methodName, TestStatus.CLASS_INSTANTIATION_FAILURE); } catch (InvocationTargetException e) { // Test Failure // Look at e for useful information including Assert messages // System.out.println(e.getCause()); + result = new Result(methodName, TestStatus.FAILURE, e); } - } return result; } diff --git a/src/test/java/squier/john/unitcorn/DummyTests.java b/src/test/java/squier/john/unitcorn/DummyTests.java new file mode 100644 index 0000000..8134d5a --- /dev/null +++ b/src/test/java/squier/john/unitcorn/DummyTests.java @@ -0,0 +1,21 @@ +package squier.john.unitcorn; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by johnsquier on 2/17/17. + */ +public class DummyTests { + + @Test + public void testThatPasses() { + Assert.assertTrue(true); + } + + @Test + public void testThatFails() { + Assert.assertTrue("This test is designed to fail as part of the UnitCornTestRunnerTest class", + false); + } +} diff --git a/src/test/java/squier/john/unitcorn/ResultTest.java b/src/test/java/squier/john/unitcorn/ResultTest.java index a78c932..9ecfc25 100644 --- a/src/test/java/squier/john/unitcorn/ResultTest.java +++ b/src/test/java/squier/john/unitcorn/ResultTest.java @@ -12,9 +12,9 @@ public class ResultTest { @Before public void setup() { - success1 = new Result(TestStatus.SUCCESS); - success2 = new Result(TestStatus.SUCCESS); - failure = new Result(TestStatus.FAILURE); + success1 = new Result("", TestStatus.SUCCESS); + success2 = new Result("", TestStatus.SUCCESS); + failure = new Result("", TestStatus.FAILURE); } @Test diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java index 51e7a87..0ff95dd 100644 --- a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -1,8 +1,10 @@ package squier.john.unitcorn; +import com.sun.org.apache.xpath.internal.operations.Bool; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; /** @@ -19,10 +21,43 @@ public void setup() throws InitializationError { @Test public void runTestMethodFromClassReflectionUtilsTest() { - Result expected = new Result(TestStatus.SUCCESS); - + Result expected = new Result("objectDoesImplementInterfaceTest", TestStatus.SUCCESS); Result actual = unitCornTestRunner.runTest(ReflectionUtilsTest.class, "objectDoesImplementInterfaceTest"); Assert.assertTrue(expected.equals(actual)); } + + @Test + public void runSuccessfulTestFromDummyTests() { + Result expected = new Result("testThatPasses", TestStatus.SUCCESS); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatPasses"); + + Assert.assertTrue(expected.equals(actual)); + } + + @Test + public void runFailureTestFromDummyTests() { + Result expected = new Result("testThatFails", TestStatus.FAILURE); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatFails"); + + Assert.assertTrue(expected.equals(actual)); + } + + @Test + public void runTestThatDoesntExist() { + Result expected = new Result("testThatDoesntExist",TestStatus.NON_EXISTENT_METHOD); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatDoesntExist"); + + Assert.assertTrue(expected.equals(actual)); + } + + @Test + public void runTestOnClassWithoutNoArgConstructor() { + class PrivateConstructor{ private PrivateConstructor(){} public void aMethod(){} } + + Result expected = new Result("aMethod", TestStatus.CLASS_INSTANTIATION_FAILURE); + Result actual = unitCornTestRunner.runTest(PrivateConstructor.class, "aMethod"); + + Assert.assertTrue(expected.equals(actual)); + } } From 84490d978479b4ee50bd0543d64cf105a619e0e1 Mon Sep 17 00:00:00 2001 From: John Squier Date: Fri, 17 Feb 2017 19:15:09 -0500 Subject: [PATCH 14/17] runTests(class) method in UnitCornTestRunner implemented and tested --- .../squier/john/unitcorn/ReflectionUtils.java | 75 ++++------ .../java/squier/john/unitcorn/Result.java | 27 ++-- .../john/unitcorn/UnitCornTestRunner.java | 134 +++++++++++++----- .../java/squier/john/unitcorn/DummyTests.java | 1 + .../john/unitcorn/ReflectionUtilsTest.java | 8 +- .../john/unitcorn/UnitCornTestRunnerTest.java | 101 ++++++++++++- 6 files changed, 242 insertions(+), 104 deletions(-) diff --git a/src/main/java/squier/john/unitcorn/ReflectionUtils.java b/src/main/java/squier/john/unitcorn/ReflectionUtils.java index c94976b..f1eb777 100644 --- a/src/main/java/squier/john/unitcorn/ReflectionUtils.java +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -9,27 +9,19 @@ /** * Created by John A. Squier on 2/15/17. * @@@ multiple refactor spots in src - * should I make everything in here static? */ public class ReflectionUtils { public boolean classImplementsInterface(String aClassName, String anInterfaceName) { - Class theClass = getClassName(aClassName); - - if ( theClass == null ) { // more readable than try-catch? - return classImplementsInterface((Object) aClassName, anInterfaceName); - } else { - return classImplementsInterface(theClass, anInterfaceName); - } + Class classClass = getClassClassFromString(aClassName); + Class interfaceClassClass = getClassClassFromString(anInterfaceName); + // will short-circuit if interfaceClassClass == null + return interfaceClassClass != null && ((classClass == null) ? checkClassForInterface(aClassName.getClass(), interfaceClassClass) : + checkClassForInterface(classClass, interfaceClassClass)); } public boolean classImplementsInterface(Class theClass, String anInterface) { - Class theInterfaceClass = getClassName(anInterface); - - if ( theInterfaceClass == null ) { // same here? - return false; - } - return checkClassForInterface(theClass, theInterfaceClass); + return classImplementsInterface(theClass.getName(), anInterface); } public boolean classImplementsInterface(Object o, String theInterface) { @@ -37,24 +29,22 @@ public boolean classImplementsInterface(Object o, String theInterface) { } public String listAllMembers(Object o) { + Class c = o.getClass(); StringBuilder sb = new StringBuilder(); + sb.append(classInfoString(c)); - Class theClass = o.getClass(); - sb.append(classInfoString(theClass)); - - while ( hasASuperClass(theClass) ) { - theClass = theClass.getSuperclass(); - sb.append(classInfoString(theClass)); + while ( hasASuperClass(c) ) { + c = c.getSuperclass(); + sb.append(classInfoString(c)); } return sb.toString(); } public String getClassHierarchy(Object o) { + Class theClass = o.getClass(); List> classHierarchyInReverse = new ArrayList<>(); - Class theClass = o.getClass(); classHierarchyInReverse.add(theClass); - while ( hasASuperClass(theClass) ) { theClass = theClass.getSuperclass(); classHierarchyInReverse.add(theClass); @@ -84,52 +74,42 @@ public List instantiateClassHierarchy(Object o) return theHierarchy; } - // @@@ refactor? - private Class getClassName(String aClassName) { + private Class getClassClassFromString(String aClassName) { if ( aClassName == null ) { return null; } - - Class theInterfaceClass; try { - theInterfaceClass = Class.forName(aClassName); - } catch (ClassNotFoundException e) { - System.err.println("Class: " + aClassName + " not found"); + return Class.forName(aClassName); + } catch ( ClassNotFoundException e ) { return null; } - return theInterfaceClass; } private boolean checkClassForInterface(Class theClass, Class theInterfaceClass) { Class[] implementedInterfaces = theClass.getInterfaces(); - - boolean result = false; for ( Class c : implementedInterfaces ) { if ( c.getName().equals(theInterfaceClass.getName()) ) { - result = true; + return true; } } - return result; + return false; } private String classInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); - sb.append(fieldsInfoString(theClass)); sb.append(constructorInfoString(theClass)); sb.append(methodsInfoString(theClass)); - return sb.toString(); } private String fieldsInfoString(Class theClass) { - StringBuilder sb = new StringBuilder(); - Field[] fields = theClass.getFields(); - sb.append("Fields\n"); - fields = sortMemberArray(fields); + StringBuilder sb = new StringBuilder(); + sb.append("Fields\n"); + for (Field f : fields) { sb.append(generateFieldInfo(f, theClass)); } @@ -137,13 +117,12 @@ private String fieldsInfoString(Class theClass) { } private String constructorInfoString(Class theClass) { - StringBuilder sb = new StringBuilder(); - Constructor[] constructors = theClass.getConstructors(); - sb.append("Constructors\n"); - // sort constructors by name? + StringBuilder sb = new StringBuilder(); + sb.append("Constructors\n"); + for (Constructor c : constructors) { sb.append(generateConstructorInfo(c, theClass)); } @@ -151,13 +130,12 @@ private String constructorInfoString(Class theClass) { } private String methodsInfoString(Class theClass) { - StringBuilder sb = new StringBuilder(); - Method[] methods = theClass.getMethods(); - sb.append("Methods\n"); - methods = sortMemberArray(methods); + StringBuilder sb = new StringBuilder(); + sb.append("Methods\n"); + for (Method m : methods) { if ( methodIsDeclaredInThisClass(m, theClass) ) { sb.append(generateMethodInfo(m, theClass)); @@ -198,7 +176,6 @@ private String generateMethodInfo(Method m, Class theClass) { private String paramsInfoString(Class[] params) { StringBuilder sb = new StringBuilder(); - if ( empty(params) ) { sb.append(")"); } else { diff --git a/src/main/java/squier/john/unitcorn/Result.java b/src/main/java/squier/john/unitcorn/Result.java index 7116faa..efdd241 100644 --- a/src/main/java/squier/john/unitcorn/Result.java +++ b/src/main/java/squier/john/unitcorn/Result.java @@ -5,26 +5,33 @@ */ public class Result { - private String methodRun; + private String nameOfMethodRun; private TestStatus status; - private Throwable thrownDuringInvoke = null; + private Throwable thrownDuringMethodInvoke; - public Result(String methodRun, TestStatus status) { - this.methodRun = methodRun; - this.status = status; + public Result(String nameOfMethodRun, TestStatus status) { + this(nameOfMethodRun, status, null); } - public Result(String methodRun, TestStatus status, Throwable thrownDuringInvoke) { - this.methodRun = methodRun; + public Result(String nameOfMethodRun, TestStatus status, Throwable thrownDuringMethodInvoke) { + this.nameOfMethodRun = nameOfMethodRun; this.status = status; - this.thrownDuringInvoke = thrownDuringInvoke; + this.thrownDuringMethodInvoke = thrownDuringMethodInvoke; + } + + public boolean equals(Result other) { + return status.equals(other.status) && nameOfMethodRun.equalsIgnoreCase(other.nameOfMethodRun); + } + + public String getNameOfMethodRun() { + return nameOfMethodRun; } public TestStatus getStatus() { return status; } - public boolean equals(Result other) { - return status.equals(other.status) && methodRun.equalsIgnoreCase(other.methodRun); + public Throwable getThrownDuringMethodInvoke() { + return thrownDuringMethodInvoke; } } diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java index 7567cb3..3fcbeed 100644 --- a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -1,7 +1,12 @@ package squier.john.unitcorn; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * Created by johnsquier on 2/16/17. @@ -10,55 +15,116 @@ public class UnitCornTestRunner { public UnitCornTestRunner() { } - // takes a class object, finds all methods declared in the class with the org.junit.Test anno. - // passes those names to runTest(class, string) and handles the results - // pretty prints results + // @@@ Need to sort methods to ensure invocation order public String runTests(Class c) { - // build up a list of test results - return null; + Method[] methodsWithTestAnnotation = getTestMethods(c); + List testResults = generateTestResults(c, methodsWithTestAnnotation); + return outputTestResultsToConsole(c, testResults); } public Result runTest(Class c, String methodName) { return runMethod(c, methodName); } - private boolean classHasMethod(Class c, String methodName) { - boolean classHasMethod = true; - if ( methodName == null ) { - classHasMethod = false; + // @@@ refactor, too long + private Method[] getTestMethods(Class c) { + Method[] allMethods = c.getMethods(); + List testMethods = new ArrayList<>(); + + for (Method m : allMethods) { + Annotation[] annos = m.getDeclaredAnnotations(); + for (Annotation a : annos) { + if ( isATestAnnotation(a) ) { + testMethods.add(m); + } + } + } + testMethods.sort(Comparator.comparing(Method::getName)); + return testMethods.toArray(new Method[0]); + } + + private List generateTestResults(Class c, Method[] methodsWithTestAnnotation) { + List results = new ArrayList<>(); + for (Method method : methodsWithTestAnnotation) { + Result result = runTest(c, method.getName()); + results.add(result); + } + return results; + } + + // @@@ Refactor + private String outputTestResultsToConsole(Class c, List testResults) { + StringBuilder sb = new StringBuilder(); + int testsPassed = numTestsPassed(testResults); + int testsFailed = numTestsFailed(testResults); + int testsBroken = numTestsBroken(testResults); + + sb.append("Class Tested : ").append(c.getSimpleName()).append("\n"); + for ( Result r : testResults ) { + sb.append("\t Method : ").append(r.getNameOfMethodRun()).append("()\n"); + sb.append("\t Result : ").append(r.getStatus()).append("\n\n"); } - else { - try { - c.getMethod(methodName); - } catch (NoSuchMethodException e) { - classHasMethod = false; + sb.append(testsPassed).append(" Test").append(sOrSpace(testsPassed)).append("Passed "); + sb.append(testsFailed).append(" Test").append(sOrSpace(testsFailed)).append("Failed "); + sb.append(testsBroken).append(" Test").append(sOrSpace(testsBroken)).append("Broken").append("\n"); + System.out.println(sb.toString()); + return sb.toString(); + } + + private String sOrSpace(int n) { + return n == 1 ? " " : "s "; + } + + private int numTestsPassed(List l) { + return countTestsWithStatus(l, TestStatus.SUCCESS); + } + + private int numTestsFailed(List l) { + return countTestsWithStatus(l, TestStatus.FAILURE); + } + + private int numTestsBroken(List l) { + return numTestsMethodError(l) + numTestsClassError(l); + } + + private int numTestsMethodError(List l) { + return countTestsWithStatus(l, TestStatus.NON_EXISTENT_METHOD); + } + + private int numTestsClassError(List l) { + return countTestsWithStatus(l, TestStatus.CLASS_INSTANTIATION_FAILURE); + } + + private int countTestsWithStatus(List l, TestStatus status) { + int count = 0; + for (Result r : l) { + if ( r.getStatus().equals(status) ) { + count++; } } - return classHasMethod; + return count; } private Result runMethod(Class c, String methodName) { - Result result; - try { - Method method = c.getMethod(methodName); - Object object = instantiateObjectFromClass(c); - Object theResult = method.invoke(object); - result = new Result(methodName, TestStatus.SUCCESS); - } catch (NoSuchMethodException e) { - result = new Result(methodName, TestStatus.NON_EXISTENT_METHOD); - } catch (IllegalAccessException | InstantiationException e) { - result = new Result(methodName, TestStatus.CLASS_INSTANTIATION_FAILURE); - } catch (InvocationTargetException e) { - // Test Failure - // Look at e for useful information including Assert messages - // System.out.println(e.getCause()); - result = new Result(methodName, TestStatus.FAILURE, e); - } - return result; + try { + Method method = c.getMethod(methodName); + Object object = instantiateObjectFromClass(c); + Object theResult = method.invoke(object); + return new Result(methodName, TestStatus.SUCCESS); + } catch (NoSuchMethodException e) { + return new Result(methodName, TestStatus.NON_EXISTENT_METHOD); + } catch (IllegalAccessException | InstantiationException e) { + return new Result(methodName, TestStatus.CLASS_INSTANTIATION_FAILURE); + } catch (InvocationTargetException e) { + return new Result(methodName, TestStatus.FAILURE, e); // look at e for useful info + } } private Object instantiateObjectFromClass(Class c) throws IllegalAccessException, InstantiationException { - Object o = c.newInstance(); - return o; + return c.newInstance(); + } + + private boolean isATestAnnotation(Annotation a) { + return a.annotationType().getSimpleName().equalsIgnoreCase("test"); } } diff --git a/src/test/java/squier/john/unitcorn/DummyTests.java b/src/test/java/squier/john/unitcorn/DummyTests.java index 8134d5a..6256ca7 100644 --- a/src/test/java/squier/john/unitcorn/DummyTests.java +++ b/src/test/java/squier/john/unitcorn/DummyTests.java @@ -15,6 +15,7 @@ public void testThatPasses() { @Test public void testThatFails() { + //@SuppressWarnings() Assert.assertTrue("This test is designed to fail as part of the UnitCornTestRunnerTest class", false); } diff --git a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java index a8bb19e..0721b3f 100644 --- a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java @@ -106,7 +106,7 @@ public void tryToCompareClassNameToNonExistentInterfaceTest() { } @Test - public void tryToCompareObjectToNullInterface() { + public void tryToCompareObjectToNullInterfaceTest() { ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object(), null); @@ -116,7 +116,7 @@ public void tryToCompareObjectToNullInterface() { } @Test - public void tryToCompareClassObjectToNullInterface() { + public void tryToCompareClassObjectToNullInterfaceTest() { ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), null); @@ -126,7 +126,7 @@ public void tryToCompareClassObjectToNullInterface() { } @Test - public void tryToCompareClassNameToNullInterface() { + public void tryToCompareClassNameToNullInterfaceTest() { ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", null); @@ -262,7 +262,7 @@ public void getClassHierarchyTreeMapTest() { } @Test - public void instantiateClassHierarchyObject() { + public void instantiateClassHierarchyObjectTest() { ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new Object()); diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java index 0ff95dd..53f7b63 100644 --- a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -1,11 +1,8 @@ package squier.john.unitcorn; -import com.sun.org.apache.xpath.internal.operations.Bool; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runners.ParentRunner; -import org.junit.runners.model.InitializationError; /** * Created by johnsquier on 2/16/17. @@ -15,7 +12,7 @@ public class UnitCornTestRunnerTest { UnitCornTestRunner unitCornTestRunner; @Before - public void setup() throws InitializationError { + public void setup() { unitCornTestRunner = new UnitCornTestRunner(); } @@ -44,9 +41,9 @@ public void runFailureTestFromDummyTests() { } @Test - public void runTestThatDoesntExist() { - Result expected = new Result("testThatDoesntExist",TestStatus.NON_EXISTENT_METHOD); - Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatDoesntExist"); + public void runTestThatDoesNotExist() { + Result expected = new Result("testThatDoesNotExist",TestStatus.NON_EXISTENT_METHOD); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatDoesNotExist"); Assert.assertTrue(expected.equals(actual)); } @@ -60,4 +57,94 @@ class PrivateConstructor{ private PrivateConstructor(){} public void aMethod(){} Assert.assertTrue(expected.equals(actual)); } + + @Test + public void runTestsInClassDummyTestsAndGenerateResults() { + String expected = "Class Tested : DummyTests\n" + + "\t Method : testThatFails()\n" + + "\t Result : FAILURE\n" + + "\n" + + "\t Method : testThatPasses()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "1 Test Passed 1 Test Failed 0 Tests Broken\n"; + String actual = unitCornTestRunner.runTests(DummyTests.class); + + Assert.assertEquals(expected, actual); + } + + @Test + public void runTestsInReflectionUtilsTestAndGenerateResults() { + String expected = "Class Tested : ReflectionUtilsTest\n" + + "\t Method : classNameDoesImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : classNameDoesNotImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : classObjectDoesImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : classObjectDoesNotImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : getClassHierarchyBooleanTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : getClassHierarchyTreeMapTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : instantiateClassHierarchyArrayList()\n" + + "\t Result : SUCCESS\n" + + "\n" + // myTestRunner makes this test fail since I don't check for exceptions + "\t Method : instantiateClassHierarchyBoolean()\n" + + "\t Result : FAILURE\n" + + "\n" + + "\t Method : instantiateClassHierarchyJPanel()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : instantiateClassHierarchyObjectTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : instantiateClassHierarchyString()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : listAllMembersBooleanTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : listAllMembersBufferedWriterTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : objectDoesImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : objectDoesNotImplementInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : stringIsNotAClassNameButAStringLiteralTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareClassNameToNonExistentInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareClassNameToNullInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareClassObjectToNonExistentInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareClassObjectToNullInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareObjectToNonExistentInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : tryToCompareObjectToNullInterfaceTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "21 Tests Passed 1 Test Failed 0 Tests Broken\n"; + String actual = unitCornTestRunner.runTests(ReflectionUtilsTest.class); + + Assert.assertEquals(expected, actual); + } } From 9cb9289a8306e259e66c2aa1f53f7250f91416c9 Mon Sep 17 00:00:00 2001 From: John Squier Date: Mon, 20 Feb 2017 08:52:24 -0500 Subject: [PATCH 15/17] made ReflectionUtils all static since the class is stateless and the methods are all utilities --- .../java/squier/john/unitcorn/DummyTests.java | 10 ++ .../squier/john/unitcorn/ReflectionUtils.java | 97 +++++++++---------- .../java/squier/john/unitcorn/TestStatus.java | 10 +- .../john/unitcorn/UnitCornTestRunner.java | 77 ++++++++++----- .../john/unitcorn/ReflectionUtilsTest.java | 92 ++++++------------ .../java/squier/john/unitcorn/ResultTest.java | 19 +++- .../john/unitcorn/UnitCornTestRunnerTest.java | 27 +++++- 7 files changed, 182 insertions(+), 150 deletions(-) rename src/{test => main}/java/squier/john/unitcorn/DummyTests.java (71%) diff --git a/src/test/java/squier/john/unitcorn/DummyTests.java b/src/main/java/squier/john/unitcorn/DummyTests.java similarity index 71% rename from src/test/java/squier/john/unitcorn/DummyTests.java rename to src/main/java/squier/john/unitcorn/DummyTests.java index 6256ca7..0081734 100644 --- a/src/test/java/squier/john/unitcorn/DummyTests.java +++ b/src/main/java/squier/john/unitcorn/DummyTests.java @@ -19,4 +19,14 @@ public void testThatFails() { Assert.assertTrue("This test is designed to fail as part of the UnitCornTestRunnerTest class", false); } + + @Test + public void testThatIsBroken() { + int[] a = new int[1]; + int x = a[10]; // out of bounds + } + + public void methodThatIsntTaggedWithTest() { + + } } diff --git a/src/main/java/squier/john/unitcorn/ReflectionUtils.java b/src/main/java/squier/john/unitcorn/ReflectionUtils.java index f1eb777..763b4ae 100644 --- a/src/main/java/squier/john/unitcorn/ReflectionUtils.java +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -9,10 +9,11 @@ /** * Created by John A. Squier on 2/15/17. * @@@ multiple refactor spots in src + * @@@ Class is stateless? gonna go static since these are all utility methods */ public class ReflectionUtils { - public boolean classImplementsInterface(String aClassName, String anInterfaceName) { + public static boolean classImplementsInterface(String aClassName, String anInterfaceName) { Class classClass = getClassClassFromString(aClassName); Class interfaceClassClass = getClassClassFromString(anInterfaceName); // will short-circuit if interfaceClassClass == null @@ -20,15 +21,15 @@ public boolean classImplementsInterface(String aClassName, String anInterfaceNam checkClassForInterface(classClass, interfaceClassClass)); } - public boolean classImplementsInterface(Class theClass, String anInterface) { + public static boolean classImplementsInterface(Class theClass, String anInterface) { return classImplementsInterface(theClass.getName(), anInterface); } - public boolean classImplementsInterface(Object o, String theInterface) { + public static boolean classImplementsInterface(Object o, String theInterface) { return classImplementsInterface(o.getClass(), theInterface); } - public String listAllMembers(Object o) { + public static String listAllMembers(Object o) { Class c = o.getClass(); StringBuilder sb = new StringBuilder(); sb.append(classInfoString(c)); @@ -40,7 +41,7 @@ public String listAllMembers(Object o) { return sb.toString(); } - public String getClassHierarchy(Object o) { + public static String getClassHierarchy(Object o) { Class theClass = o.getClass(); List> classHierarchyInReverse = new ArrayList<>(); @@ -53,7 +54,7 @@ public String getClassHierarchy(Object o) { } // @@@ refactor - public List instantiateClassHierarchy(Object o) + public static List instantiateClassHierarchy(Object o) throws ClassInHierarchyLacksNoArgConstructor, InstantiationException, IllegalAccessException { List theHierarchy = new ArrayList<>(); @@ -74,7 +75,7 @@ public List instantiateClassHierarchy(Object o) return theHierarchy; } - private Class getClassClassFromString(String aClassName) { + private static Class getClassClassFromString(String aClassName) { if ( aClassName == null ) { return null; } @@ -85,7 +86,7 @@ private Class getClassClassFromString(String aClassName) { } } - private boolean checkClassForInterface(Class theClass, Class theInterfaceClass) { + private static boolean checkClassForInterface(Class theClass, Class theInterfaceClass) { Class[] implementedInterfaces = theClass.getInterfaces(); for ( Class c : implementedInterfaces ) { if ( c.getName().equals(theInterfaceClass.getName()) ) { @@ -95,7 +96,7 @@ private boolean checkClassForInterface(Class theClass, Class theInterfaceC return false; } - private String classInfoString(Class theClass) { + private static String classInfoString(Class theClass) { StringBuilder sb = new StringBuilder(); sb.append(fieldsInfoString(theClass)); sb.append(constructorInfoString(theClass)); @@ -103,7 +104,7 @@ private String classInfoString(Class theClass) { return sb.toString(); } - private String fieldsInfoString(Class theClass) { + private static String fieldsInfoString(Class theClass) { Field[] fields = theClass.getFields(); fields = sortMemberArray(fields); @@ -116,7 +117,7 @@ private String fieldsInfoString(Class theClass) { return sb.toString(); } - private String constructorInfoString(Class theClass) { + private static String constructorInfoString(Class theClass) { Constructor[] constructors = theClass.getConstructors(); // sort constructors by name? @@ -129,7 +130,7 @@ private String constructorInfoString(Class theClass) { return sb.toString(); } - private String methodsInfoString(Class theClass) { + private static String methodsInfoString(Class theClass) { Method[] methods = theClass.getMethods(); methods = sortMemberArray(methods); @@ -144,7 +145,7 @@ private String methodsInfoString(Class theClass) { return sb.toString(); } - private String generateFieldInfo(Field f, Class theClass) { + private static String generateFieldInfo(Field f, Class theClass) { StringBuilder sb = new StringBuilder(); sb.append(classNameHeader(theClass)); sb.append(modifiers(f)); @@ -153,7 +154,7 @@ private String generateFieldInfo(Field f, Class theClass) { return sb.toString(); } - private String generateConstructorInfo(Constructor c, Class theClass) { + private static String generateConstructorInfo(Constructor c, Class theClass) { StringBuilder sb = new StringBuilder(); sb.append(classNameHeader(theClass)); sb.append(modifiers(c)); @@ -163,7 +164,7 @@ private String generateConstructorInfo(Constructor c, Class theClass) { return sb.toString(); } - private String generateMethodInfo(Method m, Class theClass) { + private static String generateMethodInfo(Method m, Class theClass) { StringBuilder sb = new StringBuilder(); sb.append(classNameHeader(theClass)); sb.append(modifiers(m)); @@ -174,7 +175,7 @@ private String generateMethodInfo(Method m, Class theClass) { return sb.toString(); } - private String paramsInfoString(Class[] params) { + private static String paramsInfoString(Class[] params) { StringBuilder sb = new StringBuilder(); if ( empty(params) ) { sb.append(")"); @@ -184,51 +185,51 @@ private String paramsInfoString(Class[] params) { return sb.toString(); } - private String classNameHeader(Class theClass) { + private static String classNameHeader(Class theClass) { return theClass.getSimpleName() + " : "; } - private String modifiers(Field f) { + private static String modifiers(Field f) { return Modifier.toString(f.getModifiers()) + " "; } - private String modifiers(Constructor c) { + private static String modifiers(Constructor c) { return Modifier.toString(c.getModifiers()) + " "; } - private String modifiers(Method m) { + private static String modifiers(Method m) { return Modifier.toString((m.getModifiers())) + " "; } - private String fieldType(Field f) { + private static String fieldType(Field f) { return f.getType().getSimpleName() + " "; } - private String methodReturnType(Method m) { + private static String methodReturnType(Method m) { return m.getReturnType() + " "; } - private String fieldName(Field f) { + private static String fieldName(Field f) { return f.getName() + "\n"; } - private String constructorName(Constructor c) { + private static String constructorName(Constructor c) { return c.getName() + "("; } - private String methodName(Method m) { + private static String methodName(Method m) { return m.getName() + "("; } - private String params(Constructor c) { + private static String params(Constructor c) { return paramsInfoString(c.getParameterTypes()); } - private String params(Method m) { + private static String params(Method m) { return paramsInfoString(m.getParameterTypes()); } - private String allParams(Class[] params) { + private static String allParams(Class[] params) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.length; i++) { @@ -238,7 +239,7 @@ private String allParams(Class[] params) { return sb.toString(); } - private String paramDelimiter(int i, Class[] a) { + private static String paramDelimiter(int i, Class[] a) { String result; if (iIsTheLastParam(i, a.length)) { result = ")"; @@ -248,28 +249,18 @@ private String paramDelimiter(int i, Class[] a) { return result; } - private Field[] sortMemberArray(Field[] f) { - Arrays.sort(f, new Comparator() { - @Override - public int compare(Field o1, Field o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + private static Field[] sortMemberArray(Field[] f) { + Arrays.sort(f, Comparator.comparing(Field::getName)); return f; } - private Method[] sortMemberArray(Method[] m) { - Arrays.sort(m, new Comparator() { - @Override - public int compare(Method o1, Method o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + private static Method[] sortMemberArray(Method[] m) { + Arrays.sort(m, Comparator.comparing(Method::getName)); return m; } // @@@ Refactor - private String generateClassHierarchyString(List> classHierarchyInReverse) { + private static String generateClassHierarchyString(List> classHierarchyInReverse) { StringBuilder sb = new StringBuilder(); int numSpaces = 0; @@ -285,7 +276,7 @@ private String generateClassHierarchyString(List> classHierarchyInRever } // @@@ refactor - private Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { + private static Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { Class superClass = o.getClass().getSuperclass(); if ( hasASuperClass(o.getClass()) && isConcrete(superClass) ) { @@ -302,28 +293,28 @@ private Object getNextConcreteClass(Object o) throws IllegalAccessException, Ins return superClass.newInstance(); } - private Object instantiate(Object o) throws IllegalAccessException, InstantiationException { + private static Object instantiate(Object o) throws IllegalAccessException, InstantiationException { Class c = o.getClass(); return c.newInstance(); } - private boolean hasASuperClass(Class c) { + private static boolean hasASuperClass(Class c) { return !c.getSimpleName().equals("Object"); } - private boolean methodIsDeclaredInThisClass(Method m, Class c) { + private static boolean methodIsDeclaredInThisClass(Method m, Class c) { return m.getDeclaringClass().getSimpleName().equals(c.getSimpleName()); } - private boolean iIsTheLastParam(int i, int n) { + private static boolean iIsTheLastParam(int i, int n) { return i == n-1; } - private boolean empty(Class[] a) { + private static boolean empty(Class[] a) { return a.length == 0; } - private boolean OHasANoArgConstructor(Object o) { + private static boolean OHasANoArgConstructor(Object o) { Constructor[] constructors = o.getClass().getConstructors(); for (Constructor c : constructors ) { @@ -334,7 +325,7 @@ private boolean OHasANoArgConstructor(Object o) { return false; } - private boolean isConcrete(Class c) { + private static boolean isConcrete(Class c) { boolean result = true; if ( Modifier.isAbstract(c.getModifiers()) ) { result = false; @@ -342,7 +333,7 @@ private boolean isConcrete(Class c) { return result; } - private boolean isObjectClass(Object o) { + private static boolean isObjectClass(Object o) { return o.getClass().getSimpleName().equals("Object"); } } \ No newline at end of file diff --git a/src/main/java/squier/john/unitcorn/TestStatus.java b/src/main/java/squier/john/unitcorn/TestStatus.java index 4dc3d8c..f13f732 100644 --- a/src/main/java/squier/john/unitcorn/TestStatus.java +++ b/src/main/java/squier/john/unitcorn/TestStatus.java @@ -3,4 +3,12 @@ /** * Created by johnsquier on 2/16/17. */ -public enum TestStatus { SUCCESS, FAILURE, NON_EXISTENT_METHOD, CLASS_INSTANTIATION_FAILURE } +public enum TestStatus { + + SUCCESS, + FAILURE, + NON_EXISTENT_METHOD, + NOT_A_TEST_METHOD, + BROKEN_TEST, + CLASS_INSTANTIATION_FAILURE +} diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java index 3fcbeed..ad67f9d 100644 --- a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -4,55 +4,75 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; /** * Created by johnsquier on 2/16/17. + * @@@ need to add handling for @Before and @After + * @@@ need to reorder methods in this class for readability */ public class UnitCornTestRunner { public UnitCornTestRunner() { } - // @@@ Need to sort methods to ensure invocation order public String runTests(Class c) { - Method[] methodsWithTestAnnotation = getTestMethods(c); - List testResults = generateTestResults(c, methodsWithTestAnnotation); + Method[] testMethods = getTestMethods(c); + List testResults = generateTestResults(c, testMethods); return outputTestResultsToConsole(c, testResults); } public Result runTest(Class c, String methodName) { - return runMethod(c, methodName); + // get method object from string + Method method; + try { + method = c.getMethod(methodName); + } catch (NoSuchMethodException e) { + return new Result(methodName, TestStatus.NON_EXISTENT_METHOD); + } + + if ( isATestMethod(method) ) { + return runTestMethod(c, method); + } + else { + return new Result(methodName, TestStatus.NOT_A_TEST_METHOD); + } } - // @@@ refactor, too long private Method[] getTestMethods(Class c) { Method[] allMethods = c.getMethods(); List testMethods = new ArrayList<>(); for (Method m : allMethods) { - Annotation[] annos = m.getDeclaredAnnotations(); - for (Annotation a : annos) { - if ( isATestAnnotation(a) ) { - testMethods.add(m); - } + if ( isATestMethod(m) ) { + testMethods.add(m); } } testMethods.sort(Comparator.comparing(Method::getName)); return testMethods.toArray(new Method[0]); } - private List generateTestResults(Class c, Method[] methodsWithTestAnnotation) { + private boolean isATestMethod(Method m) { + Annotation[] annos = m.getDeclaredAnnotations(); + for (Annotation a : annos) { + if ( isATestAnnotation(a) ) { + return true; + } + } + return false; + } + + private List generateTestResults(Class c, Method[] testMethods) { List results = new ArrayList<>(); - for (Method method : methodsWithTestAnnotation) { - Result result = runTest(c, method.getName()); + for (Method testMethod : testMethods) { + // reduce to one line?? more or less readable? + Result result = runTest(c, testMethod.getName()); results.add(result); } return results; } - // @@@ Refactor + // @@@ Refactor, too long private String outputTestResultsToConsole(Class c, List testResults) { StringBuilder sb = new StringBuilder(); int testsPassed = numTestsPassed(testResults); @@ -84,7 +104,7 @@ private int numTestsFailed(List l) { } private int numTestsBroken(List l) { - return numTestsMethodError(l) + numTestsClassError(l); + return numTestsMethodError(l) + numTestsClassError(l) + numTestsBrokenTag(l); } private int numTestsMethodError(List l) { @@ -95,6 +115,10 @@ private int numTestsClassError(List l) { return countTestsWithStatus(l, TestStatus.CLASS_INSTANTIATION_FAILURE); } + private int numTestsBrokenTag(List l) { + return countTestsWithStatus(l, TestStatus.BROKEN_TEST); + } + private int countTestsWithStatus(List l, TestStatus status) { int count = 0; for (Result r : l) { @@ -105,18 +129,23 @@ private int countTestsWithStatus(List l, TestStatus status) { return count; } - private Result runMethod(Class c, String methodName) { + // @@@ refactor?? + // I use the exceptions generated during the try to determine what + // happens when I run the given method + private Result runTestMethod(Class c, Method method) { try { - Method method = c.getMethod(methodName); Object object = instantiateObjectFromClass(c); - Object theResult = method.invoke(object); - return new Result(methodName, TestStatus.SUCCESS); - } catch (NoSuchMethodException e) { - return new Result(methodName, TestStatus.NON_EXISTENT_METHOD); + method.invoke(object); + return new Result(method.getName(), TestStatus.SUCCESS); } catch (IllegalAccessException | InstantiationException e) { - return new Result(methodName, TestStatus.CLASS_INSTANTIATION_FAILURE); + return new Result(method.getName(), TestStatus.CLASS_INSTANTIATION_FAILURE); } catch (InvocationTargetException e) { - return new Result(methodName, TestStatus.FAILURE, e); // look at e for useful info + if ( e.getCause().getClass().equals(AssertionError.class) ) { + return new Result(method.getName(), TestStatus.FAILURE, e); // look at e for useful info + } + else { + return new Result(method.getName(), TestStatus.BROKEN_TEST, e); + } } } diff --git a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java index 0721b3f..f7449a8 100644 --- a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java @@ -17,9 +17,8 @@ public class ReflectionUtilsTest { @Test public void objectDoesImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; - boolean actual = reflectionUtils.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); + boolean actual = ReflectionUtils.classImplementsInterface(new Scanner(System.in), "java.io.Closeable"); Assert.assertEquals("I expect Scanner(System.in) to implement \"java.io.Closeable\"", expected, actual); @@ -27,9 +26,8 @@ public void objectDoesImplementInterfaceTest() { @Test public void objectDoesNotImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); + boolean actual = ReflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); Assert.assertEquals("I don't expect Integer() to implement \"java.lang.Iterable\"", expected, actual); @@ -37,9 +35,8 @@ public void objectDoesNotImplementInterfaceTest() { @Test public void classObjectDoesImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; - boolean actual = reflectionUtils.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); + boolean actual = ReflectionUtils.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); Assert.assertEquals("I expect String.class to implement \"java.lang.CharSequence\"", expected, actual); @@ -47,9 +44,8 @@ public void classObjectDoesImplementInterfaceTest() { @Test public void classObjectDoesNotImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); + boolean actual = ReflectionUtils.classImplementsInterface(new Integer(10).getClass(), "java.lang.Iterable"); Assert.assertEquals("I don't expect Integer.class to implement \"java.lang.Iterable\"", expected, actual); @@ -57,9 +53,8 @@ public void classObjectDoesNotImplementInterfaceTest() { @Test public void classNameDoesImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; - boolean actual = reflectionUtils.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); + boolean actual = ReflectionUtils.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); Assert.assertEquals("I expect \"java.lang.String\" to implement \"java.lang.CharSequence\"", expected, actual); @@ -67,9 +62,8 @@ public void classNameDoesImplementInterfaceTest() { @Test public void classNameDoesNotImplementInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); + boolean actual = ReflectionUtils.classImplementsInterface("java.lang.Integer", "java.lang.Iterable"); Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement\"java.lang.Iterable\"", expected, actual); @@ -77,9 +71,8 @@ public void classNameDoesNotImplementInterfaceTest() { @Test public void tryToCompareObjectToNonExistentInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); + boolean actual = ReflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", expected, actual); @@ -87,9 +80,8 @@ public void tryToCompareObjectToNonExistentInterfaceTest() { @Test public void tryToCompareClassObjectToNonExistentInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), "abra.kadabra.Allakhazham"); + boolean actual = ReflectionUtils.classImplementsInterface(new Object().getClass(), "abra.kadabra.Allakhazham"); Assert.assertEquals("I don't expect Object.class to implement \"abra.kadabra.Allakhazham\"", expected, actual); @@ -97,9 +89,8 @@ public void tryToCompareClassObjectToNonExistentInterfaceTest() { @Test public void tryToCompareClassNameToNonExistentInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", "abra.kadabra.Allakhazham"); + boolean actual = ReflectionUtils.classImplementsInterface("java.lang.Integer", "abra.kadabra.Allakhazham"); Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement \"abra.kadabra.Allakhazham\"", expected, actual); @@ -107,9 +98,8 @@ public void tryToCompareClassNameToNonExistentInterfaceTest() { @Test public void tryToCompareObjectToNullInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Object(), null); + boolean actual = ReflectionUtils.classImplementsInterface(new Object(), null); Assert.assertEquals("I don't expect Object() to implement null", expected, actual); @@ -117,9 +107,8 @@ public void tryToCompareObjectToNullInterfaceTest() { @Test public void tryToCompareClassObjectToNullInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface(new Object().getClass(), null); + boolean actual = ReflectionUtils.classImplementsInterface(new Object().getClass(), null); Assert.assertEquals("I don't expect Object.class to implement null", expected, actual); @@ -127,9 +116,8 @@ public void tryToCompareClassObjectToNullInterfaceTest() { @Test public void tryToCompareClassNameToNullInterfaceTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = false; - boolean actual = reflectionUtils.classImplementsInterface("java.lang.Integer", null); + boolean actual = ReflectionUtils.classImplementsInterface("java.lang.Integer", null); Assert.assertEquals("I don't expect \"java.lang.Integer\" to implement null", expected, actual); @@ -137,9 +125,8 @@ public void tryToCompareClassNameToNullInterfaceTest() { @Test public void stringIsNotAClassNameButAStringLiteralTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); boolean expected = true; - boolean actual = reflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); + boolean actual = ReflectionUtils.classImplementsInterface(" ", "java.lang.CharSequence"); Assert.assertEquals("I expect \" \" to implement \"java.lang.CharSequence\"", expected, actual); @@ -147,7 +134,6 @@ public void stringIsNotAClassNameButAStringLiteralTest() { @Test public void listAllMembersBufferedWriterTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "Fields\n" + "Constructors\n" + "BufferedWriter : public java.io.BufferedWriter(java.io.Writer)\n" + @@ -191,7 +177,7 @@ public void listAllMembersBufferedWriterTest() { String actual = null; - try { actual = reflectionUtils.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } + try { actual = ReflectionUtils.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } catch ( Exception e ) { } Assert.assertEquals(expected, actual); @@ -199,7 +185,6 @@ public void listAllMembersBufferedWriterTest() { @Test public void listAllMembersBooleanTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "Fields\n" + "Boolean : public static final Boolean FALSE\n" + "Boolean : public static final Boolean TRUE\n" + @@ -238,43 +223,36 @@ public void listAllMembersBooleanTest() { "Object : public final native void wait(long)\n" + "Object : public final void wait()\n"; - String actual = reflectionUtils.listAllMembers(new Boolean(true)); + String actual = ReflectionUtils.listAllMembers(Boolean.TRUE); Assert.assertEquals(expected, actual); } @Test public void getClassHierarchyBooleanTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "java.lang.Object\n java.lang.Boolean\n"; - String actual = reflectionUtils.getClassHierarchy(new Boolean(true)); + String actual = ReflectionUtils.getClassHierarchy(Boolean.TRUE); Assert.assertEquals(expected, actual); } @Test public void getClassHierarchyTreeMapTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); String expected = "java.lang.Object\n java.util.AbstractMap\n java.util.TreeMap\n"; - String actual = reflectionUtils.getClassHierarchy(new TreeMap()); + String actual = ReflectionUtils.getClassHierarchy(new TreeMap()); Assert.assertEquals(expected, actual); } @Test public void instantiateClassHierarchyObjectTest() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new Object()); List actual = null; try { - actual = reflectionUtils.instantiateClassHierarchy(new Object()); - } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { - classInHierarchyLacksNoArgConstructor.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + actual = ReflectionUtils.instantiateClassHierarchy(new Object()); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } @@ -284,19 +262,14 @@ public void instantiateClassHierarchyObjectTest() { @Test public void instantiateClassHierarchyString() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); - expected.add(new String()); + expected.add(""); expected.add(new Object()); List actual = null; try { - actual = reflectionUtils.instantiateClassHierarchy(new String()); - } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { - classInHierarchyLacksNoArgConstructor.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + actual = ReflectionUtils.instantiateClassHierarchy(""); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } @@ -307,19 +280,14 @@ public void instantiateClassHierarchyString() { @Test public void instantiateClassHierarchyArrayList() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new ArrayList<>()); expected.add(new Object()); List actual = null; try { - actual = reflectionUtils.instantiateClassHierarchy(new ArrayList<>()); - } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { - classInHierarchyLacksNoArgConstructor.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + actual = ReflectionUtils.instantiateClassHierarchy(new ArrayList<>()); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } @@ -330,7 +298,6 @@ public void instantiateClassHierarchyArrayList() { @Test public void instantiateClassHierarchyJPanel() { - ReflectionUtils reflectionUtils = new ReflectionUtils(); List expected = new ArrayList<>(); expected.add(new JPanel()); expected.add(new Container()); @@ -338,12 +305,8 @@ public void instantiateClassHierarchyJPanel() { List actual = null; try { - actual = reflectionUtils.instantiateClassHierarchy(new JPanel()); - } catch (ClassInHierarchyLacksNoArgConstructor classInHierarchyLacksNoArgConstructor) { - classInHierarchyLacksNoArgConstructor.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + actual = ReflectionUtils.instantiateClassHierarchy(new JPanel()); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } @@ -356,8 +319,7 @@ public void instantiateClassHierarchyJPanel() { @Test(expected = ClassInHierarchyLacksNoArgConstructor.class) public void instantiateClassHierarchyBoolean() throws IllegalAccessException, ClassInHierarchyLacksNoArgConstructor, InstantiationException { - ReflectionUtils reflectionUtils = new ReflectionUtils(); - reflectionUtils.instantiateClassHierarchy(new Boolean(true)); + ReflectionUtils.instantiateClassHierarchy(Boolean.TRUE); } // @@@ add tests for the other exceptions diff --git a/src/test/java/squier/john/unitcorn/ResultTest.java b/src/test/java/squier/john/unitcorn/ResultTest.java index 9ecfc25..bac6399 100644 --- a/src/test/java/squier/john/unitcorn/ResultTest.java +++ b/src/test/java/squier/john/unitcorn/ResultTest.java @@ -1,5 +1,6 @@ package squier.john.unitcorn; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -14,18 +15,30 @@ public class ResultTest { public void setup() { success1 = new Result("", TestStatus.SUCCESS); success2 = new Result("", TestStatus.SUCCESS); - failure = new Result("", TestStatus.FAILURE); + failure = new Result("", TestStatus.FAILURE, new AssertionError()); + } + + @Test + public void getThrownDuringMethodInvokeTest() { + Class expected = AssertionError.class; + Class actual = failure.getThrownDuringMethodInvoke().getClass(); + + Assert.assertTrue(expected.equals(actual)); } @Test public void resultsEqualTest() { boolean expected = true; boolean actual = success1.equals(success2); + + Assert.assertEquals(expected, actual); } @Test - public void resultsNoTEqualTest() { - boolean expected = true; + public void resultsNotEqualTest() { + boolean expected = false; boolean actual = success1.equals(failure); + + Assert.assertEquals(expected, actual); } } diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java index 53f7b63..2b8ce5a 100644 --- a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -40,6 +40,22 @@ public void runFailureTestFromDummyTests() { Assert.assertTrue(expected.equals(actual)); } + @Test + public void runBrokenTestFromDummyTests() { + Result expected = new Result("testThatIsBroken", TestStatus.BROKEN_TEST); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatIsBroken"); + + Assert.assertTrue(expected.equals(actual)); + } + + @Test + public void runMethodThatIsntATestFromDummyTests() { + Result expected = new Result("methodThatIsntTaggedWithTest", TestStatus.NOT_A_TEST_METHOD); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "methodThatIsntTaggedWithTest"); + + Assert.assertTrue(expected.equals(actual)); + } + @Test public void runTestThatDoesNotExist() { Result expected = new Result("testThatDoesNotExist",TestStatus.NON_EXISTENT_METHOD); @@ -50,7 +66,7 @@ public void runTestThatDoesNotExist() { @Test public void runTestOnClassWithoutNoArgConstructor() { - class PrivateConstructor{ private PrivateConstructor(){} public void aMethod(){} } + class PrivateConstructor{ private PrivateConstructor(){} @Test public void aMethod(){} } Result expected = new Result("aMethod", TestStatus.CLASS_INSTANTIATION_FAILURE); Result actual = unitCornTestRunner.runTest(PrivateConstructor.class, "aMethod"); @@ -64,10 +80,13 @@ public void runTestsInClassDummyTestsAndGenerateResults() { "\t Method : testThatFails()\n" + "\t Result : FAILURE\n" + "\n" + + "\t Method : testThatIsBroken()\n" + + "\t Result : BROKEN_TEST\n" + + "\n" + "\t Method : testThatPasses()\n" + "\t Result : SUCCESS\n" + "\n" + - "1 Test Passed 1 Test Failed 0 Tests Broken\n"; + "1 Test Passed 1 Test Failed 1 Test Broken\n"; String actual = unitCornTestRunner.runTests(DummyTests.class); Assert.assertEquals(expected, actual); @@ -98,7 +117,7 @@ public void runTestsInReflectionUtilsTestAndGenerateResults() { "\t Result : SUCCESS\n" + "\n" + // myTestRunner makes this test fail since I don't check for exceptions "\t Method : instantiateClassHierarchyBoolean()\n" + - "\t Result : FAILURE\n" + + "\t Result : BROKEN_TEST\n" + "\n" + "\t Method : instantiateClassHierarchyJPanel()\n" + "\t Result : SUCCESS\n" + @@ -142,7 +161,7 @@ public void runTestsInReflectionUtilsTestAndGenerateResults() { "\t Method : tryToCompareObjectToNullInterfaceTest()\n" + "\t Result : SUCCESS\n" + "\n" + - "21 Tests Passed 1 Test Failed 0 Tests Broken\n"; + "21 Tests Passed 0 Tests Failed 1 Test Broken\n"; String actual = unitCornTestRunner.runTests(ReflectionUtilsTest.class); Assert.assertEquals(expected, actual); From 8b8862a86811cf663bebb02c3c9480f209f67e39 Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 23 Feb 2017 10:42:20 -0500 Subject: [PATCH 16/17] @Before and @After tag functionality working --- .../squier/john/unitcorn/ReflectionUtils.java | 9 +- .../john/unitcorn/UnitCornTestRunner.java | 144 +++++++++++++----- .../java/squier/john/unitcorn/DummyTests.java | 17 ++- .../john/unitcorn/UnitCornTestRunnerTest.java | 21 +++ 4 files changed, 147 insertions(+), 44 deletions(-) rename src/{main => test}/java/squier/john/unitcorn/DummyTests.java (61%) diff --git a/src/main/java/squier/john/unitcorn/ReflectionUtils.java b/src/main/java/squier/john/unitcorn/ReflectionUtils.java index 763b4ae..c74f21d 100644 --- a/src/main/java/squier/john/unitcorn/ReflectionUtils.java +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -16,9 +16,8 @@ public class ReflectionUtils { public static boolean classImplementsInterface(String aClassName, String anInterfaceName) { Class classClass = getClassClassFromString(aClassName); Class interfaceClassClass = getClassClassFromString(anInterfaceName); - // will short-circuit if interfaceClassClass == null return interfaceClassClass != null && ((classClass == null) ? checkClassForInterface(aClassName.getClass(), interfaceClassClass) : - checkClassForInterface(classClass, interfaceClassClass)); + checkClassForInterface(classClass, interfaceClassClass)); } public static boolean classImplementsInterface(Class theClass, String anInterface) { @@ -76,11 +75,8 @@ public static List instantiateClassHierarchy(Object o) } private static Class getClassClassFromString(String aClassName) { - if ( aClassName == null ) { - return null; - } try { - return Class.forName(aClassName); + return aClassName == null ? null : Class.forName(aClassName); } catch ( ClassNotFoundException e ) { return null; } @@ -119,7 +115,6 @@ private static String fieldsInfoString(Class theClass) { private static String constructorInfoString(Class theClass) { Constructor[] constructors = theClass.getConstructors(); - // sort constructors by name? StringBuilder sb = new StringBuilder(); sb.append("Constructors\n"); diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java index ad67f9d..169fad9 100644 --- a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -9,7 +9,6 @@ /** * Created by johnsquier on 2/16/17. - * @@@ need to add handling for @Before and @After * @@@ need to reorder methods in this class for readability */ public class UnitCornTestRunner { @@ -17,61 +16,122 @@ public class UnitCornTestRunner { public UnitCornTestRunner() { } public String runTests(Class c) { + Method before = null, after = null; + if ( hasABeforeMethod(c) ) { + before = getBeforeMethod(c); + } + if ( hasAnAfterMethod(c) ) { + after = getAfterMethod(c); + } Method[] testMethods = getTestMethods(c); - List testResults = generateTestResults(c, testMethods); + List testResults = generateTestResults(c, testMethods, before, after); return outputTestResultsToConsole(c, testResults); } - public Result runTest(Class c, String methodName) { - // get method object from string - Method method; - try { - method = c.getMethod(methodName); - } catch (NoSuchMethodException e) { - return new Result(methodName, TestStatus.NON_EXISTENT_METHOD); - } + private boolean hasAnAfterMethod(Class c) { + return hasMethodWithAnnotation(c, "after"); + } - if ( isATestMethod(method) ) { - return runTestMethod(c, method); - } - else { - return new Result(methodName, TestStatus.NOT_A_TEST_METHOD); + private boolean hasABeforeMethod(Class c) { + return hasMethodWithAnnotation(c, "before"); + } + + private boolean hasMethodWithAnnotation(Class c, String annotation) { + Method[] allMethods = c.getMethods(); + for ( Method m : allMethods ) { + if ( methodHasAnno(m, annotation) ) { + return true; + } } + return false; + } + + private Method getBeforeMethod(Class c) { + return getMethodWithAnnotation(c, "before"); + } + + private Method getAfterMethod(Class c) { + return getMethodWithAnnotation(c, "after"); } private Method[] getTestMethods(Class c) { + return getMethodsWithAnnotation(c, "Test"); + } + + private Method[] getMethodsWithAnnotation(Class c, String annotation) { Method[] allMethods = c.getMethods(); - List testMethods = new ArrayList<>(); + List methodsWithAnno = new ArrayList<>(); + + for ( Method m : allMethods ) { + if ( methodHasAnno(m, annotation) ) { + methodsWithAnno.add(m); + } + } + methodsWithAnno.sort(Comparator.comparing(Method::getName)); + return methodsWithAnno.toArray(new Method[0]); + } + private Method getMethodWithAnnotation(Class c, String annotation) { + Method[] allMethods = c.getMethods(); for (Method m : allMethods) { - if ( isATestMethod(m) ) { - testMethods.add(m); + if ( methodHasAnno(m, annotation) ) { + return m; } } - testMethods.sort(Comparator.comparing(Method::getName)); - return testMethods.toArray(new Method[0]); + return null; // should use a special case method object } - private boolean isATestMethod(Method m) { + private boolean methodHasAnno(Method m, String annotation) { Annotation[] annos = m.getDeclaredAnnotations(); for (Annotation a : annos) { - if ( isATestAnnotation(a) ) { + if ( a.annotationType().getSimpleName().equalsIgnoreCase(annotation) ) { return true; } } return false; } - private List generateTestResults(Class c, Method[] testMethods) { + private List generateTestResults(Class c, Method[] testMethods, Method before, Method after) { List results = new ArrayList<>(); + Result result; for (Method testMethod : testMethods) { - // reduce to one line?? more or less readable? - Result result = runTest(c, testMethod.getName()); + if ( before != null && after == null ) { + result = runTestMethodWithBefore(c, testMethod, before); + } + else if ( before == null && after != null ) { + result = runTestMethodWithAfter(c, testMethod, after); + } + else if ( before != null && after != null ) { + result = runTestMethod(c, testMethod, before, after); + } + else { + result = runTest(c, testMethod.getName()); + } results.add(result); } return results; } + public Result runTest(Class c, String methodName) { + Method method; + try { + method = c.getMethod(methodName); + } catch (NoSuchMethodException e) { + return new Result(methodName, TestStatus.NON_EXISTENT_METHOD); + } + + if ( isATestMethod(method) ) { + return runTestMethod(c, method); + } + else { + return new Result(methodName, TestStatus.NOT_A_TEST_METHOD); + } + } + + private boolean isATestMethod(Method method) { + return methodHasAnno(method, "test"); + } + // @@@ Refactor, too long private String outputTestResultsToConsole(Class c, List testResults) { StringBuilder sb = new StringBuilder(); @@ -132,28 +192,44 @@ private int countTestsWithStatus(List l, TestStatus status) { // @@@ refactor?? // I use the exceptions generated during the try to determine what // happens when I run the given method + // pass two nulls to runTestMethod private Result runTestMethod(Class c, Method method) { + return runTestMethod(c, method, null, null); + } + + private Result runTestMethodWithBefore(Class c, Method testMethod, Method beforeMethod) { + return runTestMethod(c, testMethod, beforeMethod, null); + } + + private Result runTestMethodWithAfter(Class c, Method testMethod, Method afterMethod) { + return runTestMethod(c, testMethod, null, afterMethod); + } + + private Result runTestMethod(Class c, Method testMethod, Method beforeMethod, Method afterMethod) { try { Object object = instantiateObjectFromClass(c); - method.invoke(object); - return new Result(method.getName(), TestStatus.SUCCESS); + if ( beforeMethod != null ) { + beforeMethod.invoke(object); + } + testMethod.invoke(object); + if ( afterMethod != null ) { + afterMethod.invoke(object); + } + return new Result(testMethod.getName(), TestStatus.SUCCESS); } catch (IllegalAccessException | InstantiationException e) { - return new Result(method.getName(), TestStatus.CLASS_INSTANTIATION_FAILURE); + return new Result(testMethod.getName(), TestStatus.CLASS_INSTANTIATION_FAILURE); } catch (InvocationTargetException e) { if ( e.getCause().getClass().equals(AssertionError.class) ) { - return new Result(method.getName(), TestStatus.FAILURE, e); // look at e for useful info + return new Result(testMethod.getName(), TestStatus.FAILURE, e); // look at e for useful info } else { - return new Result(method.getName(), TestStatus.BROKEN_TEST, e); + return new Result(testMethod.getName(), TestStatus.BROKEN_TEST, e); } } } + private Object instantiateObjectFromClass(Class c) throws IllegalAccessException, InstantiationException { return c.newInstance(); } - - private boolean isATestAnnotation(Annotation a) { - return a.annotationType().getSimpleName().equalsIgnoreCase("test"); - } } diff --git a/src/main/java/squier/john/unitcorn/DummyTests.java b/src/test/java/squier/john/unitcorn/DummyTests.java similarity index 61% rename from src/main/java/squier/john/unitcorn/DummyTests.java rename to src/test/java/squier/john/unitcorn/DummyTests.java index 0081734..4edd128 100644 --- a/src/main/java/squier/john/unitcorn/DummyTests.java +++ b/src/test/java/squier/john/unitcorn/DummyTests.java @@ -1,19 +1,24 @@ package squier.john.unitcorn; -import org.junit.Assert; -import org.junit.Test; +import org.junit.*; /** - * Created by johnsquier on 2/17/17. +* @author John A. Squier */ public class DummyTests { + @Before + public void setup() { + System.out.println("BEFORE"); + } + @Test public void testThatPasses() { Assert.assertTrue(true); } @Test + @Ignore // test is only for use in UnitCornTestRunnerTest public void testThatFails() { //@SuppressWarnings() Assert.assertTrue("This test is designed to fail as part of the UnitCornTestRunnerTest class", @@ -21,6 +26,7 @@ public void testThatFails() { } @Test + @Ignore // test is only for use in UnitCornTestRunnerTest public void testThatIsBroken() { int[] a = new int[1]; int x = a[10]; // out of bounds @@ -29,4 +35,9 @@ public void testThatIsBroken() { public void methodThatIsntTaggedWithTest() { } + + @After + public void teardown() { + System.out.println("AFTER"); + } } diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java index 2b8ce5a..bc238c7 100644 --- a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -21,6 +21,8 @@ public void runTestMethodFromClassReflectionUtilsTest() { Result expected = new Result("objectDoesImplementInterfaceTest", TestStatus.SUCCESS); Result actual = unitCornTestRunner.runTest(ReflectionUtilsTest.class, "objectDoesImplementInterfaceTest"); + System.out.println(actual.getStatus()); + Assert.assertTrue(expected.equals(actual)); } @@ -166,4 +168,23 @@ public void runTestsInReflectionUtilsTestAndGenerateResults() { Assert.assertEquals(expected, actual); } + + // says the tests are broken but thats because my @Before isnt working + @Test + public void runTestsInResultTestAndGenerateResults() { + String expected = "Class Tested : ResultTest\n" + + "\t Method : getThrownDuringMethodInvokeTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : resultsEqualTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "\t Method : resultsNotEqualTest()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "3 Tests Passed 0 Tests Failed 0 Tests Broken\n"; + String actual = unitCornTestRunner.runTests(ResultTest.class); + + Assert.assertEquals(expected, actual); + } } From 17da2b5bad259afb7c5d4582854665c24827d12a Mon Sep 17 00:00:00 2001 From: John Squier Date: Thu, 23 Feb 2017 11:02:18 -0500 Subject: [PATCH 17/17] added tests to reach 100% test coverage for all classes --- ...ClassInHierarchyLacksNoArgConstructor.java | 2 +- .../squier/john/unitcorn/ReflectionUtils.java | 3 +- .../john/unitcorn/UnitCornTestRunner.java | 20 +++--- .../java/squier/john/unitcorn/DummyTests.java | 4 +- .../squier/john/unitcorn/DummyTests2.java | 21 +++++++ .../squier/john/unitcorn/DummyTests3.java | 15 +++++ .../john/unitcorn/ReflectionUtilsTest.java | 9 +++ .../john/unitcorn/UnitCornTestRunnerTest.java | 61 +++++++++++++------ 8 files changed, 99 insertions(+), 36 deletions(-) create mode 100644 src/test/java/squier/john/unitcorn/DummyTests2.java create mode 100644 src/test/java/squier/john/unitcorn/DummyTests3.java diff --git a/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java index 5d8c7ea..68803b7 100644 --- a/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java +++ b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java @@ -1,6 +1,6 @@ package squier.john.unitcorn; /** - * Created by johnsquier on 2/16/17. + * @author John A. Squier */ public class ClassInHierarchyLacksNoArgConstructor extends Exception { } diff --git a/src/main/java/squier/john/unitcorn/ReflectionUtils.java b/src/main/java/squier/john/unitcorn/ReflectionUtils.java index c74f21d..d49265a 100644 --- a/src/main/java/squier/john/unitcorn/ReflectionUtils.java +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -8,8 +8,7 @@ /** * Created by John A. Squier on 2/15/17. - * @@@ multiple refactor spots in src - * @@@ Class is stateless? gonna go static since these are all utility methods + * TODO multiple refactor spots in src */ public class ReflectionUtils { diff --git a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java index 169fad9..54dcc20 100644 --- a/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -9,7 +9,7 @@ /** * Created by johnsquier on 2/16/17. - * @@@ need to reorder methods in this class for readability + * TODO need to reorder methods in this class for readability */ public class UnitCornTestRunner { @@ -73,12 +73,13 @@ private Method[] getMethodsWithAnnotation(Class c, String annotation) { private Method getMethodWithAnnotation(Class c, String annotation) { Method[] allMethods = c.getMethods(); + Method toReturn = null; for (Method m : allMethods) { if ( methodHasAnno(m, annotation) ) { - return m; + toReturn = m; } } - return null; // should use a special case method object + return toReturn; } private boolean methodHasAnno(Method m, String annotation) { @@ -189,14 +190,6 @@ private int countTestsWithStatus(List l, TestStatus status) { return count; } - // @@@ refactor?? - // I use the exceptions generated during the try to determine what - // happens when I run the given method - // pass two nulls to runTestMethod - private Result runTestMethod(Class c, Method method) { - return runTestMethod(c, method, null, null); - } - private Result runTestMethodWithBefore(Class c, Method testMethod, Method beforeMethod) { return runTestMethod(c, testMethod, beforeMethod, null); } @@ -205,6 +198,11 @@ private Result runTestMethodWithAfter(Class c, Method testMethod, Method afte return runTestMethod(c, testMethod, null, afterMethod); } + private Result runTestMethod(Class c, Method method) { + return runTestMethod(c, method, null, null); + } + + // @@@ refactor?? private Result runTestMethod(Class c, Method testMethod, Method beforeMethod, Method afterMethod) { try { Object object = instantiateObjectFromClass(c); diff --git a/src/test/java/squier/john/unitcorn/DummyTests.java b/src/test/java/squier/john/unitcorn/DummyTests.java index 4edd128..6eeae88 100644 --- a/src/test/java/squier/john/unitcorn/DummyTests.java +++ b/src/test/java/squier/john/unitcorn/DummyTests.java @@ -32,9 +32,7 @@ public void testThatIsBroken() { int x = a[10]; // out of bounds } - public void methodThatIsntTaggedWithTest() { - - } + public void methodThatIsntTaggedWithTest() { } @After public void teardown() { diff --git a/src/test/java/squier/john/unitcorn/DummyTests2.java b/src/test/java/squier/john/unitcorn/DummyTests2.java new file mode 100644 index 0000000..cd82855 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/DummyTests2.java @@ -0,0 +1,21 @@ +package squier.john.unitcorn; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author John A. Squier + */ +public class DummyTests2 { + + @Test + public void testThatIsTrue() { + Assert.assertTrue(true); + } + + @After + public void teardown() { + System.out.println("AFTER"); + } +} diff --git a/src/test/java/squier/john/unitcorn/DummyTests3.java b/src/test/java/squier/john/unitcorn/DummyTests3.java new file mode 100644 index 0000000..5f2aadb --- /dev/null +++ b/src/test/java/squier/john/unitcorn/DummyTests3.java @@ -0,0 +1,15 @@ +package squier.john.unitcorn; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author John A. Squier + */ +public class DummyTests3 { + + @Test + public void testThatIsTrue() { + Assert.assertTrue(true); + } +} diff --git a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java index f7449a8..6b7f898 100644 --- a/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java +++ b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java @@ -1,6 +1,7 @@ package squier.john.unitcorn; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import javax.swing.*; @@ -15,6 +16,14 @@ */ public class ReflectionUtilsTest { + ReflectionUtils reflectionUtils; + + @Before + public void setup() { + // this is only here for 100% test coverage, all methods are static + reflectionUtils = new ReflectionUtils(); + } + @Test public void objectDoesImplementInterfaceTest() { boolean expected = true; diff --git a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java index bc238c7..bbf197f 100644 --- a/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -76,24 +76,6 @@ class PrivateConstructor{ private PrivateConstructor(){} @Test public void aMeth Assert.assertTrue(expected.equals(actual)); } - @Test - public void runTestsInClassDummyTestsAndGenerateResults() { - String expected = "Class Tested : DummyTests\n" + - "\t Method : testThatFails()\n" + - "\t Result : FAILURE\n" + - "\n" + - "\t Method : testThatIsBroken()\n" + - "\t Result : BROKEN_TEST\n" + - "\n" + - "\t Method : testThatPasses()\n" + - "\t Result : SUCCESS\n" + - "\n" + - "1 Test Passed 1 Test Failed 1 Test Broken\n"; - String actual = unitCornTestRunner.runTests(DummyTests.class); - - Assert.assertEquals(expected, actual); - } - @Test public void runTestsInReflectionUtilsTestAndGenerateResults() { String expected = "Class Tested : ReflectionUtilsTest\n" + @@ -169,7 +151,6 @@ public void runTestsInReflectionUtilsTestAndGenerateResults() { Assert.assertEquals(expected, actual); } - // says the tests are broken but thats because my @Before isnt working @Test public void runTestsInResultTestAndGenerateResults() { String expected = "Class Tested : ResultTest\n" + @@ -187,4 +168,46 @@ public void runTestsInResultTestAndGenerateResults() { Assert.assertEquals(expected, actual); } + + @Test + public void runTestsInClassDummyTestsAndGenerateResults() { + String expected = "Class Tested : DummyTests\n" + + "\t Method : testThatFails()\n" + + "\t Result : FAILURE\n" + + "\n" + + "\t Method : testThatIsBroken()\n" + + "\t Result : BROKEN_TEST\n" + + "\n" + + "\t Method : testThatPasses()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "1 Test Passed 1 Test Failed 1 Test Broken\n"; + String actual = unitCornTestRunner.runTests(DummyTests.class); + + Assert.assertEquals(expected, actual); + } + + @Test + public void runTestsInDummyTests2AndGenerateResults() { + String expected = "Class Tested : DummyTests2\n" + + "\t Method : testThatIsTrue()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "1 Test Passed 0 Tests Failed 0 Tests Broken\n"; + String actual = unitCornTestRunner.runTests(DummyTests2.class); + + Assert.assertEquals(expected, actual); + } + + @Test + public void runTestsInDummyTests3AndGenerateResults() { + String expected = "Class Tested : DummyTests3\n" + + "\t Method : testThatIsTrue()\n" + + "\t Result : SUCCESS\n" + + "\n" + + "1 Test Passed 0 Tests Failed 0 Tests Broken\n"; + String actual = unitCornTestRunner.runTests(DummyTests3.class); + + Assert.assertEquals(expected, actual); + } }