[SUREFIRE-1766] Surefire does not display TestNG data provider values on command line
diff --git a/pom.xml b/pom.xml
index 7cde7cd..06361d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -668,6 +668,7 @@
                   <maxJdkVersion>${maven.compiler.target}</maxJdkVersion>
                   <excludes>
                     <exclude>org.junit.platform:junit-platform-commons</exclude>
+                    <exclude>org.assertj:assertj-core</exclude>
                   </excludes>
                 </enforceBytecodeVersion>
               </rules>
diff --git a/surefire-providers/surefire-testng/pom.xml b/surefire-providers/surefire-testng/pom.xml
index 2dddddc..539cdcd 100644
--- a/surefire-providers/surefire-testng/pom.xml
+++ b/surefire-providers/surefire-testng/pom.xml
@@ -17,76 +17,93 @@
   ~ under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.maven.surefire</groupId>
-    <artifactId>surefire-providers</artifactId>
-    <version>3.0.0-SNAPSHOT</version>
-  </parent>
+    <parent>
+        <groupId>org.apache.maven.surefire</groupId>
+        <artifactId>surefire-providers</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
 
-  <artifactId>surefire-testng</artifactId>
+    <artifactId>surefire-testng</artifactId>
 
-  <name>SureFire TestNG Runner</name>
-  <description>SureFire TestNG Runner</description>
+    <name>SureFire TestNG Runner</name>
+    <description>SureFire TestNG Runner</description>
 
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>3.8.2</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.surefire</groupId>
-      <artifactId>common-java5</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.surefire</groupId>
-      <artifactId>surefire-testng-utils</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.testng</groupId>
-      <artifactId>testng</artifactId>
-      <version>5.10</version>
-      <classifier>jdk15</classifier>
-      <scope>provided</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.jacoco</groupId>
-        <artifactId>jacoco-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>jacoco-agent</id>
-            <goals>
-              <goal>prepare-agent</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <propertyName>jacoco.agent</propertyName>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
-        </configuration>
-        <dependencies>
-          <dependency>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.maven.surefire</groupId>
-            <artifactId>surefire-shadefire</artifactId>
-            <version>3.0.0-M4</version> <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
-          </dependency>
-        </dependencies>
-      </plugin>
-    </plugins>
-  </build>
+            <artifactId>common-java5</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.surefire</groupId>
+            <artifactId>surefire-testng-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>5.10</version>
+            <classifier>jdk15</classifier>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-reflect</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>jacoco-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <propertyName>jacoco.agent</propertyName>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>${jvm.args.tests} ${jacoco.agent}</argLine>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.surefire</groupId>
+                        <artifactId>surefire-shadefire</artifactId>
+                        <!-- ${shadedVersion}, but resolved due to https://issues.apache.org/jira/browse/MRELEASE-799 -->
+                        <version>3.0.0-M4</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
index 83c9d2b..1c483a5 100644
--- a/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
+++ b/surefire-providers/surefire-testng/src/main/java/org/apache/maven/surefire/testng/TestNGReporter.java
@@ -32,6 +32,8 @@
 import org.testng.ITestListener;
 import org.testng.ITestResult;
 
+import java.util.Arrays;
+
 import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
 import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
 
@@ -67,13 +69,13 @@
     {
         String clazz = result.getTestClass().getName();
         String group = groupString( result.getMethod().getGroups(), clazz );
-        reporter.testStarting( new CategorizedReportEntry( clazz, result.getName(), group ) );
+        reporter.testStarting( new CategorizedReportEntry( clazz, testName( result ), group ) );
     }
 
     @Override
     public void onTestSuccess( ITestResult result )
     {
-        ReportEntry report = new SimpleReportEntry( result.getTestClass().getName(), null, result.getName(), null );
+        ReportEntry report = new SimpleReportEntry( result.getTestClass().getName(), null, testName( result ), null );
         reporter.testSucceeded( report );
     }
 
@@ -81,10 +83,9 @@
     public void onTestFailure( ITestResult result )
     {
         IClass clazz = result.getTestClass();
-        ReportEntry report = withException( clazz.getName(), null, result.getName(), null,
-                new PojoStackTraceWriter( clazz.getRealClass().getName(),
-                        result.getMethod().getMethodName(),
-                        result.getThrowable() ) );
+        ReportEntry report = withException( clazz.getName(), null, testName( result ), null,
+            new PojoStackTraceWriter( clazz.getRealClass().getName(), result.getMethod().getMethodName(),
+                result.getThrowable() ) );
 
         reporter.testFailed( report );
     }
@@ -95,7 +96,7 @@
         //noinspection ThrowableResultOfMethodCallIgnored
         Throwable t = result.getThrowable();
         String reason = t == null ? null : t.getMessage();
