summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-10-24 22:44:50 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-10-24 22:44:50 -0700
commit8175b657bd5d008db67fc5d4f28e8463acb8d1ad (patch)
tree5c1f4763bea20b356459c4434b0befa67ce85397 /src/test
parent6f3b2bd9a769b3a47414b6d9c43c99afe3d4460b (diff)
downloadmill-8175b657bd5d008db67fc5d4f28e8463acb8d1ad.tar.gz
mill-8175b657bd5d008db67fc5d4f28e8463acb8d1ad.tar.bz2
mill-8175b657bd5d008db67fc5d4f28e8463acb8d1ad.zip
Macro-based anonymous `Target` naming now works: we use the `T{...}` macro look at any `Target`s defined lexically within the call, and as long as they can only be evaluated once (relative to the `T{...}`) we assign them labels with an incrementing integer suffixed onto the enclosing `T{...}`s label
Diffstat (limited to 'src/test')
-rw-r--r--src/test/scala/forge/ForgeTests.scala143
1 files changed, 118 insertions, 25 deletions
diff --git a/src/test/scala/forge/ForgeTests.scala b/src/test/scala/forge/ForgeTests.scala
index d5275d0c..cf903461 100644
--- a/src/test/scala/forge/ForgeTests.scala
+++ b/src/test/scala/forge/ForgeTests.scala
@@ -6,7 +6,8 @@ import java.nio.{file => jnio}
object ForgeTests extends TestSuite{
val tests = Tests{
- val evaluator = new Evaluator(jnio.Paths.get("target/workspace"), implicitly)
+ val baseCtx = DefCtx("forge.ForgeTests.tests ")
+ val evaluator = new Evaluator(jnio.Paths.get("target/workspace"), baseCtx)
object Singleton {
val single = T{ test() }
}
@@ -30,11 +31,69 @@ object ForgeTests extends TestSuite{
val down = T{ test(test(up), test(up)) }
}
- 'neg - {
- compileError("T{ 123 }")
- compileError("T{ println() }")
- ()
+
+ 'syntaxLimits - {
+ // Make sure that we properly prohibit cases where a `test()` target can
+ // be created more than once with the same `DefCtx`, while still allowing
+ // cases where the `test()` target is created exactly one time, or even
+ // zero-or-one times (since that's ok, as long as it's not more than once)
+
+ 'neg - {
+ 'nakedTest - {
+ compileError("test()")
+ ()
+ }
+ 'notFunctionCall - {
+ compileError("T{ 123 }")
+ ()
+ }
+ 'functionCallWithoutImplicit - {
+ compileError("T{ println() }")
+ ()
+ }
+ // Make sure the snippets without `test()`s compile, but the same snippets
+ // *with* the `test()` calls do not (presumably due to the `@compileTimeOnly`
+ // annotation)
+ //
+ // For some reason, `if(false)` isn't good enough because scalac constant
+ // folds the conditional, eliminates the entire code block, and makes any
+ // `@compileTimeOnly`s annotations disappear...
+
+
+ 'canEvaluateMoreThanOnce - {
+ if (math.random() > 10) T{ Seq(1, 2).map(_ => ???); test() }
+ compileError("T{ Seq(1, 2).map(_ => test()); test() }")
+
+ if (math.random() > 10) T{ class Foo{ ??? }; test() }
+ compileError("T{ class Foo{ test() }; test() }")
+
+ if (math.random() > 10) T{ test({while(true){ }; ???}) }
+ compileError("T{ test({while(true){ test() }; ???}) }")
+
+ if (math.random() > 10) T{ do{ } while(true); test() }
+ compileError("T{ do{ test() } while(true); test() }")
+
+ if (math.random() > 10) T{ def foo() = ???; test() }
+ compileError("T{ def foo() = test(); test() }")
+
+ if (math.random() > 10) T{ None.getOrElse(???); test() }
+ if (math.random() > 10) T{ None.contains(test()); test() }
+ compileError("T{ None.getOrElse(test()); test() }")
+
+ ()
+ }
+ }
+ 'pos - {
+ T{ test({val x = test(); x}) }
+ T{ test({lazy val x = test(); x}) }
+ T { object foo {val x = test()}; test(foo.x) }
+ T{ test({val x = if (math.random() > 0.5) test() else test(); x}) }
+
+ ()
+ }
}
+
+
'topoSortedTransitiveTargets - {
def check(targets: Seq[Target[_]], expected: Seq[Target[_]]) = {
val result = Evaluator.topoSortedTransitiveTargets(targets)
@@ -67,55 +126,89 @@ object ForgeTests extends TestSuite{
)
)
}
+ 'labeling - {
+
+ def check(t: Target[_], relPath: String) = {
+ val targetLabel = t.defCtx.label
+ val expectedLabel = baseCtx.label + relPath
+ assert(targetLabel == expectedLabel)
+ }
+ 'singleton - check(Singleton.single, "Singleton.single")
+ 'pair - {
+ check(Pair.up, "Pair.up")
+ check(Pair.down, "Pair.down")
+ }
+
+ 'anonTriple - {
+ check(AnonTriple.up, "AnonTriple.up")
+ check(AnonTriple.down.inputs(0), "AnonTriple.down1")
+ check(AnonTriple.down, "AnonTriple.down")
+ }
+
+ 'diamond - {
+ check(Diamond.up, "Diamond.up")
+ check(Diamond.left, "Diamond.left")
+ check(Diamond.right, "Diamond.right")
+ check(Diamond.down, "Diamond.down")
+ }
+
+ 'anonDiamond - {
+ check(AnonDiamond.up, "AnonDiamond.up")
+ check(AnonDiamond.down.inputs(0), "AnonDiamond.down1")
+ check(AnonDiamond.down.inputs(1), "AnonDiamond.down2")
+ check(AnonDiamond.down, "AnonDiamond.down")
+ }
+
+ }
'evaluate - {
def check(targets: Seq[Target[_]],
- values: Seq[Any],
- evaluated: Seq[Target[_]]) = {
+ expectedValues: Seq[Any],
+ expectedEvaluated: Seq[Target[_]]) = {
val Evaluator.Results(returnedValues, returnedEvaluated) = evaluator.evaluate(targets)
assert(
- returnedValues == values,
- returnedEvaluated == evaluated
+ returnedValues == expectedValues,
+ returnedEvaluated == expectedEvaluated
)
}
'singleton - {
import Singleton._
// First time the target is evaluated
- check(Seq(single), values = Seq(0), evaluated = Seq(single))
+ check(Seq(single), expectedValues = Seq(0), expectedEvaluated = Seq(single))
// Second time the value is already cached, so no evaluation needed
- check(Seq(single), values = Seq(0), evaluated = Seq())
+ check(Seq(single), expectedValues = Seq(0), expectedEvaluated = Seq())
single.counter += 1
// After incrementing the counter, it forces re-evaluation
- check(Seq(single), values = Seq(1), evaluated = Seq(single))
+ check(Seq(single), expectedValues = Seq(1), expectedEvaluated = Seq(single))
// Then it's cached again
- check(Seq(single), values = Seq(1), evaluated = Seq())
+ check(Seq(single), expectedValues = Seq(1), expectedEvaluated = Seq())
}
'pair - {
import Pair._
- check(Seq(down), values = Seq(0), evaluated = Seq(up, down))
- check(Seq(down), values = Seq(0), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(0), expectedEvaluated = Seq(up, down))
+ check(Seq(down), expectedValues = Seq(0), expectedEvaluated = Seq())
down.counter += 1
- check(Seq(down), values = Seq(1), evaluated = Seq(down))
- check(Seq(down), values = Seq(1), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(1), expectedEvaluated = Seq(down))
+ check(Seq(down), expectedValues = Seq(1), expectedEvaluated = Seq())
up.counter += 1
- check(Seq(down), values = Seq(2), evaluated = Seq(up, down))
- check(Seq(down), values = Seq(2), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(2), expectedEvaluated = Seq(up, down))
+ check(Seq(down), expectedValues = Seq(2), expectedEvaluated = Seq())
}
'anonTriple - {
import AnonTriple._
val middle = down.inputs(0)
- check(Seq(down), values = Seq(0), evaluated = Seq(up, middle, down))
- check(Seq(down), values = Seq(0), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(0), expectedEvaluated = Seq(up, middle, down))
+ check(Seq(down), expectedValues = Seq(0), expectedEvaluated = Seq())
down.counter += 1
- check(Seq(down), values = Seq(1), evaluated = Seq(middle, down))
- check(Seq(down), values = Seq(1), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(1), expectedEvaluated = Seq(down))
+ check(Seq(down), expectedValues = Seq(1), expectedEvaluated = Seq())
up.counter += 1
- check(Seq(down), values = Seq(2), evaluated = Seq(up, middle, down))
- check(Seq(down), values = Seq(2), evaluated = Seq())
+ check(Seq(down), expectedValues = Seq(2), expectedEvaluated = Seq(up, middle, down))
+ check(Seq(down), expectedValues = Seq(2), expectedEvaluated = Seq())
}
}