package sbt package compiler import org.scalacheck._ import Prop._ import scala.tools.nsc.reporters.StoreReporter object EvalTest extends Properties("eval") { private[this] val reporter = new StoreReporter import reporter.{ERROR,Info,Severity} private[this] val eval = new Eval(_ => reporter, None) property("inferred integer") = forAll{ (i: Int) => val result = eval.eval(i.toString) (label("Value", value(result)) |: (value(result) == i)) && (label("Type", value(result)) |: (result.tpe == IntType)) && (label("Files", result.generated) |: (result.generated.isEmpty)) } property("explicit integer") = forAll{ (i: Int) => val result = eval.eval(i.toString, tpeName = Some(IntType)) (label("Value", value(result)) |: (value(result) == i)) && (label("Type", result.tpe) |: (result.tpe == IntType)) && (label("Files", result.generated) |: (result.generated.isEmpty)) } property("type mismatch") = forAll{ (i: Int, l: Int) => val line = math.abs(l) val src = "mismatch" throws(eval.eval(i.toString, tpeName =Some(BooleanType), line = line, srcName = src), classOf[RuntimeException]) && hasErrors(line+1, src) } property("backed local class") = forAll{ (i: Int) => IO.withTemporaryDirectory { dir => val eval = new Eval(_ => reporter, backing = Some(dir)) val result = eval.eval(local(i)) val v = value(result).asInstanceOf[{def i: Int}].i (label("Value", v) |: (v == i)) && (label("Type", result.tpe) |: (result.tpe == LocalType)) && (label("Files", result.generated) |: (!result.generated.isEmpty)) } } val ValTestNames = Set("x", "a") val ValTestContent = """ val x: Int = { val y: Int = 4 y } val z: Double = 3.0 val a = 9 val p = { object B { val i = 3 } class C { val j = 4 } "asdf" } """ property("val test") = secure { val defs = (ValTestContent, 1 to 7) :: Nil val res = eval.evalDefinitions(defs, new EvalImports(Nil, ""), "", "scala.Int" :: Nil) label("Val names", res.valNames) |: (res.valNames.toSet == ValTestNames) } property("explicit import") = forAll(testImport("import math.abs" :: Nil)) property("wildcard import") = forAll(testImport("import math._" :: Nil)) property("comma-separated imports") = forAll(testImport("import util._, math._, xml._" :: Nil)) property("multiple imports") = forAll(testImport("import util._" :: "import math._" :: "import xml._" :: Nil)) private[this] def testImport(imports: Seq[String]): Int => Prop = i => value(eval.eval("abs("+i+")", new EvalImports(imports.zipWithIndex, "imp"))) == math.abs(i) private[this] def local(i: Int) = "{ class ETest(val i: Int); new ETest(" + i + ") }" val LocalType = "Object{val i: Int}" private[this] def value(r: EvalResult) = r.getValue(getClass.getClassLoader) private[this] def hasErrors(line: Int, src: String) = { val is = reporter.infos ("Has errors" |: (!is.isEmpty)) && all(is.toSeq.map(validPosition(line,src)) :_*) } private[this] def validPosition(line: Int, src: String)(i: Info) = { val nme = i.pos.source.file.name (label("Severity", i.severity) |: (i.severity == ERROR)) && (label("Line", i.pos.line) |: (i.pos.line == line)) && (label("Name", nme) |: (nme == src)) } val IntType = "Int" val BooleanType = "Boolean" def label(s: String, value: Any) = s + " (" + value + ")" }