package autograder; import java.io.PrintStream; import java.lang.annotation.*; import java.util.*; import kvstore.*; import org.junit.FixMethodOrder; import org.junit.experimental.categories.*; import org.junit.experimental.categories.Categories.IncludeCategory; import org.junit.runner.*; import org.junit.runners.*; public final class AGCategories { // JUnit Categories public interface AG_CS162 {} public interface AG_PROJ3 extends AG_CS162 {} public interface AG_PROJ3_TEST extends AG_PROJ3 {} public interface AG_PROJ3_CODE extends AG_PROJ3 {} public interface AG_PROJ4 extends AG_CS162 {} public interface AG_PROJ4_TEST extends AG_PROJ4 {} public interface AG_PROJ4_CODE extends AG_PROJ4 {} // JUnit Suites (defined by categories) @RunWith(Categories.class) @Suite.SuiteClasses({ EndToEndTest.class, KVCacheTest.class, KVClientTest.class, KVMessageTest.class, KVStoreTest.class, SocketServerTest.class, ThreadPoolTest.class, KVServerTest.class }) @IncludeCategory(AG_PROJ3_CODE.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public static class AGSuite_proj3_code {} @IncludeCategory(AG_PROJ3_TEST.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public static class AGSuite_proj3_test extends AGSuite_proj3_code {} @RunWith(Categories.class) @Suite.SuiteClasses({ }) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @IncludeCategory(AG_PROJ4_CODE.class) public static class AGSuite_proj4_code {} @FixMethodOrder(MethodSorters.NAME_ASCENDING) @IncludeCategory(AG_PROJ4_TEST.class) public static class AGSuite_proj4_test extends AGSuite_proj4_code {} @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AGTestDetails { // int uid(); // Unique ID (manually chosen) float points() default Float.NaN; // Points during grading String desc(); // Public description for students String developNotes() default ""; // Private description for AG developers/TA's String testFamily() default ""; // If blank, just uses class name boolean isPublic() default true; // Made available in public auto-autograder } public static String getTestTitle(Description d) { AGTestDetails details = d.getAnnotation(AGTestDetails.class); if (details == null) return d.getMethodName(); return String.format("%s", d.getDisplayName()); } public static String getTestDesc(Description d) { AGTestDetails details = d.getAnnotation(AGTestDetails.class); if (details == null) return d.getDisplayName(); return details.desc(); } public static String getTestFamily(Description d) { AGTestDetails details = d.getAnnotation(AGTestDetails.class); String family = (details == null) ? null : details.testFamily(); if ((family == null) || family.isEmpty()) { family = d.getTestClass().getSimpleName(); } return family; } public static String getTestWeights(Description d, boolean showAll) { AGTestDetails details = d.getAnnotation(AGTestDetails.class); if (details == null) return (showAll) ? "??? 0 " + d.getDisplayName() : null; return (!((details.points() > 0.0f) || showAll)) ? null : String.format("%s %d %s", d.getDisplayName(), Math.round(details.points()), getTestFamily(d)); } public static String getTestDetailText(Description d) { AGTestDetails details = d.getAnnotation(AGTestDetails.class); if (details == null) return d.getDisplayName(); return String.format("%s %.2f %s [%s] %s", d.getDisplayName(), details.points(), getTestFamily(d), details.isPublic() ? "public" : "private", details.desc()); } static enum AGSuite { proj3_test(AGSuite_proj3_test.class), proj3_code(AGSuite_proj3_code.class), proj4_test(AGSuite_proj4_test.class), proj4_code(AGSuite_proj4_code.class); private Class<?> suiteClass; AGSuite(Class<?> suite) { suiteClass = suite; } public Request getJUnitRequest() { return Request.aClass(suiteClass); } } public static boolean runJUnitTests(final Request request) { // TODO: Explicitly take two streams, then redirect & restore stdout/err PrintStream psOut = System.err; System.setErr(System.out); Calendar startCal = Calendar.getInstance(); System.out.format("AutoGrader Run: %1tc%n%n", startCal); System.out.println("========================== DISPLAYING FAILED TESTS =========================="); System.out.flush(); // psOut.format("START-ALL: %1tc%n", startCal); // Perform the JUnit run proper SuccessListener jlistener = new SuccessListener(request, System.err, System.err);//psOut); JUnitCore jcore = new JUnitCore(); jcore.addListener(jlistener); // Result result = jcore.run(request); jcore.run(request); boolean perfectOnRequired = (jlistener.testsLost == 0); // Report on the run in various summary forms // jlistener.logSummary(System.err, true); // jlistener.logSummary(System.err, false); // jlistener.logSummary(psOut, true); // Just encourage finalization of stuff (probably useless) // result = null; jlistener = null; jcore = null; System.gc(); System.runFinalization(); System.err.flush(); psOut.flush(); // Calendar finishCal = Calendar.getInstance(); // System.out.format("%n%nFINISH-ALL: %1tc [ ELAPSED: %2tT ]%n%n", // finishCal, TestUtils.elapsedTime(startCal, finishCal)); return perfectOnRequired; } public static void listTests(Description desc, int level) { int nextLevel = level + (int) Math.signum(level); List<Description> reqList = desc.getChildren(); if ((level > 0) || desc.isTest()) { String line = null; if (level == 0) { line = getTestWeights(desc, false); } else if (level > 0) { line = getTestDetailText(desc); if (line != null) { line = TestUtils.indentStr(level - 1, "\t") + line; } } else { line = getTestDetailText(desc); } if (line != null) { System.out.println(line); } } for (Description child: reqList) { listTests(child, nextLevel); } } }