Skip to content

Commit

Permalink
fix #8 simple 'hello world' scala module with tests on it; extract te…
Browse files Browse the repository at this point in the history
…st evaluator
  • Loading branch information
rockjam committed Nov 26, 2017
1 parent 7390f69 commit bd793cb
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 21 deletions.
3 changes: 3 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ trait MillModule extends ScalaModule{ outer =>
override def sources = basePath/'src/'main/'scala
object test extends this.Tests{
def basePath = outer.basePath
override def projectDeps =
if (this == Core.test) Seq(Core)
else Seq(outer, Core.test)
override def ivyDeps = Seq(Dep("com.lihaoyi", "utest", "0.6.0"))
override def sources = basePath/'src/'test/'scala
def testFramework = "mill.UTestFramework"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.collection._ // unused import to check unused imports warning

object Main extends App {
println("hello world")
val person = Person.fromString("rockjam:24")
println(s"hello ${person.name}, your age is: ${person.age}")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Person {
def fromString(s: String): Person = {
val Array(name, age) = s.split(":")
Person(name, age.toInt)
}
}
case class Person(name: String, age: Int)
24 changes: 3 additions & 21 deletions scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package mill.scalaplugin

import ammonite.ops.ImplicitWd._
import ammonite.ops._
import mill.define.{Cross, Target, Task}
import mill.define.{Cross,Task}
import mill.discover.Discovered
import mill.eval.{Evaluator, PathRef, Result}
import mill.modules.Jvm.jarUp
import mill.{Module, T}
import mill.util.OSet
import mill.eval.Result
import utest._
import mill.util.JsonFormatters._
object AcyclicBuild{
Expand Down Expand Up @@ -43,22 +40,7 @@ object AcyclicTests extends TestSuite{
mkdir(workspacePath/up)
cp(srcPath, workspacePath)
val mapping = Discovered.mapping(AcyclicBuild)
def eval[T](t: Task[T]): Either[Result.Failing, (T, Int)] = {
val evaluator = new Evaluator(workspacePath, mapping, _ => ())
val evaluated = evaluator.evaluate(OSet(t))

if (evaluated.failing.keyCount == 0){
Right(Tuple2(
evaluated.rawValues(0).asInstanceOf[Result.Success[T]].value,
evaluated.evaluated.collect{
case t: Target[_] if mapping.contains(t) => t
case t: mill.define.Command[_] => t
}.size
))
}else{
Left(evaluated.failing.lookupKey(evaluated.failing.keys().next).items.next())
}
}
def eval[T](t: Task[T]) = TestEvaluator.eval(mapping, workspacePath)(t)

// We can compile
val Right((pathRef, evalCount)) = eval(AcyclicBuild.acyclic("2.12.4").compile)
Expand Down
195 changes: 195 additions & 0 deletions scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package mill.scalaplugin

import ammonite.ops._
import mill._
import mill.define.{Target, Task}
import mill.discover.Discovered
import mill.discover.Mirror.LabelledTarget
import mill.eval.Result
import sbt.internal.inc.CompileFailed
import utest._

trait HelloWorldModule extends ScalaModule {
def scalaVersion = "2.12.4"
def basePath = HelloWorldTests.workspacePath
}

object HelloWorld extends HelloWorldModule

object HelloWorldWarnUnused extends HelloWorldModule {
override def scalacOptions = T(Seq("-Ywarn-unused"))
}

object HelloWorldFatalWarnings extends HelloWorldModule {
override def scalacOptions = T(Seq("-Ywarn-unused", "-Xfatal-warnings"))
}

object HelloWorldTests extends TestSuite {

val srcPath = pwd / 'scalaplugin / 'src / 'test / 'resource / "hello-world"
val workspacePath = pwd / 'target / 'workspace / "hello-world"
val mainObject = workspacePath / 'src / 'main / 'scala / "Main.scala"

def eval[T](t: Task[T], mapping: Map[Target[_], LabelledTarget[_]]) =
TestEvaluator.eval(mapping, workspacePath / 'out)(t)

def tests: Tests = Tests {
prepareWorkspace()
'scalaVersion - {
"from build" - {
val Right((result, evalCount)) =
eval(HelloWorld.scalaVersion, Discovered.mapping(HelloWorld))

assert(
result == "2.12.4",
evalCount > 0
)
}
"overriding" - {
object HelloWorldScalaOverride extends HelloWorldModule {
override def scalaVersion: Target[String] = "2.11.11"
}

val Right((result, evalCount)) =
eval(HelloWorldScalaOverride.scalaVersion,
Discovered.mapping(HelloWorldScalaOverride))

assert(
result == "2.11.11",
evalCount > 0
)
}
}
'scalacOptions - {
"empty by default" - {
val Right((result, evalCount)) =
eval(HelloWorld.scalacOptions, Discovered.mapping(HelloWorld))

assert(
result.isEmpty,
evalCount > 0
)
}
"overriding" - {
val Right((result, evalCount)) =
eval(HelloWorldFatalWarnings.scalacOptions,
Discovered.mapping(HelloWorldFatalWarnings))

assert(
result == Seq("-Ywarn-unused", "-Xfatal-warnings"),
evalCount > 0
)
}
}
'compile - {
"compile from scratch" - {
val Right((result, evalCount)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))

val outPath = result.path
val outputFiles = ls.rec(outPath)
assert(
outPath == workspacePath / 'out / 'compile / 'classes,
outputFiles.contains(outPath / "Main.class"),
outputFiles.contains(outPath / "Person.class"),
evalCount > 0
)
}
"don't recompile unchanged sources" - {
val Right((_, freshEvalCount)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))
assert(freshEvalCount > 0)

val Right((_, unchangedEvalCount)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))
assert(unchangedEvalCount == 0)
}
"compile incrementally" - {
val Right((_, freshCount)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))
assert(freshCount > 0)

write.append(mainObject, "\n")

val Right((_, incCompileCount)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))
assert(incCompileCount == 1)
}
"fail compilation on error" - {
write.append(mainObject, "val x: ")

val Left(Result.Exception(err)) =
eval(HelloWorld.compile, Discovered.mapping(HelloWorld))

assert(err.isInstanceOf[CompileFailed])
}
"pass scalacOptions on compilation" - {
// compilation fails because of "-Xfatal-warnings" flag
val Left(Result.Exception(err)) =
eval(HelloWorldFatalWarnings.compile,
Discovered.mapping(HelloWorldFatalWarnings))

assert(err.isInstanceOf[CompileFailed])
}
// TODO: not possible to reproduce in test because of classpath hash
// "recompile on build change" - {
// val Left(_) = eval(HelloWorldFatalWarnings.compile,
// Discovered.mapping(HelloWorldFatalWarnings))
//
// val Right((result, evalCount)) =
// eval(HelloWorldWarnUnused.compile,
// Discovered.mapping(HelloWorldWarnUnused))
//
// assert(
// result.path == workspacePath / 'out / 'compile / 'classes,
// evalCount > 0
// )
// }
}
'run - {
"run when Main object passed to args" - {
val Right((_, evalCount)) =
eval(HelloWorld.run("Main"), Discovered.mapping(HelloWorld))

assert(evalCount > 0)
}
"not run when invalid Main object not passed to args" - {
val Left(Result.Exception(err)) =
eval(HelloWorld.run("Invalid"), Discovered.mapping(HelloWorld))

assert(
err.isInstanceOf[InteractiveShelloutException]
)
}
"not run when sources doesn't compile" - {
write.append(mainObject, "val x: ")

val Left(Result.Exception(err)) =
eval(HelloWorld.run("Main"), Discovered.mapping(HelloWorld))

assert(
err.isInstanceOf[CompileFailed]
)
}
}
'jar - {
"produce jar file" - {
val Right((result, evalCount)) =
eval(HelloWorld.jar, Discovered.mapping(HelloWorld))

assert(
exists(result.path),
evalCount > 0
)
}
// TODO: check that we can `java -jar` produced jar
}
}

def prepareWorkspace(): Unit = {
rm(workspacePath)
mkdir(workspacePath / up)
cp(srcPath, workspacePath)
}

}
31 changes: 31 additions & 0 deletions scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package mill.scalaplugin

import ammonite.ops.Path
import mill.define.{Target, Task}
import mill.discover.Mirror
import mill.eval.{Evaluator, Result}
import mill.util.OSet

object TestEvaluator {

def eval[T](mapping: Map[Target[_], Mirror.LabelledTarget[_]], outPath: Path)(
t: Task[T]): Either[Result.Failing, (T, Int)] = {
val evaluator = new Evaluator(outPath, mapping, _ =>())
val evaluated = evaluator.evaluate(OSet(t))

if (evaluated.failing.keyCount == 0) {
Right(
Tuple2(
evaluated.rawValues.head.asInstanceOf[Result.Success[T]].value,
evaluated.evaluated.collect {
case t: Target[_] if mapping.contains(t) => t
case t: mill.define.Command[_] => t
}.size
))
} else {
Left(
evaluated.failing.lookupKey(evaluated.failing.keys().next).items.next())
}
}

}

0 comments on commit bd793cb

Please sign in to comment.