From b80d85e12baf1050947097c19f0b1ce9cc8e5cf7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sun, 24 Dec 2017 18:15:01 +0100 Subject: [PATCH 1/3] Add decompiler tests --- .../decompiler/DecompilationPrinter.scala | 33 ++- .../dotty/tools/dotc/FromTastyTests.scala | 10 +- .../dotty/tools/vulpix/ParallelTesting.scala | 204 ++++++++++++------ tests/pos/lambda.decompiled | 13 ++ tests/pos/lambda.scala | 4 + tests/pos/methodTypes.decompiled | 11 + tests/pos/methodTypes.scala | 5 + tests/pos/simpleCaseObject.decompiled | 25 +++ tests/pos/simpleClass.decompiled | 7 + tests/run/puzzle.decompiled | 18 ++ 10 files changed, 249 insertions(+), 81 deletions(-) create mode 100644 tests/pos/lambda.decompiled create mode 100644 tests/pos/lambda.scala create mode 100644 tests/pos/methodTypes.decompiled create mode 100644 tests/pos/methodTypes.scala create mode 100644 tests/pos/simpleCaseObject.decompiled create mode 100644 tests/pos/simpleClass.decompiled create mode 100644 tests/run/puzzle.decompiled diff --git a/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala b/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala index b189b44133f5..9b7e6e7d1568 100644 --- a/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala +++ b/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala @@ -1,9 +1,12 @@ package dotty.tools.dotc package decompiler +import java.io.{OutputStream, PrintStream} + import dotty.tools.dotc.core.Contexts._ import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.core.tasty.TastyPrinter +import dotty.tools.io.{File, Path} /** Phase that prints the trees in all loaded compilation units. * @@ -14,23 +17,39 @@ class DecompilationPrinter extends Phase { override def phaseName: String = "decompilationPrinter" override def run(implicit ctx: Context): Unit = { - val unit = ctx.compilationUnit + val outputDir = ctx.settings.outputDir.value + if (outputDir == ".") printToOutput(System.out) + else { + var os: OutputStream = null + var ps: PrintStream = null + try { + os = File(outputDir + ".decompiled").outputStream() + ps = new PrintStream(os) + printToOutput(ps) + } finally { + if (os ne null) os.close() + if (ps ne null) ps.close() + } + } + } + private def printToOutput(out: PrintStream)(implicit ctx: Context): Unit = { + val unit = ctx.compilationUnit val pageWidth = ctx.settings.pageWidth.value val doubleLine = "=" * pageWidth val line = "-" * pageWidth - println(doubleLine) - println(unit.source) - println(line) + out.println(doubleLine) + out.println(unit.source) + out.println(line) - println(unit.tpdTree.show) - println(line) + out.println(unit.tpdTree.show) + out.println(line) if (ctx.settings.printTasty.value) { new TastyPrinter(unit.pickled.head._2).printContents() - println(line) + out.println(line) } } } diff --git a/compiler/test/dotty/tools/dotc/FromTastyTests.scala b/compiler/test/dotty/tools/dotc/FromTastyTests.scala index 91617aa027f0..caddc61caf1a 100644 --- a/compiler/test/dotty/tools/dotc/FromTastyTests.scala +++ b/compiler/test/dotty/tools/dotc/FromTastyTests.scala @@ -26,7 +26,7 @@ class FromTastyTests extends ParallelTesting { // > dotc -Ythrough-tasty -Ycheck:all implicit val testGroup: TestGroup = TestGroup("posTestFromTasty") - val (step1, step2) = compileTastyInDir("../tests/pos", defaultOptions, + val (step1, step2, step3) = compileTastyInDir("../tests/pos", defaultOptions, blacklist = Set( "NoCyclicReference.scala", "depfuntype.scala", @@ -53,7 +53,8 @@ class FromTastyTests extends ParallelTesting { ) step1.checkCompile() // Compile all files to generate the class files with tasty step2.checkCompile() // Compile from tasty - (step1 + step2).delete() + step3.checkCompile() // Decompile from tasty + (step1 + step2 + step3).delete() } @Test def runTestFromTasty: Unit = { @@ -63,7 +64,7 @@ class FromTastyTests extends ParallelTesting { // > dotr Test implicit val testGroup: TestGroup = TestGroup("runTestFromTasty") - val (step1, step2) = compileTastyInDir("../tests/run", defaultOptions, + val (step1, step2, step3) = compileTastyInDir("../tests/run", defaultOptions, blacklist = Set( "Course-2002-13.scala", "bridges.scala", @@ -93,7 +94,8 @@ class FromTastyTests extends ParallelTesting { ) step1.checkCompile() // Compile all files to generate the class files with tasty step2.checkRuns() // Compile from tasty and run the result - (step1 + step2).delete() + step3.checkCompile() // Decompile from tasty + (step1 + step2 + step3).delete() } private implicit class tastyCompilationTuples(tup: (CompilationTest, CompilationTest)) { diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 062eb929e3e8..9e907ea5cb2b 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -22,6 +22,7 @@ import dotc.reporting.diagnostic.MessageContainer import dotc.interfaces.Diagnostic.ERROR import dotc.util.DiffUtil import dotc.{ Driver, Compiler } +import dotc.decompiler /** A parallel testing suite whose goal is to integrate nicely with JUnit * @@ -47,7 +48,7 @@ trait ParallelTesting extends RunnerOrchestration { self => /** A test source whose files or directory of files is to be compiled * in a specific way defined by the `Test` */ - private sealed trait TestSource { self => + protected sealed trait TestSource { self => def name: String def outDir: JFile def flags: TestFlags @@ -133,7 +134,8 @@ trait ParallelTesting extends RunnerOrchestration { self => files: Array[JFile], flags: TestFlags, outDir: JFile, - fromTasty: Boolean = false + fromTasty: Boolean = false, + decompilation: Boolean = false ) extends TestSource { def sourceFiles: Array[JFile] = files.filter(isSourceFile) @@ -215,7 +217,7 @@ trait ParallelTesting extends RunnerOrchestration { self => private val filteredSources = if (!testFilter.isDefined) testSources else testSources.filter { - case JointCompilationSource(_, files, _, _, _) => + case JointCompilationSource(_, files, _, _, _, _) => files.exists(file => file.getAbsolutePath.contains(testFilter.get)) case SeparateCompilationSource(_, dir, _, _) => dir.getAbsolutePath.contains(testFilter.get) @@ -422,6 +424,34 @@ trait ParallelTesting extends RunnerOrchestration { self => reporter } + protected def decompile(flags0: TestFlags, suppressErrors: Boolean, targetDir: JFile): TestReporter = { + val decompilationOutput = new JFile(targetDir.getPath) + decompilationOutput.mkdir() + val flags = + flags0 and ("-d", decompilationOutput.getAbsolutePath) and + "-decompile" and "-pagewidth" and "80" + + def hasTastyFileToClassName(f: JFile): String = + targetDir.toPath.relativize(f.toPath).toString.dropRight(".hasTasty".length).replace('/', '.') + val classes = flattenFiles(targetDir).filter(isHasTastyFile).map(hasTastyFileToClassName) + + val reporter = + TestReporter.reporter(realStdout, logLevel = + if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR) + + val driver = decompiler.Main + + // Compile with a try to catch any StackTrace generated by the compiler: + try { + driver.process(flags.all ++ classes, reporter = reporter) + } + catch { + case NonFatal(ex) => reporter.logStackTrace(ex) + } + + reporter + } + private[ParallelTesting] def executeTestSuite(): this.type = { assert(_testSourcesCompleted == 0, "not allowed to re-use a `CompileRun`") @@ -474,9 +504,52 @@ trait ParallelTesting extends RunnerOrchestration { self => protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable { def checkTestSource(): Unit = tryCompile(testSource) { testSource match { - case testSource @ JointCompilationSource(_, files, flags, outDir, fromTasty) => + case testSource @ JointCompilationSource(name, files, flags, outDir, fromTasty, decompilation) => val reporter = - if (fromTasty) compileFromTasty(flags, false, outDir) + if (decompilation) { + val rep = decompile(flags, false, outDir) + + val checkFileOpt = files.flatMap { file => + if (file.isDirectory) Nil + else { + val fname = file.getAbsolutePath.reverse.dropWhile(_ != '.').reverse + "decompiled" + val checkFile = new JFile(fname) + if (checkFile.exists) List(checkFile) + else Nil + } + }.headOption + checkFileOpt match { + case Some(checkFile) => + val stripTrailingWhitespaces = "(.*\\S|)\\s+".r + val output = Source.fromFile(outDir + ".decompiled").getLines().map {line => + stripTrailingWhitespaces.unapplySeq(line).map(_.head).getOrElse(line) + }.mkString("\n") + .replaceFirst("@scala\\.annotation\\.internal\\.SourceFile\\([^\\)]+\\)( |\\n )", "") // FIXME: should not be printed in the decompiler + + checkDiff(output, checkFile, testSource, 0) match { + case Some(diff) => + println("Expected:") + println(checkFile) + println("Actual output;") + println(output) + println("Diff;") + echo(diff) + addFailureInstruction(diff) + + // Print build instructions to file and summary: + val buildInstr = testSource.buildInstructions(0, rep.warningCount) + addFailureInstruction(buildInstr) + + // Fail target: + failTestSource(testSource) + case None => + } + case _ => + } + + rep + } + else if (fromTasty) compileFromTasty(flags, false, outDir) else compile(testSource.sourceFiles, flags, false, outDir) registerCompletion(reporter.errorCount) @@ -526,39 +599,20 @@ trait ParallelTesting extends RunnerOrchestration { self => if (Properties.testsNoRun) addNoRunWarning() else runMain(testSource.runClassPath) match { case Success(_) if !checkFile.isDefined || !checkFile.get.exists => // success! - case Success(output) => { - val outputLines = output.lines.toArray :+ DiffUtil.EOF - val checkLines: Array[String] = Source.fromFile(checkFile.get).getLines().toArray :+ DiffUtil.EOF - val sourceTitle = testSource.title - - def linesMatch = - outputLines - .zip(checkLines) - .forall { case (x, y) => x == y } - - if (outputLines.length != checkLines.length || !linesMatch) { - // Print diff to files and summary: - val expectedSize = DiffUtil.EOF.length max checkLines.map(_.length).max - val diff = outputLines.padTo(checkLines.length, "").zip(checkLines.padTo(outputLines.length, "")).map { case (act, exp) => - DiffUtil.mkColoredLineDiff(exp, act, expectedSize) - }.mkString("\n") - - val msg = - s"""|Output from '$sourceTitle' did not match check file. - |Diff (expected on the left, actual right): - |""".stripMargin + diff + "\n" - echo(msg) - addFailureInstruction(msg) - - // Print build instructions to file and summary: - val buildInstr = testSource.buildInstructions(0, warnings) - addFailureInstruction(buildInstr) - - // Fail target: - failTestSource(testSource) + case Success(output) => + checkDiff(output, checkFile.get, testSource, warnings) match { + case Some(msg) => + echo(msg) + addFailureInstruction(msg) + + // Print build instructions to file and summary: + val buildInstr = testSource.buildInstructions(0, warnings) + addFailureInstruction(buildInstr) + + // Fail target: + failTestSource(testSource) + case None => } - } - case Failure(output) => echo(s"Test '${testSource.title}' failed with output:") echo(output) @@ -573,7 +627,7 @@ trait ParallelTesting extends RunnerOrchestration { self => protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable { def checkTestSource(): Unit = tryCompile(testSource) { val (compilerCrashed, errorCount, warningCount, verifier: Function0[Unit]) = testSource match { - case testSource @ JointCompilationSource(_, files, flags, outDir, fromTasty) => + case testSource @ JointCompilationSource(_, files, flags, outDir, fromTasty, decompilation) => val checkFile = files.flatMap { file => if (file.isDirectory) Nil else { @@ -682,7 +736,7 @@ trait ParallelTesting extends RunnerOrchestration { self => } val (compilerCrashed, expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match { - case testSource @ JointCompilationSource(_, files, flags, outDir, fromTasty) => + case testSource @ JointCompilationSource(_, files, flags, outDir, fromTasty, decompilation) => val sourceFiles = testSource.sourceFiles val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(sourceFiles) val reporter = compile(sourceFiles, flags, true, outDir) @@ -736,6 +790,31 @@ trait ParallelTesting extends RunnerOrchestration { self => } } + private def checkDiff(output: String, checkFile: JFile, testSource: TestSource, warnings: Int): Option[String] = { + val outputLines = output.lines.toArray :+ DiffUtil.EOF + val checkLines: Array[String] = Source.fromFile(checkFile).getLines().toArray :+ DiffUtil.EOF + val sourceTitle = testSource.title + + def linesMatch = + outputLines + .zip(checkLines) + .forall { case (x, y) => x == y } + + if (outputLines.length != checkLines.length || !linesMatch) { + // Print diff to files and summary: + val expectedSize = DiffUtil.EOF.length max checkLines.map(_.length).max + val diff = outputLines.padTo(checkLines.length, "").zip(checkLines.padTo(outputLines.length, "")).map { case (act, exp) => + DiffUtil.mkColoredLineDiff(exp, act, expectedSize) + }.mkString("\n") + + val msg = + s"""|Output from '$sourceTitle' did not match check file. + |Diff (expected on the left, actual right): + |""".stripMargin + diff + "\n" + Some(msg) + } else None + } + /** The `CompilationTest` is the main interface to `ParallelTesting`, it * can be instantiated via one of the following methods: * @@ -967,7 +1046,7 @@ trait ParallelTesting extends RunnerOrchestration { self => */ def copyToTarget(): CompilationTest = new CompilationTest ( targets.map { - case target @ JointCompilationSource(_, files, _, outDir, _) => + case target @ JointCompilationSource(_, files, _, outDir, _, _) => target.copy(files = files.map(copyToDir(outDir,_))) case target @ SeparateCompilationSource(_, dir, _, outDir) => target.copy(dir = copyToDir(outDir, dir)) @@ -1083,34 +1162,6 @@ trait ParallelTesting extends RunnerOrchestration { self => new CompilationTest(target) } - /** Compiles a single file from the string path `f` using the supplied flags - * - * Tests in the first part of the tuple must be executed before the second. - * Both testsRequires explicit delete(). - */ - def compileTasty(f: String, flags: TestFlags)(implicit testGroup: TestGroup): (CompilationTest, CompilationTest) = { - val sourceFile = new JFile(f) - val parent = sourceFile.getParentFile - val outDir = - defaultOutputDir + testGroup + "/" + - sourceFile.getName.substring(0, sourceFile.getName.lastIndexOf('.')) + "/" - - require( - sourceFile.exists && !sourceFile.isDirectory && - (parent ne null) && parent.exists && parent.isDirectory, - s"Source file: $f, didn't exist" - ) - val tastySource = createOutputDirsForFile(sourceFile, parent, outDir) - val target = JointCompilationSource( - testGroup.name, - Array(sourceFile), - flags.withClasspath(tastySource.getPath) and "-from-tasty", - tastySource, - fromTasty = true - ) - (compileFile(f, flags).keepOutput, new CompilationTest(target).keepOutput) - } - /** Compiles a directory `f` using the supplied `flags`. This method does * deep compilation, that is - it compiles all files and subdirectories * contained within the directory `f`. @@ -1216,7 +1267,7 @@ trait ParallelTesting extends RunnerOrchestration { self => * Both testsRequires explicit delete(). */ def compileTastyInDir(f: String, flags0: TestFlags, blacklist: Set[String] = Set.empty)( - implicit testGroup: TestGroup): (CompilationTest, CompilationTest) = { + implicit testGroup: TestGroup): (CompilationTest, CompilationTest, CompilationTest) = { val outDir = defaultOutputDir + testGroup + "/" val flags = flags0 and "-Yretain-trees" val sourceDir = new JFile(f) @@ -1231,9 +1282,22 @@ trait ParallelTesting extends RunnerOrchestration { self => } // TODO add SeparateCompilationSource from tasty? + val targets2 = + files + .filter(f => dotty.tools.io.File(f.toPath).changeExtension("decompiled").exists) + .map { f => + val classpath = createOutputDirsForFile(f, sourceDir, outDir) + JointCompilationSource(testGroup.name, Array(f), flags.withClasspath(classpath.getPath), classpath, decompilation = true) + } + // Create a CompilationTest and let the user decide whether to execute a pos or a neg test val generateClassFiles = compileFilesInDir(f, flags0, blacklist) - (generateClassFiles.keepOutput, new CompilationTest(targets).keepOutput) + + ( + generateClassFiles.keepOutput, + new CompilationTest(targets).keepOutput, + new CompilationTest(targets2).keepOutput + ) } diff --git a/tests/pos/lambda.decompiled b/tests/pos/lambda.decompiled new file mode 100644 index 000000000000..75e5e32589f0 --- /dev/null +++ b/tests/pos/lambda.decompiled @@ -0,0 +1,13 @@ +================================================================================ +../out/posTestFromTasty/pos/lambda/foo/Foo.class +-------------------------------------------------------------------------------- +package foo { + class Foo() extends Object() { + val a: Int => Int = + { + def $anonfun(x: Int): Int = x.*(x) + closure($anonfun) + } + } +} +-------------------------------------------------------------------------------- diff --git a/tests/pos/lambda.scala b/tests/pos/lambda.scala new file mode 100644 index 000000000000..952e28826894 --- /dev/null +++ b/tests/pos/lambda.scala @@ -0,0 +1,4 @@ +package foo +class Foo { + val a = (x: Int) => x * x +} diff --git a/tests/pos/methodTypes.decompiled b/tests/pos/methodTypes.decompiled new file mode 100644 index 000000000000..776508a9e5cd --- /dev/null +++ b/tests/pos/methodTypes.decompiled @@ -0,0 +1,11 @@ +================================================================================ +../out/posTestFromTasty/pos/methodTypes/Foo.class +-------------------------------------------------------------------------------- +package { + class Foo() extends Object() { + val x: Int = 1 + def y: Int = 2 + def z(): Int = 3 + } +} +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/tests/pos/methodTypes.scala b/tests/pos/methodTypes.scala new file mode 100644 index 000000000000..be509a0e5c30 --- /dev/null +++ b/tests/pos/methodTypes.scala @@ -0,0 +1,5 @@ +class Foo { + val x = 1 + def y = 2 + def z() = 3 +} diff --git a/tests/pos/simpleCaseObject.decompiled b/tests/pos/simpleCaseObject.decompiled new file mode 100644 index 000000000000..1affe040e09f --- /dev/null +++ b/tests/pos/simpleCaseObject.decompiled @@ -0,0 +1,25 @@ +================================================================================ +../out/posTestFromTasty/pos/simpleCaseObject/foo/Foo.class +-------------------------------------------------------------------------------- +package foo { + final lazy module case val Foo: foo.Foo = new foo.Foo() + final module case class Foo() extends Object() with _root_.scala.Product { + this: foo.Foo.type => + + override def hashCode(): Int = + { + var acc: Int = 329201766 + scala.runtime.Statics#finalizeHash(acc, 0) + } + override def toString(): String = "Foo" + override def canEqual(that: Any): Boolean = that.isInstanceOf[foo.Foo] + override def productArity: Int = 0 + override def productPrefix: String = "Foo" + override def productElement(n: Int): Any = + n match + { + case _ => throw new IndexOutOfBoundsException(n.toString()) + } + } +} +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/tests/pos/simpleClass.decompiled b/tests/pos/simpleClass.decompiled new file mode 100644 index 000000000000..86b7cf6b1204 --- /dev/null +++ b/tests/pos/simpleClass.decompiled @@ -0,0 +1,7 @@ +================================================================================ +../out/posTestFromTasty/pos/simpleClass/foo/A.class +-------------------------------------------------------------------------------- +package foo { + class A() extends Object() {} +} +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/tests/run/puzzle.decompiled b/tests/run/puzzle.decompiled new file mode 100644 index 000000000000..c578bead0631 --- /dev/null +++ b/tests/run/puzzle.decompiled @@ -0,0 +1,18 @@ +================================================================================ +../out/runTestFromTasty/run/puzzle/Test.class +-------------------------------------------------------------------------------- +package { + final lazy module val Test: Test = new Test() + final module class Test() extends Object() { this: Test.type => + def main(args: Array[String]): Unit = + { + println(if false then 5.0 else 53.0) + val x: Double = if false then 5.0 else 53.0 + println(x) + val z: Long = 1L + val y: Float = Long.long2float(z) + () + } + } +} +-------------------------------------------------------------------------------- \ No newline at end of file From bfb38d3d7ab97fa5d9a71dbc601f3c08a476562f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 16 Jan 2018 13:50:14 +0100 Subject: [PATCH 2/3] Output to file and not show diff in terminal --- .gitignore | 2 + .../dotty/tools/vulpix/ParallelTesting.scala | 37 ++++++++++--------- tests/pos/simpleCaseObject.decompiled | 6 +-- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 11f3d71e8025..b8e3c9e0f96e 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,5 @@ compiler/test/debug/Gen.jar compiler/before-pickling.txt compiler/after-pickling.txt *.dotty-ide-version + +*.decompiled.out diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 9e907ea5cb2b..6612e8671f41 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -526,23 +526,26 @@ trait ParallelTesting extends RunnerOrchestration { self => }.mkString("\n") .replaceFirst("@scala\\.annotation\\.internal\\.SourceFile\\([^\\)]+\\)( |\\n )", "") // FIXME: should not be printed in the decompiler - checkDiff(output, checkFile, testSource, 0) match { - case Some(diff) => - println("Expected:") - println(checkFile) - println("Actual output;") - println(output) - println("Diff;") - echo(diff) - addFailureInstruction(diff) - - // Print build instructions to file and summary: - val buildInstr = testSource.buildInstructions(0, rep.warningCount) - addFailureInstruction(buildInstr) - - // Fail target: - failTestSource(testSource) - case None => + val check: String = Source.fromFile(checkFile).getLines().mkString("\n") + + + if (output != check) { + val outFile = dotty.tools.io.File(checkFile.toPath).addExtension(".out") + outFile.writeAll(output) + val msg = + s"""Output differed for test $name, use the following command to see the diff: + | > diff $checkFile $outFile + """.stripMargin + + echo(msg) + addFailureInstruction(msg) + + // Print build instructions to file and summary: + val buildInstr = testSource.buildInstructions(0, rep.warningCount) + addFailureInstruction(buildInstr) + + // Fail target: + failTestSource(testSource) } case _ => } diff --git a/tests/pos/simpleCaseObject.decompiled b/tests/pos/simpleCaseObject.decompiled index 1affe040e09f..35761b4ac5d7 100644 --- a/tests/pos/simpleCaseObject.decompiled +++ b/tests/pos/simpleCaseObject.decompiled @@ -6,11 +6,7 @@ package foo { final module case class Foo() extends Object() with _root_.scala.Product { this: foo.Foo.type => - override def hashCode(): Int = - { - var acc: Int = 329201766 - scala.runtime.Statics#finalizeHash(acc, 0) - } + override def hashCode(): Int = 1045991777 override def toString(): String = "Foo" override def canEqual(that: Any): Boolean = that.isInstanceOf[foo.Foo] override def productArity: Int = 0 From 8ae50fe6e76a115fad50c404141452a5579972d3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 16 Jan 2018 13:52:57 +0100 Subject: [PATCH 3/3] Cleanup --- .../dotty/tools/vulpix/ParallelTesting.scala | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 6612e8671f41..32df00e60db7 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -48,7 +48,7 @@ trait ParallelTesting extends RunnerOrchestration { self => /** A test source whose files or directory of files is to be compiled * in a specific way defined by the `Test` */ - protected sealed trait TestSource { self => + private sealed trait TestSource { self => def name: String def outDir: JFile def flags: TestFlags @@ -602,20 +602,39 @@ trait ParallelTesting extends RunnerOrchestration { self => if (Properties.testsNoRun) addNoRunWarning() else runMain(testSource.runClassPath) match { case Success(_) if !checkFile.isDefined || !checkFile.get.exists => // success! - case Success(output) => - checkDiff(output, checkFile.get, testSource, warnings) match { - case Some(msg) => - echo(msg) - addFailureInstruction(msg) - - // Print build instructions to file and summary: - val buildInstr = testSource.buildInstructions(0, warnings) - addFailureInstruction(buildInstr) - - // Fail target: - failTestSource(testSource) - case None => + case Success(output) => { + val outputLines = output.lines.toArray :+ DiffUtil.EOF + val checkLines: Array[String] = Source.fromFile(checkFile.get).getLines().toArray :+ DiffUtil.EOF + val sourceTitle = testSource.title + + def linesMatch = + outputLines + .zip(checkLines) + .forall { case (x, y) => x == y } + + if (outputLines.length != checkLines.length || !linesMatch) { + // Print diff to files and summary: + val expectedSize = DiffUtil.EOF.length max checkLines.map(_.length).max + val diff = outputLines.padTo(checkLines.length, "").zip(checkLines.padTo(outputLines.length, "")).map { case (act, exp) => + DiffUtil.mkColoredLineDiff(exp, act, expectedSize) + }.mkString("\n") + + val msg = + s"""|Output from '$sourceTitle' did not match check file. + |Diff (expected on the left, actual right): + |""".stripMargin + diff + "\n" + echo(msg) + addFailureInstruction(msg) + + // Print build instructions to file and summary: + val buildInstr = testSource.buildInstructions(0, warnings) + addFailureInstruction(buildInstr) + + // Fail target: + failTestSource(testSource) } + } + case Failure(output) => echo(s"Test '${testSource.title}' failed with output:") echo(output) @@ -793,31 +812,6 @@ trait ParallelTesting extends RunnerOrchestration { self => } } - private def checkDiff(output: String, checkFile: JFile, testSource: TestSource, warnings: Int): Option[String] = { - val outputLines = output.lines.toArray :+ DiffUtil.EOF - val checkLines: Array[String] = Source.fromFile(checkFile).getLines().toArray :+ DiffUtil.EOF - val sourceTitle = testSource.title - - def linesMatch = - outputLines - .zip(checkLines) - .forall { case (x, y) => x == y } - - if (outputLines.length != checkLines.length || !linesMatch) { - // Print diff to files and summary: - val expectedSize = DiffUtil.EOF.length max checkLines.map(_.length).max - val diff = outputLines.padTo(checkLines.length, "").zip(checkLines.padTo(outputLines.length, "")).map { case (act, exp) => - DiffUtil.mkColoredLineDiff(exp, act, expectedSize) - }.mkString("\n") - - val msg = - s"""|Output from '$sourceTitle' did not match check file. - |Diff (expected on the left, actual right): - |""".stripMargin + diff + "\n" - Some(msg) - } else None - } - /** The `CompilationTest` is the main interface to `ParallelTesting`, it * can be instantiated via one of the following methods: *