Port mutable.Specification to verify.BasicTestSuite

This commit is contained in:
Eugene Yokota 2021-01-16 00:47:53 -05:00
parent 508a4b4bb9
commit 1c6a5d21bb
18 changed files with 544 additions and 480 deletions

View File

@ -7,54 +7,43 @@
package sbt package sbt
import org.specs2.mutable.Specification import BuildPaths.expandTildePrefix
object BuildPathsTest extends Specification { object BuildPathsTest extends verify.BasicTestSuite {
private def assertExpandedPath(given: String, expected: String) = { test("expandTildePrefix should expand empty path to itself") {
val actual = BuildPaths.expandTildePrefix(given) assertEquals("", expandTildePrefix(""))
actual must be equalTo (expected)
} }
"expandTildePrefix" should { test("it should expand /home/user/path to itself") {
assertEquals("/home/user/path", expandTildePrefix("/home/user/path"))
"expand empty path to itself" in {
assertExpandedPath("", "")
}
"expand /home/user/path to itself" in {
assertExpandedPath("/home/user/path", "/home/user/path")
}
"expand /~/foo/ to itself" in {
assertExpandedPath("/~/foo/", "/~/foo/")
}
"expand ~ to $HOME" in {
assertExpandedPath("~", sys.env.getOrElse("HOME", ""))
}
"expand ~/foo/bar to $HOME/foo/bar" in {
assertExpandedPath("~/foo/bar", sys.env.getOrElse("HOME", "") + "/foo/bar")
}
"expand ~+ to $PWD" in {
assertExpandedPath("~+", sys.env.getOrElse("PWD", ""))
}
"expand ~+/foo/bar to $PWD/foo/bar" in {
assertExpandedPath("~+/foo/bar", sys.env.getOrElse("PWD", "") + "/foo/bar")
}
"expand ~- to $OLDPWD" in {
assertExpandedPath("~-", sys.env.getOrElse("OLDPWD", ""))
}
"expand ~-/foo/bar to $OLDPWD/foo/bar" in {
assertExpandedPath("~-/foo/bar", sys.env.getOrElse("OLDPWD", "") + "/foo/bar")
}
} }
test("it should expand /~/foo/ to itself") {
assertEquals("/~/foo/", expandTildePrefix("/~/foo/"))
}
test("it should expand ~ to $HOME") {
assertEquals(sys.env.getOrElse("HOME", ""), expandTildePrefix("~"))
}
test("it should expand ~/foo/bar to $HOME/foo/bar") {
assertEquals(sys.env.getOrElse("HOME", "") + "/foo/bar", expandTildePrefix("~/foo/bar"))
}
test("it should expand ~+ to $PWD") {
assertEquals(sys.env.getOrElse("PWD", ""), expandTildePrefix("~+"))
}
test("it should expand ~+/foo/bar to $PWD/foo/bar") {
assertEquals(sys.env.getOrElse("PWD", "") + "/foo/bar", expandTildePrefix("~+/foo/bar"))
}
test("it should expand ~- to $OLDPWD") {
assertEquals(sys.env.getOrElse("OLDPWD", ""), expandTildePrefix("~-"))
}
test("it should expand ~-/foo/bar to $OLDPWD/foo/bar") {
assertEquals(sys.env.getOrElse("OLDPWD", "") + "/foo/bar", expandTildePrefix("~-/foo/bar"))
}
} }

View File

@ -7,63 +7,77 @@
package sbt package sbt
import org.specs2.mutable.Specification object DefaultsTest extends verify.BasicTestSuite {
object DefaultsTest extends Specification { test("`selectedFilter` should return all tests for an empty list") {
private def assertFiltered(filter: List[String], expected: Map[String, Boolean]) = { val expected = Map("Test1" -> true, "Test2" -> true)
val actual = expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) val filter = List.empty[String]
assert(
actual must be equalTo (expected) expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
} }
"`selectedFilter`" should { test("it should work correctly with exact matches") {
"return all tests for an empty list" in { val expected = Map("Test1" -> true, "Test2" -> false, "Foo" -> false)
assertFiltered(List(), Map("Test1" -> true, "Test2" -> true)) val filter = List("Test1", "foo")
} assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
"work correctly with exact matches" in { )
assertFiltered(List("Test1", "foo"), Map("Test1" -> true, "Test2" -> false, "Foo" -> false))
}
"work correctly with glob" in {
assertFiltered(List("Test*"), Map("Test1" -> true, "Test2" -> true, "Foo" -> false))
}
"work correctly with excludes" in {
assertFiltered(
List("Test*", "-Test2"),
Map("Test1" -> true, "Test2" -> false, "Foo" -> false)
)
}
"work correctly without includes" in {
assertFiltered(List("-Test2"), Map("Test1" -> true, "Test2" -> false, "Foo" -> true))
}
"work correctly with excluded globs" in {
assertFiltered(List("Test*", "-F*"), Map("Test1" -> true, "Test2" -> true, "Foo" -> false))
}
"cope with multiple filters" in {
assertFiltered(
List("T*1", "T*2", "-F*"),
Map("Test1" -> true, "Test2" -> true, "Foo" -> false)
)
}
"cope with multiple exclusion filters, no includes" in {
assertFiltered(
List("-A*", "-F*"),
Map("Test1" -> true, "Test2" -> true, "AAA" -> false, "Foo" -> false)
)
}
"cope with multiple exclusion filters with includes" in {
assertFiltered(
List("T*", "-T*1", "-T*2"),
Map("Test1" -> false, "Test2" -> false, "Test3" -> true)
)
}
} }
test("it should work correctly with glob") {
val expected = Map("Test1" -> true, "Test2" -> true, "Foo" -> false)
val filter = List("Test*")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should work correctly with excludes") {
val expected = Map("Test1" -> true, "Test2" -> false, "Foo" -> false)
val filter = List("Test*", "-Test2")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should work correctly without includes") {
val expected = Map("Test1" -> true, "Test2" -> false, "Foo" -> true)
val filter = List("-Test2")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should work correctly with excluded globs") {
val expected = Map("Test1" -> true, "Test2" -> true, "Foo" -> false)
val filter = List("Test*", "-F*")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should cope with multiple filters") {
val expected = Map("Test1" -> true, "Test2" -> true, "Foo" -> false)
val filter = List("T*1", "T*2", "-F*")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should cope with multiple exclusion filters, no includes") {
val expected = Map("Test1" -> true, "Test2" -> true, "AAA" -> false, "Foo" -> false)
val filter = List("-A*", "-F*")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
test("it should cope with multiple exclusion filters with includes") {
val expected = Map("Test1" -> false, "Test2" -> false, "Test3" -> true)
val filter = List("T*", "-T*1", "-T*2")
assert(
expected.map(t => (t._1, Defaults.selectedFilter(filter).exists(fn => fn(t._1)))) == expected
)
}
} }

View File

@ -9,7 +9,6 @@ package sbt
import java.io._ import java.io._
import org.specs2.mutable.Specification
import sbt.internal._ import sbt.internal._
import sbt.internal.util.{ import sbt.internal.util.{
AttributeEntry, AttributeEntry,
@ -29,45 +28,41 @@ package subpackage {
} }
object PluginCommandTest extends Specification { object PluginCommandTest extends verify.BasicTestSuite {
sequential
import subpackage._ import subpackage._
import FakeState._ import FakeState._
"The `plugin` command" should { test("`plugin` command should work for plugins within nested in one package") {
val output = processCommand(
"should work for plugins within nested in one package" in { "plugin sbt.PluginCommandTestPlugin0",
val output = processCommand( PluginCommandTestPlugin0,
"plugin sbt.PluginCommandTestPlugin0", PluginCommandTestPlugin1
PluginCommandTestPlugin0, )
PluginCommandTestPlugin1 assert(output.contains("sbt.PluginCommandTestPlugin0 is activated."))
)
output must contain("sbt.PluginCommandTestPlugin0 is activated.")
}
"should work for plugins nested more than one package" in {
val output = processCommand(
"plugin sbt.subpackage.PluginCommandTestPlugin1",
PluginCommandTestPlugin0,
PluginCommandTestPlugin1
)
output must contain("sbt.subpackage.PluginCommandTestPlugin1 is activated.")
}
"suggest a plugin when given an incorrect plugin with a similar name" in {
val output = processCommand(
"plugin PluginCommandTestPlugin0",
PluginCommandTestPlugin0,
PluginCommandTestPlugin1
)
output must contain(
"Not a valid plugin: PluginCommandTestPlugin0 (similar: sbt.PluginCommandTestPlugin0, sbt.subpackage.PluginCommandTestPlugin1)"
)
}
} }
test("it should work for plugins nested more than one package") {
val output = processCommand(
"plugin sbt.subpackage.PluginCommandTestPlugin1",
PluginCommandTestPlugin0,
PluginCommandTestPlugin1
)
assert(output.contains("sbt.subpackage.PluginCommandTestPlugin1 is activated."))
}
test("it should suggest a plugin when given an incorrect plugin with a similar name") {
val output = processCommand(
"plugin PluginCommandTestPlugin0",
PluginCommandTestPlugin0,
PluginCommandTestPlugin1
)
assert(
output.contains(
"Not a valid plugin: PluginCommandTestPlugin0 (similar: sbt.PluginCommandTestPlugin0, sbt.subpackage.PluginCommandTestPlugin1)"
)
)
}
} }
object FakeState { object FakeState {

View File

@ -7,20 +7,10 @@
package sbt package sbt
import org.specs2.Specification object ProjectSpec extends verify.BasicTestSuite {
test("Project should normalize projectIDs if they are empty") {
class ProjectSpec extends Specification { assert(Project.normalizeProjectID(emptyFilename) == Right("root"))
def is = s2""" }
This is a specification to check utility methods on the Project object
Project should
normalize projectIDs if they are empty ${normalizeEmptyFileName}
"""
def emptyFilename = "" def emptyFilename = ""
def normalizeEmptyFileName =
Project.normalizeProjectID(emptyFilename) must equalTo(Right("root"))
} }

View File

@ -7,23 +7,18 @@
package sbt.internal package sbt.internal
import org.specs2.mutable.Specification object AggregationSpec extends verify.BasicTestSuite {
class AggregationSpec extends Specification {
val timing = Aggregation.timing(Aggregation.defaultFormat, 0, _: Long) val timing = Aggregation.timing(Aggregation.defaultFormat, 0, _: Long)
"timing" should { test("timing should format total time properly") {
"format total time properly" in { assert(timing(101).startsWith("Total time: 0 s,"))
timing(101) must be startWith "Total time: 0 s," assert(timing(1000).startsWith("Total time: 1 s,"))
timing(1000) must be startWith "Total time: 1 s," assert(timing(3000).startsWith("Total time: 3 s,"))
timing(3000) must be startWith "Total time: 3 s," assert(timing(30399).startsWith("Total time: 30 s,"))
timing(30399) must be startWith "Total time: 30 s," assert(timing(60399).startsWith("Total time: 60 s,"))
timing(60399) must be startWith "Total time: 60 s," assert(timing(60699).startsWith("Total time: 61 s (01:01),"))
timing(60699) must be startWith "Total time: 61 s (01:01)," assert(timing(303099).startsWith("Total time: 303 s (05:03),"))
timing(303099) must be startWith "Total time: 303 s (05:03)," assert(timing(6003099).startsWith("Total time: 6003 s (01:40:03),"))
timing(6003099) must be startWith "Total time: 6003 s (01:40:03)," assert(timing(96003099).startsWith("Total time: 96003 s (26:40:03),"))
timing(96003099) must be startWith "Total time: 96003 s (26:40:03),"
}
} }
} }

View File

@ -7,6 +7,4 @@
package sbt.internal.parser package sbt.internal.parser
import org.specs2.mutable._ trait AbstractSpec extends verify.BasicTestSuite with SplitExpression
trait AbstractSpec extends Specification with SplitExpression

View File

@ -14,30 +14,33 @@ abstract class CheckIfParsedSpec(
EvaluateConfigurations.splitExpressions EvaluateConfigurations.splitExpressions
) extends AbstractSpec { ) extends AbstractSpec {
this.getClass.getName should { test(s"${this.getClass.getName} should parse sbt file") {
files foreach {
"Parse sbt file " in { case (content, description, nonEmptyImports, nonEmptyStatements) =>
foreach(files) { println(s"""${getClass.getSimpleName}: "$description" """)
case (content, description, nonEmptyImports, nonEmptyStatements) => val (imports, statements) = split(content)
println(s"""${getClass.getSimpleName}: "$description" """) assert(
val (imports, statements) = split(content) nonEmptyStatements == statements.nonEmpty,
statements.nonEmpty must be_==(nonEmptyStatements).setMessage(s"""$description s"""$description
|***${shouldContains(nonEmptyStatements)} statements*** |***${shouldContains(nonEmptyStatements)} statements***
|$content """.stripMargin) |$content """.stripMargin
imports.nonEmpty must be_==(nonEmptyImports).setMessage(s"""$description )
|***${shouldContains(nonEmptyImports)} imports*** assert(
|$content """.stripMargin) nonEmptyImports == imports.nonEmpty,
} s"""$description
|***${shouldContains(nonEmptyImports)} imports***
|$content """.stripMargin
)
} }
} }
private def shouldContains(b: Boolean) = private def shouldContains(b: Boolean): String =
s"""Should ${if (b) { s"""Should ${if (b) {
"contain" "contain"
} else { } else {
"not contain" "not contain"
}}""" }}"""
protected val files: Seq[(String, String, Boolean, Boolean)] protected def files: Seq[(String, String, Boolean, Boolean)]
} }

View File

@ -7,7 +7,7 @@
package sbt.internal.parser package sbt.internal.parser
class CommentedXmlSpec extends CheckIfParsedSpec { object CommentedXmlSpec extends CheckIfParsedSpec {
override protected val files = Seq( override protected val files = Seq(
( (

View File

@ -9,44 +9,41 @@ package sbt.internal.parser
import sbt.internal.util.MessageOnlyException import sbt.internal.util.MessageOnlyException
class EmbeddedXmlSpec extends CheckIfParsedSpec { object EmbeddedXmlSpec extends CheckIfParsedSpec {
"File with xml content " should { test("File with xml content should Handle last xml part") {
val errorLine = """<version>4.0<version>"""
"Handle last xml part" in { val buildSbt = s"""|
val errorLine = """<version>4.0<version>""" |
val buildSbt = s"""| |name := "play-html-compressor"
| |
|name := "play-html-compressor" |scalaVersion := "2.11.1"
| |
|scalaVersion := "2.11.1" |val pom = <xml:group><scm>
| |<url>git@github.com:mhiva/play-html-compressor.git</url>
|val pom = <xml:group><scm> |<connection>scm:git:git@github.com:mohiva/play-html-compressor.git</connection>
|<url>git@github.com:mhiva/play-html-compressor.git</url> | </scm>
|<connection>scm:git:git@github.com:mohiva/play-html-compressor.git</connection> |<developers>
| </scm> | <developer>
|<developers> | <id>akkie</id>
| <developer> | <name>Christian Kaps</name>
| <id>akkie</id> | <url>http://mohiva.com</url>
| <name>Christian Kaps</name> | </developer>
| <url>http://mohiva.com</url> | </developers></xml:group>
| </developer> |$errorLine
| </developers></xml:group> |
|$errorLine |""".stripMargin
|
|""".stripMargin
split(buildSbt) must throwA[MessageOnlyException].like {
case exception =>
val index = buildSbt.linesIterator.indexWhere(line => line.contains(errorLine)) + 1
val numberRegex = """(\d+)""".r
val message = exception.getMessage
val list = numberRegex.findAllIn(message).toList
list must contain(index.toString)
}
try {
split(buildSbt)
} catch {
case exception: MessageOnlyException =>
val index = buildSbt.linesIterator.indexWhere(line => line.contains(errorLine)) + 1
val numberRegex = """(\d+)""".r
val message = exception.getMessage
val list = numberRegex.findAllIn(message).toList
assert(list.contains(index.toString))
} }
} }
protected val files = Seq( protected val files = Seq(

View File

@ -13,29 +13,29 @@ import java.io.File
import sbt.internal.util.MessageOnlyException import sbt.internal.util.MessageOnlyException
import scala.io.Source import scala.io.Source
class ErrorSpec extends AbstractSpec { object ErrorSpec extends AbstractSpec {
implicit val splitter: SplitExpressions.SplitExpression = EvaluateConfigurations.splitExpressions implicit val splitter: SplitExpressions.SplitExpression = EvaluateConfigurations.splitExpressions
"Parser " should { test("Parser should contains file name and line number") {
val rootPath = getClass.getResource("/error-format/").getPath
"contains file name and line number" in { println(s"Reading files from: $rootPath")
val rootPath = getClass.getResource("/error-format/").getPath new File(rootPath).listFiles foreach { file =>
println(s"Reading files from: $rootPath") print(s"Processing ${file.getName}: ")
foreach(new File(rootPath).listFiles) { file => val buildSbt = Source.fromFile(file).getLines().mkString("\n")
print(s"Processing ${file.getName}: ") try {
val buildSbt = Source.fromFile(file).getLines().mkString("\n") SbtParser(file, buildSbt.linesIterator.toSeq)
SbtParser(file, buildSbt.linesIterator.toSeq) must throwA[MessageOnlyException] } catch {
.like { case exp: MessageOnlyException =>
case exp => val message = exp.getMessage
val message = exp.getMessage println(s"${exp.getMessage}")
println(s"${exp.getMessage}") assert(message.contains(file.getName))
message must contain(file.getName)
}
containsLineNumber(buildSbt)
} }
containsLineNumber(buildSbt)
} }
}
"handle wrong parsing " in { test("it should handle wrong parsing") {
intercept[MessageOnlyException] {
val buildSbt = val buildSbt =
""" """
|libraryDependencies ++= Seq("a" % "b" % "2") map { |libraryDependencies ++= Seq("a" % "b" % "2") map {
@ -50,25 +50,25 @@ class ErrorSpec extends AbstractSpec {
2, 2,
"fake.txt", "fake.txt",
new MessageOnlyException("fake") new MessageOnlyException("fake")
) must throwA[MessageOnlyException] )
()
} }
}
"handle xml error " in { test("it should handle xml error") {
try {
val buildSbt = val buildSbt =
""" """
|val a = <a/><b/> |val a = <a/><b/>
|val s = ' |val s = '
""".stripMargin """.stripMargin
SbtParser(SbtParser.FAKE_FILE, buildSbt.linesIterator.toSeq) must throwA[ SbtParser(SbtParser.FAKE_FILE, buildSbt.linesIterator.toSeq)
MessageOnlyException } catch {
].like { case exp: MessageOnlyException =>
case exp => val message = exp.getMessage
val message = exp.getMessage println(s"${exp.getMessage}")
println(s"${exp.getMessage}") assert(message.contains(SbtParser.FAKE_FILE.getName))
message must contain(SbtParser.FAKE_FILE.getName)
}
} }
} }
private def containsLineNumber(buildSbt: String) = { private def containsLineNumber(buildSbt: String) = {

View File

@ -11,29 +11,22 @@ package parser
import java.io.File import java.io.File
import org.junit.runner.RunWith
import org.specs2.runner.JUnitRunner
import scala.io.Source import scala.io.Source
@RunWith(classOf[JUnitRunner]) object NewFormatSpec extends AbstractSpec {
class NewFormatSpec extends AbstractSpec {
implicit val splitter: SplitExpressions.SplitExpression = EvaluateConfigurations.splitExpressions implicit val splitter: SplitExpressions.SplitExpression = EvaluateConfigurations.splitExpressions
"New Format " should { test("New Format should handle lines") {
"Handle lines " in { val rootPath = getClass.getResource("/new-format").getPath
val rootPath = getClass.getResource("/new-format").getPath println(s"Reading files from: $rootPath")
println(s"Reading files from: $rootPath") val allFiles = new File(rootPath).listFiles.toList
val allFiles = new File(rootPath).listFiles.toList allFiles foreach { path =>
foreach(allFiles) { path => println(s"$path")
println(s"$path") val lines = Source.fromFile(path).getLines().toList
val lines = Source.fromFile(path).getLines().toList val (_, statements) = splitter(path, lines)
val (_, statements) = splitter(path, lines) assert(statements.nonEmpty, s"""
statements.nonEmpty must be_==(true).setMessage(s""" |***should contains statements***
|***should contains statements*** |$lines """.stripMargin)
|$lines """.stripMargin)
}
} }
} }
} }

View File

@ -11,9 +11,6 @@ package parser
import java.io.{ File, FilenameFilter } import java.io.{ File, FilenameFilter }
import org.specs2.matcher.MatchResult
import scala.collection.GenTraversableOnce
import scala.io.Source import scala.io.Source
import SessionSettings.SessionSetting import SessionSettings.SessionSetting
@ -22,35 +19,32 @@ abstract class AbstractSessionSettingsSpec(folder: String) extends AbstractSpec
println(s"Reading files from: $rootPath") println(s"Reading files from: $rootPath")
protected val rootDir = new File(rootPath) protected val rootDir = new File(rootPath)
"SessionSettings " should { test("SessionSettings should be identical for empty map") {
"Be identical for empty map " in { def unit(f: File) = Seq((Source.fromFile(f).getLines().toList, Seq()))
def unit(f: File) = Seq((Source.fromFile(f).getLines().toList, Seq())) runTestOnFiles(unit)
runTestOnFiles(unit) }
}
"Replace statements " in { test("it should replace statements") {
runTestOnFiles(replace) runTestOnFiles(replace)
}
} }
private def runTestOnFiles( private def runTestOnFiles(
expectedResultAndMap: File => Seq[(List[String], Seq[SessionSetting])] expectedResultAndMap: File => Seq[(List[String], Seq[SessionSetting])]
): MatchResult[GenTraversableOnce[File]] = { ): Unit = {
val allFiles = rootDir val allFiles = rootDir
.listFiles(new FilenameFilter() { .listFiles(new FilenameFilter() {
def accept(dir: File, name: String) = name.endsWith(".sbt.txt") def accept(dir: File, name: String) = name.endsWith(".sbt.txt")
}) })
.toList .toList
foreach(allFiles) { file => allFiles foreach { file =>
val originalLines = Source.fromFile(file).getLines().toList val originalLines = Source.fromFile(file).getLines().toList
foreach(expectedResultAndMap(file)) { expectedResultAndMap(file) foreach {
case (expectedResultList, commands) => case (expectedResultList, commands) =>
val resultList = SbtRefactorings.applySessionSettings((file, originalLines), commands) val resultList = SbtRefactorings.applySessionSettings((file, originalLines), commands)
val expected = SbtParser(file, expectedResultList) val expected = SbtParser(file, expectedResultList)
val result = SbtParser(file, resultList._2) val result = SbtParser(file, resultList._2)
result.settings must_== expected.settings assert(result.settings == expected.settings)
} }
} }
} }

View File

@ -11,44 +11,44 @@ package parser
import java.io.File import java.io.File
import org.specs2.mutable.SpecificationLike import sbt.internal.util.LineRange
trait SplitExpression { trait SplitExpression {
def split(s: String, file: File = new File("noFile"))( def split(s: String, file: File = new File("noFile"))(
implicit splitter: SplitExpressions.SplitExpression implicit splitter: SplitExpressions.SplitExpression
) = splitter(file, s.split("\n").toSeq) ): (Seq[(String, Int)], Seq[(String, LineRange)]) = splitter(file, s.split("\n").toSeq)
} }
trait SplitExpressionsBehavior extends SplitExpression { this: SpecificationLike => trait SplitExpressionsBehavior extends SplitExpression { this: verify.BasicTestSuite =>
def newExpressionsSplitter(implicit splitter: SplitExpressions.SplitExpression) = { def newExpressionsSplitter(implicit splitter: SplitExpressions.SplitExpression) = {
"parse a two settings without intervening blank line" in { test("parse a two settings without intervening blank line") {
val (imports, settings) = split("""version := "1.0" val (imports, settings) = split("""version := "1.0"
scalaVersion := "2.10.4"""") scalaVersion := "2.10.4"""")
imports.isEmpty should beTrue assert(imports.isEmpty)
settings.size === 2 assert(settings.size == 2)
} }
"parse a setting and val without intervening blank line" in { test("parse a setting and val without intervening blank line") {
val (imports, settings) = val (imports, settings) =
split("""version := "1.0" split("""version := "1.0"
lazy val root = (project in file(".")).enablePlugins­(PlayScala)""") lazy val root = (project in file(".")).enablePlugins­(PlayScala)""")
imports.isEmpty should beTrue assert(imports.isEmpty)
settings.size === 2 assert(settings.size == 2)
} }
"parse a config containing two imports and a setting with no blank line" in { test("parse a config containing two imports and a setting with no blank line") {
val (imports, settingsAndDefs) = split( val (imports, settingsAndDefs) = split(
"""import foo.Bar """import foo.Bar
import foo.Bar import foo.Bar
version := "1.0" version := "1.0"
""".stripMargin """.stripMargin
) )
imports.size === 2 assert(imports.size == 2)
settingsAndDefs.size === 1 assert(settingsAndDefs.size == 1)
} }
} }

View File

@ -9,10 +9,6 @@ package sbt
package internal package internal
package parser package parser
import org.specs2.mutable.Specification object SplitExpressionsTest extends verify.BasicTestSuite with SplitExpressionsBehavior {
newExpressionsSplitter(EvaluateConfigurations.splitExpressions)
class SplitExpressionsTest extends Specification with SplitExpressionsBehavior {
"EvaluateConfigurations" should newExpressionsSplitter(EvaluateConfigurations.splitExpressions)
} }

View File

@ -10,169 +10,233 @@ package internal
package server package server
import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Caffeine
import sbt.internal.inc.Analysis
class DefinitionTest extends org.specs2.mutable.Specification { object DefinitionTest extends verify.BasicTestSuite {
import Definition.textProcessor import Definition.textProcessor
test(
"text processor" should { "text processor should find valid standard scala identifier when caret is set at the start of it"
"find valid standard scala identifier when caret is set at the start of it" in { ) {
textProcessor.identifier("val identifier = 0", 4) must beSome("identifier") assert(textProcessor.identifier("val identifier = 0", 4) == Some("identifier"))
}
"not find valid standard scala identifier because it is '='" in {
textProcessor.identifier("val identifier = 0", 15) must beNone
}
"find valid standard scala identifier when caret is set in the middle of it" in {
textProcessor.identifier("val identifier = 0", 11) must beSome("identifier")
}
"find valid standard scala identifier with comma" in {
textProcessor.identifier("def foo(a: identifier, b: other) = ???", 13) must beSome(
"identifier"
)
}
"find valid standard short scala identifier when caret is set at the start of it" in {
textProcessor.identifier("val a = 0", 4) must beSome("a")
}
"find valid standard short scala identifier when caret is set at the end of it" in {
textProcessor.identifier("def foo(f: Int) = Foo(f)", 19) must beSome("Foo")
}
"find valid non-standard short scala identifier when caret is set at the start of it" in {
textProcessor.identifier("val == = 0", 4) must beSome("==")
}
"find valid non-standard short scala identifier when caret is set in the middle of it" in {
textProcessor.identifier("val == = 0", 5) must beSome("==")
}
"find valid non-standard short scala identifier when caret is set at the end of it" in {
textProcessor.identifier("val == = 0", 6) must beSome("==")
}
"choose longest valid standard scala identifier from scala keyword when caret is set at the start of it" in {
textProcessor.identifier("val k = 0", 0) must beSome("va") or beSome("al")
}
"choose longest valid standard scala identifier from scala keyword when caret is set in the middle of it" in {
textProcessor.identifier("val k = 0", 1) must beSome("va") or beSome("al")
}
"match symbol as class name" in {
textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A") must be_==("com.acme.A")
}
"match symbol as object name" in {
textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$") must be_==("com.acme.A$")
}
"match symbol as inner class name" in {
textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$A") must be_==("com.acme.A$A")
}
"match symbol as inner object name" in {
textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$A$") must be_==("com.acme.A$A$")
}
"match symbol as default package class name" in {
textProcessor.potentialClsOrTraitOrObj("A")("A") must be_==("A")
}
"match symbol as default package object name" in {
textProcessor.potentialClsOrTraitOrObj("A")("A$") must be_==("A$")
}
"match object in line version 1" in {
textProcessor.classTraitObjectInLine("A")(" object A ") must contain(("object A", 3))
}
"match object in line version 2" in {
textProcessor.classTraitObjectInLine("A")(" object A ") must contain(("object A", 3))
}
"match object in line version 3" in {
textProcessor.classTraitObjectInLine("A")("object A {") must contain(("object A", 0))
}
"not match object in line" in {
textProcessor.classTraitObjectInLine("B")("object A ") must be empty
}
"match class in line version 1" in {
textProcessor.classTraitObjectInLine("A")(" class A ") must contain(("class A", 3))
}
"match class in line version 2" in {
textProcessor.classTraitObjectInLine("A")(" class A ") must contain(("class A", 3))
}
"match class in line version 3" in {
textProcessor.classTraitObjectInLine("A")("class A {") must contain(("class A", 0))
}
"match class in line version 4" in {
textProcessor.classTraitObjectInLine("A")(" class A[A] ") must contain(
("class A", 3)
)
}
"match class in line version 5" in {
textProcessor.classTraitObjectInLine("A")(" class A [A] ") must contain(
("class A", 3)
)
}
"match class in line version 6" in {
textProcessor.classTraitObjectInLine("A")("class A[A[_]] {") must contain(("class A", 0))
}
"not match class in line" in {
textProcessor.classTraitObjectInLine("B")("class A ") must be empty
}
"match trait in line version 1" in {
textProcessor.classTraitObjectInLine("A")(" trait A ") must contain(("trait A", 3))
}
"match trait in line version 2" in {
textProcessor.classTraitObjectInLine("A")(" trait A ") must contain(("trait A", 3))
}
"match trait in line version 3" in {
textProcessor.classTraitObjectInLine("A")("trait A {") must contain(("trait A", 0))
}
"match trait in line version 4" in {
textProcessor.classTraitObjectInLine("A")(" trait A[A] ") must contain(
("trait A", 3)
)
}
"match trait in line version 5" in {
textProcessor.classTraitObjectInLine("A")(" trait A [A] ") must contain(
("trait A", 3)
)
}
"match trait in line version 6" in {
textProcessor.classTraitObjectInLine("A")("trait A[A[_]] {") must contain(("trait A", 0))
}
"not match trait in line" in {
textProcessor.classTraitObjectInLine("B")("trait A ") must be empty
}
} }
"definition" should { test("it should not find valid standard scala identifier because it is '='") {
assert(textProcessor.identifier("val identifier = 0", 15) == None)
}
"cache data in cache" in { test("it should find valid standard scala identifier when caret is set in the middle of it") {
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]() assert(textProcessor.identifier("val identifier = 0", 11) == Some("identifier"))
val cacheFile = "Test.scala" }
val useBinary = true
Definition.updateCache(cache)(cacheFile, useBinary) test("it should find valid standard scala identifier with comma") {
assert(
textProcessor.identifier("def foo(a: identifier, b: other) = ???", 13) == Some("identifier")
)
}
val actual = Definition.AnalysesAccess.getFrom(cache) test("it should find valid standard short scala identifier when caret is set at the start of it") {
assert(textProcessor.identifier("val a = 0", 4) == Some("a"))
}
actual.get should contain("Test.scala" -> true -> None) test("it should find valid standard short scala identifier when caret is set at the end of it") {
} assert(textProcessor.identifier("def foo(f: Int) = Foo(f)", 19) == Some("Foo"))
}
"replace cache data in cache" in { test(
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]() "it should find valid non-standard short scala identifier when caret is set at the start of it"
val cacheFile = "Test.scala" ) {
val useBinary = true assert(textProcessor.identifier("val == = 0", 4) == Some("=="))
val falseUseBinary = false }
Definition.updateCache(cache)(cacheFile, falseUseBinary) test(
Definition.updateCache(cache)(cacheFile, useBinary) "it should find valid non-standard short scala identifier when caret is set in the middle of it"
) {
assert(textProcessor.identifier("val == = 0", 5) == Some("=="))
}
val actual = Definition.AnalysesAccess.getFrom(cache) test(
"it should find valid non-standard short scala identifier when caret is set at the end of it"
) {
assert(textProcessor.identifier("val == = 0", 6) == Some("=="))
}
actual.get should contain("Test.scala" -> true -> None) test(
} "it should choose longest valid standard scala identifier from scala keyword when caret is set at the start of it"
) {
assert(
textProcessor.identifier("val k = 0", 0) == Some("va") || textProcessor
.identifier("val k = 0", 0) == Some("al")
)
}
"cache more data in cache" in { test(
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]() "it should choose longest valid standard scala identifier from scala keyword when caret is set in the middle of it"
val cacheFile = "Test.scala" ) {
val useBinary = true assert(
val otherCacheFile = "OtherTest.scala" textProcessor.identifier("val k = 0", 1) == Some("va") || textProcessor
val otherUseBinary = false .identifier("val k = 0", 1) == Some("al")
)
}
Definition.updateCache(cache)(otherCacheFile, otherUseBinary) test("it should match symbol as class name") {
Definition.updateCache(cache)(cacheFile, useBinary) assert(textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A") == "com.acme.A")
}
val actual = Definition.AnalysesAccess.getFrom(cache) test("it should match symbol as object name") {
assert(textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$") == "com.acme.A$")
}
actual.get should contain("Test.scala" -> true -> None, "OtherTest.scala" -> false -> None) test("it should match symbol as inner class name") {
} assert(textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$A") == "com.acme.A$A")
}
test("it should match symbol as inner object name") {
assert(textProcessor.potentialClsOrTraitOrObj("A")("com.acme.A$A$") == "com.acme.A$A$")
}
test("it should match symbol as default package class name") {
assert(textProcessor.potentialClsOrTraitOrObj("A")("A") == "A")
}
test("it should match symbol as default package object name") {
assert(textProcessor.potentialClsOrTraitOrObj("A")("A$") == "A$")
}
test("it should match object in line version 1") {
assert(textProcessor.classTraitObjectInLine("A")(" object A ").contains(("object A", 3)))
}
test("it should match object in line version 2") {
assert(
textProcessor.classTraitObjectInLine("A")(" object A ").contains(("object A", 3))
)
}
test("it should match object in line version 3") {
assert(textProcessor.classTraitObjectInLine("A")("object A {").contains(("object A", 0)))
}
test("it should not match object in line") {
assert(textProcessor.classTraitObjectInLine("B")("object A ").isEmpty)
}
test("it should match class in line version 1") {
assert(textProcessor.classTraitObjectInLine("A")(" class A ").contains(("class A", 3)))
}
test("it should match class in line version 2") {
assert(textProcessor.classTraitObjectInLine("A")(" class A ").contains(("class A", 3)))
}
test("it should match class in line version 3") {
assert(textProcessor.classTraitObjectInLine("A")("class A {").contains(("class A", 0)))
}
test("it should match class in line version 4") {
assert(
textProcessor.classTraitObjectInLine("A")(" class A[A] ").contains(("class A", 3))
)
}
test("it should match class in line version 5") {
assert(
textProcessor
.classTraitObjectInLine("A")(" class A [A] ")
.contains(
("class A", 3)
)
)
}
test("it should match class in line version 6") {
assert(textProcessor.classTraitObjectInLine("A")("class A[A[_]] {").contains(("class A", 0)))
}
test("it should not match class in line") {
assert(textProcessor.classTraitObjectInLine("B")("class A ").isEmpty)
}
test("match trait in line version 1") {
assert(textProcessor.classTraitObjectInLine("A")(" trait A ").contains(("trait A", 3)))
}
test("it should match trait in line version 2") {
assert(textProcessor.classTraitObjectInLine("A")(" trait A ").contains(("trait A", 3)))
}
test("it should match trait in line version 3") {
assert(textProcessor.classTraitObjectInLine("A")("trait A {").contains(("trait A", 0)))
}
test("it should match trait in line version 4") {
assert(
textProcessor
.classTraitObjectInLine("A")(" trait A[A] ")
.contains(
("trait A", 3)
)
)
}
test("it should match trait in line version 5") {
assert(
textProcessor
.classTraitObjectInLine("A")(" trait A [A] ")
.contains(
("trait A", 3)
)
)
}
test("it should match trait in line version 6") {
assert(textProcessor.classTraitObjectInLine("A")("trait A[A[_]] {").contains(("trait A", 0)))
}
test("it should not match trait in line") {
assert(textProcessor.classTraitObjectInLine("B")("trait A ").isEmpty)
}
test("definition should cache data in cache") {
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]()
val cacheFile = "Test.scala"
val useBinary = true
Definition.updateCache(cache)(cacheFile, useBinary)
val actual = Definition.AnalysesAccess.getFrom(cache)
assert(actual.get.contains(("Test.scala" -> true -> None)))
}
test("it should replace cache data in cache") {
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]()
val cacheFile = "Test.scala"
val useBinary = true
val falseUseBinary = false
Definition.updateCache(cache)(cacheFile, falseUseBinary)
Definition.updateCache(cache)(cacheFile, useBinary)
val actual = Definition.AnalysesAccess.getFrom(cache)
assert(actual.get.contains(("Test.scala" -> true -> None)))
}
test("it should cache more data in cache") {
val cache = Caffeine.newBuilder().build[String, Definition.Analyses]()
val cacheFile = "Test.scala"
val useBinary = true
val otherCacheFile = "OtherTest.scala"
val otherUseBinary = false
Definition.updateCache(cache)(otherCacheFile, otherUseBinary)
Definition.updateCache(cache)(cacheFile, useBinary)
val actual = Definition.AnalysesAccess.getFrom(cache)
assert(
actual.get.contains("Test.scala" -> true -> Option.empty[Analysis]) &&
actual.get.contains("OtherTest.scala" -> false -> Option.empty[Analysis])
)
} }
} }

View File

@ -15,6 +15,7 @@ import java.nio.file._
import java.util.concurrent._ import java.util.concurrent._
import scala.collection.mutable import scala.collection.mutable
import scala.util.Properties.versionNumberString
import xsbti.{ Logger => _, _ } import xsbti.{ Logger => _, _ }
import sbt.io.IO import sbt.io.IO
@ -25,7 +26,7 @@ import sbt.BuildPaths._
import sbt.Def.{ ScopeLocal, ScopedKey, Setting } import sbt.Def.{ ScopeLocal, ScopedKey, Setting }
import sbt.Keys._ import sbt.Keys._
object SettingQueryTest extends org.specs2.mutable.Specification { object SettingQueryTest extends verify.BasicTestSuite {
implicit class PathOps(val path: Path) extends AnyVal { implicit class PathOps(val path: Path) extends AnyVal {
def /(other: String): Path = if (other == ".") path else path resolve other def /(other: String): Path = if (other == ".") path else path resolve other
} }
@ -201,50 +202,87 @@ object SettingQueryTest extends org.specs2.mutable.Specification {
payload payload
} }
// -.- avoid specs2's ko/ok def qok(x: String, t: String): String =
import org.specs2.matcher.MatchResult s"""{"type":"SettingQuerySuccess","value":$x,"contentType":"$t"}"""
def qok(x: String, t: String): String => MatchResult[Any] = def qko(msg: String): String =
query(_) must_== """{"type":"SettingQuerySuccess","value":""" + x + ""","contentType":"""" + t + """"}""" s"""{"type":"SettingQueryFailure","message":"$msg"}"""
def qko(msg: String): String => MatchResult[Any] =
query(_) must_== """{"type":"SettingQueryFailure","message":"""" + msg + """"}"""
"setting query" should { test("t/scalaVersion") {
"t/scalaVersion" in qok("\"2.12.1\"", "java.lang.String") assertEquals(qok("\"2.12.1\"", "java.lang.String"), query("t/scalaVersion"))
// "t/pollInterval" in qok("500", "Int") }
"t/sourcesInBase" in qok("true", "Boolean")
"t/startYear" in qok("null", "scala.Option[Int]") // test("t/pollInterval") {
"t/scalaArtifacts" in { // assertEquals(qok("500", "Int"), query("t/pollInterval"))
if (scala.util.Properties.versionNumberString.startsWith("2.12")) // }
test("t/sourcesInBase") {
assertEquals(qok("true", "Boolean"), query("t/sourcesInBase"))
}
test("t/startYear") {
assertEquals(qok("null", "scala.Option[Int]"), query("t/startYear"))
}
test("t/scalaArtifacts") {
if (versionNumberString.startsWith("2.12"))
assertEquals(
qok( qok(
"""["scala-library","scala-compiler","scala-reflect","scala-actors","scalap"]""", """["scala-library","scala-compiler","scala-reflect","scala-actors","scalap"]""",
"scala.collection.Seq[java.lang.String]" "scala.collection.Seq[java.lang.String]"
) ),
else query("t/scalaArtifacts"),
)
else
assertEquals(
qok( qok(
"""["scala-library","scala-compiler","scala-reflect","scala-actors","scalap"]""", """["scala-library","scala-compiler","scala-reflect","scala-actors","scalap"]""",
"scala.collection.immutable.Seq[java.lang.String]" "scala.collection.immutable.Seq[java.lang.String]"
) ),
} query("t/scalaArtifacts"),
)
}
"t/libraryDependencies" in { test("t/libraryDependencies") {
if (scala.util.Properties.versionNumberString.startsWith("2.12")) if (versionNumberString.startsWith("2.12"))
assertEquals(
qok( qok(
"""[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}]""", """[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}]""",
"scala.collection.Seq[sbt.librarymanagement.ModuleID]" "scala.collection.Seq[sbt.librarymanagement.ModuleID]"
) ),
else query("t/libraryDependencies"),
)
else
assertEquals(
qok( qok(
"""[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}]""", """[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}]""",
"scala.collection.immutable.Seq[sbt.librarymanagement.ModuleID]" "scala.collection.immutable.Seq[sbt.librarymanagement.ModuleID]"
) ),
} query("t/libraryDependencies"),
)
}
"scalaVersion" in qko("Not a valid project ID: scalaVersion\\nscalaVersion\\n ^") test("scalaVersion") {
"t/scalacOptions" in qko( assertEquals(
s"""Key ProjectRef(uri(\\"$baseUri\\"), \\"t\\") / Compile / scalacOptions is a task, can only query settings""" qko("Not a valid project ID: scalaVersion\\nscalaVersion\\n ^"),
query("scalaVersion"),
) )
"t/fooo" in qko( }
"Expected ':' (if selecting a configuration)\\nNot a valid key: fooo (similar: fork)\\nt/fooo\\n ^"
test("t/scalacOptions") {
assertEquals(
qko(
s"""Key ProjectRef(uri(\\"$baseUri\\"), \\"t\\") / Compile / scalacOptions is a task, can only query settings"""
),
query("t/scalacOptions"),
)
}
test("t/fooo") {
assertEquals(
qko(
"Expected ':' (if selecting a configuration)\\nNot a valid key: fooo (similar: fork)\\nt/fooo\\n ^"
),
query("t/fooo"),
) )
} }
} }

View File

@ -94,9 +94,8 @@ object Dependencies {
val jansi = "org.fusesource.jansi" % "jansi" % "2.0.1" val jansi = "org.fusesource.jansi" % "jansi" % "2.0.1"
val scalatest = "org.scalatest" %% "scalatest" % "3.0.8" val scalatest = "org.scalatest" %% "scalatest" % "3.0.8"
val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0" val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0"
val specs2 = "org.specs2" %% "specs2-junit" % "4.10.0"
val junit = "junit" % "junit" % "4.13.1" val junit = "junit" % "junit" % "4.13.1"
val scalaVerify = "com.eed3si9n.verify" %% "verify" % "0.2.0" val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0"
val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1" val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1"
val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.3.0" val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.3.0"

View File

@ -13,7 +13,6 @@ object NightlyPlugin extends AutoPlugin {
if (includeTestDependencies.value) if (includeTestDependencies.value)
Seq( Seq(
scalacheck % Test, scalacheck % Test,
specs2 % Test,
junit % Test, junit % Test,
scalatest % Test, scalatest % Test,
scalaVerify % Test, scalaVerify % Test,