test discovery (initial)

This commit is contained in:
Anna Kozlova
2015-07-16 12:53:11 +03:00
parent 5cb838e435
commit 73f043718e
20 changed files with 1465 additions and 5 deletions
+9
View File
@@ -17,6 +17,15 @@
<orderEntry type="module" module-name="java-impl" />
<orderEntry type="module" module-name="java-indexing-api" />
<orderEntry type="module" module-name="smRunner" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../../lib/testDiscoveryInstrumenter.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
<component name="copyright">
<Base>
@@ -0,0 +1,37 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.JavaRunConfigurationModule;
import com.intellij.execution.configurations.ModuleBasedConfiguration;
import com.intellij.execution.configurations.RefactoringListenerProvider;
import com.intellij.execution.testframework.sm.runner.SMRunnerConsolePropertiesProvider;
import org.jetbrains.annotations.NotNull;
public abstract class JavaTestConfigurationBase extends ModuleBasedConfiguration<JavaRunConfigurationModule>
implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider, SMRunnerConsolePropertiesProvider {
public JavaTestConfigurationBase(String name,
@NotNull JavaRunConfigurationModule configurationModule,
@NotNull ConfigurationFactory factory) {
super(name, configurationModule, factory);
}
public JavaTestConfigurationBase(JavaRunConfigurationModule configurationModule,
ConfigurationFactory factory) {
super(configurationModule, factory);
}
}
@@ -0,0 +1,184 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.execution.ui.AlternativeJREPanel;
import com.intellij.execution.ui.CommonJavaParametersPanel;
import com.intellij.execution.ui.ConfigurationModuleSelector;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.ui.PanelWithAnchor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> extends SettingsEditor<T> implements PanelWithAnchor {
private final ConfigurationModuleSelector myModuleSelector;
// Fields
private JPanel myWholePanel = new JPanel(new BorderLayout());
private LabeledComponent<JComboBox> myModule = new LabeledComponent<JComboBox>();
private CommonJavaParametersPanel myCommonJavaParameters = new CommonJavaParametersPanel();
private AlternativeJREPanel myAlternativeJREPanel = new AlternativeJREPanel();
private JTextField myPosition = new JTextField();
private ComboBox myChangeLists = new ComboBox();
private JRadioButton myPositionRb = new JRadioButton("Tests for method:");
private JRadioButton myChangesRb = new JRadioButton("Tests for change list:");
private JComponent anchor;
public TestDiscoveryConfigurable(final Project project) {
myModule.setText("Use classpath of");
myModule.setLabelLocation(BorderLayout.WEST);
myModule.setComponent(new JComboBox());
myModuleSelector = new ConfigurationModuleSelector(project, getModulesComponent());
myCommonJavaParameters.setModuleContext(myModuleSelector.getModule());
myCommonJavaParameters.setHasModuleMacro();
myModule.getComponent().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myCommonJavaParameters.setModuleContext(myModuleSelector.getModule());
}
});
final JPanel panelWithSettings = new JPanel(new GridBagLayout());
final GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 0,
GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
panelWithSettings.add(myPositionRb, gc);
panelWithSettings.add(myPosition, gc);
panelWithSettings.add(myChangesRb, gc);
panelWithSettings.add(myChangeLists, gc);
ButtonGroup gr = new ButtonGroup();
gr.add(myPositionRb);
gr.add(myChangesRb);
final ActionListener l = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateComponents();
}
};
myPositionRb.addActionListener(l);
myChangesRb.addActionListener(l);
final java.util.List<LocalChangeList> changeLists = ChangeListManager.getInstance(project).getChangeLists();
final DefaultComboBoxModel model = new DefaultComboBoxModel();
model.addElement("All");
for (LocalChangeList changeList : changeLists) {
model.addElement(changeList.getName());
}
myChangeLists.setModel(model);
ChangeListManager changeListManager = ChangeListManager.getInstance(project);
if (changeListManager.getAffectedFiles().isEmpty()) {
myChangesRb.setEnabled(false);
}
myWholePanel.add(panelWithSettings, BorderLayout.NORTH);
myWholePanel.add(myCommonJavaParameters, BorderLayout.CENTER);
final JPanel classpathPanel = new JPanel(new BorderLayout());
myWholePanel.add(classpathPanel, BorderLayout.SOUTH);
classpathPanel.add(myModule, BorderLayout.NORTH);
classpathPanel.add(myAlternativeJREPanel, BorderLayout.CENTER);
UIUtil.setEnabled(myCommonJavaParameters.getProgramParametersComponent(), false, true);
setAnchor(myModule.getLabel());
myAlternativeJREPanel.setAnchor(myModule.getLabel());
myCommonJavaParameters.setAnchor(myModule.getLabel());
}
private void updateComponents() {
myPosition.setEnabled(myPositionRb.isSelected());
myChangeLists.setEnabled(myChangesRb.isSelected());
}
public void applyEditorTo(final TestDiscoveryConfiguration configuration) {
applyHelpersTo(configuration);
configuration.setAlternativeJrePath(myAlternativeJREPanel.getPath());
configuration.setAlternativeJrePathEnabled(myAlternativeJREPanel.isPathEnabled());
configuration.setPosition(myPositionRb.isSelected() ? myPosition.getText() : null);
if (myChangesRb.isSelected()) {
final Object selectedItem = myChangeLists.getSelectedItem();
configuration.setChangeList("All".equals(selectedItem) ? null : (String)selectedItem);
}
else {
configuration.setChangeList(null);
}
myCommonJavaParameters.applyTo(configuration);
}
public void resetEditorFrom(final TestDiscoveryConfiguration configuration) {
myCommonJavaParameters.reset(configuration);
getModuleSelector().reset(configuration);
myAlternativeJREPanel.init(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled());
final String position = configuration.getPosition();
if (position != null) {
myPositionRb.setSelected(true);
myPosition.setText(position);
}
else if (myChangesRb.isEnabled()) {
myChangesRb.setSelected(true);
}
else {
myPositionRb.setSelected(true);
}
final String changeList = configuration.getChangeList();
if (changeList != null) {
myChangeLists.setSelectedItem(changeList);
}
else if (myChangesRb.isEnabled()) {
myChangeLists.setSelectedIndex(0);
}
updateComponents();
}
public JComboBox getModulesComponent() {
return myModule.getComponent();
}
public ConfigurationModuleSelector getModuleSelector() {
return myModuleSelector;
}
@Override
public JComponent getAnchor() {
return anchor;
}
@Override
public void setAnchor(JComponent anchor) {
this.anchor = anchor;
}
@NotNull
public JComponent createEditor() {
return myWholePanel;
}
private void applyHelpersTo(final TestDiscoveryConfiguration currentState) {
myCommonJavaParameters.applyTo(currentState);
getModuleSelector().applyTo(currentState);
}
}
@@ -0,0 +1,212 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.diagnostic.logging.LogConfigurationPanel;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBase {
private String myChangeList;
private String myPosition;
protected JavaTestConfigurationBase myDelegate;
public TestDiscoveryConfiguration(String name,
@NotNull JavaRunConfigurationModule configurationModule,
@NotNull ConfigurationFactory factory,
JavaTestConfigurationBase delegate) {
super(name, configurationModule, factory);
myDelegate = delegate;
}
@Override
public void setVMParameters(String value) {
myDelegate.setVMParameters(value);
}
@Override
public String getVMParameters() {
return myDelegate.getVMParameters();
}
@Override
public boolean isAlternativeJrePathEnabled() {
return myDelegate.isAlternativeJrePathEnabled();
}
@Override
public void setAlternativeJrePathEnabled(boolean enabled) {
myDelegate.setAlternativeJrePathEnabled(enabled);
}
@Override
@Nullable
public String getAlternativeJrePath() {
return myDelegate.getAlternativeJrePath();
}
@Override
public void setAlternativeJrePath(String path) {
myDelegate.setAlternativeJrePath(path);
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
if (myPosition == null &&
myChangeList != null && ChangeListManager.getInstance(getProject()).findChangeList(myChangeList) == null) {
throw new RuntimeConfigurationException("Change list " + myChangeList + " doesn't exist");
}
if (myPosition != null && !myPosition.contains(",")) {
throw new RuntimeConfigurationException("Wrong position format: className,methodName expected");
}
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
}
@Override
public Collection<Module> getValidModules() {
return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
}
@NotNull
@Override
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
SettingsEditorGroup<TestDiscoveryConfiguration> group = new SettingsEditorGroup<TestDiscoveryConfiguration>();
group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"),
new TestDiscoveryConfigurable<TestDiscoveryConfiguration>(getProject()));
JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<TestDiscoveryConfiguration>());
return group;
}
@Override
public void readExternal(Element element) throws InvalidDataException {
myDelegate.readExternal(element);
super.readExternal(element);
readModule(element);
myPosition = element.getAttributeValue("position");
myChangeList = element.getAttributeValue("changeList");
if ("All".equals(myChangeList)) {
myChangeList = null;
}
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
myDelegate.writeExternal(element);
super.writeExternal(element);
writeModule(element);
if (myPosition != null) {
element.setAttribute("position", myPosition);
}
element.setAttribute("changeList", myChangeList == null ? "All" : myChangeList);
}
@Nullable
@Override
public String getRunClass() {
return null;
}
@Nullable
@Override
public String getPackage() {
return null;
}
@Override
public void setProgramParameters(@Nullable String value) {
myDelegate.setProgramParameters(value);
}
@Override
@Nullable
public String getProgramParameters() {
return myDelegate.getProgramParameters();
}
@Override
public void setWorkingDirectory(@Nullable String value) {
myDelegate.setWorkingDirectory(value);
}
@Override
@Nullable
public String getWorkingDirectory() {
return myDelegate.getWorkingDirectory();
}
@Override
public void setEnvs(@NotNull Map<String, String> envs) {
myDelegate.setEnvs(envs);
}
@Override
@NotNull
public Map<String, String> getEnvs() {
return myDelegate.getEnvs();
}
@Override
public void setPassParentEnvs(boolean passParentEnvs) {
myDelegate.setPassParentEnvs(passParentEnvs);
}
@Override
public boolean isPassParentEnvs() {
return myDelegate.isPassParentEnvs();
}
@Override
public SMTRunnerConsoleProperties createTestConsoleProperties(Executor executor) {
return myDelegate.createTestConsoleProperties(executor);
}
public void setPosition(String position) {
myPosition = position;
}
public void setChangeList(String changeList) {
myChangeList = changeList;
}
public String getPosition() {
return myPosition;
}
public String getChangeList() {
return myChangeList;
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.junit.JavaRunConfigurationProducerBase;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testIntegration.TestFramework;
import java.io.IOException;
import java.util.Collection;
public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigurationProducerBase<TestDiscoveryConfiguration> {
protected TestDiscoveryConfigurationProducer(ConfigurationType type) {
super(type);
}
@Override
protected boolean setupConfigurationFromContext(TestDiscoveryConfiguration configuration,
ConfigurationContext configurationContext,
Ref<PsiElement> ref) {
final Location contextLocation = configurationContext.getLocation();
assert contextLocation != null;
final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
if (location == null) return false;
final String position = getPosition(location);
if (position != null) {
try {
final Collection<String> testsByMethodName = TestDiscoveryIndex
.getInstance(configuration.getProject()).getTestsByMethodName(position.replace(',', '.'));
if (testsByMethodName == null || testsByMethodName.isEmpty()) return false;
}
catch (IOException e) {
return false;
}
configuration.setPosition(position);
configuration.setName("Tests for " + StringUtil.getShortName(position));
setupPackageConfiguration(configurationContext, configuration, TestSearchScope.MODULE_WITH_DEPENDENCIES);
return true;
}
return false;
}
private static String getPosition(Location location) {
final PsiElement psiElement = location.getPsiElement();
final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(psiElement, PsiMethod.class);
if (psiMethod != null) {
final PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass != null) {
final TestFramework testFramework = TestFrameworks.detectFramework(containingClass);
if (testFramework != null) {
return null;
}
final String qualifiedName = containingClass.getQualifiedName();
if (qualifiedName != null) {
return qualifiedName + "," + psiMethod.getName();
}
}
}
return null;
}
@Override
public boolean isConfigurationFromContext(TestDiscoveryConfiguration configuration, ConfigurationContext configurationContext) {
final String position = getPosition(configurationContext.getLocation());
return position != null && position.equals(configuration.getPosition());
}
}
@@ -0,0 +1,136 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.execution.JavaTestConfigurationBase;
import com.intellij.execution.RunConfigurationExtension;
import com.intellij.execution.TestDiscoveryListener;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.PathUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.testme.instrumentation.ProjectData;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
public class TestDiscoveryExtension extends RunConfigurationExtension {
private static final Logger LOG = Logger.getInstance("#" + TestDiscoveryExtension.class.getName());
@Nullable
public SettingsEditor createEditor(@NotNull RunConfigurationBase configuration) {
return null;
}
@Nullable
public String getEditorTitle() {
return null;
}
@NotNull
@Override
public String getSerializationId() {
return "testDiscovery";
}
@Override
protected void attachToProcess(@NotNull final RunConfigurationBase configuration,
@NotNull final ProcessHandler handler,
@Nullable RunnerSettings runnerSettings) {
if (runnerSettings == null && isApplicableFor(configuration)) {
handler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
final String tracesDirectory = getTracesDirectory(configuration);
final TestDiscoveryIndex coverageIndex = TestDiscoveryIndex.getInstance(configuration.getProject());
final File[] testMethodTraces = new File(tracesDirectory).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".tr");
}
});
if (testMethodTraces != null) {
for (File testMethodTrace : testMethodTraces) {
try {
coverageIndex.updateFromTestTrace(testMethodTrace);
FileUtil.delete(testMethodTrace);
}
catch (IOException e) {
LOG.error("Can not load " + testMethodTrace, e);
}
}
}
handler.removeProcessListener(this);
}
});
}
}
public void updateJavaParameters(RunConfigurationBase configuration, JavaParameters params, RunnerSettings runnerSettings) {
if (runnerSettings != null || !isApplicableFor(configuration)) {
return;
}
StringBuilder argument = new StringBuilder("-javaagent:");
final String agentPath = PathUtil.getJarPathForClass(ProjectData.class);//todo spaces
argument.append(agentPath);
params.getVMParametersList().add(argument.toString());
params.getClassPath().add(agentPath);
params.getVMParametersList().addProperty(ProjectData.TRACE_DIR, getTracesDirectory(configuration));
}
@NotNull
private static String getTracesDirectory(RunConfigurationBase configuration) {
return baseTestDiscoveryPathForProject(configuration.getProject()) + File.separator + configuration.getUniqueID();
}
@Override
public boolean isListenerDisabled(RunConfigurationBase configuration, Object listener, RunnerSettings runnerSettings) {
return !(listener instanceof TestDiscoveryListener) || runnerSettings != null;
}
@Override
public void readExternal(@NotNull final RunConfigurationBase runConfiguration, @NotNull Element element) throws InvalidDataException {}
@Override
public void writeExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws WriteExternalException {
throw new WriteExternalException();
}
protected boolean isApplicableFor(@NotNull final RunConfigurationBase configuration) {
return configuration instanceof JavaTestConfigurationBase && Registry.is("testDiscovery.enabled");
}
@NotNull
public static String baseTestDiscoveryPathForProject(Project project) {
return PathManager.getSystemPath() + File.separator + "testDiscovery" + File.separator + project.getName() + "." + project.getLocationHash();
}
}
@@ -0,0 +1,345 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
import com.intellij.util.io.*;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.io.DataOutputStream;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
/**
* Created by Maxim.Mossienko on 7/9/2015.
*/
public class TestDiscoveryIndex implements ProjectComponent {
private static final String REMOVED_MARKER = "-removed-";
private final Object ourLock = new Object();
private final Project myProject;
private volatile Holder myHolder;
public TestDiscoveryIndex(Project project) {
myProject = project;
}
public Collection<String> getTestsByMethodName(String fqmethodName) throws IOException {
synchronized (ourLock) {
return getHolder().myMethodQNameToTestNames.get(fqmethodName);
}
}
private Holder getHolder() {
Holder holder = myHolder;
if (holder == null) {
synchronized (ourLock) {
holder = myHolder;
if (holder == null) holder = myHolder = new Holder();
}
}
return holder;
}
public static TestDiscoveryIndex getInstance(Project project) {
return project.getComponent(TestDiscoveryIndex.class);
}
@Override
public void initComponent() {}
@Override
public void disposeComponent() {
synchronized (ourLock) {
Holder holder = myHolder;
if (holder != null) {
holder.dispose();
myHolder = null;
}
}
}
@NotNull
@Override
public String getComponentName() {
return getClass().getName();
}
@Override
public void projectOpened() {}
@Override
public void projectClosed() {}
private final class Holder {
final PersistentHashMap<String, Collection<String>> myMethodQNameToTestNames;
final PersistentHashMap<String, Map<String, List<String>>> myTestNameToUsedClassesAndMethodMap;
private ScheduledFuture<?> myFlushingFuture;
private boolean myDisposed;
Holder() {
String path = myProject != null ?
TestDiscoveryExtension.baseTestDiscoveryPathForProject(myProject) :
"out";
final File methodQNameToTestNameFile = new File(path + File.separator + "methodQNameToTestName.data");
final File testNameToUsedClassesAndMethodMapFile = new File(path + File.separator + "testToCalledMethodNames");
try {
// todo better io recovery
myMethodQNameToTestNames = IOUtil.openCleanOrResetBroken(
new ThrowableComputable<PersistentHashMap<String, Collection<String>>, IOException>() {
@Override
public PersistentHashMap<String, Collection<String>> compute() throws IOException {
return new PersistentHashMap<String, Collection<String>>(
methodQNameToTestNameFile,
EnumeratorStringDescriptor.INSTANCE,
new DataExternalizer<Collection<String>>() {
public void save(@NotNull DataOutput dataOutput, Collection<String> strings) throws IOException {
for (String string : strings) IOUtil.writeUTF(dataOutput, string);
}
public Collection<String> read(@NotNull DataInput dataInput) throws IOException {
Set<String> result = new THashSet<String>();
while (((InputStream)dataInput).available() > 0) {
String string = IOUtil.readUTF(dataInput);
if (REMOVED_MARKER.equals(string)) {
string = IOUtil.readUTF(dataInput);
result.remove(string);
}
else {
result.add(string);
}
}
return result;
}
}
);
}
}, methodQNameToTestNameFile);
myTestNameToUsedClassesAndMethodMap = IOUtil.openCleanOrResetBroken(
new ThrowableComputable<PersistentHashMap<String, Map<String, List<String>>>, IOException>() {
@Override
public PersistentHashMap<String, Map<String, List<String>>> compute() throws IOException {
return new PersistentHashMap<String, Map<String, List<String>>>(
testNameToUsedClassesAndMethodMapFile,
EnumeratorStringDescriptor.INSTANCE,
new DataExternalizer<Map<String, List<String>>>() {
public void save(@NotNull DataOutput dataOutput, Map<String, List<String>> classAndMethodsMap)
throws IOException {
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream();
Deflater deflater = new Deflater(1);
DataOutputStream dataOutputStream =
new DataOutputStream(new BufferedOutputStream(new DeflaterOutputStream(out, deflater)));
DataInputOutputUtil.writeINT(dataOutputStream, classAndMethodsMap.size());
for (Map.Entry<String, List<String>> e : classAndMethodsMap.entrySet()) {
IOUtil.writeUTF(dataOutputStream, e.getKey());
DataInputOutputUtil.writeINT(dataOutputStream, e.getValue().size());
for (String methodName : e.getValue()) IOUtil.writeUTF(dataOutputStream, methodName);
}
dataOutputStream.close();
deflater.end();
dataOutput.write(out.getInternalBuffer(), 0, out.size());
}
public Map<String, List<String>> read(@NotNull DataInput dataInput) throws IOException {
byte[] buf;
dataInput.readFully(buf = new byte[((InputStream)dataInput).available()]);
DataInputStream dataInputStream =
new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(buf)));
int numberOfClasses = DataInputOutputUtil.readINT(dataInputStream);
THashMap<String, List<String>> result = new THashMap<String, List<String>>(numberOfClasses);
while (numberOfClasses-- > 0) {
String className = IOUtil.readUTF(dataInputStream);
int numberOfMethods = DataInputOutputUtil.readINT(dataInputStream);
ArrayList<String> methods = new ArrayList<String>(numberOfMethods);
while (numberOfMethods-- > 0) methods.add(IOUtil.readUTF(dataInputStream));
result.put(className, methods);
}
dataInputStream.close();
return result;
}
}
);
}
}, testNameToUsedClassesAndMethodMapFile);
myFlushingFuture = FlushingDaemon.everyFiveSeconds(new Runnable() {
@Override
public void run() {
synchronized (ourLock) {
if (myDisposed) {
myFlushingFuture.cancel(false);
return;
}
if (myMethodQNameToTestNames.isDirty()) {
myMethodQNameToTestNames.force();
}
if (myTestNameToUsedClassesAndMethodMap.isDirty()) {
myTestNameToUsedClassesAndMethodMap.force();
}
}
}
});
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
void dispose() {
assert Thread.holdsLock(ourLock);
try {
myMethodQNameToTestNames.close();
myTestNameToUsedClassesAndMethodMap.close();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
myDisposed = true;
}
}
}
public void updateFromTestTrace(File file) throws IOException {
synchronized (ourLock) {
int fileNameDotIndex = file.getName().lastIndexOf('.');
final String testName = fileNameDotIndex != -1 ? file.getName().substring(0, fileNameDotIndex) : file.getName();
Holder holder = getHolder();
if (holder.myDisposed) return;
Map<String, List<String>> classData = loadClassAndMethodsMap(file);
Map<String, List<String>> previousClassData = holder.myTestNameToUsedClassesAndMethodMap.get(testName);
ValueDiff valueDiff = new ValueDiff(classData, previousClassData);
if (valueDiff.myRemovedClassData != null && !valueDiff.myRemovedClassData.isEmpty()) {
for(String classQName: valueDiff.myRemovedClassData.keySet()) {
for(String methodName: valueDiff.myRemovedClassData.get(classQName)) {
holder.myMethodQNameToTestNames.appendData(classQName + "." + methodName,
new PersistentHashMap.ValueDataAppender() {
@Override
public void append(DataOutput dataOutput) throws IOException {
IOUtil.writeUTF(dataOutput, REMOVED_MARKER);
IOUtil.writeUTF(dataOutput, testName);
}
}
);
}
}
}
if (valueDiff.myAddedOrChangedClassData != null && !valueDiff.myAddedOrChangedClassData.isEmpty()) {
for(String classQName: valueDiff.myAddedOrChangedClassData.keySet()) {
for(String methodName: valueDiff.myAddedOrChangedClassData.get(classQName)) {
holder.myMethodQNameToTestNames.appendData(classQName + "." + methodName,
new PersistentHashMap.ValueDataAppender() {
@Override
public void append(DataOutput dataOutput) throws IOException {
IOUtil.writeUTF(dataOutput, testName);
}
});
}
}
}
if (valueDiff.myAddedOrChangedClassData != null && !valueDiff.myAddedOrChangedClassData.isEmpty() ||
valueDiff.myRemovedClassData != null && !valueDiff.myRemovedClassData.isEmpty()
) {
holder.myTestNameToUsedClassesAndMethodMap.put(testName, classData);
}
}
}
static class ValueDiff {
final Map<String, List<String>> myAddedOrChangedClassData;
final Map<String, List<String>> myRemovedClassData;
ValueDiff(Map<String, List<String>> classData, Map<String, List<String>> previousClassData) {
Map<String, List<String>> addedOrChangedClassData = classData;
Map<String, List<String>> removedClassData = previousClassData;
if (previousClassData != null && !previousClassData.isEmpty()) {
removedClassData = new THashMap<String, List<String>>();
addedOrChangedClassData = new THashMap<String, List<String>>();
for(String classQName: classData.keySet()) {
List<String> currentMethods = classData.get(classQName);
List<String> previousMethods = previousClassData.get(classQName);
if (previousMethods == null) {
addedOrChangedClassData.put(classQName, currentMethods);
continue;
}
THashSet<String> previousMethodsSet = new THashSet<String>(previousMethods);
THashSet<String> currentMethodsSet = new THashSet<String>(currentMethods);
currentMethodsSet.removeAll(previousMethods);
previousMethodsSet.removeAll(currentMethods);
if (!currentMethodsSet.isEmpty()) {
addedOrChangedClassData.put(classQName, new ArrayList<String>(currentMethodsSet));
}
if (!previousMethodsSet.isEmpty()) {
removedClassData.put(classQName, new ArrayList<String>(previousMethodsSet));
}
}
for(String classQName: previousClassData.keySet()) {
if (classData.containsKey(classQName)) continue;
List<String> previousMethods = previousClassData.get(classQName);
removedClassData.put(classQName, previousMethods);
}
}
myAddedOrChangedClassData = addedOrChangedClassData;
myRemovedClassData = removedClassData;
}
}
@NotNull
private static Map<String, List<String>> loadClassAndMethodsMap(File file) throws IOException {
DataInputStream inputStream = new DataInputStream(new InflaterInputStream(new BufferedInputStream(new FileInputStream(file))));
try {
int numberOfClasses = inputStream.readInt();
Map<String, List<String>> classData = new THashMap<String, List<String>>();
while (numberOfClasses-- > 0) {
String classQName = inputStream.readUTF();
int numberOfMethods = inputStream.readInt();
List<String> methodsList;
classData.put(classQName, methodsList = new ArrayList<String>(numberOfMethods));
//System.out.println(classQName + "," + numberOfMethods);
while (numberOfMethods-- > 0) {
String methodName = inputStream.readUTF();
methodsList.add(methodName);
//System.out.println(methodName);
}
}
return classData;
} finally {
inputStream.close();
}
}
}
@@ -0,0 +1,161 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.testDiscovery;
import com.intellij.codeInsight.actions.FormatChangedTextUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.testframework.SearchForTestsTask;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.*;
public abstract class TestDiscoverySearchTask extends SearchForTestsTask {
private final String myPosition;
private final String myChangeList;
public TestDiscoverySearchTask(Project project, ServerSocket socket, String position, String changeList) {
super(project, socket);
myPosition = position;
myChangeList = changeList;
}
protected abstract void writeFoundPatterns(Set<String> patterns) throws ExecutionException;
@Override
protected void search() throws ExecutionException {
final Project project = getProject();
final Set<String> patterns = new LinkedHashSet<String>();
if (myPosition != null) {
try {
final Collection<String> testsByMethodName = TestDiscoveryIndex
.getInstance(project).getTestsByMethodName(myPosition.replace(',', '.'));
if (testsByMethodName != null) {
for (String pattern : testsByMethodName) {
patterns.add(pattern.replace('-', ','));
}
}
}
catch (IOException ignore) {
}
}
else {
final List<VirtualFile> files = getAffectedFiles();
final PsiManager psiManager = PsiManager.getInstance(project);
for (final VirtualFile file : files) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile != null) {
try {
final List<TextRange> changedTextRanges = FormatChangedTextUtil.getChangedTextRanges(project, psiFile);
for (TextRange textRange : changedTextRanges) {
final PsiElement start = psiFile.findElementAt(textRange.getStartOffset());
final PsiElement end = psiFile.findElementAt(textRange.getEndOffset());
final PsiElement parent = PsiTreeUtil.findCommonParent(new PsiElement[]{start, end});
final Collection<PsiMethod> methods = new ArrayList<PsiMethod>(
PsiTreeUtil.findChildrenOfType(parent, PsiMethod.class));
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
if (containingMethod != null) {
methods.add(containingMethod);
}
for (PsiMethod changedMethod : methods) {
final LinkedHashSet<String> detectedPatterns = collectPatterns(changedMethod);
if (detectedPatterns != null) {
patterns.addAll(detectedPatterns);
}
}
}
}
catch (FilesTooBigForDiffException ignore) {
}
}
}
});
}
}
writeFoundPatterns(patterns);
}
@NotNull
private List<VirtualFile> getAffectedFiles() {
final ChangeListManager changeListManager = ChangeListManager.getInstance(getProject());
if (myChangeList == null) {
return changeListManager.getAffectedFiles();
}
final LocalChangeList changeList = changeListManager.findChangeList(myChangeList);
if (changeList != null) {
List<VirtualFile> files = new ArrayList<VirtualFile>();
for (Change change : changeList.getChanges()) {
final ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision != null) {
final VirtualFile file = afterRevision.getFile().getVirtualFile();
if (file != null) {
files.add(file);
}
}
}
return files;
}
return Collections.emptyList();
}
@Override
protected void onFound() {
}
@Nullable
protected static LinkedHashSet<String> collectPatterns(PsiMethod psiMethod) {
LinkedHashSet<String> patterns = new LinkedHashSet<String>();
final PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass != null) {
final String qualifiedName = containingClass.getQualifiedName();
if (qualifiedName != null) {
final String methodFQN = StringUtil.getQualifiedName(qualifiedName, psiMethod.getName());
try {
final Collection<String> testsByMethodName
= TestDiscoveryIndex.getInstance(containingClass.getProject()).getTestsByMethodName(methodFQN);
if (testsByMethodName != null) {
for (String pattern : testsByMethodName) {
patterns.add(pattern.replace('-', ','));
}
}
}
catch (IOException e) {
return null;
}
}
}
return patterns;
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution;
import java.lang.reflect.Method;
public class TestDiscoveryListener {
public void testStarted(String className, String methodName) {
final Object data = getData();
try {
Method testStarted = data.getClass().getMethod("testStarted", new Class[] {String.class});
testStarted.invoke(data, new Object[] {className + "-" + methodName});
} catch (Throwable t) {
t.printStackTrace();
}
}
public void testFinished(String className, String methodName) {
final Object data = getData();
try {
Method testEnded = data.getClass().getMethod("testEnded", new Class[] {String.class});
testEnded.invoke(data, new Object[] {className + "-" + methodName});
} catch (Throwable t) {
t.printStackTrace();
}
}
protected Object getData() {
try {
return Class.forName("org.jetbrains.testme.instrumentation.ProjectData")
.getMethod("getProjectData", new Class[0])
.invoke(null, new Object[0]);
} catch (Exception e) {
return null; //should not happen
}
}
}
+1
View File
@@ -65,6 +65,7 @@ snappy-in-java-0.3.1.jar
swingx-core-1.6.2.jar
slf4j-api-1.7.10.jar
slf4j-log4j12-1.7.10.jar
testDiscoveryInstrumenter.jar
trove4j.jar
velocity.jar
winp-1.23.jar
Binary file not shown.
@@ -626,4 +626,5 @@ dart.server.additional.arguments=
dart.server.driven.resolution=false
editor.breadcrumbs.highlight.on.hover=false
editor.breadcrumbs.highlight.on.hover.description=Highlight corresponding ranges in editor on breadcrumb item hover (requires project reopening)
editor.breadcrumbs.highlight.on.hover.description=Highlight corresponding ranges in editor on breadcrumb item hover (requires project reopening)
testDiscovery.enabled=true
+3
View File
@@ -61,6 +61,9 @@
<programRunner implementation="com.intellij.execution.junit.JUnitDebuggerRunner"/>
<codeInsight.unresolvedReferenceQuickFixProvider implementation="com.intellij.execution.junit.codeInsight.JUnitUnresolvedReferenceQuickFixProvider"/>
<junitListener implementation="com.intellij.junit4.JUnitTestDiscoveryListener"/>
<configurationType implementation="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationType"/>
<runConfigurationProducer implementation="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer"/>
</extensions>
<extensionPoints>
@@ -51,8 +51,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.*;
public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider, SMRunnerConsolePropertiesProvider {
public class JUnitConfiguration extends JavaTestConfigurationBase {
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
@NonNls public static final String TEST_CLASS = "class";
@@ -0,0 +1,108 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.junit.testDiscovery;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.JUnitConfigurationType;
import com.intellij.execution.junit.TestObject;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testDiscovery.TestDiscoveryConfiguration;
import com.intellij.execution.testDiscovery.TestDiscoverySearchTask;
import com.intellij.execution.testframework.SearchForTestsTask;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.util.FunctionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class JUnitTestDiscoveryConfiguration extends TestDiscoveryConfiguration {
public JUnitTestDiscoveryConfiguration(String name, Project project, ConfigurationFactory factory) {
super(name, new JavaRunConfigurationModule(project, false), factory,
new JUnitConfiguration("", project, JUnitConfigurationType.getInstance().getConfigurationFactories()[0]));
}
@Override
protected ModuleBasedConfiguration createInstance() {
final JUnitTestDiscoveryConfigurationType configurationType =
ConfigurationTypeUtil.findConfigurationType(JUnitTestDiscoveryConfigurationType.class);
final ConfigurationFactory[] factories = configurationType.getConfigurationFactories();
return new JUnitTestDiscoveryConfiguration(getName(), getProject(), factories[0]);
}
@Nullable
@Override
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException {
return new JUnitTestDiscoveryRunnableState(environment);
}
@Nullable
@Override
public RefactoringElementListener getRefactoringElementListener(PsiElement element) {
return null;
}
private class JUnitTestDiscoveryRunnableState extends TestObject {
public JUnitTestDiscoveryRunnableState(ExecutionEnvironment environment) {
super(((JUnitConfiguration)myDelegate), environment);
}
@Override
public SearchForTestsTask createSearchingForTestsTask() {
return new TestDiscoverySearchTask(getProject(), myServerSocket, getPosition(), getChangeList()) {
@Override
protected void writeFoundPatterns(Set<String> patterns) throws ExecutionException {
addClassesListToJavaParameters(patterns, FunctionUtil.<String>id(), "", false, getJavaParameters());
}
};
}
@Override
protected JavaParameters createJavaParameters() throws ExecutionException {
final JavaParameters javaParameters = super.createJavaParameters();
createTempFiles(javaParameters);
createServerSocket(javaParameters);
return javaParameters;
}
@Override
public String suggestActionName() {
return "";
}
@Override
public RefactoringElementListener getListener(PsiElement element, JUnitConfiguration configuration) {
return null;
}
@Override
public boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
PsiPackage testPackage,
PsiDirectory testDir) {
return false;
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.junit.testDiscovery;
import com.intellij.execution.configurations.ConfigurationTypeUtil;
import com.intellij.execution.testDiscovery.TestDiscoveryConfigurationProducer;
public class JUnitTestDiscoveryConfigurationProducer extends TestDiscoveryConfigurationProducer {
protected JUnitTestDiscoveryConfigurationProducer() {
super(ConfigurationTypeUtil.findConfigurationType(JUnitTestDiscoveryConfigurationType.class));
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.junit.testDiscovery;
import com.intellij.execution.configuration.ConfigurationFactoryEx;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.configurations.ModuleBasedConfiguration;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.testDiscovery.TestDiscoveryConfiguration;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class JUnitTestDiscoveryConfigurationType implements ConfigurationType {
private final ConfigurationFactory myFactory;
public JUnitTestDiscoveryConfigurationType() {
myFactory = new ConfigurationFactoryEx(this) {
public RunConfiguration createTemplateConfiguration(Project project) {
return new JUnitTestDiscoveryConfiguration("", project, this);
}
@Override
public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) {
((ModuleBasedConfiguration)configuration).onNewConfigurationCreated();
}
};
}
@Override
public String getDisplayName() {
return "JUnit Test Discovery";
}
@Override
public String getConfigurationTypeDescription() {
return "Runs junit tests which passed changed code";
}
@Override
public Icon getIcon() {
return AllIcons.RunConfigurations.Junit;
}
@NotNull
@Override
public String getId() {
return "JUnitTestDiscovery";
}
@Override
public ConfigurationFactory[] getConfigurationFactories() {
return new ConfigurationFactory[] {myFactory};
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.junit4;
import com.intellij.execution.TestDiscoveryListener;
import com.intellij.rt.execution.junit.IDEAJUnitListener;
public class JUnitTestDiscoveryListener extends TestDiscoveryListener implements IDEAJUnitListener {
}
@@ -58,8 +58,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider, SMRunnerConsolePropertiesProvider {
public class TestNGConfiguration extends JavaTestConfigurationBase {
@NonNls private static final String PATTERNS_EL_NAME = "patterns";
@NonNls private static final String PATTERN_EL_NAME = "pattern";
@NonNls private static final String TEST_CLASS_ATT_NAME = "testClass";
+5
View File
@@ -62,6 +62,10 @@
<interface-class>com.intellij.psi.RefResolveService</interface-class>
<implementation-class>com.intellij.psi.refResolve.RefResolveServiceImpl</implementation-class>
</component>
<component>
<implementation-class>com.intellij.execution.testDiscovery.TestDiscoveryIndex</implementation-class>
</component>
</project-components>
<extensionPoints>
@@ -1586,6 +1590,7 @@
<projectStructureDetector implementation="com.intellij.ide.util.projectWizard.importSources.impl.JavaProjectStructureDetector" order="first"/>
<applicationService serviceImplementation="com.intellij.execution.JavaRunConfigurationExtensionManager"/>
<runConfigurationExtension implementation="com.intellij.execution.testDiscovery.TestDiscoveryExtension"/>
<regExpLanguageHost forClass="com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl"
implementationClass="com.intellij.psi.impl.JavaRegExpHost"/>