diff --git a/.gitignore b/.gitignore index 32858aa..c3106dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,60 @@ +# 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* + +# junk files # +############## +test.txt 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 diff --git a/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java new file mode 100644 index 0000000..68803b7 --- /dev/null +++ b/src/main/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructor.java @@ -0,0 +1,6 @@ +package squier.john.unitcorn; + +/** + * @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 new file mode 100644 index 0000000..d49265a --- /dev/null +++ b/src/main/java/squier/john/unitcorn/ReflectionUtils.java @@ -0,0 +1,333 @@ +package squier.john.unitcorn; + +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 John A. Squier on 2/15/17. + * TODO multiple refactor spots in src + */ +public class ReflectionUtils { + + public static boolean classImplementsInterface(String aClassName, String anInterfaceName) { + Class classClass = getClassClassFromString(aClassName); + Class interfaceClassClass = getClassClassFromString(anInterfaceName); + return interfaceClassClass != null && ((classClass == null) ? checkClassForInterface(aClassName.getClass(), interfaceClassClass) : + checkClassForInterface(classClass, interfaceClassClass)); + } + + public static boolean classImplementsInterface(Class theClass, String anInterface) { + return classImplementsInterface(theClass.getName(), anInterface); + } + + public static boolean classImplementsInterface(Object o, String theInterface) { + return classImplementsInterface(o.getClass(), theInterface); + } + + public static String listAllMembers(Object o) { + Class c = o.getClass(); + StringBuilder sb = new StringBuilder(); + sb.append(classInfoString(c)); + + while ( hasASuperClass(c) ) { + c = c.getSuperclass(); + sb.append(classInfoString(c)); + } + return sb.toString(); + } + + public static String getClassHierarchy(Object o) { + Class theClass = o.getClass(); + List> classHierarchyInReverse = new ArrayList<>(); + + classHierarchyInReverse.add(theClass); + while ( hasASuperClass(theClass) ) { + theClass = theClass.getSuperclass(); + classHierarchyInReverse.add(theClass); + } + return generateClassHierarchyString(classHierarchyInReverse); + } + + // @@@ refactor + public static 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; + } + + private static Class getClassClassFromString(String aClassName) { + try { + return aClassName == null ? null : Class.forName(aClassName); + } catch ( ClassNotFoundException e ) { + return null; + } + } + + private static 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 static String classInfoString(Class theClass) { + StringBuilder sb = new StringBuilder(); + sb.append(fieldsInfoString(theClass)); + sb.append(constructorInfoString(theClass)); + sb.append(methodsInfoString(theClass)); + return sb.toString(); + } + + private static String fieldsInfoString(Class theClass) { + Field[] fields = theClass.getFields(); + fields = sortMemberArray(fields); + + StringBuilder sb = new StringBuilder(); + sb.append("Fields\n"); + + for (Field f : fields) { + sb.append(generateFieldInfo(f, theClass)); + } + return sb.toString(); + } + + private static String constructorInfoString(Class theClass) { + Constructor[] constructors = theClass.getConstructors(); + + StringBuilder sb = new StringBuilder(); + sb.append("Constructors\n"); + + for (Constructor c : constructors) { + sb.append(generateConstructorInfo(c, theClass)); + } + return sb.toString(); + } + + private static String methodsInfoString(Class theClass) { + Method[] methods = theClass.getMethods(); + methods = sortMemberArray(methods); + + StringBuilder sb = new StringBuilder(); + sb.append("Methods\n"); + + for (Method m : methods) { + if ( methodIsDeclaredInThisClass(m, theClass) ) { + sb.append(generateMethodInfo(m, theClass)); + } + } + return sb.toString(); + } + + private static 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 static 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 static 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 static String paramsInfoString(Class[] params) { + StringBuilder sb = new StringBuilder(); + if ( empty(params) ) { + sb.append(")"); + } else { + sb.append(allParams(params)); + } + return sb.toString(); + } + + private static String classNameHeader(Class theClass) { + return theClass.getSimpleName() + " : "; + } + + private static String modifiers(Field f) { + return Modifier.toString(f.getModifiers()) + " "; + } + + private static String modifiers(Constructor c) { + return Modifier.toString(c.getModifiers()) + " "; + } + + private static String modifiers(Method m) { + return Modifier.toString((m.getModifiers())) + " "; + } + + private static String fieldType(Field f) { + return f.getType().getSimpleName() + " "; + } + + private static String methodReturnType(Method m) { + return m.getReturnType() + " "; + } + + private static String fieldName(Field f) { + return f.getName() + "\n"; + } + + private static String constructorName(Constructor c) { + return c.getName() + "("; + } + + private static String methodName(Method m) { + return m.getName() + "("; + } + + private static String params(Constructor c) { + return paramsInfoString(c.getParameterTypes()); + } + + private static String params(Method m) { + return paramsInfoString(m.getParameterTypes()); + } + + private static 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 static String paramDelimiter(int i, Class[] a) { + String result; + if (iIsTheLastParam(i, a.length)) { + result = ")"; + } else { + result = ", "; + } + return result; + } + + private static Field[] sortMemberArray(Field[] f) { + Arrays.sort(f, Comparator.comparing(Field::getName)); + return f; + } + + private static Method[] sortMemberArray(Method[] m) { + Arrays.sort(m, Comparator.comparing(Method::getName)); + return m; + } + + // @@@ Refactor + private static 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(); + } + + // @@@ refactor + private static Object getNextConcreteClass(Object o) throws IllegalAccessException, InstantiationException { + Class superClass = o.getClass().getSuperclass(); + + if ( hasASuperClass(o.getClass()) && isConcrete(superClass) ) { + return superClass.newInstance(); + } + else { + while ( hasASuperClass(superClass) ) { + if ( isConcrete(superClass) ) { + return superClass.newInstance(); + } + superClass = superClass.getSuperclass(); + } + } + return superClass.newInstance(); + } + + private static Object instantiate(Object o) throws IllegalAccessException, InstantiationException { + Class c = o.getClass(); + return c.newInstance(); + } + + private static boolean hasASuperClass(Class c) { + return !c.getSimpleName().equals("Object"); + } + + private static boolean methodIsDeclaredInThisClass(Method m, Class c) { + return m.getDeclaringClass().getSimpleName().equals(c.getSimpleName()); + } + + private static boolean iIsTheLastParam(int i, int n) { + return i == n-1; + } + + private static boolean empty(Class[] a) { + return a.length == 0; + } + + private static boolean OHasANoArgConstructor(Object o) { + Constructor[] constructors = o.getClass().getConstructors(); + + for (Constructor c : constructors ) { + if ( c.getParameterTypes().length == 0 ) { + return true; + } + } + return false; + } + + private static boolean isConcrete(Class c) { + boolean result = true; + if ( Modifier.isAbstract(c.getModifiers()) ) { + result = false; + } + return result; + } + + 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/Result.java b/src/main/java/squier/john/unitcorn/Result.java new file mode 100644 index 0000000..efdd241 --- /dev/null +++ b/src/main/java/squier/john/unitcorn/Result.java @@ -0,0 +1,37 @@ +package squier.john.unitcorn; + +/** + * Created by johnsquier on 2/16/17. + */ +public class Result { + + private String nameOfMethodRun; + private TestStatus status; + private Throwable thrownDuringMethodInvoke; + + public Result(String nameOfMethodRun, TestStatus status) { + this(nameOfMethodRun, status, null); + } + + public Result(String nameOfMethodRun, TestStatus status, Throwable thrownDuringMethodInvoke) { + this.nameOfMethodRun = nameOfMethodRun; + this.status = status; + 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 Throwable getThrownDuringMethodInvoke() { + return thrownDuringMethodInvoke; + } +} 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..f13f732 --- /dev/null +++ b/src/main/java/squier/john/unitcorn/TestStatus.java @@ -0,0 +1,14 @@ +package squier.john.unitcorn; + +/** + * Created by johnsquier on 2/16/17. + */ +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 new file mode 100644 index 0000000..54dcc20 --- /dev/null +++ b/src/main/java/squier/john/unitcorn/UnitCornTestRunner.java @@ -0,0 +1,233 @@ +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.Comparator; +import java.util.List; + +/** + * Created by johnsquier on 2/16/17. + * TODO need to reorder methods in this class for readability + */ +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, before, after); + return outputTestResultsToConsole(c, testResults); + } + + private boolean hasAnAfterMethod(Class c) { + return hasMethodWithAnnotation(c, "after"); + } + + 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 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(); + Method toReturn = null; + for (Method m : allMethods) { + if ( methodHasAnno(m, annotation) ) { + toReturn = m; + } + } + return toReturn; + } + + private boolean methodHasAnno(Method m, String annotation) { + Annotation[] annos = m.getDeclaredAnnotations(); + for (Annotation a : annos) { + if ( a.annotationType().getSimpleName().equalsIgnoreCase(annotation) ) { + return true; + } + } + return false; + } + + private List generateTestResults(Class c, Method[] testMethods, Method before, Method after) { + List results = new ArrayList<>(); + Result result; + for (Method testMethod : testMethods) { + 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(); + 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"); + } + 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) + numTestsBrokenTag(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 numTestsBrokenTag(List l) { + return countTestsWithStatus(l, TestStatus.BROKEN_TEST); + } + + private int countTestsWithStatus(List l, TestStatus status) { + int count = 0; + for (Result r : l) { + if ( r.getStatus().equals(status) ) { + count++; + } + } + return count; + } + + 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 method) { + return runTestMethod(c, method, null, null); + } + + // @@@ refactor?? + private Result runTestMethod(Class c, Method testMethod, Method beforeMethod, Method afterMethod) { + try { + Object object = instantiateObjectFromClass(c); + 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(testMethod.getName(), TestStatus.CLASS_INSTANTIATION_FAILURE); + } catch (InvocationTargetException e) { + if ( e.getCause().getClass().equals(AssertionError.class) ) { + return new Result(testMethod.getName(), TestStatus.FAILURE, e); // look at e for useful info + } + else { + return new Result(testMethod.getName(), TestStatus.BROKEN_TEST, e); + } + } + } + + + private Object instantiateObjectFromClass(Class c) throws IllegalAccessException, InstantiationException { + return c.newInstance(); + } +} diff --git a/src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java b/src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java new file mode 100644 index 0000000..32ac9f8 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/ClassInHierarchyLacksNoArgConstructorTest.java @@ -0,0 +1,16 @@ +package squier.john.unitcorn; + +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/unitcorn/DummyTests.java b/src/test/java/squier/john/unitcorn/DummyTests.java new file mode 100644 index 0000000..6eeae88 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/DummyTests.java @@ -0,0 +1,41 @@ +package squier.john.unitcorn; + +import org.junit.*; + +/** +* @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", + false); + } + + @Test + @Ignore // test is only for use in UnitCornTestRunnerTest + public void testThatIsBroken() { + int[] a = new int[1]; + int x = a[10]; // out of bounds + } + + public void methodThatIsntTaggedWithTest() { } + + @After + public void teardown() { + System.out.println("AFTER"); + } +} 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 new file mode 100644 index 0000000..6b7f898 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/ReflectionUtilsTest.java @@ -0,0 +1,335 @@ +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.util.*; +import java.util.List; + +/** + * Created by johnsquier on 2/15/17. + */ +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; + 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); + } + + @Test + public void objectDoesNotImplementInterfaceTest() { + boolean expected = false; + boolean actual = ReflectionUtils.classImplementsInterface(new Integer(10), "java.lang.Iterable"); + + Assert.assertEquals("I don't expect Integer() to implement \"java.lang.Iterable\"", + expected, actual); + } + + @Test + public void classObjectDoesImplementInterfaceTest() { + boolean expected = true; + boolean actual = ReflectionUtils.classImplementsInterface("string".getClass(), "java.lang.CharSequence"); + + Assert.assertEquals("I expect String.class to implement \"java.lang.CharSequence\"", + expected, actual); + } + + @Test + public void classObjectDoesNotImplementInterfaceTest() { + boolean expected = false; + 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); + } + + @Test + public void classNameDoesImplementInterfaceTest() { + boolean expected = true; + boolean actual = ReflectionUtils.classImplementsInterface("java.lang.String", "java.lang.CharSequence"); + + Assert.assertEquals("I expect \"java.lang.String\" to implement \"java.lang.CharSequence\"", + expected, actual); + } + + @Test + public void classNameDoesNotImplementInterfaceTest() { + boolean expected = false; + 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); + } + + @Test + public void tryToCompareObjectToNonExistentInterfaceTest() { + boolean expected = false; + boolean actual = ReflectionUtils.classImplementsInterface(new Object(), "abra.kadabra.Allakhazham"); + + Assert.assertEquals("I don't expect Object() to implement \"abra.kadabra.Allakhazham\"", + expected, actual); + } + + @Test + public void tryToCompareClassObjectToNonExistentInterfaceTest() { + boolean expected = false; + 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); + } + + @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 tryToCompareObjectToNullInterfaceTest() { + 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 tryToCompareClassObjectToNullInterfaceTest() { + 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 tryToCompareClassNameToNullInterfaceTest() { + 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); + } + + @Test + public void listAllMembersBufferedWriterTest() { + 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 = ReflectionUtils.listAllMembers(new BufferedWriter(new FileWriter("test.txt"))); } + catch ( Exception e ) { } + + Assert.assertEquals(expected, actual); + } + + @Test + public void listAllMembersBooleanTest() { + String expected = "Fields\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" + + "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 = ReflectionUtils.listAllMembers(Boolean.TRUE); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getClassHierarchyBooleanTest() { + String expected = "java.lang.Object\n java.lang.Boolean\n"; + String actual = ReflectionUtils.getClassHierarchy(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 = ReflectionUtils.getClassHierarchy(new TreeMap()); + + Assert.assertEquals(expected, actual); + } + + @Test + public void instantiateClassHierarchyObjectTest() { + List expected = new ArrayList<>(); + expected.add(new Object()); + + List actual = null; + try { + actual = ReflectionUtils.instantiateClassHierarchy(new Object()); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | 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(""); + expected.add(new Object()); + + List actual = null; + try { + actual = ReflectionUtils.instantiateClassHierarchy(""); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | 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<>()); + expected.add(new Object()); + + List actual = null; + try { + actual = ReflectionUtils.instantiateClassHierarchy(new ArrayList<>()); + } catch (ClassInHierarchyLacksNoArgConstructor | InstantiationException | 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 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 | InstantiationException | 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 { + 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 new file mode 100644 index 0000000..bac6399 --- /dev/null +++ b/src/test/java/squier/john/unitcorn/ResultTest.java @@ -0,0 +1,44 @@ +package squier.john.unitcorn; + +import org.junit.Assert; +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, 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 = false; + boolean actual = success1.equals(failure); + + Assert.assertEquals(expected, actual); + } +} 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..bbf197f --- /dev/null +++ b/src/test/java/squier/john/unitcorn/UnitCornTestRunnerTest.java @@ -0,0 +1,213 @@ +package squier.john.unitcorn; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by johnsquier on 2/16/17. + */ +public class UnitCornTestRunnerTest { + + UnitCornTestRunner unitCornTestRunner; + + @Before + public void setup() { + unitCornTestRunner = new UnitCornTestRunner(); + } + + @Test + 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)); + } + + @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 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); + Result actual = unitCornTestRunner.runTest(DummyTests.class, "testThatDoesNotExist"); + + Assert.assertTrue(expected.equals(actual)); + } + + @Test + public void runTestOnClassWithoutNoArgConstructor() { + class PrivateConstructor{ private PrivateConstructor(){} @Test public void aMethod(){} } + + Result expected = new Result("aMethod", TestStatus.CLASS_INSTANTIATION_FAILURE); + Result actual = unitCornTestRunner.runTest(PrivateConstructor.class, "aMethod"); + + Assert.assertTrue(expected.equals(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 : BROKEN_TEST\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 0 Tests Failed 1 Test Broken\n"; + String actual = unitCornTestRunner.runTests(ReflectionUtilsTest.class); + + Assert.assertEquals(expected, actual); + } + + @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); + } + + @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); + } +}