summaryrefslogtreecommitdiff
path: root/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala
blob: 185cffc8138afa6d71699e0bd1f30389e69e8ac7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package mill.scalaplugin

import ammonite.ops.ImplicitWd._
import ammonite.ops._
import mill.define.{Cross,Task}
import mill.discover.Discovered
import mill.eval.Result
import utest._
import mill.util.JsonFormatters._
object AcyclicBuild{
  val acyclic =
    for(crossVersion <- Cross("2.10.6", "2.11.8", "2.12.3", "2.12.4"))
    yield new SbtScalaModule{outer =>
      def basePath = AcyclicTests.workspacePath
      def organization = "com.lihaoyi"
      def name = "acyclic"

      def version = "0.1.7"
      def scalaVersion = crossVersion
      def ivyDeps = Seq(
        Dep.Java("org.scala-lang", "scala-compiler", scalaVersion())
      )
      object test extends this.Tests{
        def forkWorkingDir = pwd/'scalaplugin/'src/'test/'resource/'acyclic
        def ivyDeps = Seq(
          Dep("com.lihaoyi", "utest", "0.6.0")
        )
        def testFramework = "utest.runner.Framework"
      }
    }
}
object AcyclicTests extends TestSuite{
  val workspacePath = pwd / 'target / 'workspace / 'acyclic
  val srcPath = pwd / 'scalaplugin / 'src / 'test / 'resource / 'acyclic
  val tests = Tests{
    rm(workspacePath)
    mkdir(workspacePath/up)
    cp(srcPath, workspacePath)
    val mapping = Discovered.mapping(AcyclicBuild)
    def eval[T](t: Task[T]) = TestEvaluator.eval(mapping, workspacePath)(t)

    val packageScala = workspacePath/'src/'main/'scala/'acyclic/"package.scala"

    'scala210 - check("2.10.6", full = false)
    'scala211 - check("2.11.8", full = false)
    'scala2123 - check("2.12.3", full = true)
    'scala2124 - check("2.12.4", full = false)

    val allBinaryVersions = Seq("2.10", "2.11", "2.12")
    def check(scalaVersion: String, full: Boolean) = {
      // Dependencies are right; make sure every dependency is of the correct
      // binary Scala version, except for the compiler-bridge which is of the
      // same version as the host classpath.
      val Right((compileDepClasspath, _)) = eval(AcyclicBuild.acyclic(scalaVersion).compileDepClasspath)
      val binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".")
      val compileDeps = compileDepClasspath.map(_.path.toString())
      val offBinaryVersions = allBinaryVersions.filter(_ != binaryScalaVersion)
      val offVersionedDeps = compileDeps.filter(p => offBinaryVersions.exists(p.contains))
      assert(offVersionedDeps.forall(_.contains("compiler-bridge")))

      // We can compile
      val Right((pathRef, evalCount)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
      val outputPath = pathRef.classes.path
      val outputFiles = ls.rec(outputPath)
      assert(
        evalCount > 0,
        outputFiles.contains(outputPath/'acyclic/'plugin/"GraphAnalysis.class"),
        outputFiles.contains(outputPath/'acyclic/'plugin/"PluginPhase.class")
      )

      // Compilation is cached
      val Right((_, evalCount2)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
      assert(evalCount2 == 0)

      if (full){
        // Caches are invalidated if code is changed
        write.append(packageScala, "\n")
        val Right((_, evalCount3)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
        assert(evalCount3 > 0)

        // Compilation can fail on broken code, and work when fixed
        write.append(packageScala, "\n}}")
        val Left(Result.Exception(ex)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
        assert(ex.isInstanceOf[sbt.internal.inc.CompileFailed])

        write.write(packageScala, read(packageScala).dropRight(3))
        val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).compile)

        // Tests compile & run
        val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())

        // Tests can be broken
        write.append(packageScala, "\n}}")
        val Left(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())

        // Tests can be fixed
        write.write(packageScala, read(packageScala).dropRight(3))
        val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
      }
    }

  }
}