diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 5dc348471..0c0e69821 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -566,11 +566,18 @@ object Defaults extends BuildCommon { def selectedFilter(args: Seq[String]): Seq[String => Boolean] = { - val filters = args map GlobFilter.apply - if (filters.isEmpty) + val (excludeArgs, includeArgs) = args.partition(s => s.startsWith("-")) + + val includeFilters = includeArgs map GlobFilter.apply + val excludeFilters = excludeArgs.map(_.substring(1)).map(GlobFilter.apply) + + if (includeFilters.isEmpty && excludeArgs.isEmpty) Seq(const(true)) - else - filters.map { f => (s: String) => f accept s } + else if (includeFilters.isEmpty) { + excludeFilters.map { f => (s: String) => !f.accept(s) } + } else { + includeFilters.map { f => (s: String) => (f.accept(s) && !excludeFilters.exists(x => x.accept(s))) } + } } def detectTests: Initialize[Task[Seq[TestDefinition]]] = (loadedTestFrameworks, compile, streams) map { (frameworkMap, analysis, s) => Tests.discover(frameworkMap.values.toList, analysis, s.log)._1 @@ -892,7 +899,7 @@ object Defaults extends BuildCommon { selectTests ~ options } - def distinctParser(exs: Set[String], raw: Boolean): Parser[Seq[String]] = + private def distinctParser(exs: Set[String], raw: Boolean): Parser[Seq[String]] = { import DefaultParsers._ val base = token(Space) ~> token(NotSpace - "--" examples exs) diff --git a/sbt/src/sbt-test/tests/test-exclude/project/Build.scala b/sbt/src/sbt-test/tests/test-exclude/project/Build.scala new file mode 100644 index 000000000..7f2f30f93 --- /dev/null +++ b/sbt/src/sbt-test/tests/test-exclude/project/Build.scala @@ -0,0 +1,10 @@ +import sbt._ +import Keys._ +import Defaults._ + +object B extends Build { + lazy val root = Project("root", file("."), settings = defaultSettings ++ Seq( + libraryDependencies += "org.scalatest" %% "scalatest" % "1.9.1" % "test", + parallelExecution in test := false + )) +} diff --git a/sbt/src/sbt-test/tests/test-exclude/src/test/scala/Test.scala b/sbt/src/sbt-test/tests/test-exclude/src/test/scala/Test.scala new file mode 100644 index 000000000..c7b0235e2 --- /dev/null +++ b/sbt/src/sbt-test/tests/test-exclude/src/test/scala/Test.scala @@ -0,0 +1,15 @@ +import java.io.File +import org.scalatest.FlatSpec +import org.scalatest.matchers.ShouldMatchers + +class Test1 extends FlatSpec with ShouldMatchers { + "a test" should "pass" in { + new File("target/Test1.run").createNewFile() + } +} + +class Test2 extends FlatSpec with ShouldMatchers { + "a test" should "pass" in { + new File("target/Test2.run").createNewFile() + } +} diff --git a/sbt/src/sbt-test/tests/test-exclude/test b/sbt/src/sbt-test/tests/test-exclude/test new file mode 100644 index 000000000..ec11c6a39 --- /dev/null +++ b/sbt/src/sbt-test/tests/test-exclude/test @@ -0,0 +1,55 @@ +# Test1 & Test2 create files Test1.run & Test2.run respectively + +# no parameters +> test-only +$ exists target/Test1.run +$ exists target/Test2.run + +$ delete target/Test1.run +$ delete target/Test2.run + + +# with explicit match +> test-only Test1* +$ exists target/Test1.run +-$ exists target/Test2.run + +$ delete target/Test1.run + + +# with explicit match and exclusion +> test-only Test* -Test1 +-$ exists target/Test1.run +$ exists target/Test2.run + +$ delete target/Test2.run + + +# with explicit match and exclusion +> test-only Test* -Test2 +$ exists target/Test1.run +-$ exists target/Test2.run + +$ delete target/Test1.run + + +# with only exclusion +> test-only -Test2 +$ exists target/Test1.run +-$ exists target/Test2.run + +$ delete target/Test1.run + + +# with only exclusion +> test-only -Test1 +-$ exists target/Test1.run +$ exists target/Test2.run + +$ delete target/Test2.run + + +# with only glob exclusion +> test-only -Test* +-$ exists target/Test1.run +-$ exists target/Test2.run