mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
test discovery: set class/method separately to avoid ambiguities when working with groovy names in position part;
test method browser extracted, one for all configurations
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.configuration.BrowseModuleValueActionListener;
|
||||
import com.intellij.execution.junit.JUnitUtil;
|
||||
import com.intellij.execution.ui.ConfigurationModuleSelector;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
public abstract class MethodBrowser extends BrowseModuleValueActionListener {
|
||||
|
||||
public MethodBrowser(final Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
protected abstract String getClassName();
|
||||
protected abstract ConfigurationModuleSelector getModuleSelector();
|
||||
protected abstract Condition<PsiMethod> getFilter(PsiClass testClass);
|
||||
|
||||
protected String showDialog() {
|
||||
final String className = getClassName();
|
||||
if (className.trim().length() == 0) {
|
||||
Messages.showMessageDialog(getField(), ExecutionBundle.message("set.class.name.message"),
|
||||
ExecutionBundle.message("cannot.browse.method.dialog.title"), Messages.getInformationIcon());
|
||||
return null;
|
||||
}
|
||||
final PsiClass testClass = getModuleSelector().findClass(className);
|
||||
if (testClass == null) {
|
||||
Messages.showMessageDialog(getField(), ExecutionBundle.message("class.does.not.exists.error.message", className),
|
||||
ExecutionBundle.message("cannot.browse.method.dialog.title"),
|
||||
Messages.getInformationIcon());
|
||||
return null;
|
||||
}
|
||||
final MethodListDlg dlg = new MethodListDlg(testClass, getFilter(testClass), getField());
|
||||
if (dlg.showAndGet()) {
|
||||
final PsiMethod method = dlg.getSelected();
|
||||
if (method != null) {
|
||||
return method.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-2
@@ -14,9 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.execution.junit2.configuration;
|
||||
package com.intellij.execution;
|
||||
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.ide.structureView.impl.StructureNodeRenderer;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
+96
-7
@@ -15,16 +15,29 @@
|
||||
*/
|
||||
package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.execution.MethodBrowser;
|
||||
import com.intellij.execution.junit.JUnitUtil;
|
||||
import com.intellij.execution.ui.AlternativeJREPanel;
|
||||
import com.intellij.execution.ui.ClassBrowser;
|
||||
import com.intellij.execution.ui.CommonJavaParametersPanel;
|
||||
import com.intellij.execution.ui.ConfigurationModuleSelector;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.openapi.fileTypes.PlainTextLanguage;
|
||||
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.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.EditorTextFieldWithBrowseButton;
|
||||
import com.intellij.ui.PanelWithAnchor;
|
||||
import com.intellij.util.TextFieldCompletionProvider;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -32,6 +45,7 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> extends SettingsEditor<T> implements PanelWithAnchor {
|
||||
@@ -41,7 +55,9 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
private LabeledComponent<JComboBox> myModule = new LabeledComponent<JComboBox>();
|
||||
private CommonJavaParametersPanel myCommonJavaParameters = new CommonJavaParametersPanel();
|
||||
private AlternativeJREPanel myAlternativeJREPanel = new AlternativeJREPanel();
|
||||
private JTextField myPosition = new JTextField();
|
||||
private LabeledComponent<EditorTextFieldWithBrowseButton> myClass = new LabeledComponent<EditorTextFieldWithBrowseButton>();
|
||||
private LabeledComponent<EditorTextFieldWithBrowseButton> myMethod = new LabeledComponent<EditorTextFieldWithBrowseButton>();
|
||||
|
||||
private ComboBox myChangeLists = new ComboBox();
|
||||
private JRadioButton myPositionRb = new JRadioButton("Tests for method:");
|
||||
private JRadioButton myChangesRb = new JRadioButton("Tests for change list:");
|
||||
@@ -64,7 +80,77 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(0, 0, 0, 0), 0, 0);
|
||||
panelWithSettings.add(myPositionRb, gc);
|
||||
panelWithSettings.add(myPosition, gc);
|
||||
myClass.setText("Class:");
|
||||
final ClassBrowser classBrowser = new ClassBrowser(project, "Choose Class") {
|
||||
@Override
|
||||
protected ClassFilter.ClassFilterWithScope getFilter() throws NoFilterException {
|
||||
return new ClassFilter.ClassFilterWithScope() {
|
||||
@Override
|
||||
public GlobalSearchScope getScope() {
|
||||
return GlobalSearchScope.allScope(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass aClass) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiClass findClass(String className) {
|
||||
return JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project));
|
||||
}
|
||||
};
|
||||
final EditorTextFieldWithBrowseButton classComponent = new EditorTextFieldWithBrowseButton(project, true);
|
||||
myClass.setComponent(classComponent);
|
||||
classBrowser.setField(classComponent);
|
||||
panelWithSettings.add(myClass, gc);
|
||||
myMethod.setText("Method:");
|
||||
final EditorTextFieldWithBrowseButton textFieldWithBrowseButton = new EditorTextFieldWithBrowseButton(project, true,
|
||||
JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE,
|
||||
PlainTextLanguage.INSTANCE.getAssociatedFileType());
|
||||
new TextFieldCompletionProvider() {
|
||||
@Override
|
||||
protected void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix, @NotNull CompletionResultSet result) {
|
||||
final String className = myClass.getComponent().getText();
|
||||
if (className.trim().length() == 0) {
|
||||
return;
|
||||
}
|
||||
final PsiClass testClass = getModuleSelector().findClass(className);
|
||||
if (testClass == null) return;
|
||||
final JUnitUtil.TestMethodFilter filter = new JUnitUtil.TestMethodFilter(testClass);
|
||||
for (PsiMethod psiMethod : testClass.getAllMethods()) {
|
||||
if (filter.value(psiMethod)) {
|
||||
result.addElement(LookupElementBuilder.create(psiMethod.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}.apply(textFieldWithBrowseButton.getChildComponent());
|
||||
myMethod.setComponent(textFieldWithBrowseButton);
|
||||
final MethodBrowser methodBrowser = new MethodBrowser(project) {
|
||||
protected Condition<PsiMethod> getFilter(final PsiClass testClass) {
|
||||
return new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return method.getContainingClass() == testClass;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClassName() {
|
||||
return myClass.getComponent().getText().trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationModuleSelector getModuleSelector() {
|
||||
return myModuleSelector;
|
||||
}
|
||||
};
|
||||
methodBrowser.setField(textFieldWithBrowseButton);
|
||||
|
||||
panelWithSettings.add(myMethod, gc);
|
||||
panelWithSettings.add(myChangesRb, gc);
|
||||
panelWithSettings.add(myChangeLists, gc);
|
||||
|
||||
@@ -82,7 +168,7 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
myChangesRb.addActionListener(l);
|
||||
|
||||
|
||||
final java.util.List<LocalChangeList> changeLists = ChangeListManager.getInstance(project).getChangeLists();
|
||||
final List<LocalChangeList> changeLists = ChangeListManager.getInstance(project).getChangeLists();
|
||||
final DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||
model.addElement("All");
|
||||
for (LocalChangeList changeList : changeLists) {
|
||||
@@ -109,7 +195,8 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
}
|
||||
|
||||
private void updateComponents() {
|
||||
myPosition.setEnabled(myPositionRb.isSelected());
|
||||
myClass.setEnabled(myPositionRb.isSelected());
|
||||
myMethod.setEnabled(myPositionRb.isSelected());
|
||||
myChangeLists.setEnabled(myChangesRb.isSelected());
|
||||
}
|
||||
|
||||
@@ -117,7 +204,8 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
applyHelpersTo(configuration);
|
||||
configuration.setAlternativeJrePath(myAlternativeJREPanel.getPath());
|
||||
configuration.setAlternativeJrePathEnabled(myAlternativeJREPanel.isPathEnabled());
|
||||
configuration.setPosition(myPositionRb.isSelected() ? myPosition.getText() : null);
|
||||
configuration.setPosition(myPositionRb.isSelected() ? Pair.create(myClass.getComponent().getText().trim(),
|
||||
myMethod.getComponent().getText().trim()) : null);
|
||||
if (myChangesRb.isSelected()) {
|
||||
final Object selectedItem = myChangeLists.getSelectedItem();
|
||||
configuration.setChangeList("All".equals(selectedItem) ? null : (String)selectedItem);
|
||||
@@ -132,10 +220,11 @@ public class TestDiscoveryConfigurable<T extends TestDiscoveryConfiguration> ext
|
||||
myCommonJavaParameters.reset(configuration);
|
||||
getModuleSelector().reset(configuration);
|
||||
myAlternativeJREPanel.init(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled());
|
||||
final String position = configuration.getPosition();
|
||||
final Pair<String, String> position = configuration.getPosition();
|
||||
if (position != null) {
|
||||
myPositionRb.setSelected(true);
|
||||
myPosition.setText(position);
|
||||
myClass.getComponent().setText(position.first);
|
||||
myMethod.getComponent().setText(position.second);
|
||||
}
|
||||
else if (myChangesRb.isEnabled()) {
|
||||
myChangesRb.setSelected(true);
|
||||
|
||||
+17
-7
@@ -24,7 +24,9 @@ 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.Pair;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,7 +38,7 @@ import java.util.Map;
|
||||
|
||||
public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBase {
|
||||
private String myChangeList;
|
||||
private String myPosition;
|
||||
private Pair<String, String> myPosition;
|
||||
|
||||
protected JavaTestConfigurationBase myDelegate;
|
||||
|
||||
@@ -85,8 +87,13 @@ public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBa
|
||||
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");
|
||||
if (myPosition != null) {
|
||||
if (StringUtil.isEmptyOrSpaces(myPosition.first)) {
|
||||
throw new RuntimeConfigurationException("No class specified");
|
||||
}
|
||||
if (StringUtil.isEmptyOrSpaces(myPosition.second)) {
|
||||
throw new RuntimeConfigurationException("No method specified");
|
||||
}
|
||||
}
|
||||
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
|
||||
}
|
||||
@@ -113,7 +120,9 @@ public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBa
|
||||
super.readExternal(element);
|
||||
readModule(element);
|
||||
|
||||
myPosition = element.getAttributeValue("position");
|
||||
final String classQName = element.getAttributeValue("class");
|
||||
final String methodName = element.getAttributeValue("method");
|
||||
myPosition = classQName != null && methodName != null ? Pair.create(classQName, methodName) : null;
|
||||
myChangeList = element.getAttributeValue("changeList");
|
||||
if ("All".equals(myChangeList)) {
|
||||
myChangeList = null;
|
||||
@@ -128,7 +137,8 @@ public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBa
|
||||
writeModule(element);
|
||||
|
||||
if (myPosition != null) {
|
||||
element.setAttribute("position", myPosition);
|
||||
element.setAttribute("class", myPosition.first);
|
||||
element.setAttribute("method", myPosition.second);
|
||||
}
|
||||
element.setAttribute("changeList", myChangeList == null ? "All" : myChangeList);
|
||||
}
|
||||
@@ -194,7 +204,7 @@ public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBa
|
||||
return myDelegate.createTestConsoleProperties(executor);
|
||||
}
|
||||
|
||||
public void setPosition(String position) {
|
||||
public void setPosition(Pair<String, String> position) {
|
||||
myPosition = position;
|
||||
}
|
||||
|
||||
@@ -202,7 +212,7 @@ public abstract class TestDiscoveryConfiguration extends JavaTestConfigurationBa
|
||||
myChangeList = changeList;
|
||||
}
|
||||
|
||||
public String getPosition() {
|
||||
public Pair<String, String> getPosition() {
|
||||
return myPosition;
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -22,6 +22,7 @@ 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.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiClass;
|
||||
@@ -46,25 +47,25 @@ public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigur
|
||||
assert contextLocation != null;
|
||||
final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
|
||||
if (location == null) return false;
|
||||
final String position = getPosition(location);
|
||||
final Pair<String, String> position = getPosition(location);
|
||||
if (position != null) {
|
||||
try {
|
||||
final Collection<String> testsByMethodName = TestDiscoveryIndex
|
||||
.getInstance(configuration.getProject()).getTestsByMethodName(position.replace(',', '.'));
|
||||
.getInstance(configuration.getProject()).getTestsByMethodName(position.first, position.second);
|
||||
if (testsByMethodName == null || testsByMethodName.isEmpty()) return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
configuration.setPosition(position);
|
||||
configuration.setName("Tests for " + StringUtil.getShortName(position));
|
||||
configuration.setName("Tests for " + StringUtil.getShortName(position.first) + "," + position.second);
|
||||
setupPackageConfiguration(configurationContext, configuration, TestSearchScope.MODULE_WITH_DEPENDENCIES);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getPosition(Location location) {
|
||||
private static Pair<String, String> getPosition(Location location) {
|
||||
final PsiElement psiElement = location.getPsiElement();
|
||||
final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(psiElement, PsiMethod.class);
|
||||
if (psiMethod != null) {
|
||||
@@ -76,7 +77,7 @@ public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigur
|
||||
}
|
||||
final String qualifiedName = containingClass.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
return qualifiedName + "," + psiMethod.getName();
|
||||
return Pair.create(qualifiedName, psiMethod.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +86,7 @@ public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigur
|
||||
|
||||
@Override
|
||||
public boolean isConfigurationFromContext(TestDiscoveryConfiguration configuration, ConfigurationContext configurationContext) {
|
||||
final String position = getPosition(configurationContext.getLocation());
|
||||
final Pair<String, String> position = getPosition(configurationContext.getLocation());
|
||||
return position != null && position.equals(configuration.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
+316
-276
@@ -17,6 +17,7 @@ package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
|
||||
@@ -37,309 +38,348 @@ 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;
|
||||
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 TestDiscoveryIndex(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public Collection<String> getTestsByMethodName(String classFQName, String methodName) throws IOException {
|
||||
synchronized (ourLock) {
|
||||
return getHolder().myMethodQNameToTestNames.get(Pair.create(classFQName, methodName));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private Holder getHolder() {
|
||||
Holder holder = myHolder;
|
||||
public static TestDiscoveryIndex getInstance(Project project) {
|
||||
return project.getComponent(TestDiscoveryIndex.class);
|
||||
}
|
||||
|
||||
if (holder == null) {
|
||||
@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<Pair<String, 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<Pair<String, String>, Collection<String>>, IOException>() {
|
||||
@Override
|
||||
public PersistentHashMap<Pair<String, String>, Collection<String>> compute() throws IOException {
|
||||
return new PersistentHashMap<Pair<String, String>, Collection<String>>(
|
||||
methodQNameToTestNameFile,
|
||||
new StringPairKeyDescriptor(),
|
||||
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) {
|
||||
holder = myHolder;
|
||||
if (holder == null) holder = myHolder = new Holder();
|
||||
if (myDisposed) {
|
||||
myFlushingFuture.cancel(false);
|
||||
return;
|
||||
}
|
||||
if (myMethodQNameToTestNames.isDirty()) {
|
||||
myMethodQNameToTestNames.force();
|
||||
}
|
||||
if (myTestNameToUsedClassesAndMethodMap.isDirty()) {
|
||||
myTestNameToUsedClassesAndMethodMap.force();
|
||||
}
|
||||
}
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static TestDiscoveryIndex getInstance(Project project) {
|
||||
return project.getComponent(TestDiscoveryIndex.class);
|
||||
void dispose() {
|
||||
assert Thread.holdsLock(ourLock);
|
||||
try {
|
||||
myMethodQNameToTestNames.close();
|
||||
myTestNameToUsedClassesAndMethodMap.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
myDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initComponent() {}
|
||||
}
|
||||
|
||||
private static class StringPairKeyDescriptor implements KeyDescriptor<Pair<String, String>> {
|
||||
public static final StringPairKeyDescriptor INSTANCE = new StringPairKeyDescriptor();
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
synchronized (ourLock) {
|
||||
Holder holder = myHolder;
|
||||
if (holder != null) {
|
||||
holder.dispose();
|
||||
myHolder = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return getClass().getName();
|
||||
public void save(@NotNull DataOutput out, Pair<String, String> value) throws IOException {
|
||||
IOUtil.writeUTF(out, value.first);
|
||||
IOUtil.writeUTF(out, value.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpened() {}
|
||||
public Pair<String, String> read(@NotNull DataInput in) throws IOException {
|
||||
return Pair.create(IOUtil.readUTF(in), IOUtil.readUTF(in));
|
||||
}
|
||||
|
||||
@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 int getHashCode(Pair<String, String> value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isEqual(Pair<String, String> val1, Pair<String, String> val2) {
|
||||
return val1.equals(val2);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
static class ValueDiff {
|
||||
final Map<String, List<String>> myAddedOrChangedClassData;
|
||||
final Map<String, List<String>> myRemovedClassData;
|
||||
Holder holder = getHolder();
|
||||
if (holder.myDisposed) return;
|
||||
Map<String, List<String>> classData = loadClassAndMethodsMap(file);
|
||||
Map<String, List<String>> previousClassData = holder.myTestNameToUsedClassesAndMethodMap.get(testName);
|
||||
|
||||
ValueDiff(Map<String, List<String>> classData, Map<String, List<String>> previousClassData) {
|
||||
Map<String, List<String>> addedOrChangedClassData = classData;
|
||||
Map<String, List<String>> removedClassData = previousClassData;
|
||||
ValueDiff valueDiff = new ValueDiff(classData, 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;
|
||||
if (valueDiff.myRemovedClassData != null && !valueDiff.myRemovedClassData.isEmpty()) {
|
||||
for (String classQName : valueDiff.myRemovedClassData.keySet()) {
|
||||
for (String methodName : valueDiff.myRemovedClassData.get(classQName)) {
|
||||
holder.myMethodQNameToTestNames.appendData(createKey(classQName, methodName),
|
||||
new PersistentHashMap.ValueDataAppender() {
|
||||
@Override
|
||||
public void append(DataOutput dataOutput) throws IOException {
|
||||
IOUtil.writeUTF(dataOutput, REMOVED_MARKER);
|
||||
IOUtil.writeUTF(dataOutput, testName);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@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();
|
||||
if (valueDiff.myAddedOrChangedClassData != null && !valueDiff.myAddedOrChangedClassData.isEmpty()) {
|
||||
for (String classQName : valueDiff.myAddedOrChangedClassData.keySet()) {
|
||||
for (String methodName : valueDiff.myAddedOrChangedClassData.get(classQName)) {
|
||||
holder.myMethodQNameToTestNames.appendData(createKey(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Pair<String, String> createKey(String classQName, String methodName) {
|
||||
return Pair.create(classQName, methodName);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -20,8 +20,8 @@ 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.Pair;
|
||||
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;
|
||||
@@ -38,10 +38,10 @@ import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class TestDiscoverySearchTask extends SearchForTestsTask {
|
||||
private final String myPosition;
|
||||
private final Pair<String, String> myPosition;
|
||||
private final String myChangeList;
|
||||
|
||||
public TestDiscoverySearchTask(Project project, ServerSocket socket, String position, String changeList) {
|
||||
public TestDiscoverySearchTask(Project project, ServerSocket socket, Pair<String, String> position, String changeList) {
|
||||
super(project, socket);
|
||||
myPosition = position;
|
||||
myChangeList = changeList;
|
||||
@@ -56,7 +56,7 @@ public abstract class TestDiscoverySearchTask extends SearchForTestsTask {
|
||||
if (myPosition != null) {
|
||||
try {
|
||||
final Collection<String> testsByMethodName = TestDiscoveryIndex
|
||||
.getInstance(project).getTestsByMethodName(myPosition.replace(',', '.'));
|
||||
.getInstance(project).getTestsByMethodName(myPosition.first, myPosition.second);
|
||||
if (testsByMethodName != null) {
|
||||
for (String pattern : testsByMethodName) {
|
||||
patterns.add(pattern.replace('-', ','));
|
||||
@@ -141,10 +141,9 @@ public abstract class TestDiscoverySearchTask extends SearchForTestsTask {
|
||||
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);
|
||||
= TestDiscoveryIndex.getInstance(containingClass.getProject()).getTestsByMethodName(qualifiedName, psiMethod.getName());
|
||||
if (testsByMethodName != null) {
|
||||
for (String pattern : testsByMethodName) {
|
||||
patterns.add(pattern.replace('-', ','));
|
||||
|
||||
+17
-31
@@ -19,6 +19,7 @@ package com.intellij.execution.junit2.configuration;
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.MethodBrowser;
|
||||
import com.intellij.execution.configuration.BrowseModuleValueActionListener;
|
||||
import com.intellij.execution.junit.JUnitConfiguration;
|
||||
import com.intellij.execution.junit.JUnitConfigurationType;
|
||||
@@ -43,6 +44,7 @@ import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.*;
|
||||
import com.intellij.openapi.ui.ex.MessagesEx;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
@@ -123,7 +125,21 @@ public class JUnitConfigurable<T extends JUnitConfiguration> extends SettingsEdi
|
||||
myBrowsers = new BrowseModuleValueActionListener[]{
|
||||
new PackageChooserActionListener(project),
|
||||
new TestClassBrowser(project),
|
||||
new MethodBrowser(project),
|
||||
new MethodBrowser(project) {
|
||||
protected Condition<PsiMethod> getFilter(PsiClass testClass) {
|
||||
return new JUnitUtil.TestMethodFilter(testClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClassName() {
|
||||
return JUnitConfigurable.this.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationModuleSelector getModuleSelector() {
|
||||
return myModuleSelector;
|
||||
}
|
||||
},
|
||||
new TestsChooserActionListener(project),
|
||||
new BrowseModuleValueActionListener(project) {
|
||||
@Override
|
||||
@@ -610,36 +626,6 @@ public class JUnitConfigurable<T extends JUnitConfiguration> extends SettingsEdi
|
||||
}
|
||||
}
|
||||
|
||||
private class MethodBrowser extends BrowseModuleValueActionListener {
|
||||
public MethodBrowser(final Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
protected String showDialog() {
|
||||
final String className = getClassName();
|
||||
if (className.trim().length() == 0) {
|
||||
Messages.showMessageDialog(getField(), ExecutionBundle.message("set.class.name.message"),
|
||||
ExecutionBundle.message("cannot.browse.method.dialog.title"), Messages.getInformationIcon());
|
||||
return null;
|
||||
}
|
||||
final PsiClass testClass = getModuleSelector().findClass(className);
|
||||
if (testClass == null) {
|
||||
Messages.showMessageDialog(getField(), ExecutionBundle.message("class.does.not.exists.error.message", className),
|
||||
ExecutionBundle.message("cannot.browse.method.dialog.title"),
|
||||
Messages.getInformationIcon());
|
||||
return null;
|
||||
}
|
||||
final MethodListDlg dlg = new MethodListDlg(testClass, new JUnitUtil.TestMethodFilter(testClass), getField());
|
||||
if (dlg.showAndGet()) {
|
||||
final PsiMethod method = dlg.getSelected();
|
||||
if (method != null) {
|
||||
return method.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class CategoryBrowser extends ClassBrowser {
|
||||
public CategoryBrowser(Project project) {
|
||||
super(project, "Category Interface");
|
||||
|
||||
+29
-1
@@ -26,7 +26,9 @@ import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.execution.ExecutionBundle;
|
||||
import com.intellij.execution.JavaExecutionUtil;
|
||||
import com.intellij.execution.MethodBrowser;
|
||||
import com.intellij.execution.configuration.BrowseModuleValueActionListener;
|
||||
import com.intellij.execution.junit.JUnitUtil;
|
||||
import com.intellij.execution.testframework.TestSearchScope;
|
||||
import com.intellij.execution.ui.AlternativeJREPanel;
|
||||
import com.intellij.execution.ui.CommonJavaParametersPanel;
|
||||
@@ -43,6 +45,7 @@ import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.*;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -115,7 +118,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
|
||||
public TestNGConfigurationEditor(Project project) {
|
||||
this.project = project;
|
||||
BrowseModuleValueActionListener[] browseListeners = new BrowseModuleValueActionListener[]{new PackageBrowser(project),
|
||||
new TestClassBrowser(project, this), new MethodBrowser(project, this), new GroupBrowser(project, this), new SuiteBrowser(project),
|
||||
new TestClassBrowser(project, this), new TestNGMethodBrowser(project), new GroupBrowser(project, this), new SuiteBrowser(project),
|
||||
new TestClassBrowser(project, this) {
|
||||
@Override
|
||||
protected void onClassChoosen(PsiClass psiClass) {
|
||||
@@ -612,4 +615,29 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TestNGMethodBrowser extends MethodBrowser {
|
||||
public TestNGMethodBrowser(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
protected Condition<PsiMethod> getFilter(PsiClass testClass) {
|
||||
return new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return TestNGUtil.hasTest(method);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getClassName() {
|
||||
return TestNGConfigurationEditor.this.getClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationModuleSelector getModuleSelector() {
|
||||
return moduleSelector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.theoryinpractice.testng.configuration.browser;
|
||||
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.execution.configuration.BrowseModuleValueActionListener;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfigurationEditor;
|
||||
|
||||
/**
|
||||
* @author Hani Suleiman
|
||||
* Date: Jul 21, 2005
|
||||
* Time: 4:29:00 PM
|
||||
*/
|
||||
public class MethodBrowser extends BrowseModuleValueActionListener
|
||||
{
|
||||
private final TestNGConfigurationEditor editor;
|
||||
|
||||
public MethodBrowser(Project project, TestNGConfigurationEditor editor) {
|
||||
super(project);
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String showDialog() {
|
||||
String className = editor.getClassName();
|
||||
if(className.trim().length() == 0) {
|
||||
Messages.showMessageDialog(getField(), "Set class name first", "Cannot Browse Methods", Messages.getInformationIcon());
|
||||
return null;
|
||||
}
|
||||
PsiClass psiclass = editor.getModuleSelector().findClass(className);
|
||||
if(psiclass == null) {
|
||||
Messages.showMessageDialog(getField(), "Class " + className + " does not exist", "Cannot Browse Methods", Messages.getInformationIcon());
|
||||
return null;
|
||||
} else {
|
||||
PsiMethod psimethod = MethodList.showDialog(psiclass, getField());
|
||||
return psimethod == null ? null : psimethod.getName();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.theoryinpractice.testng.configuration.browser;
|
||||
|
||||
import com.intellij.ide.structureView.impl.StructureNodeRenderer;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class MethodList extends JPanel
|
||||
{
|
||||
private final SortedListModel<PsiMethod> model;
|
||||
private final JList list;
|
||||
private final PsiClass psiClass;
|
||||
|
||||
private static final Comparator<PsiMethod> comparator = new Comparator<PsiMethod>() {
|
||||
|
||||
public int compare(PsiMethod method1, PsiMethod method2)
|
||||
{
|
||||
return method1.getName().compareToIgnoreCase(method2.getName());
|
||||
}
|
||||
};
|
||||
|
||||
public static class TestMethodFilter implements Condition<PsiMethod>
|
||||
{
|
||||
public boolean value(PsiMethod method)
|
||||
{
|
||||
return TestNGUtil.hasTest(method);
|
||||
}
|
||||
}
|
||||
|
||||
public MethodList(PsiClass psiClass)
|
||||
{
|
||||
super(new BorderLayout());
|
||||
model = new SortedListModel<PsiMethod>(comparator);
|
||||
list = new JBList(model);
|
||||
this.psiClass = psiClass;
|
||||
evaluate(psiClass.getAllMethods(), new TestMethodFilter());
|
||||
add(ScrollPaneFactory.createScrollPane(list));
|
||||
list.setCellRenderer(new ColoredListCellRenderer() {
|
||||
|
||||
@Override
|
||||
protected void customizeCellRenderer(JList jlist, Object obj, int i, boolean flag, boolean flag1)
|
||||
{
|
||||
PsiMethod psimethod = (PsiMethod)obj;
|
||||
append(PsiFormatUtil.formatMethod(psimethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME, 0), StructureNodeRenderer.applyDeprecation(psimethod, SimpleTextAttributes.REGULAR_ATTRIBUTES));
|
||||
PsiClass psiclass1 = psimethod.getContainingClass();
|
||||
if(!MethodList.this.psiClass.equals(psiclass1)) {
|
||||
append(" (" + psiclass1.getQualifiedName() + ')', StructureNodeRenderer.applyDeprecation(psiclass1, SimpleTextAttributes.GRAY_ATTRIBUTES));
|
||||
}
|
||||
}
|
||||
});
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
ListScrollingUtil.ensureSelectionExists(list);
|
||||
}
|
||||
|
||||
private void evaluate(PsiMethod methods[], Condition<PsiMethod> condition)
|
||||
{
|
||||
for(PsiMethod psimethod : methods) {
|
||||
if(condition.value(psimethod)) model.add(psimethod);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PsiMethod getSelected()
|
||||
{
|
||||
return (PsiMethod)list.getSelectedValue();
|
||||
}
|
||||
|
||||
public static PsiMethod showDialog(PsiClass psiClass, JComponent component)
|
||||
{
|
||||
MethodList list = new MethodList(psiClass);
|
||||
DialogBuilder builder = new DialogBuilder(component);
|
||||
builder.setCenterPanel(list);
|
||||
builder.setPreferredFocusComponent(list.list);
|
||||
builder.setTitle("Choose Test Method");
|
||||
return builder.show() != 0 ? null : list.getSelected();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user