mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
test discovery (initial)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
+184
@@ -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);
|
||||
}
|
||||
}
|
||||
+212
@@ -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;
|
||||
}
|
||||
}
|
||||
+91
@@ -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());
|
||||
}
|
||||
}
|
||||
+136
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+161
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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";
|
||||
|
||||
+108
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -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));
|
||||
}
|
||||
}
|
||||
+71
@@ -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 {
|
||||
}
|
||||
+1
-2
@@ -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";
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user