-        ReportEntry report = ignored( result.getTestClass().getName(), null, result.getName(), null, reason );
+        ReportEntry report = ignored( result.getTestClass().getName(), null, testName( result ), null, reason );
         reporter.testSkipped( report );
     }
 
@@ -103,10 +104,9 @@
     public void onTestFailedButWithinSuccessPercentage( ITestResult result )
     {
         IClass clazz = result.getTestClass();
-        ReportEntry report = withException( clazz.getName(), null, result.getName(), null,
-                new PojoStackTraceWriter( clazz.getRealClass().getName(),
-                        result.getMethod().getMethodName(),
-                        result.getThrowable() ) );
+        ReportEntry report = withException( clazz.getName(), null, testName( result ), null,
+            new PojoStackTraceWriter( clazz.getRealClass().getName(), result.getMethod().getMethodName(),
+                result.getThrowable() ) );
 
         reporter.testSucceeded( report );
     }
@@ -183,4 +183,18 @@
         //onTestSuccess( result );
     }
 
+    /**
+     * Acquire a better representation of the test name that includes parameters and the invocation count, if there are
+     * any parameters
+     *
+     * @param result the test result to extract from
+     * @return a descriptive name for the test
+     */
+    private static String testName( ITestResult result )
+    {
+        Object[] parameters = result.getParameters();
+        String name = result.getName();
+        return parameters == null || parameters.length == 0
+            ? name : name + Arrays.toString( parameters ) + "(" + result.getMethod().getCurrentInvocationCount() + ")";
+    }
 }
