package forge
import forge.util.OSet
import utest._
import utest.framework.TestPath
object EvaluationTests extends TestSuite{
val tests = Tests{
val graphs = new TestGraphs()
import graphs._
'evaluateSingle - {
class Checker[T: Discovered](base: T)(implicit tp: TestPath) {
val workspace = ammonite.ops.pwd / 'target / 'workspace / tp.value
ammonite.ops.rm(ammonite.ops.Path(workspace, ammonite.ops.pwd))
// Make sure data is persisted even if we re-create the evaluator each time
def evaluator = new Evaluator(
workspace,
Discovered.mapping(base)
)
def apply(target: Target[_], expValue: Any,
expEvaled: OSet[Target[_]],
extraEvaled: Int = 0) = {
val Evaluator.Results(returnedValues, returnedEvaluated) = evaluator.evaluate(OSet(target))
val (matchingReturnedEvaled, extra) = returnedEvaluated.items.partition(expEvaled.contains)
assert(
returnedValues == Seq(expValue),
matchingReturnedEvaled.toSet == expEvaled.toSet,
extra.length == extraEvaled
)
// Second time the value is already cached, so no evaluation needed
val Evaluator.Results(returnedValues2, returnedEvaluated2) = evaluator.evaluate(OSet(target))
assert(
returnedValues2 == returnedValues,
returnedEvaluated2 == OSet()
)
}
}
'singleton - {
import singleton._
val check = new Checker(singleton)
// First time the target is evaluated
check(single, expValue = 0, expEvaled = OSet(single))
single.counter += 1
// After incrementing the counter, it forces re-evaluation
check(single, expValue = 1, expEvaled = OSet(single))
}
'pair - {
import pair._
val check = new Checker(pair)
check(down, expValue = 0, expEvaled = OSet(up, down))
down.counter += 1
check(down, expValue = 1, expEvaled = OSet(down))
up.counter += 1
check(down, expValue = 2, expEvaled = OSet(up, down))
}
'anonTriple - {
import anonTriple._
val check = new Checker(anonTriple)
val middle = down.inputs(0)
check(down, expValue = 0, expEvaled = OSet(up, middle, down))
down.counter += 1
check(down, expValue = 1, expEvaled = OSet(middle, down))
up.counter += 1
check(down, expValue = 2, expEvaled = OSet(up, middle, down))
middle.asInstanceOf[TestUtil.Test].counter += 1
check(down, expValue = 3, expEvaled = OSet(middle, down))
}
'diamond - {
import diamond._
val check = new Checker(diamond)
check(down, expValue = 0, expEvaled = OSet(up, left, right, down))
down.counter += 1
check(down, expValue = 1, expEvaled = OSet(down))
up.counter += 1
// Increment by 2 because up is referenced twice: once by left once by right
check(down, expValue = 3, expEvaled = OSet(up, left, right, down))
left.counter += 1
check(down, expValue = 4, expEvaled = OSet(left, down))
right.counter += 1
check(down, expValue = 5, expEvaled = OSet(right, down))
}
'anonDiamond - {
import anonDiamond._
val check = new Checker(anonDiamond)
val left = down.inputs(0).asInstanceOf[TestUtil.Test]
val right = down.inputs(1).asInstanceOf[TestUtil.Test]
check(down, expValue = 0, expEvaled = OSet(up, left, right, down))
down.counter += 1
check(down, expValue = 1, expEvaled = OSet(left, right, down))
up.counter += 1
// Increment by 2 because up is referenced twice: once by left once by right
check(down, expValue = 3, expEvaled = OSet(up, left, right, down))
left.counter += 1
check(down, expValue = 4, expEvaled = OSet(left, right, down))
right.counter += 1
check(down, expValue = 5, expEvaled = OSet(left, right, down))
}
'bigSingleTerminal - {
import bigSingleTerminal._
val check = new Checker(bigSingleTerminal)
check(j, expValue = 0, expEvaled = OSet(a, b, e, f, i, j), extraEvaled = 22)
j.counter += 1
check(j, expValue = 1, expEvaled = OSet(j), extraEvaled = 3)
i.counter += 1
// increment value by 2 because `i` is used twice on the way to `j`
check(j, expValue = 3, expEvaled = OSet(j, i), extraEvaled = 8)
b.counter += 1
// increment value by 4 because `b` is used four times on the way to `j`
check(j, expValue = 7, expEvaled = OSet(b, e, f, i, j), extraEvaled = 20)
}
}
}
}