The same method invoked multiple times was reporting the same time stamp.

Fix for:

- http://code.google.com/p/testng/issues/detail?id=7
- http://code.google.com/p/testng/issues/detail?id=86

Details:

- Added ISuite#getAllInvokedMethods
- Made SuiteRunner an IInvokedMethodListener to store invoked methods
- Updated SuiteRunner to use getAllInvokedMethods
- Added a test to InvokedMethodListenerTest
diff --git a/CHANGES.txt b/CHANGES.txt
index eac6d7f..bf0d2fd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -8,6 +8,8 @@
 Added: Hierarchical XmlSuites (Nalin Makar) 
 Added: Reporter#clear()
 Fixed: Initialize all Suite/Test runners at beginning to catch configuration issues right at start (Nalin Makar)
+Fixed: Incorrect dates reported for configuration methods (http://code.google.com/p/testng/issues/detail?id=7 and 86)
+Fixed: Initialize all Suite/Test runners at beginning to catch configuration issues right at start
 Fixed: Issue24 OOM errors in SuiteHTMLReporter (Nalin Makar)
 Fixed: Time outs specified in XML were not honored for <suite parallel="tests">
 Fixed: <suite> and <test> time outs were hardcoded, they now honor their time-out attribute
diff --git a/src/org/testng/ISuite.java b/src/org/testng/ISuite.java
index c9eccb9..99f0b5d 100755
--- a/src/org/testng/ISuite.java
+++ b/src/org/testng/ISuite.java
@@ -2,6 +2,7 @@
 

 

 import java.util.Collection;

+import java.util.List;

 import java.util.Map;

 

 import org.testng.internal.annotations.IAnnotationFinder;

@@ -56,10 +57,16 @@
   /**

    * Retrieves the list of all the methods that were invoked during this run.

    * @return a collection of ITestNGMethods belonging to all tests included in the suite.

+   * @deprecated Use getAllInvokedMthods().

    */

   public Collection<ITestNGMethod> getInvokedMethods();

 

   /**

+   * @return a list of all the methods that were invoked in this suite.

+   */

+  public List<IInvokedMethod> getAllInvokedMethods();

+

+  /**

    * @return All the methods that were not included in this test run.

    */

   public Collection<ITestNGMethod> getExcludedMethods();

diff --git a/src/org/testng/Reporter.java b/src/org/testng/Reporter.java
index 1d90a5e..842bda4 100755
--- a/src/org/testng/Reporter.java
+++ b/src/org/testng/Reporter.java
@@ -52,6 +52,7 @@
    */
   public static void clear() {
     m_methodOutputMap.clear();
+    m_output.clear();
   }
 
   private static synchronized void log(String s, ITestResult m) {
diff --git a/src/org/testng/SuiteRunner.java b/src/org/testng/SuiteRunner.java
index 850ca20..41e26c0 100644
--- a/src/org/testng/SuiteRunner.java
+++ b/src/org/testng/SuiteRunner.java
@@ -30,7 +30,7 @@
  *
  * @author Cedric Beust, Apr 26, 2004
  */
-public class SuiteRunner implements ISuite, Serializable {
+public class SuiteRunner implements ISuite, Serializable, IInvokedMethodListener {
   
   /* generated */
   private static final long serialVersionUID = 5284208932089503131L;
@@ -62,7 +62,10 @@
 
   private IMethodInterceptor m_methodInterceptor;
   private List<IInvokedMethodListener> m_invokedMethodListeners;
-  
+
+  /** The list of all the methods invoked during this run */
+  private List<IInvokedMethod> m_invokedMethods = Lists.newArrayList();
+
 //  transient private IAnnotationTransformer m_annotationTransformer = null;
 
   public SuiteRunner(IConfiguration configuration, XmlSuite suite,
@@ -122,6 +125,12 @@
       m_objectFactory = suite.getObjectFactory();
     }
     m_invokedMethodListeners = invokedMethodListener;
+    // Add our own IInvokedMethodListener
+    if (m_invokedMethodListeners == null) {
+      m_invokedMethodListeners = Lists.newArrayList();
+    }
+    m_invokedMethodListeners.add(this);
+
     m_skipFailedInvocationCounts = suite.skipFailedInvocationCounts();
     if (null != testListeners) {
       m_testListeners.addAll(testListeners);
@@ -560,4 +569,25 @@
   public Object removeAttribute(String name) {
     return m_attributes.removeAttribute(name);
   }
+
+  /////
+  // implements IInvokedMethodListener
+  //
+
+  @Override
+  public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
+    m_invokedMethods.add(method);
+  }
+
+  @Override
+  public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
+  }
+
+  //
+  // implements IInvokedMethodListener
+  /////
+
+  public List<IInvokedMethod> getAllInvokedMethods() {
+    return m_invokedMethods;
+  }
 }
diff --git a/src/org/testng/reporters/SuiteHTMLReporter.java b/src/org/testng/reporters/SuiteHTMLReporter.java
index b9e2731..eea7051 100755
--- a/src/org/testng/reporters/SuiteHTMLReporter.java
+++ b/src/org/testng/reporters/SuiteHTMLReporter.java
@@ -1,5 +1,17 @@
 package org.testng.reporters;
 
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.IInvokedMethod;
 import org.testng.IReporter;
 import org.testng.ISuite;
 import org.testng.ISuiteResult;
@@ -12,17 +24,6 @@
 import org.testng.internal.Utils;
 import org.testng.xml.XmlSuite;
 
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-
 /**
  * This class implements an HTML reporter for suites.
  * 
@@ -345,14 +346,14 @@
     Utils.writeFile(getOutputDirectory(xmlSuite), outputFileName, sb.toString());
     sb = null; //not needed anymore
 
-    Collection<ITestNGMethod> invokedMethods = suite.getInvokedMethods();
+    Collection<IInvokedMethod> invokedMethods = suite.getAllInvokedMethods();
     if (alphabetical) {
       @SuppressWarnings({"unchecked"})
       Comparator<? super ITestNGMethod>  alphabeticalComparator = new Comparator(){
         public int compare(Object o1, Object o2) {
-          ITestNGMethod m1 = (ITestNGMethod) o1;
-          ITestNGMethod m2 = (ITestNGMethod) o2;
-          return m1.getMethodName().compareTo(m2.getMethodName());
+          IInvokedMethod m1 = (IInvokedMethod) o1;
+          IInvokedMethod m2 = (IInvokedMethod) o2;
+          return m1.getTestMethod().getMethodName().compareTo(m2.getTestMethod().getMethodName());
         }
       };
       Collections.sort((List) invokedMethods, alphabeticalComparator);
@@ -361,7 +362,8 @@
     SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
     StringBuffer table = new StringBuffer();
     boolean addedHeader = false;
-    for (ITestNGMethod tm : invokedMethods) {
+    for (IInvokedMethod iim : invokedMethods) {
+      ITestNGMethod tm = iim.getTestMethod();
       table.setLength(0);
       if (!addedHeader) {
         table.append("<table border=\"1\">\n")
@@ -407,11 +409,11 @@
         instances.append(o).append(" ");
       }
       
-      if (startDate == -1) startDate = tm.getDate();
-      String date = format.format(tm.getDate());
+      if (startDate == -1) startDate = iim.getDate();
+      String date = format.format(iim.getDate());
       table.append("<tr bgcolor=\"" + createColor(tm) + "\">")
         .append("  <td>").append(date).append("</td> ")
-        .append("  <td>").append(tm.getDate() - startDate).append("</td> ")
+        .append("  <td>").append(iim.getDate() - startDate).append("</td> ")
         .append(td(configurationSuiteMethod))
         .append(td(configurationTestMethod))
         .append(td(configurationClassMethod))
diff --git a/test/src/test/invokedmethodlistener/InvokedMethodListener.java b/test/src/test/invokedmethodlistener/InvokedMethodListener.java
new file mode 100644
index 0000000..1f7b687
--- /dev/null
+++ b/test/src/test/invokedmethodlistener/InvokedMethodListener.java
@@ -0,0 +1,24 @@
+package test.invokedmethodlistener;
+
+import java.util.List;
+
+import org.testng.IInvokedMethod;
+import org.testng.IInvokedMethodListener;
+import org.testng.ITestResult;
+import org.testng.collections.Lists;
+
+public class InvokedMethodListener implements IInvokedMethodListener {
+  
+  public static List<IInvokedMethod> m_methods = Lists.newArrayList();
+
+  @Override
+  public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
+    if (m_methods == null) m_methods = Lists.newArrayList();
+    m_methods.add(method);
+  }
+  
+  @Override
+  public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
+  }
+
+}
diff --git a/test/src/test/invokedmethodlistener/InvokedMethodListenerTest.java b/test/src/test/invokedmethodlistener/InvokedMethodListenerTest.java
index 17c3e76..34bbbbd 100644
--- a/test/src/test/invokedmethodlistener/InvokedMethodListenerTest.java
+++ b/test/src/test/invokedmethodlistener/InvokedMethodListenerTest.java
@@ -1,6 +1,10 @@
 package test.invokedmethodlistener;
 
+import java.util.List;
+
 import org.testng.Assert;
+import org.testng.IInvokedMethod;
+import org.testng.ITestNGMethod;
 import org.testng.ITestResult;
 import org.testng.TestNG;
 import org.testng.annotations.Test;
@@ -38,4 +42,25 @@
     Assert.assertTrue(null != l.getMethodThrowable());
     Assert.assertTrue(l.getMethodThrowable().getClass() == IllegalArgumentException.class);
   }
+
+  /**
+   * Fix for:
+   * http://code.google.com/p/testng/issues/detail?id=7
+   * http://code.google.com/p/testng/issues/detail?id=86
+   */
+  @Test
+  public void sameMethodInvokedMultipleTimesShouldHaveDifferentTimeStamps() {
+    TestNG tng = create(Sample.class);
+    tng.addListener(new InvokedMethodListener());
+    tng.run();
+    List<IInvokedMethod> m = InvokedMethodListener.m_methods;
+//    for (IInvokedMethod mm : m) {
+//      System.out.println(mm.getTestMethod().getMethodName() + " " + mm.getDate());
+//    }
+    IInvokedMethod after1 = m.get(1);
+    Assert.assertTrue(after1.getTestMethod().isAfterMethodConfiguration());
+    IInvokedMethod after2 = m.get(3);
+    Assert.assertTrue(after2.getTestMethod().isAfterMethodConfiguration());
+    Assert.assertTrue(after1.getDate() != after2.getDate());
+  }
 }
diff --git a/test/src/test/invokedmethodlistener/Sample.java b/test/src/test/invokedmethodlistener/Sample.java
new file mode 100644
index 0000000..78ffc78
--- /dev/null
+++ b/test/src/test/invokedmethodlistener/Sample.java
@@ -0,0 +1,30 @@
+package test.invokedmethodlistener;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+public class Sample {
+
+  @Test
+  public void t1() {
+    try {
+      Thread.sleep(100);
+    } catch (InterruptedException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void t2() {
+    try {
+      Thread.sleep(100);
+    } catch (InterruptedException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+  }
+
+  @AfterMethod
+  public void am() {}
+}
diff --git a/test/src/test/tmp/A.java b/test/src/test/tmp/A.java
index 9fc07f7..695b74b 100644
--- a/test/src/test/tmp/A.java
+++ b/test/src/test/tmp/A.java
@@ -1,6 +1,5 @@
 package test.tmp;
 
-import org.testng.Reporter;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -37,16 +36,17 @@
 
   @Test
   public void atest1() {
-    System.out.println("A.atest1");
-    Reporter.log("line 1");
-    Reporter.log("line 2");
+    try {
+      Thread.sleep(12*1000);
+    } catch (InterruptedException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
   }
 
-  @Test
+//  @Test(dependsOnMethods = "atest1")
   public void atest2() {
-    System.out.println("A.atest2");
-    Reporter.clear();
-    Reporter.log("atest2");
+    log("atest2");
   }
 
 //  @Test(priority = 3)
diff --git a/test/testng-single.xml b/test/testng-single.xml
index e5d679b..863e4f3 100644
--- a/test/testng-single.xml
+++ b/test/testng-single.xml
@@ -26,9 +26,11 @@
     </groups>
     <parameter name="count" value="10"/>
     <classes>
-      <class name="test.preserveorder.PreserveOrderTest" />
+      <class name="test.invokedmethodlistener.InvokedMethodListenerTest" />
 <!-- 
       <class name="test.tmp.A" />
+      <class name="test.thread.MultiThreadedDependentTest" />
+      <class name="test.thread.FactoryTest" />
       <class name="test.tmp.B" />
       <class name="test.thread.MultiThreadedDependentTest" />
       <class name="test.thread.FactoryTest" />