You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2015/11/15 23:25:16 UTC

[2/2] maven-surefire git commit: [SUREFIRE-1185] single method test spews status of every single other test

[SUREFIRE-1185] single method test spews status of every single other test


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/021b263a
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/021b263a
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/021b263a

Branch: refs/heads/master
Commit: 021b263ab29a11243c7c7a8aa1a4df2345d292ce
Parents: e29d4e9
Author: Tibor17 <ti...@lycos.com>
Authored: Sun Nov 15 23:22:10 2015 +0100
Committer: Tibor17 <ti...@lycos.com>
Committed: Sun Nov 15 23:22:10 2015 +0100

----------------------------------------------------------------------
 .../plugin/surefire/AbstractSurefireMojo.java   |  59 +-
 .../surefire/booterclient/BooterSerializer.java |   6 +-
 .../plugin/surefire/util/DependencyScanner.java |  12 +-
 .../plugin/surefire/util/DirectoryScanner.java  |  13 +-
 .../surefire/util/DependenciesScannerTest.java  |  45 +-
 .../surefire/util/DirectoryScannerTest.java     |  50 +-
 .../src/site/apt/examples/single-test.apt.vm    |   6 +
 .../surefire/testset/GenericTestPattern.java    |   9 +-
 .../maven/surefire/testset/ResolvedTest.java    |  71 ++-
 .../surefire/testset/TestListResolver.java      | 134 ++---
 .../maven/surefire/testset/TestRequest.java     |   2 +-
 .../java/org/apache/maven/JUnit4SuiteTest.java  |   4 +-
 .../surefire/testset/FundamentalFilterTest.java | 581 +++++++++++++++++++
 .../surefire/testset/TestListResolverTest.java  | 186 ++++--
 .../surefire/booter/BooterDeserializer.java     |   2 -
 .../its/AbstractTestMultipleMethodPatterns.java |  17 +-
 .../jiras/Surefire1185DoNotSpawnTestsIT.java    |  62 ++
 .../src/test/resources/surefire-1185/pom.xml    |  73 +++
 .../src/test/java/pkg/RunningTest.java          |  29 +
 .../src/test/java/pkg/UnlistedTest.java         |  29 +
 .../common/junit48/CombinedCategoryFilter.java  |  18 +-
 .../surefire/common/junit48/MethodFilter.java   |   4 +-
 .../surefire/common/junit48/RequestedTest.java  |  35 +-
 .../common/junit48/FilterFactoryTest.java       |  23 +-
 .../maven/surefire/junit4/JUnit4Provider.java   |   3 +-
 .../surefire/junitcore/JUnitCoreProvider.java   |  10 +-
 .../surefire/testng/utils/MethodSelector.java   |   4 +-
 .../maven/surefire/testng/TestNGProvider.java   |  14 +-
 28 files changed, 1222 insertions(+), 279 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 9c6a30e..ca3a4be 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -714,9 +714,14 @@ public abstract class AbstractSurefireMojo
     protected abstract void handleSummary( RunResult summary, Exception firstForkException )
         throws MojoExecutionException, MojoFailureException;
 
+    protected abstract boolean isSkipExecution();
+
     protected abstract String[] getDefaultIncludes();
 
-    protected abstract boolean isSkipExecution();
+    private String getDefaultExcludes()
+    {
+        return "**/*$*";
+    }
 
     private SurefireDependencyResolver dependencyResolver;
 
@@ -769,9 +774,7 @@ public abstract class AbstractSurefireMojo
     private DefaultScanResult scanDirectories()
         throws MojoFailureException
     {
-        DirectoryScanner scanner = new DirectoryScanner( getTestClassesDirectory(),
-                                                         getIncludedAndExcludedTests(),
-                                                         getSpecificTests() );
+        DirectoryScanner scanner = new DirectoryScanner( getTestClassesDirectory(), getIncludedAndExcludedTests() );
         return scanner.scan();
     }
 
@@ -789,9 +792,7 @@ public abstract class AbstractSurefireMojo
                 @SuppressWarnings( "unchecked" )
                 List<File> dependenciesToScan =
                     DependencyScanner.filter( project.getTestArtifacts(), Arrays.asList( getDependenciesToScan() ) );
-                DependencyScanner scanner = new DependencyScanner( dependenciesToScan,
-                                                                   getIncludedAndExcludedTests(),
-                                                                   getSpecificTests() );
+                DependencyScanner scanner = new DependencyScanner( dependenciesToScan, getIncludedAndExcludedTests() );
                 return scanner.scan();
             }
             catch ( Exception e )
@@ -1432,19 +1433,20 @@ public abstract class AbstractSurefireMojo
     private ProviderConfiguration createProviderConfiguration( RunOrderParameters runOrderParameters )
         throws MojoExecutionException, MojoFailureException
     {
-        ReporterConfiguration reporterConfiguration =
+        final ReporterConfiguration reporterConfiguration =
             new ReporterConfiguration( getReportsDirectory(), isTrimStackTrace() );
 
-        Artifact testNgArtifact = getTestNgArtifact();
-        DirectoryScannerParameters directoryScannerParameters = null;
+        final Artifact testNgArtifact = getTestNgArtifact();
         final boolean isTestNg = testNgArtifact != null;
-        TestArtifactInfo testNg =
+        final TestArtifactInfo testNg =
             isTestNg ? new TestArtifactInfo( testNgArtifact.getVersion(), testNgArtifact.getClassifier() ) : null;
-        TestRequest testSuiteDefinition = new TestRequest( suiteXmlFiles(), getTestSourceDirectory(),
-                                                           getSpecificTests(), getRerunFailingTestsCount() );
+        final TestRequest testSuiteDefinition = new TestRequest( suiteXmlFiles(),
+                                                                 getTestSourceDirectory(),
+                                                                 getSpecificTests(),
+                                                                 getRerunFailingTestsCount() );
 
         final boolean actualFailIfNoTests;
-
+        DirectoryScannerParameters directoryScannerParameters = null;
         if ( hasSuiteXmlFiles() && !isSpecificTestSpecified() )
         {
             actualFailIfNoTests = getFailIfNoTests() != null && getFailIfNoTests();
@@ -1472,7 +1474,7 @@ public abstract class AbstractSurefireMojo
             List<String> actualIncludes = getIncludeList(); // Collections.emptyList(); behaves same
             List<String> actualExcludes = getExcludeList(); // Collections.emptyList(); behaves same
             // Collections.emptyList(); behaves same
-            List<String> specificTests = new ArrayList<String>( getSpecificTests().getTestSpecificClasses() );
+            List<String> specificTests = Collections.emptyList();
 
             directoryScannerParameters =
                 new DirectoryScannerParameters( getTestClassesDirectory(), actualIncludes, actualExcludes,
@@ -1626,11 +1628,7 @@ public abstract class AbstractSurefireMojo
         List<String> actualExcludes = null;
         if ( isSpecificTestSpecified() )
         {
-            // Check to see if we are running a single test. The raw parameter will
-            // come through if it has not been set.
-            // FooTest -> **/FooTest.java
-
-            actualExcludes = new ArrayList<String>();
+            actualExcludes = Collections.emptyList();
         }
         else
         {
@@ -1639,7 +1637,6 @@ public abstract class AbstractSurefireMojo
                 actualExcludes = readListFromFile( getExcludesFile() );
             }
 
-            // If we have excludesFile, and we have excludes, then append excludes to excludesFile content
             if ( actualExcludes == null )
             {
                 actualExcludes = getExcludes();
@@ -1651,11 +1648,9 @@ public abstract class AbstractSurefireMojo
 
             checkMethodFilterInIncludesExcludes( actualExcludes );
 
-            // defaults here, qdox doesn't like the end javadoc value
-            // Have to wrap in an ArrayList as surefire expects an ArrayList instead of a List for some reason
             if ( actualExcludes == null || actualExcludes.isEmpty() )
             {
-                actualExcludes = Collections.singletonList( "**/*$*" );
+                actualExcludes = Collections.singletonList( getDefaultExcludes() );
             }
         }
         return filterNulls( actualExcludes );
@@ -1667,7 +1662,8 @@ public abstract class AbstractSurefireMojo
         List<String> includes = null;
         if ( isSpecificTestSpecified() )
         {
-            includes = Collections.singletonList( getTest() );
+            includes = new ArrayList<String>();
+            Collections.addAll( includes, StringUtils.split( getTest(), "," ) );
         }
         else
         {
@@ -1676,7 +1672,6 @@ public abstract class AbstractSurefireMojo
                 includes = readListFromFile( getIncludesFile() );
             }
 
-            // If we have includesFile, and we have includes, then append includes to includesFile content
             if ( includes == null )
             {
                 includes = getIncludes();
@@ -1688,8 +1683,6 @@ public abstract class AbstractSurefireMojo
 
             checkMethodFilterInIncludesExcludes( includes );
 
-            // defaults here, qdox doesn't like the end javadoc value
-            // Have to wrap in an ArrayList as surefire expects an ArrayList instead of a List for some reason
             if ( includes == null || includes.isEmpty() )
             {
                 includes = Arrays.asList( getDefaultIncludes() );
@@ -1743,7 +1736,11 @@ public abstract class AbstractSurefireMojo
         {
             if ( item != null )
             {
-                result.add( item );
+                item = item.trim();
+                if ( item.length() != 0 )
+                {
+                    result.add( item );
+                }
             }
         }
 
@@ -1807,7 +1804,7 @@ public abstract class AbstractSurefireMojo
         return getProjectArtifactMap().get( "junit:junit-dep" );
     }
 
-    protected ForkStarter createForkStarter( ProviderInfo provider, ForkConfiguration forkConfiguration,
+    private ForkStarter createForkStarter( ProviderInfo provider, ForkConfiguration forkConfiguration,
                                              ClassLoaderConfiguration classLoaderConfiguration,
                                              RunOrderParameters runOrderParameters, Log log )
         throws MojoExecutionException, MojoFailureException
@@ -1820,7 +1817,7 @@ public abstract class AbstractSurefireMojo
                                 getForkedProcessTimeoutInSeconds(), startupReportConfiguration, log );
     }
 
-    protected InPluginVMSurefireStarter createInprocessStarter( ProviderInfo provider,
+    private InPluginVMSurefireStarter createInprocessStarter( ProviderInfo provider,
                                                                 ClassLoaderConfiguration classLoaderConfiguration,
                                                                 RunOrderParameters runOrderParameters )
         throws MojoExecutionException, MojoFailureException

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
index 21807f5..e67efb0 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/BooterSerializer.java
@@ -97,10 +97,8 @@ class BooterSerializer
         {
             properties.setProperty( SOURCE_DIRECTORY, testSuiteDefinition.getTestSourceDirectory() );
             properties.addList( testSuiteDefinition.getSuiteXmlFiles(), TEST_SUITE_XML_FILES );
-            TestListResolver methodFilter = testSuiteDefinition.getTestListResolver();
-            String requestedTest =
-                methodFilter == null || methodFilter.isEmpty() ? null : methodFilter.getPluginParameterTest();
-            properties.setNullableProperty( REQUESTEDTEST, requestedTest );
+            TestListResolver testFilter = testSuiteDefinition.getTestListResolver();
+            properties.setProperty( REQUESTEDTEST, testFilter == null ? "" : testFilter.getPluginParameterTest() );
             properties.setNullableProperty( RERUN_FAILING_TESTS_COUNT,
                                             String.valueOf( testSuiteDefinition.getRerunFailingTestsCount() ) );
         }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
index 1fb14f5..9faf8e6 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DependencyScanner.java
@@ -46,16 +46,12 @@ public class DependencyScanner
 {
     private final List<File> dependenciesToScan;
 
-    private final TestListResolver includedAndExcludedTests;
+    private final TestListResolver filter;
 
-    private final TestListResolver specificTests;
-
-    public DependencyScanner( List<File> dependenciesToScan,
-                              TestListResolver includedAndExcludedTests, TestListResolver specificTests )
+    public DependencyScanner( List<File> dependenciesToScan, TestListResolver filter )
     {
         this.dependenciesToScan = dependenciesToScan;
-        this.includedAndExcludedTests = includedAndExcludedTests;
-        this.specificTests = specificTests;
+        this.filter = filter;
     }
 
     public DefaultScanResult scan()
@@ -66,7 +62,7 @@ public class DependencyScanner
         {
             try
             {
-                scanArtifact( artifact, includedAndExcludedTests.and( specificTests ), classes );
+                scanArtifact( artifact, filter, classes );
             }
             catch ( IOException e )
             {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
index 8b4c434..6dc81f0 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/DirectoryScanner.java
@@ -36,24 +36,19 @@ public class DirectoryScanner
 {
     private final File basedir;
 
-    private final TestListResolver includedAndExcludedTests;
+    private final TestListResolver filter;
 
-    private final TestListResolver specificTests;
-
-    public DirectoryScanner( File basedir, TestListResolver includedAndExcludedTests, TestListResolver specificTests )
+    public DirectoryScanner( File basedir, TestListResolver filter )
     {
         this.basedir = basedir;
-        this.includedAndExcludedTests = includedAndExcludedTests;
-        this.specificTests = specificTests;
+        this.filter = filter;
     }
 
     public DefaultScanResult scan()
     {
         FileScanner scanner = new FileScanner( basedir, "class" );
         List<String> result = new ArrayList<String>();
-        TestListResolver includedExcludedClasses = includedAndExcludedTests.createClassFilters();
-        TestListResolver specificClasses = specificTests.createClassFilters();
-        scanner.scanTo( result, includedExcludedClasses.and( specificClasses ) );
+        scanner.scanTo( result, filter );
         return new DefaultScanResult( result );
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
index f4eb9e8..c8dd436 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DependenciesScannerTest.java
@@ -44,44 +44,49 @@ public class DependenciesScannerTest
         File testFile = writeTestFile();
 
         // use target as people can configure ide to compile in an other place than maven
-        Artifact artifact = new DefaultArtifact(
-                "org.surefire.dependency", "test-jar",
-                VersionRange.createFromVersion("1.0"), "test", "jar", "tests", null);
-        artifact.setFile(testFile);
+        Artifact artifact =
+            new DefaultArtifact( "org.surefire.dependency", "test-jar", VersionRange.createFromVersion( "1.0" ), "test",
+                                 "jar", "tests", null );
+        artifact.setFile( testFile );
 
         List<String> scanDependencies = new ArrayList<String>();
-        scanDependencies.add("org.surefire.dependency:test-jar");
+        scanDependencies.add( "org.surefire.dependency:test-jar" );
 
         List<String> include = new ArrayList<String>();
         include.add( "**/*A.java" );
         List<String> exclude = new ArrayList<String>();
 
-        DependencyScanner scanner = new DependencyScanner(
-                DependencyScanner.filter(Collections.singletonList(artifact), scanDependencies),
-                new TestListResolver( include, exclude ), new TestListResolver( "" ) );
+        DependencyScanner scanner =
+            new DependencyScanner( DependencyScanner.filter( Collections.singletonList( artifact ), scanDependencies ),
+                                   new TestListResolver( include, exclude ) );
 
         ScanResult classNames = scanner.scan();
         assertNotNull( classNames );
-        System.out.println( "classNames " + classNames.toString() );
         assertEquals( 1, classNames.size() );
-        System.out.println(classNames.getClassName(0));
 
         Map<String, String> props = new HashMap<String, String>();
         classNames.writeTo( props );
         assertEquals( 1, props.size() );
     }
 
-    private File writeTestFile() throws Exception {
-        File output = new File("target/DependenciesScannerTest-tests.jar");
+    private File writeTestFile()
+        throws Exception
+    {
+        File output = new File( "target/DependenciesScannerTest-tests.jar" );
         output.delete();
 
-        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(output));
-
-        out.putNextEntry(new ZipEntry("org/test/TestA.class"));
-        out.closeEntry();
-        out.putNextEntry(new ZipEntry("org/test/TestB.class"));
-        out.closeEntry();
-        out.close();
-        return output;
+        ZipOutputStream out = new ZipOutputStream( new FileOutputStream( output ) );
+        try
+        {
+            out.putNextEntry( new ZipEntry( "org/test/TestA.class" ) );
+            out.closeEntry();
+            out.putNextEntry( new ZipEntry( "org/test/TestB.class" ) );
+            out.closeEntry();
+            return output;
+        }
+        finally
+        {
+            out.close();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DirectoryScannerTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DirectoryScannerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DirectoryScannerTest.java
index db28917..20d9f19 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DirectoryScannerTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/util/DirectoryScannerTest.java
@@ -19,38 +19,60 @@ package org.apache.maven.plugin.surefire.util;
  * under the License.
  */
 
-import junit.framework.TestCase;
 import org.apache.maven.surefire.testset.TestListResolver;
 import org.apache.maven.surefire.util.ScanResult;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.io.File;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.runners.Parameterized.*;
 
 /**
  * @author Kristian Rosenvold
  */
+@RunWith( Parameterized.class )
 public class DirectoryScannerTest
-    extends TestCase
 {
-    public void testLocateTestClasses()
+
+    @Parameters( name = "\"{0}\" should count {1} classes" )
+    public static Object[][] data() {
+        return new Object[][] {
+            { "**/*ZT*A.java", is( 3 ) },
+            { "**/*ZT*A.java#testMethod", is( 3 ) },
+            { "**/*ZT?A.java#testMethod, !*ZT2A", is( 2 ) },
+            { "**/*ZT?A.java#testMethod, !*ZT2A#testMethod", is( 3 ) },
+            { "#testMethod", is( greaterThanOrEqualTo( 3 ) ) },
+        };
+    }
+
+    @Parameter( 0 )
+    public String filter;
+
+    @Parameter( 1 )
+    public Matcher<? super Integer> expectedClassesCount;
+
+    @Test
+    public void locateTestClasses()
         throws Exception
     {
         // use target as people can configure ide to compile in an other place than maven
         File baseDir = new File( new File( "target/test-classes" ).getCanonicalPath() );
-        List<String> include = new ArrayList<String>();
-        include.add( "**/*ZT*A.java" );
-        List<String> exclude = new ArrayList<String>();
-
-        DirectoryScanner surefireDirectoryScanner =
-            new DirectoryScanner( baseDir, new TestListResolver( include, exclude ), new TestListResolver( "" ) );
+        TestListResolver resolver = new TestListResolver( filter );
+        DirectoryScanner surefireDirectoryScanner = new DirectoryScanner( baseDir, resolver );
 
         ScanResult classNames = surefireDirectoryScanner.scan();
-        assertNotNull( classNames );
-        System.out.println( "classNames " + Collections.singletonList(classNames));
-        assertEquals( 3, classNames.size() );
+        assertThat( classNames, is( notNullValue() ) );
+        assertThat( classNames.size(), is( expectedClassesCount ) );
 
         Map<String, String> props = new HashMap<String, String>();
         classNames.writeTo( props );
-        assertEquals( 3, props.size() );
+        assertThat( props.values(), hasSize( expectedClassesCount ) );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/maven-surefire-plugin/src/site/apt/examples/single-test.apt.vm
----------------------------------------------------------------------
diff --git a/maven-surefire-plugin/src/site/apt/examples/single-test.apt.vm b/maven-surefire-plugin/src/site/apt/examples/single-test.apt.vm
index 6b44bde..af75e17 100644
--- a/maven-surefire-plugin/src/site/apt/examples/single-test.apt.vm
+++ b/maven-surefire-plugin/src/site/apt/examples/single-test.apt.vm
@@ -37,6 +37,12 @@ Running a Single Test
 mvn -Dtest=TestCircle test
 +---+
 
+If you have multiple executions configured in surefire plugin within your POM, you may want to execute the only default test phase:
+
++---+
+mvn surefire:test -Dtest=TestCircle
++---+
+
   The value for the <<<test>>> parameter is the name of the test class (without the extension; we'll strip off the extension if you accidentally provide one).
 #{else}
   During development, you may run a single test class repeatedly. To run this

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/main/java/org/apache/maven/surefire/testset/GenericTestPattern.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/GenericTestPattern.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/GenericTestPattern.java
index 585351c..4db54a7 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/GenericTestPattern.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/GenericTestPattern.java
@@ -24,12 +24,11 @@ import java.util.Set;
 /**
  * Resolves string test patterns in object oriented patterns {@code P}.
  *
- * @param <T>    itself
  * @param <P>    resolved atomic test, object oriented - not necessary to be a string
  * @param <C>    test class, or null if not mandatory
  * @param <M>    test method, or null if not mandatory
  */
-public interface GenericTestPattern<T extends GenericTestPattern, P, C, M>
+public interface GenericTestPattern<P, C, M>
     extends TestFilter<C, M>
 {
     boolean hasIncludedMethodPatterns();
@@ -38,10 +37,6 @@ public interface GenericTestPattern<T extends GenericTestPattern, P, C, M>
 
     boolean hasMethodPatterns();
 
-    T createMethodFilters();
-
-    T createClassFilters();
-
     boolean isEmpty();
 
     String getPluginParameterTest();
@@ -49,6 +44,4 @@ public interface GenericTestPattern<T extends GenericTestPattern, P, C, M>
     Set<P> getIncludedPatterns();
 
     Set<P> getExcludedPatterns();
-
-    Set<String> getTestSpecificClasses();
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/main/java/org/apache/maven/surefire/testset/ResolvedTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/ResolvedTest.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/ResolvedTest.java
index 635010e..558aaed 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/ResolvedTest.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/ResolvedTest.java
@@ -107,7 +107,8 @@ public final class ResolvedTest
     }
 
     /**
-     * Test class file pattern, e.g. org&#47;**&#47;Cat*.class<br/>
+     * Test class file pattern, e.g. org&#47;**&#47;Cat*.class<br/>, or null if not any
+     * and {@link #hasTestClassPattern()} returns false.
      * Other examples: org&#47;animals&#47;Cat*, org&#47;animals&#47;Ca?.class, %regex[Cat.class|Dog.*]<br/>
      * <br/>
      * '*' means zero or more characters<br>
@@ -124,7 +125,7 @@ public final class ResolvedTest
     }
 
     /**
-     * Test method, e.g. "realTestMethod".<br/>
+     * Test method, e.g. "realTestMethod".<br/>, or null if not any and {@link #hasTestMethodPattern()} returns false.
      * Other examples: test* or testSomethin? or %regex[testOne|testTwo] or %ant[testOne|testTwo]<br/>
      * <br/>
      * '*' means zero or more characters<br>
@@ -155,35 +156,20 @@ public final class ResolvedTest
         return classPattern == null && methodPattern == null;
     }
 
-    public boolean shouldRun( String testClassFile, String methodName )
+    public boolean matchAsInclusive( String testClassFile, String methodName )
     {
-        if ( isEmpty() )
-        {
-            return true;
-        }
+        testClassFile = tryBlank( testClassFile );
+        methodName = tryBlank( methodName );
 
-        boolean matchedMethodPattern = false;
+        return isEmpty() || alwaysInclusiveQuietly( testClassFile ) || match( testClassFile, methodName );
+    }
 
-        if ( methodPattern != null && methodName != null )
-        {
-            if ( SelectorUtils.matchPath( methodPattern, methodName ) )
-            {
-                matchedMethodPattern = true;
-            }
-            else
-            {
-                return false;
-            }
-        }
+    public boolean matchAsExclusive( String testClassFile, String methodName )
+    {
+        testClassFile = tryBlank( testClassFile );
+        methodName = tryBlank( methodName );
 
-        if ( classPattern != null )
-        {
-            return isRegexTestClassPattern ? matchClassRegexPatter( testClassFile ) : matchClassPatter( testClassFile );
-        }
-        else
-        {
-            return matchedMethodPattern;
-        }
+        return !isEmpty() && canMatchExclusive( testClassFile, methodName ) && match( testClassFile, methodName );
     }
 
     @Override
@@ -240,6 +226,37 @@ public final class ResolvedTest
         return isRegex && description != null ? wrapRegex( description ) : description;
     }
 
+    private boolean canMatchExclusive( String testClassFile, String methodName )
+    {
+        return testClassFile == null && methodName != null && classPattern == null && methodPattern != null
+            || testClassFile != null && methodName == null && classPattern != null && methodPattern == null
+            || testClassFile != null && methodName != null && ( classPattern != null || methodPattern != null );
+    }
+
+    /**
+     * Prevents {@link #match(String, String)} from throwing NPE in situations when inclusive returns true.
+     */
+    private boolean alwaysInclusiveQuietly( String testClassFile )
+    {
+        return testClassFile == null && classPattern != null;
+    }
+
+    private boolean match( String testClassFile, String methodName )
+    {
+        return ( classPattern == null || matchTestClassFile( testClassFile ) )
+            && ( methodPattern == null || methodName == null || matchMethodName( methodName ) );
+    }
+
+    private boolean matchTestClassFile( String testClassFile )
+    {
+        return isRegexTestClassPattern ? matchClassRegexPatter( testClassFile ) : matchClassPatter( testClassFile );
+    }
+
+    private boolean matchMethodName( String methodName )
+    {
+        return SelectorUtils.matchPath( methodPattern, methodName );
+    }
+
     private boolean matchClassPatter( String testClassFile )
     {
         //@todo We have to use File.separator only because the MatchPatterns is using it internally - cannot override.

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
index 6bda2ad..c54bd97 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
@@ -19,17 +19,18 @@ package org.apache.maven.surefire.testset;
  * under the License.
  */
 
-import org.apache.maven.shared.utils.StringUtils;
-import org.apache.maven.shared.utils.io.SelectorUtils;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
+import static org.apache.maven.shared.utils.StringUtils.isBlank;
+import static org.apache.maven.shared.utils.StringUtils.isNotBlank;
+import static org.apache.maven.shared.utils.StringUtils.split;
+import static org.apache.maven.shared.utils.io.SelectorUtils.PATTERN_HANDLER_SUFFIX;
+import static org.apache.maven.shared.utils.io.SelectorUtils.REGEX_HANDLER_PREFIX;
 import static java.util.Collections.singleton;
-import static java.util.Collections.emptySet;
 
 /**
  * Resolved multi pattern filter e.g. -Dtest=MyTest#test,!AnotherTest#otherTest into an object model
@@ -40,20 +41,18 @@ import static java.util.Collections.emptySet;
  * using specific ClassLoader.
  */
 public class TestListResolver
-    implements GenericTestPattern<TestListResolver, ResolvedTest, String, String>
+    implements GenericTestPattern<ResolvedTest, String, String>
 {
     private static final String JAVA_CLASS_FILE_EXTENSION = ".class";
 
-    private static final Set<ResolvedTest> EMPTY_TEST_PATTERNS = emptySet();
+    private static final TestListResolver WILDCARD = new TestListResolver( "*" + JAVA_CLASS_FILE_EXTENSION );
 
-    private static final Set<String> EMPTY_SPECIFIC_TESTS = emptySet();
+    private static final TestListResolver EMPTY = new TestListResolver( "" );
 
     private final Set<ResolvedTest> includedPatterns;
 
     private final Set<ResolvedTest> excludedPatterns;
 
-    private final Set<String> specificClasses;
-
     private final boolean hasIncludedMethodPatterns;
 
     private final boolean hasExcludedMethodPatterns;
@@ -63,13 +62,12 @@ public class TestListResolver
         final IncludedExcludedPatterns patterns = new IncludedExcludedPatterns();
         final Set<ResolvedTest> includedFilters = new LinkedHashSet<ResolvedTest>( 0 );
         final Set<ResolvedTest> excludedFilters = new LinkedHashSet<ResolvedTest>( 0 );
-        final Set<String> specificClasses = new LinkedHashSet<String>( 0 );
 
         for ( final String csvTests : tests )
         {
-            if ( StringUtils.isNotBlank( csvTests ) )
+            if ( isNotBlank( csvTests ) )
             {
-                for ( String request : StringUtils.split( csvTests, "," ) )
+                for ( String request : split( csvTests, "," ) )
                 {
                     request = request.trim();
                     if ( request.length() != 0 && !request.equals( "!" ) )
@@ -80,17 +78,6 @@ public class TestListResolver
             }
         }
 
-        for ( ResolvedTest test : includedFilters )
-        {
-            populateSpecificClasses( specificClasses, test );
-        }
-
-        for ( ResolvedTest test : excludedFilters )
-        {
-            populateSpecificClasses( specificClasses, test );
-        }
-
-        this.specificClasses = Collections.unmodifiableSet( specificClasses );
         this.includedPatterns = Collections.unmodifiableSet( includedFilters );
         this.excludedPatterns = Collections.unmodifiableSet( excludedFilters );
         this.hasIncludedMethodPatterns = patterns.hasIncludedMethodPatterns;
@@ -111,16 +98,21 @@ public class TestListResolver
      * Used only in method filter.
      */
     private TestListResolver( boolean hasIncludedMethodPatterns, boolean hasExcludedMethodPatterns,
-                              Set<String> specificClasses, Set<ResolvedTest> includedPatterns,
-                              Set<ResolvedTest> excludedPatterns )
+                              Set<ResolvedTest> includedPatterns, Set<ResolvedTest> excludedPatterns )
     {
         this.includedPatterns = includedPatterns;
         this.excludedPatterns = excludedPatterns;
-        this.specificClasses = specificClasses;
         this.hasIncludedMethodPatterns = hasIncludedMethodPatterns;
         this.hasExcludedMethodPatterns = hasExcludedMethodPatterns;
     }
 
+    public static TestListResolver newTestListResolver( Set<ResolvedTest> includedPatterns,
+                                                        Set<ResolvedTest> excludedPatterns )
+    {
+        return new TestListResolver( haveMethodPatterns( includedPatterns ), haveMethodPatterns( excludedPatterns ),
+                                     includedPatterns, excludedPatterns );
+    }
+
     public boolean hasIncludedMethodPatterns()
     {
         return hasIncludedMethodPatterns;
@@ -137,21 +129,29 @@ public class TestListResolver
     }
 
     /**
-     * Method filter.
+     *
+     * @param resolver    filter possibly having method patterns
+     * @return {@code resolver} if {@link TestListResolver#hasMethodPatterns() resolver.hasMethodPatterns()}
+     * returns <tt>true</tt>; Otherwise wildcard filter <em>*.class</em> is returned.
      */
-    public TestListResolver createMethodFilters()
+    public static TestListResolver optionallyWildcardFilter( TestListResolver resolver )
     {
-        boolean hasMethodPatterns = hasMethodPatterns();
-        Set<ResolvedTest> inc = hasMethodPatterns ? getIncludedPatterns() : EMPTY_TEST_PATTERNS;
-        Set<ResolvedTest> exc = hasMethodPatterns ? getExcludedPatterns() : EMPTY_TEST_PATTERNS;
-        Set<String> specificClasses = hasMethodPatterns ? getTestSpecificClasses() : EMPTY_SPECIFIC_TESTS;
-        return new TestListResolver( hasIncludedMethodPatterns(), hasExcludedMethodPatterns(), specificClasses,
-                                     inc, exc );
+        return resolver.hasMethodPatterns() ? resolver : WILDCARD;
     }
 
-    public TestListResolver createClassFilters()
+    public static TestListResolver getWildcard()
     {
-        return hasMethodPatterns() ? new TestListResolver( "" ) : this;
+        return WILDCARD;
+    }
+
+    public static TestListResolver getEmpty()
+    {
+        return EMPTY;
+    }
+
+    public final boolean isWildcard()
+    {
+        return equals( WILDCARD );
     }
 
     public TestFilter<String, String> and( final TestListResolver another )
@@ -185,7 +185,7 @@ public class TestListResolver
 
     public boolean shouldRun( String testClassFile, String methodName )
     {
-        if ( isEmpty() || StringUtils.isBlank( testClassFile ) && StringUtils.isBlank( methodName ) )
+        if ( isEmpty() || isBlank( testClassFile ) && isBlank( methodName ) )
         {
             return true;
         }
@@ -201,7 +201,7 @@ public class TestListResolver
             {
                 for ( ResolvedTest filter : getIncludedPatterns() )
                 {
-                    if ( filter.shouldRun( testClassFile, methodName ) )
+                    if ( filter.matchAsInclusive( testClassFile, methodName ) )
                     {
                         shouldRun = true;
                         break;
@@ -213,7 +213,7 @@ public class TestListResolver
             {
                 for ( ResolvedTest filter : getExcludedPatterns() )
                 {
-                    if ( filter.shouldRun( testClassFile, methodName ) )
+                    if ( filter.matchAsExclusive( testClassFile, methodName ) )
                     {
                         shouldRun = false;
                         break;
@@ -226,14 +226,20 @@ public class TestListResolver
 
     public boolean isEmpty()
     {
-        return getIncludedPatterns().isEmpty() && getExcludedPatterns().isEmpty();
+        return equals( EMPTY );
     }
 
     public String getPluginParameterTest()
     {
         String aggregatedTest = aggregatedTest( "", getIncludedPatterns() );
+
+        if ( isNotBlank( aggregatedTest ) && !getExcludedPatterns().isEmpty() )
+        {
+            aggregatedTest += ", ";
+        }
+
         aggregatedTest += aggregatedTest( "!", getExcludedPatterns() );
-        return aggregatedTest.length() == 0 ? null : aggregatedTest;
+        return aggregatedTest.length() == 0 ? "" : aggregatedTest;
     }
 
     public Set<ResolvedTest> getIncludedPatterns()
@@ -246,11 +252,6 @@ public class TestListResolver
         return excludedPatterns;
     }
 
-    public Set<String> getTestSpecificClasses()
-    {
-        return specificClasses;
-    }
-
     @Override
     public boolean equals( Object o )
     {
@@ -317,19 +318,6 @@ public class TestListResolver
         }
     }
 
-    private static void populateSpecificClasses( Set<String> specificClasses, ResolvedTest test )
-    {
-        String pattern = test.getTestClassPattern();
-        if ( pattern != null )
-        {
-            if ( !test.isRegexTestClassPattern() && pattern.endsWith( JAVA_CLASS_FILE_EXTENSION ) )
-            {
-                pattern = pattern.substring( 0, pattern.length() - JAVA_CLASS_FILE_EXTENSION.length() );
-            }
-            specificClasses.add( pattern );
-        }
-    }
-
     private static String aggregatedTest( String testPrefix, Set<ResolvedTest> tests )
     {
         String aggregatedTest = "";
@@ -338,7 +326,7 @@ public class TestListResolver
             String readableTest = test.toString();
             if ( aggregatedTest.length() != 0 && readableTest != null )
             {
-                aggregatedTest += ",";
+                aggregatedTest += ", ";
             }
             aggregatedTest += testPrefix + readableTest;
         }
@@ -375,13 +363,13 @@ public class TestListResolver
 
     static boolean isRegexPrefixedPattern( String pattern )
     {
-        int indexOfRegex = pattern.indexOf( SelectorUtils.REGEX_HANDLER_PREFIX );
-        int prefixLength = SelectorUtils.REGEX_HANDLER_PREFIX.length();
+        int indexOfRegex = pattern.indexOf( REGEX_HANDLER_PREFIX );
+        int prefixLength = REGEX_HANDLER_PREFIX.length();
         if ( indexOfRegex != -1 )
         {
             if ( indexOfRegex != 0
-                || !pattern.endsWith( SelectorUtils.PATTERN_HANDLER_SUFFIX )
-                || pattern.indexOf( SelectorUtils.REGEX_HANDLER_PREFIX, prefixLength ) != -1 )
+                || !pattern.endsWith( PATTERN_HANDLER_SUFFIX )
+                || pattern.indexOf( REGEX_HANDLER_PREFIX, prefixLength ) != -1 )
             {
                 String msg = "Illegal test|includes|excludes regex '%s'. Expected %%regex[class#method] "
                     + "or !%%regex[class#method] " + "with optional class or #method.";
@@ -398,8 +386,8 @@ public class TestListResolver
     static String[] unwrapRegex( String regex )
     {
         regex = regex.trim();
-        int from = SelectorUtils.REGEX_HANDLER_PREFIX.length();
-        int to = regex.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length();
+        int from = REGEX_HANDLER_PREFIX.length();
+        int to = regex.length() - PATTERN_HANDLER_SUFFIX.length();
         return unwrap( regex.substring( from, to ) );
     }
 
@@ -423,7 +411,7 @@ public class TestListResolver
                          IncludedExcludedPatterns patterns,
                          Collection<ResolvedTest> includedFilters, Collection<ResolvedTest> excludedFilters )
     {
-        for ( String method : StringUtils.split( methods, "+" ) )
+        for ( String method : split( methods, "+" ) )
         {
             method = method.trim();
             ResolvedTest test = new ResolvedTest( clazz, method, false );
@@ -481,4 +469,16 @@ public class TestListResolver
             updatedFilters( isExcluded, test, patterns, includedFilters, excludedFilters );
         }
     }
+
+    private static boolean haveMethodPatterns( Set<ResolvedTest> patterns )
+    {
+        for ( ResolvedTest pattern : patterns )
+        {
+            if ( pattern.hasTestMethodPattern() )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestRequest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestRequest.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestRequest.java
index 3a489fc..a1c9315 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestRequest.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestRequest.java
@@ -87,7 +87,7 @@ public class TestRequest
      */
     public int getRerunFailingTestsCount()
     {
-        return this.rerunFailingTestsCount;
+        return rerunFailingTestsCount;
     }
 
     private static List<File> createFiles( List suiteXmlFiles )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index c2ec153..c43a3a6 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -28,6 +28,7 @@ import org.apache.maven.surefire.booter.MasterProcessCommandTest;
 import org.apache.maven.surefire.booter.SurefireReflectorTest;
 import org.apache.maven.surefire.report.LegacyPojoStackTraceWriterTest;
 import org.apache.maven.surefire.suite.RunResultTest;
+import org.apache.maven.surefire.testset.FundamentalFilterTest;
 import org.apache.maven.surefire.testset.ResolvedTestTest;
 import org.apache.maven.surefire.testset.TestListResolverTest;
 import org.apache.maven.surefire.util.DefaultDirectoryScannerTest;
@@ -66,7 +67,8 @@ import org.junit.runners.Suite;
     ScanResultTest.class,
     TestsToRunTest.class,
     UrlUtilsTest.class,
-    SpecificTestClassFilterTest.class
+    SpecificTestClassFilterTest.class,
+    FundamentalFilterTest.class
 } )
 @RunWith( Suite.class )
 public class JUnit4SuiteTest

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/test/java/org/apache/maven/surefire/testset/FundamentalFilterTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/testset/FundamentalFilterTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/testset/FundamentalFilterTest.java
new file mode 100644
index 0000000..9118448
--- /dev/null
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/testset/FundamentalFilterTest.java
@@ -0,0 +1,581 @@
+package org.apache.maven.surefire.testset;
+/*
+ * 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 org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+/**
+ * Inclusive test patters:<p>
+ *
+ * <table cellspacing=0 border=1>
+ * <tr>
+ * <td style=min-width:50px> test</td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px> pattern</td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px></td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>class</td>
+ * <td style=min-width:50px>method</td>
+ * <td style=min-width:50px>class</td>
+ * <td style=min-width:50px>method</td>
+ * <td style=min-width:50px>shouldRunAsInclusive</td>
+ * <td style=min-width:50px></td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (wildcard pattern)</td>
+ * <td style=min-width:50px>testIncludes1</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y (suppose suite and custome filter)</td>
+ * <td style=min-width:50px>testIncludes2</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (suppose Suite)</td>
+ * <td style=min-width:50px>testIncludes3</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y (suppose Suite)</td>
+ * <td style=min-width:50px>testIncludes4</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (wildcard pattern)</td>
+ * <td style=min-width:50px>testIncludes5</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match methods</td>
+ * <td style=min-width:50px>testIncludes6</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (due to Cucumber)</td>
+ * <td style=min-width:50px>testIncludes7</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y (due to Cucumber)</td>
+ * <td style=min-width:50px>testIncludes8</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (wildcard pattern)</td>
+ * <td style=min-width:50px>testIncludes9</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y (suppose suite and custome filter)</td>
+ * <td style=min-width:50px>testIncludes10</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>match classes</td>
+ * <td style=min-width:50px>testIncludes11</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match classes</td>
+ * <td style=min-width:50px>testIncludes12</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y (wildcard pattern)</td>
+ * <td style=min-width:50px>testIncludes13</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match methods</td>
+ * <td style=min-width:50px>testIncludes14</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>match classes</td>
+ * <td style=min-width:50px>testIncludes15</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match all</td>
+ * <td style=min-width:50px>testIncludes16</td>
+ * </tr>
+ * </table>
+ * <p>
+ * <p>
+ * Exclusive test patters:<p>
+ *
+ * <table cellspacing=0 border=1>
+ * <tr>
+ * <td style=min-width:50px> test</td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px> pattern</td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px></td>
+ * <td style=min-width:50px></td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>class</td>
+ * <td style=min-width:50px>method</td>
+ * <td style=min-width:50px>class</td>
+ * <td style=min-width:50px>method</td>
+ * <td style=min-width:50px>shouldRunAsExclusive</td>
+ * <td style=min-width:50px></td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (wildcard pattern)</td>
+ * <td style=min-width:50px>testExcludes1</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n (suppose suite and custome filter)</td>
+ * <td style=min-width:50px>testExcludes2</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (suppose Suite)</td>
+ * <td style=min-width:50px>testExcludes3</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n (suppose Suite)</td>
+ * <td style=min-width:50px>testExcludes4</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (wildcard pattern)</td>
+ * <td style=min-width:50px>testExcludes5</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match methods</td>
+ * <td style=min-width:50px>testExcludes6</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (due to Cucumber)</td>
+ * <td style=min-width:50px>testExcludes7</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n (due to Cucumber)</td>
+ * <td style=min-width:50px>testExcludes8</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (wildcard pattern)</td>
+ * <td style=min-width:50px>testExcludes9</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n (suppose suite and custome filter)</td>
+ * <td style=min-width:50px>testExcludes10</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>match classes</td>
+ * <td style=min-width:50px>testExcludes11</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n (cannot exclude in dir.scanner)</td>
+ * <td style=min-width:50px>testExcludes12</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>n (wildcard pattern)</td>
+ * <td style=min-width:50px>testExcludes13</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match methods</td>
+ * <td style=min-width:50px>testExcludes14</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>n</td>
+ * <td style=min-width:50px>match classes</td>
+ * <td style=min-width:50px>testExcludes15</td>
+ * </tr>
+ * <tr>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>y</td>
+ * <td style=min-width:50px>match all</td>
+ * <td style=min-width:50px>testExcludes16</td>
+ * </tr>
+ * </table>
+ */
+public class FundamentalFilterTest
+{
+    @Test
+    public void testIncludes1()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsInclusive( null, null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes2()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsInclusive( null, null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes3()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsInclusive( null, null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes4()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsInclusive( null, null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes5()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsInclusive( null, "method" ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes6()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsInclusive( null, "method" ), is( true ) );
+        assertThat( pattern.matchAsInclusive( null, "otherMethod" ), is( false ) );
+    }
+
+    /**
+     * Does not throw NPE due to Cucumber has test class NULL and test method NOT NULL.
+     */
+    @Test
+    public void testIncludes7()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsInclusive( null, "method" ), is( true ) );
+    }
+
+    /**
+     * Does not throw NPE due to Cucumber has test class NULL and test method NOT NULL.
+     */
+    @Test
+    public void testIncludes8()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsInclusive( null, "method" ), is( true ) );
+        assertThat( pattern.matchAsInclusive( null, "otherMethod" ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes9()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsInclusive( "Test.class", null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes10()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsInclusive( "Test.class", null ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes11()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsInclusive( "Test.class", null ), is( true ) );
+        assertThat( pattern.matchAsInclusive( "Other.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testIncludes12()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsInclusive( "Test.class", null ), is( true ) );
+        assertThat( pattern.matchAsInclusive( "Other.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testIncludes13()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsInclusive( "Test.class", "method" ), is( true ) );
+    }
+
+    @Test
+    public void testIncludes14()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsInclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsInclusive( "Test.class", "otherMethod" ), is( false ) );
+    }
+
+    @Test
+    public void testIncludes15()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsInclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsInclusive( "Other.class", "method" ), is( false ) );
+    }
+
+    @Test
+    public void testIncludes16()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsInclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsInclusive( "Test.class", "otherMethod" ), is( false ) );
+        assertThat( pattern.matchAsInclusive( "Other.class", "method" ), is( false ) );
+        assertThat( pattern.matchAsInclusive( "Other.class", "otherMethod" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes1()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsExclusive( null, null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes2()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsExclusive( null, null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes3()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsExclusive( null, null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes4()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsExclusive( null, null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes5()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsExclusive( null, "method" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes6()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsExclusive( null, "method" ), is( true ) );
+        assertThat( pattern.matchAsExclusive( null, "otherMethod" ), is( false ) );
+    }
+
+    /**
+     * Does not throw NPE due to Cucumber has test class NULL and test method NOT NULL.
+     */
+    @Test
+    public void testExcludes7()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsExclusive( null, "method" ), is( false ) );
+    }
+
+    /**
+     * Does not throw NPE due to Cucumber has test class NULL and test method NOT NULL.
+     */
+    @Test
+    public void testExcludes8()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsExclusive( null, "method" ), is( false ) );
+        assertThat( pattern.matchAsExclusive( null, "otherMethod" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes9()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsExclusive( "Test.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes10()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsExclusive( "Test.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes11()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsExclusive( "Test.class", null ), is( true ) );
+        assertThat( pattern.matchAsExclusive( "Other.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes12()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsExclusive( "Test.class", null ), is( false ) );
+        assertThat( pattern.matchAsExclusive( "Other.class", null ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes13()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, null, false );
+        assertThat( pattern.matchAsExclusive( "Test.class", "method" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes14()
+    {
+        ResolvedTest pattern = new ResolvedTest( (String) null, "method", false );
+        assertThat( pattern.matchAsExclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsExclusive( "Test.class", "otherMethod" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes15()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", null, false );
+        assertThat( pattern.matchAsExclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsExclusive( "Other.class", "method" ), is( false ) );
+    }
+
+    @Test
+    public void testExcludes16()
+    {
+        ResolvedTest pattern = new ResolvedTest( "Test", "method", false );
+        assertThat( pattern.matchAsExclusive( "Test.class", "method" ), is( true ) );
+        assertThat( pattern.matchAsExclusive( "Test.class", "otherMethod" ), is( false ) );
+        assertThat( pattern.matchAsExclusive( "Other.class", "method" ), is( false ) );
+        assertThat( pattern.matchAsExclusive( "Other.class", "otherMethod" ), is( false ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-api/src/test/java/org/apache/maven/surefire/testset/TestListResolverTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/testset/TestListResolverTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/testset/TestListResolverTest.java
index e34e080..8fb1729 100644
--- a/surefire-api/src/test/java/org/apache/maven/surefire/testset/TestListResolverTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/surefire/testset/TestListResolverTest.java
@@ -21,14 +21,30 @@ package org.apache.maven.surefire.testset;
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static java.util.Collections.addAll;
+import static org.apache.maven.surefire.testset.TestListResolver.newTestListResolver;
+import static org.apache.maven.surefire.testset.ResolvedTest.Type.CLASS;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
 
 public class TestListResolverTest
     extends TestCase
 {
+    private static final String DEFAULT_SUREFIRE_INCLUDED_TEST_PATTERNS =
+        "**/Test*.java, **/*Test.java, **/*TestCase.java";
+
+    private static final String DEFAULT_SUREFIRE_EXCLUDED_TEST_PATTERNS = "**/*$*";
+
     public void testRegexSanity1()
     {
         try
@@ -128,8 +144,8 @@ public class TestListResolverTest
         assertTrue( test.hasTestMethodPattern() );
         assertEquals( "**/MyTest", test.getTestClassPattern() );
         assertEquals( "myTest", test.getTestMethodPattern() );
-        assertTrue( test.shouldRun( "MyTest", "myTest" ) );
-        assertFalse( test.shouldRun( "MyTest", "otherTest" ) );
+        assertTrue( test.matchAsInclusive( "MyTest", "myTest" ) );
+        assertFalse( test.matchAsInclusive( "MyTest", "otherTest" ) );
     }
 
     public void testNonRegexClassAndMethods()
@@ -153,7 +169,7 @@ public class TestListResolverTest
         assertTrue( first.hasTestMethodPattern() );
         assertEquals( "**/MyTest.class", first.getTestClassPattern() );
         assertEquals( "first*", first.getTestMethodPattern() );
-        assertTrue( first.shouldRun( "your/pkg/MyTest.class", "firstTest" ) );
+        assertTrue( first.matchAsInclusive( "your/pkg/MyTest.class", "firstTest" ) );
         ResolvedTest second = tests.next();
         assertFalse( second.isEmpty() );
         assertFalse( second.isRegexTestClassPattern() );
@@ -162,8 +178,8 @@ public class TestListResolverTest
         assertTrue( second.hasTestMethodPattern() );
         assertEquals( "**/MyTest.class", second.getTestClassPattern() );
         assertEquals( "second*", second.getTestMethodPattern() );
-        assertTrue( second.shouldRun( "your/pkg/MyTest.class", "secondTest" ) );
-        assertFalse( second.shouldRun( "your/pkg/MyTest.class", "thirdTest" ) );
+        assertTrue( second.matchAsInclusive( "your/pkg/MyTest.class", "secondTest" ) );
+        assertFalse( second.matchAsInclusive( "your/pkg/MyTest.class", "thirdTest" ) );
     }
 
     public void testNegativeNonRegexClassAndMethod()
@@ -186,9 +202,9 @@ public class TestListResolverTest
         assertEquals( "**/MyTest", test.getTestClassPattern() );
         assertEquals( "myTest", test.getTestMethodPattern() );
         // ResolvedTest should not care about isExcluded. This attribute is handled by TestListResolver.
-        assertTrue( test.shouldRun( "MyTest", "myTest" ) );
-        assertFalse( test.shouldRun( "MyTest", "otherTest" ) );
-        assertFalse( test.shouldRun( "pkg/OtherTest.class", "myTest" ) );
+        assertTrue( test.matchAsInclusive( "MyTest", "myTest" ) );
+        assertFalse( test.matchAsInclusive( "MyTest", "otherTest" ) );
+        assertFalse( test.matchAsInclusive( "pkg/OtherTest.class", "myTest" ) );
     }
 
     public void testResolveTestRequest()
@@ -205,9 +221,14 @@ public class TestListResolverTest
         assertEquals( 1, excludedFilters.size() );
         ResolvedTest test = excludedFilters.iterator().next();
         // ResolvedTest should not care about isExcluded. This attribute is handled by TestListResolver.
-        assertTrue( test.shouldRun( "pkg/MyTest.class", "myTest" ) );
-        assertFalse( test.shouldRun( "pkg/MyTest.class", "otherTest" ) );
-        assertFalse( test.shouldRun( "pkg/OtherTest.class", "myTest" ) );
+        assertTrue( test.matchAsInclusive( "pkg/MyTest.class", "myTest" ) );
+        assertFalse( test.matchAsInclusive( "pkg/MyTest.class", "otherTest" ) );
+        assertFalse( test.matchAsInclusive( "pkg/OtherTest.class", "myTest" ) );
+    }
+
+    public void testShouldRunTestWithoutMethod()
+    {
+        new TestListResolver("**/*Test.class, !%regex[.*.MyTest.class#myTest]").shouldRun( "pkg/MyTest.class", null );
     }
 
     public void testShouldNotRunExcludedMethods()
@@ -216,15 +237,15 @@ public class TestListResolverTest
         assertTrue( resolver.shouldRun( "pkg/MyTest.class", null ) );
     }
 
-    public void testShouldNotRunIncludedMethods()
+    public void testShouldRunSuiteWithIncludedMethods()
     {
         TestListResolver resolver = new TestListResolver( "#*Fail*, %regex[#.*One], #testSuccessThree" );
-        assertFalse( resolver.shouldRun( "pkg/MyTest.class", null ) );
+        assertTrue( resolver.shouldRun( "pkg/MyTest.class", null ) );
     }
 
     public void testShouldRunAny()
     {
-        TestListResolver resolver = new TestListResolver( "" );
+        TestListResolver resolver = TestListResolver.getEmpty();
         assertTrue( resolver.shouldRun( "pkg/MyTest.class", null ) );
 
         resolver = new TestListResolver( Collections.<String>emptySet() );
@@ -234,24 +255,25 @@ public class TestListResolverTest
     public void testClassFilter()
     {
         TestListResolver resolver = new TestListResolver( "#test" );
-        assertTrue( resolver.createClassFilters().shouldRun( "pkg/MyTest.class", null ) );
+        assertTrue( resolver.shouldRun( "pkg/MyTest.class", null ) );
 
         resolver = new TestListResolver( "!#test" );
-        assertTrue( resolver.createClassFilters().shouldRun( "pkg/MyTest.class", null ) );
+        assertTrue( resolver.shouldRun( "pkg/MyTest.class", null ) );
 
         resolver = new TestListResolver( "SomeOtherClass" );
-        assertFalse( resolver.createClassFilters().shouldRun( "pkg/MyTest.class", null ) );
+        assertFalse( resolver.shouldRun( "pkg/MyTest.class", null ) );
     }
 
     public void testBrokenPatternThrowsException()
     {
-        Collection<String> included = Collections.emptySet();
-        Collection<String> excluded = Arrays.asList( "BasicTest, !**/TestTwo, **/TestThree.java" );
+        Collection<String> included = emptySet();
+        Collection<String> excluded = asList( "BasicTest, !**/TestTwo, **/TestThree.java" );
         try
         {
             new TestListResolver( included, excluded );
             fail( "Expected: IllegalArgumentException" );
-        } catch ( IllegalArgumentException e )
+        }
+        catch ( IllegalArgumentException e )
         {
             // JUnit 3.x style
             assertEquals( "Exclamation mark not expected in 'exclusion': BasicTest, !**/TestTwo, **/TestThree.java",
@@ -261,8 +283,8 @@ public class TestListResolverTest
 
     public void testMultipleExcludedClassesOnly()
     {
-        Collection<String> included = Collections.emptySet();
-        Collection<String> excluded = Arrays.asList( "BasicTest, **/TestTwo, **/TestThree.java" );
+        Collection<String> included = emptySet();
+        Collection<String> excluded = asList( "BasicTest, **/TestTwo, **/TestThree.java" );
         TestListResolver resolver = new TestListResolver( included, excluded );
         assertFalse( resolver.shouldRun( "jiras/surefire745/BasicTest.class", null ) );
         assertFalse( resolver.shouldRun( "jiras/surefire745/TestTwo.class", null ) );
@@ -272,8 +294,8 @@ public class TestListResolverTest
 
     public void testMultipleExcludedClasses()
     {
-        Collection<String> included = Arrays.asList( "**/Test*.java, **/*Test.java, **/*TestCase.java" );
-        Collection<String> excluded = Arrays.asList( "BasicTest, **/TestTwo, **/TestThree.java" );
+        Collection<String> included = singleton( DEFAULT_SUREFIRE_INCLUDED_TEST_PATTERNS );
+        Collection<String> excluded = asList( "BasicTest, **/TestTwo, **/TestThree.java" );
         TestListResolver resolver = new TestListResolver( included, excluded );
         assertFalse( resolver.shouldRun( "jiras/surefire745/BasicTest.class", null ) );
         assertFalse( resolver.shouldRun( "jiras/surefire745/TestTwo.class", null ) );
@@ -281,22 +303,112 @@ public class TestListResolverTest
         assertTrue( resolver.shouldRun( "jiras/surefire745/TestFour.class", null ) );
     }
 
-    public void testMultipleExcludedClassesWithNoSpecificTests()
+    public void testAndFilters()
     {
-        Collection<String> included = Arrays.asList( "**/Test*.java, **/*Test.java, **/*TestCase.java" );
-        Collection<String> excluded = Arrays.asList( "BasicTest, **/TestTwo, **/TestThree.java" );
+        TestListResolver firstFilter = new TestListResolver( "BasicTest, **/TestTwo, **/TestThree.java" );
+        TestListResolver secondFilter = new TestListResolver( "*icTest, Test???*" );
+        TestFilter<String, String> filter = firstFilter.and( secondFilter );
 
-        TestListResolver includedAndExcludedTests = new TestListResolver( included, excluded );
-        TestListResolver includedExcludedClasses = includedAndExcludedTests.createClassFilters();
+        assertTrue( filter.shouldRun( "jiras/surefire745/BasicTest.class", null ) );
+        assertTrue( filter.shouldRun( "jiras/surefire745/TestTwo.class", null ) );
+        assertTrue( filter.shouldRun( "jiras/surefire745/TestThree.class", null ) );
+        assertFalse( filter.shouldRun( "jiras/surefire745/TestFour.class", null ) );
+    }
 
-        TestListResolver specificTests = new TestListResolver( "" );
-        TestListResolver specificClasses = specificTests.createClassFilters();
+    public void testTestListResolverWithoutMethods()
+    {
+        ResolvedTest inc1 = new ResolvedTest( "A?Test.java", null, false );
+        ResolvedTest inc2 = new ResolvedTest( "**/?Test", null, false );
+        ResolvedTest exc1 = new ResolvedTest( "AATest", null, false );
+        ResolvedTest exc2 = new ResolvedTest( "**/BTest.java", null, false );
+        TestListResolver resolver = newTestListResolver( $( inc1, inc2 ), $( exc1, exc2 ) );
+        assertThat( resolver.getPluginParameterTest(), is( "A?Test.java, **/?Test, !AATest, !**/BTest.java" ) );
+        assertFalse( resolver.isEmpty() );
+        assertFalse( resolver.hasIncludedMethodPatterns() );
+        assertFalse( resolver.hasExcludedMethodPatterns() );
+        assertFalse( resolver.hasMethodPatterns() );
+        assertTrue( resolver.shouldRun( "ATest.class", null ) );
+        assertFalse( resolver.shouldRun( "AATest.class", null ) );
+        assertTrue( resolver.shouldRun( "ABTest.class", null ) );
+        assertFalse( resolver.shouldRun( "BTest.class", null ) );
+        assertTrue( resolver.shouldRun( "CTest.class", null ) );
+        assertFalse( resolver.hasMethodPatterns() );
+    }
 
-        TestFilter<String, String> filter = includedExcludedClasses.and( specificClasses );
+    public void testTestListResolverWithMethods()
+    {
+        ResolvedTest inc1 = new ResolvedTest( "A?Test.java", null, false );
+        ResolvedTest inc2 = new ResolvedTest( "*?Test", null, false );
+        ResolvedTest exc1 = new ResolvedTest( "AATest", null, false );
+        ResolvedTest exc2 = new ResolvedTest( "*BTest.java", "failedTest", false );
+        TestListResolver resolver = newTestListResolver( $( inc1, inc2 ), $( exc1, exc2 ) );
+        assertThat( resolver.getPluginParameterTest(), is( "A?Test.java, *?Test, !AATest, !*BTest.java#failedTest" ) );
+        assertFalse( resolver.isEmpty() );
+        assertFalse( resolver.hasIncludedMethodPatterns() );
+        assertTrue( resolver.hasExcludedMethodPatterns() );
+        assertTrue( resolver.hasMethodPatterns() );
+        assertTrue( resolver.shouldRun( "ATest.class", null ) );
+        assertFalse( resolver.shouldRun( "AATest.class", null ) );
+        assertTrue( resolver.shouldRun( "ABTest.class", null ) );
+        assertTrue( resolver.shouldRun( "BTest.class", null ) );
+        assertFalse( resolver.shouldRun( "BTest.class", "failedTest" ) );
+        assertTrue( resolver.shouldRun( "CTest.class", null ) );
+        assertFalse( TestListResolver.optionallyWildcardFilter( resolver ).isEmpty() );
+    }
 
-        assertFalse( filter.shouldRun( "jiras/surefire745/BasicTest.class", null ) );
-        assertFalse( filter.shouldRun( "jiras/surefire745/TestTwo.class", null ) );
-        assertFalse( filter.shouldRun( "jiras/surefire745/TestThree.class", null ) );
-        assertTrue( filter.shouldRun( "jiras/surefire745/TestFour.class", null ) );
+    private static Set<ResolvedTest> $( ResolvedTest... patterns )
+    {
+        Set<ResolvedTest> set = new LinkedHashSet<ResolvedTest>();
+        addAll( set, patterns );
+        return set;
+    }
+
+    public void testDefaultPatternsMatching()
+    {
+        Set<ResolvedTest> inclusions = resolveClass( DEFAULT_SUREFIRE_INCLUDED_TEST_PATTERNS );
+        Set<ResolvedTest> exclusions = resolveClass( DEFAULT_SUREFIRE_EXCLUDED_TEST_PATTERNS );
+        TestListResolver tlr = newTestListResolver( inclusions, exclusions );
+        boolean shouldRun = tlr.shouldRun( "org/apache/maven/surefire/SomeTest.class", null );
+        assertTrue( shouldRun );
+    }
+
+    public void testDefaultPatternsNotMatching()
+    {
+        Set<ResolvedTest> inclusions = resolveClass( DEFAULT_SUREFIRE_INCLUDED_TEST_PATTERNS );
+        Set<ResolvedTest> exclusions = resolveClass( DEFAULT_SUREFIRE_EXCLUDED_TEST_PATTERNS );
+        TestListResolver tlr = newTestListResolver( inclusions, exclusions );
+        boolean shouldRun = tlr.shouldRun( "org/apache/maven/surefire/SomeTestNotRunning.class", null );
+        assertFalse( shouldRun );
+    }
+
+    public void testInclusiveWithDefaultExclusivePattern()
+    {
+        Set<ResolvedTest> defaultExclusions = resolveClass( DEFAULT_SUREFIRE_EXCLUDED_TEST_PATTERNS );
+        boolean runnable = newTestListResolver( resolveClass( "A*Test" ), defaultExclusions )
+            .shouldRun( "org/apache/maven/surefire/ARunnableTest.class", null );
+        assertTrue( runnable );
+    }
+
+    public void testWildcard()
+    {
+        TestListResolver tlr = TestListResolver.optionallyWildcardFilter( new TestListResolver( (String) null ) );
+        assertThat( tlr, is( new TestListResolver( "**/*.class" ) ) );
+        assertThat( tlr.isWildcard(), is( true ) );
+        assertThat( tlr.isEmpty(), is( false ) );
+
+        tlr = TestListResolver.optionallyWildcardFilter( new TestListResolver( "**/**/MethodLessPattern.class" ) );
+        assertThat( tlr, is( new TestListResolver( "**/*.class" ) ) );
+        assertThat( tlr.isWildcard(), is( true ) );
+        assertThat( tlr.isEmpty(), is( false ) );
+    }
+
+    private static Set<ResolvedTest> resolveClass( String patterns )
+    {
+        Set<ResolvedTest> resolved = new HashSet<ResolvedTest>();
+        for ( String pattern : patterns.split( "," ) )
+        {
+            resolved.add( new ResolvedTest( CLASS, pattern, false ) );
+        }
+        return resolved;
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
----------------------------------------------------------------------
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
index 2540a7f..02fde8f 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/BooterDeserializer.java
@@ -50,8 +50,6 @@ import static org.apache.maven.surefire.cli.CommandLineOption.*;
  */
 public class BooterDeserializer
 {
-
-
     private final PropertiesWrapper properties;
 
     public BooterDeserializer( InputStream inputStream )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractTestMultipleMethodPatterns.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractTestMultipleMethodPatterns.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractTestMultipleMethodPatterns.java
index 9c7b4b4..a4b5367 100644
--- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractTestMultipleMethodPatterns.java
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/AbstractTestMultipleMethodPatterns.java
@@ -36,6 +36,10 @@ import static org.junit.Assume.assumeThat;
 public abstract class AbstractTestMultipleMethodPatterns
     extends SurefireJUnit4IntegrationTestCase
 {
+    private static final String CSV_DELIMITER_SHORT = ",";
+    private static final String CSV_DELIMITER_LONG = ", ";
+    private static final String NOT_DELIMITER = "!";
+
     protected abstract Settings getSettings();
 
     protected abstract SurefireLauncher unpack();
@@ -65,18 +69,18 @@ public abstract class AbstractTestMultipleMethodPatterns
     {
         String included = "";
         String excluded = "";
-        for ( String pattern : patterns.split( "," ) )
+        for ( String pattern : patterns.split( CSV_DELIMITER_SHORT ) )
         {
             pattern = pattern.trim();
-            if ( pattern.startsWith( "!" ) )
+            if ( pattern.startsWith( NOT_DELIMITER ) )
             {
-                excluded += pattern.substring( 1 );
-                excluded += ", ";
+                excluded += pattern.substring( NOT_DELIMITER.length() ).trim();
+                excluded += CSV_DELIMITER_LONG;
             }
             else
             {
                 included += pattern;
-                included += ", ";
+                included += CSV_DELIMITER_LONG;
             }
         }
         return new String[]{ trimEndComma( included ), trimEndComma( excluded ) };
@@ -85,7 +89,8 @@ public abstract class AbstractTestMultipleMethodPatterns
     private static String trimEndComma( String pattern )
     {
         pattern = pattern.trim();
-        return pattern.endsWith( "," ) ? pattern.substring( 0, pattern.length() - 1 ) : pattern;
+        return pattern.endsWith( CSV_DELIMITER_LONG )
+            ? pattern.substring( 0, pattern.length() - CSV_DELIMITER_LONG.length() ) : pattern;
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/021b263a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1185DoNotSpawnTestsIT.java
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1185DoNotSpawnTestsIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1185DoNotSpawnTestsIT.java
new file mode 100644
index 0000000..16e27cf
--- /dev/null
+++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1185DoNotSpawnTestsIT.java
@@ -0,0 +1,62 @@
+package org.apache.maven.surefire.its.jiras;
+
+/*
+ * 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 org.apache.maven.it.VerificationException;
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Surefire 2.19 spawns unnecessary tests in surefire-junit4 provider.
+ * https://issues.apache.org/jira/browse/SUREFIRE-1185
+ * Example, UnlistedTest is the problem here because it runs with filtered out methods:
+ *
+ * Running pkg.UnlistedTest
+ * Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in pkg.UnlistedTest
+ * Running pkg.RunningTest
+ * Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in pkg.RunningTest
+ *
+ * Results :
+ *
+ * Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
+ */
+public class Surefire1185DoNotSpawnTestsIT
+    extends SurefireJUnit4IntegrationTestCase
+{
+    @Test
+    public void doNotSpawnUnwantedTests()
+        throws VerificationException
+    {
+        unpack().setTestToRun( "RunningTest#test" )
+            .executeTest()
+            .assertTestSuiteResults( 1 )
+            .assertThatLogLine( containsString( "in pkg.RunningTest" ), is( 1 ) )
+            .assertThatLogLine( containsString( "in pkg.UnlistedTest" ), is( 0 ) );
+    }
+
+    private SurefireLauncher unpack()
+    {
+        return unpack( "surefire-1185" );
+    }
+}