simple-build-tool (sbt) and specs

somewhat updated

Some people land on this page searching for "sbt specs" on Google, so I feel somewhat obligated to update the info on this page.

First of all, as of 2011, the specs signature in Project file looks like:

    val specsVersion = crossScalaVersionString match {
      case "2.8.0" => "1.6.5"
      case _ => "1.6.6"
    }
    val specs = "org.scala-tools.testing" % ("specs_" + crossScalaVersionString) % specsVersion % "test"

Next, I was fitting integration test into specs, but it really should be used for writing BDD style test like the following:

import org.specs._
import scalaxb.compiler.{Verbose}
 
object IncTest extends Specification {
  val module = new scalaxb.compiler.xsd2.Driver // with Verbose
 
  lazy val generated = module.processString(schemaString, "general")
  lazy val entitySource = generated(0)
  ...
 
  "the generated entity source" should {
    "start with // Generated by" >> {
      entitySource must startWith("// Generated by")
    }
  }
}

When you run the test, each item is printed out in either in green or red color.

[info] + the generated entity source should
[info]   + start with // Generated by

Kind of like a spec document.

original article

Running Ant was getting old. It was one of few things I still had lying around from old code base. Especially because I'm using text editor (TextMate) to code, I was running Ant every minute. The problem was that was taking long time every time because it wouldn't build unless I built everything from scratch. I had somewhat utopian hope about simple-build-tool and specs, but I soon met the reality of things not working so easily.

First challenge was to get specs working with sbt that's cross compiling to scala 2.8.0.Beta1. The following took care of that.

  val specs = "org.scala-tools.testing" % "specs_2.8.0.Beta1" % "1.6.2" % "test"

Next challenge was testing the generated scala code. Using Ant I was able to call scala compiler along with "test" code. I was expecting to find specs matcher that I can say

  List(generated) must compile

or

  (List("import ipo._",
        "Address(\"\", \"\", \"\").toString"), 
   List(generated)) must evaluateTo("Address(,,)")

Unfortunately, I could not find any specs matcher quite like it, so I had to write one myself: CompilerMatcher.scala.

I knew I could use scalac as library, but having other's successful implementation helped. I got most of the details from Foo.scala from sbt, Vassil Dichev's Speaking My (Programming) Language: Embedded Scala interpreter and Josh Suresh's Rants, Raves, and Ridicule: Embedding the Scala Interpreter. I still had to comb through docs and codes to get things working.

The first example

  List(generated) must compile

simply passes a list of files and it checks whether they compile without errors.

The next example

  (List("import ipo._",
        "Address(\"\", \"\", \"\").toString"), 
   List(generated)) must evaluateTo("Address(,,)")

does the same, but it also interprets a list of code and checks the last line against the given expected value. I need this because scalaxb generates scala code. And what better way to check a scala code than using it.