testng: run multiple tests at once
authoranna <Anna.Kozlova@jetbrains.com>
Tue, 17 Jan 2012 15:03:09 +0000 (16:03 +0100)
committeranna <Anna.Kozlova@jetbrains.com>
Tue, 17 Jan 2012 15:41:52 +0000 (16:41 +0100)
plugins/testng/src/META-INF/plugin.xml
plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfiguration.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.form
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGPatternConfigurationProducer.java [new file with mode: 0644]
plugins/testng/src/com/theoryinpractice/testng/model/TestData.java
plugins/testng/src/com/theoryinpractice/testng/model/TestNGConfigurationModel.java
plugins/testng/src/com/theoryinpractice/testng/model/TestType.java

index 8e67df9c856654b4e7151c69ab2da8ddda15c60b..d946f530892af4b6e31957bcebc6f03f8d1d901a 100644 (file)
@@ -8,6 +8,7 @@
         <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
         <deadCode implementation="com.theoryinpractice.testng.inspection.TestNGEntryPoint"/>
         <cantBeStatic implementation="com.theoryinpractice.testng.inspection.TestNGCanBeStaticExtension" />
+        <configurationProducer implementation="com.theoryinpractice.testng.configuration.TestNGPatternConfigurationProducer"/>
         <configurationProducer implementation="com.theoryinpractice.testng.configuration.TestNGInClassConfigurationProducer"/>
         <configurationProducer implementation="com.theoryinpractice.testng.configuration.TestNGPackageConfigurationProducer"/>
         <configurationProducer implementation="com.theoryinpractice.testng.configuration.TestNGSuiteConfigurationProducer"/>
index 7b3b1e9a78a733f39e7f1d8748c4f3feadf56c75..0be68346398ac87caade3112a927a6f7a46daa2c 100644 (file)
@@ -371,6 +371,30 @@ public class SearchingForTestsTask extends Task.Backgroundable {
         }
       }
     }
+    else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
+      for (final String className : data.getPatterns()) {
+        final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
+          @Nullable
+          @Override
+          public PsiClass compute() {
+            return ClassUtil.findPsiClass(psiManager, className.replace('/', '.'), null, true, getSearchScope());
+          }
+        });
+        if (psiClass == null) {
+          throw new CantRunException("Class " + className + " not found");
+        }
+        if (ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+          @Override
+          public Boolean compute() {
+            return TestNGUtil.hasTest(psiClass);
+          }
+        })) {
+          calculateDependencies(null, classes, psiClass);
+        } else {
+          throw new CantRunException("No tests found in class " + className);
+        }
+      }
+    }
   }
 
   private Map<String, String> buildTestParameters() {
index 726629aad1df0e48cdca04cd1892010dd67d3c9c..324b23f9d7769857459d4f07d791e076c0ce3732 100644 (file)
@@ -44,17 +44,21 @@ import com.intellij.refactoring.listeners.RefactoringElementListener;
 import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
 import com.theoryinpractice.testng.model.TestData;
 import com.theoryinpractice.testng.model.TestType;
+import com.theoryinpractice.testng.util.TestNGUtil;
 import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.testng.xml.Parser;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
   implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider {
+  @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";
+  
   //private TestNGResultsContainer resultsContainer;
   protected TestData data;
   protected transient Project project;
@@ -305,6 +309,21 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
       catch (Exception e) {
         throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
       }
+    } else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
+      final Set<String> patterns = data.getPatterns();
+      if (patterns.isEmpty()) {
+        throw new RuntimeConfigurationWarning("No pattern selected");
+      }
+      final GlobalSearchScope searchScope = GlobalSearchScope.allScope(getProject());
+      for (String pattern : patterns) {
+        final PsiClass psiClass = JavaExecutionUtil.findMainClass(getProject(), pattern, searchScope);
+        if (psiClass == null) {
+          throw new RuntimeConfigurationWarning("Class " + pattern + " not found");
+        }
+        if (!TestNGUtil.hasTest(psiClass)) {
+          throw new RuntimeConfigurationWarning("Class " + pattern + " not a test");
+        }
+      }
     }
     JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
     //TODO add various checks here
@@ -339,6 +358,15 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
         listeners.add(listenerClassName.getAttributeValue("class"));
       }
     }
+    final Element patternsElement = element.getChild(PATTERNS_EL_NAME);
+    if (patternsElement != null) {
+      final Set<String> tests = new LinkedHashSet<String>();
+      for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) {
+        Element patternElement = (Element)o;
+        tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME));
+      }
+      getPersistantData().setPatterns(tests);
+    }
   }
 
   @Override
@@ -377,6 +405,16 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
       listenerElement.setAttribute("class", listener);
       listenersElement.addContent(listenerElement);
     }
+    final Set<String> patterns = getPersistantData().getPatterns();
+    if (!patterns.isEmpty()) {
+      final Element patternsElement = new Element(PATTERNS_EL_NAME);
+      for (String o : patterns) {
+        final Element patternElement = new Element(PATTERN_EL_NAME);
+        patternElement.setAttribute(TEST_CLASS_ATT_NAME, o);
+        patternsElement.addContent(patternElement);
+      }
+      element.addContent(patternsElement);
+    }
 
     PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
   }
index 8418d00197fe0189fdeb63fe4fee05e321531423..25853fe593e878b92b3ae4fa846d2cf846c4684a 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.theoryinpractice.testng.configuration.TestNGConfigurationEditor">
-  <grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="4" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+  <grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="4" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="0" left="0" bottom="0" right="0"/>
     <constraints>
       <xy x="20" y="20" width="772" height="523"/>
           <text value="&amp;Method"/>
         </properties>
       </component>
-      <grid id="b9bd" layout-manager="GridLayoutManager" row-count="6" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+      <grid id="b9bd" layout-manager="GridLayoutManager" row-count="7" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
         <margin top="0" left="0" bottom="0" right="0"/>
         <constraints>
-          <grid row="1" column="0" row-span="1" col-span="5" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="0" row-span="1" col-span="6" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties/>
         <clientProperties>
@@ -71,7 +71,7 @@
             <colspec value="left:4dlu:noGrow"/>
             <colspec value="fill:max(d;4px):grow"/>
             <constraints>
-              <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
+              <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
             </constraints>
             <properties/>
             <border type="none"/>
           </component>
           <component id="d1d3" class="com.intellij.openapi.ui.LabeledComponent" binding="outputDirectory">
             <constraints>
-              <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+              <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
             </constraints>
             <properties>
               <labelLocation value="West"/>
               <text value="&amp;Group"/>
             </properties>
           </component>
+          <component id="d64d9" class="com.intellij.openapi.ui.LabeledComponent" binding="myPattern">
+            <constraints>
+              <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <componentClass value="javax.swing.JPanel"/>
+              <labelLocation value="West"/>
+              <text value="Pattern"/>
+              <visible value="true"/>
+            </properties>
+          </component>
         </children>
       </grid>
       <tabbedpane id="7ce0a" class="com.intellij.ui.components.JBTabbedPane" default-binding="true">
         <constraints>
-          <grid row="2" column="0" row-span="1" col-span="5" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+          <grid row="2" column="0" row-span="1" col-span="6" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
             <preferred-size width="200" height="200"/>
           </grid>
         </constraints>
           <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
         </constraints>
       </vspacer>
+      <component id="99b4d" class="com.intellij.ui.components.JBRadioButton" binding="patternTest">
+        <constraints>
+          <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Pattern"/>
+        </properties>
+      </component>
     </children>
   </grid>
   <buttonGroups>
     <group name="testGroup">
-      <member id="dcd9c"/>
-      <member id="d8c06"/>
       <member id="5eaf8"/>
       <member id="61e8b"/>
       <member id="2ab9d"/>
+      <member id="dcd9c"/>
+      <member id="d8c06"/>
+      <member id="99b4d"/>
     </group>
   </buttonGroups>
 </form>
index 0296bfddb5f085bcb340bed0cd2c7066a78f679d..fb8c5ef9b5e284b5039e6e7c21cc88e2b0c57143 100644 (file)
@@ -39,18 +39,18 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.options.SettingsEditor;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.ComponentWithBrowseButton;
-import com.intellij.openapi.ui.LabeledComponent;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.ui.*;
+import com.intellij.openapi.util.IconLoader;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.JavaCodeFragment;
 import com.intellij.psi.PsiClass;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiMethod;
 import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.ui.PanelWithAnchor;
 import com.intellij.ui.EditorTextFieldWithBrowseButton;
+import com.intellij.ui.PanelWithAnchor;
 import com.intellij.ui.table.TableView;
+import com.intellij.util.PlatformIcons;
 import com.intellij.util.TextFieldCompletionProvider;
 import com.theoryinpractice.testng.MessageInfoException;
 import com.theoryinpractice.testng.configuration.browser.*;
@@ -62,6 +62,7 @@ import org.jetbrains.annotations.Nullable;
 import javax.swing.*;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import javax.swing.text.Document;
 import javax.swing.text.PlainDocument;
 import java.awt.*;
 import java.awt.event.ActionEvent;
@@ -84,6 +85,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
   private JRadioButton classTest;
   private JRadioButton methodTest;
   private JRadioButton groupTest;
+  private JRadioButton patternTest;
   private final TestNGConfigurationModel model;
   private LabeledComponent<EditorTextFieldWithBrowseButton> methodField;
   private LabeledComponent<EditorTextFieldWithBrowseButton> packageField;
@@ -105,6 +107,8 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
   private JList listenersTable;
   private JButton removeListener;
   private JCheckBox myUseDefaultReportersCheckBox;
+  private LabeledComponent<JPanel> myPattern;
+  TextFieldWithBrowseButton myPatternTextField;
   private final CommonJavaParametersPanel commonJavaParameters = new CommonJavaParametersPanel();
   private ArrayList<Map.Entry> propertiesList;
   private TestNGListenersTableModel listenerModel;
@@ -114,7 +118,20 @@ 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 MethodBrowser(project, this), new GroupBrowser(project, this), new SuiteBrowser(project),
+        new TestClassBrowser(project, this){
+          @Override
+          protected void onClassChoosen(PsiClass psiClass) {
+            final JTextField textField = myPatternTextField.getTextField();
+            final String text = textField.getText();
+            textField.setText(text + (text.length() > 0 ? "||" : "") + psiClass.getQualifiedName());
+          }
+
+          @Override
+          public void actionPerformed(ActionEvent e) {
+            showDialog();
+          }
+        }};
     model = new TestNGConfigurationModel(project);
     model.setListener(this);
     createView();
@@ -125,7 +142,22 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
         commonJavaParameters.setModuleContext(moduleSelector.getModule());
       }
     });
-    registerListener(new JRadioButton[] {packageTest, classTest, methodTest, groupTest, suiteTest}, new ChangeListener()
+
+    final JPanel panel = myPattern.getComponent();
+    panel.setLayout(new BorderLayout());
+    myPatternTextField = new TextFieldWithBrowseButton();
+    myPatternTextField.setButtonIcon(PlatformIcons.ADD_ICON);
+    panel.add(myPatternTextField, BorderLayout.CENTER);
+    final FixedSizeButton editBtn = new FixedSizeButton();
+    editBtn.setIcon(IconLoader.getIcon("/actions/showViewer.png"));
+    editBtn.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        Messages.showTextAreaDialog(myPatternTextField.getTextField(), "Configure suite tests", "EditParametersPopupWindow");
+      }
+    });
+    panel.add(editBtn, BorderLayout.EAST);
+
+    registerListener(new JRadioButton[] {packageTest, classTest, methodTest, groupTest, suiteTest, patternTest}, new ChangeListener()
     {
       public void stateChanged(ChangeEvent e) {
         ButtonModel buttonModel = (ButtonModel) e.getSource();
@@ -140,6 +172,8 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
             model.setType(TestType.GROUP);
           } else if (buttonModel == suiteTest.getModel()) {
             model.setType(TestType.SUITE);
+          } else if (buttonModel == patternTest.getModel()) {
+            model.setType(TestType.PATTERN);
           }
           redisplay();
         }
@@ -153,17 +187,26 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       }
     });
 
-    LabeledComponent[] components = new LabeledComponent[] {packageField, classField, methodField, groupField, suiteField};
+    LabeledComponent[] components = new LabeledComponent[] {packageField, classField, methodField, groupField, suiteField, myPattern};
     for (int i = 0; i < components.length; i++) {
-      ComponentWithBrowseButton field = (ComponentWithBrowseButton)components[i].getComponent();
+      JComponent field = components[i].getComponent();
       Object document = model.getDocument(i);
       if (field instanceof TextFieldWithBrowseButton) {
         ((TextFieldWithBrowseButton)field).getTextField().setDocument((PlainDocument)document);
-      } else {
-        final com.intellij.openapi.editor.Document componentDocument = ((EditorTextFieldWithBrowseButton)field).getChildComponent().getDocument();
+      }
+      else if (field instanceof EditorTextFieldWithBrowseButton) {
+        final com.intellij.openapi.editor.Document componentDocument =
+          ((EditorTextFieldWithBrowseButton)field).getChildComponent().getDocument();
         model.setDocument(i, componentDocument);
       }
-      browseListeners[i].setField(field);
+      else {
+        field = myPatternTextField;
+        document = new PlainDocument();
+        ((TextFieldWithBrowseButton)field).getTextField().setDocument((Document)document);
+        model.setDocument(i, document);
+      }
+            
+      browseListeners[i].setField((ComponentWithBrowseButton)field);
     }
     model.setType(TestType.CLASS);
     addListener.addActionListener(new AddTestListenerListener());
@@ -198,30 +241,42 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       methodField.setVisible(false);
       groupField.setVisible(false);
       suiteField.setVisible(false);
+      myPattern.setVisible(false);
     } else if (classTest.isSelected()) {
       packagePanel.setVisible(false);
       classField.setVisible(true);
       methodField.setVisible(false);
       groupField.setVisible(false);
       suiteField.setVisible(false);
+      myPattern.setVisible(false);
     } else if (methodTest.isSelected()) {
       packagePanel.setVisible(false);
       classField.setVisible(true);
       methodField.setVisible(true);
       groupField.setVisible(false);
       suiteField.setVisible(false);
+      myPattern.setVisible(false);
     } else if (groupTest.isSelected()) {
       packagePanel.setVisible(false);
       classField.setVisible(false);
       methodField.setVisible(false);
       groupField.setVisible(true);
       suiteField.setVisible(false);
+      myPattern.setVisible(false);
     } else if (suiteTest.isSelected()) {
       packagePanel.setVisible(false);
       classField.setVisible(false);
       methodField.setVisible(false);
       groupField.setVisible(false);
       suiteField.setVisible(true);
+      myPattern.setVisible(false);
+    } else if (patternTest.isSelected()) {
+      packagePanel.setVisible(false);
+      classField.setVisible(false);
+      methodField.setVisible(false);
+      groupField.setVisible(false);
+      suiteField.setVisible(false);
+      myPattern.setVisible(true);
     }
   }
 
@@ -333,6 +388,8 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
     groupTest.setEnabled(true);
     classTest.setSelected(false);
     classTest.setEnabled(true);
+    patternTest.setSelected(false);
+    patternTest.setEnabled(true);
 
     classField.setComponent(new EditorTextFieldWithBrowseButton(project, true, new JavaCodeFragment.VisibilityChecker() {
       @Override
@@ -444,6 +501,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       methodField.setEnabled(false);
       groupField.setEnabled(false);
       suiteField.setEnabled(false);
+      myPattern.setEnabled(false);
     } else if (type == TestType.CLASS) {
       classTest.setSelected(true);
       packageField.setEnabled(false);
@@ -451,6 +509,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       methodField.setEnabled(false);
       groupField.setEnabled(false);
       suiteField.setEnabled(false);
+      myPattern.setEnabled(false);
     } else if (type == TestType.METHOD) {
       methodTest.setSelected(true);
       packageField.setEnabled(false);
@@ -458,6 +517,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       methodField.setEnabled(true);
       groupField.setEnabled(false);
       suiteField.setEnabled(false);
+      myPattern.setEnabled(false);
     } else if (type == TestType.GROUP) {
       groupTest.setSelected(true);
       groupField.setEnabled(true);
@@ -465,6 +525,7 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       classField.setEnabled(false);
       methodField.setEnabled(false);
       suiteField.setEnabled(false);
+      myPattern.setEnabled(false);
     } else if (type == TestType.SUITE) {
       suiteTest.setSelected(true);
       suiteField.setEnabled(true);
@@ -472,6 +533,15 @@ public class TestNGConfigurationEditor extends SettingsEditor<TestNGConfiguratio
       classField.setEnabled(false);
       methodField.setEnabled(false);
       groupField.setEnabled(false);
+      myPattern.setEnabled(false);
+    } else if (type == TestType.PATTERN) {
+      patternTest.setSelected(true);
+      myPattern.setEnabled(true);
+      suiteField.setEnabled(false);
+      packageField.setEnabled(false);
+      classField.setEnabled(false);
+      methodField.setEnabled(false);
+      groupField.setEnabled(false);
     }
   }
 
index 48ef83cf54bcf0d56edec0ac2727411bf19a3657..8a8c991d374d35429b2cb795f74077b38474e018 100644 (file)
@@ -22,6 +22,7 @@ package com.theoryinpractice.testng.configuration;
 
 import com.intellij.execution.*;
 import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
@@ -39,6 +40,11 @@ public class TestNGInClassConfigurationProducer extends TestNGConfigurationProdu
 
   @Nullable
   protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext context) {
+    final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
+    if (elements != null && TestNGPatternConfigurationProducer.collectTestClasses(elements).size() > 1) {
+      return null;
+    }
+
     PsiClass psiClass = null;
     PsiElement element = location.getPsiElement();
     while (element != null) {
diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGPatternConfigurationProducer.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGPatternConfigurationProducer.java
new file mode 100644 (file)
index 0000000..9294974
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+
+/*
+ * User: anna
+ * Date: 23-May-2007
+ */
+package com.theoryinpractice.testng.configuration;
+
+import com.intellij.execution.JavaRunConfigurationExtensionManager;
+import com.intellij.execution.Location;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.theoryinpractice.testng.model.TestData;
+import com.theoryinpractice.testng.model.TestType;
+import com.theoryinpractice.testng.util.TestNGUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class TestNGPatternConfigurationProducer extends TestNGConfigurationProducer{
+
+  private PsiElement[] myElements;
+  
+
+  public int compareTo(Object o) {
+    return PREFERED;
+  }
+
+  protected RunnerAndConfigurationSettings createConfigurationByElement(final Location location, final ConfigurationContext context) {
+    final Project project = location.getProject();
+    final LinkedHashSet<String> classes = new LinkedHashSet<String>();
+    myElements = collectPatternElements(context, classes);
+    if (classes.size() <= 1) return null;
+    RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(project, context);
+    final TestNGConfiguration configuration = (TestNGConfiguration)settings.getConfiguration();
+    final TestData data = configuration.getPersistantData();
+    data.getPatterns().addAll(classes);
+    data.TEST_OBJECT = TestType.PATTERN.getType();
+    data.setScope(setupPackageConfiguration(context, project, configuration, data.getScope()));
+    configuration.setGeneratedName();
+    JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location);
+    return settings;
+  }
+
+  static Set<PsiClass> collectTestClasses(PsiElement[] psiElements) {
+    final Set<PsiClass> foundClasses = new LinkedHashSet<PsiClass>();
+    for (PsiElement psiElement : psiElements) {
+      if (psiElement instanceof PsiClassOwner) {
+        final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses();
+        for (PsiClass aClass : classes) {
+          if (JUnitUtil.isTestClass(aClass)) {
+            foundClasses.add(aClass);
+          }
+        }
+      } else if (psiElement instanceof PsiClass) {
+        if (TestNGUtil.hasTest((PsiClass)psiElement)) {
+          foundClasses.add((PsiClass)psiElement);
+        }
+      }
+    }
+    return foundClasses;
+  }
+
+  private static PsiElement[] collectPatternElements(ConfigurationContext context, LinkedHashSet<String> classes) {
+    final DataContext dataContext = context.getDataContext();
+    PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
+    if (elements != null) {
+      for (PsiClass psiClass : collectTestClasses(elements)) {
+        classes.add(psiClass.getQualifiedName());
+      }
+      return elements;
+    } else {
+      final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
+      if (file instanceof PsiClassOwner) {
+        for (PsiClass psiClass : collectTestClasses(((PsiClassOwner)file).getClasses())) {
+          classes.add(psiClass.getQualifiedName());
+        }
+        return new PsiElement[]{file};
+      }
+    }
+    return null;
+  }
+
+  public PsiElement getSourceElement() {
+    return myElements[0];
+  }
+
+  @Override
+  protected RunnerAndConfigurationSettings findExistingByElement(@NotNull Location location,
+                                                                 @NotNull RunnerAndConfigurationSettings[] existingConfigurations,
+                                                                 ConfigurationContext context) {
+    final LinkedHashSet<String> classes = new LinkedHashSet<String>();
+    collectPatternElements(context, classes);
+    for (RunnerAndConfigurationSettings existingConfiguration : existingConfigurations) {
+      final TestNGConfiguration unitConfiguration = (TestNGConfiguration)existingConfiguration.getConfiguration();
+      final String type = unitConfiguration.getPersistantData().TEST_OBJECT;
+      if (Comparing.equal(type, TestType.PATTERN.getType())) {
+        if (Comparing.equal(classes, unitConfiguration.getPersistantData().getPatterns())) {
+          return existingConfiguration;
+        }
+      }
+    }
+    return null;
+  }
+}
\ No newline at end of file
index 113e32c2e2536d5441efd5a63462d93da6326397..00394391257e477dbd3fa20ee52ce4140f5f9ef1 100644 (file)
@@ -24,6 +24,7 @@ import com.intellij.execution.testframework.TestSearchScope;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
 import com.intellij.psi.util.PsiTreeUtil;
 
@@ -55,6 +56,7 @@ public class TestData implements Cloneable
   public List<String> TEST_LISTENERS = new ArrayList<String>();
   public boolean USE_DEFAULT_REPORTERS = false;
   public String PROPERTIES_FILE;
+  private Set<String> myPatterns = new HashSet<String>();
 
   public TestData() {
     TEST_OBJECT = TestType.CLASS.getType();
@@ -132,6 +134,7 @@ public class TestData implements Cloneable
           && Comparing.equal(OUTPUT_DIRECTORY, data.OUTPUT_DIRECTORY)
           && Comparing.equal(VM_PARAMETERS, data.VM_PARAMETERS)
           && Comparing.equal(PARAMETERS, data.PARAMETERS)
+          && Comparing.equal(myPatterns, data.myPatterns)
           && USE_DEFAULT_REPORTERS == data.USE_DEFAULT_REPORTERS;
     }
   }
@@ -147,7 +150,8 @@ public class TestData implements Cloneable
         Comparing.hashcode(OUTPUT_DIRECTORY) ^
         Comparing.hashcode(VM_PARAMETERS) ^
         Comparing.hashcode(PARAMETERS) ^
-        Comparing.hashcode(USE_DEFAULT_REPORTERS);
+        Comparing.hashcode(USE_DEFAULT_REPORTERS) ^
+        Comparing.hashcode(myPatterns);
   }
 
   @Override
@@ -163,6 +167,8 @@ public class TestData implements Cloneable
 
     data.USE_DEFAULT_REPORTERS = USE_DEFAULT_REPORTERS;
     data.ENVS = new LinkedHashMap<String, String>(ENVS);
+    data.myPatterns = new HashSet<String>();
+    data.myPatterns.addAll(myPatterns);
     data.setScope(getScope());
     return data;
   }
@@ -187,6 +193,11 @@ public class TestData implements Cloneable
       return getSuiteName();
     }
     else {
+      if (TestType.PATTERN.getType().equals(TEST_OBJECT)) {
+        final int size = myPatterns.size();
+        if (size == 0) return "Temp suite";
+        return StringUtil.getShortName(myPatterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
+      }
       return name;
     }
   }
@@ -242,4 +253,12 @@ public class TestData implements Cloneable
   public void setEnvs(final Map<String, String> envs) {
     ENVS = envs;
   }
+
+  public Set<String> getPatterns() {
+    return myPatterns;
+  }
+
+  public void setPatterns(Set<String> set) {
+    myPatterns = set;
+  }
 }
index 0aa261a23bbf6b11b0655ba8845ec6bae7b96858..6291fbfd6e46e5cf590d7fc027696f5d779cfedf 100644 (file)
@@ -17,26 +17,19 @@ package com.theoryinpractice.testng.model;
 
 import com.intellij.execution.JavaExecutionUtil;
 import com.intellij.execution.junit.JUnitUtil;
-import com.intellij.openapi.Disposable;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.RangeMarker;
-import com.intellij.openapi.editor.event.DocumentListener;
-import com.intellij.openapi.editor.markup.MarkupModel;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiClass;
 import com.theoryinpractice.testng.configuration.TestNGConfiguration;
 import com.theoryinpractice.testng.configuration.TestNGConfigurationEditor;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.PlainDocument;
-import java.beans.PropertyChangeListener;
+import java.util.LinkedHashSet;
 
 /**
  * @author Hani Suleiman Date: Jul 21, 2005 Time: 1:20:14 PM
@@ -47,7 +40,7 @@ public class TestNGConfigurationModel
 
     private TestNGConfigurationEditor editor;
     private TestType type;
-    private final Object[] typeDocuments = new Object[5];
+    private final Object[] typeDocuments = new Object[6];
     private final Document propertiesFileDocument = new PlainDocument();
     private final Document outputDirectoryDocument = new PlainDocument();
     private final Project project;
@@ -60,7 +53,7 @@ public class TestNGConfigurationModel
         this.project = project;
     }
 
-    public void setDocument(int type, com.intellij.openapi.editor.Document doc) {
+    public void setDocument(int type, Object doc) {
       typeDocuments[type] = doc;
     }
 
@@ -138,6 +131,16 @@ public class TestNGConfigurationModel
             data.MAIN_CLASS_NAME = "";
             data.METHOD_NAME = "";
         }
+        else if (TestType.PATTERN == type) {
+          final LinkedHashSet<String> set = new LinkedHashSet<String>();
+          final String[] patterns = getText(TestType.PATTERN).split("\\|\\|");
+          for (String pattern : patterns) {
+            if (pattern.length() > 0) {
+              set.add(pattern);
+            }
+          }
+          data.setPatterns(set);
+        }
 
         try {
             data.PROPERTIES_FILE = propertiesFileDocument.getText(0, propertiesFileDocument.getLength());
@@ -177,6 +180,7 @@ public class TestNGConfigurationModel
         setTypeValue(TestType.METHOD, data.getMethodName());
         setTypeValue(TestType.GROUP, data.getGroupName());
         setTypeValue(TestType.SUITE, data.getSuiteName());
+        setTypeValue(TestType.PATTERN, StringUtil.join(data.getPatterns(), "||"));
 
         setDocumentText(propertiesFileDocument, data.getPropertiesFile());
         setDocumentText(outputDirectoryDocument, data.getOutputDirectory());
index 05c57398acf48db3a93623b50ffa070e964e8b6c..788c6cd58641e7d79046e7532f52217bc336e1b5 100644 (file)
@@ -30,6 +30,7 @@ public class TestType
     public static final TestType METHOD = new TestType("METHOD", 2);
     public static final TestType GROUP = new TestType("GROUP", 3);
     public static final TestType SUITE = new TestType("SUITE", 4);
+    public static final TestType PATTERN = new TestType("PATTERN", 5);
     
     public final String type;
     public final int value;
@@ -73,6 +74,9 @@ public class TestType
         {
             return SUITE;
         }
+        if (PATTERN.type.equals(type)) {
+            return PATTERN;
+        }
         throw new IllegalArgumentException("Invalid type requested " + type);
     }
 }
\ No newline at end of file