Skip to content

Commit f04b2ea

Browse files
Merge pull request #5894 from dotty-staging/add-update-checkfiles
Add `updateCheckFiles` to override tests check files with output
2 parents 51853d6 + 7076c74 commit f04b2ea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+99
-144
lines changed

compiler/test/dotc/comptest.scala

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ object comptest extends ParallelTesting {
1111
def safeMode = false
1212
def isInteractive = true
1313
def testFilter = None
14+
def updateCheckFiles: Boolean = false
1415

1516
val posDir = "./tests/pos/"
1617
val negDir = "./tests/neg/"

compiler/test/dotty/Properties.scala

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ object Properties {
2020
*/
2121
val testsFilter: Option[String] = sys.props.get("dotty.tests.filter")
2222

23+
/** Tests should override the checkfiles with the current output */
24+
val testsUpdateCheckfile: Boolean = propIsNullOrTrue("dotty.tests.updateCheckfiles")
25+
2326
/** When set, the run tests are only compiled - not run, a warning will be
2427
* issued
2528
*/

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

+1-5
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,8 @@ import org.junit.Assert._
77
import org.junit.Assume._
88
import org.junit.experimental.categories.Category
99

10-
import java.nio.file._
11-
import java.util.stream.{ Stream => JStream }
12-
import scala.collection.JavaConverters._
13-
import scala.util.matching.Regex
1410
import scala.concurrent.duration._
1511
import vulpix._
16-
import dotty.tools.io.JFile
1712

1813
@Category(Array(classOf[BootstrappedOnlyTests]))
1914
class BootstrappedOnlyCompilationTests extends ParallelTesting {
@@ -28,6 +23,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
2823
def safeMode = Properties.testsSafeMode
2924
def isInteractive = SummaryReport.isInteractive
3025
def testFilter = Properties.testsFilter
26+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
3127

3228
// Positive tests ------------------------------------------------------------
3329

compiler/test/dotty/tools/dotc/CompilationTests.scala

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class CompilationTests extends ParallelTesting {
2727
def safeMode = Properties.testsSafeMode
2828
def isInteractive = SummaryReport.isInteractive
2929
def testFilter = Properties.testsFilter
30+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
3031

3132
// Positive tests ------------------------------------------------------------
3233

compiler/test/dotty/tools/dotc/FromTastyTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class FromTastyTests extends ParallelTesting {
2020
def safeMode = Properties.testsSafeMode
2121
def isInteractive = SummaryReport.isInteractive
2222
def testFilter = Properties.testsFilter
23-
23+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
2424

2525
@Test def posTestFromTasty: Unit = {
2626
// Can be reproduced with

compiler/test/dotty/tools/dotc/IdempotencyTests.scala

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class IdempotencyTests extends ParallelTesting {
2424
def safeMode = Properties.testsSafeMode
2525
def isInteractive = SummaryReport.isInteractive
2626
def testFilter = Properties.testsFilter
27+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
2728

2829
@Category(Array(classOf[SlowTests]))
2930
@Test def idempotency: Unit = {

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

+36-16
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
4646
*/
4747
def testFilter: Option[String]
4848

49+
/** Tests should override the checkfiles with the current output */
50+
def updateCheckFiles: Boolean
51+
4952
/** A test source whose files or directory of files is to be compiled
5053
* in a specific way defined by the `Test`
5154
*/
@@ -505,6 +508,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
505508
this
506509
}
507510

511+
protected def updateCheckFile(checkFile: JFile, lines: Seq[String]): Unit = {
512+
val outFile = dotty.tools.io.File(checkFile.toPath)
513+
outFile.writeAll(lines.mkString("", EOL, EOL))
514+
echo("Updated checkfile: " + checkFile.getPath)
515+
}
516+
508517
/** Returns all files in directory or the file if not a directory */
509518
private def flattenFiles(f: JFile): Array[JFile] =
510519
if (f.isDirectory) f.listFiles.flatMap(flattenFiles)
@@ -537,28 +546,32 @@ trait ParallelTesting extends RunnerOrchestration { self =>
537546
val output = Source.fromFile(outDir.getParent + "_decompiled" + JFile.separator + outDir.getName
538547
+ JFile.separator + "decompiled.scala", "UTF-8").getLines().map {line =>
539548
stripTrailingWhitespaces.unapplySeq(line).map(_.head).getOrElse(line)
540-
}.toList
549+
}.filter(!_.startsWith(ignoredFilePathLine)).toList
541550

542-
val check: String = Source.fromFile(checkFile, "UTF-8").getLines().filter(!_.startsWith(ignoredFilePathLine))
551+
val check: String = Source.fromFile(checkFile, "UTF-8").getLines()
543552
.mkString(EOL)
544553

545-
if (output.filter(!_.startsWith(ignoredFilePathLine)).mkString(EOL) != check) {
554+
if (output.mkString(EOL) != check) {
546555
val outFile = dotty.tools.io.File(checkFile.toPath).addExtension(".out")
547-
outFile.writeAll(output.mkString(EOL))
548-
val msg =
549-
s"""Output differed for test $name, use the following command to see the diff:
550-
| > diff $checkFile $outFile
556+
if (updateCheckFiles) {
557+
updateCheckFile(checkFile, output)
558+
} else {
559+
outFile.writeAll(output.mkString("", EOL, ""))
560+
val msg =
561+
s"""Output differed for test $name, use the following command to see the diff:
562+
| > diff $checkFile $outFile
551563
""".stripMargin
552564

553-
echo(msg)
554-
addFailureInstruction(msg)
565+
echo(msg)
566+
addFailureInstruction(msg)
555567

556-
// Print build instructions to file and summary:
557-
val buildInstr = testSource.buildInstructions(0, rep.warningCount)
558-
addFailureInstruction(buildInstr)
568+
// Print build instructions to file and summary:
569+
val buildInstr = testSource.buildInstructions(0, rep.warningCount)
570+
addFailureInstruction(buildInstr)
559571

560-
// Fail target:
561-
failTestSource(testSource)
572+
// Fail target:
573+
failTestSource(testSource)
574+
}
562575
}
563576
case _ =>
564577
}
@@ -631,6 +644,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
631644

632645
// Fail target:
633646
failTestSource(testSource)
647+
648+
if (updateCheckFiles)
649+
updateCheckFile(checkFile.get, outputLines)
634650
}
635651
}
636652

@@ -766,7 +782,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
766782
}
767783
def checkFileTest(sourceName: String, checkFile: JFile, actual: List[String]) = {
768784
val expexted = Source.fromFile(checkFile, "UTF-8").getLines().toList
769-
diffMessage(sourceName, actual, expexted).foreach(fail)
785+
for (msg <- diffMessage(sourceName, actual, expexted)) {
786+
fail(msg)
787+
if (updateCheckFiles)
788+
updateCheckFile(checkFile, actual)
789+
}
770790
}
771791

772792
val (compilerCrashed, expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
@@ -1371,7 +1391,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
13711391
|Test '$title' compiled with $errors error(s) and $warnings warning(s),
13721392
|the test can be reproduced by running:
13731393
|
1374-
| sbt "testFromTasty $file"
1394+
| sbt "testCompilation --from-tasty $file"
13751395
|
13761396
|This tests can be disabled by adding `${file.getName}` to `compiler${JFile.separator}test${JFile.separator}dotc${JFile.separator}$runOrPos-$listName.blacklist`
13771397
|

compiler/test/dotty/tools/vulpix/SummaryReport.scala

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ trait SummaryReporting {
4040

4141
/** Echoes contents of `it` to file *immediately* then flushes */
4242
def echoToLog(it: Iterator[String]): Unit
43+
4344
}
4445

4546
/** A summary report that doesn't do anything */
@@ -53,6 +54,7 @@ final class NoSummaryReport extends SummaryReporting {
5354
def echoSummary(): Unit = ()
5455
def echoToLog(msg: String): Unit = ()
5556
def echoToLog(it: Iterator[String]): Unit = ()
57+
def updateCheckFiles: Boolean = false
5658
}
5759

5860
/** A summary report that logs to both stdout and the `TestReporter.logWriter`

compiler/test/dotty/tools/vulpix/VulpixMetaTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package vulpix
44
import org.junit.Test
55
import org.junit.experimental.categories.Category
66
import scala.concurrent.duration._
7-
import dotty.Properties
87
import TestConfiguration._
98

109
/** Meta tests for the Vulpix test suite. This test follows the structure of
@@ -19,6 +18,7 @@ class VulpixMetaTests extends ParallelTesting {
1918
def safeMode = false // Don't fork a new VM after each run test
2019
def isInteractive = false // Don't beautify output for interactive use.
2120
def testFilter = None // Run all the tests.
21+
def updateCheckFiles: Boolean = false
2222

2323
implicit val summaryReport: SummaryReporting = new SummaryReport
2424
implicit def testGroup: TestGroup = TestGroup("VulpixMetaTests")

compiler/test/dotty/tools/vulpix/VulpixUnitTests.scala

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class VulpixUnitTests extends ParallelTesting {
2121
def safeMode = sys.env.get("SAFEMODE").isDefined
2222
def isInteractive = !sys.env.contains("DRONE")
2323
def testFilter = None
24+
def updateCheckFiles: Boolean = false
2425

2526
// To fail with something else than an AssertionError
2627
def fail(): Unit = throw new Exception("didn't fail properly")

docs/docs/contributing/testing.md

+18
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,27 @@ This will run both the test `./tests/pos/companions.scala` and
8080
`./tests/neg/companions.scala` since both of these match the given string.
8181
This also means that you could run `testCompilation` with no arguments to run all integration tests.
8282

83+
When complex checkfiles must be updated, `testCompilation` can run in a mode where it overrides the checkfiles with the test outputs.
84+
```bash
85+
$ sbt
86+
> testCompilation --update-checkfiles
87+
```
88+
8389
### Bootstrapped-only tests
8490

8591
To run `testCompilation` on a bootstrapped Dotty compiler, use
8692
`dotty-compiler-bootstrapped/testCompilation` (with the same syntax as above).
8793
Some tests can only be run in bootstrapped compilers; that includes all tests
8894
with `with-compiler` in their name.
95+
96+
### From TASTy tests
97+
98+
`testCompilation` has a additional mode to run tests that compile code from a `.tasty` file, decompile a `.tasty` file and recompile the decompiled tasty.
99+
Modify blacklist and whitelists in `compiler/test/dotc` to enable or disable tests from `.tasty` files.
100+
101+
```bash
102+
$ sbt
103+
> testCompilation --from-tasty
104+
```
105+
106+
This mode can be combined with `--update-checkfiles` to update the `.decompiled` files or can be run under `dotty-compiler-bootstrapped/testCompilation` to test on a bootstrapped Dotty compiler.

project/Build.scala

+11-14
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ object Build {
8585
// Run tests with filter through vulpix test suite
8686
val testCompilation = inputKey[Unit]("runs integration test with the supplied filter")
8787

88-
// Run TASTY tests with filter through vulpix test suite
89-
val testFromTasty = inputKey[Unit]("runs tasty integration test with the supplied filter")
90-
9188
// Spawns a repl with the correct classpath
9289
val repl = inputKey[Unit]("run the REPL with correct classpath")
9390

@@ -438,15 +435,6 @@ object Build {
438435
case Bootstrapped => `dotty-doc-bootstrapped`
439436
}
440437

441-
def testOnlyFiltered(test: String, options: String) = Def.inputTaskDyn {
442-
val args = spaceDelimited("<arg>").parsed
443-
val cmd = s" $test -- $options" + {
444-
if (args.nonEmpty) " -Ddotty.tests.filter=" + args.mkString(" ")
445-
else ""
446-
}
447-
(testOnly in Test).toTask(cmd)
448-
}
449-
450438
def findLib(attList: Seq[Attributed[File]], name: String) = attList
451439
.map(_.data.getAbsolutePath)
452440
.find(_.contains(name))
@@ -547,8 +535,17 @@ object Build {
547535
jarOpts ::: tuning ::: agentOptions ::: ci_build
548536
},
549537

550-
testCompilation := testOnlyFiltered("dotty.tools.dotc.*CompilationTests", "--exclude-categories=dotty.SlowTests").evaluated,
551-
testFromTasty := testOnlyFiltered("dotty.tools.dotc.FromTastyTests", "").evaluated,
538+
testCompilation := Def.inputTaskDyn {
539+
val args = spaceDelimited("<arg>").parsed
540+
val updateCheckfile = args.contains("--update-checkfiles")
541+
val fromTasty = args.contains("--from-tasty")
542+
val args1 = if (updateCheckfile | fromTasty) args.filter(x => x != "--update-checkfiles" && x != "--from-tasty") else args
543+
val test = if (fromTasty) "dotty.tools.dotc.FromTastyTests" else "dotty.tools.dotc.*CompilationTests"
544+
val cmd = s" $test -- --exclude-categories=dotty.SlowTests" +
545+
(if (updateCheckfile) " -Ddotty.tests.updateCheckfiles=true" else "") +
546+
(if (args1.nonEmpty) " -Ddotty.tests.filter=" + args1.mkString(" ") else "")
547+
(testOnly in Test).toTask(cmd)
548+
}.evaluated,
552549

553550
dotr := {
554551
val args: List[String] = spaceDelimited("<arg>").parsed.toList

tests/pos/classWithCompObj.decompiled

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
/** Decompiled from out/posTestFromTasty/pos/classWithCompObj/Foo.class */
21
class Foo()
3-
object Foo
2+
object Foo

tests/pos/conforms.decompiled

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/conforms/Test.class */
21
object Test {
32
def f[A, B](x: A)(implicit e: scala.Predef.<:<[A, B]): B = e.apply(x)
4-
}
3+
}

tests/pos/i0306.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i0306/bar.class */
21
object bar {
32
class C[T <: scala.Seq[_ >: scala.Nothing <: scala.Any]]()
43
val x: scala.AnyRef = new bar.C[scala.collection.Seq[_ >: scala.Nothing <: scala.Any]]()

tests/pos/i1181.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i1181/Test.class */
21
object Test {
32
def foo[M[_$1]](x: M[scala.Int]): M[scala.Int] = x
43
type Alias[A] = scala.Tuple2[A, A]

tests/pos/i1444.decompiled

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i1444/Test.class */
21
object Test {
32
class Cls(implicit x: Test.X)
43
class ClsImpl() extends Test.Cls()(Test.AnX)
@@ -8,4 +7,4 @@ object Test {
87
class Tr2Impl() extends Test.Tr2()(Test.AnX)
98
trait X() extends java.lang.Object
109
object AnX extends Test.X
11-
}
10+
}

tests/pos/i1570.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i1570/Test.class */
21
object Test {
32
inline def foo(n: scala.Int): scala.Int = Test.bar(n)
43
inline def bar(n: scala.Int): scala.Int = n

tests/pos/i2104b.decompiled

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i2104b/Cons.tasty */
21
trait Cons[+H, +T]() extends java.lang.Object
32
object Cons {
43
def apply[H, T](h: H, t: T): Cons[H, T] = scala.Predef.???
54
def unapply[H, T](t: Cons[H, T]): scala.Option[Pair[H, T]] = scala.Predef.???
65
}
7-
/** Decompiled from out/posTestFromTasty/pos/i2104b/Pair.tasty */
86
case class Pair[A, B](_1: A, _2: B) {
97
override def hashCode(): scala.Int = {
108
var acc: scala.Int = 2479866
@@ -32,10 +30,9 @@ case class Pair[A, B](_1: A, _2: B) {
3230
}
3331
}
3432
object Pair extends scala.AnyRef
35-
/** Decompiled from out/posTestFromTasty/pos/i2104b/Test.tasty */
3633
object Test {
3734
def main(args: scala.Array[scala.Predef.String]): scala.Unit = Cons.apply[scala.Option[scala.Int], scala.None.type](scala.Option.apply[scala.Int](1), scala.None) match {
3835
case Cons(scala.Some(i), scala.None) =>
3936
()
4037
}
41-
}
38+
}

tests/pos/i4526-2.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i4526-2/Foo.class */
21
class Foo(x: scala.Int, y: scala.Int)

tests/pos/i4526a.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i4526a/bar/Foo.class */
21
package bar {
32
class Foo() {
43
protected[bar] def foo(): scala.Int = 0

tests/pos/i4526b.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i4526b/Foo.class */
21
class Foo() {
32
def justdoit(f: scala.Either[scala.Int, scala.Predef.String]): scala.Predef.String = f match {
43
case scala.Left(i) =>

tests/pos/i4678.decompiled

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i4678/Foo.tasty */
21
class Foo() {
32
val x: scala.Int = (1: @annot1 @annot2 @annot3 @annot4 @annot5)
43
}
5-
/** Decompiled from out/posTestFromTasty/pos/i4678/annot1.tasty */
64
class annot1() extends scala.annotation.Annotation
7-
/** Decompiled from out/posTestFromTasty/pos/i4678/annot2.tasty */
85
class annot2() extends scala.annotation.Annotation
9-
/** Decompiled from out/posTestFromTasty/pos/i4678/annot3.tasty */
106
class annot3() extends scala.annotation.Annotation
11-
/** Decompiled from out/posTestFromTasty/pos/i4678/annot4.tasty */
127
class annot4() extends scala.annotation.Annotation
13-
/** Decompiled from out/posTestFromTasty/pos/i4678/annot5.tasty */
14-
class annot5() extends scala.annotation.Annotation
8+
class annot5() extends scala.annotation.Annotation

tests/pos/i566.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/i566/Test.class */
21
class Test() {
32
type T = scala.Predef.String
43
type U

tests/pos/lambda.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/lambda/foo/Foo.class */
21
package foo {
32
class Foo() {
43
((x: scala.Int) => 2)

tests/pos/methodTypes.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/methodTypes/Foo.class */
21
class Foo() {
32
val x: scala.Int = 1
43
def y: scala.Int = 2

tests/pos/selftypes.decompiled

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/** Decompiled from out/posTestFromTasty/pos/selftypes/selftypes.class */
21
object selftypes {
32
trait A() extends java.lang.Object { self: selftypes.AB =>
43
type AA = scala.List[this.BX]

0 commit comments

Comments
 (0)