aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2016-02-19 14:13:36 +0100
committerDmitry Petrashko <dark@d-d.me>2016-02-19 14:13:36 +0100
commitea407f143591aa9ffd0fd0f9a25a9ec9e812e76c (patch)
treee21df2017f852a3bc2e45736e5b1bd38a96c35ef /test
parent46b7fc713da460023073c9a9d4d25fc2c7acf5e2 (diff)
parent70f5d93898095aa47b8f7bb33de00d415888dfcf (diff)
downloaddotty-ea407f143591aa9ffd0fd0f9a25a9ec9e812e76c.tar.gz
dotty-ea407f143591aa9ffd0fd0f9a25a9ec9e812e76c.tar.bz2
dotty-ea407f143591aa9ffd0fd0f9a25a9ec9e812e76c.zip
Merge pull request #1106 from dotty-staging/neg-lines
Neg tests check files for // error markers (rebased and updated)
Diffstat (limited to 'test')
-rw-r--r--test/test/CompilerTest.scala136
1 files changed, 133 insertions, 3 deletions
diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala
index 526392576..b8cd88f2d 100644
--- a/test/test/CompilerTest.scala
+++ b/test/test/CompilerTest.scala
@@ -3,9 +3,12 @@ package test
import dotty.partest.DPConfig
import dotty.tools.dotc.{Main, Bench, Driver}
import dotty.tools.dotc.reporting.Reporter
+import dotty.tools.dotc.util.SourcePosition
+import dotty.tools.dotc.config.CompilerCommand
import scala.collection.mutable.ListBuffer
-import scala.reflect.io.{ Path, Directory, File => SFile }
+import scala.reflect.io.{ Path, Directory, File => SFile, AbstractFile }
import scala.tools.partest.nest.{ FileManager, NestUI }
+import scala.annotation.tailrec
import java.io.{ RandomAccessFile, File => JFile }
import org.junit.Test
@@ -178,13 +181,140 @@ abstract class CompilerTest {
// ========== HELPERS =============
- private def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = {
+ private def compileArgs(args: Array[String], xerrors: Int = 0)
+ (implicit defaultOptions: List[String]): Unit = {
val allArgs = args ++ defaultOptions
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
- val nerrors = processor.process(allArgs).errorCount
+ val reporter = processor.process(allArgs)
+
+ val nerrors = reporter.errorCount
assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors")
+
+ // NEG TEST
+ if (xerrors > 0) {
+ val errorLines = reporter.allErrors.map(_.pos)
+ // reporter didn't record as many errors as its errorCount says
+ assert(errorLines.length == nerrors, s"Not enough errors recorded.")
+
+ val allFiles = (allArgs filter {
+ arg => !arg.startsWith("-") && (arg.endsWith(".scala") || arg.endsWith(".java"))
+ }).toList
+ val expectedErrorsPerFile = allFiles.map(getErrors(_))
+
+ // Some compiler errors have an associated source position. Each error
+ // needs to correspond to a "// error" marker on that line in the source
+ // file and vice versa.
+ // Other compiler errors don't have an associated source position. Their
+ // number should correspond to the total count of "// nopos-error"
+ // markers in all files
+ val (errorsByFile, errorsWithoutPos) = errorLines.groupBy(_.source.file).toList.partition(_._1.toString != "<no source>")
+
+ // check errors with source position
+ val foundErrorsPerFile = errorsByFile.map({ case (fileName, errorList) =>
+ val posErrorLinesToNr = errorList.groupBy(_.line).toList.map({ case (line, list) => (line, list.length) }).sortBy(_._1)
+ ErrorsInFile(fileName.toString, 0, posErrorLinesToNr)
+ })
+ val expectedErrorsPerFileZeroed = expectedErrorsPerFile.map({
+ case ErrorsInFile(fileName, _, posErrorLinesToNr) =>
+ ErrorsInFile(fileName.toString, 0, posErrorLinesToNr)
+ })
+ checkErrorsWithPosition(expectedErrorsPerFileZeroed, foundErrorsPerFile)
+
+ // check errors without source position
+ val expectedNoPos = expectedErrorsPerFile.map(_.noposErrorNr).sum
+ val foundNoPos = errorsWithoutPos.map(_._2.length).sum
+ assert(foundNoPos == expectedNoPos,
+ s"Wrong # of errors without source position. Expected (all files): $expectedNoPos, found (compiler): $foundNoPos")
+ }
}
+ // ========== NEG TEST HELPERS =============
+
+ /** Captures the number of nopos-errors in the given file and the number of
+ * errors with a position, represented as a tuple of source line and number
+ * of errors on that line. */
+ case class ErrorsInFile(fileName: String, noposErrorNr: Int, posErrorLinesToNr: List[(Int, Int)])
+
+ /** Extracts the errors expected for the given neg test file. */
+ def getErrors(fileName: String): ErrorsInFile = {
+ val content = SFile(fileName).slurp
+ val (line, rest) = content.span(_ != '\n')
+
+ @tailrec
+ def checkLine(line: String, rest: String, index: Int, noposAcc: Int, posAcc: List[(Int, Int)]): ErrorsInFile = {
+ val posErrors = "// ?error".r.findAllIn(line).length
+ val newPosAcc = if (posErrors > 0) (index, posErrors) :: posAcc else posAcc
+ val newNoPosAcc = noposAcc + "// ?nopos-error".r.findAllIn(line).length
+ val (newLine, newRest) = rest.span(_ != '\n')
+ if (newRest.isEmpty)
+ ErrorsInFile(fileName.toString, newNoPosAcc, newPosAcc.reverse)
+ else
+ checkLine(newLine, newRest.tail, index + 1, newNoPosAcc, newPosAcc) // skip leading '\n'
+ }
+
+ checkLine(line, rest.tail, 0, 0, Nil) // skip leading '\n'
+ }
+
+ /** Asserts that the expected and found number of errors correspond, and
+ * otherwise throws an error with the filename, plus optionally a line
+ * number if available. */
+ def errorMsg(fileName: String, lineNumber: Option[Int], exp: Int, found: Int) = {
+ val i = lineNumber.map({ i => ":" + (i + 1) }).getOrElse("")
+ assert(found == exp, s"Wrong # of errors for $fileName$i. Expected (file): $exp, found (compiler): $found")
+ }
+
+ /** Compares the expected with the found errors and creates a nice error
+ * message if they don't agree. */
+ def checkErrorsWithPosition(expected: List[ErrorsInFile], found: List[ErrorsInFile]): Unit = {
+ // create nice error messages
+ expected.diff(found) match {
+ case Nil => // nothing missing
+ case ErrorsInFile(fileName, _, expectedLines) :: xs =>
+ found.find(_.fileName == fileName) match {
+ case None =>
+ // expected some errors, but none found for this file
+ errorMsg(fileName, None, expectedLines.map(_._2).sum, 0)
+ case Some(ErrorsInFile(_,_,foundLines)) =>
+ // found wrong number/location of markers for this file
+ compareLines(fileName, expectedLines, foundLines)
+ }
+ }
+
+ found.diff(expected) match {
+ case Nil => // nothing missing
+ case ErrorsInFile(fileName, _, foundLines) :: xs =>
+ expected.find(_.fileName == fileName) match {
+ case None =>
+ // found some errors, but none expected for this file
+ errorMsg(fileName, None, 0, foundLines.map(_._2).sum)
+ case Some(ErrorsInFile(_,_,expectedLines)) =>
+ // found wrong number/location of markers for this file
+ compareLines(fileName, expectedLines, foundLines)
+ }
+ }
+ }
+
+ /** Gives an error message for one line where the expected number of errors and
+ * the number of compiler errors differ. */
+ def compareLines(fileName: String, expectedLines: List[(Int, Int)], foundLines: List[(Int, Int)]) = {
+ expectedLines.foreach({ case (line, expNr) =>
+ foundLines.find(_._1 == line) match {
+ case Some((_, `expNr`)) => // this line is ok
+ case Some((_, foundNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
+ case None => errorMsg(fileName, Some(line), expNr, 0)
+ }
+ })
+ foundLines.foreach({ case (line, foundNr) =>
+ expectedLines.find(_._1 == line) match {
+ case Some((_, `foundNr`)) => // this line is ok
+ case Some((_, expNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
+ case None => errorMsg(fileName, Some(line), 0, foundNr)
+ }
+ })
+ }
+
+ // ========== PARTEST HELPERS =============
+
// In particular, don't copy flags from scalac tests
private val extensionsToCopy = scala.collection.immutable.HashSet("scala", "java")