diff --git a/surefire-providers/surefire-testng/src/test/java/org/apache/maven/surefire/testng/TestNGReporterTest.java b/surefire-providers/surefire-testng/src/test/java/org/apache/maven/surefire/testng/TestNGReporterTest.java
new file mode 100644
index 0000000..36a7600
--- /dev/null
+++ b/surefire-providers/surefire-testng/src/test/java/org/apache/maven/surefire/testng/TestNGReporterTest.java
@@ -0,0 +1,240 @@
+package org.apache.maven.surefire.testng;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.TestCase;
+import org.apache.maven.surefire.report.CategorizedReportEntry;
+import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.mockito.ArgumentCaptor;
+import org.testng.ITestClass;
+import org.testng.ITestNGMethod;
+import org.testng.ITestResult;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ * Tests for {@link TestNGReporter}.
+ */
+public class TestNGReporterTest extends TestCase
+{
+    public void testParameterizedTestName() throws Exception
+    {
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 3 );
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+        when( testResult.getMethod() ).thenReturn( method );
+        String testName = invokeMethod( TestNGReporter.class, "testName", testResult );
+        assertThat( testName )
+            .isEqualTo( "myTest[val1, val2](3)" );
+    }
+
+    public void testWithoutParameterizedTestName() throws Exception
+    {
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getMethod() ).thenReturn( method );
+        String testName = invokeMethod( TestNGReporter.class, "testName", testResult );
+        assertThat( testName )
+            .isEqualTo( "myTest" );
+    }
+
+    public void testOnTestStart()
+    {
+        ITestClass cls = mock( ITestClass.class );
+        when( cls.getName() ).thenReturn( "pkg.MyClass" );
+
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 3 );
+        when( method.getGroups() ).thenReturn( new String[0] );
+
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getTestClass() ).thenReturn( cls );
+        when( testResult.getMethod() ).thenReturn( method );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+
+        RunListener listener = mock( RunListener.class );
+        TestNGReporter reporter = new TestNGReporter( listener );
+        reporter.onTestStart( testResult );
+
+        ArgumentCaptor<CategorizedReportEntry> reportEntry = ArgumentCaptor.forClass( CategorizedReportEntry.class );
+        verify( listener ).testStarting( reportEntry.capture() );
+        verifyNoMoreInteractions( listener );
+
+        assertThat( reportEntry.getValue().getSourceName() )
+            .isEqualTo( "pkg.MyClass" );
+
+        assertThat( reportEntry.getValue().getName() )
+            .isEqualTo( "myTest[val1, val2](3)" );
+    }
+
+    public void testOnTestSuccess()
+    {
+        ITestClass cls = mock( ITestClass.class );
+        when( cls.getName() ).thenReturn( "pkg.MyClass" );
+
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 3 );
+
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getTestClass() ).thenReturn( cls );
+        when( testResult.getMethod() ).thenReturn( method );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+
+        RunListener listener = mock( RunListener.class );
+        TestNGReporter reporter = new TestNGReporter( listener );
+        reporter.onTestSuccess( testResult );
+
+        ArgumentCaptor<SimpleReportEntry> reportEntry = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSucceeded( reportEntry.capture() );
+        verifyNoMoreInteractions( listener );
+
+        assertThat( reportEntry.getValue().getSourceName() )
+            .isEqualTo( "pkg.MyClass" );
+
+        assertThat( reportEntry.getValue().getName() )
+            .isEqualTo( "myTest[val1, val2](3)" );
+    }
+
+    public void testOnTestFailure()
+    {
+        Exception stackTrace = new Exception();
+
+        ITestClass cls = mock( ITestClass.class );
+        when( cls.getName() ).thenReturn( getClass().getName() );
+
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 1 );
+        when( method.getMethodName() ).thenReturn( "myTest" );
+
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getThrowable() ).thenReturn( stackTrace );
+        when( cls.getRealClass() ).thenReturn( getClass() );
+        when( testResult.getTestClass() ).thenReturn( cls );
+        when( testResult.getMethod() ).thenReturn( method );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+
+        RunListener listener = mock( RunListener.class );
+        TestNGReporter reporter = new TestNGReporter( listener );
+        reporter.onTestFailure( testResult );
+
+        ArgumentCaptor<SimpleReportEntry> reportEntry = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testFailed( reportEntry.capture() );
+        verifyNoMoreInteractions( listener );
+
+        assertThat( reportEntry.getValue().getSourceName() )
+            .isEqualTo( getClass().getName() );
+
+        assertThat( reportEntry.getValue().getName() )
+            .isEqualTo( "myTest[val1, val2](1)" );
+
+        assertThat( reportEntry.getValue().getStackTraceWriter() )
+            .isNotNull();
+
+        assertThat( reportEntry.getValue().getStackTraceWriter().getThrowable().getTarget() )
+            .isSameAs( stackTrace );
+    }
+
+    public void testOnSkippedTest()
+    {
+        Exception stackTrace = new Exception( "test skip reason" );
+
+        ITestClass cls = mock( ITestClass.class );
+        when( cls.getName() ).thenReturn( getClass().getName() );
+
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 1 );
+
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getThrowable() ).thenReturn( stackTrace );
+        when( testResult.getTestClass() ).thenReturn( cls );
+        when( testResult.getMethod() ).thenReturn( method );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+
+        RunListener listener = mock( RunListener.class );
+        TestNGReporter reporter = new TestNGReporter( listener );
+        reporter.onTestSkipped( testResult );
+
+        ArgumentCaptor<SimpleReportEntry> reportEntry = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSkipped( reportEntry.capture() );
+        verifyNoMoreInteractions( listener );
+
+        assertThat( reportEntry.getValue().getSourceName() )
+            .isEqualTo( getClass().getName() );
+
+        assertThat( reportEntry.getValue().getName() )
+            .isEqualTo( "myTest[val1, val2](1)" );
+
+        assertThat( reportEntry.getValue().getMessage() )
+            .isEqualTo( stackTrace.getMessage() );
+    }
+
+    public void testOnTestFailedButWithinSuccessPercentage()
+    {
+        Exception stackTrace = new Exception();
+
+        ITestClass cls = mock( ITestClass.class );
+        when( cls.getName() ).thenReturn( getClass().getName() );
+
+        ITestNGMethod method = mock( ITestNGMethod.class );
+        when( method.getCurrentInvocationCount() ).thenReturn( 1 );
+        when( method.getMethodName() ).thenReturn( "myTest" );
+
+        ITestResult testResult = mock( ITestResult.class );
+        when( testResult.getThrowable() ).thenReturn( stackTrace );
+        when( cls.getRealClass() ).thenReturn( getClass() );
+        when( testResult.getTestClass() ).thenReturn( cls );
+        when( testResult.getMethod() ).thenReturn( method );
+        when( testResult.getName() ).thenReturn( "myTest" );
+        when( testResult.getParameters() ).thenReturn( new String[] { "val1", "val2" } );
+
+        RunListener listener = mock( RunListener.class );
+        TestNGReporter reporter = new TestNGReporter( listener );
+        reporter.onTestFailedButWithinSuccessPercentage( testResult );
+
+        ArgumentCaptor<SimpleReportEntry> reportEntry = ArgumentCaptor.forClass( SimpleReportEntry.class );
+        verify( listener ).testSucceeded( reportEntry.capture() );
+        verifyNoMoreInteractions( listener );
+
+        assertThat( reportEntry.getValue().getSourceName() )
+            .isEqualTo( getClass().getName() );
+
+        assertThat( reportEntry.getValue().getName() )
+            .isEqualTo( "myTest[val1, val2](1)" );
+
+        assertThat( reportEntry.getValue().getStackTraceWriter() )
+            .isNotNull();
+
+        assertThat( reportEntry.getValue().getStackTraceWriter().getThrowable().getTarget() )
+            .isSameAs( stackTrace );
+    }
+}