@@ -200,6 +200,22 @@ trait ParallelTesting extends RunnerOrchestration { self =>
200
200
final def countWarnings (reporters : Seq [TestReporter ]) = countErrorsAndWarnings(reporters)._2
201
201
final def reporterFailed (r : TestReporter ) = r.compilerCrashed || r.errorCount > 0
202
202
203
+ final def checkFile (testSource : TestSource ): Option [JFile ] = (testSource match {
204
+ case ts : JointCompilationSource =>
205
+ ts.files.filter(f => ! f.isDirectory).map { f => new JFile (f.getAbsolutePath.replaceFirst(" \\ .scala$" , " .check" )) }.headOption
206
+
207
+ case ts : SeparateCompilationSource =>
208
+ Option (new JFile (dir.getAbsolutePath + " .check" ))
209
+ }).filter(_.exists)
210
+
211
+ final def diffTest (sourceName : String , checkFile : JFile , actual : List [String ]) = {
212
+ val expected = Source .fromFile(checkFile, " UTF-8" ).getLines().toList
213
+ for (msg <- diffMessage(sourceName, actual, expected)) {
214
+ fail(msg)
215
+ dumpOutputToFile(checkFile, actual)
216
+ }
217
+ }
218
+
203
219
final def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable { self =>
204
220
def checkTestSource (): Unit = tryCompile(testSource) {
205
221
val reporters = compileTestSource(testSource)
@@ -606,47 +622,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
606
622
if (Properties .testsNoRun) addNoRunWarning()
607
623
else runMain(testSource.runClassPath) match {
608
624
case Success (_) if ! checkFile.isDefined || ! checkFile.get.exists => // success!
609
- case Success (output) => {
610
- val outputLines = output.linesIterator.toSeq
611
- val checkLines : Seq [String ] = Source .fromFile(checkFile.get, " UTF-8" ).getLines().toSeq
612
- val sourceTitle = testSource.title
613
-
614
- diffMessage(sourceTitle, outputLines, checkLines).foreach { msg =>
615
-
616
- echo(msg)
617
- addFailureInstruction(msg)
618
-
619
- // Print build instructions to file and summary:
620
- val buildInstr = testSource.buildInstructions(0 , warnings)
621
- addFailureInstruction(buildInstr)
622
-
623
- // Fail target:
624
- failTestSource(testSource)
625
-
626
- dumpOutputToFile(checkFile.get, outputLines)
627
- }
628
- }
629
-
625
+ case Success (output) => checkFile.foreach(diffTest(testSource, _, output.linesIterator.toSeq))
630
626
case Failure (output) =>
631
627
echo(s " Test ' ${testSource.title}' failed with output: " )
632
628
echo(output)
633
629
failTestSource(testSource)
634
-
635
630
case Timeout =>
636
631
echo(" failed because test " + testSource.title + " timed out" )
637
632
failTestSource(testSource, TimeoutFailure (testSource.title))
638
633
}
639
634
}
640
635
641
- def checkFile (testSource : TestSource ): Option [JFile ] = testSource match {
642
- case ts : JointCompilationSource => ts.files.filter(f => ! f.isDirectory).flatMap { file =>
643
- Option (new JFile (file.getAbsolutePath.reverse.dropWhile(_ != '.' ).reverse + " check" )).filter(_.exists) }.headOption
644
-
645
- case ts : SeparateCompilationSource =>
646
- Option (new JFile (ts.dir.getAbsolutePath.reverse.dropWhile(_ == JFile .separatorChar).reverse + " .check" )).filter(_.exists)
647
- }
648
-
649
-
650
636
override def onSuccess (testSource : TestSource , reporters : Seq [TestReporter ], logger : LoggedRunnable ) =
651
637
verifyOutput(checkFile(testSource), testSource.outDir, testSource, countWarnings(reporters))
652
638
}
@@ -666,16 +652,60 @@ trait ParallelTesting extends RunnerOrchestration { self =>
666
652
else None
667
653
}
668
654
669
- def files : List [JFile ] = testSource match {
670
- case ts : JointCompilationSource =>
671
- files.filter(f => ! f.isDirectory).map { f =>
672
- new JFile (f.getAbsolutePath.replaceFirst(" \\ .scala$" , " .check" )) }
655
+ override def onSuccess (testSource : TestSource , reporters : Seq [TestReporter ], logger : LoggedRunnable ): Unit =
656
+ checkFile(testSource).foreach(diffTest(testSource.title, _, reporterOutputLines(reporters)))
657
+
658
+ def reporterOutputLines (reporters : List [TestReporter ]): List [String ] =
659
+ reporters.flatMap(_.allErrors).sortBy(_.pos.source.toString).flatMap { error =>
660
+ (error.pos.span.toString + " in " + error.pos.source.file.name) :: error.getMessage().linesIterator.toList }
661
+
662
+ // In neg-tests we allow two types of error annotations,
663
+ // "nopos-error" which doesn't care about position and "error" which
664
+ // has to be annotated on the correct line number.
665
+ //
666
+ // We collect these in a map `"file:row" -> numberOfErrors`, for
667
+ // nopos errors we save them in `"file" -> numberOfNoPosErrors`
668
+ def getErrorMapAndExpectedCount (files : Array [JFile ]): (HashMap [String , Integer ], Int ) = {
669
+ val errorMap = new HashMap [String , Integer ]()
670
+ var expectedErrors = 0
671
+ files.filter(_.getName.endsWith(" .scala" )).foreach { file =>
672
+ Source .fromFile(file, " UTF-8" ).getLines().zipWithIndex.foreach { case (line, lineNbr) =>
673
+ val errors = line.sliding(" // error" .length).count(_.mkString == " // error" )
674
+ if (errors > 0 )
675
+ errorMap.put(s " ${file.getAbsolutePath}: ${lineNbr}" , errors)
676
+
677
+ val noposErrors = line.sliding(" // nopos-error" .length).count(_.mkString == " // nopos-error" )
678
+ if (noposErrors > 0 ) {
679
+ val nopos = errorMap.get(" nopos" )
680
+ val existing : Integer = if (nopos eq null ) 0 else nopos
681
+ errorMap.put(" nopos" , noposErrors + existing)
682
+ }
673
683
674
- case ts : SeparateCompilationSource =>
684
+ expectedErrors += noposErrors + errors
685
+ }
686
+ }
687
+
688
+ (errorMap, expectedErrors)
675
689
}
676
690
677
- override def onSuccess (testSource : TestSource , reporters : Seq [TestReporter ], logger : LoggedRunnable ): Unit = {
691
+ def getMissingExpectedErrors (errorMap : HashMap [String , Integer ], reporterErrors : Iterator [MessageContainer ]) = ! reporterErrors.forall { error =>
692
+ val key = if (error.pos.exists) {
693
+ val fileName = error.pos.source.file.toString
694
+ s " $fileName: ${error.pos.line}"
695
+
696
+ } else " nopos"
678
697
698
+ val errors = errorMap.get(key)
699
+
700
+ if (errors ne null ) {
701
+ if (errors == 1 ) errorMap.remove(key)
702
+ else errorMap.put(key, errors - 1 )
703
+ true
704
+ }
705
+ else {
706
+ echo(s " Error reported in ${error.pos.source}, but no annotation found " )
707
+ false
708
+ }
679
709
}
680
710
}
681
711
0 commit comments