summaryrefslogtreecommitdiff
path: root/main/test/src/define
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-12-12 16:56:02 -0800
committerGitHub <noreply@github.com>2018-12-12 16:56:02 -0800
commit9ba4cb69331386dfde9bac69dc2d5b22401face3 (patch)
tree120349e8015ae5717d36bd44209cde6ff9543518 /main/test/src/define
parentea7fceb6e56f53bde3517586dfc57e10a605a524 (diff)
downloadmill-9ba4cb69331386dfde9bac69dc2d5b22401face3.tar.gz
mill-9ba4cb69331386dfde9bac69dc2d5b22401face3.tar.bz2
mill-9ba4cb69331386dfde9bac69dc2d5b22401face3.zip
collapse boilerplate folder structure within src/ folders (#505)
* collapse boilerplate folder structure within src/ folders * .
Diffstat (limited to 'main/test/src/define')
-rw-r--r--main/test/src/define/ApplicativeTests.scala125
-rw-r--r--main/test/src/define/BasePathTests.scala73
-rw-r--r--main/test/src/define/CacherTests.scala75
-rw-r--r--main/test/src/define/DiscoverTests.scala63
-rw-r--r--main/test/src/define/GraphTests.scala211
-rw-r--r--main/test/src/define/MacroErrorTests.scala145
6 files changed, 692 insertions, 0 deletions
diff --git a/main/test/src/define/ApplicativeTests.scala b/main/test/src/define/ApplicativeTests.scala
new file mode 100644
index 00000000..9dd2132f
--- /dev/null
+++ b/main/test/src/define/ApplicativeTests.scala
@@ -0,0 +1,125 @@
+package mill.define
+
+import mill.api.Ctx.ImplicitStub
+import utest._
+
+import scala.annotation.compileTimeOnly
+import scala.language.experimental.macros
+
+
+object ApplicativeTests extends TestSuite {
+ implicit def optionToOpt[T](o: Option[T]): Opt[T] = new Opt(o)
+ class Opt[T](val self: Option[T]) extends Applicative.Applyable[Option, T]
+ object Opt extends OptGenerated with Applicative.Applyer[Opt, Option, Applicative.Id, String]{
+
+ val injectedCtx = "helloooo"
+ def underlying[A](v: Opt[A]) = v.self
+ def apply[T](t: T): Option[T] = macro Applicative.impl[Option, T, String]
+
+ def mapCtx[A, B](a: Option[A])(f: (A, String) => B): Option[B] = a.map(f(_, injectedCtx))
+ def zip() = Some(())
+ def zip[A](a: Option[A]) = a.map(Tuple1(_))
+ }
+ class Counter{
+ var value = 0
+ def apply() = {
+ value += 1
+ value
+ }
+ }
+ @compileTimeOnly("Target.ctx() can only be used with a T{...} block")
+ @ImplicitStub
+ implicit def taskCtx: String = ???
+
+ val tests = Tests{
+
+ 'selfContained - {
+
+ 'simple - assert(Opt("lol " + 1) == Some("lol 1"))
+ 'singleSome - assert(Opt("lol " + Some("hello")()) == Some("lol hello"))
+ 'twoSomes - assert(Opt(Some("lol ")() + Some("hello")()) == Some("lol hello"))
+ 'singleNone - assert(Opt("lol " + None()) == None)
+ 'twoNones - assert(Opt("lol " + None() + None()) == None)
+ }
+ 'context - {
+ assert(Opt(Opt.ctx() + Some("World")()) == Some("hellooooWorld"))
+ }
+ 'capturing - {
+ val lol = "lol "
+ def hell(o: String) = "hell" + o
+ 'simple - assert(Opt(lol + 1) == Some("lol 1"))
+ 'singleSome - assert(Opt(lol + Some(hell("o"))()) == Some("lol hello"))
+ 'twoSomes - assert(Opt(Some(lol)() + Some(hell("o"))()) == Some("lol hello"))
+ 'singleNone - assert(Opt(lol + None()) == None)
+ 'twoNones - assert(Opt(lol + None() + None()) == None)
+ }
+ 'allowedLocalDef - {
+ // Although x is defined inside the Opt{...} block, it is also defined
+ // within the LHS of the Applyable#apply call, so it is safe to life it
+ // out into the `zipMap` arguments list.
+ val res = Opt{ "lol " + Some("hello").flatMap(x => Some(x)).apply() }
+ assert(res == Some("lol hello"))
+ }
+ 'upstreamAlwaysEvaluated - {
+ // Whether or not control-flow reaches the Applyable#apply call inside an
+ // Opt{...} block, we always evaluate the LHS of the Applyable#apply
+ // because it gets lifted out of any control flow statements
+ val counter = new Counter()
+ def up = Opt{ "lol " + counter() }
+ val down = Opt{ if ("lol".length > 10) up() else "fail" }
+ assert(
+ down == Some("fail"),
+ counter.value == 1
+ )
+ }
+ 'upstreamEvaluatedOnlyOnce - {
+ // Even if control-flow reaches the Applyable#apply call more than once,
+ // it only gets evaluated once due to its lifting out of the Opt{...} block
+ val counter = new Counter()
+ def up = Opt{ "lol " + counter() }
+ def runTwice[T](t: => T) = (t, t)
+ val down = Opt{ runTwice(up()) }
+ assert(
+ down == Some(("lol 1", "lol 1")),
+ counter.value == 1
+ )
+ }
+ 'evaluationsInsideLambdasWork - {
+ // This required some fiddling with owner chains inside the macro to get
+ // working, so ensure it doesn't regress
+ val counter = new Counter()
+ def up = Opt{ "hello" + counter() }
+ val down1 = Opt{ (() => up())() }
+ val down2 = Opt{ Seq(1, 2, 3).map(n => up() * n) }
+ assert(
+ down1 == Some("hello1"),
+ down2 == Some(Seq("hello2", "hello2hello2", "hello2hello2hello2"))
+ )
+ }
+ 'appliesEvaluatedOncePerLexicalCallsite - {
+ // If you have multiple Applyable#apply() lexically in the source code of
+ // your Opt{...} call, each one gets evaluated once, even if the LHS of each
+ // apply() call is identical. It's up to the downstream zipMap()
+ // implementation to decide if it wants to dedup them or do other things.
+ val counter = new Counter()
+ def up = Opt{ "hello" + counter() }
+ val down = Opt{ Seq(1, 2, 3).map(n => n + up() + up()) }
+ assert(down == Some(Seq("1hello1hello2", "2hello1hello2", "3hello1hello2")))
+ }
+ 'appliesEvaluateBeforehand - {
+ // Every Applyable#apply() within a Opt{...} block evaluates before any
+ // other logic within that block, even if they would happen first in the
+ // normal Scala evaluation order
+ val counter = new Counter()
+ def up = Opt{ counter() }
+ val down = Opt{
+ val res = counter()
+ val one = up()
+ val two = up()
+ val three = up()
+ (res, one, two, three)
+ }
+ assert(down == Some((4, 1, 2, 3)))
+ }
+ }
+}
diff --git a/main/test/src/define/BasePathTests.scala b/main/test/src/define/BasePathTests.scala
new file mode 100644
index 00000000..b8a653c8
--- /dev/null
+++ b/main/test/src/define/BasePathTests.scala
@@ -0,0 +1,73 @@
+package mill.define
+
+import mill.util.{TestGraphs, TestUtil}
+import utest._
+import mill.{Module, T}
+object BasePathTests extends TestSuite{
+ val testGraphs = new TestGraphs
+ val tests = Tests{
+ def check[T <: Module](m: T)(f: T => Module, segments: String*) = {
+ val remaining = f(m).millSourcePath.relativeTo(m.millSourcePath).segments
+ assert(remaining == segments)
+ }
+ 'singleton - {
+ check(testGraphs.singleton)(identity)
+ }
+ 'backtickIdentifiers - {
+ check(testGraphs.bactickIdentifiers)(
+ _.`nested-module`,
+ "nested-module"
+ )
+ }
+ 'separateGroups - {
+ check(TestGraphs.triangleTask)(identity)
+ }
+ 'TraitWithModuleObject - {
+ check(TestGraphs.TraitWithModuleObject)(
+ _.TraitModule,
+ "TraitModule"
+ )
+ }
+ 'nestedModuleNested - {
+ check(TestGraphs.nestedModule)(_.nested, "nested")
+ }
+ 'nestedModuleInstance - {
+ check(TestGraphs.nestedModule)(_.classInstance, "classInstance")
+ }
+ 'singleCross - {
+ check(TestGraphs.singleCross)(_.cross, "cross")
+ check(TestGraphs.singleCross)(_.cross("210"), "cross", "210")
+ check(TestGraphs.singleCross)(_.cross("211"), "cross", "211")
+ }
+ 'doubleCross - {
+ check(TestGraphs.doubleCross)(_.cross, "cross")
+ check(TestGraphs.doubleCross)(_.cross("210", "jvm"), "cross", "210", "jvm")
+ check(TestGraphs.doubleCross)(_.cross("212", "js"), "cross", "212", "js")
+ }
+ 'nestedCrosses - {
+ check(TestGraphs.nestedCrosses)(_.cross, "cross")
+ check(TestGraphs.nestedCrosses)(
+ _.cross("210").cross2("js"),
+ "cross", "210", "cross2", "js"
+ )
+ }
+ 'overriden - {
+ object overridenBasePath extends TestUtil.BaseModule {
+ override def millSourcePath = os.pwd / 'overridenBasePathRootValue
+ object nested extends Module{
+ override def millSourcePath = super.millSourcePath / 'overridenBasePathNested
+ object nested extends Module{
+ override def millSourcePath = super.millSourcePath / 'overridenBasePathDoubleNested
+ }
+ }
+ }
+ assert(
+ overridenBasePath.millSourcePath == os.pwd / 'overridenBasePathRootValue,
+ overridenBasePath.nested.millSourcePath == os.pwd / 'overridenBasePathRootValue / 'nested / 'overridenBasePathNested,
+ overridenBasePath.nested.nested.millSourcePath == os.pwd / 'overridenBasePathRootValue / 'nested / 'overridenBasePathNested / 'nested / 'overridenBasePathDoubleNested
+ )
+ }
+
+ }
+}
+
diff --git a/main/test/src/define/CacherTests.scala b/main/test/src/define/CacherTests.scala
new file mode 100644
index 00000000..59ebf3f6
--- /dev/null
+++ b/main/test/src/define/CacherTests.scala
@@ -0,0 +1,75 @@
+package mill.define
+
+import mill.util.{DummyLogger, TestEvaluator, TestUtil}
+import mill.util.Strict.Agg
+import mill.T
+import mill.api.Result.Success
+import utest._
+import utest.framework.TestPath
+
+
+object CacherTests extends TestSuite{
+ object Base extends Base
+ trait Base extends TestUtil.BaseModule{
+ def value = T{ 1 }
+ def result = T{ Success(1) }
+ }
+ object Middle extends Middle
+ trait Middle extends Base{
+ override def value = T{ super.value() + 2}
+ def overriden = T{ super.value()}
+ }
+ object Terminal extends Terminal
+ trait Terminal extends Middle{
+ override def value = T{ super.value() + 4}
+ }
+
+ val tests = Tests{
+ def eval[T <: TestUtil.BaseModule, V](mapping: T, v: Task[V])
+ (implicit tp: TestPath) = {
+ val evaluator = new TestEvaluator(mapping)
+ evaluator(v).right.get._1
+ }
+ def check(x: Any, y: Any) = assert(x == y)
+
+ 'simpleDefIsCached - {
+ Predef.assert(Base.value eq Base.value)
+ Predef.assert(eval(Base, Base.value) == 1)
+ }
+
+ 'resultDefIsCached - {
+ Predef.assert(Base.result eq Base.result)
+ Predef.assert(eval(Base, Base.result) == 1)
+ }
+
+
+ 'overridingDefIsAlsoCached - {
+ Predef.assert(eval(Middle, Middle.value) == 3)
+ Predef.assert(Middle.value eq Middle.value)
+ }
+
+ 'overridenDefRemainsAvailable - {
+ Predef.assert(eval(Middle, Middle.overriden) == 1)
+ }
+
+
+ 'multipleOverridesWork- {
+ Predef.assert(eval(Terminal, Terminal.value) == 7)
+ Predef.assert(eval(Terminal, Terminal.overriden) == 1)
+ }
+ // Doesn't fail, presumably compileError doesn't go far enough in the
+ // compilation pipeline to hit the override checks
+ //
+ // 'overrideOutsideModuleFails - {
+ // compileError("""
+ // trait Foo{
+ // def x = 1
+ // }
+ // object Bar extends Foo{
+ // def x = 2
+ // }
+ // """)
+ // }
+ }
+}
+
diff --git a/main/test/src/define/DiscoverTests.scala b/main/test/src/define/DiscoverTests.scala
new file mode 100644
index 00000000..248d6afe
--- /dev/null
+++ b/main/test/src/define/DiscoverTests.scala
@@ -0,0 +1,63 @@
+package mill.define
+
+import mill.util.TestGraphs
+import utest._
+
+object DiscoverTests extends TestSuite{
+ val testGraphs = new TestGraphs
+ val tests = Tests{
+ def check[T <: Module](m: T)(targets: (T => Target[_])*) = {
+ val discovered = m.millInternal.targets
+ val expected = targets.map(_(m)).toSet
+ assert(discovered == expected)
+ }
+ 'singleton - {
+ check(testGraphs.singleton)(_.single)
+ }
+ 'backtickIdentifiers {
+ check(testGraphs.bactickIdentifiers)(_.`up-target`, _.`a-down-target`, _.`nested-module`.`nested-target`)
+ }
+ 'separateGroups - {
+ check(TestGraphs.triangleTask)(_.left, _.right)
+ }
+ 'TraitWithModuleObject - {
+ check(TestGraphs.TraitWithModuleObject)(_.TraitModule.testFrameworks)
+ }
+ 'nestedModule - {
+ check(TestGraphs.nestedModule)(_.single, _.nested.single, _.classInstance.single)
+ }
+ 'singleCross - {
+ check(TestGraphs.singleCross)(
+ _.cross("210").suffix,
+ _.cross("211").suffix,
+ _.cross("212").suffix
+ )
+ }
+ 'doubleCross - {
+ check(TestGraphs.doubleCross)(
+ _.cross("210", "jvm").suffix,
+ _.cross("210", "js").suffix,
+ _.cross("211", "jvm").suffix,
+ _.cross("211", "js").suffix,
+ _.cross("212", "jvm").suffix,
+ _.cross("212", "js").suffix,
+ _.cross("212", "native").suffix
+ )
+ }
+ 'nestedCrosses - {
+ check(TestGraphs.nestedCrosses)(
+ _.cross("210").cross2("jvm").suffix,
+ _.cross("210").cross2("js").suffix,
+ _.cross("210").cross2("native").suffix,
+ _.cross("211").cross2("jvm").suffix,
+ _.cross("211").cross2("js").suffix,
+ _.cross("211").cross2("native").suffix,
+ _.cross("212").cross2("jvm").suffix,
+ _.cross("212").cross2("js").suffix,
+ _.cross("212").cross2("native").suffix
+ )
+ }
+
+ }
+}
+
diff --git a/main/test/src/define/GraphTests.scala b/main/test/src/define/GraphTests.scala
new file mode 100644
index 00000000..224ce59f
--- /dev/null
+++ b/main/test/src/define/GraphTests.scala
@@ -0,0 +1,211 @@
+package mill.define
+
+
+import mill.eval.Evaluator
+import mill.util.{TestGraphs, TestUtil}
+import utest._
+import mill.util.Strict.Agg
+object GraphTests extends TestSuite{
+
+ val tests = Tests{
+
+
+ val graphs = new TestGraphs()
+ import graphs._
+ import TestGraphs._
+
+ 'topoSortedTransitiveTargets - {
+ def check(targets: Agg[Task[_]], expected: Agg[Task[_]]) = {
+ val result = Graph.topoSorted(Graph.transitiveTargets(targets)).values
+ TestUtil.checkTopological(result)
+ assert(result == expected)
+ }
+
+ 'singleton - check(
+ targets = Agg(singleton.single),
+ expected = Agg(singleton.single)
+ )
+ 'backtickIdentifiers - check(
+ targets = Agg(bactickIdentifiers.`a-down-target`),
+ expected = Agg(bactickIdentifiers.`up-target`, bactickIdentifiers.`a-down-target`)
+ )
+ 'pair - check(
+ targets = Agg(pair.down),
+ expected = Agg(pair.up, pair.down)
+ )
+ 'anonTriple - check(
+ targets = Agg(anonTriple.down),
+ expected = Agg(anonTriple.up, anonTriple.down.inputs(0), anonTriple.down)
+ )
+ 'diamond - check(
+ targets = Agg(diamond.down),
+ expected = Agg(diamond.up, diamond.left, diamond.right, diamond.down)
+ )
+ 'anonDiamond - check(
+ targets = Agg(diamond.down),
+ expected = Agg(
+ diamond.up,
+ diamond.down.inputs(0),
+ diamond.down.inputs(1),
+ diamond.down
+ )
+ )
+ 'defCachedDiamond - check(
+ targets = Agg(defCachedDiamond.down),
+ expected = Agg(
+ defCachedDiamond.up.inputs(0),
+ defCachedDiamond.up,
+ defCachedDiamond.down.inputs(0).inputs(0).inputs(0),
+ defCachedDiamond.down.inputs(0).inputs(0),
+ defCachedDiamond.down.inputs(0).inputs(1).inputs(0),
+ defCachedDiamond.down.inputs(0).inputs(1),
+ defCachedDiamond.down.inputs(0),
+ defCachedDiamond.down
+ )
+ )
+ 'bigSingleTerminal - {
+ val result = Graph.topoSorted(Graph.transitiveTargets(Agg(bigSingleTerminal.j))).values
+ TestUtil.checkTopological(result)
+ assert(result.size == 28)
+ }
+ }
+
+ 'groupAroundNamedTargets - {
+ def check[T, R <: Target[Int]](base: T)
+ (target: T => R,
+ important0: Agg[T => Target[_]],
+ expected: Agg[(R, Int)]) = {
+
+ val topoSorted = Graph.topoSorted(Graph.transitiveTargets(Agg(target(base))))
+
+ val important = important0.map(_ (base))
+ val grouped = Graph.groupAroundImportantTargets(topoSorted) {
+ case t: Target[_] if important.contains(t) => t
+ }
+ val flattened = Agg.from(grouped.values().flatMap(_.items))
+
+ TestUtil.checkTopological(flattened)
+ for ((terminal, expectedSize) <- expected) {
+ val grouping = grouped.lookupKey(terminal)
+ assert(
+ grouping.size == expectedSize,
+ grouping.flatMap(_.asTarget: Option[Target[_]]).filter(important.contains) == Agg(terminal)
+ )
+ }
+ }
+
+ 'singleton - check(singleton)(
+ _.single,
+ Agg(_.single),
+ Agg(singleton.single -> 1)
+ )
+ 'backtickIdentifiers - check(bactickIdentifiers)(
+ _.`a-down-target`,
+ Agg(_.`up-target`, _.`a-down-target`),
+ Agg(
+ bactickIdentifiers.`up-target` -> 1,
+ bactickIdentifiers.`a-down-target` -> 1
+ )
+ )
+ 'pair - check(pair)(
+ _.down,
+ Agg(_.up, _.down),
+ Agg(pair.up -> 1, pair.down -> 1)
+ )
+ 'anonTriple - check(anonTriple)(
+ _.down,
+ Agg(_.up, _.down),
+ Agg(anonTriple.up -> 1, anonTriple.down -> 2)
+ )
+ 'diamond - check(diamond)(
+ _.down,
+ Agg(_.up, _.left, _.right, _.down),
+ Agg(
+ diamond.up -> 1,
+ diamond.left -> 1,
+ diamond.right -> 1,
+ diamond.down -> 1
+ )
+ )
+
+ 'defCachedDiamond - check(defCachedDiamond)(
+ _.down,
+ Agg(_.up, _.left, _.right, _.down),
+ Agg(
+ defCachedDiamond.up -> 2,
+ defCachedDiamond.left -> 2,
+ defCachedDiamond.right -> 2,
+ defCachedDiamond.down -> 2
+ )
+ )
+
+ 'anonDiamond - check(anonDiamond)(
+ _.down,
+ Agg(_.down, _.up),
+ Agg(
+ anonDiamond.up -> 1,
+ anonDiamond.down -> 3
+ )
+ )
+ 'bigSingleTerminal - check(bigSingleTerminal)(
+ _.j,
+ Agg(_.a, _.b, _.e, _.f, _.i, _.j),
+ Agg(
+ bigSingleTerminal.a -> 3,
+ bigSingleTerminal.b -> 2,
+ bigSingleTerminal.e -> 9,
+ bigSingleTerminal.i -> 6,
+ bigSingleTerminal.f -> 4,
+ bigSingleTerminal.j -> 4
+ )
+ )
+ }
+ 'multiTerminalGroupCounts - {
+ def countGroups(goals: Task[_]*) = {
+
+ val topoSorted = Graph.topoSorted(
+ Graph.transitiveTargets(Agg.from(goals))
+ )
+ val grouped = Graph.groupAroundImportantTargets(topoSorted) {
+ case t: NamedTask[Any] => t
+ case t if goals.contains(t) => t
+ }
+ grouped.keyCount
+ }
+
+ 'separateGroups - {
+ import separateGroups._
+ val groupCount = countGroups(right, left)
+ assert(groupCount == 3)
+ }
+
+ 'triangleTask - {
+ // Make sure the following graph ends up as a single group, since although
+ // `right` depends on `left`, both of them depend on the un-cached `task`
+ // which would force them both to re-compute every time `task` changes
+ import triangleTask._
+ val groupCount = countGroups(right, left)
+ assert(groupCount == 2)
+ }
+
+
+ 'multiTerminalGroup - {
+ // Make sure the following graph ends up as two groups
+ import multiTerminalGroup._
+ val groupCount = countGroups(right, left)
+ assert(groupCount == 2)
+ }
+
+
+ 'multiTerminalBoundary - {
+ // Make sure the following graph ends up as a three groups: one for
+ // each cached target, and one for the downstream task we are running
+ import multiTerminalBoundary._
+ val groupCount = countGroups(task2)
+ assert(groupCount == 3)
+ }
+ }
+
+
+ }
+}
diff --git a/main/test/src/define/MacroErrorTests.scala b/main/test/src/define/MacroErrorTests.scala
new file mode 100644
index 00000000..c8b140fa
--- /dev/null
+++ b/main/test/src/define/MacroErrorTests.scala
@@ -0,0 +1,145 @@
+package mill.define
+
+import utest._
+import mill.{T, Module}
+import mill.util.TestUtil
+object MacroErrorTests extends TestSuite{
+
+ val tests = Tests{
+
+ 'errors{
+ val expectedMsg =
+ "T{} members must be defs defined in a Cacher class/trait/object body"
+
+ val err = compileError("object Foo extends TestUtil.BaseModule{ val x = T{1} }")
+ assert(err.msg == expectedMsg)
+ }
+
+ 'badParameterSets - {
+ 'command - {
+ val e = compileError("""
+ object foo extends mill.util.TestUtil.BaseModule{
+ def w = T.command{1}
+ }
+ mill.define.Discover[foo.type]
+ """)
+ assert(
+ e.msg.contains("`T.command` definitions must have 1 parameter list"),
+ e.pos.contains("def w = ")
+ )
+ }
+ 'target - {
+ val e = compileError("""
+ object foo extends mill.util.TestUtil.BaseModule{
+ def x() = T{1}
+ }
+ mill.define.Discover[foo.type]
+ """)
+ assert(
+ e.msg.contains("`T{...}` definitions must have 0 parameter lists"),
+ e.pos.contains("def x() = ")
+ )
+ }
+ 'input - {
+ val e = compileError("""
+ object foo extends mill.util.TestUtil.BaseModule{
+ def y() = T.input{1}
+ }
+ mill.define.Discover[foo.type]
+ """)
+ assert(
+ e.msg.contains("`T.input` definitions must have 0 parameter lists"),
+ e.pos.contains("def y() = ")
+ )
+ }
+ 'sources - {
+ val e = compileError("""
+ object foo extends mill.util.TestUtil.BaseModule{
+ def z() = T.sources{ammonite.ops.pwd}
+ }
+ mill.define.Discover[foo.type]
+ """)
+ assert(
+ e.msg.contains("`T.sources` definitions must have 0 parameter lists"),
+ e.pos.contains("def z() = ")
+ )
+ }
+ 'persistent - {
+ val e = compileError("""
+ object foo extends mill.util.TestUtil.BaseModule{
+ def a() = T.persistent{1}
+ }
+ mill.define.Discover[foo.type]
+ """)
+ assert(
+ e.msg.contains("`T.persistent` definitions must have 0 parameter lists"),
+ e.pos.contains("def a() = ")
+ )
+ }
+ }
+ 'badTmacro - {
+ // Make sure we can reference values from outside the T{...} block as part
+ // of our `Target#apply()` calls, but we cannot reference any values that
+ // come from inside the T{...} block
+ 'pos - {
+ val e = compileError("""
+ val a = T{ 1 }
+ val arr = Array(a)
+ val b = {
+ val c = 0
+ T{
+ arr(c)()
+ }
+ }
+ """)
+ assert(e.msg.contains(
+ "Modules, Targets and Commands can only be defined within a mill Module")
+ )
+ }
+ 'neg - {
+
+ val expectedMsg =
+ "Target#apply() call cannot use `value n` defined within the T{...} block"
+ val err = compileError("""new Module{
+ def a = T{ 1 }
+ val arr = Array(a)
+ def b = {
+ T{
+ val n = 0
+ arr(n)()
+ }
+ }
+ }""")
+ assert(err.msg == expectedMsg)
+ }
+ 'neg2 - {
+
+ val expectedMsg =
+ "Target#apply() call cannot use `value x` defined within the T{...} block"
+ val err = compileError("""new Module{
+ def a = T{ 1 }
+ val arr = Array(a)
+ def b = {
+ T{
+ arr.map{x => x()}
+ }
+ }
+ }""")
+ assert(err.msg == expectedMsg)
+ }
+ 'neg3{
+ val borkedCachedDiamond1 = utest.compileError("""
+ object borkedCachedDiamond1 {
+ def up = T{ TestUtil.test() }
+ def left = T{ TestUtil.test(up) }
+ def right = T{ TestUtil.test(up) }
+ def down = T{ TestUtil.test(left, right) }
+ }
+ """)
+ assert(borkedCachedDiamond1.msg.contains(
+ "Modules, Targets and Commands can only be defined within a mill Module")
+ )
+ }
+ }
+ }
+}