/******************************************************************************* * Copyright (c) 2008, 2016 xored software, Inc. and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.ruby.testing.internal; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.SearchEngine; import org.eclipse.dltk.internal.launching.IPathEquality; import org.eclipse.dltk.internal.launching.PathEqualityUtils; import org.eclipse.dltk.ruby.debug.RubyFilenameLinenumberResolver; import org.eclipse.dltk.ruby.internal.debug.ui.console.RubyFileHyperlink; import org.eclipse.dltk.testing.AbstractTestRunnerUI; import org.eclipse.dltk.testing.ITestElementResolver; import org.eclipse.dltk.testing.ITestRunnerUI; import org.eclipse.dltk.testing.ITestingEngine; import org.eclipse.dltk.testing.TestElementResolution; import org.eclipse.dltk.testing.model.ITestCaseElement; import org.eclipse.dltk.testing.model.ITestElement; import org.eclipse.dltk.testing.model.ITestSuiteElement; import org.eclipse.jface.action.IAction; import org.eclipse.jface.preference.IPreferenceStore; public abstract class AbstractRubyTestRunnerUI extends AbstractTestRunnerUI implements ITestRunnerUI, ITestElementResolver { protected static final Pattern STACK_FRAME_IN_PATTERN = Pattern .compile("(.+):(\\d+):in `(.+)'"); //$NON-NLS-1$ protected static final Pattern STACK_FRAME_PATTERN = RubyFilenameLinenumberResolver .createPattern(); protected final IScriptProject project; protected final AbstractRubyTestingEngine testingEngine; protected IPathEquality pathEquality; /** * @param testingEngine * @param project */ public AbstractRubyTestRunnerUI(AbstractRubyTestingEngine testingEngine, IScriptProject project) { this.testingEngine = testingEngine; this.project = project; // TODO use project environment specific entry this.pathEquality = PathEqualityUtils.getInstance(); } @Override public String getDisplayName() { return testingEngine.getName(); } @Override public boolean isStackFrame(String line) { return STACK_FRAME_IN_PATTERN.matcher(line).matches() || STACK_FRAME_PATTERN.matcher(line).matches(); } @Override public IAction createOpenEditorAction(String line) { Matcher matcher = STACK_FRAME_IN_PATTERN.matcher(line); if (!matcher.matches()) { matcher = STACK_FRAME_PATTERN.matcher(line); } if (matcher.matches()) { Object element = RubyFileHyperlink.findSourceModule(matcher .group(1)); if (element != null) { final int lineNumber; try { lineNumber = Integer.parseInt(matcher.group(2)); } catch (NumberFormatException e) { return null; } return new RubyOpenEditorAction(element, lineNumber); } } return null; } @SuppressWarnings("unchecked") @Override public <T> T getAdapter(Class<T> adapter) { if (ITestElementResolver.class.equals(adapter)) { return (T) this; } else { return super.getAdapter(adapter); } } protected final IDLTKSearchScope getSearchScope() { return SearchEngine.createSearchScope(project); } @Override public TestElementResolution resolveElement(ITestElement element) { if (element instanceof ITestCaseElement) { return resolveTestCase((ITestCaseElement) element); } else if (element instanceof ITestSuiteElement) { return resolveTestSuite((ITestSuiteElement) element); } return null; } /** * @param element * @return */ protected abstract TestElementResolution resolveTestSuite( ITestSuiteElement element); /** * @param element * @return */ protected abstract TestElementResolution resolveTestCase( ITestCaseElement element); @Override protected IPreferenceStore getPreferenceStore() { return RubyTestingPlugin.getDefault().getPreferenceStore(); } /* * @see org.eclipse.dltk.testing.AbstractTestRunnerUI#canFilterStack() */ @Override public boolean canFilterStack() { return true; } @Override public String filterStackTrace(String trace) { BufferedReader reader = new BufferedReader(new StringReader(trace)); try { StringWriter stringWriter = new StringWriter(); PrintWriter printer = new PrintWriter(stringWriter); String line; // first line contains the thrown exception line = reader.readLine(); if (line != null) { printer.println(line); // the stack frames of the trace while ((line = reader.readLine()) != null) { if (isStackFrame(line)) { if (selectLine(line)) { printer.println(line); } } else { printer.println(line); } } } return stringWriter.toString(); } catch (IOException e) { // should not happen actually return trace; } } /** * Tests if the specified line should pass thru the filter. * * @param line * @return */ protected boolean selectLine(String line) { return true; } protected String extractFileName(String line) { Matcher matcher = STACK_FRAME_PATTERN.matcher(line); boolean matches = matcher.matches(); if (!matches) { matcher = STACK_FRAME_IN_PATTERN.matcher(line); matches = matcher.matches(); } if (matches) { return matcher.group(1); } else { return null; } } @Override public ITestingEngine getTestingEngine() { return testingEngine; } @Override public IScriptProject getProject() { return project; } }