-
-
Notifications
You must be signed in to change notification settings - Fork 354
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix #8 simple 'hello world' scala module with tests on it; extract te…
…st evaluator
- Loading branch information
Showing
6 changed files
with
246 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
scalaplugin/src/test/resource/hello-world/src/main/scala/Main.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}") | ||
} |
7 changes: 7 additions & 0 deletions
7
scalaplugin/src/test/resource/hello-world/src/main/scala/Result.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
195 changes: 195 additions & 0 deletions
195
scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
31
scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | ||
} | ||
} | ||
|
||
} |