Merge branch 'master' of git://github.com/cbeust/testng
diff --git a/CHANGES.txt b/CHANGES.txt
index a8b0f1d..7630064 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -18,6 +18,11 @@
 Fixed: Invoke IInvokedMethodListener.afterInvocation after fixing results for tests expecting exceptions (Nalin Makar)
 
 Eclipse:
+Added: Excluded methods are now listed in the Summary tab
+Added: Double clicking on an excluded method in the Summary tab will take you to its definition
+Added: If you select a package before invoking the "New TestNG class" wizard, the source and package text boxes will be auto-filled
+Added: When an item is selected in a tab, the same item will be selected when switching tabs
+Added: A new "Summary" tab that allows the user to see a summary of the tests, sort them by time, name, etc...
 Added: It's now possible "Run/Debug As" with a right click from pretty much any element that makes sense in the tree.
 Added: The conversion of a JUnit test to TestNG now replaces @Test(timeout) with @Test(timeOut) (5.14.2.4)
 Added: The conversion of a JUnit test to TestNG now replaces @Test(expected) with @Test(expectedExceptions) (5.14.2.4)
@@ -26,6 +31,8 @@
 Added: The progress bar is now orange if the suite contained skipped tests and no failures
 Added: Skipped test and suite icons are now orange (previously: blue)
 Added: New method shortcuts: "Alt+Shift+X N", "Alt+Shift+D N" (Sven Johansson)
+Fixed: NPE when you select a passed test and click on the Compare Result icon (Mohamed Mansour)
+Fixed: When the run is over, the plug-in will no longer force the focus back to the Console view
 Fixed: The counter in the progress bar sometimes went over the total number of test methods (5.14.2.9)
 Fixed: org.eclipse.ui.internal.ErrorViewPart cannot be cast to org.testng.eclipse.ui.TestRunnerViewPart (5.14.2.9)
 Fixed: Workspace preferences now offer the "XML template" option as well as the project specific preferences (Asiel Brumfield)
diff --git a/src/main/java/org/testng/TestNG.java b/src/main/java/org/testng/TestNG.java
index cd88b2d..56bc4a2 100644
--- a/src/main/java/org/testng/TestNG.java
+++ b/src/main/java/org/testng/TestNG.java
@@ -689,8 +689,8 @@
     return m_suiteListeners;
   }
 
-  /** The verbosity level. TODO why not a simple int? */
-  private int m_verbose = 1;
+  /** If m_verbose gets set, it will override the verbose setting in testng.xml */
+  private Integer m_verbose = null;
 
   private IAnnotationTransformer m_annotationTransformer = new DefaultAnnotationTransformer();
 
@@ -869,31 +869,25 @@
   public List<ISuite> runSuitesLocally() {
     Map<XmlSuite, ISuite> suiteRunnerMap = Maps.newHashMap();
     if (m_suites.size() > 0) {
-      /*
-       * first initialize the suite runners to ensure there are no configuration issues.
-       * Create a map with XmlSuite as key and corresponding SuiteRunner as value
-       */
+       // First initialize the suite runners to ensure there are no configuration issues.
+       // Create a map with XmlSuite as key and corresponding SuiteRunner as value
       for (XmlSuite xmlSuite : m_suites) {
         createSuiteRunners(suiteRunnerMap, xmlSuite);
       }
 
-      /*
-       * Run suites
-       */
+      //
+      // Run suites
+      //
       if (m_suiteThreadPoolSize == 1 && !m_randomizeSuites) {
-        /*
-         * Only of we want suites to run in order specified in XML and the suite thread pool
-         * size is 1, we run this block
-         */
+        // Single threaded and not randomized: run the suites in order
         for (XmlSuite xmlSuite : m_suites) {
-          runSuitesSequentially(xmlSuite, suiteRunnerMap, m_verbose, getDefaultSuiteName());
+          runSuitesSequentially(xmlSuite, suiteRunnerMap, xmlSuite.getVerbose(),
+              getDefaultSuiteName());
         }
       } else {
-        /*
-         * Generate a dynamic graph that stores the suite hierarchy. This is then
-         * used to run related suites in specific order. Parent suites are run only
-         * once all the child suites have completed execution
-         */
+        // Multithreaded: generate a dynamic graph that stores the suite hierarchy. This is then
+        // used to run related suites in specific order. Parent suites are run only
+        // once all the child suites have completed execution
         DynamicGraph<ISuite> suiteGraph = new DynamicGraph<ISuite>();
         for (XmlSuite xmlSuite : m_suites) {
           populateSuiteGraph(suiteGraph, suiteRunnerMap, xmlSuite);
@@ -907,10 +901,9 @@
           new LinkedBlockingQueue<Runnable>());
 
         Utils.log("TestNG", 2, "Starting executor for all suites");
-        //run all suites in parallel
+        // Run all suites in parallel
         pooledExecutor.run();
         try {
-          //TODO: Setting timeout to Long.MAX_VALUE. Is it correct/ok?
           pooledExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
           pooledExecutor.shutdownNow();
         }
@@ -1011,7 +1004,8 @@
       xmlSuite.setSkipFailedInvocationCounts(m_skipFailedInvocationCounts);
     }
 
-    if (xmlSuite.getVerbose() == null) {
+    // Override the XmlSuite verbose value with the one from TestNG
+    if (m_verbose != null) {
       xmlSuite.setVerbose(m_verbose);
     }
 
diff --git a/src/main/java/org/testng/internal/Utils.java b/src/main/java/org/testng/internal/Utils.java
index 786cfd6..f4a71c1 100644
--- a/src/main/java/org/testng/internal/Utils.java
+++ b/src/main/java/org/testng/internal/Utils.java
@@ -14,9 +14,12 @@
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.StringReader;
@@ -713,4 +716,31 @@
 
     return sb.toString();
   }
+
+  public static void copyFile(File from, File to) {
+    try{
+      InputStream in = new FileInputStream(from);
+
+      //For Append the file.
+//        OutputStream out = new FileOutputStream(f2,true);
+
+      //For Overwrite the file.
+      to.getParentFile().mkdirs();
+      OutputStream out = new FileOutputStream(to);
+
+      byte[] buf = new byte[1024];
+      int len;
+      while ((len = in.read(buf)) > 0){
+        out.write(buf, 0, len);
+      }
+      in.close();
+      out.close();
+    }
+    catch(FileNotFoundException ex){
+      ex.printStackTrace();
+    }
+    catch(IOException e){
+      e.printStackTrace();
+    }
+  }
 }
diff --git a/src/main/java/org/testng/remote/RemoteTestNG.java b/src/main/java/org/testng/remote/RemoteTestNG.java
index 9c98203..a97c68f 100644
--- a/src/main/java/org/testng/remote/RemoteTestNG.java
+++ b/src/main/java/org/testng/remote/RemoteTestNG.java
@@ -27,11 +27,8 @@
 

 /**

  * Extension of TestNG registering a remote TestListener.

- * <p>

- * <i>Developer note</i>: be aware that a copy of this source is distributed along with the

- * Eclipse plugin to assure backward compatibility.

- * </p>

- * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>

+ *

+ * @author Cedric Beust <cedric@beust.com>

  */

 public class RemoteTestNG extends TestNG {

   private static final String LOCALHOST = "127.0.0.1";

@@ -166,6 +163,9 @@
         sb.append(s).append(" ");

       }

       p(sb.toString());

+      testNG.setVerbose(2);

+    } else {

+      testNG.setVerbose(0);

     }

     validateCommandLineParameters(cla);

     if (m_debug) {

@@ -173,6 +173,7 @@
       // without having to relauch RemoteTestNG.

       while(true) {

         testNG.run();

+        testNG.configure(cla);

       }

     } else {

       testNG.run();

diff --git a/src/main/java/org/testng/remote/strprotocol/MessageHelper.java b/src/main/java/org/testng/remote/strprotocol/MessageHelper.java
index 18a9eb0..4fb871a 100755
--- a/src/main/java/org/testng/remote/strprotocol/MessageHelper.java
+++ b/src/main/java/org/testng/remote/strprotocol/MessageHelper.java
@@ -67,9 +67,23 @@
     int type = getMessageType(message);
     String[] messageParts = parseMessage(message);
 
-    return new SuiteMessage(messageParts[1],
+    SuiteMessage result = new SuiteMessage(messageParts[1],
                             MessageHelper.SUITE_START == type,
                             Integer.parseInt(messageParts[2]));
+    // Any excluded methods?
+    if (messageParts.length > 3) {
+      int count = Integer.parseInt(messageParts[3]);
+      if (count > 0) {
+        List<String> methods = Lists.newArrayList();
+        int i = 4;
+        while (count-- > 0) {
+          methods.add(messageParts[i++]);
+        }
+        result.setExcludedMethods(methods);
+      }
+    }
+
+    return result;
   }
 
   public static TestMessage createTestMessage(final String message) {
diff --git a/src/main/java/org/testng/remote/strprotocol/SuiteMessage.java b/src/main/java/org/testng/remote/strprotocol/SuiteMessage.java
index 034a038..9383222 100755
--- a/src/main/java/org/testng/remote/strprotocol/SuiteMessage.java
+++ b/src/main/java/org/testng/remote/strprotocol/SuiteMessage.java
@@ -1,6 +1,11 @@
 package org.testng.remote.strprotocol;
 
 import org.testng.ISuite;
+import org.testng.ITestNGMethod;
+import org.testng.collections.Lists;
+
+import java.util.Collection;
+import java.util.List;
 
 
 /**
@@ -12,6 +17,7 @@
   protected final String m_suiteName;
   protected final int m_testMethodCount;
   protected final boolean m_startSuite;
+  private List<String> m_excludedMethods = null;
 
   SuiteMessage(final String suiteName, final boolean startSuiteRun, final int methodCount) {
     m_suiteName = suiteName;
@@ -23,6 +29,22 @@
     m_suiteName = suite.getName();
     m_testMethodCount =suite.getInvokedMethods().size();
     m_startSuite = startSuiteRun;
+    Collection<ITestNGMethod> excludedMethods = suite.getExcludedMethods();
+    if (excludedMethods != null && excludedMethods.size() > 0) {
+      m_excludedMethods = Lists.newArrayList();
+      for (ITestNGMethod m : excludedMethods) {
+        m_excludedMethods.add(m.getTestClass().getName() + "." + m.getMethodName());
+      }
+    }
+  }
+
+  public void setExcludedMethods(List<String> methods) {
+    m_excludedMethods = Lists.newArrayList();
+    m_excludedMethods.addAll(methods);
+  }
+
+  public List<String> getExcludedMethods() {
+    return m_excludedMethods;
   }
 
   public boolean isMessageOnStart() {
@@ -51,6 +73,14 @@
         .append(m_testMethodCount)
         ;
 
+    if (m_excludedMethods != null && m_excludedMethods.size() > 0) {
+      buf.append(MessageHelper.DELIMITER);
+      buf.append(m_excludedMethods.size());
+      for (String method : m_excludedMethods) {
+        buf.append(MessageHelper.DELIMITER);
+        buf.append(method);
+      }
+    }
     return buf.toString();
   }
 }
diff --git a/src/main/java/org/testng/reporters/TextReporter.java b/src/main/java/org/testng/reporters/TextReporter.java
index 6fe77af..805cc7f 100644
--- a/src/main/java/org/testng/reporters/TextReporter.java
+++ b/src/main/java/org/testng/reporters/TextReporter.java
@@ -9,7 +9,7 @@
 import java.util.List;
 
 /**
- * A simple reporter that collects the results and does nothing else.
+ * A simple reporter that collects the results and prints them on standard out.
  *
  * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
  * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
@@ -31,7 +31,6 @@
     }
   }
 
-
   private ITestNGMethod[] resultsToMethods(List<ITestResult> results) {
     ITestNGMethod[] result = new ITestNGMethod[results.size()];
     int i = 0;
@@ -42,7 +41,6 @@
     return result;
   }
 
-
   private void logResults() {
     //
     // Log Text
diff --git a/src/main/java/org/testng/xml/LaunchSuite.java b/src/main/java/org/testng/xml/LaunchSuite.java
index b684762..19c2795 100755
--- a/src/main/java/org/testng/xml/LaunchSuite.java
+++ b/src/main/java/org/testng/xml/LaunchSuite.java
@@ -3,7 +3,9 @@
 
 import org.testng.collections.Lists;
 import org.testng.internal.AnnotationTypeEnum;
+import org.testng.internal.Utils;
 import org.testng.log4testng.Logger;
+import org.testng.remote.RemoteTestNG;
 import org.testng.reporters.XMLStringBuffer;
 
 import java.io.File;
@@ -75,12 +77,14 @@
     }
 
     /**
-     * {@inheritDoc} This implementation saves nothing because the suite file already
-     * exists.
+     * Trying to run an existing XML file: copy its content to where the plug-in
+     * expects it.
      */
     @Override
     public File save(File directory) {
-      return m_suitePath;
+      File result = new File(directory, RemoteTestNG.DEBUG_SUITE_FILE);
+      Utils.copyFile(m_suitePath, result);
+      return result;
     }
   }