Skip to content

Zinc based testQuick command #4787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions core/define/src/mill/define/Task.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,13 @@ object Task extends TaskBase {
inline def Command[T](inline t: Result[T])(implicit
inline w: W[T],
inline ctx: mill.define.ModuleCtx
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }) }
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }, '{ false }) }

inline def Command[T](persistent: Boolean)(inline t: Result[T])(implicit
inline w: W[T],
inline ctx: mill.define.ModuleCtx
): Command[T] =
${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }, '{ persistent }) }

/**
* @param exclusive Exclusive commands run serially at the end of an evaluation,
Expand Down Expand Up @@ -394,7 +400,8 @@ class Command[+T](
val ctx0: mill.define.ModuleCtx,
val writer: W[?],
val isPrivate: Option[Boolean],
val exclusive: Boolean
val exclusive: Boolean,
override val persistent: Boolean
) extends NamedTask[T] {

override def asCommand: Some[Command[T]] = Some(this)
Expand Down Expand Up @@ -546,7 +553,15 @@ private object TaskMacros {
appImpl[Command, T](
(in, ev) =>
'{
new Command[T]($in, $ev, $ctx, $w, ${ taskIsPrivate() }, exclusive = $exclusive)
new Command[T](
$in,
$ev,
$ctx,
$w,
${ taskIsPrivate() },
exclusive = $exclusive,
persistent = $persistent
)
},
t
)
Expand Down
24 changes: 24 additions & 0 deletions integration/feature/test-quick/resources/app/src/MyNumber.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package app

import lib.*

final case class MyNumber(val value: Int)

object MyNumber {

given gCombinator: Combinator[MyNumber] = new Combinator[MyNumber] {
def combine(a: MyNumber, b: MyNumber): MyNumber = MyNumber(a.value + b.value)
}

given gDefaultValue: DefaultValue[MyNumber] = new DefaultValue[MyNumber] {
def defaultValue: MyNumber = MyNumber(0)
}

def combine(a: MyNumber, b: MyNumber, c: MyNumber): MyNumber = {
val temp = gCombinator.combine(a, b)
gCombinator.combine(temp, c)
}

def defaultValue: MyNumber = gDefaultValue.defaultValue

}
24 changes: 24 additions & 0 deletions integration/feature/test-quick/resources/app/src/MyString.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package app

import lib.*

final case class MyString(val value: String)

object MyString {

given gCombinator: Combinator[MyString] = new Combinator[MyString] {
def combine(a: MyString, b: MyString): MyString = MyString(a.value + b.value)
}

given gDefaultValue: DefaultValue[MyString] = new DefaultValue[MyString] {
def defaultValue: MyString = MyString("")
}

def combine(a: MyString, b: MyString, c: MyString): MyString = {
val temp = gCombinator.combine(a, b)
gCombinator.combine(temp, c)
}

def defaultValue: MyString = gDefaultValue.defaultValue

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app

import utest.*
import app.MyNumber

object MyNumberCombinatorTests extends TestSuite {
def tests = Tests {
test("simple") {
val a = MyNumber(1)
val b = MyNumber(2)
val c = MyNumber(3)
val result = MyNumber.combine(a, b, c)
assert(result == MyNumber(6))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app

import utest.*
import app.MyNumber

object MyNumberDefaultValueTests extends TestSuite {
def tests = Tests {
test("simple") {
val result = MyNumber.defaultValue
assert(result == MyNumber(0))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app

import utest.*
import app.MyString

object MyStringCombinatorTests extends TestSuite {
def tests = Tests {
test("simple") {
val a = MyString("a")
val b = MyString("b")
val c = MyString("c")
val result = MyString.combine(a, b, c)
assert(result == MyString("abc"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app

import utest.*
import app.MyString

object MyStringDefaultValueTests extends TestSuite {
def tests = Tests {
test("simple") {
val result = MyString.defaultValue
assert(result == MyString(""))
}
}
}
18 changes: 18 additions & 0 deletions integration/feature/test-quick/resources/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package build

import mill._, scalalib._

object lib extends ScalaModule {
def scalaVersion = "3.3.1"
}

object app extends ScalaModule {
def scalaVersion = "3.3.1"
def moduleDeps = Seq(lib)

object test extends ScalaTests {
def ivyDeps = Seq(ivy"com.lihaoyi::utest:0.8.5")
def testFramework = "utest.runner.Framework"
def moduleDeps = Seq(app)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lib

trait Combinator[T] {
def combine(a: T, b: T): T
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lib

trait DefaultValue[T] {
def defaultValue: T
}
115 changes: 115 additions & 0 deletions integration/feature/test-quick/src/TestQuickTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package mill.integration

import mill.testkit.UtestIntegrationTestSuite

import utest._

object TestQuickTests extends UtestIntegrationTestSuite {
val tests: Tests = Tests {
test("update app file") - integrationTest { tester =>
import tester._

// First run, all tests should run
val firstRun = eval("app.test.testQuick")
val firstRunOutLines = firstRun.out.linesIterator.toSeq
Seq(
"app.MyNumberCombinatorTests.simple",
"app.MyStringCombinatorTests.simple",
"app.MyStringDefaultValueTests.simple",
"app.MyNumberDefaultValueTests.simple"
).foreach { expectedLines =>
val exists = firstRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Second run, nothing should run because we're not changing anything
val secondRun = eval("app.test.testQuick")
assert(secondRun.out.isEmpty)

// Third run, MyNumber.scala changed, so MyNumberDefaultValueTests & MyNumberCombinatorTests should run
modifyFile(
workspacePath / "app" / "src" / "MyNumber.scala",
_.replace(
"def defaultValue: MyNumber = MyNumber(0)",
"def defaultValue: MyNumber = MyNumber(1)"
)
)
val thirdRun = eval("app.test.testQuick")
val thirdRunOutLines = thirdRun.out.linesIterator.toSeq
Seq(
"app.MyNumberCombinatorTests.simple",
"app.MyNumberDefaultValueTests.simple"
).foreach { expectedLines =>
val exists = thirdRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Fourth run, MyNumberDefaultValueTests was failed, so it should run again
val fourthRun = eval("app.test.testQuick")
val fourthRunOutLines = fourthRun.out.linesIterator.toSeq
Seq(
"app.MyNumberDefaultValueTests.simple"
).foreach { expectedLines =>
val exists = fourthRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Fifth run, MyNumberDefaultValueTests was fixed, so it should run again
modifyFile(
workspacePath / "app" / "test" / "src" / "MyNumberDefaultValueTests.scala",
_.replace("assert(result == MyNumber(0))", "assert(result == MyNumber(1))")
)
val fifthRun = eval("app.test.testQuick")
val fifthRunOutLines = fifthRun.out.linesIterator.toSeq
Seq(
"app.MyNumberDefaultValueTests.simple"
).foreach { expectedLines =>
val exists = fifthRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Sixth run, nothing should run because we're not changing anything
val sixthRun = eval("app.test.testQuick")
assert(sixthRun.out.isEmpty)
}
test("update lib file") - integrationTest { tester =>
import tester._

// First run, all tests should run
val firstRun = eval("app.test.testQuick")
val firstRunOutLines = firstRun.out.linesIterator.toSeq
Seq(
"app.MyNumberCombinatorTests.simple",
"app.MyStringCombinatorTests.simple",
"app.MyStringDefaultValueTests.simple",
"app.MyNumberDefaultValueTests.simple"
).foreach { expectedLines =>
val exists = firstRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Second run, nothing should run because we're not changing anything
val secondRun = eval("app.test.testQuick")
assert(secondRun.out.isEmpty)

// Third run, Combinator.scala changed, so MyNumberCombinatorTests & MyStringCombinatorTests should run
modifyFile(
workspacePath / "lib" / "src" / "Combinator.scala",
_.replace("def combine(a: T, b: T): T", "def combine(b: T, a: T): T")
)
val thirdRun = eval("app.test.testQuick")
val thirdRunOutLines = thirdRun.out.linesIterator.toSeq
Seq(
"app.MyNumberCombinatorTests.simple",
"app.MyStringCombinatorTests.simple"
).foreach { expectedLines =>
val exists = thirdRunOutLines.exists(_.contains(expectedLines))
assert(exists)
}

// Fourth run, nothing should run because we're not changing anything
val fourthRun = eval("app.test.testQuick")
assert(fourthRun.out.isEmpty)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mill.scalalib.api

final case class TransitiveSourceStampResults(
currentStamps: Map[String, String],
previousStamps: Option[Map[String, String]] = None
) {
lazy val changedSources: Set[String] = {
previousStamps match {
case Some(prevStamps) =>
currentStamps.view
.flatMap { (source, stamp) =>
prevStamps.get(source) match {
case None => Some(source) // new source
case Some(prevStamp) => Option.when(stamp != prevStamp)(source) // changed source
}
}
.toSet
case None => currentStamps.keySet
}
}
}

object TransitiveSourceStampResults {
implicit val jsonFormatter: upickle.default.ReadWriter[TransitiveSourceStampResults] =
upickle.default.macroRW
}
3 changes: 2 additions & 1 deletion scalalib/package.mill
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ object `package` extends RootModule with build.MillStableScalaModule {
// (also transitively included by com.eed3si9n.jarjarabrams:jarjar-abrams-core)
// perhaps the class can be copied here?
Agg(build.Deps.scalaReflect(scalaVersion()))
}
} ++
Agg(build.Deps.zinc)
}
def testIvyDeps = super.testIvyDeps() ++ Agg(build.Deps.TestDeps.scalaCheck)
def testTransitiveDeps =
Expand Down
Loading