Skip to content

Add test for #620 #6647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
params ::: rest
} else impl.body

val bodyText = " {" ~~ selfText ~~ toTextGlobal(primaryConstrs ::: body, "\n") ~ "}"
val bodyText = " {" ~~ selfText ~ toTextGlobal(primaryConstrs ::: body, "\n") ~ "}"

prefix ~
keywordText(" extends").provided(!ofNew && impl.parents.nonEmpty) ~~ parentsText ~
Expand Down
63 changes: 63 additions & 0 deletions compiler/test/dotty/tools/dotc/printing/PrintingTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dotty
package tools
package dotc

import vulpix.FileDiff
import vulpix.TestConfiguration
import vulpix.TestConfiguration
import reporting.TestReporter

import java.io._
import java.nio.file.{Path => JPath}
import java.lang.System.{lineSeparator => EOL}

import interfaces.Diagnostic.INFO
import dotty.tools.io.Directory

import scala.io.Source
import org.junit.Test

class PrintingTest {
val testsDir = "tests/printing"
val options = List("-Xprint:frontend", "-color:never", "-classpath", TestConfiguration.basicClasspath)

private def fileContent(filePath: String): List[String] =
if (new File(filePath).exists)
Source.fromFile(filePath, "UTF-8").getLines().toList
else Nil


private def compileFile(path: JPath): Boolean = {
val baseFilePath = path.toString.stripSuffix(".scala")
val checkFilePath = baseFilePath + ".check"
val byteStream = new ByteArrayOutputStream()
val reporter = TestReporter.reporter(new PrintStream(byteStream), INFO)

try {
Main.process((path.toString::options).toArray, reporter, null)
} catch {
case e: Throwable =>
println(s"Compile $path exception:")
e.printStackTrace()
}

val actualLines = byteStream.toString("UTF-8").split("\\r?\\n")

FileDiff.checkAndDump(path.toString, actualLines, checkFilePath)
}

@Test
def printing: Unit = {
val res = Directory(testsDir).list.toList
.filter(f => f.extension == "scala")
.map { f => compileFile(f.jpath) }

val failed = res.filter(!_)

val msg = s"Pass: ${res.length - failed.length}, Failed: ${failed.length}"

assert(failed.length == 0, msg)

println(msg)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@ package tools
package dotc
package transform

import vulpix.FileDiff
import vulpix.TestConfiguration
import reporting.TestReporter

import dotty.tools.io.Directory

import java.io._
import java.nio.file.{Path => JPath}

import scala.io.Source._
import dotty.tools.io.Directory
import org.junit.Test
import reporting.TestReporter
import vulpix.TestConfiguration

class PatmatExhaustivityTest {
val testsDir = "tests/patmat"
// stop-after: patmatexhaust-huge.scala crash compiler
val options = List("-color:never", "-Ystop-after:crossCast", "-Ycheck-all-patmat", "-classpath", TestConfiguration.basicClasspath)

private def compileFile(path: JPath) = {
private def compileFile(path: JPath): Boolean = {
val stringBuffer = new StringWriter()
val reporter = TestReporter.simplifiedReporter(new PrintWriter(stringBuffer))

Expand All @@ -31,18 +32,18 @@ class PatmatExhaustivityTest {
e.printStackTrace()
}

val actual = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n")
val checkFilePath = path.toAbsolutePath.toString.stripSuffix(".scala") + ".check"
val checkContent =
if (new File(checkFilePath).exists)
fromFile(checkFilePath).getLines().map(_.replaceAll("\\s+$", "")).mkString("\n").trim
else ""
val actualLines: Seq[String] = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n") match {
case "" => Nil
case s => s.split("\\r?\\n")
}
val baseFilePath = path.toString.stripSuffix(".scala")
val checkFilePath = baseFilePath + ".check"

(path, checkContent, actual)
FileDiff.checkAndDump(path.toString, actualLines, checkFilePath)
}

/** A single test with multiple files grouped in a folder */
private def compileDir(path: JPath) = {
private def compileDir(path: JPath): Boolean = {
val stringBuffer = new StringWriter()
val reporter = TestReporter.simplifiedReporter(new PrintWriter(stringBuffer))

Expand All @@ -58,14 +59,14 @@ class PatmatExhaustivityTest {
e.printStackTrace()
}

val actual = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n")
val actualLines: Seq[String] = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n") match {
case "" => Nil
case s => s.split("\\r?\\n")
}

val checkFilePath = path + File.separator + "expected.check"
val checkContent =
if (new File(checkFilePath).exists)
fromFile(checkFilePath).getLines().map(_.replaceAll("\\s+$", "")).mkString("\n").trim
else ""

(path, checkContent, actual)
FileDiff.checkAndDump(path.toString, actualLines, checkFilePath)
}

@Test
Expand All @@ -79,15 +80,9 @@ class PatmatExhaustivityTest {
compileFile(f.jpath)
}

val failed = res.filter { case (_, expected, actual) => expected != actual }
val failed = res.filter(!_)
val ignored = Directory(testsDir).list.toList.filter(_.extension == "ignore")

failed.foreach { case (file, expected, actual) =>
println(s"\n----------------- incorrect output for $file --------------\n" +
s"Expected:\n---------\n$expected\n\nActual:\n-------\n$actual\n"
)
}

val msg = s"Total: ${res.length + ignored.length}, Failed: ${failed.length}, Ignored: ${ignored.length}"

assert(failed.length == 0, msg)
Expand Down
48 changes: 48 additions & 0 deletions compiler/test/dotty/tools/vulpix/FileDiff.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dotty.tools.vulpix

import scala.io.Source
import java.io.File
import java.lang.System.{lineSeparator => EOL}

object FileDiff {
def diffMessage(expectFile: String, actualFile: String): String =
s"""Test output dumped in: $actualFile
| See diff of the checkfile (`brew install icdiff` for colored diff)
| > diff $expectFile $actualFile
| Replace checkfile with current output output
| > mv $actualFile $expectFile
""".stripMargin

def check(sourceTitle: String, outputLines: Seq[String], checkFile: String): Option[String] = {
val checkLines =
if (!(new File(checkFile)).exists) Nil
else Source.fromFile(checkFile, "UTF-8").getLines().toList

def linesMatch =
outputLines.length == checkLines.length &&
(outputLines, checkLines).zipped.forall(_ == _)

if (!linesMatch) Some(
s"""|Output from '$sourceTitle' did not match check file. Actual output:
|${outputLines.mkString(EOL)}
|""".stripMargin + "\n")
else None
}

def dump(path: String, content: Seq[String]): Unit = {
val outFile = dotty.tools.io.File(path)
outFile.writeAll(content.mkString("", EOL, EOL))
}

def checkAndDump(sourceTitle: String, actualLines: Seq[String], checkFilePath: String): Boolean =
FileDiff.check(sourceTitle, actualLines, checkFilePath) match {
case Some(msg) =>
val outFilePath = checkFilePath + ".out"
FileDiff.dump(outFilePath, actualLines)
println(msg)
println(FileDiff.diffMessage(checkFilePath, outFilePath))
false
case _ =>
true
}
}
45 changes: 12 additions & 33 deletions compiler/test/dotty/tools/vulpix/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
* If not, fails the test.
*/
final def diffTest(testSource: TestSource, checkFile: JFile, actual: List[String], reporters: Seq[TestReporter], logger: LoggedRunnable) = {
val expected = Source.fromFile(checkFile, "UTF-8").getLines().toList
for (msg <- diffMessage(testSource.title, actual, expected)) {
for (msg <- FileDiff.check(testSource.title, actual, checkFile.getPath)) {
onFailure(testSource, reporters, logger, Some(msg))
dumpOutputToFile(checkFile, actual)

if (updateCheckFiles) {
FileDiff.dump(checkFile.toPath.toString, actual)
echo("Updated checkfile: " + checkFile.getPath)
} else {
val outFile = checkFile.toPath.resolveSibling(checkFile.toPath.getFileName + ".out").toString
FileDiff.dump(outFile, actual)
echo(FileDiff.diffMessage(checkFile.getPath, outFile))
}
}
}

Expand Down Expand Up @@ -568,24 +575,6 @@ trait ParallelTesting extends RunnerOrchestration { self =>
this
}

protected def dumpOutputToFile(checkFile: JFile, lines: Seq[String]): Unit = {
if (updateCheckFiles) {
val outFile = dotty.tools.io.File(checkFile.toPath)
outFile.writeAll(lines.mkString("", EOL, EOL))
echo("Updated checkfile: " + checkFile.getPath)
} else {
val outFile = dotty.tools.io.File(checkFile.toPath.resolveSibling(checkFile.toPath.getFileName + ".out"))
outFile.writeAll(lines.mkString("", EOL, EOL))
echo(
s"""Test output dumped in: ${outFile.path}
| See diff of the checkfile
| > diff $checkFile $outFile
| Replace checkfile with current output output
| > mv $outFile $checkFile
""".stripMargin)
}
}

/** Returns all files in directory or the file if not a directory */
private def flattenFiles(f: JFile): Array[JFile] =
if (f.isDirectory) f.listFiles.flatMap(flattenFiles)
Expand All @@ -611,12 +600,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>

private def verifyOutput(checkFile: Option[JFile], dir: JFile, testSource: TestSource, warnings: Int, reporters: Seq[TestReporter], logger: LoggedRunnable) = {
if (Properties.testsNoRun) addNoRunWarning()
else runMain(testSource.runClassPath) match {
else runMain(testSource.runClassPath) match {
case Success(output) => checkFile match {
case Some(file) if file.exists => diffTest(testSource, file, output.linesIterator.toList, reporters, logger)
case _ =>
}
case Failure(output) =>
case Failure(output) =>
echo(s"Test '${testSource.title}' failed with output:")
echo(output)
failTestSource(testSource)
Expand Down Expand Up @@ -712,16 +701,6 @@ trait ParallelTesting extends RunnerOrchestration { self =>
override def maybeFailureMessage(testSource: TestSource, reporters: Seq[TestReporter]): Option[String] = None
}

def diffMessage(sourceTitle: String, outputLines: Seq[String], checkLines: Seq[String]): Option[String] = {
def linesMatch =
(outputLines, checkLines).zipped.forall(_ == _)

if (outputLines.length != checkLines.length || !linesMatch) Some(
s"""|Output from '$sourceTitle' did not match check file. Actual output:
|${outputLines.mkString(EOL)}
|""".stripMargin + "\n")
else None
}

/** The `CompilationTest` is the main interface to `ParallelTesting`, it
* can be instantiated via one of the following methods:
Expand Down
30 changes: 30 additions & 0 deletions tests/printing/i620.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
result of tests/printing/i620.scala after frontend:
package O {
package O.A {
class D() extends Object() {
class C() extends Object() {
protected[D] def a: Int = 0
private[D] def b: Int = 0
private def c: Int = 0
protected def d: Int = 0
private[A] def e: Int = 0
protected[A] def f: Int = 0
def g: Int = 0
}
private[D] class E() extends Object() {}
private class F() extends Object() {}
private[A] class G() extends Object() {}
protected[D] class H() extends Object() {}
protected class I() extends Object() {}
protected[A] class J() extends Object() {}
class K() extends Object() {}
protected[D] val a: Int = 0
private[D] val b: Int = 0
private val c: Int = 0
protected val d: Int = 0
private[A] val e: Int = 0
protected[A] val f: Int = 0
val g: Int = 0
}
}
}
32 changes: 32 additions & 0 deletions tests/printing/i620.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// test printing of private[D] and protected[D]

package O
package A

class D {
class C {
protected[D] def a: Int = 0
private[D] def b: Int = 0
private def c: Int = 0
protected def d: Int = 0
private[A] def e: Int = 0
protected[A] def f: Int = 0
def g: Int = 0
}

private[D] class E
private class F
private[A] class G
protected[D] class H
protected class I
protected[A] class J
class K

protected[D] val a: Int = 0
private[D] val b: Int = 0
private val c: Int = 0
protected val d: Int = 0
private[A] val e: Int = 0
protected[A] val f: Int = 0
val g: Int = 0
}