Wrench is a micro test framework for developing compiler plugins for Dotty.
It is supposed to make your life easier if
- you are a PL researcher and want to write a plugin to demonstrate research result
- you are a compiler hacker and want to write a solid plugin for production usage
Add Wrench as a test dependency in SBT:
libraryDependencies += "org.xmid" %% "scala-wrench" % "0.0.4" % "test"
// for Dotty 0.17, use 0.0.2
Also, set the option fork
to true
:
fork := true // important
Now, you can specify the tests like the following:
class Tests {
@Test def posTests = testsIn("tests/pos").shouldCompile
@Test def negTests = testsIn("tests/neg").shouldNotCompile
@Test def runTests = testsIn("tests/run").shouldRun
@Test def pluginDivZeroTests = withPlugin("tests/plugins/divideZero") {
testsIn("tests/plugins/divideZeroTests").shouldNotCompile
}
}
Here is an example test file: Tests.scala
file("tests/pos/hello.scala")
-
Create a single file test case for the file
tests/pos/hello.scala
. You can optionally put a check filehello.check
inside the same directory for run tests. directory("tests/pos/lib")
-
Create a directory test case for the path
tests/pos/lib
. You can optionally put a check filelib.check
inside the directorytests/pos/lib
for run tests.The source files in the directory may be compiled in groups. The groups are recognized and ordered by file name endings. For example, given the following files in the directory:
A_1.scala
B_1.scala
C_2.scala
D_2.scala
The files
A_1.scala
andB_1.scala
will be compiled first, and the compiled class files will be used to compileC_2.scala
andD_2.scala
. testsIn("tests/pos")
-
Create a list of test cases for each file or directory under
test/pos
. Non-Scala files are ignored. Each sub-directory will be a directory test, each Scala file will be a file test.
checkCompile
-
Compilation of the test(s) should produce the same errors as specified in source code. The errors should match code line as well as the number of errors.
You can annotate the source code with
// error
to indicate that a compilation error is expected at the line. Multiple annotations at the same line is supported by repeating// error
. shouldCompile
-
The test(s) should compile without errors.
shouldRun
- The test(s) should compile and run without errors. If a check file is provided, the output of the run should be exactly the same as the content of the check file.
withPlugin(paths) { ... }
-
First compile the plugins in
paths
, then enable the plugins for all compilation in the body. withPluginBin(paths) { ... }
-
Enable precompiled plugins in
paths
for all compilations in the body.
To run the tests sequentially, use the following TestContext
:
implicit val testCtx: TestContext = new DefaultContext
The ParallelContext
supports running the tests in parallel:
implicit val testCtx: TestContext = new ParallelContext
Suppose that your plugin is an SBT project, given the following setting in SBT:
javaOptions in Test ++= {
lazy val pluginJars = (Compile / packageBin / artifactPath).value
List("-Dplugin=" + pluginJars)
}
You can use the plugin as follows in testing:
withPluginBin(sys.props("plugin")) { ... }
Suppose that your plugin project is located in a sub-directory plugin/
under
the project root directory, you can use the following code to reset
the default working directory:
baseDirectory in Test := baseDirectory.value / ".."
Then you can write testsIn("tests/pos/")
instead of testsIn("../tests/pos/")
.
If you want to check that a warning (instead of an error) should happen
at a line, enable the compiler option -Xfatal-warning
.
implicit val flags: TestFlags = Defaults.defaultOptions.and("-Xfatal-warnings")
If you want your plugin to be used by the public, it is highly recommended to test it against the compiler test set.
First, clone the Dotty repo, then make the following changes in the source:
--- a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala
+++ b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala
@@ -8,7 +8,8 @@ object TestConfiguration {
val noCheckOptions = Array(
"-pagewidth", "120",
- "-color:never"
+ "-color:never",
+ "-Xplugin:lib/my-plugin_0.19-0.0.1.jar"
)
Now you can run the test set:
sbt dotty-bootstrapped/testCompilation
The code takes inspiration from the test framework for Dotty, and follows its convention on error annotations and ending-based test groups.