diff --git a/CHANGES.txt b/CHANGES.txt
index fa0add3e7..0a2108680 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
Current (7.11.0)
+Fixed: GITHUB-3111: Replacement API for IClass.getInstanceHashCodes() and IClass.getInstances(boolean) (Krishnan Mahadevan)
7.10.1
Fixed: GITHUB-3110: Update from testng 7.9.0 to 7.10.0 break maven build with junit5 (Krishnan Mahadevan)
diff --git a/testng-core-api/src/main/java/org/testng/IParameterInfo.java b/testng-core-api/src/main/java/org/testng/IParameterInfo.java
new file mode 100644
index 000000000..3374d1eb2
--- /dev/null
+++ b/testng-core-api/src/main/java/org/testng/IParameterInfo.java
@@ -0,0 +1,36 @@
+package org.testng;
+
+/** Represents the ability to retrieve the parameters associated with a factory method. */
+public interface IParameterInfo {
+
+ /** @return - The actual instance associated with a factory method */
+ Object getInstance();
+
+ /**
+ * @return - The actual index of instance associated with a factory method. This index has a 1:1
+ * correspondence with what were specified via the indices
attribute of the
+ * @Factory
annotation. For e.g., lets say you specified the
+ * indices to the "1" and your factory returned 4 instances, then the instance on which this
+ * method is invoked would have the value as "1".
+ */
+ int getIndex();
+
+ /**
+ * @return - returns an index which indicates the running position in the array of test class
+ * instances that were produced by a @Factory
annotated constructor or static
+ * method. For e.g., lets say your @Factory
method returned 4 instances, then
+ * each of the invocations to this method would return a value from 0
to 3
+ *
+ */
+ int currentIndex();
+
+ /** @return - The parameters associated with the factory method as an array. */
+ Object[] getParameters();
+
+ static Object embeddedInstance(Object original) {
+ if (original instanceof IParameterInfo) {
+ return ((IParameterInfo) original).getInstance();
+ }
+ return original;
+ }
+}
diff --git a/testng-core-api/src/main/java/org/testng/internal/IParameterInfo.java b/testng-core-api/src/main/java/org/testng/internal/IParameterInfo.java
index 6ccf1b041..3446078ec 100644
--- a/testng-core-api/src/main/java/org/testng/internal/IParameterInfo.java
+++ b/testng-core-api/src/main/java/org/testng/internal/IParameterInfo.java
@@ -1,21 +1,9 @@
package org.testng.internal;
-/** Represents the ability to retrieve the parameters associated with a factory method. */
-public interface IParameterInfo {
-
- /** @return - The actual instance associated with a factory method */
- Object getInstance();
-
- /** @return - The actual index of instance associated with a factory method */
- int getIndex();
-
- /** @return - The parameters associated with the factory method as an array. */
- Object[] getParameters();
-
- static Object embeddedInstance(Object original) {
- if (original instanceof IParameterInfo) {
- return ((IParameterInfo) original).getInstance();
- }
- return original;
- }
-}
+/**
+ * Represents the ability to retrieve the parameters associated with a factory method.
+ *
+ * @deprecated - This interface stands deprecated as of TestNG 7.11.0
.
+ */
+@Deprecated
+public interface IParameterInfo extends org.testng.IParameterInfo {}
diff --git a/testng-core/src/main/java/org/testng/internal/BaseTestMethod.java b/testng-core/src/main/java/org/testng/internal/BaseTestMethod.java
index c0ad3379f..fbee5f4c6 100644
--- a/testng-core/src/main/java/org/testng/internal/BaseTestMethod.java
+++ b/testng-core/src/main/java/org/testng/internal/BaseTestMethod.java
@@ -153,7 +153,7 @@ public String getMethodName() {
public Object getInstance() {
return Optional.ofNullable(m_instance)
.map(IObject.IdentifiableObject::getInstance)
- .map(IParameterInfo::embeddedInstance)
+ .map(org.testng.IParameterInfo::embeddedInstance)
.orElse(null);
}
diff --git a/testng-core/src/main/java/org/testng/internal/ClassImpl.java b/testng-core/src/main/java/org/testng/internal/ClassImpl.java
index f893b6008..098e7f191 100644
--- a/testng-core/src/main/java/org/testng/internal/ClassImpl.java
+++ b/testng-core/src/main/java/org/testng/internal/ClassImpl.java
@@ -162,7 +162,7 @@ public void addInstance(Object instance) {
}
private static int computeHashCode(Object instance) {
- return IParameterInfo.embeddedInstance(instance).hashCode();
+ return org.testng.IParameterInfo.embeddedInstance(instance).hashCode();
}
private DetailedAttributes newDetailedAttributes(boolean create, String errMsgPrefix) {
diff --git a/testng-core/src/main/java/org/testng/internal/FactoryMethod.java b/testng-core/src/main/java/org/testng/internal/FactoryMethod.java
index c5bf4de1f..901ad7cb7 100644
--- a/testng-core/src/main/java/org/testng/internal/FactoryMethod.java
+++ b/testng-core/src/main/java/org/testng/internal/FactoryMethod.java
@@ -7,6 +7,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.testng.DataProviderHolder;
import org.testng.IDataProviderInterceptor;
@@ -144,8 +145,8 @@ private static String[] getAllGroups(
return groups.toArray(new String[0]);
}
- public IParameterInfo[] invoke() {
- List result = Lists.newArrayList();
+ public org.testng.IParameterInfo[] invoke() {
+ List result = Lists.newArrayList();
Map allParameterNames = Maps.newHashMap();
Parameters.MethodParameters methodParameters =
@@ -174,6 +175,7 @@ public IParameterInfo[] invoke() {
try {
List indices = factoryAnnotation.getIndices();
int position = 0;
+ AtomicInteger counter = new AtomicInteger(0);
while (parameterIterator.hasNext()) {
Object[] parameters = parameterIterator.next();
if (parameters == null) {
@@ -196,13 +198,18 @@ public IParameterInfo[] invoke() {
final int instancePosition = position;
result.addAll(
Arrays.stream(testInstances)
- .map(instance -> new ParameterInfo(instance, instancePosition, parameters))
+ .map(
+ instance ->
+ new ParameterInfo(
+ instance, instancePosition, parameters, counter.getAndIncrement()))
.collect(Collectors.toList()));
} else {
for (Integer index : indices) {
int i = index - position;
if (i >= 0 && i < testInstances.length) {
- result.add(new ParameterInfo(testInstances[i], position, parameters));
+ result.add(
+ new ParameterInfo(
+ testInstances[i], position, parameters, counter.getAndIncrement()));
}
}
}
@@ -210,7 +217,8 @@ public IParameterInfo[] invoke() {
} else {
if (indices == null || indices.isEmpty() || indices.contains(position)) {
Object instance = m_objectFactory.newInstance(com.getConstructor(), parameters);
- result.add(new ParameterInfo(instance, position, parameters));
+ result.add(
+ new ParameterInfo(instance, position, parameters, counter.getAndIncrement()));
}
position++;
}
diff --git a/testng-core/src/main/java/org/testng/internal/ParameterInfo.java b/testng-core/src/main/java/org/testng/internal/ParameterInfo.java
index 7b514d1da..82e427caa 100644
--- a/testng-core/src/main/java/org/testng/internal/ParameterInfo.java
+++ b/testng-core/src/main/java/org/testng/internal/ParameterInfo.java
@@ -1,14 +1,16 @@
package org.testng.internal;
public class ParameterInfo implements IParameterInfo {
- private Object instance;
+ private final Object instance;
private final int index;
- private Object[] parameters;
+ private final Object[] parameters;
+ private final int currentIndex;
- public ParameterInfo(Object instance, int index, Object[] parameters) {
+ public ParameterInfo(Object instance, int index, Object[] parameters, int currentIndex) {
this.instance = instance;
this.index = index;
this.parameters = parameters;
+ this.currentIndex = currentIndex;
}
@Override
@@ -21,6 +23,11 @@ public int getIndex() {
return index;
}
+ @Override
+ public int currentIndex() {
+ return currentIndex;
+ }
+
@Override
public Object[] getParameters() {
return parameters;
diff --git a/testng-core/src/main/java/org/testng/internal/TestNGClassFinder.java b/testng-core/src/main/java/org/testng/internal/TestNGClassFinder.java
index b8d00d888..aa2d39efe 100644
--- a/testng-core/src/main/java/org/testng/internal/TestNGClassFinder.java
+++ b/testng-core/src/main/java/org/testng/internal/TestNGClassFinder.java
@@ -178,7 +178,7 @@ private ClassInfoMap processFactory(IClass ic, ConstructorOrMethod factoryMethod
// If the factory returned IInstanceInfo, get the class from it,
// otherwise, just call getClass() on the returned instances
int i = 0;
- for (IParameterInfo o : fm.invoke()) {
+ for (org.testng.IParameterInfo o : fm.invoke()) {
if (o == null) {
throw new TestNGException(
"The factory " + fm + " returned a null instance" + "at index " + i);
@@ -329,8 +329,8 @@ private void addInstance(IInstanceInfo ii) {
private void addInstance(IObject.IdentifiableObject o) {
Class> key = o.getInstance().getClass();
- if (o.getInstance() instanceof IParameterInfo) {
- key = ((IParameterInfo) o.getInstance()).getInstance().getClass();
+ if (o.getInstance() instanceof org.testng.IParameterInfo) {
+ key = ((org.testng.IParameterInfo) o.getInstance()).getInstance().getClass();
}
addInstance(key, o);
}
diff --git a/testng-core/src/test/java/test/factory/FactoryIntegrationTest.java b/testng-core/src/test/java/test/factory/FactoryIntegrationTest.java
index f18c8289d..21476eb89 100644
--- a/testng-core/src/test/java/test/factory/FactoryIntegrationTest.java
+++ b/testng-core/src/test/java/test/factory/FactoryIntegrationTest.java
@@ -3,13 +3,24 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
import org.testng.Assert;
+import org.testng.IParameterInfo;
+import org.testng.ITestListener;
+import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.TestNG;
import org.testng.TestNGException;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import test.InvokedMethodNameListener;
import test.SimpleBaseTest;
+import test.factory.issue3111.SimpleFactoryPoweredTestSample;
+import test.factory.issue3111.SimpleFactoryPoweredTestWithIndicesSample;
+import test.factory.issue3111.SimpleFactoryPoweredTestWithoutDataProviderSample;
+import test.factory.issue3111.SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample;
public class FactoryIntegrationTest extends SimpleBaseTest {
@@ -22,7 +33,9 @@ public void testExceptionWithNonStaticFactoryMethod() {
} catch (TestNGException e) {
assertThat(e)
.hasMessage(
- "\nCan't invoke public java.lang.Object[] test.factory.GitHub876Sample.createInstances(): either make it static or add a no-args constructor to your class");
+ "\nCan't invoke public java.lang.Object[] test.factory.GitHub876Sample"
+ + ".createInstances(): either make it static or add a no-args constructor to "
+ + "your class");
}
}
@@ -46,7 +59,8 @@ public void testExceptionWithBadFactoryMethodReturnType() {
} catch (TestNGException e) {
assertThat(e)
.hasMessage(
- "\ntest.factory.BadMethodReturnTypeFactory.createInstances MUST return [ java.lang.Object[] or org.testng.IInstanceInfo[] ] but returns java.lang.Object");
+ "\ntest.factory.BadMethodReturnTypeFactory.createInstances MUST return [ java.lang"
+ + ".Object[] or org.testng.IInstanceInfo[] ] but returns java.lang.Object");
}
}
@@ -65,4 +79,31 @@ public void doubleFactoryMethodShouldWork() {
"FactoryBaseSample{1}#f",
"FactoryBaseSample{2}#f", "FactoryBaseSample{3}#f", "FactoryBaseSample{4}#f");
}
+
+ @Test(dataProvider = "testdata", description = "GITHUB-3111")
+ public void ensureCurrentIndexWorksForFactoryPoweredTests(Class> klass, Integer[] expected) {
+ List params = new ArrayList<>();
+ TestNG testng = create(klass);
+ testng.addListener(
+ new ITestListener() {
+ @Override
+ public void onTestSuccess(ITestResult result) {
+ params.add(result.getMethod().getFactoryMethodParamsInfo());
+ }
+ });
+ testng.run();
+ List actualIndices =
+ params.stream().map(IParameterInfo::currentIndex).sorted().collect(Collectors.toList());
+ assertThat(actualIndices).containsExactly(expected);
+ }
+
+ @DataProvider(name = "testdata")
+ public Object[][] testdata() {
+ return new Object[][] {
+ {SimpleFactoryPoweredTestSample.class, new Integer[] {0, 1, 2}},
+ {SimpleFactoryPoweredTestWithIndicesSample.class, new Integer[] {0}},
+ {SimpleFactoryPoweredTestWithoutDataProviderSample.class, new Integer[] {0, 1, 2}},
+ {SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample.class, new Integer[] {0}},
+ };
+ }
}
diff --git a/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestSample.java b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestSample.java
new file mode 100644
index 000000000..a85ba3e2b
--- /dev/null
+++ b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestSample.java
@@ -0,0 +1,26 @@
+package test.factory.issue3111;
+
+import org.testng.Reporter;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class SimpleFactoryPoweredTestSample {
+
+ private final int i;
+
+ @Factory(dataProvider = "data")
+ public SimpleFactoryPoweredTestSample(int i) {
+ this.i = i;
+ }
+
+ @Test
+ public void test() {
+ Reporter.log(Integer.toString(i));
+ }
+
+ @DataProvider
+ public static Object[][] data() {
+ return new Object[][] {{1}, {2}, {3}};
+ }
+}
diff --git a/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithIndicesSample.java b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithIndicesSample.java
new file mode 100644
index 000000000..3a745ac1b
--- /dev/null
+++ b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithIndicesSample.java
@@ -0,0 +1,28 @@
+package test.factory.issue3111;
+
+import org.testng.Reporter;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class SimpleFactoryPoweredTestWithIndicesSample {
+
+ private final int i;
+
+ @Factory(
+ dataProvider = "data",
+ indices = {1})
+ public SimpleFactoryPoweredTestWithIndicesSample(int i) {
+ this.i = i;
+ }
+
+ @Test
+ public void test() {
+ Reporter.log(Integer.toString(i));
+ }
+
+ @DataProvider
+ public static Object[][] data() {
+ return new Object[][] {{1}, {2}, {3}};
+ }
+}
diff --git a/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderSample.java b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderSample.java
new file mode 100644
index 000000000..fb8bb9dac
--- /dev/null
+++ b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderSample.java
@@ -0,0 +1,28 @@
+package test.factory.issue3111;
+
+import org.testng.Reporter;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class SimpleFactoryPoweredTestWithoutDataProviderSample {
+
+ private final int i;
+
+ public SimpleFactoryPoweredTestWithoutDataProviderSample(int i) {
+ this.i = i;
+ }
+
+ @Test
+ public void test() {
+ Reporter.log(Integer.toString(i));
+ }
+
+ @Factory
+ public static Object[] data() {
+ return new Object[] {
+ new SimpleFactoryPoweredTestWithoutDataProviderSample(1),
+ new SimpleFactoryPoweredTestWithoutDataProviderSample(2),
+ new SimpleFactoryPoweredTestWithoutDataProviderSample(3),
+ };
+ }
+}
diff --git a/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample.java b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample.java
new file mode 100644
index 000000000..be564b302
--- /dev/null
+++ b/testng-core/src/test/java/test/factory/issue3111/SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample.java
@@ -0,0 +1,28 @@
+package test.factory.issue3111;
+
+import org.testng.Reporter;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample {
+
+ private final int i;
+
+ public SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample(int i) {
+ this.i = i;
+ }
+
+ @Test
+ public void test() {
+ Reporter.log(Integer.toString(i));
+ }
+
+ @Factory(indices = {1})
+ public static Object[] data() {
+ return new Object[] {
+ new SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample(1),
+ new SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample(2),
+ new SimpleFactoryPoweredTestWithoutDataProviderWithIndicesSample(3),
+ };
+ }
+}
diff --git a/testng-runner-api/src/main/java/org/testng/internal/TestResult.java b/testng-runner-api/src/main/java/org/testng/internal/TestResult.java
index e48352d8c..2e730047c 100644
--- a/testng-runner-api/src/main/java/org/testng/internal/TestResult.java
+++ b/testng-runner-api/src/main/java/org/testng/internal/TestResult.java
@@ -298,7 +298,7 @@ public void setParameters(Object[] parameters) {
@Override
public Object getInstance() {
- return IParameterInfo.embeddedInstance(this.m_method.getInstance());
+ return org.testng.IParameterInfo.embeddedInstance(this.m_method.getInstance());
}
@Override