Changes to assist with scripted testing of sbt 0.6.x series

This commit is contained in:
Mark Harrah 2009-12-04 21:31:03 -05:00
parent 20983c7dc2
commit f139e5a9c1
6 changed files with 107 additions and 10 deletions

View File

@ -1,7 +1,5 @@
#Project properties
#Sat Nov 14 17:25:10 EST 2009
project.organization=org.scala-tools.sbt
project.name=xsbt
sbt.version=0.5.6
project.version=0.6.4
project.version=0.6.5-p1
scala.version=2.7.5

View File

@ -13,9 +13,9 @@ class ScriptRunner
def apply(statements: List[(StatementHandler, Statement)])
{
val states = new HashMap[StatementHandler, Any]
def processStatement(handler: StatementHandler, statement: Statement)
{
val state = states.getOrElseUpdate(handler, handler.initialState).asInstanceOf[handler.State]
def processStatement(handler: StatementHandler, statement: Statement)
{
val state = states(handler).asInstanceOf[handler.State]
val nextState =
try { Right( handler(statement.command, statement.arguments, state) ) }
catch { case e: Exception => Left(e) }
@ -23,7 +23,12 @@ class ScriptRunner
{
case Left(err) =>
if(statement.successExpected)
throw new TestException(statement, "Command failed", err)
{
err match {
case t: TestFailed => throw new TestException(statement, "Command failed: " + t.getMessage, null)
case _ => throw new TestException(statement, "Command failed", err)
}
}
else
()
case Right(s) =>
@ -33,7 +38,20 @@ class ScriptRunner
throw new TestException(statement, "Command succeeded but failure was expected", null)
}
}
statements.foreach { case (handler, _) => states(handler) = handler.initialState }
statements foreach( Function.tupled(processStatement) )
val handlers = Set() ++ statements.map(_._1)
try
{
handlers.foreach { handler => states(handler) = handler.initialState }
statements foreach( Function.tupled(processStatement) )
}
finally
{
for(handler <- handlers; state <- states.get(handler))
{
try { handler.finish(state.asInstanceOf[handler.State]) }
catch { case e: Exception => () }
}
}
}
}

View File

@ -5,6 +5,7 @@ trait StatementHandler
type State
def initialState: State
def apply(command: String, arguments: List[String], state: State): State
def finish(state: State): Unit
}
trait BasicStatementHandler extends StatementHandler
@ -13,4 +14,11 @@ trait BasicStatementHandler extends StatementHandler
final def initialState = ()
final def apply(command: String, arguments: List[String], state: Unit): Unit= apply(command, arguments)
def apply(command: String, arguments: List[String]): Unit
def finish(state: Unit) = ()
}
/** Use when a stack trace is not useful */
final class TestFailed(msg: String) extends RuntimeException(msg)
{
override def fillInStackTrace = this
}

View File

@ -114,6 +114,7 @@ class StandardCompile(val sources: Task[Set[File]], val classpath: Task[Set[File
def jarDependency(jar: File, source: File) { tracking.use(source, jar) }
def classDependency(clazz: File, source: File) { tracking.dependency(source, clazz) }
def generatedClass(source: File, clazz: File) { tracking.product(source, clazz) }
def api(source: File, api: xsbti.api.Source) = ()
}
}

72
util/io/IPC.scala Normal file
View File

@ -0,0 +1,72 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
package xsbt
import java.io.{BufferedReader, BufferedWriter, InputStream, InputStreamReader, OutputStreamWriter, OutputStream}
import java.net.{InetAddress, ServerSocket, Socket}
object IPC
{
private val portMin = 1025
private val portMax = 65536
private val loopback = InetAddress.getByName(null) // loopback
def client[T](port: Int)(f: IPC => T): T =
ipc(new Socket(loopback, port))(f)
def pullServer[T](f: Server => T): T =
{
val server = makeServer
try { f(new Server(server)) }
finally { server.close() }
}
def makeServer: ServerSocket =
{
val random = new java.util.Random
def nextPort = random.nextInt(portMax - portMin + 1) + portMin
def createServer(attempts: Int): ServerSocket =
if(attempts > 0)
try { new ServerSocket(nextPort, 1, loopback) }
catch { case _: Exception => createServer(attempts - 1) }
else
error("Could not connect to socket: maximum attempts exceeded")
createServer(10)
}
def server[T](f: IPC => Option[T]): T = serverImpl(makeServer, f)
def server[T](port: Int)(f: IPC => Option[T]): T =
serverImpl(new ServerSocket(port, 1, loopback), f)
private def serverImpl[T](server: ServerSocket, f: IPC => Option[T]): T =
{
def listen(): T =
{
ipc(server.accept())(f) match
{
case Some(done) => done
case None => listen()
}
}
try { listen() }
finally { server.close() }
}
private def ipc[T](s: Socket)(f: IPC => T): T =
try { f(new IPC(s)) }
finally { s.close() }
final class Server private[IPC](s: ServerSocket) extends NotNull
{
def port = s.getLocalPort
def close() = s.close()
def connection[T](f: IPC => T): T = IPC.ipc(s.accept())(f)
}
}
final class IPC private(s: Socket) extends NotNull
{
def port = s.getLocalPort
private val in = new BufferedReader(new InputStreamReader(s.getInputStream))
private val out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream))
def send(s: String) = { out.write(s); out.newLine(); out.flush() }
def receive: String = in.readLine()
}

View File

@ -59,7 +59,7 @@ object OpenResource
def resource[Source, T <: Closeable](openF: Source => T): OpenResource[Source,T] =
resource(openF, _.close)
def resource[Source, T <: Closeable](openF: Source => T, closeF: T => Unit): OpenResource[Source,T] =
def resource[Source, T](openF: Source => T, closeF: T => Unit): OpenResource[Source,T] =
new OpenResource[Source,T]
{
def open(s: Source) = openF(s)