aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-04-10 16:26:14 +0200
committerFelix Mulder <felix.mulder@gmail.com>2017-04-12 11:31:15 +0200
commitf891b224228f7c4939d09ac1849ad562d1298640 (patch)
tree1727ad2648f243fa2962b065714313aefd162aea
parentd42a28d07683d95e6dffd27cdb9078ebeb599c15 (diff)
downloaddotty-f891b224228f7c4939d09ac1849ad562d1298640.tar.gz
dotty-f891b224228f7c4939d09ac1849ad562d1298640.tar.bz2
dotty-f891b224228f7c4939d09ac1849ad562d1298640.zip
Make sure that everything is dumped to log files
-rw-r--r--compiler/test/dotty/tools/dotc/reporting/TestReporter.scala22
-rw-r--r--compiler/test/dotty/tools/vulpix/ParallelTesting.scala142
-rw-r--r--compiler/test/dotty/tools/vulpix/SummaryReport.java13
3 files changed, 120 insertions, 57 deletions
diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
index 5641240a7..efba2dc8f 100644
--- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
+++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala
@@ -23,6 +23,10 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
final def errors: Iterator[MessageContainer] = _errorBuf.iterator
protected final val _messageBuf = mutable.ArrayBuffer.empty[String]
+ final def messages: Iterator[String] = _messageBuf.iterator
+
+ private[this] var _didCrash = false
+ final def compilerCrashed: Boolean = _didCrash
final def flushToFile(): Unit =
_messageBuf
@@ -33,7 +37,6 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
final def flushToStdErr(): Unit =
_messageBuf
.iterator
- .map(_.replaceAll("\u001b\\[.*?m", ""))
.foreach(System.err.println)
final def inlineInfo(pos: SourcePosition): String =
@@ -44,9 +47,17 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
}
else ""
- def echo(msg: String) =
+ def log(msg: String) =
_messageBuf.append(msg)
+ def logStackTrace(thrown: Throwable): Unit = {
+ _didCrash = true
+ val sw = new java.io.StringWriter
+ val pw = new java.io.PrintWriter(sw)
+ thrown.printStackTrace(pw)
+ log(sw.toString)
+ }
+
/** Prints the message with the given position indication. */
def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = {
val msg = messageAndPos(m.contained, m.pos, diagnosticLevel(m))
@@ -73,15 +84,14 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M
_errorBuf.append(m)
printMessageAndPos(m, extra)
}
- case w: Warning =>
- printMessageAndPos(w, extra)
- case _ =>
+ case m =>
+ printMessageAndPos(m, extra)
}
}
}
object TestReporter {
- private[this] lazy val logWriter = {
+ lazy val logWriter = {
val df = new SimpleDateFormat("yyyy-MM-dd-HH:mm")
val timestamp = df.format(new Date)
new JFile("../testlogs").mkdirs()
diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
index e1babfb9c..82a15c4a4 100644
--- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
+++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
@@ -183,12 +183,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
/** Each `Test` takes the `testSources` and performs the compilation and assertions
* according to the implementing class "neg", "run" or "pos".
*/
- private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) {
+ private abstract class Test(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) { test =>
protected final val realStdout = System.out
protected final val realStderr = System.err
+ /** A runnable that logs its contents in a buffer */
+ trait LoggedRunnable extends Runnable {
+ import TestReporter.logWriter
+
+ /** Instances of `LoggedRunnable` implement this method instead of the
+ * `run` method
+ */
+ def checkTestSource(): Unit
+
+ private[this] val logBuffer = mutable.ArrayBuffer.empty[String]
+ def log(msg: String): Unit = logBuffer.append(msg)
+
+ def logReporterContents(reporter: TestReporter): Unit =
+ reporter.messages.foreach(log)
+
+ def echo(msg: String): Unit = {
+ log(msg)
+ test.echo(msg)
+ }
+
+ final def run(): Unit = {
+ checkTestSource()
+ logBuffer.iterator.foreach(logWriter.println)
+ logWriter.flush()
+ }
+ }
+
/** Actual compilation run logic, the test behaviour is defined here */
- protected def compilationRunnable(testSource: TestSource): Runnable
+ protected def encapsulatedCompilation(testSource: TestSource): LoggedRunnable
/** All testSources left after filtering out */
private val filteredSources =
@@ -220,7 +247,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
protected[this] final def fail(): Unit = synchronized { _failed = true }
def didFail: Boolean = _failed
- protected def echoBuildInstructions(reporter: TestReporter, testSource: TestSource, err: Int, war: Int) = {
+ protected def logBuildInstructions(reporter: TestReporter, testSource: TestSource, err: Int, war: Int) = {
val errorMsg = testSource.buildInstructions(reporter.errorCount, reporter.warningCount)
addFailureInstruction(errorMsg)
failTestSource(testSource)
@@ -278,7 +305,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
*/
protected def tryCompile(testSource: TestSource)(op: => Unit): Unit =
try {
- if (!isInteractive) realStdout.println(s"Testing ${testSource.title}")
+ val testing = s"Testing ${testSource.title}"
+ TestReporter.logWriter.println(testing)
+ if (!isInteractive) realStdout.println(testing)
op
} catch {
case NonFatal(e) => {
@@ -342,10 +371,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
}
val allArgs = addOutDir(flags)
- driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
- val javaFiles = files.filter(_.getName.endsWith(".java")).map(_.getAbsolutePath)
- assert(compileWithJavac(javaFiles), s"java compilation failed for ${javaFiles.mkString(", ")}")
+ // Compile with a try to catch any StackTrace generated by the compiler:
+ try {
+ driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
+
+ val javaFiles = files.filter(_.getName.endsWith(".java")).map(_.getAbsolutePath)
+ assert(compileWithJavac(javaFiles), s"java compilation failed for ${javaFiles.mkString(", ")}")
+ }
+ catch {
+ case NonFatal(ex) => reporter.logStackTrace(ex)
+ }
reporter
}
@@ -362,7 +398,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
if (isInteractive && !suppressAllOutput) pool.submit(createProgressMonitor)
filteredSources.foreach { target =>
- pool.submit(compilationRunnable(target))
+ pool.submit(encapsulatedCompilation(target))
}
pool.shutdown()
@@ -392,22 +428,25 @@ trait ParallelTesting extends RunnerOrchestration { self =>
private final class PosTest(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
extends Test(testSources, times, threadLimit, suppressAllOutput) {
- protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
- def run(): Unit = tryCompile(testSource) {
+ protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
+ def checkTestSource(): Unit = tryCompile(testSource) {
testSource match {
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
val reporter = compile(testSource.sourceFiles, flags, false, outDir)
registerCompletion(reporter.errorCount)
- if (reporter.errorCount > 0)
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ if (reporter.compilerCrashed || reporter.errorCount > 0) {
+ logReporterContents(reporter)
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ }
}
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
val reporters = testSource.compilationGroups.map(files => compile(files, flags, false, outDir))
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
val errorCount = reporters.foldLeft(0) { (acc, reporter) =>
if (reporter.errorCount > 0)
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
acc + reporter.errorCount
}
@@ -416,8 +455,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
registerCompletion(errorCount)
- if (errorCount > 0)
- echoBuildInstructions(reporters.head, testSource, errorCount, warningCount)
+ if (compilerCrashed || errorCount > 0) {
+ reporters.foreach(logReporterContents)
+ logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
+ }
}
}
}
@@ -483,9 +524,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
}
}
- protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
- def run(): Unit = tryCompile(testSource) {
- val (errorCount, warningCount, hasCheckFile, verifier: Function0[Unit]) = testSource match {
+ protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
+ def checkTestSource(): Unit = tryCompile(testSource) {
+ val (compilerCrashed, errorCount, warningCount, hasCheckFile, verifier: Function0[Unit]) = testSource match {
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
val checkFile = files.flatMap { file =>
if (file.isDirectory) Nil
@@ -498,33 +539,37 @@ trait ParallelTesting extends RunnerOrchestration { self =>
}.headOption
val reporter = compile(testSource.sourceFiles, flags, false, outDir)
- if (reporter.errorCount > 0)
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ if (reporter.compilerCrashed || reporter.errorCount > 0) {
+ logReporterContents(reporter)
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ }
- (reporter.errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
+ (reporter.compilerCrashed, reporter.errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
}
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
val checkFile = new JFile(dir.getAbsolutePath.reverse.dropWhile(_ == '/').reverse + ".check")
+ val reporters = testSource.compilationGroups.map(compile(_, flags, false, outDir))
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
val (errorCount, warningCount) =
- testSource
- .compilationGroups
- .map(compile(_, flags, false, outDir))
- .foldLeft((0,0)) { case ((errors, warnings), reporter) =>
- if (reporter.errorCount > 0)
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
+ reporters.foldLeft((0,0)) { case ((errors, warnings), reporter) =>
+ if (reporter.errorCount > 0)
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
- (errors + reporter.errorCount, warnings + reporter.warningCount)
- }
+ (errors + reporter.errorCount, warnings + reporter.warningCount)
+ }
- if (errorCount > 0) fail()
+ if (errorCount > 0) {
+ reporters.foreach(logReporterContents)
+ logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
+ }
- (errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
+ (compilerCrashed, errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
}
}
- if (errorCount == 0 && hasCheckFile) verifier()
- else if (errorCount == 0) {
+ if (!compilerCrashed && errorCount == 0 && hasCheckFile) verifier()
+ else if (!compilerCrashed && errorCount == 0) {
if (Properties.testsNoRun) addNoRunWarning()
else runMain(testSource.classPath) match {
case Success(_) => // success!
@@ -537,17 +582,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
failTestSource(testSource, Some("test timed out"))
}
}
- else if (errorCount > 0) {
+ else {
echo(s"\n Compilation failed for: '$testSource'")
val buildInstr = testSource.buildInstructions(errorCount, warningCount)
addFailureInstruction(buildInstr)
failTestSource(testSource)
}
- else {
- realStdout.println("Got a super weird error that I haven't handled yet")
- realStdout.println("errorCount: " + errorCount)
- realStdout.println("test: " + testSource.title + " " + testSource.name)
- }
registerCompletion(errorCount)
}
}
@@ -555,8 +595,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
private final class NegTest(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
extends Test(testSources, times, threadLimit, suppressAllOutput) {
- protected def compilationRunnable(testSource: TestSource): Runnable = new Runnable {
- def run(): Unit = tryCompile(testSource) {
+ protected def encapsulatedCompilation(testSource: TestSource) = new LoggedRunnable {
+ def checkTestSource(): Unit = tryCompile(testSource) {
// In neg-tests we allow two types of error annotations,
// "nopos-error" which doesn't care about position and "error" which
// has to be annotated on the correct line number.
@@ -608,27 +648,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
}
}
- val (expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
+ val (compilerCrashed, expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
case testSource @ JointCompilationSource(_, files, flags, outDir) => {
val sourceFiles = testSource.sourceFiles
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(sourceFiles)
val reporter = compile(sourceFiles, flags, true, outDir)
val actualErrors = reporter.errorCount
- (expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
+ if (reporter.compilerCrashed || actualErrors > 0)
+ logReporterContents(reporter)
+
+ (reporter.compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
}
case testSource @ SeparateCompilationSource(_, dir, flags, outDir) => {
val compilationGroups = testSource.compilationGroups
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(compilationGroups.toArray.flatten)
val reporters = compilationGroups.map(compile(_, flags, true, outDir))
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
val actualErrors = reporters.foldLeft(0)(_ + _.errorCount)
val errors = reporters.iterator.flatMap(_.errors)
- (expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
+
+ if (actualErrors > 0)
+ reporters.foreach(logReporterContents)
+
+ (compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
}
}
- if (expectedErrors != actualErrors) {
+ if (compilerCrashed) {
+ echo(s"Compiler crashed when compiling: ${testSource.title}")
+ failTestSource(testSource)
+ }
+ else if (expectedErrors != actualErrors) {
echo {
s"\nWrong number of errors encountered when compiling $testSource, expected: $expectedErrors, actual: $actualErrors\n"
}
diff --git a/compiler/test/dotty/tools/vulpix/SummaryReport.java b/compiler/test/dotty/tools/vulpix/SummaryReport.java
index 23209eefc..b7aa423ff 100644
--- a/compiler/test/dotty/tools/vulpix/SummaryReport.java
+++ b/compiler/test/dotty/tools/vulpix/SummaryReport.java
@@ -2,6 +2,7 @@ package dotty.tools.vulpix;
import org.junit.BeforeClass;
import org.junit.AfterClass;
+import java.util.Iterator;
import java.util.ArrayDeque;
import java.util.function.Supplier;
import scala.Function0;
@@ -75,7 +76,7 @@ public class SummaryReport {
}
@AfterClass public final static void teardown() {
- rep.echo(
+ rep.log(
"\n================================================================================" +
"\nTest Report" +
"\n================================================================================" +
@@ -86,26 +87,26 @@ public class SummaryReport {
startingMessages
.stream()
- .forEach(rep::echo);
+ .forEach(rep::log);
failedTests
.stream()
.map(x -> " " + x)
- .forEach(rep::echo);
+ .forEach(rep::log);
// If we're compiling locally, we don't need reproduce instructions
if (isInteractive) rep.flushToStdErr();
- rep.echo("");
+ rep.log("");
reproduceInstructions
.stream()
- .forEach(rep::echo);
+ .forEach(rep::log);
// If we're on the CI, we want everything
if (!isInteractive) rep.flushToStdErr();
- if (failed > 0) rep.flushToFile();
+ rep.flushToFile();
// Perform cleanup callback:
if (cleanup != null) cleanup.get();