/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.tvl.goworks.project.testing; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.modules.gsf.testrunner.api.Manager; import org.netbeans.modules.gsf.testrunner.api.Report; import org.netbeans.modules.gsf.testrunner.api.Status; import org.netbeans.modules.gsf.testrunner.api.TestSession; import org.netbeans.modules.gsf.testrunner.api.TestSuite; import org.netbeans.modules.gsf.testrunner.api.Testcase; import org.openide.util.Parameters; import org.tvl.goworks.project.GoProject; import org.tvl.goworks.project.testing.nodes.GoTestRunnerNodeFactory; /** * * @author Sam Harwell */ public class GoTestOutputWriter extends Writer { // -J-Dorg.tvl.goworks.project.testing.GoTestOutputWriter.level=FINE private static final Logger LOGGER = Logger.getLogger(GoTestOutputWriter.class.getName()); private final GoProject _project; private final StringBuilder _buffer = new StringBuilder(); private final List<Testcase> _cases = new ArrayList<>(); private float _totalTime; private TestSession _session; public GoTestOutputWriter(@NonNull GoProject project) { Parameters.notNull("project", project); this._project = project; } @Override public void write(char[] cbuf, int off, int len) throws IOException { _buffer.append(cbuf, off, len); processBufferLines(false); } @Override public void flush() throws IOException { processBufferLines(true); } @Override public void close() throws IOException { if (_session != null) { Manager.getInstance().sessionFinished(_session); _session = null; } } private void processBufferLines(boolean flush) { if (_buffer.length() == 0) { return; } while (true) { int newline = _buffer.length(); for (int i = 0; i < _buffer.length(); i++) { if (_buffer.charAt(i) == '\r' || _buffer.charAt(i) == '\n') { newline = i; break; } } if (newline == _buffer.length() && !flush) { break; } String line = _buffer.substring(0, newline); if (!line.isEmpty()) { processLine(line); } _buffer.delete(0, Math.min(_buffer.length(), newline + 1)); } } private static final Pattern RUN_PATTERN = Pattern.compile("^===\\s*RUN\\s+([a-zA-Z0-9_]+)\\s*$"); private static final Pattern TEST_RESULT_PATTERN = Pattern.compile("^---\\s*(PASS|FAIL):\\s*([a-zA-Z0-9_]+)\\s+\\(([0-9+](\\.[0-9]+)?)\\s+seconds\\)\\s*$"); private static final Pattern PACKAGE_RESULT_PATTERN = Pattern.compile( "^" + "(\\?|ok|FAIL)" + // result "\\s+" + "([a-zA-Z0-9_]+)" + // package "\\s+" + "(?:" + "([0-9+](\\.[0-9]+)?)s" + // time "|" + "\\[(.*?)\\]" + // message ")\\s*$"); private void processLine(String line) { Matcher runMatcher = RUN_PATTERN.matcher(line); if (runMatcher.matches()) { createSession(); String test = runMatcher.group(1); processRun(test); return; } Matcher testResultMatcher = TEST_RESULT_PATTERN.matcher(line); if (testResultMatcher.matches()) { createSession(); String result = testResultMatcher.group(1); String test = testResultMatcher.group(2); String time = testResultMatcher.group(3); processTestResult(result, test, time); return; } Matcher packageResultMatcher = PACKAGE_RESULT_PATTERN.matcher(line); if (packageResultMatcher.matches()) { createSession(); String result = packageResultMatcher.group(1); String packageName = packageResultMatcher.group(2); String time = packageResultMatcher.group(3); String message = packageResultMatcher.group(4); processPackageResult(result, packageName, time, message); return; } if (_session != null) { Manager.getInstance().displayOutput(_session, line, true); } LOGGER.log(Level.FINE, "Unknown output line: {0}", line); } private void createSession() { if (_session != null) { return; } TestSession.SessionType sessionType = TestSession.SessionType.TEST; _session = new TestSession(_project.getProjectDirectory().getName(), _project, sessionType, new GoTestRunnerNodeFactory()); Manager.getInstance().testStarted(_session); } private void processRun(String test) { LOGGER.log(Level.FINE, "Running test: {0}", test); } private void processTestResult(String result, String test, String time) { Testcase testcase = new Testcase(test, null, _session); if ("PASS".equals(result)) { testcase.setStatus(Status.PASSED); } else { testcase.setStatus(Status.FAILED); } try { Float timeInSeconds = Float.valueOf(time); testcase.setTimeMillis(Math.round(timeInSeconds * 1000)); } catch (NumberFormatException ex) { } _cases.add(testcase); LOGGER.log(Level.FINE, "Test result: result={0}, test={1}, time={2}", new Object[] { result, test, time }); } private void processPackageResult(String result, String packageName, String time, String message) { float timeInSeconds = 0; if (time != null) { try { timeInSeconds = Float.valueOf(time); } catch (NumberFormatException ex) { timeInSeconds = 0; } } TestSuite suite = new TestSuite(packageName); _session.addSuite(suite); Manager.getInstance().displaySuiteRunning(_session, suite.getName()); for (Testcase testcase : _cases) { testcase.setClassName(packageName); _session.addTestCase(testcase); } _cases.clear(); _totalTime += timeInSeconds; Report report = _session.getReport(Math.round(timeInSeconds * 1000)); Manager.getInstance().displayReport(_session, report); LOGGER.log(Level.FINE, "Package result: result={0}, test={1}, time={2}, message={3}", new Object[] { result, packageName, time, message }); } }