Skip to content

Commit 3e91fc2

Browse files
author
Javier de Silóniz Sandino
committed
Merge branch 'master' into js-IncludeFPinScalaExercises
2 parents 6605c18 + bf5bc48 commit 3e91fc2

File tree

4 files changed

+63
-19
lines changed

4 files changed

+63
-19
lines changed

src/main/scala/org/scalaexercises/exercises/Evaluator.scala

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@ import java.util.concurrent.{ TimeoutException, Callable, FutureTask, TimeUnit }
2222
import scala.util.Try
2323
import scala.util.control.NonFatal
2424
import scala.concurrent.duration._
25+
import scala.concurrent._
2526
import scala.language.reflectiveCalls
27+
2628
import com.twitter.util.Eval
2729

30+
import monix.execution._
31+
2832
import scala.reflect.internal.util.{ BatchSourceFile, Position }
2933

3034
sealed trait Severity
@@ -43,12 +47,14 @@ object EvalResult {
4347

4448
case object Timeout extends EvalResult[Nothing]
4549
case class Success[T](complilationInfos: CI, result: T, consoleOutput: String) extends EvalResult[T]
50+
case class Timeout[T]() extends EvalResult[T]
4651
case class EvalRuntimeError(complilationInfos: CI, runtimeError: Option[RuntimeError]) extends EvalResult[Nothing]
4752
case class CompilationError(complilationInfos: CI) extends EvalResult[Nothing]
4853
case class GeneralError(stack: Throwable) extends EvalResult[Nothing]
4954
}
5055

51-
class Evaluator(timeout: Duration = 20.seconds) {
56+
class Evaluator(timeout: FiniteDuration = 20.seconds) {
57+
implicit val scheduler: ExecutionContext = Scheduler.io("evaluation-scheduler")
5258

5359
def convert(errors: (Position, String, String)): (Severity, List[CompilationInfo]) = {
5460
val (pos, msg, severity) = errors
@@ -60,11 +66,7 @@ class Evaluator(timeout: Duration = 20.seconds) {
6066
(sev, CompilationInfo(msg, Some(RangePosition(pos.start, pos.point, pos.end))) :: Nil)
6167
}
6268

63-
def apply[T](pre: String, code: String): EvalResult[T] = {
64-
val allCode = s"""
65-
|$pre
66-
|$code
67-
""".stripMargin
69+
def eval[T](code: String): EvalResult[T] = {
6870
val eval = new Eval {
6971
@volatile var errors: Map[Severity, List[CompilationInfo]] = Map.empty
7072

@@ -82,26 +84,30 @@ class Evaluator(timeout: Duration = 20.seconds) {
8284
}
8385

8486
val result = for {
85-
_ Try(eval.check(allCode))
86-
result Try(eval.apply[T](allCode, resetState = true))
87+
_ Try(eval.check(code))
88+
result Try(eval.apply[T](code, resetState = true))
8789
} yield result
8890

8991
val errors: Map[Severity, List[CompilationInfo]] = eval.errors.toMap
9092

91-
println(allCode)
92-
93-
println(result)
94-
95-
println(errors)
96-
9793
result match {
9894
case scala.util.Success(r) EvalResult.Success[T](errors, r, "")
9995
case scala.util.Failure(t) t match {
10096
case e: Eval.CompilerException EvalResult.CompilationError(errors)
101-
case e EvalResult.EvalRuntimeError(errors, None)
97+
case NonFatal(e) EvalResult.EvalRuntimeError(errors, Option(RuntimeError(e, None)))
98+
case e EvalResult.GeneralError(e)
10299
}
103100
}
104-
105101
}
106102

103+
def apply[T](pre: String, code: String): EvalResult[T] = {
104+
val allCode = s"""
105+
|$pre
106+
|$code
107+
""".stripMargin
108+
val fut = Future({ eval(allCode) })
109+
Try(
110+
Await.result(fut, timeout)
111+
).getOrElse(EvalResult.Timeout())
112+
}
107113
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* scala-exercises-runtime
3+
* Copyright (C) 2015-2016 47 Degrees, LLC. <http://www.47deg.com>
4+
*/
5+
6+
package org.scalaexercises.runtime
7+
8+
import scala.concurrent.duration._
9+
import org.scalatest._
10+
11+
class EvaluatorSpec extends FunSpec with Matchers {
12+
13+
describe("evaluation") {
14+
it("fails with a timeout when takes longer than the configured timeout") {
15+
val evaluator = new Evaluator(1 second)
16+
val result: EvalResult[Int] = evaluator("", "{ while(true) {}; 123 }")
17+
result should matchPattern {
18+
case t: EvalResult.Timeout[Int]
19+
}
20+
}
21+
}
22+
}

src/test/scala/com/fortysevendeg/exercises/ExampleTarget.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package org.scalaexercises.runtime
22

3-
object ExampleTarget {
3+
import org.scalatest._
4+
5+
object ExampleTarget extends FlatSpec with Matchers {
46
def intStringMethod(a: Int, b: String): String = {
57
s"$a$b"
68
}
79

10+
def isOne(a: Int) = {
11+
a shouldBe 1
12+
}
13+
814
class ExampleException extends Exception("this is an example exception")
915

1016
def throwsExceptionMethod() {

src/test/scala/com/fortysevendeg/exercises/MethodEvalSpec.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,18 @@ class MethodEvalSpec extends FunSpec with Matchers {
4949
assert(res.toExecutionXor.isRight)
5050
}
5151

52-
/* TODO fix this
52+
it("fails with assertion error when the parameters are incorrect") {
53+
val res = methodEval.eval(
54+
"org.scalaexercises.runtime",
55+
"org.scalaexercises.runtime.ExampleTarget.isOne",
56+
"2" :: Nil
57+
)
58+
59+
res should matchPattern {
60+
case EvaluationException(_: TestFailedException)
61+
}
62+
}
63+
5364
it("captures exceptions thrown by the called method") {
5465
val res = methodEval.eval(
5566
"org.scalaexercises.runtime",
@@ -63,7 +74,6 @@ class MethodEvalSpec extends FunSpec with Matchers {
6374
assert(res.toSuccessXor.isLeft)
6475
assert(res.toExecutionXor.isRight)
6576
}
66-
*/
6777

6878
it("interprets imports properly") {
6979
val res = methodEval.eval(

0 commit comments

Comments
 (0)