Skip to content

Commit 418c118

Browse files
vsalvisVladimirNik
authored andcommitted
Negtests (JUnit only) check that each error line has a // error
1 parent 1ed3867 commit 418c118

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

src/dotty/tools/dotc/reporting/Reporter.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ abstract class Reporter {
223223
var warningCount = 0
224224
def hasErrors = errorCount > 0
225225
def hasWarnings = warningCount > 0
226+
private var errors: List[Error] = Nil
227+
def allErrors = errors
226228

227229
/** Have errors been reported by this reporter, or in the
228230
* case where this is a StoreReporter, by an outer reporter?
@@ -238,7 +240,9 @@ abstract class Reporter {
238240
d match {
239241
case d: ConditionalWarning if !d.enablingOption.value => unreportedWarnings(d.enablingOption.name) += 1
240242
case d: Warning => warningCount += 1
241-
case d: Error => errorCount += 1
243+
case d: Error =>
244+
errors = d :: errors
245+
errorCount += 1
242246
case d: Info => // nothing to do here
243247
// match error if d is something else
244248
}

test/test/CompilerTest.scala

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package test
33
import dotty.partest.DPConfig
44
import dotty.tools.dotc.{Main, Bench, Driver}
55
import dotty.tools.dotc.reporting.Reporter
6+
import dotty.tools.dotc.util.SourcePosition
7+
import dotty.tools.dotc.config.CompilerCommand
68
import scala.collection.mutable.ListBuffer
7-
import scala.reflect.io.{ Path, Directory, File => SFile }
9+
import scala.reflect.io.{ Path, Directory, File => SFile, AbstractFile }
810
import scala.tools.partest.nest.{ FileManager, NestUI }
11+
import scala.annotation.tailrec
912
import java.io.{ RandomAccessFile, File => JFile }
1013

1114
import org.junit.Test
@@ -178,13 +181,83 @@ abstract class CompilerTest {
178181

179182
// ========== HELPERS =============
180183

181-
private def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = {
184+
private def compileArgs(args: Array[String], xerrors: Int = 0)
185+
(implicit defaultOptions: List[String]): Unit = {
182186
val allArgs = args ++ defaultOptions
183187
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
184-
val nerrors = processor.process(allArgs).errorCount
188+
val reporter = processor.process(allArgs)
189+
190+
val nerrors = reporter.errorCount
185191
assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors")
192+
193+
// is neg test, check errors occur on right line
194+
if (xerrors > 0) {
195+
val errorLines = reporter.allErrors.map(_.pos)
196+
// reporter didn't record as many errors as its errorCount says
197+
assert(errorLines.length == nerrors, s"Not enough errors recorded.")
198+
val (byFile, noPos) = errorLines.groupBy(_.source.file).partition(_._1.toString != "<no source>")
199+
200+
// check the compiler errors that have a source position
201+
val noPosErrFiles = byFile.foldLeft(0)(_ + checkErrorsInFile(_))
202+
203+
// check that files without compiler errors don't contain error markers
204+
val allFiles = (allArgs filter {
205+
case arg => arg.endsWith(".scala") || arg.endsWith(".java")
206+
}).toList
207+
val checkedFiles = byFile.keys.toList.map(_.toString)
208+
val noPosExpected = noPosErrFiles + checkNoErrorMissing(allFiles.filter(!checkedFiles.contains(_)))
209+
210+
// check compiler errors without source position, their number should
211+
// correspond to all "// nopos-error" markers in any files
212+
val noPosFound = noPos.foldLeft(0)(_ + _._2.length)
213+
assert(noPosFound == noPosExpected,
214+
s"Wrong # of errors without source position. Expected (all files): $noPosExpected, found (compiler): $noPosFound")
215+
}
186216
}
187217

218+
/** For neg tests, check that all errors thrown by compiler have a "// error"
219+
* on the corresponding line in the source file.
220+
*/
221+
def checkErrorsInFile(errors: (AbstractFile, List[SourcePosition])): Int = {
222+
errors match {
223+
case (fileName, pos@(first :: rest)) =>
224+
val content = first.source.content.mkString
225+
val (line, rest) = content.span(_ != '\n')
226+
val byLine = scala.collection.mutable.Map(errors._2.groupBy(_.line).toSeq: _*)
227+
228+
@tailrec
229+
def checkLine(line: String, rest: String, index: Int): Unit = {
230+
val expected = countErrors(line)
231+
byLine.remove(index) match {
232+
case Some(pos) => checkErrors(fileName.toString, Some(index), expected, pos.length)
233+
case None => checkErrors(fileName.toString, Some(index), expected, 0)
234+
}
235+
val (newLine, newRest) = rest.span(_ != '\n')
236+
if (!newRest.isEmpty)
237+
checkLine(newLine, newRest.drop(1), index + 1)
238+
}
239+
240+
checkLine(line, rest.drop(1), 0)
241+
assert(byLine.isEmpty, "Some compiler errors don't correspond to any line in the source file: " + fileName + ": " + byLine)
242+
countNoPosErrors(content)
243+
case (fileName, Nil) => assert(false, "impossible: empty groupBy value in file: " + fileName); 0
244+
}
245+
}
246+
247+
def countErrors(s: String) = "// ?error".r.findAllIn(s).length
248+
def countNoPosErrors(s: String) = "// ?nopos-error".r.findAllIn(s).length
249+
250+
def checkErrors(fileName: String, index: Option[Int], exp: Int, found: Int) = {
251+
val i = index.map({ i => ":" + (i + 1) }).getOrElse("")
252+
assert(found == exp, s"Wrong # of errors for $fileName$i. Expected (file): $exp, found (compiler): $found")
253+
}
254+
255+
def checkNoErrorMissing(files: List[String]) = files.foldLeft(0)({ case (sum, fileName) =>
256+
val content = SFile(fileName).slurp
257+
checkErrors(fileName, None, countErrors(content), 0)
258+
sum + countNoPosErrors(content)
259+
})
260+
188261
// In particular, don't copy flags from scalac tests
189262
private val extensionsToCopy = scala.collection.immutable.HashSet("scala", "java")
190263

0 commit comments

Comments
 (0)