aboutsummaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
authorTomasz Bekas <tbekas@infusion.com>2016-08-09 18:44:04 +0000
committerChristopher Vogt <oss.nsp@cvogt.org>2016-11-07 02:08:39 -0500
commitd89c9bdd16c7be729383acf438fcde4cdd863e9c (patch)
tree69bc9860f1f8c92feeb466deff6b737349936374 /libraries
parentb0d84f6663662cb20cc7535924903cd65a6b74b8 (diff)
downloadcbt-d89c9bdd16c7be729383acf438fcde4cdd863e9c.tar.gz
cbt-d89c9bdd16c7be729383acf438fcde4cdd863e9c.tar.bz2
cbt-d89c9bdd16c7be729383acf438fcde4cdd863e9c.zip
util-eval: Reset reporter between checks
Problem When you want to use the util-eval for validating the correctness of a small chunk of code, you have to reset whole state between invocations (flag resetState=true), which is expensive when you already have a bunch of compiled and loaded classes. Without this, if one check fails, all subsequent checks will fail as well, since some errors has been reported previously. Solution Scala compiler API allows for resetting just the reporter, so that compiled and loaded classes can remain for re-usage for next checks. Result Public API remains the same, however the internal API has one new synchronized method resetReporter() which does what is explained in the "Solution" section. Signed-off-by: Ryan O'Neill <ryano@twitter.com> RB_ID=859878
Diffstat (limited to 'libraries')
-rw-r--r--libraries/eval/Eval.scala11
-rw-r--r--libraries/eval/test/EvalTest.scala18
2 files changed, 28 insertions, 1 deletions
diff --git a/libraries/eval/Eval.scala b/libraries/eval/Eval.scala
index 92329d3..abd1836 100644
--- a/libraries/eval/Eval.scala
+++ b/libraries/eval/Eval.scala
@@ -242,6 +242,7 @@ class Eval(target: Option[File]) {
val id = uniqueId(sourceForString(code))
val className = "Evaluator__" + id
val wrappedCode = wrapCodeInClass(className, code)
+ resetReporter()
compile(wrappedCode) // may throw CompilerException
}
@@ -266,6 +267,10 @@ class Eval(target: Option[File]) {
compiler.findClass(className).getOrElse { throw new ClassNotFoundException("no such class: " + className) }
}
+ private[util] def resetReporter(): Unit = {
+ compiler.resetReporter()
+ }
+
private[util] def uniqueId(code: String, idOpt: Option[Int] = Some(jvmId)): String = {
val digest = MessageDigest.getInstance("SHA-1").digest(code.getBytes())
val sha = new BigInteger(1, digest).toString(16)
@@ -533,6 +538,12 @@ class Eval(target: Option[File]) {
classLoader = new AbstractFileClassLoader(target, this.getClass.getClassLoader)
}
+ def resetReporter(): Unit = {
+ synchronized {
+ reporter.reset()
+ }
+ }
+
object Debug {
val enabled =
System.getProperty("eval.debug") != null
diff --git a/libraries/eval/test/EvalTest.scala b/libraries/eval/test/EvalTest.scala
index 52913ab..8b986e2 100644
--- a/libraries/eval/test/EvalTest.scala
+++ b/libraries/eval/test/EvalTest.scala
@@ -205,7 +205,7 @@ class EvalTest extends WordSpec {
assert(eval.errors.nonEmpty)
}
- "reset reporter between invocations" in {
+ "reset state between invocations" in {
val ctx = new Ctx
import ctx._
@@ -216,6 +216,22 @@ class EvalTest extends WordSpec {
assert(eval[Int]("val d = 3; val e = 2; d + e", true) == 5)
assert(eval.errors.isEmpty)
}
+
+ "reporter should be reset between checks, but loaded class should remain" in {
+ val ctx = new Ctx
+ import ctx._
+
+ // compile and load compiled class
+ eval.compile("class A()")
+
+ intercept[Throwable] {
+ eval.check("new B()")
+ }
+ assert(eval.errors.nonEmpty)
+
+ eval.check("new A()")
+ assert(eval.errors.isEmpty)
+ }
}
}
}