Advertisement
ahawtho

JUnit4Runner

Feb 17th, 2012
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5 20.11 KB | None | 0 0
  1. package com.mycompany.test;
  2.  
  3. import static java.util.concurrent.TimeUnit.NANOSECONDS;
  4. import static java.util.concurrent.TimeUnit.SECONDS;
  5. import static java.util.logging.Level.WARNING;
  6. import static org.w3c.dom.DOMException.NOT_FOUND_ERR;
  7. import static org.w3c.dom.DOMException.NOT_SUPPORTED_ERR;
  8.  
  9. import java.io.BufferedOutputStream;
  10. import java.io.BufferedReader;
  11. import java.io.File;
  12. import java.io.FileNotFoundException;
  13. import java.io.FileOutputStream;
  14. import java.io.FileReader;
  15. import java.io.IOException;
  16. import java.io.PrintStream;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.InetAddress;
  20. import java.net.UnknownHostException;
  21. import java.text.SimpleDateFormat;
  22. import java.util.ArrayList;
  23. import java.util.Collections;
  24. import java.util.Set;
  25. import java.util.TimeZone;
  26. import java.util.logging.Logger;
  27. import java.util.logging.SimpleFormatter;
  28. import java.util.logging.StreamHandler;
  29.  
  30. import junit.framework.AssertionFailedError;
  31.  
  32. import org.junit.Ignore;
  33. import org.junit.internal.AssumptionViolatedException;
  34. import org.junit.runner.Description;
  35. import org.junit.runner.JUnitCore;
  36. import org.junit.runner.Result;
  37. import org.junit.runner.notification.Failure;
  38. import org.junit.runner.notification.RunListener;
  39. import org.w3c.dom.CDATASection;
  40. import org.w3c.dom.Comment;
  41. import org.w3c.dom.DOMException;
  42. import org.w3c.dom.DOMImplementation;
  43. import org.w3c.dom.Document;
  44. import org.w3c.dom.Element;
  45. import org.w3c.dom.bootstrap.DOMImplementationRegistry;
  46. import org.w3c.dom.ls.DOMImplementationLS;
  47. import org.w3c.dom.ls.LSOutput;
  48. import org.w3c.dom.ls.LSSerializer;
  49.  
  50. public class Junit4Runner {
  51.     private static final Logger LOG =
  52.         Logger.getLogger(Junit4Runner.class.getName());
  53.     private static String m_hostname;
  54.     private final String[] m_argv;
  55.  
  56.     public Junit4Runner(String[] p_argv) {
  57.         m_argv = p_argv;
  58.     }
  59.  
  60.     public int run() {
  61.         PrintStream sysout = System.out;
  62.         PrintStream syserr = System.err;
  63.         File stdout = null;
  64.         File stderr = null;
  65.         try {
  66.             try {
  67.                 stdout = File.createTempFile(Junit4Runner.class.getName(), "_out.log");
  68.                 stdout.deleteOnExit();
  69.                 System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(stdout))));
  70.             } catch (IOException e) {
  71.                 LOG.log(WARNING, "Could not redirect stdout", e);
  72.             }
  73.             try {
  74.                 stderr = File.createTempFile(Junit4Runner.class.getName(), "_err.log");
  75.                 stderr.deleteOnExit();
  76.                 PrintStream errStream = new PrintStream(new FileOutputStream(stderr));
  77.                 System.setErr(errStream);
  78.             } catch (IOException e) {
  79.                 LOG.log(WARNING, "Could not redirect stderr", e);
  80.             }
  81.             JUnitCore core = new JUnitCore();
  82.             XMLResultListener listener;
  83.             listener = new XMLResultListener(stdout, stderr);
  84.             core.addListener(listener);
  85.             ArrayList<Class<?>> cl = new ArrayList<Class<?>>();
  86.             for (String arg : m_argv) {
  87.                 try {
  88.                     cl.add(Class.forName(arg));
  89.                 } catch (ClassNotFoundException e) {
  90.                     LOG.log(WARNING, "Warning: Cannot find class " + arg, e);
  91.                 }
  92.             }
  93.             Class<?>[] tests = new Class<?>[cl.size()];
  94.             cl.toArray(tests);
  95.             core.run(tests);
  96.             sysout.printf("Tests run: %d, Failures: %d, Errors: %d, Skipped: %d, Time elapsed: %.3f sec%n", listener.tests(), listener.failed(), listener.errors(), listener.skipped(), listener.time());
  97.             return listener.internalError()? 1 : 0;
  98.         } finally {
  99.             System.setOut(sysout);
  100.             System.setErr(syserr);
  101.         }
  102.     }
  103.  
  104.     public static void main(String[] p_argv) throws IOException {
  105.         Junit4Runner runner = new Junit4Runner(p_argv);
  106.         System.exit(runner.run());
  107.     }
  108.  
  109.     private static String hostname() {
  110.         if (m_hostname == null) {
  111.             try {
  112.                 m_hostname = InetAddress.getLocalHost().getCanonicalHostName();
  113.             } catch (UnknownHostException e) {
  114.                 m_hostname = "<unknown>";
  115.             }
  116.         }
  117.         return m_hostname;
  118.     }
  119.  
  120.     // convenience method
  121.     private static String stringOf(Object p_obj) {
  122.         return String.valueOf(p_obj);
  123.     }
  124.  
  125.     @SuppressWarnings("unchecked")
  126.     private static <T extends Throwable> T initCause(T p_throwable,
  127.                                                      Throwable p_cause)
  128.         throws T {
  129.         throw (T)p_throwable.initCause(p_cause);
  130.     }
  131.  
  132.     static {
  133.         LOG.addHandler(new StreamHandler(System.out, new SimpleFormatter()));
  134.         LOG.setUseParentHandlers(false);
  135.     }
  136.  
  137.     private static class XMLResultListener extends RunListener {
  138.         private final DOMImplementation m_dom;
  139.         private Document m_doc;
  140.         private Element m_suite;
  141.         private Element m_testcase;
  142.         private long m_errors;
  143.         private long m_failures;
  144.         private long m_skipped;
  145.         private long m_total;
  146.         private long m_suiteStartTime;
  147.         private long m_startTime;
  148.         private final File m_stdout;
  149.         private final File m_stderr;
  150.         private double m_time;
  151.         private boolean m_internalError;
  152.  
  153.         public XMLResultListener(File p_stdout, File p_stderr)
  154.             throws DOMException {
  155.             m_stdout = p_stdout;
  156.             m_stderr = p_stderr;
  157.             DOMImplementationRegistry registry;
  158.             try {
  159.                 registry = DOMImplementationRegistry.newInstance();
  160.             } catch (ClassCastException e) {
  161.                 throw initCause(new DOMException(NOT_SUPPORTED_ERR,
  162.                                                  e.getMessage()),
  163.                                 e);
  164.             } catch (ClassNotFoundException e) {
  165.                 throw initCause(new DOMException(NOT_FOUND_ERR, e.getMessage()),
  166.                                 e);
  167.             } catch (InstantiationException e) {
  168.                 throw initCause(new DOMException(NOT_SUPPORTED_ERR,
  169.                                                  e.getMessage()),
  170.                                 e);
  171.             } catch (IllegalAccessException e) {
  172.                 throw initCause(new DOMException(NOT_SUPPORTED_ERR,
  173.                                                  e.getMessage()),
  174.                                 e);
  175.             }
  176.             m_dom = registry.getDOMImplementation("XML 3.0");
  177.         }
  178.  
  179.         public boolean internalError() {
  180.             return m_internalError;
  181.         }
  182.  
  183.         public double time() {
  184.             return m_time;
  185.         }
  186.  
  187.         public long skipped() {
  188.             return m_skipped;
  189.         }
  190.  
  191.         public long errors() {
  192.             return m_errors;
  193.         }
  194.  
  195.         public long failed() {
  196.             return m_failures;
  197.         }
  198.  
  199.         public long tests() {
  200.             return m_total;
  201.         }
  202.  
  203.         @Override
  204.         public void testRunStarted(Description p_description) {
  205.             m_suiteStartTime = System.nanoTime();
  206.             try {
  207.                 m_doc = m_dom.createDocument(null, "testsuite", null);
  208.                 m_suite = m_doc.getDocumentElement();
  209.                 TimeZone timeZone = TimeZone.getDefault();
  210.                 long ts = System.currentTimeMillis();
  211.                 int offset = timeZone.getOffset(ts);
  212.                 String date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(ts - offset);
  213.                 m_suite.setAttribute("timestamp", date);
  214.                 m_suite.setAttribute("hostname", hostname());
  215.                 String displayName = getDisplayName(p_description);
  216.                 if (displayName == null) {
  217.                     ArrayList<Description> children =
  218.                         p_description.getChildren();
  219.                     if (children != null && children.size() == 1) {
  220.                         Description child = children.get(0);
  221.                         displayName = getDisplayName(child);
  222.                     }
  223.                 }
  224.                 m_suite.setAttribute("name", displayName);
  225.             } catch (RuntimeException e) {
  226.                 throw throwLog("testRunStarted", e);
  227.             }
  228.         }
  229.  
  230.         private String getDisplayName(Description p_description) {
  231.             String displayName;
  232.             displayName = p_description.getDisplayName();
  233. //            if (displayName == null || "null".equals(displayName))
  234. //                displayName = p_description.getClassName();
  235. //            if (displayName == null || "null".equals(displayName)) {
  236. //                Class<?> testClass = p_description.getTestClass();
  237. //                if (testClass != null) {
  238. //                    displayName = testClass.getCanonicalName();
  239. //                    if (displayName == null || "null".equals(displayName))
  240. //                        displayName = p_description.getTestClass().getName();
  241. //                }
  242. //            }
  243.             if ("null".equals(displayName))
  244.                 displayName = null;
  245.             return displayName;
  246.         }
  247.  
  248.         @Override
  249.         public void testRunFinished(Result p_result) {
  250.             try {
  251.                 long endSuiteTime = System.nanoTime();
  252.                 m_time = (endSuiteTime - m_suiteStartTime)
  253.                          / (double)NANOSECONDS.convert(1, SECONDS);
  254.                 m_suite.setAttribute("time", String.format("%.3f", m_time));
  255.                 m_suite.setAttribute("errors", stringOf(m_errors));
  256.                 m_suite.setAttribute("failures", stringOf(m_failures));
  257.                 m_suite.setAttribute("skipped", stringOf(m_skipped));
  258.                 m_suite.setAttribute("tests", stringOf(m_total));
  259.  
  260.                 @SuppressWarnings({"unchecked", "rawtypes"})
  261.                 ArrayList<String> l = new ArrayList<String>((Set)System.getProperties().keySet());
  262.                 Collections.sort(l);
  263.                 Element props = m_doc.createElement("properties");
  264.                 for (String propKey : l) {
  265.                     Element prop = m_doc.createElement("property");
  266.                     prop.setAttribute("name", xmlEscape(propKey));
  267.                     prop.setAttribute("value", xmlEscape(System.getProperty(propKey)));
  268.                     props.appendChild(prop);
  269.                 }
  270.                 m_suite.insertBefore(props, m_suite.getFirstChild());
  271.                 Comment comment =
  272.                     m_doc.createComment("Created by "
  273.                                         + Junit4Runner.class.getName());
  274.                 m_suite.insertBefore(comment, props);
  275.  
  276.                 System.out.flush();
  277.                 System.err.flush();
  278.                 Element sysout = m_doc.createElement("system-out");
  279.                 extractOutputData(m_stdout, sysout);
  280.                 m_suite.appendChild(sysout);
  281.                 Element syserr = m_doc.createElement("system-err");
  282.                 extractOutputData(m_stderr, syserr);
  283.                 m_suite.appendChild(syserr);
  284.  
  285.                 // Save the test output
  286.                 String testName = m_suite.getAttribute("name");
  287.                 DOMImplementationLS ls = (DOMImplementationLS)m_dom;
  288.                 LSOutput output = ls.createLSOutput();
  289.                 output.setByteStream(new FileOutputStream("TEST-" + testName + ".xml"));
  290.                 LSSerializer serializer = ls.createLSSerializer();
  291.                 serializer.getDomConfig().setParameter("format-pretty-print", true);
  292.                 serializer.getDomConfig().setParameter("element-content-whitespace", true);
  293.                 serializer.write(m_doc, output);
  294.             } catch (RuntimeException e) {
  295.                 throw throwLog("testRunFinished", e);
  296.             } catch (IOException e) {
  297.                 throw throwLog("testRunFinished", e);
  298.             }
  299.         }
  300.  
  301.         public void extractOutputData(File p_file, Element p_element)
  302.             throws FileNotFoundException, IOException {
  303.             FileReader fr = new FileReader(p_file);
  304.             BufferedReader r = new BufferedReader(fr);
  305.             String line;
  306.             while ((line = r.readLine()) != null) {
  307.                 CDATASection cdata = m_doc.createCDATASection(line);
  308.                 cdata.appendData("\n");
  309.                 p_element.appendChild(cdata);
  310.             }
  311.         }
  312.  
  313.         @Override
  314.         public void testStarted(Description p_description) {
  315.             try {
  316.                 createTestCaseNode(p_description);
  317.             } catch (RuntimeException e) {
  318.                 throw throwLog("testStarted", e);
  319.             }
  320.         }
  321.  
  322.         public void createTestCaseNode(Description p_description) {
  323.             m_testcase = m_doc.createElement("testcase");
  324.             m_suite.appendChild(m_testcase);
  325.             try {
  326.                 Method m;
  327.                 try {
  328.                     m = p_description.getClass().getMethod("getClassName");
  329.                 } catch (NoSuchMethodException e) {
  330.                     m = null;
  331.                 }
  332.                 if (m != null) {
  333.                     Object o = m.invoke(p_description);
  334.                     if (o != null) {
  335.                         m_testcase.setAttribute("classname", stringOf(o));
  336.                     }
  337.                 } else {
  338.                     m_testcase.setAttribute("classname",
  339.                                             p_description.getDisplayName());
  340.                 }
  341.                 m_testcase.setAttribute("name", p_description.getDisplayName());
  342.             } catch (IllegalAccessException e) {
  343.                 throw throwLog("setting name", e);
  344.             } catch (InvocationTargetException e) {
  345.                 throw throwLog("setting name", e);
  346.             }
  347.             m_startTime = System.nanoTime();
  348.         }
  349.  
  350.         @Override
  351.         public void testFinished(Description p_description) {
  352.             try {
  353.                 long endTime = System.nanoTime();
  354.                 m_total++;
  355.                 m_testcase.setAttribute("time", stringOf((endTime - m_startTime) / 1000000.0));
  356.             } catch (RuntimeException e) {
  357.                 throw throwLog("testFinished", e);
  358.             }
  359.         }
  360.  
  361.         @Override
  362.         public void testAssumptionFailure(Failure p_failure) {
  363.             try {
  364.                 Throwable ex = p_failure.getException();
  365.                 Element skippedElem = m_doc.createElement("skipped");
  366.                 m_skipped++;
  367.                 skippedElem.setAttribute("message", xmlEscape(ex.getMessage()));
  368. //                skippedElem.setAttribute("type", ex.getClass().getName());
  369.                 // This modifies the exception, and the failure uses the
  370.                 // same exception to produce the text content, so this
  371.                 // allows us to eat our cake and have it too.
  372.                 filterStackTraces(ex);
  373.                 skippedElem.setTextContent(xmlEscape(p_failure.getTrace()));
  374.                 m_testcase.appendChild(skippedElem);
  375.             } catch (RuntimeException e) {
  376.                 throw throwLog("testAssumptionFailure", e);
  377.             }
  378.  
  379.         }
  380.  
  381.         @Override
  382.         public void testFailure(Failure p_failure) {
  383.             Throwable ex = p_failure.getException();
  384.             Element failureElem;
  385.             Ignore ann;
  386.             try {
  387.                 if ((ann = p_failure.getDescription().getAnnotation(Ignore.class))
  388.                     != null) {
  389.                     failureElem = m_doc.createElement("skipped");
  390.                     m_skipped++;
  391.                     failureElem.setAttribute("message", xmlEscape(ann.value()));
  392.                 } else {
  393.                     if ((ex instanceof AssertionError)
  394.                         || (ex instanceof AssertionFailedError)) {
  395.                         failureElem = m_doc.createElement("failure");
  396.                         m_failures++;
  397.                     } else if (ex instanceof AssumptionViolatedException
  398.                                || ex.getClass().getName().equals(AssumptionViolatedException.class.getName())) {
  399.                         testAssumptionFailure(p_failure);
  400.                         return;
  401.                     } else {
  402.                         failureElem = m_doc.createElement("error");
  403.                         m_errors++;
  404.                     }
  405.                     failureElem.setAttribute("message", xmlEscape(ex.getMessage()));
  406.                     failureElem.setAttribute("type", ex.getClass().getName());
  407.                     // This modifies the exception, and the failure uses the
  408.                     // same exception to produce the text content, so this
  409.                     // allows us to eat our cake and have it too.
  410.                     filterStackTraces(ex);
  411.                     failureElem.setTextContent(xmlEscape(p_failure.getTrace()));
  412.                 }
  413.                 m_testcase.appendChild(failureElem);
  414.             } catch (RuntimeException e) {
  415.                 throw throwLog("testFailure", e);
  416.             }
  417.         }
  418.  
  419.         private void filterStackTraces(Throwable p_ex) {
  420.             ArrayList<StackTraceElement> l = new ArrayList<StackTraceElement>();
  421.             for (StackTraceElement elem : p_ex.getStackTrace()) {
  422.                 if (! elem.getClassName().startsWith("org.junit.")
  423.                     && ! elem.getClassName().startsWith("junit.framework.")
  424.                     && ! elem.getClassName().startsWith("sun.reflect.")
  425.                     && ! elem.getClassName().startsWith("java.lang.reflect.")) {
  426.                     l.add(elem);
  427.                 }
  428.             }
  429.             p_ex.setStackTrace(l.toArray(new StackTraceElement[l.size()]));
  430.             if (p_ex.getCause() != null)
  431.                 filterStackTraces(p_ex.getCause());
  432.         }
  433.  
  434.         @Override
  435.         public void testIgnored(Description p_description) throws Exception {
  436.             try {
  437.                 createTestCaseNode(p_description);
  438.                 Ignore annotation = p_description.getAnnotation(Ignore.class);
  439.                 Element skippedElem = m_doc.createElement("skipped");
  440.                 skippedElem.setAttribute("message", xmlEscape(annotation.value()));
  441. //                skippedElem.setAttribute("type", Ignore.class.getName());
  442.                 m_testcase.appendChild(skippedElem);
  443.                 m_skipped++;
  444.             } catch (RuntimeException e) {
  445.                 throw throwLog("testIgnored", e);
  446.             }
  447.         }
  448.  
  449.         private RuntimeException throwLog(String p_message,
  450.                                           Throwable p_exception)
  451.         throws RuntimeException {
  452.             m_internalError = true;
  453.             LOG.log(WARNING, p_message, p_exception);
  454.             throw new RuntimeException(p_message, p_exception);
  455.         }
  456.  
  457.         public static String xmlEscape(String p_input) {
  458.             if (p_input == null)
  459.                 return null;
  460.             StringBuilder buf = null;
  461.             int last = -1;
  462.             for (int i = 0; i < p_input.length(); ++i) {
  463.                 char c = p_input.charAt(i);
  464.                 if (Character.isISOControl(c)
  465.                     && c != '\n'
  466.                     && c != '\r'
  467.                     && c != '\t'
  468.                     && c != '\u0085') {
  469.                     if (buf == null)
  470.                         buf = new StringBuilder(p_input.length() + 24); // Allow for 4 chars.
  471.                     buf.append(p_input.substring(last + 1, i));
  472.                     // XML doesn't allow '0' at all, so we have to escape it.
  473.                     if (c == 0) {
  474.                         buf.append("\\0");
  475.                     } else {
  476.                         buf.append("&#x")
  477.                            .append(Integer.toHexString(c))
  478.                            .append( ';' );
  479.                         last = i;
  480.                     }
  481.                 }
  482.             }
  483.             String ret;
  484.             if (buf != null) {
  485.                 buf.append(p_input.substring(last + 1));
  486.                 ret = buf.toString();
  487.             } else {
  488.                 ret = p_input;
  489.             }
  490.             return ret;
  491.         }
  492.     }
  493. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement