[testng] 01/02: Import upstream version 6.8.17

Eugene Zhukov eugene-guest at moszumanska.debian.org
Sat Jan 24 20:21:51 UTC 2015


This is an automated email from the git hooks/post-receive script.

eugene-guest pushed a commit to branch master
in repository testng.

commit 24006fbed5a964515ba0f0dd6e1c05b06af5ba57
Author: Eugene Zhukov <jevgeni.zh at gmail.com>
Date:   Fri Jan 23 20:28:59 2015 +0000

    Import upstream version 6.8.17
---
 CHANGES.txt                                        |   7 +-
 README.dev                                         |  16 +-
 build.properties                                   |   2 +-
 build.xml                                          |   1 +
 doc/documentation-main.html                        |   4 +-
 doc/index.html                                     |   4 +-
 pom-test.xml                                       |   2 +-
 pom.xml                                            |   2 +-
 src/main/java/org/testng/Reporter.java             |  21 +-
 src/main/java/org/testng/TestRunner.java           |   2 -
 src/main/java/org/testng/collections/Lists.java    |   5 +-
 src/main/java/org/testng/internal/ClassHelper.java |  22 +-
 src/main/java/org/testng/internal/IInvoker.java    |   6 +-
 src/main/java/org/testng/internal/Invoker.java     | 507 +++++++++------------
 .../org/testng/internal/MethodGroupsHelper.java    |  55 ++-
 .../testng/internal/MethodInvocationHelper.java    |  28 +-
 src/main/java/org/testng/internal/Parameters.java  |  52 +--
 .../TestMethodWithDataProviderMethodWorker.java    |  45 +-
 .../java/org/testng/internal/TestMethodWorker.java |  15 +-
 .../internal/annotations/JDK15TagFactory.java      |  25 +-
 .../org/testng/reporters/FileStringBuffer.java     |   6 +
 .../java/org/testng/reporters/XMLStringBuffer.java |   4 +-
 src/main/java/org/testng/xml/XmlSuite.java         |  20 +-
 src/main/java/org/testng/xml/XmlTest.java          |  18 +-
 .../test/InvocationAndSuccessPercentageTest.java   |   4 +-
 .../test/dataprovider/DataProviderWithError.java   |  25 +
 .../test/dataprovider/FailingDataProviderTest.java |  15 +-
 src/test/java/test/testng106/TestNG106.java        |   6 +-
 src/test/resources/testng-single.xml               |   9 +-
 29 files changed, 460 insertions(+), 468 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 3f18f1d..e1e85ec 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,11 @@
 Current
 
-Fixed: GITHUB-376: Some results can be lost (Konstantin Savin)
+6.8.15:
+
+Fixed: OutOfMemoryException while generating reports.
+Fixed: GITHUB-566: Build does not fail when successPercentage for @Test is not met
+Fixed: XmlTest#setGroupInstances was not being shown in toXml().
+Fixed: GITHUB-376: Some results can be lost (Konstantin Savin).
 Fixed: Handle relative paths of Suite XML files properly (Nalin Makar)
 
 6.8.5:
diff --git a/README.dev b/README.dev
index a26a7e9..c74f7e5 100644
--- a/README.dev
+++ b/README.dev
@@ -13,12 +13,24 @@ Send the public key:
 
 
 Configure ~/.m2/settings.xml with Nexus user/password:
+
   <settings>
     <servers>
       <server>
+        <id>sonatype-nexus-snapshots</id>
+        <username>***</username>
+        <password>***</password>
+      </server>
+      <server>
         <id>sonatype-nexus-staging</id>
-        <username>xxx</username>
-        <password>xxx</password>
+        <username>***</username>
+        <password>***</password>
       </server>
     </servers>
   </settings>
+
+Snaphot deploy:
+mvn -Dgpg.passphrase= -Dgpg.keyname=<public_key> deploy
+
+Staging deploy:
+mvn -Dgpg.passphrase= -Dgpg.keyname=<public_key> release:clean release:prepare release:perform
diff --git a/build.properties b/build.properties
index 085a02d..f4309d8 100644
--- a/build.properties
+++ b/build.properties
@@ -2,7 +2,7 @@
 # TestNG distribution
 #
 testng.basename=testng
-testng.version=6.8.8
+testng.version=6.8.14-SNAPSHOT
 testng.fullname=${testng.basename}-${testng.version}
 
 #
diff --git a/build.xml b/build.xml
index 63477cc..7f8059c 100644
--- a/build.xml
+++ b/build.xml
@@ -33,6 +33,7 @@
     <!-- java greater than 1.5 required to build -->
     <condition property="requiredJavaVersion">
       <or>
+        <equals arg1="${ant.java.version}" arg2="1.8" />
         <equals arg1="${ant.java.version}" arg2="1.7" />
         <equals arg1="${ant.java.version}" arg2="1.6" />
       </or>
diff --git a/doc/documentation-main.html b/doc/documentation-main.html
index 9a372bf..36a661a 100644
--- a/doc/documentation-main.html
+++ b/doc/documentation-main.html
@@ -1425,9 +1425,9 @@ signOut("uk")
 For this ordering, you can use the XML attribute <tt>group-by-instances</tt>. This attribute is valid either on <suite> or <test>:
 
 <pre class="brush: xml">
-  <suite name="Factory" order-by-instances="true">
+  <suite name="Factory" group-by-instances="true">
 or
-  <test name="Factory" order-by-instances="true">
+  <test name="Factory" group-by-instances="true">
 </pre>
 
 
diff --git a/doc/index.html b/doc/index.html
index 1b07c94..cae6a27 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -42,9 +42,9 @@
 
 
 <p align="right"><font size="-2"><em>Cédric Beust (cedric at beust.com)<br>
-Current version: 6.8.1<br>
+Current version: 6.8.15<br>
 Created: April 27th, 2004<br>
-Last Modified:  March 30th, 2013</em></font></p>
+Last Modified:  January 14th, 2015</em></font></p>
 
 
 <p>TestNG is a testing framework inspired from JUnit and NUnit but introducing
diff --git a/pom-test.xml b/pom-test.xml
index d318865..bf83d94 100644
--- a/pom-test.xml
+++ b/pom-test.xml
@@ -72,7 +72,7 @@
     <dependency>
       <groupId>org.testng</groupId>
       <artifactId>testng</artifactId>
-      <version>6.8.9-SNAPSHOT</version>
+      <version>6.8.13</version>
       <scope>test</scope>
     </dependency>
    </dependencies>
diff --git a/pom.xml b/pom.xml
index ac16a84..7c26d90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
   <artifactId>testng</artifactId>
   <packaging>jar</packaging>
   <name>TestNG</name>
-  <version>6.8.13</version>
+  <version>6.8.17</version>
   <description>TestNG is a testing framework.</description>
   <url>http://testng.org</url>
     
diff --git a/src/main/java/org/testng/Reporter.java b/src/main/java/org/testng/Reporter.java
index 01f8f36..b2f30eb 100755
--- a/src/main/java/org/testng/Reporter.java
+++ b/src/main/java/org/testng/Reporter.java
@@ -1,13 +1,13 @@
 package org.testng;
 
-import org.testng.collections.Lists;
-import org.testng.collections.Maps;
-import org.testng.util.Strings;
-
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
+import org.testng.collections.Lists;
+import org.testng.collections.Maps;
+import org.testng.util.Strings;
+
 /**
  * This class is used for test methods to log messages that will be
  * included in the HTML reports generated by TestNG.
@@ -18,8 +18,8 @@ import java.util.Vector;
  * <br>
  * The reporter keeps a combined output of strings (in m_output) and also
  * a record of which method output which line.  In order to do this, callers
- * specify what the current method is with setCurrentMethod() and the
- * Reporter maintaing a mapping of each method with a list of integers.
+ * specify what the current method is with setCurrentTestResult() and the
+ * Reporter maintaing a mapping of each test result with a list of integers.
  * These integers are indices in the combined output (avoids duplicating
  * the output).
  *
@@ -37,7 +37,8 @@ public class Reporter {
    */
   private static List<String> m_output = new Vector<String>();
 
-  private static Map<ITestResult, List<Integer>> m_methodOutputMap = Maps.newHashMap();
+  /** The key is the hashCode of the ITestResult */
+  private static Map<Integer, List<Integer>> m_methodOutputMap = Maps.newHashMap();
 
   private static boolean m_escapeHtml = false;
 
@@ -72,10 +73,10 @@ public class Reporter {
 
     // synchronization needed to ensure the line number and m_output are updated atomically
     int n = getOutput().size();
-    List<Integer> lines = m_methodOutputMap.get(m);
+    List<Integer> lines = m_methodOutputMap.get(m.hashCode());
     if (lines == null) {
       lines = Lists.newArrayList();
-      m_methodOutputMap.put(m, lines);
+      m_methodOutputMap.put(m.hashCode(), lines);
     }
     lines.add(n);
     getOutput().add(s);
@@ -144,7 +145,7 @@ public class Reporter {
 
   public static synchronized List<String> getOutput(ITestResult tr) {
     List<String> result = Lists.newArrayList();
-    List<Integer> lines = m_methodOutputMap.get(tr);
+    List<Integer> lines = m_methodOutputMap.get(tr.hashCode());
     if (lines != null) {
       for (Integer n : lines) {
         result.add(getOutput().get(n));
diff --git a/src/main/java/org/testng/TestRunner.java b/src/main/java/org/testng/TestRunner.java
index 1f2936b..49daa5f 100644
--- a/src/main/java/org/testng/TestRunner.java
+++ b/src/main/java/org/testng/TestRunner.java
@@ -899,7 +899,6 @@ public class TestRunner
           methodInstances.toArray(new IMethodInstance[methodInstances.size()]),
           m_xmlTest.getSuite(),
           m_xmlTest.getAllParameters(),
-          m_allTestMethods,
           m_groupMethods,
           m_classMethodMap,
           this);
@@ -938,7 +937,6 @@ public class TestRunner
         findClasses(methodInstances, c),
         m_xmlTest.getSuite(),
         params,
-        m_allTestMethods,
         m_groupMethods,
         m_classMethodMap,
         this);
diff --git a/src/main/java/org/testng/collections/Lists.java b/src/main/java/org/testng/collections/Lists.java
index a0cba2d..2b5eaec 100755
--- a/src/main/java/org/testng/collections/Lists.java
+++ b/src/main/java/org/testng/collections/Lists.java
@@ -2,6 +2,7 @@ package org.testng.collections;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 public class Lists {
@@ -16,9 +17,7 @@ public class Lists {
 
   public static <K> List<K> newArrayList(K... elements) {
     List<K> result = new ArrayList<K>();
-    for (K e : elements) {
-      result.add(e);
-    }
+    Collections.addAll(result, elements);
     return result;
   }
 
diff --git a/src/main/java/org/testng/internal/ClassHelper.java b/src/main/java/org/testng/internal/ClassHelper.java
index b919d55..42b4eb4 100644
--- a/src/main/java/org/testng/internal/ClassHelper.java
+++ b/src/main/java/org/testng/internal/ClassHelper.java
@@ -86,9 +86,7 @@ public final class ClassHelper {
       allClassLoaders.addAll(m_classLoaders);
     }
 
-    int count = 0;
     for (ClassLoader classLoader : allClassLoaders) {
-      ++count;
       if (null == classLoader) {
         continue;
       }
@@ -133,13 +131,9 @@ public final class ClassHelper {
     ConstructorOrMethod result = null;
 
     for (Method method : cls.getMethods()) {
-      IFactoryAnnotation f = (IFactoryAnnotation) finder.findAnnotation(method,
-          IFactoryAnnotation.class);
+      IFactoryAnnotation f = finder.findAnnotation(method, IFactoryAnnotation.class);
 
       if (null != f) {
-        if (result != null) {
-          throw new TestNGException(cls.getName() + ":  only one @Factory method allowed");
-        }
         result = new ConstructorOrMethod(method);
         result.setEnabled(f.getEnabled());
         break;
@@ -323,8 +317,7 @@ public final class ClassHelper {
       //
       Constructor<?> constructor = findAnnotatedConstructor(finder, declaringClass);
       if (null != constructor) {
-        IParametersAnnotation annotation = (IParametersAnnotation) finder.findAnnotation(constructor,
-                                                                     IParametersAnnotation.class);
+        IParametersAnnotation annotation = finder.findAnnotation(constructor, IParametersAnnotation.class);
 
         String[] parameterNames = annotation.getValue();
         Object[] parameters = Parameters.createInstantiationParameters(constructor,
@@ -374,12 +367,12 @@ public final class ClassHelper {
           parameters = new Object[] { enclosingClassInstance };
         } // isStatic
 
-        Constructor<?> ct = null;
+        Constructor<?> ct;
         try {
           ct = declaringClass.getDeclaredConstructor(parameterTypes);
         }
         catch (NoSuchMethodException ex) {
-          ct = declaringClass.getDeclaredConstructor(new Class[] {String.class});
+          ct = declaringClass.getDeclaredConstructor(String.class);
           parameters = new Object[] { "Default test name" };
           // If ct == null here, we'll pass a null
           // constructor to the factory and hope it can deal with it
@@ -442,8 +435,7 @@ public final class ClassHelper {
     Constructor<?>[] constructors = declaringClass.getDeclaredConstructors();
 
     for (Constructor<?> result : constructors) {
-      IParametersAnnotation annotation = (IParametersAnnotation)
-          finder.findAnnotation(result, IParametersAnnotation.class);
+      IParametersAnnotation annotation = finder.findAnnotation(result, IParametersAnnotation.class);
 
       if (null != annotation) {
         String[] parameters = annotation.getValue();
@@ -471,8 +463,8 @@ public final class ClassHelper {
         return null;
       }
 
-      Constructor<T> ctor = declaringClass.getConstructor(new Class[] { String.class });
-      result = ctor.newInstance(new Object[] { "Default test name" });
+      Constructor<T> ctor = declaringClass.getConstructor(String.class);
+      result = ctor.newInstance("Default test name");
     }
     catch (Exception e) {
       String message = e.getMessage();
diff --git a/src/main/java/org/testng/internal/IInvoker.java b/src/main/java/org/testng/internal/IInvoker.java
index b3ad180..98cda2e 100755
--- a/src/main/java/org/testng/internal/IInvoker.java
+++ b/src/main/java/org/testng/internal/IInvoker.java
@@ -37,8 +37,6 @@ public interface IInvoker {
    * Invoke the given method
    *
    * @param testMethod
-   * @param allTestMethods The list of all the test methods
-   * @param methodIndex The index of testMethod in the allTestMethods array
    * @param suite
    * @param parameters
    * @param groupMethods
@@ -46,12 +44,10 @@ public interface IInvoker {
    * @return a list containing the results of the test methods invocations
    */
   public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod,
-                                             ITestNGMethod[] allTestMethods,
-                                             int methodIndex,
                                              XmlSuite suite,
                                              Map<String, String> parameters,
                                              ConfigurationGroupMethods groupMethods,
-                                             Object[] instances,
+                                             Object instance,
                                              ITestContext testContext);
 
 }
diff --git a/src/main/java/org/testng/internal/Invoker.java b/src/main/java/org/testng/internal/Invoker.java
index 6d55292..4b46ac9 100644
--- a/src/main/java/org/testng/internal/Invoker.java
+++ b/src/main/java/org/testng/internal/Invoker.java
@@ -43,6 +43,8 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -171,11 +173,11 @@ public class Invoker implements IInvoker {
 
       IConfigurationAnnotation configurationAnnotation= null;
       try {
-        Object[] instances= tm.getInstances();
-        if (instances == null || instances.length == 0) {
-          instances = new Object[] { instance };
+        Object inst = tm.getInstance();
+        if (inst == null) {
+          inst = instance;
         }
-        Class<?> objectClass= instances[0].getClass();
+        Class<?> objectClass= inst.getClass();
         Method method= tm.getMethod();
 
         // Only run the configuration if
@@ -206,11 +208,11 @@ public class Invoker implements IInvoker {
                 testMethodResult);
             testResult.setParameters(parameters);
 
-            Object[] newInstances= (null != instance) ? new Object[] { instance } : instances;
+            Object newInstance = null != instance ? instance: inst;
 
             runConfigurationListeners(testResult, true /* before */);
 
-            invokeConfigurationMethod(newInstances, tm,
+            invokeConfigurationMethod(newInstance, tm,
               parameters, isClassConfiguration, isSuiteConfiguration, testResult);
 
             // TODO: probably we should trigger the event for each instance???
@@ -320,13 +322,10 @@ public class Invoker implements IInvoker {
   {
     Throwable cause= ite.getCause() != null ? ite.getCause() : ite;
 
-    if(SkipException.class.isAssignableFrom(cause.getClass())) {
-      SkipException skipEx= (SkipException) cause;
-      if(skipEx.isSkip()) {
-        testResult.setThrowable(skipEx);
-        handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite);
-        return;
-      }
+    if(isSkipExceptionAndSkip(cause)) {
+      testResult.setThrowable(cause);
+      handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite);
+      return;
     }
     Utils.log("", 3, "Failed to invoke configuration method "
         + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage());
@@ -501,7 +500,7 @@ public class Invoker implements IInvoker {
    * TODO: Should change this method to be more like invokeMethod() so that we can
    * handle calls to {@code IInvokedMethodListener} better.
    *
-   * @param instances the instances to invoke the configuration method on
+   * @param targetInstance the instance to invoke the configuration method on
    * @param tm the configuration method
    * @param params the parameters needed for method invocation
    * @param isClass flag if the configuration method is a class level method // FIXME: this looks like a missusage
@@ -509,7 +508,7 @@ public class Invoker implements IInvoker {
    * @throws InvocationTargetException
    * @throws IllegalAccessException
    */
-  private void invokeConfigurationMethod(Object[] instances,
+  private void invokeConfigurationMethod(Object targetInstance,
                                          ITestNGMethod tm,
                                          Object[] params,
                                          boolean isClass,
@@ -520,15 +519,7 @@ public class Invoker implements IInvoker {
     // Mark this method with the current thread id
     tm.setId(ThreadUtil.currentThreadInfo());
 
-    // Only a @BeforeMethod/@AfterMethod needs to be run before each instance, all the other
-    // configuration methods only need to be run once
-    List<Object> actualInstances = Lists.newArrayList();
-    if (tm.isBeforeMethodConfiguration() || tm.isAfterMethodConfiguration()) {
-      actualInstances.addAll(Arrays.asList(instances));
-    } else {
-      actualInstances.add(instances[0]);
-    }
-    for(Object targetInstance : actualInstances) {
+    {
       InvokedMethod invokedMethod= new InvokedMethod(targetInstance,
                                           tm,
                                           params,
@@ -544,15 +535,12 @@ public class Invoker implements IInvoker {
         Method method = tm.getMethod();
 
         //
-        // If this method is a IHookable, invoke its run() method
+        // If this method is a IConfigurable, invoke its run() method
         //
         IConfigurable configurableInstance =
           IConfigurable.class.isAssignableFrom(tm.getMethod().getDeclaringClass()) ?
           (IConfigurable) targetInstance : m_configuration.getConfigurable();
         if (configurableInstance != null) {
-          //
-          // If this method is a IConfigurable, invoke its run() method
-          //
           MethodInvocationHelper.invokeConfigurable(targetInstance, params, configurableInstance, method,
               testResult);
         }
@@ -572,10 +560,6 @@ public class Invoker implements IInvoker {
             }
           }
         }
-        // Only run the method once if it's @BeforeSuite or @AfterSuite
-        if (isSuite) {
-          break;
-        }
       }
       catch (InvocationTargetException ex) {
        throwConfigurationFailure(testResult, ex);
@@ -625,8 +609,7 @@ public class Invoker implements IInvoker {
   }
 
   // pass both paramValues and paramIndex to be thread safe in case parallel=true + dataprovider.
-  private ITestResult invokeMethod(Object[] instances,
-                                   int instanceIndex,
+  private ITestResult invokeMethod(Object instance,
                                    final ITestNGMethod tm,
                                    Object[] parameterValues,
                                    int parametersIndex,
@@ -635,13 +618,13 @@ public class Invoker implements IInvoker {
                                    ITestClass testClass,
                                    ITestNGMethod[] beforeMethods,
                                    ITestNGMethod[] afterMethods,
-                                   ConfigurationGroupMethods groupMethods) {
+                                   ConfigurationGroupMethods groupMethods,
+                                   FailureContext failureContext) {
     TestResult testResult = new TestResult();
 
     //
     // Invoke beforeGroups configurations
     //
-    Object instance = instances[instanceIndex];
     invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params,
         instance);
 
@@ -688,11 +671,10 @@ public class Invoker implements IInvoker {
 
       m_notifier.addInvokedMethod(invokedMethod);
 
-      Method thisMethod= tm.getMethod();
+      Method thisMethod = tm.getConstructorOrMethod().getMethod();
 
       if(confInvocationPassed(tm, tm, testClass, instance)) {
-        log(3, "Invoking " + thisMethod.getDeclaringClass().getName() + "." +
-            thisMethod.getName());
+        log(3, "Invoking " + tm.getRealClass().getName() + "." + tm.getMethodName());
 
         // If no timeOut, just invoke the method
         if (MethodHelper.calculateTimeOut(tm) <= 0) {
@@ -701,7 +683,7 @@ public class Invoker implements IInvoker {
           // If this method is a IHookable, invoke its run() method
           //
           IHookable hookableInstance =
-            IHookable.class.isAssignableFrom(thisMethod.getDeclaringClass()) ?
+              IHookable.class.isAssignableFrom(tm.getRealClass()) ?
             (IHookable) instance : m_configuration.getHookable();
           if (hookableInstance != null) {
             MethodInvocationHelper.invokeHookable(instance,
@@ -747,12 +729,14 @@ public class Invoker implements IInvoker {
       testResult.setStatus(ITestResult.FAILURE);
     }
     finally {
+      // Set end time ASAP
+      testResult.setEndMillis(System.currentTimeMillis());
+
       ExpectedExceptionsHolder expectedExceptionClasses
           = MethodHelper.findExpectedExceptions(m_annotationFinder, tm.getMethod());
-      List<ITestResult> results = Lists.newArrayList();
-      results.add(testResult);
-      handleInvocationResults(tm, results, null, 0, expectedExceptionClasses, false,
-          false /* collect results */);
+      List<ITestResult> results = Lists.<ITestResult>newArrayList(testResult);
+      handleInvocationResults(tm, results, expectedExceptionClasses, false,
+          false /* collect results */, failureContext);
 
       // If this method has a data provider and just failed, memorize the number
       // at which it failed.
@@ -769,14 +753,13 @@ public class Invoker implements IInvoker {
       //
       tm.incrementCurrentInvocationCount();
 
-      if (testResult != null) {
-        testResult.setEndMillis(System.currentTimeMillis());
-      }
-
       // Run invokedMethodListeners after updating TestResult
       runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult);
       runTestListeners(testResult);
-      collectResults(tm, results, testResult);
+      // Do not notify if will retry.
+      if (!results.isEmpty()) {
+        collectResults(tm, Collections.<ITestResult>singleton(testResult));
+      }
 
       //
       // Invoke afterMethods only if
@@ -803,21 +786,21 @@ public class Invoker implements IInvoker {
     return testResult;
   }
 
-  private void collectResults(ITestNGMethod testMethod, List<ITestResult> results, TestResult testResult) {
-    for (int i = 0; i < results.size(); i++) {
+  void collectResults(ITestNGMethod testMethod, Collection<ITestResult> results) {
+    for (ITestResult result : results) {
       // Collect the results
-      int status = results.get(i).getStatus();
+      final int status = result.getStatus();
       if(ITestResult.SUCCESS == status) {
-        m_notifier.addPassedTest(testMethod, testResult);
+        m_notifier.addPassedTest(testMethod, result);
       }
       else if(ITestResult.SKIP == status) {
-        m_notifier.addSkippedTest(testMethod, testResult);
+        m_notifier.addSkippedTest(testMethod, result);
       }
       else if(ITestResult.FAILURE == status) {
-        m_notifier.addFailedTest(testMethod, testResult);
+        m_notifier.addFailedTest(testMethod, result);
       }
       else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) {
-        m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, testResult);
+        m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, result);
       }
       else {
         assert false : "UNKNOWN STATUS:" + status;
@@ -878,10 +861,10 @@ public class Invoker implements IInvoker {
    * </ul>
    *
    * <p/>
-   * This method is also reponsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup
+   * This method is also responsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup
    * if it is the case for the passed in @Test method.
    */
-  protected List<ITestResult> invokeTestMethod(Object[] instances,
+  protected ITestResult invokeTestMethod(Object instance,
                                              final ITestNGMethod tm,
                                              Object[] parameterValues,
                                              int parametersIndex,
@@ -890,19 +873,16 @@ public class Invoker implements IInvoker {
                                              ITestClass testClass,
                                              ITestNGMethod[] beforeMethods,
                                              ITestNGMethod[] afterMethods,
-                                             ConfigurationGroupMethods groupMethods)
+                                             ConfigurationGroupMethods groupMethods,
+                                             FailureContext failureContext)
   {
-    List<ITestResult> results = Lists.newArrayList();
-
     // Mark this method with the current thread id
     tm.setId(ThreadUtil.currentThreadInfo());
 
-    for(int i= 0; i < instances.length; i++) {
-      results.add(invokeMethod(instances, i, tm, parameterValues, parametersIndex, suite, params,
-          testClass, beforeMethods, afterMethods, groupMethods));
-    }
+    ITestResult result = invokeMethod(instance, tm, parameterValues, parametersIndex, suite, params,
+        testClass, beforeMethods, afterMethods, groupMethods, failureContext);
 
-    return results;
+    return result;
   }
 
   /**
@@ -1018,8 +998,7 @@ public class Invoker implements IInvoker {
     return null;
   }
 
-  int retryFailed(Object[] instances,
-                           int instanceIndex,
+  int retryFailed(Object instance,
                            final ITestNGMethod tm,
                            XmlSuite suite,
                            ITestClass testClass,
@@ -1032,37 +1011,34 @@ public class Invoker implements IInvoker {
                            ITestContext testContext,
                            Map<String, String> parameters,
                            int parametersIndex) {
-    List<Object> failedInstances;
-
+    final FailureContext failure = new FailureContext();
+    failure.count = failureCount;
     do {
-      failedInstances = Lists.newArrayList();
       Map<String, String> allParameters = Maps.newHashMap();
       /**
        * TODO: This recreates all the parameters every time when we only need
        * one specific set. Should optimize it by only recreating the set needed.
        */
       ParameterBag bag = createParameters(tm, parameters,
-          allParameters, null, suite, testContext, null /* fedInstance */, null /* testResult */);
+          allParameters, suite, testContext, null /* fedInstance */);
       Object[] parameterValues =
           getParametersFromIndex(bag.parameterHolder.parameters, parametersIndex);
 
-      result.add(invokeMethod(instances, instanceIndex, tm, parameterValues,parametersIndex, suite,
-          allParameters, testClass, beforeMethods, afterMethods, groupMethods));
-      failureCount = handleInvocationResults(tm, result, failedInstances,
-          failureCount, expectedExceptionHolder, true, true /* collect results */);
+      result.add(invokeMethod(instance, tm, parameterValues, parametersIndex, suite,
+          allParameters, testClass, beforeMethods, afterMethods, groupMethods, failure));
+      // It's already handled inside 'invokeMethod' but results not collected
+      handleInvocationResults(tm, result, expectedExceptionHolder, true, true/* collect results */, failure);
     }
-    while (!failedInstances.isEmpty());
-    return failureCount;
+    while (!failure.instances.isEmpty());
+    return failure.count;
   }
 
   private ParameterBag createParameters(ITestNGMethod testMethod,
                                         Map<String, String> parameters,
                                         Map<String, String> allParameterNames,
-                                        Object[] parameterValues,
                                         XmlSuite suite,
                                         ITestContext testContext,
-                                        Object fedInstance,
-                                        ITestResult testResult)
+                                        Object fedInstance)
   {
     Object instance;
     if (fedInstance != null) {
@@ -1072,9 +1048,8 @@ public class Invoker implements IInvoker {
       instance = testMethod.getInstance();
     }
 
-    ParameterBag bag= handleParameters(testMethod,
-        instance, allParameterNames, parameters, parameterValues, suite, testContext, fedInstance,
-        testResult);
+    ParameterBag bag = handleParameters(testMethod,
+        instance, allParameterNames, parameters, null, suite, testContext, fedInstance, null);
 
     return bag;
   }
@@ -1092,101 +1067,84 @@ public class Invoker implements IInvoker {
    *
    * Note (alex): this method can be refactored to use a SingleTestMethodWorker that
    * directly invokes
-   * {@link #invokeTestMethod(Object[], ITestNGMethod, Object[], XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods)}
+   * {@link #invokeTestMethod(Object, ITestNGMethod, Object[], int, XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods, FailureContext)}
    * and this would simplify the implementation (see how DataTestMethodWorker is used)
    */
   @Override
   public List<ITestResult> invokeTestMethods(ITestNGMethod testMethod,
-                                             ITestNGMethod[] allTestMethods,
-                                             int testMethodIndex,
                                              XmlSuite suite,
                                              Map<String, String> testParameters,
                                              ConfigurationGroupMethods groupMethods,
-                                             Object[] instances,
+                                             Object instance,
                                              ITestContext testContext)
   {
     // Potential bug here if the test method was declared on a parent class
     assert null != testMethod.getTestClass()
-    : "COULDN'T FIND TESTCLASS FOR " + testMethod.getMethod().getDeclaringClass();
-
-    List<ITestResult> result = Lists.newArrayList();
+        : "COULDN'T FIND TESTCLASS FOR " + testMethod.getRealClass();
 
     if (!MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) {
-      /*
-       * return if the method is not enabled. No need to do any more calculations
-       */
-      return result;
+      // return if the method is not enabled. No need to do any more calculations
+      return Collections.emptyList();
     }
 
-    ITestClass testClass= testMethod.getTestClass();
-    long start = System.currentTimeMillis();
+    // By the time this testMethod to be invoked,
+    // all dependencies should be already run or we need to skip this method,
+    // so invocation count should not affect dependencies check
+    final String okToProceed = checkDependencies(testMethod, testContext.getAllTestMethods());
+
+    if (okToProceed != null) {
+      //
+      // Not okToProceed. Test is being skipped
+      //
+      ITestResult result = registerSkippedTestResult(testMethod, null, System.currentTimeMillis(),
+          new Throwable(okToProceed));
+      m_notifier.addSkippedTest(testMethod, result);
+      return Collections.singletonList(result);
+    }
+
+
+    final Map<String, String> parameters =
+        testMethod.findMethodParameters(testContext.getCurrentXmlTest());
+
+    // For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread.
+    if (testMethod.getInvocationCount() > 1 && testMethod.getThreadPoolSize() > 1) {
+      return invokePooledTestMethods(testMethod, suite, parameters, groupMethods, testContext);
+    }
 
-    // For invocationCount > 1 and threadPoolSize > 1 the method will be invoked on a thread pool
     long timeOutInvocationCount = testMethod.getInvocationTimeOut();
     //FIXME: Is this correct?
     boolean onlyOne = testMethod.getThreadPoolSize() > 1 ||
       timeOutInvocationCount > 0;
 
     int invocationCount = onlyOne ? 1 : testMethod.getInvocationCount();
-    int failureCount = 0;
 
     ExpectedExceptionsHolder expectedExceptionHolder =
         MethodHelper.findExpectedExceptions(m_annotationFinder, testMethod.getMethod());
+    final ITestClass testClass= testMethod.getTestClass();
+    final List<ITestResult> result = Lists.newArrayList();
+    final FailureContext failure = new FailureContext();
+    final ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), CAN_RUN_FROM_CLASS);
+    final ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), CAN_RUN_FROM_CLASS);
     while(invocationCount-- > 0) {
-      boolean okToProceed = checkDependencies(testMethod, allTestMethods);
-
-      if (!okToProceed) {
-        //
-        // Not okToProceed. Test is being skipped
-        //
-        ITestResult testResult = new TestResult(testClass, null /* instance */,
-                                               testMethod,
-                                               null /* cause */,
-                                               start,
-                                               System.currentTimeMillis(),
-                                               m_testContext);
-        String missingGroup = testMethod.getMissingGroup();
-        if (missingGroup != null) {
-          testResult.setThrowable(new Throwable("Method " + testMethod
-              + " depends on nonexistent group \"" + missingGroup + "\""));
-        }
-
-        testResult.setStatus(ITestResult.SKIP);
-        result.add(testResult);
-        m_notifier.addSkippedTest(testMethod, testResult);
-        runTestListeners(testResult);
-        return result;
-      }
-
-      //
-      // If threadPoolSize specified, run this method in its own pool thread.
-      //
-      Map<String, String> parameters =
-          testMethod.findMethodParameters(testContext.getCurrentXmlTest());
-      if (testMethod.getThreadPoolSize() > 1 && testMethod.getInvocationCount() > 1) {
-          return invokePooledTestMethods(testMethod, allTestMethods, suite,
-              parameters, groupMethods, testContext);
+      if(false) {
+        // Prevent code formatting
       }
       //
       // No threads, regular invocation
       //
       else {
-        ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(),
-            CAN_RUN_FROM_CLASS);
-        ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(),
-            CAN_RUN_FROM_CLASS);
+        // Used in catch statement
+        long start = System.currentTimeMillis();
 
         Map<String, String> allParameterNames = Maps.newHashMap();
         ParameterBag bag = createParameters(testMethod,
-            parameters, allParameterNames, null, suite, testContext, instances[0],
-            null);
+            parameters, allParameterNames, suite, testContext, instance);
 
         if (bag.hasErrors()) {
-          failureCount = handleInvocationResults(testMethod,
-              bag.errorResults, null, failureCount, expectedExceptionHolder, true,
-              true /* collect results */);
-          ITestResult tr = registerSkippedTestResult(testMethod, instances[0], start,
-              bag.errorResults.get(0).getThrowable());
+          final ITestResult tr = bag.errorResult;
+          tr.setStatus(ITestResult.SKIP);
+          runTestListeners(tr);
+          m_notifier.addSkippedTest(testMethod, tr);
           result.add(tr);
           continue;
         }
@@ -1205,10 +1163,10 @@ public class Invoker implements IInvoker {
               TestMethodWithDataProviderMethodWorker w =
                 new TestMethodWithDataProviderMethodWorker(this,
                     testMethod, parametersIndex,
-                    parameterValues, instances, suite, parameters, testClass,
+                    parameterValues, instance, suite, parameters, testClass,
                     beforeMethods, afterMethods, groupMethods,
                     expectedExceptionHolder, testContext, m_skipFailedInvocationCounts,
-                    invocationCount, failureCount, m_notifier);
+                    invocationCount, failure.count, m_notifier);
               workers.add(w);
               // testng387: increment the param index in the bag.
               parametersIndex++;
@@ -1228,34 +1186,28 @@ public class Invoker implements IInvoker {
               List<ITestResult> tmpResults = Lists.newArrayList();
 
               try {
-                tmpResults.addAll(invokeTestMethod(instances,
-                                                   testMethod,
-                                                   parameterValues,
-                                                   parametersIndex,
-                                                   suite,
-                                                   parameters,
-                                                   testClass,
-                                                   beforeMethods,
-                                                   afterMethods,
-                                                   groupMethods));
+                tmpResults.add(invokeTestMethod(instance,
+                    testMethod,
+                    parameterValues,
+                    parametersIndex,
+                    suite,
+                    parameters,
+                    testClass,
+                    beforeMethods,
+                    afterMethods,
+                    groupMethods, failure));
               }
               finally {
-                List<Object> failedInstances = Lists.newArrayList();
-
-                failureCount = handleInvocationResults(testMethod, tmpResults,
-                    failedInstances, failureCount, expectedExceptionHolder, true,
-                    false /* don't collect results */);
-                if (failedInstances.isEmpty()) {
+                if (failure.instances.isEmpty()) {
                   result.addAll(tmpResults);
                 } else {
-                  for (int i = 0; i < failedInstances.size(); i++) {
+                  for (Object failedInstance : failure.instances) {
                     List<ITestResult> retryResults = Lists.newArrayList();
 
-                    failureCount =
-                     retryFailed(failedInstances.toArray(),
-                     i, testMethod, suite, testClass, beforeMethods,
+                    failure.count = retryFailed(
+                            failedInstance, testMethod, suite, testClass, beforeMethods,
                      afterMethods, groupMethods, retryResults,
-                     failureCount, expectedExceptionHolder,
+                     failure.count, expectedExceptionHolder,
                      testContext, parameters, parametersIndex);
                   result.addAll(retryResults);
                   }
@@ -1265,11 +1217,11 @@ public class Invoker implements IInvoker {
                 // If we have a failure, skip all the
                 // other invocationCounts
                 //
-                if (failureCount > 0
+                if (failure.count > 0
                       && (m_skipFailedInvocationCounts
                             || testMethod.skipFailedInvocations())) {
                   while (invocationCount-- > 0) {
-                    result.add(registerSkippedTestResult(testMethod, instances[0], start, null));
+                    result.add(registerSkippedTestResult(testMethod, instance, System.currentTimeMillis(), null));
                   }
                   break;
                 }
@@ -1281,7 +1233,7 @@ public class Invoker implements IInvoker {
         catch (Throwable cause) {
           ITestResult r =
               new TestResult(testMethod.getTestClass(),
-                instances[0],
+                instance,
                 testMethod,
                 cause,
                 start,
@@ -1390,14 +1342,13 @@ public class Invoker implements IInvoker {
                 testMethod.getMethod(), testContext, testResult),
             suite,
             m_annotationFinder,
-            fedInstance),
-          null /* TestResult */);
+            fedInstance));
     }
 //    catch(TestNGException ex) {
 //      throw ex;
 //    }
     catch(Throwable cause) {
-      return new ParameterBag(null /* ParameterHolder */,
+      return new ParameterBag(
           new TestResult(
               testMethod.getTestClass(),
               instance,
@@ -1413,7 +1364,6 @@ public class Invoker implements IInvoker {
    * Invokes a method that has a specified threadPoolSize.
    */
   private List<ITestResult> invokePooledTestMethods(ITestNGMethod testMethod,
-                                                    ITestNGMethod[] allTestMethods,
                                                     XmlSuite suite,
                                                     Map<String, String> parameters,
                                                     ConfigurationGroupMethods groupMethods,
@@ -1436,38 +1386,42 @@ public class Invoker implements IInvoker {
           mi,
           suite,
           parameters,
-          allTestMethods,
           testContext));
     }
 
     return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite, parameters);
   }
 
+  static class FailureContext {
+    int count = 0;
+    List<Object> instances = Lists.newArrayList();
+  }
+
   /**
    * @param testMethod
    * @param result
-   * @param failureCount
    * @param expectedExceptionsHolder
+   * @param failure
    * @return
    */
-  int handleInvocationResults(ITestNGMethod testMethod,
-                                      List<ITestResult> result,
-                                      List<Object> failedInstances,
-                                      int failureCount,
-                                      ExpectedExceptionsHolder expectedExceptionsHolder,
-                                      boolean triggerListeners,
-                                      boolean collectResults)
+  void handleInvocationResults(ITestNGMethod testMethod,
+                               List<ITestResult> result,
+                               ExpectedExceptionsHolder expectedExceptionsHolder,
+                               boolean triggerListeners,
+                               boolean collectResults,
+                               FailureContext failure)
   {
     //
     // Go through all the results and create a TestResult for each of them
     //
     List<ITestResult> resultsToRetry = Lists.newArrayList();
 
-    for (int i = 0; i < result.size(); i++) {
-      ITestResult testResult = result.get(i);
+    for (ITestResult testResult : result) {
       Throwable ite= testResult.getThrowable();
       int status= testResult.getStatus();
 
+      boolean handled = false;
+
       // Exception thrown?
       if (ite != null) {
 
@@ -1484,24 +1438,18 @@ public class Invoker implements IInvoker {
                     " but got \"" + ite.getMessage() + "\"", ite));
             status= ITestResult.FAILURE;
           }
-        } else if (SkipException.class.isAssignableFrom(ite.getClass())){
-          SkipException skipEx= (SkipException) ite;
-          if(skipEx.isSkip()) {
-            status = ITestResult.SKIP;
-          }
-          else {
-            handleException(ite, testMethod, testResult, failureCount++);
-            status = ITestResult.FAILURE;
-          }
-        } else if (ite != null && expectedExceptionsHolder != null) {
+        } else if (isSkipExceptionAndSkip(ite)){
+          status = ITestResult.SKIP;
+        } else if (expectedExceptionsHolder != null) {
           testResult.setThrowable(
-              new TestException("Expected exception "
-                 + expectedExceptionsHolder.expectedClasses[0].getName()
-                 + " but got " + ite, ite));
+              new TestException("Expected exception of " +
+                  getExpectedExceptionsPluralize(expectedExceptionsHolder)
+                  + " but got " + ite, ite));
           status= ITestResult.FAILURE;
         } else {
-          handleException(ite, testMethod, testResult, failureCount++);
-          status= testResult.getStatus();
+          handleException(ite, testMethod, testResult, failure.count++);
+          handled = true;
+          status = testResult.getStatus();
         }
       }
 
@@ -1511,53 +1459,52 @@ public class Invoker implements IInvoker {
         if (classes != null && classes.length > 0) {
           testResult.setThrowable(
               new TestException("Method " + testMethod + " should have thrown an exception of "
-                  + expectedExceptionsHolder.expectedClasses[0]));
+                  + getExpectedExceptionsPluralize(expectedExceptionsHolder)));
           status= ITestResult.FAILURE;
         }
       }
 
       testResult.setStatus(status);
 
-      boolean retry = false;
+      if (status == ITestResult.FAILURE && !handled) {
+        handleException(ite, testMethod, testResult, failure.count++);
+        status = testResult.getStatus();
+      }
 
-      if (testResult.getStatus() == ITestResult.FAILURE) {
+      if (status == ITestResult.FAILURE) {
         IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer();
 
-        if (retryAnalyzer != null && failedInstances != null) {
-          retry = retryAnalyzer.retry(testResult);
-        }
-
-        if (retry) {
+        if (retryAnalyzer != null &&  failure.instances != null && retryAnalyzer.retry(testResult)) {
           resultsToRetry.add(testResult);
-          if (failedInstances != null) {
-            failedInstances.add(testResult.getInstance());
-          }
+          failure.instances.add(testResult.getInstance());
         }
       }
       if (collectResults) {
         // Collect the results
-        if(ITestResult.SUCCESS == status) {
-          m_notifier.addPassedTest(testMethod, testResult);
-        }
-        else if(ITestResult.SKIP == status) {
-          m_notifier.addSkippedTest(testMethod, testResult);
-        }
-        else if(ITestResult.FAILURE == status) {
-          m_notifier.addFailedTest(testMethod, testResult);
-        }
-        else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) {
-          m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, testResult);
-        }
-        else {
-          assert false : "UNKNOWN STATUS:" + status;
-        }
+        collectResults(testMethod, Collections.singleton(testResult));
 //        if (triggerListeners && status != ITestResult.SUCCESS) {
 //          runTestListeners(testResult);
 //        }
       }
     } // for results
 
-    return removeResultsToRetryFromResult(resultsToRetry, result, failureCount);
+    removeResultsToRetryFromResult(resultsToRetry, result, failure);
+  }
+
+  private String getExpectedExceptionsPluralize(final ExpectedExceptionsHolder holder) {
+    StringBuilder sb = new StringBuilder();
+    if (holder.expectedClasses.length > 1) {
+      sb.append("any of types ");
+      sb.append(Arrays.toString(holder.expectedClasses));
+    } else {
+      sb.append("type ");
+      sb.append(holder.expectedClasses[0]);
+    }
+    return sb.toString();
+  }
+
+  private boolean isSkipExceptionAndSkip(Throwable ite) {
+    return SkipException.class.isAssignableFrom(ite.getClass()) && ((SkipException) ite).isSkip();
   }
 
   /**
@@ -1569,23 +1516,19 @@ public class Invoker implements IInvoker {
     if (".*".equals(messageRegExp)) {
       return true;
     } else {
-      if (ite.getMessage() == null) {
-        return false;
-      } else {
-        return Pattern.matches(messageRegExp, ite.getMessage());
-      }
+      final String message = ite.getMessage();
+      return message != null && Pattern.matches(messageRegExp, message);
     }
   }
 
-  private int removeResultsToRetryFromResult(List<ITestResult> resultsToRetry,
-      List<ITestResult> result, int failureCount) {
+  private void removeResultsToRetryFromResult(List<ITestResult> resultsToRetry,
+                                              List<ITestResult> result, FailureContext failure) {
     if (resultsToRetry != null) {
       for (ITestResult res : resultsToRetry) {
         result.remove(res);
-        failureCount--;
+        failure.count--;
       }
     }
-    return failureCount;
   }
 
   /**
@@ -1640,51 +1583,55 @@ public class Invoker implements IInvoker {
    * Checks to see of the test method has certain dependencies that prevents
    * TestNG from executing it
    * @param testMethod test method being checked for
-   * @param testClass
-   * @return dependencies have been run successfully
+   * @return error message or null if dependencies have been run successfully
    */
-  private boolean checkDependencies(ITestNGMethod testMethod,
-      ITestNGMethod[] allTestMethods)
+  private String checkDependencies(ITestNGMethod testMethod,
+                                   ITestNGMethod[] allTestMethods)
   {
-    boolean result = true;
-
     // If this method is marked alwaysRun, no need to check for its dependencies
     if (testMethod.isAlwaysRun()) {
-      return true;
+      return null;
     }
 
     // Any missing group?
     if (testMethod.getMissingGroup() != null
-          && !testMethod.ignoreMissingDependencies()) {
-      return false;
+        && !testMethod.ignoreMissingDependencies()) {
+      return "Method " + testMethod + " depends on nonexistent group \"" + testMethod.getMissingGroup() + "\"";
     }
 
     // If this method depends on groups, collect all the methods that
     // belong to these groups and make sure they have been run successfully
-    if (dependsOnGroups(testMethod)) {
-      String[] groupsDependedUpon = testMethod.getGroupsDependedUpon();
-
+    final String[] groups = testMethod.getGroupsDependedUpon();
+    if (null != groups && groups.length > 0) {
       // Get all the methods that belong to the group depended upon
-      for (String element : groupsDependedUpon) {
+      for (String element : groups) {
         ITestNGMethod[] methods =
-          MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod,
-              m_testContext.getAllTestMethods(),
-              element);
-
-        result = result && haveBeenRunSuccessfully(testMethod, methods);
+            MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod,
+                m_testContext.getAllTestMethods(),
+                element);
+        if (methods.length == 0 && !testMethod.ignoreMissingDependencies()) {
+          // Group is missing
+          return "Method " + testMethod + " depends on nonexistent group \"" + element + "\"";
+        }
+        if (!haveBeenRunSuccessfully(testMethod, methods)) {
+          return "Method " + testMethod +
+              " depends on not successfully finished methods in group \"" + element + "\"";
+        }
       }
     } // depends on groups
 
     // If this method depends on other methods, make sure all these other
     // methods have been run successfully
-    if (result && dependsOnMethods(testMethod)) {
+    if (dependsOnMethods(testMethod)) {
       ITestNGMethod[] methods =
-        MethodHelper.findDependedUponMethods(testMethod, allTestMethods);
+          MethodHelper.findDependedUponMethods(testMethod, allTestMethods);
 
-      result = result && haveBeenRunSuccessfully(testMethod, methods);
+      if (!haveBeenRunSuccessfully(testMethod, methods)) {
+        return "Method " + testMethod + " depends on not successfully finished methods";
+      }
     }
 
-    return result;
+    return null;
   }
 
   /**
@@ -1693,13 +1640,12 @@ public class Invoker implements IInvoker {
   private Set<ITestResult> keepSameInstances(ITestNGMethod method, Set<ITestResult> results) {
     Set<ITestResult> result = Sets.newHashSet();
     for (ITestResult r : results) {
-      for (Object o : method.getInstances()) {
+      final Object o = method.getInstance();
         // Keep this instance if 1) It's on a different class or 2) It's on the same class
         // and on the same instance
         Object instance = r.getInstance() != null
-            ? r.getInstance() : r.getMethod().getInstances()[0];
+            ? r.getInstance() : r.getMethod().getInstance();
         if (r.getTestClass() != method.getTestClass() || instance == o) result.add(r);
-      }
     }
     return result;
   }
@@ -1750,7 +1696,9 @@ public class Invoker implements IInvoker {
                                ITestNGMethod testMethod,
                                ITestResult testResult,
                                int failureCount) {
-    testResult.setThrowable(throwable);
+    if (throwable != null) {
+      testResult.setThrowable(throwable);
+    }
     int successPercentage= testMethod.getSuccessPercentage();
     int invocationCount= testMethod.getInvocationCount();
     float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100f;
@@ -1766,13 +1714,13 @@ public class Invoker implements IInvoker {
 
   /**
    * @param ite The exception that was just thrown
-   * @param expectedExceptions The list of expected exceptions for this
+   * @param exceptionHolder Expected exceptions holder for this
    * test method
    * @return true if the exception that was just thrown is part of the
    * expected exceptions
    */
   private boolean isExpectedException(Throwable ite, ExpectedExceptionsHolder exceptionHolder) {
-    if (exceptionHolder == null) {
+    if (exceptionHolder == null || exceptionHolder.expectedClasses == null) {
       return false;
     }
 
@@ -1834,21 +1782,11 @@ public class Invoker implements IInvoker {
   }
 
   /**
-   * @return true if this method depends on certain groups.
-   */
-  private boolean dependsOnGroups(ITestNGMethod tm) {
-    String[] groups = tm.getGroupsDependedUpon();
-    boolean result = (null != groups) && (groups.length > 0);
-    return result;
-  }
-
-  /**
-   * @return true if this method depends on certain groups.
+   * @return true if this method depends on certain methods.
    */
   private boolean dependsOnMethods(ITestNGMethod tm) {
     String[] methods = tm.getMethodsDependedUpon();
-    boolean result = (null != methods) && (methods.length > 0);
-    return result;
+    return null != methods && methods.length > 0;
   }
 
   private void runConfigurationListeners(ITestResult tr, boolean before) {
@@ -1917,22 +1855,25 @@ public class Invoker implements IInvoker {
   }
 
   /**
-   * This class holds a {@code ParameterHolder} and in case of an error, a non-null
+   * This class holds a {@code ParameterHolder} or in case of an error, a non-null
    * {@code TestResult} containing the cause
    */
   private static class ParameterBag {
     final ParameterHolder parameterHolder;
-    final List<ITestResult> errorResults = Lists.newArrayList();
+    final ITestResult errorResult;
 
-    public ParameterBag(ParameterHolder params, TestResult tr) {
-      parameterHolder = params;
-      if (tr != null) {
-        errorResults.add(tr);
-      }
+    public ParameterBag(ParameterHolder parameterHolder) {
+      this.parameterHolder = parameterHolder;
+      this.errorResult = null;
+    }
+
+    public ParameterBag(ITestResult errorResult) {
+      this.parameterHolder = null;
+      this.errorResult = errorResult;
     }
 
     public boolean hasErrors() {
-      return !errorResults.isEmpty();
+      return errorResult != null;
     }
   }
 
diff --git a/src/main/java/org/testng/internal/MethodGroupsHelper.java b/src/main/java/org/testng/internal/MethodGroupsHelper.java
index 11cb668..622a122 100644
--- a/src/main/java/org/testng/internal/MethodGroupsHelper.java
+++ b/src/main/java/org/testng/internal/MethodGroupsHelper.java
@@ -254,34 +254,57 @@ public class MethodGroupsHelper {
       ITestNGMethod method,
       ITestNGMethod[] methods, String groupRegexp)
   {
-    boolean foundGroup = false;
-    List<ITestNGMethod> vResult = Lists.newArrayList();
-    Pattern groupPattern = PATTERN_CACHE.get(groupRegexp);
-    if (groupPattern == null) {
-      groupPattern = Pattern.compile(groupRegexp);
-      PATTERN_CACHE.put(groupRegexp, groupPattern);
+    ITestNGMethod[] found = findMethodsThatBelongToGroup(methods, groupRegexp);
+
+    if (found.length == 0) {
+      method.setMissingGroup(groupRegexp);
     }
+
+    return found;
+  }
+
+  /**
+   * @param methods list of methods to search
+   * @param groupRegexp regex representing the group
+   *
+   * @return all the methods that belong to the group specified by the regular
+   * expression groupRegExp.  methods[] is the list of all the methods we
+   * are choosing from.
+   */
+  protected static ITestNGMethod[] findMethodsThatBelongToGroup(ITestNGMethod[] methods, String groupRegexp)
+  {
+    List<ITestNGMethod> vResult = Lists.newArrayList();
+    final Pattern pattern = getPattern(groupRegexp);
     for (ITestNGMethod tm : methods) {
       String[] groups = tm.getGroups();
       for (String group : groups) {
-        Pair<String, String> cacheKey = Pair.create(groupRegexp, group);
-        Boolean match = MATCH_CACHE.get(cacheKey);
-        if (match == null) {
-          match = groupPattern.matcher(group).matches();
-          MATCH_CACHE.put(cacheKey, match);
-        }
+        Boolean match = isMatch(pattern, group);
         if (match) {
           vResult.add(tm);
-          foundGroup = true;
         }
       }
     }
 
-    if (!foundGroup) {
-      method.setMissingGroup(groupRegexp);
+    return vResult.toArray(new ITestNGMethod[vResult.size()]);
+  }
+
+  private static Boolean isMatch(Pattern pattern, String group) {
+    Pair<String, String> cacheKey = Pair.create(pattern.pattern(), group);
+    Boolean match = MATCH_CACHE.get(cacheKey);
+    if (match == null) {
+      match = pattern.matcher(group).matches();
+      MATCH_CACHE.put(cacheKey, match);
     }
+    return match;
+  }
 
-    return vResult.toArray(new ITestNGMethod[vResult.size()]);
+  private static Pattern getPattern(String groupRegexp) {
+    Pattern groupPattern = PATTERN_CACHE.get(groupRegexp);
+    if (groupPattern == null) {
+      groupPattern = Pattern.compile(groupRegexp);
+      PATTERN_CACHE.put(groupRegexp, groupPattern);
+    }
+    return groupPattern;
   }
 
 
diff --git a/src/main/java/org/testng/internal/MethodInvocationHelper.java b/src/main/java/org/testng/internal/MethodInvocationHelper.java
index 79b92e5..f5821f8 100644
--- a/src/main/java/org/testng/internal/MethodInvocationHelper.java
+++ b/src/main/java/org/testng/internal/MethodInvocationHelper.java
@@ -1,7 +1,9 @@
 package org.testng.internal;
 
+import org.testng.IConfigurable;
 import org.testng.IConfigureCallBack;
 import org.testng.IHookCallBack;
+import org.testng.IHookable;
 import org.testng.ITestContext;
 import org.testng.ITestNGMethod;
 import org.testng.ITestResult;
@@ -36,7 +38,6 @@ public class MethodInvocationHelper {
 
   protected static Object invokeMethod(Method thisMethod, Object instance, Object[] parameters)
       throws InvocationTargetException, IllegalAccessException {
-    Object result = null;
     Utils.checkInstanceOrStatic(instance, thisMethod);
 
     // TESTNG-326, allow IObjectFactory to load from non-standard classloader
@@ -87,7 +88,7 @@ public class MethodInvocationHelper {
   protected static Iterator<Object[]> invokeDataProvider(Object instance, Method dataProvider,
       ITestNGMethod method, ITestContext testContext, Object fedInstance,
       IAnnotationFinder annotationFinder) {
-    Iterator<Object[]> result = null;
+    Iterator<Object[]> result;
     final ConstructorOrMethod com = method.getConstructorOrMethod();
 
     // If it returns an Object[][], convert it to an Iterable<Object[]>
@@ -149,7 +150,7 @@ public class MethodInvocationHelper {
         method.setParameterInvocationCount(oResult.length);
         result = MethodHelper.createArrayIterator(oResult);
       } else if (Iterator.class.isAssignableFrom(returnType)) {
-        // Already an Iterable<Object[]>, assign it directly
+        // Already an Iterator<Object[]>, assign it directly
         result = (Iterator<Object[]>) invokeMethod(dataProvider, instance, parameters);
       } else {
         throw new TestNGException("Data Provider " + dataProvider + " must return"
@@ -188,9 +189,8 @@ public class MethodInvocationHelper {
    *           <tt>thisMethod</code> results in an exception
    */
   protected static void invokeHookable(final Object testInstance, final Object[] parameters,
-      Object hookableInstance, final Method thisMethod, TestResult testResult) throws Throwable {
-    Method runMethod = hookableInstance.getClass().getMethod("run",
-        new Class[] { IHookCallBack.class, ITestResult.class });
+                                       final IHookable hookable, final Method thisMethod,
+                                       final TestResult testResult) throws Throwable {
     final Throwable[] error = new Throwable[1];
 
     IHookCallBack callback = new IHookCallBack() {
@@ -209,7 +209,7 @@ public class MethodInvocationHelper {
         return parameters;
       }
     };
-    runMethod.invoke(hookableInstance, new Object[] { callback, testResult });
+    hookable.run(callback, testResult);
     if (error[0] != null) {
       throw error[0];
     }
@@ -248,7 +248,7 @@ public class MethodInvocationHelper {
   private static void invokeWithTimeoutWithNewExecutor(ITestNGMethod tm, Object instance,
       Object[] parameterValues, ITestResult testResult)
       throws InterruptedException, ThreadExecutionException {
-    IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethod().getName());
+    IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethodName());
 
     InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues);
     IFutureResult future = exec.submitRunnable(imr);
@@ -265,7 +265,7 @@ public class MethodInvocationHelper {
       testResult.setThrowable(exception);
       testResult.setStatus(ITestResult.FAILURE);
     } else {
-      Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethod()
+      Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethodName()
           + " completed within the time-out " + tm.getTimeOut());
 
       // We don't need the result from the future but invoking get() on it
@@ -279,10 +279,8 @@ public class MethodInvocationHelper {
   }
 
   protected static void invokeConfigurable(final Object instance, final Object[] parameters,
-      Object configurableInstance, final Method thisMethod, ITestResult testResult)
-      throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, Throwable {
-    Method runMethod = configurableInstance.getClass().getMethod("run",
-        new Class[] { IConfigureCallBack.class, ITestResult.class });
+                                           final IConfigurable configurableInstance, final Method thisMethod,
+                                           final ITestResult testResult) throws Throwable {
     final Throwable[] error = new Throwable[1];
 
     IConfigureCallBack callback = new IConfigureCallBack() {
@@ -301,10 +299,10 @@ public class MethodInvocationHelper {
         return parameters;
       }
     };
-    runMethod.invoke(configurableInstance, new Object[] { callback, testResult });
+    configurableInstance.run(callback, testResult);
     if (error[0] != null) {
       throw error[0];
     }
   }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/testng/internal/Parameters.java b/src/main/java/org/testng/internal/Parameters.java
index 3708011..4fa7c91 100755
--- a/src/main/java/org/testng/internal/Parameters.java
+++ b/src/main/java/org/testng/internal/Parameters.java
@@ -1,5 +1,15 @@
 package org.testng.internal;
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.testng.ITestContext;
 import org.testng.ITestNGMethod;
 import org.testng.ITestResult;
@@ -19,16 +29,6 @@ import org.testng.util.Strings;
 import org.testng.xml.XmlSuite;
 import org.testng.xml.XmlTest;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * Methods that bind parameters declared in testng.xml to actual values
  * used to invoke methods.
@@ -220,28 +220,28 @@ public class Parameters {
       result = value;
     }
     else if(type == int.class || type == Integer.class) {
-      result = Integer.valueOf(Integer.parseInt(value));
+      result = Integer.parseInt(value);
     }
     else if(type == boolean.class || type == Boolean.class) {
       result = Boolean.valueOf(value);
     }
     else if(type == byte.class || type == Byte.class) {
-      result = Byte.valueOf(Byte.parseByte(value));
+      result = Byte.parseByte(value);
     }
     else if(type == char.class || type == Character.class) {
-      result = Character.valueOf(value.charAt(0));
+      result = value.charAt(0);
     }
     else if(type == double.class || type == Double.class) {
-      result = Double.valueOf(Double.parseDouble(value));
+      result = Double.parseDouble(value);
     }
     else if(type == float.class || type == Float.class) {
-      result = Float.valueOf(Float.parseFloat(value));
+      result = Float.parseFloat(value);
     }
     else if(type == long.class || type == Long.class) {
-      result = Long.valueOf(Long.parseLong(value));
+      result = Long.parseLong(value);
     }
     else if(type == short.class || type == Short.class) {
-      result = Short.valueOf(Short.parseShort(value));
+      result = Short.parseShort(value);
     }
     else if (type.isEnum()) {
     	result = Enum.valueOf(type, value);
@@ -282,7 +282,7 @@ public class Parameters {
    */
   private static IDataProvidable findDataProviderInfo(Class clazz, ConstructorOrMethod m,
       IAnnotationFinder finder) {
-    IDataProvidable result = null;
+    IDataProvidable result;
 
     if (m.getMethod() != null) {
       //
@@ -325,8 +325,7 @@ public class Parameters {
     }
 
     for (Method m : ClassHelper.getAvailableMethods(cls)) {
-      IDataProviderAnnotation dp = (IDataProviderAnnotation)
-          finder.findAnnotation(m, IDataProviderAnnotation.class);
+      IDataProviderAnnotation dp = finder.findAnnotation(m, IDataProviderAnnotation.class);
       if (null != dp && name.equals(getDataProviderName(dp, m))) {
         if (shouldBeStatic && (m.getModifiers() & Modifier.STATIC) == 0) {
           throw new TestNGException("DataProvider should be static: " + m);
@@ -352,11 +351,11 @@ public class Parameters {
   {
     List<Object> result = Lists.newArrayList();
 
-    Object[] extraParameters = new Object[0];
+    Object[] extraParameters;
     //
     // Try to find an @Parameters annotation
     //
-    IParametersAnnotation annotation = (IParametersAnnotation) finder.findAnnotation(m, IParametersAnnotation.class);
+    IParametersAnnotation annotation = finder.findAnnotation(m, IParametersAnnotation.class);
     Class<?>[] types = m.getParameterTypes();
     if(null != annotation) {
       String[] parameterNames = annotation.getValue();
@@ -383,9 +382,7 @@ public class Parameters {
     //
     // Add the extra parameters we found
     //
-    for (Object p : extraParameters) {
-      result.add(p);
-    }
+    Collections.addAll(result, extraParameters);
 
     // If the method declared an Object[] parameter and we have parameter values, inject them
     for (int i = 0; i < types.length; i++) {
@@ -413,7 +410,7 @@ public class Parameters {
       Object fedInstance)
   {
     ParameterHolder result;
-    Iterator<Object[]> parameters = null;
+    Iterator<Object[]> parameters;
 
     /*
      * Do we have a @DataProvider? If yes, then we have several
@@ -462,8 +459,7 @@ public class Parameters {
       // Turn it into an Iterable
       parameters = MethodHelper.createArrayIterator(allParameterValuesArray);
 
-      result = new ParameterHolder(parameters, ParameterOrigin.ORIGIN_XML,
-          dataProviderHolder);
+      result = new ParameterHolder(parameters, ParameterOrigin.ORIGIN_XML, null);
     }
 
     return result;
diff --git a/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java b/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java
index 8ba02f3..96be14a 100755
--- a/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java
+++ b/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java
@@ -15,7 +15,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe
 
   private ITestNGMethod m_testMethod;
   private Object[] m_parameterValues;
-  private Object[] m_instances;
+  private Object m_instance;
   private XmlSuite m_xmlSuite;
   private Map<String, String> m_parameters;
   private ITestClass m_testClass;
@@ -35,7 +35,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe
 
   public TestMethodWithDataProviderMethodWorker(Invoker invoker, ITestNGMethod testMethod,
       int parameterIndex,
-      Object[] parameterValues, Object[] instances, XmlSuite suite,
+      Object[] parameterValues, Object instance, XmlSuite suite,
       Map<String, String> parameters, ITestClass testClass,
       ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods,
       ConfigurationGroupMethods groupMethods, ExpectedExceptionsHolder expectedExceptionHolder,
@@ -45,7 +45,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe
     m_testMethod = testMethod;
     m_parameterIndex = parameterIndex;
     m_parameterValues = parameterValues;
-    m_instances = instances;
+    m_instance = instance;
     m_xmlSuite = suite;
     m_parameters = parameters;
     m_testClass = testClass;
@@ -69,33 +69,32 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe
     List<ITestResult> tmpResults = Lists.newArrayList();
     long start = System.currentTimeMillis();
 
+    final Invoker.FailureContext failure = new Invoker.FailureContext();
+    failure.count = m_failureCount;
     try {
-      tmpResults.addAll(m_invoker.invokeTestMethod(m_instances,
-           m_testMethod,
-           m_parameterValues,
-           m_parameterIndex,
-           m_xmlSuite,
-           m_parameters,
-           m_testClass,
-           m_beforeMethods,
-           m_afterMethods,
-           m_groupMethods));
+      tmpResults.add(m_invoker.invokeTestMethod(m_instance,
+          m_testMethod,
+          m_parameterValues,
+          m_parameterIndex,
+          m_xmlSuite,
+          m_parameters,
+          m_testClass,
+          m_beforeMethods,
+          m_afterMethods,
+          m_groupMethods,
+          failure));
     }
     finally {
-      List<Object> failedInstances = Lists.newArrayList();
-
-      m_failureCount = m_invoker.handleInvocationResults(m_testMethod, tmpResults,
-          failedInstances, m_failureCount, m_expectedExceptionHolder, true,
-          false /* don't collect results */);
-      if (failedInstances.isEmpty()) {
+      m_failureCount = failure.count;
+      if (failure.instances.isEmpty()) {
         m_testResults.addAll(tmpResults);
       } else {
-        for (int i = 0; i < failedInstances.size(); i++) {
+        for (Object instance : failure.instances) {
           List<ITestResult> retryResults = Lists.newArrayList();
 
           m_failureCount =
-             m_invoker.retryFailed(failedInstances.toArray(),
-                 i, m_testMethod, m_xmlSuite, m_testClass, m_beforeMethods,
+             m_invoker.retryFailed(
+                 instance, m_testMethod, m_xmlSuite, m_testClass, m_beforeMethods,
                  m_afterMethods, m_groupMethods, retryResults,
                  m_failureCount, m_expectedExceptionHolder,
                  m_testContext, m_parameters, m_parameterIndex);
@@ -118,7 +117,7 @@ public class TestMethodWithDataProviderMethodWorker implements Callable<List<ITe
         while (m_invocationCount-- > 0) {
           ITestResult r =
             new TestResult(m_testMethod.getTestClass(),
-              m_instances[0],
+              m_instance,
               m_testMethod,
               null,
               start,
diff --git a/src/main/java/org/testng/internal/TestMethodWorker.java b/src/main/java/org/testng/internal/TestMethodWorker.java
index d251264..cb93beb 100644
--- a/src/main/java/org/testng/internal/TestMethodWorker.java
+++ b/src/main/java/org/testng/internal/TestMethodWorker.java
@@ -36,7 +36,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
   private final IInvoker m_invoker;
   private final Map<String, String> m_parameters;
   private final XmlSuite m_suite;
-  private final ITestNGMethod[] m_allTestMethods;
   private List<ITestResult> m_testResults = Lists.newArrayList();
   private final ConfigurationGroupMethods m_groupMethods;
   private final ClassMethodMap m_classMethodMap;
@@ -46,7 +45,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
                           IMethodInstance[] testMethods,
                           XmlSuite suite,
                           Map<String, String> parameters,
-                          ITestNGMethod[] allTestMethods,
                           ConfigurationGroupMethods groupMethods,
                           ClassMethodMap classMethodMap,
                           ITestContext testContext)
@@ -55,7 +53,6 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
     m_methodInstances = testMethods;
     m_suite = suite;
     m_parameters = parameters;
-    m_allTestMethods = allTestMethods;
     m_groupMethods = groupMethods;
     m_classMethodMap = classMethodMap;
     m_testContext = testContext;
@@ -108,7 +105,7 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
 
       // Invoke test method
       try {
-        invokeTestMethods(testMethod, testMthdInst.getInstances(), m_testContext);
+        invokeTestMethods(testMethod, testMthdInst.getInstance(), m_testContext);
       }
       finally {
         invokeAfterClassMethods(testClass, testMthdInst);
@@ -116,7 +113,7 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
     }
   }
 
-  protected void invokeTestMethods(ITestNGMethod tm, Object[] instances,
+  protected void invokeTestMethods(ITestNGMethod tm, Object instance,
       ITestContext testContext)
   {
     // Potential bug here:  we look up the method index of tm among all
@@ -126,12 +123,10 @@ public class TestMethodWorker implements IWorker<ITestNGMethod> {
     // more efficient)
     List<ITestResult> testResults =
         m_invoker.invokeTestMethods(tm,
-            m_allTestMethods,
-            indexOf(tm, m_allTestMethods),
             m_suite,
             m_parameters,
             m_groupMethods,
-            instances,
+            instance,
             testContext);
 
     if (testResults != null) {
@@ -288,16 +283,14 @@ class SingleTestMethodWorker extends TestMethodWorker {
                                 MethodInstance testMethod,
                                 XmlSuite suite,
                                 Map<String, String> parameters,
-                                ITestNGMethod[] allTestMethods,
                                 ITestContext testContext)
   {
     super(invoker,
           new MethodInstance[] {testMethod},
           suite,
           parameters,
-          allTestMethods,
           EMPTY_GROUP_METHODS,
           null,
           testContext);
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java b/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java
index 2773460..5d4e6b3 100755
--- a/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java
+++ b/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java
@@ -2,7 +2,9 @@ package org.testng.internal.annotations;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
-import java.util.Map;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import org.testng.IAnnotationTransformer;
 import org.testng.TestNGException;
@@ -31,7 +33,7 @@ import org.testng.annotations.ITestAnnotation;
 import org.testng.annotations.Listeners;
 import org.testng.annotations.Parameters;
 import org.testng.annotations.Test;
-import org.testng.collections.Maps;
+import org.testng.collections.Lists;
 import org.testng.internal.Utils;
 
 /**
@@ -417,15 +419,15 @@ public class JDK15TagFactory {
   }
 
   private String[] join(String[] strings, String[] strings2) {
-    Map<String, String> vResult = Maps.newHashMap();
-    for (String s : strings) {
-      vResult.put(s, s);
-    }
+    List<String> result = Lists.newArrayList(strings);
+    Set<String> seen = new HashSet<String>(Lists.newArrayList(strings));
     for (String s : strings2) {
-      vResult.put(s, s);
+      if (! seen.contains(s)) {
+        result.add(s);
+      }
     }
 
-    return vResult.keySet().toArray(new String[vResult.size()]);
+    return result.toArray(new String[result.size()]);
   }
 
   /**
@@ -494,21 +496,20 @@ public class JDK15TagFactory {
       return new String[0];
     }
 
-    Map<String, String> vResult = Maps.newHashMap();
+    List<String> result = Lists.newArrayList();
 
     while (cls != null && cls != Object.class) {
       Annotation annotation = cls.getAnnotation(annotationClass);
       if (annotation != null) {
         String[] g = (String[]) invokeMethod(annotation, methodName);
         for (String s : g) {
-          vResult.put(s, s);
+          result.add(s);
         }
       }
       cls = cls.getSuperclass();
     }
 
-    String[] result = vResult.keySet().toArray(new String[vResult.size()]);
-    return result;
+    return result.toArray(new String[result.size()]);
   }
 
   private Object invokeMethod(Annotation test, String methodName) {
diff --git a/src/main/java/org/testng/reporters/FileStringBuffer.java b/src/main/java/org/testng/reporters/FileStringBuffer.java
index 80e774e..af2e98b 100644
--- a/src/main/java/org/testng/reporters/FileStringBuffer.java
+++ b/src/main/java/org/testng/reporters/FileStringBuffer.java
@@ -43,6 +43,9 @@ public class FileStringBuffer implements IBuffer {
 
   @Override
   public FileStringBuffer append(CharSequence s) {
+    if (s == null) {
+      throw new IllegalArgumentException("CharSequence (Argument 0 of FileStringBuffer#append) should not be null");
+    }
 //    m_sb.append(s);
     if (m_sb.length() > m_maxCharacters) {
       flushToFile();
@@ -64,6 +67,9 @@ public class FileStringBuffer implements IBuffer {
 
   @Override
   public void toWriter(Writer fw) {
+    if (fw == null) {
+      throw new IllegalArgumentException("Writer (Argument 0 of FileStringBuffer#toWriter) should not be null");
+    }
     try {
       BufferedWriter bw = new BufferedWriter(fw);
       if (m_file == null) {
diff --git a/src/main/java/org/testng/reporters/XMLStringBuffer.java b/src/main/java/org/testng/reporters/XMLStringBuffer.java
index 092c10e..84046b4 100755
--- a/src/main/java/org/testng/reporters/XMLStringBuffer.java
+++ b/src/main/java/org/testng/reporters/XMLStringBuffer.java
@@ -14,8 +14,8 @@ import java.util.regex.Pattern;
  * @author <a href="mailto:cedric at beust.com">Cedric Beust</a> Jul 21, 2003
  */
 public class XMLStringBuffer {
-  /** End of line */
-  private static final String EOL = System.getProperty("line.separator");
+  /** End of line, value of 'line.separator' system property or '\n' */
+  private static final String EOL = System.getProperty("line.separator", "\n");
 
   /** Tab space indent for XML document */
   private static final String DEFAULT_INDENT_INCREMENT = "  ";
diff --git a/src/main/java/org/testng/xml/XmlSuite.java b/src/main/java/org/testng/xml/XmlSuite.java
index 61612eb..bdcc3e5 100755
--- a/src/main/java/org/testng/xml/XmlSuite.java
+++ b/src/main/java/org/testng/xml/XmlSuite.java
@@ -1,7 +1,12 @@
 package org.testng.xml;
 
-import static org.testng.collections.CollectionUtils.hasElements;
-import static org.testng.internal.Utils.isStringNotEmpty;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
 
 import org.testng.ITestObjectFactory;
 import org.testng.TestNG;
@@ -12,13 +17,8 @@ import org.testng.xml.dom.OnElement;
 import org.testng.xml.dom.OnElementList;
 import org.testng.xml.dom.Tag;
 
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import static org.testng.collections.CollectionUtils.hasElements;
+import static org.testng.internal.Utils.isStringNotEmpty;
 
 /**
  * This class describes the tag <suite> in testng.xml.
@@ -439,6 +439,8 @@ public class XmlSuite implements Serializable, Cloneable {
     if(isStringNotEmpty(parallel) && !DEFAULT_PARALLEL.equals(parallel)) {
       p.setProperty("parallel", parallel);
     }
+    XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()),
+        DEFAULT_GROUP_BY_INSTANCES.toString());
     XmlUtils.setProperty(p, "configfailurepolicy", getConfigFailurePolicy(),
         DEFAULT_CONFIG_FAILURE_POLICY);
     XmlUtils.setProperty(p, "thread-count", String.valueOf(getThreadCount()),
diff --git a/src/main/java/org/testng/xml/XmlTest.java b/src/main/java/org/testng/xml/XmlTest.java
index 06abec1..cbc8c12 100755
--- a/src/main/java/org/testng/xml/XmlTest.java
+++ b/src/main/java/org/testng/xml/XmlTest.java
@@ -1,12 +1,5 @@
 package org.testng.xml;
 
-import org.testng.TestNG;
-import org.testng.TestNGException;
-import org.testng.collections.Lists;
-import org.testng.collections.Maps;
-import org.testng.reporters.XMLStringBuffer;
-import org.testng.xml.dom.ParentSetter;
-
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
@@ -14,6 +7,13 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.UUID;
 
+import org.testng.TestNG;
+import org.testng.TestNGException;
+import org.testng.collections.Lists;
+import org.testng.collections.Maps;
+import org.testng.reporters.XMLStringBuffer;
+import org.testng.xml.dom.ParentSetter;
+
 /**
  * This class describes the tag <test>  in testng.xml.
  *
@@ -477,6 +477,10 @@ public class XmlTest implements Serializable, Cloneable {
     if (m_threadCount != -1) {
       p.setProperty("thread-count", Integer.toString(m_threadCount));
     }
+    if (m_groupByInstances != null) {
+      XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()),
+          XmlSuite.DEFAULT_GROUP_BY_INSTANCES.toString());
+    }
 
     xsb.push("test", p);
 
diff --git a/src/test/java/test/InvocationAndSuccessPercentageTest.java b/src/test/java/test/InvocationAndSuccessPercentageTest.java
index ec0254f..56f4434 100644
--- a/src/test/java/test/InvocationAndSuccessPercentageTest.java
+++ b/src/test/java/test/InvocationAndSuccessPercentageTest.java
@@ -67,9 +67,9 @@ public class InvocationAndSuccessPercentageTest extends BaseTest {
     * 1 failed but within success percentage
     * 1 failed
     */
-   @Test(enabled = false)
+   @Test
    public void successPercentageThatFails() {
-     addClass("test.sample.InvocationCountTest");
+     addClass(test.sample.InvocationCountTest.class);
      addIncludedGroup("successPercentageThatFailsOnly");
      run();
      String[] passed = {
diff --git a/src/test/java/test/dataprovider/DataProviderWithError.java b/src/test/java/test/dataprovider/DataProviderWithError.java
new file mode 100644
index 0000000..a7b8c7f
--- /dev/null
+++ b/src/test/java/test/dataprovider/DataProviderWithError.java
@@ -0,0 +1,25 @@
+package test.dataprovider;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author Vladislav.Rassokhin
+ */
+public class DataProviderWithError {
+  @Test(dataProvider = "Data", invocationCount = 2)
+  public void testShouldSkip() throws Exception {
+    Assert.fail();
+  }
+
+  @Test(dataProvider = "Data", invocationCount = 2, successPercentage = 10)
+  public void testShouldSkipEvenIfSuccessPercentage() throws Exception {
+    Assert.fail();
+  }
+
+  @DataProvider(name = "Data")
+  public static Object[][] Data() {
+    throw new RuntimeException("Fail");
+  }
+}
diff --git a/src/test/java/test/dataprovider/FailingDataProviderTest.java b/src/test/java/test/dataprovider/FailingDataProviderTest.java
index fff2564..ee31493 100644
--- a/src/test/java/test/dataprovider/FailingDataProviderTest.java
+++ b/src/test/java/test/dataprovider/FailingDataProviderTest.java
@@ -3,27 +3,32 @@ package test.dataprovider;
 import org.testng.Assert;
 import org.testng.TestListenerAdapter;
 import org.testng.TestNG;
-import org.testng.TestNGException;
 import org.testng.annotations.Test;
 
 import test.SimpleBaseTest;
 
 public class FailingDataProviderTest extends SimpleBaseTest {
-  private void shouldSkipOne(Class cls, String message) {
+  private void shouldSkip(Class cls, String message, int expected) {
     TestNG testng = create(cls);
     TestListenerAdapter tla = new TestListenerAdapter();
     testng.addListener(tla);
     testng.run();
-    Assert.assertEquals(tla.getSkippedTests().size(), 1, message);
+    Assert.assertEquals(tla.getSkippedTests().size(), expected, message);
   }
 
   @Test(description = "TESTNG-142: Exceptions in DataProvider are not reported as failed test")
   public void failingDataProvider() {
-    shouldSkipOne(FailingDataProvider.class, "Test method should be marked as skipped");
+    shouldSkip(FailingDataProvider.class, "Test method should be marked as skipped", 1);
   }
 
   @Test(description = "TESTNG-447: Abort when two data providers have the same name")
   public void duplicateDataProviders() {
-    shouldSkipOne(DuplicateDataProviderSampleTest.class, "");
+    shouldSkip(DuplicateDataProviderSampleTest.class, "", 1);
+  }
+
+  @Test
+  public void failingDataProviderAndInvocationCount() throws Exception {
+    shouldSkip(DataProviderWithError.class,
+        "Test should be skipped even if invocation counter and success percentage set", 4);
   }
 }
diff --git a/src/test/java/test/testng106/TestNG106.java b/src/test/java/test/testng106/TestNG106.java
index 92c883f..171463a 100644
--- a/src/test/java/test/testng106/TestNG106.java
+++ b/src/test/java/test/testng106/TestNG106.java
@@ -1,12 +1,13 @@
 package test.testng106;
 
+import java.util.Arrays;
+
 import org.testng.Assert;
 import org.testng.TestNG;
 import org.testng.annotations.Test;
 import org.testng.xml.XmlSuite;
-import test.SimpleBaseTest;
 
-import java.util.Arrays;
+import test.SimpleBaseTest;
 
 public class TestNG106 extends SimpleBaseTest {
   @Test
@@ -18,7 +19,6 @@ public class TestNG106 extends SimpleBaseTest {
     createXmlTest(s, "myTest3", Test2.class.getName());
     createXmlTest(s, "myTest-last", Test2.class.getName());
     tng.setXmlSuites(Arrays.asList(s));
-    tng.setVerbose(3);
     tng.run();
     Assert.assertEquals(FailingSuiteFixture.s_invocations, 0, "@BeforeSuite has failed. All tests should be skipped.");
   }
diff --git a/src/test/resources/testng-single.xml b/src/test/resources/testng-single.xml
index 6898468..d144918 100644
--- a/src/test/resources/testng-single.xml
+++ b/src/test/resources/testng-single.xml
@@ -9,16 +9,11 @@
     <parameter name="string" value="s"/>
 
     <groups>
-      <dependencies>
-        <group name="c" depends-on="a  b" />
-        <group name="z" depends-on="c" />
-      </dependencies>
     </groups>
 
     <classes>
-      <class name="test.tmp.A">
-       </class>
-     </classes>
+      <class name="test.mannotation.MAnnotationSampleTest" />
+    </classes>
   </test>
 
 </suite>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/testng.git



More information about the pkg-java-commits mailing list