import java.lang.reflect.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Set; import java.util.HashSet; import java.util.Map; import java.util.List; import java.util.HashMap; import java.util.LinkedHashMap; import java.io.StringWriter; import java.io.PrintWriter; import java.util.function.Predicate; public class TestHW5 { // For use as a standalone file. public static void main(String[] args) { HW5Srv srv = new HW5Srv(); TestHW5 testDrv = new TestHW5(); // --- isTeen ------------------------------------------------------------------- try { int n = 13; boolean expected = true; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 19; expected = true; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 15; expected = true; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 12; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 20; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 4; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = -17; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 0; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); n = 54; expected = false; TestHW5.doTest(srv, "isTeen", new Object[] {n}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- allTeens ------------------------------------------------------------------- try { int[] nArr = {17,15,18,15}; boolean expected = true; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {12,15,18}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {17}; expected = true; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {14,16,19,17}; expected = true; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {17,17,17,17,20}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {11,3,6,-1,17}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {-14,-16}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {14,4,4,4,4,4,14}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); nArr = new int[] {}; expected = false; TestHW5.doTest(srv, "allTeens", new Object[] {nArr}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- justTeens ------------------------------------------------------------------- try { int[] nArr = {3,12,1,4,77}; int[] expected = {}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); nArr = new int[] {44,15,-9,17}; expected = new int[] {15,17}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); nArr = new int[] {15,16,18}; expected = new int[] {15,16,18}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); nArr = new int[] {13,12,9,6,4,15,3,7,-7,0,19}; expected = new int[] {13,15,19}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); nArr = new int[] {2,2,3,0,14,2,1,14,5,7}; expected = new int[] {14,14}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); nArr = new int[] {}; expected = new int[] {}; TestHW5.doTest(srv, "justTeens", new Object[] {nArr}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- whichOnesAreTeen ---------------------------------------------------------- try { int[] nArr = {15,12,18,14,77}; boolean[] expected = {true, false, true, true, false}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {44,20,-9,72}; expected = new boolean[] {false, false, false, false}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {-5,17,56,123}; expected = new boolean[] {false,true,false,false}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {13}; expected = new boolean[] {true}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {345,-12,0-2,-1,655,3,-4}; expected = new boolean[] {false, false, false, false, false, false, false}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {18,15,15,17,14,15,13,19}; expected = new boolean[] {true, true, true, true, true, true,true, true}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {98,78,55,18}; expected = new boolean[] {false, false, false, true}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {33}; expected = new boolean[] {false}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); nArr = new int[] {}; expected = new boolean[] {}; TestHW5.doTest(srv, "whichOnesAreTeen", new Object[] {nArr}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- combineArrays ---------------------------------------------------------- try { int[] nArr1 = {1,1,1}; int[] nArr2 = {2,2,2,2,2}; int[] expected = {3,3,3,2,2}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {2,2,2,2,2}; nArr2 = new int[] {1,1,1}; expected = new int[] {3,3,3,2,2}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {1,2,3,4,5,6,7}; nArr2 = new int[] {}; expected = new int[] {1,2,3,4,5,6,7}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {}; nArr2 = new int[] {1,2,3,4,5,6,7}; expected = new int[] {1,2,3,4,5,6,7}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {2,4,6,8,10}; nArr2 = new int[] {10,8,6,4,2}; expected = new int[] {12,12,12,12,12}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {0,0,0,0,0,0,0,0,0}; nArr2 = new int[] {3,5,7,6,2,9}; expected = new int[] {3,5,7,6,2,9,0,0,0}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {-3,4,-5,-100,-50,-2}; nArr2 = new int[] {3,3,10,4,25}; expected = new int[] {0,7,5,-96,-25,-2}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {45,0,-33,67,111}; nArr2 = new int[] {-5,6,110,-2,345,6}; expected = new int[] {40,6,77,65,456,6}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); nArr1 = new int[] {}; nArr2 = new int[] {}; expected = new int[] {}; TestHW5.doTest(srv, "combineArrays", new Object[] {nArr1, nArr2}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- digitsInFront ---------------------------------------------------------- try { char[] arr = "AB1C2D".toCharArray(); char[] expected = "12ABCD".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "Nonums".toCharArray(); expected = "Nonums".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "345".toCharArray(); expected = "345".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "$4".toCharArray(); expected = "4$".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "2 good 2 be 4got10".toCharArray(); expected = "22410 good be got".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "99 red balloons".toCharArray(); expected = "99 red balloons".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "$50 44% 3# 5&10 1!".toCharArray(); expected = "504435101$ % # & !".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "4score and 7 years".toCharArray(); expected = "47score and years".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); arr = "".toCharArray(); expected = "".toCharArray(); TestHW5.doTest(srv, "digitsInFront", new Object[] {arr}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- hiForLo ------------------------------------------------------------------- try { int[] numArr = {5,3,8,3,7}; int[] expected = {5,8,8,8,7}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {1,1,22}; expected = new int[] {22,22,22}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {}; expected = new int[] {}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {4,6,8,7,2,13,5,2,2,9,11,4,7,2}; expected = new int[] {4,6,8,7,13,13,5,13,13,9,11,4,7,13}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {7,7,7,7,7,7,7,7,7}; expected = new int[] {7,7,7,7,7,7,7,7,7}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {89,-17,4,54,23,-3,-17,8,0,6,-17,89,4,-9}; expected = new int[] {89,89,4,54,23,-3,89,8,0,6,89,89,4,-9}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {66,66,66,66,66,66,1,66,66}; expected = new int[] {66,66,66,66,66,66,66,66,66}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {7,2}; expected = new int[] {7,7}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {-4,22,22,22,22,22}; expected = new int[] {22,22,22,22,22,22}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {33,33,33,33,5}; expected = new int[] {33,33,33,33,33}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {457,3,5,-43,67,-43}; expected = new int[] {457,3,5,457,67,457}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {3,3,3,3,3,9,3,3}; expected = new int[] {9,9,9,9,9,9,9,9}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {9,3,3,3,3,3,3,3}; expected = new int[] {9,9,9,9,9,9,9,9}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {3,3,3,3,3,3,3,9}; expected = new int[] {9,9,9,9,9,9,9,9}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); numArr = new int[] {7}; expected = new int[] {7}; TestHW5.doTest(testDrv, "hiForLo", new Object[] {srv, numArr}, expected); } catch (Throwable tt) { TestHW5.printCachedMessages(); throw tt; } TestHW5.printResults(); // --- summary ------------------------------------------------------------------- TestHW5.printSummary(); } public int[] hiForLo(HW5Srv srvObj, int[] arr) { srvObj.hiForLo(arr); return arr; } private static final String MSG_PASS_TRUE = " "; private static final String MSG_PASS_FALSE = "FAIL: "; private static final String COMMENT_PREFIX = " // "; private static final String SPACE_COMMENT = "#SPACE_COMMENT#"; private static class Tt { private boolean didPass = false; protected void setPassed(boolean passed) { didPass = passed; if (didPass) { msgPass = MSG_PASS_TRUE; } else { msgPass = MSG_PASS_FALSE; } } protected boolean passed() { return didPass; } private boolean isComment = false; protected boolean threwException = false; protected String methodName; protected String msgPass = MSG_PASS_FALSE; protected String msgCall = ""; protected String msgReturn = ""; protected Object returnedObject; public String toString() { return "Tt: method: " + methodName + " didPass: " + didPass + " returnedObject: " + wrappedObjToString(returnedObject); } } // Use this Predicate factory to test if actualResult double is close enough to expectedResult double to be considered correct. public static Predicate closeEnough(double precision, double expectedResult) { return dd -> { double actualResult = ((Double) dd); return (Math.abs(actualResult - expectedResult) < precision); }; } private static List cachedComments = new ArrayList(); private static Map> testMap = new LinkedHashMap<>(); private static Map> methodAlternateNamesMap = new LinkedHashMap<>(); private final static Map, Class> primitiveMap = new HashMap, Class>(); static { primitiveMap.put(Boolean.class, boolean.class); primitiveMap.put(Byte.class, byte.class); primitiveMap.put(Short.class, short.class); primitiveMap.put(Character.class, char.class); primitiveMap.put(Integer.class, int.class); primitiveMap.put(Long.class, long.class); primitiveMap.put(Float.class, float.class); primitiveMap.put(Double.class, double.class); } private static String currentTestSequenceName = null; private static int outLines = 3; public static void beginTesting(String testSequenceName) { beginTesting(testSequenceName, 3); } // if linesBetweeenSpacesInOutput is 0, you can manually add spaces by calling Test.space(). public static void beginTesting(String testSequenceName, int linesBetweenSpacesInOutput) { currentTestSequenceName = testSequenceName; outLines = linesBetweenSpacesInOutput; addLabelToMap(testSequenceName); } public static void finishTesting() { currentTestSequenceName = null; } // For use when method names collide. // Note that Tt's do not distinguish between methods with the same name but different signatures. // Use an alternate name in that case. // Assign the alternate name using this method, then use the alternate name in your call to the // doTest method. public static void addAlternateNameForMethod(String methodName, String alternate) { List arr = methodAlternateNamesMap.get(methodName); if (arr == null) { arr = new ArrayList<>(); methodAlternateNamesMap.put(methodName, arr); } arr.add(alternate); } public static void addAlternateNamesForMethod(String methodName, List alternates) { List arr = methodAlternateNamesMap.get(methodName); if (arr == null) { methodAlternateNamesMap.put(methodName, alternates); } else { arr.addAll(alternates); } } /** We invoke the method with name methodName on the srv object with the parameters found in params. For explanatory purposes, the call would look like this: actualResult = srv.methodName(params[0], params[1], ...); The expectedResult is then compared to the actual result. msgOnFail will be appended to the test's line of output if the test fails. It could contain a useful diagnostic message to the method writer pointing out the reason for failure. */ public static Tt doTest(Object srv, String methodName, Object[] params, Object expectedResult, String msgOnFail) { Predicate equalsExpected = obj -> { return wrappedObjsAreEqual(obj, expectedResult); }; Tt test = doTest(srv, methodName, params, equalsExpected, msgOnFail); if (test != null && !test.passed()) { if (!test.threwException) { if (msgOnFail == null || msgOnFail.length() == 0) { test.msgReturn += " (expected " + wrappedObjToString(expectedResult) + ")"; } else { int failMsgIdx = test.msgReturn.lastIndexOf(msgOnFail); test.msgReturn = test.msgReturn.substring(0, failMsgIdx) + "expected " + wrappedObjToString(expectedResult) + " (" + test.msgReturn.substring(failMsgIdx) + "))"; } } } return test; } public static Tt doTest(Object srv, String methodName, Object[] params, Object expectedResult) { return doTest(srv, methodName, params, expectedResult, ""); } /** We invoke the method with name methodName on the srv object with the parameters found in params. For explanatory purposes, the call would look like this: actualResult = srv.methodName(params[0], params[1], ...); The result is then tested using the tester Predicate. msgOnFail will be appended to the test's line of output if the test fails. It could contain a useful diagnostic message to the method writer pointing out the reason for failure. */ public static Tt doTest(Object srv, String methodName, Object[] params, Predicate tester, String msgOnFail) { return doTest(false, srv, methodName, params, tester, msgOnFail); } public static Tt doTest(Object srv, String methodName, Object[] params, Predicate tester) { return doTest(false, srv, methodName, params, tester, ""); } private static Tt doTest(boolean isAlternateMethodName, Object srv, String methodName, Object[] params, Predicate tester, String msgOnFail) { if (currentTestSequenceName == null || currentTestSequenceName.length() == 0) { beginTesting(methodName); } Class classSrv = srv.getClass(); Class[] paramClasses = new Class[params.length]; for (int ii = 0; ii < params.length; ii++) { paramClasses[ii] = params[ii].getClass(); if (primitiveMap.containsKey(paramClasses[ii])) { paramClasses[ii] = primitiveMap.get(paramClasses[ii]); } } Tt out = new Tt(); out.methodName = methodName; if (params.length == 0) { out.msgCall = methodName + "()"; } else { out.msgCall = methodName + "("; for (int ii = 0; ii < params.length; ii++) { Object param = params[ii]; out.msgCall += wrappedObjToString(param); if (ii < params.length - 1) { out.msgCall += ", "; } else { out.msgCall += ")"; } } } Method method = null; try { method = classSrv.getMethod(methodName, paramClasses); out.returnedObject = method.invoke(srv, params); } catch(NoSuchMethodException exc) { if (isAlternateMethodName) { out.threwException = true; out.msgReturn = "--> ERROR: method <" + methodName + "> either doesn't exist or doesn't take the parameter or param types provided."; return out; } List alternates = methodAlternateNamesMap.get(methodName); if (alternates != null) { int ii = 0; for (String altMethodName : alternates) { Tt altOut = doTest(true, srv, altMethodName, params, tester, msgOnFail); if (!altOut.threwException) { return altOut; } ii++; } } out.threwException = true; out.msgReturn = "--> ERROR: method <" + methodName + "> either doesn't exist or doesn't take the parameter or param types provided."; addTestToMap(currentTestSequenceName, out); return out; } catch(InvocationTargetException exc) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exc.getCause().printStackTrace(pw); out.threwException = true; out.msgReturn = "--> (Exception shown below)\n" + sw.toString(); out.msgReturn = out.msgReturn.replaceAll("(?m)^", " "); addTestToMap(currentTestSequenceName, out); return out; } catch(Exception exc) { System.err.println("ERROR: Unwrapped Exception during invocation."); exc.printStackTrace(); } out.msgReturn = "--> "; out.msgReturn += wrappedObjToString(out.returnedObject); if (tester.test(out.returnedObject)) { out.setPassed(true); } else { if (msgOnFail != null && msgOnFail.length() > 0) { out.msgReturn += " (" + msgOnFail + ")"; } } addTestToMap(currentTestSequenceName, out); return out; } // add a blank line to the output. primarily for use when beginTesting's linesBetweenSpacesInOutput is 0. public static Tt space() { return comment(SPACE_COMMENT); } public static Tt space(int numberOfBlankLines) { for (int ii = 0; ii < numberOfBlankLines - 1; ii++) { comment(SPACE_COMMENT); } return comment(SPACE_COMMENT); } public static Tt comment(String comment) { Tt out = new Tt(); out.isComment = true; out.msgCall = COMMENT_PREFIX + comment; addCommentToMap(out); return out; } public static void printCachedMessages() { System.out.println(rightPad("----- cached messages for <" + currentTestSequenceName + "> ", "-", 80) + "\n"); printMsgs(currentTestSequenceName, true); finishTesting(); } public static void printMsgs(String testSequenceName, boolean supressMsgIfAllTestsSame) { if (!testMap.containsKey(testSequenceName)) { System.err.println("Test array not created for <" + testSequenceName + ">."); return; } List arr = testMap.get(testSequenceName); if (arr.isEmpty()) { System.err.println("No <" + testSequenceName + "> tests have been run."); return; } String delimiterLeft = "<"; String delimiterRight = ">"; if (arr.get(0).returnedObject instanceof String) { delimiterLeft = "\""; delimiterRight = "\""; } else if (arr.get(0).returnedObject instanceof Character) { delimiterLeft = "'"; delimiterRight = "'"; } if (!allTestsThrewExceptions(testSequenceName) && allReturnedObjsAreEqualAndSomeFailsPresent(testSequenceName) && supressMsgIfAllTestsSame && countMethodsInTestSequence(testSequenceName) > 1) { System.out.println(" ==> <" + testSequenceName + "> not implemented: returns " + delimiterLeft + wrappedObjToString(commonReturnedObject(testSequenceName, arr)) + delimiterRight + " for all tests.\n"); } else { int lenMsgCallMax = 0; for (Tt out : arr) { if (!out.isComment) { int lenMsgCall = out.msgCall.length(); if (lenMsgCall > lenMsgCallMax) lenMsgCallMax = lenMsgCall; } } int spacer = 0; for (int ii = 0; ii < arr.size(); ii++) { Tt out = arr.get(ii); if (out.isComment) { if (!out.msgCall.contains(SPACE_COMMENT)) { System.out.println(out.msgCall); } else { System.out.println(); } } else { System.out.println(out.msgPass + rightPad(out.msgCall, " ", lenMsgCallMax) + " " + out.msgReturn); spacer++; if (outLines > 0) { if (spacer%outLines == 0 && ii < arr.size() - 1) { System.out.println(); spacer = 0; } } } } } } public static Object commonReturnedObject(String testSequenceName, List arr) { Object oo = null; for (Tt tt : arr) { if (testSequenceName.equals(tt.methodName)) { return tt.returnedObject; } } return arr.get(0).returnedObject; } public static void printResults(boolean supressMsgIfAllTestsSame) { System.out.println(rightPad("----- <" + currentTestSequenceName + "> ", "-", 80) + "\n"); printMsgs(currentTestSequenceName, supressMsgIfAllTestsSame); printTestSequenceSummary(currentTestSequenceName, supressMsgIfAllTestsSame); finishTesting(); } public static void printResults() { printResults(false); } public static void printTestSequenceSummary(String testSequenceName, boolean supressMsgIfAllTestsSame) { if (!testMap.containsKey(testSequenceName)) { System.err.println("ERROR in test file: call to printTestSequenceSummary for test <" + testSequenceName + ">, but no calls to doTest for it."); return; } List arr = testMap.get(testSequenceName); if (arr.isEmpty()) { System.out.println(" ==> No <" + testSequenceName + "> tests were performed. Is the appropriate method present and named correctly in your server?\n"); return; } if (!supressMsgIfAllTestsSame || !allReturnedObjsAreEqualAndSomeFailsPresent(testSequenceName)) { int testsFailed = countTestsFailed(testSequenceName); if (testsFailed == 0) { System.out.println("\n ==> All <" + testSequenceName + "> tests passed!\n"); } else if (testsFailed == 1) { System.out.println("\n ==> All <" + testSequenceName + "> tests passed except one- getting close!\n"); } else { System.out.println("\n ==> The <" + testSequenceName + "> tests failed " + testsFailed + " tests. More work to do...\n"); } } } public static void printSummary() { String out = ""; for (String testSequenceName : testMap.keySet()) { List arr = testMap.get(testSequenceName); if (arr.isEmpty()) { if (out.length() > 0) { out += "\n"; } out += " | No <" + testSequenceName + "> tests were performed."; } else if (allReturnedObjsAreEqualAndSomeFailsPresent(testSequenceName) && !allTestsThrewExceptions(testSequenceName) && countMethodsInTestSequence(testSequenceName) > 1) { if (out.length() > 0) { out += "\n"; } String delimiterLeft = "<"; String delimiterRight = ">"; if (arr.get(0).returnedObject instanceof String) { delimiterLeft = "\""; delimiterRight = "\""; } else if (arr.get(0).returnedObject instanceof Character) { delimiterLeft = "'"; delimiterRight = "'"; } out += " | <" + testSequenceName + "> not implemented: returns " + delimiterLeft + wrappedObjToString(arr.get(0).returnedObject) + delimiterRight + " for all tests."; } else { int fails = countTestsFailed(testSequenceName); if (fails > 0) { if (out.length() > 0) { out += "\n"; } out += " | <" + testSequenceName + "> failed " + fails + " test" + (fails > 1 ? "s" : "") + "."; } int excsThrown = countThrownExceptions(testSequenceName); if (excsThrown > 0) { if (out.length() > 0) { out += "\n"; } out += " | (<" + testSequenceName + "> threw Exception for " + excsThrown + " test" + (excsThrown > 1 ? "s" : "") + ".)"; } } } if (out.length() == 0) { System.out.println(" +--------------------------------------+"); System.out.println(" | -* * * W O O H O O ! * * *- |"); System.out.println(" | -All methods pass all tests!- |"); System.out.println(" +--------------------------------------+\n"); } else { System.out.println(rightPad(" +", "-", 80)); System.out.println(out); System.out.println(rightPad(" +", "-", 80) + "\n"); } } public static void reset() { testMap = new LinkedHashMap>(); } private static String wrappedObjToString(Object obj) { if (obj == null) { return "null"; } if (!isArray(obj)) { return obj.toString(); } Class cc = obj.getClass(); String out = ""; try { Method mm; if (!cc.getComponentType().isPrimitive()) { cc = Object[].class; mm = Arrays.class.getMethod("deepToString", cc); } else { mm = Arrays.class.getMethod("toString", cc); } out = (String)mm.invoke(null, obj); } catch(Exception exc) { exc.printStackTrace(); } return out; } private static boolean wrappedObjsAreEqual(Object obj1, Object obj2) { if (obj1 == null ^ obj2 == null) { return false; } return Arrays.deepEquals(new Object[] { obj1 }, new Object[] { obj2 }); } private static boolean isArray(Object obj) { return (obj != null && obj.getClass().isArray()); } private static String rightPad(String in, String ss, int totalLen) { while (in.length() < totalLen) in += ss; return in; } private static void addLabelToMap(String testSequenceName) { if (!testMap.containsKey(testSequenceName)) { List arr = new ArrayList<>(); testMap.put(testSequenceName, arr); addCachedCommentsToMap(testSequenceName); } } private static void addTestToMap(String testSequenceName, Tt test) { if (!testMap.containsKey(testSequenceName)) { addLabelToMap(testSequenceName); } List arr = testMap.get(testSequenceName); arr.add(test); } private static void addCommentToMap(Tt comment) { if (currentTestSequenceName == null || currentTestSequenceName.length() == 0) { cachedComments.add(comment); } else { List arr = testMap.get(currentTestSequenceName); arr.add(comment); } } private static void addCachedCommentsToMap(String testSequenceName) { if (!testMap.containsKey(testSequenceName)) { addLabelToMap(testSequenceName); } List arr = testMap.get(testSequenceName); arr.addAll(cachedComments); cachedComments.clear(); } private static int countThrownExceptions(String testSequenceName) { List arr = testMap.get(testSequenceName); int excsThrown = 0; for (Tt test : arr) { if (test.threwException) { excsThrown++; } } return excsThrown; } private static boolean allTestsThrewExceptions(String testSequenceName) { List arr = testMap.get(testSequenceName); boolean allThrew = true; for (Tt test : arr) { if (!test.isComment && !test.threwException) { allThrew = false; } } return allThrew; } private static int countTestsFailed(String testSequenceName) { List arr = testMap.get(testSequenceName); int testsFailed = 0; for (Tt test : arr) { if (!test.isComment && !test.passed()) { testsFailed++; } } return testsFailed; } private static int countMethodsInTestSequence(String testSequenceName) { Set methodNames = new HashSet(); List arr = testMap.get(testSequenceName); for (Tt tt : arr) { methodNames.add(tt.methodName); } return arr.size(); } private static boolean allReturnedObjsAreEqualAndSomeFailsPresent(String testSequenceName) { List arr = testMap.get(testSequenceName); Map> testsByMethod = new HashMap<>(); for (Tt tt : arr) { List tests = testsByMethod.get(tt.methodName); if (tests == null) { tests = new ArrayList(); testsByMethod.put(tt.methodName, tests); } tests.add(tt); } boolean allReturnedObjsAreEqual = true; boolean someFailsPresent = false; for (String methodName : testsByMethod.keySet()) { List tests = testsByMethod.get(methodName); Object returnedObjPrev = null; for (Tt test : tests) { if (!test.isComment) { if (!test.passed()) { someFailsPresent = true; } if (returnedObjPrev != null) { if (!wrappedObjsAreEqual(test.returnedObject, returnedObjPrev)) { allReturnedObjsAreEqual = false; } } returnedObjPrev = test.returnedObject; } } } // System.out.println("DEBUG: allRetObjsAreEqual: " + allReturnedObjsAreEqual + " someFailsPresent: " + someFailsPresent); return allReturnedObjsAreEqual && someFailsPresent; } }