/** * Powerunit - A JDK1.8 test framework * Copyright (C) 2014 Mathieu Boretti. * * This file is part of Powerunit * * Powerunit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Powerunit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. */ package ch.powerunit.impl; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import ch.powerunit.TestContext; import ch.powerunit.TestResultListener; import ch.powerunit.report.Error; import ch.powerunit.report.Failure; import ch.powerunit.report.Testcase; import ch.powerunit.report.Testsuite; import ch.powerunit.report.Testsuites; /** * @author borettim * */ public class DefaultTestResultListener<T> implements TestResultListener<T> { public DefaultTestResultListener(String targetFolder) { this(targetFolder, null); } public DefaultTestResultListener(String targetFolder, PrintStream outputConsole) { this(targetFolder, outputConsole, null); } public DefaultTestResultListener(String targetFolder, PrintStream outputConsole, PowerUnit mbean) { this.outputConsole = outputConsole; this.targetFolder = new File(targetFolder); this.targetFolder.mkdirs(); this.mbean = mbean; } private static final JAXBContext JAXB_CONTEXT; private final StringBuilder resumedSucess = new StringBuilder(); private final StringBuilder resumedFailure = new StringBuilder(); private final StringBuilder resumedSkipped = new StringBuilder(); /** * @return the resumed */ public String getResumed() { return "Success tests:\n" + resumedSucess.toString() + "\n\nSkipped tests:\n" + resumedSkipped.toString() + "\n\nFailed tests:\n" + resumedFailure.toString() + "\n"; } /** * @return the resumedSucess */ public String getResumedSucess() { return resumedSucess.toString(); } /** * @return the resumedFailure */ public String getResumedFailure() { return resumedFailure.toString(); } /** * @return the resumedSkipped */ public String getResumedSkipped() { return resumedSkipped.toString(); } static { try { JAXB_CONTEXT = JAXBContext.newInstance(Testsuites.class); } catch (JAXBException e) { throw new IllegalArgumentException("Unable to setup jaxb " + e.getMessage(), e); } } private boolean error = false; private final PrintStream outputConsole; private final Map<String, Testsuite> result = new HashMap<>(); private final Map<String, Testsuites> results = new HashMap<>(); private final Map<String, Map<String, Testcase>> resultcase = new HashMap<>(); private final File targetFolder; private final PowerUnit mbean; private void printf(String format, Object... args) { if (outputConsole != null) { outputConsole.printf(format, args); } } @Override public void notifySetStart(String setName, String parameters) { Testsuites tss = new Testsuites(); tss.setDisabled(0); tss.setErrors(0); tss.setFailures(0); tss.setName(setName); tss.setTests(0); tss.setTime(0L); results.put(setName, tss); Testsuite ts = new Testsuite(); result.put(setName, ts); ts.setName(setName.replace('$', '.')); ts.setDisabled(0); ts.setErrors(0); ts.setFailures(0); ts.setTests(0); ts.setTime(0L); resultcase.put(setName, new HashMap<>()); } @Override public void notifySetEnd(String setName, String parameters) { try { File target = new File(targetFolder, setName + ".xml"); printf("Pushing test results into %1$s%n", target.getAbsolutePath()); Object o = results.get(setName); if (results.get(setName).getTestsuite().isEmpty()) { o = result.get(setName); } if (mbean != null) { ByteArrayOutputStream str = new ByteArrayOutputStream(); JAXB_CONTEXT.createMarshaller().marshal(o, str); mbean.addResult(new String(str.toByteArray())); } JAXB_CONTEXT.createMarshaller().marshal(o, target); } catch (JAXBException e) { throw new IllegalArgumentException("Unable to setup jaxb " + e.getMessage(), e); } } @Override public void notifyStart(TestContext<T> context) { String setName = context.getSetName() + (context.getParameterName() == null ? "" : context .getParameterName()); Testsuite ts = result.get(setName); Testcase tc = new Testcase(); tc.setName(context.getLocalTestName() + (context.getParameterName() == null ? "" : "[" + context.getParameterName() + "]")); tc.setClassname(context.getTestSuiteObject().getClass() .getCanonicalName()); resultcase.get(setName).put(context.getFullTestName(), tc); ts.getTestcase().add(tc); tc.setTime(System.currentTimeMillis()); printf("Start of test %1$s%n", context.getFullTestName()); } @Override public void notifySuccess(TestContext<T> context) { String setName = context.getSetName() + (context.getParameterName() == null ? "" : context .getParameterName()); long end = System.currentTimeMillis(); Testsuite ts = result.get(setName); Testcase tc = resultcase.get(setName).get(context.getFullTestName()); tc.setTime((end - tc.getTime()) / 1000); ts.setTime(ts.getTime() + tc.getTime()); ts.setTests(ts.getTests() + 1); printf("Success of test %1$s%n", context.getFullTestName()); resumedSucess.append("\t").append(context.getLocalTestName()) .append(" of ").append(context.getSetName()).append("\n"); } @Override public void notifyFailure(TestContext<T> context, Throwable cause) { String setName = context.getSetName() + (context.getParameterName() == null ? "" : context .getParameterName()); long end = System.currentTimeMillis(); Testsuite ts = result.get(setName); Testcase tc = resultcase.get(setName).get(context.getFullTestName()); tc.setTime((end - tc.getTime()) / 1000); ts.setTime(ts.getTime() + tc.getTime()); error = true; ts.setFailures(ts.getFailures() + 1); Failure f = new Failure(); tc.getFailure().add(f); f.setType(cause.getClass().getCanonicalName()); f.setMessage(cause.getMessage()); StringBuilder stack = new StringBuilder("" + cause.getMessage()) .append('\n'); completeStack(cause, stack); f.setContent(stack.toString()); printf("Failure of test %1$s because of %2$s%n", context.getFullTestName(), cause.getMessage()); resumedFailure.append("\t").append(context.getLocalTestName()) .append(" of ").append(context.getSetName()) .append(" caused by ").append(cause.getMessage()).append("\n"); } @Override public void notifySkipped(TestContext<T> context) { String setName = context.getSetName() + (context.getParameterName() == null ? "" : context .getParameterName()); long end = System.currentTimeMillis(); Testsuite ts = result.get(setName); Testcase tc = resultcase.get(setName).get(context.getFullTestName()); tc.setTime((end - tc.getTime()) / 1000); ts.setTime(ts.getTime() + tc.getTime()); ts.setDisabled(ts.getDisabled() + 1); tc.setSkipped("Skipped"); printf("Skip of test %1$s%n", context.getFullTestName()); resumedSkipped.append("\t").append(context.getLocalTestName()) .append(" of ").append(context.getSetName()).append("\n"); } @Override public void notifyError(TestContext<T> context, Throwable cause) { String setName = context.getSetName() + (context.getParameterName() == null ? "" : context .getParameterName()); long end = System.currentTimeMillis(); Testsuite ts = result.get(setName); Testcase tc = resultcase.get(setName).get(context.getFullTestName()); tc.setTime((end - tc.getTime()) / 1000); ts.setTime(ts.getTime() + tc.getTime()); error = true; ts.setErrors(ts.getErrors() + 1); Error e = new Error(); tc.getError().add(e); e.setType(cause.getClass().getCanonicalName()); e.setMessage(cause.getMessage()); StringBuilder stack = new StringBuilder("" + cause.getMessage()) .append('\n'); completeStack(cause, stack); e.setContent(stack.toString()); printf("Error of test %1$s because of %2$s%n", context.getFullTestName(), cause.getMessage()); resumedFailure.append("\t").append(context.getLocalTestName()) .append(" of ").append(context.getSetName()) .append(" caused by ").append(cause.getMessage()).append("\n"); } /** * @param cause * @param stack */ private void completeStack(Throwable cause, StringBuilder stack) { for (StackTraceElement ste : cause.getStackTrace()) { stack.append(ste.toString()).append('\n'); } Throwable by = cause.getCause(); if (by != null) { stack.append("caused by ").append(by.getMessage() + "\n"); completeStack(by, stack); } } @Override public void notifyParameterStart(String setName, String parameterName) { Testsuites tss = results.get(setName); Testsuite ts = new Testsuite(); result.put(setName + parameterName, ts); ts.setName(setName + "[" + parameterName + "]"); ts.setDisabled(0); ts.setErrors(0); ts.setFailures(0); ts.setTests(0); ts.setTime(0L); resultcase.put(setName + parameterName, new HashMap<>()); tss.getTestsuite().add(ts); } @Override public void notifyParameterEnd(String setName, String parameterName) { Testsuites tss = results.get(setName); Testsuite ts = result.get(setName + parameterName); tss.setDisabled(tss.getDisabled() + ts.getDisabled()); tss.setErrors(tss.getErrors() + ts.getErrors()); tss.setFailures(tss.getFailures() + ts.getFailures()); tss.setTests(tss.getTests() + ts.getTests()); tss.setTime(tss.getTime() + ts.getTime()); } /** * @return the error */ public boolean isError() { return error; } }