blob: f83b8e1b040773b0f987c7667a98fb49903b2c87 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2016 xored software, Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* 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;
}
}