Skip to content

Commit 1a8c26c

Browse files
committed
Add testing of new test framework
1 parent 35fb01d commit 1a8c26c

13 files changed

+188
-49
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dotty
2+
package tools
3+
package dotc
4+
5+
import org.junit.Assert._
6+
import org.junit.Test
7+
8+
import scala.util.control.NonFatal
9+
10+
class ParallelTestTests extends ParallelTesting {
11+
import CompilationTests._
12+
13+
def interactive: Boolean = !sys.env.contains("DRONE")
14+
15+
@Test def missingFile: Unit =
16+
try {
17+
compileFile("../tests/partest-test/i-dont-exist.scala", defaultOptions).expectFailure.neg()
18+
fail("didn't fail properly")
19+
}
20+
catch {
21+
case _: IllegalArgumentException => // pass!
22+
case NonFatal(_) => fail("wrong exception thrown")
23+
}
24+
25+
@Test def pos1Error: Unit =
26+
compileFile("../tests/partest-test/posFail1Error.scala", defaultOptions).expectFailure.pos()
27+
28+
@Test def negMissingAnnot: Unit =
29+
compileFile("../tests/partest-test/negMissingAnnot.scala", defaultOptions).expectFailure.neg()
30+
31+
@Test def negAnnotWrongLine: Unit =
32+
compileFile("../tests/partest-test/negAnnotWrongLine.scala", defaultOptions).expectFailure.neg()
33+
34+
@Test def negTooManyAnnots: Unit =
35+
compileFile("../tests/partest-test/negTooManyAnnots.scala", defaultOptions).expectFailure.neg()
36+
37+
@Test def negNoPositionAnnot: Unit =
38+
compileFile("../tests/partest-test/negNoPositionAnnots.scala", defaultOptions).expectFailure.neg()
39+
40+
@Test def runCompileFail: Unit =
41+
compileFile("../tests/partest-test/posFail1Error.scala", defaultOptions).expectFailure.run()
42+
43+
@Test def runWrongOutput1: Unit =
44+
compileFile("../tests/partest-test/runWrongOutput1.scala", defaultOptions).expectFailure.run()
45+
46+
@Test def runWrongOutput2: Unit =
47+
compileFile("../tests/partest-test/runWrongOutput2.scala", defaultOptions).expectFailure.run()
48+
49+
@Test def runDiffOutput1: Unit =
50+
compileFile("../tests/partest-test/runDiffOutput1.scala", defaultOptions).expectFailure.run()
51+
}

compiler/test/dotty/tools/dotc/ParallelTesting.scala

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ trait ParallelTesting {
2929
def outDir: JFile
3030
def flags: Array[String]
3131

32-
def withFlags(newFlags: Array[String]) =
32+
def withFlags(newFlags0: String*) = {
33+
val newFlags = newFlags0.toArray
3334
if (!flags.containsSlice(newFlags)) self match {
3435
case self: ConcurrentCompilationTarget =>
35-
self.copy(flags = newFlags)
36+
self.copy(flags = flags ++ newFlags)
3637
case self: SeparateCompilationTarget =>
37-
self.copy(flags = newFlags)
38+
self.copy(flags = flags ++ newFlags)
3839
}
3940
else self
41+
}
4042

4143
def buildInstructions(errors: Int, warnings: Int): String = {
4244
val sb = new StringBuilder
@@ -114,7 +116,7 @@ trait ParallelTesting {
114116
.toList.sortBy(_._1).map(_._2.filter(isCompilable))
115117
}
116118

117-
private abstract class Test(targets: List[Target], times: Int, threadLimit: Option[Int]) {
119+
private abstract class Test(targets: List[Target], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean) {
118120

119121
/** Actual compilation run logic, the test behaviour is defined here */
120122
protected def compilationRunnable(target: Target): Runnable
@@ -154,6 +156,9 @@ trait ParallelTesting {
154156
fail()
155157
}
156158

159+
protected def echo(msg: String): Unit =
160+
if (!suppressAllOutput) System.err.println(msg)
161+
157162
private def statusRunner: Runnable = new Runnable {
158163
def run(): Unit = {
159164
val start = System.currentTimeMillis
@@ -235,7 +240,8 @@ trait ParallelTesting {
235240
val javaCompiledBefore = compileWithJavac(javaFiles)
236241

237242
// Then we compile the scala files:
238-
val reporter = TestReporter.parallelReporter(this, logLevel = if (suppressErrors) ERROR + 1 else ERROR)
243+
val reporter = TestReporter.parallelReporter(this, logLevel =
244+
if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR)
239245
val driver =
240246
if (times == 1) new Driver { def newCompiler(implicit ctx: Context) = new Compiler }
241247
else new Driver {
@@ -270,7 +276,7 @@ trait ParallelTesting {
270276
case None => JExecutors.newWorkStealingPool()
271277
}
272278

273-
if (interactive) pool.submit(statusRunner)
279+
if (interactive && !suppressAllOutput) pool.submit(statusRunner)
274280

275281
targets.foreach { target =>
276282
pool.submit(compilationRunnable(target))
@@ -281,15 +287,15 @@ trait ParallelTesting {
281287
throw new TimeoutException("Compiling targets timed out")
282288

283289
if (didFail) {
284-
System.err.println {
290+
echo {
285291
"""|
286292
|================================================================================
287293
|Test Report
288294
|================================================================================
289295
|Failing tests:""".stripMargin
290296
}
291-
failedCompilationTargets.toArray.sorted.foreach(System.err.println)
292-
failureInstructions.iterator.foreach(System.err.println)
297+
failedCompilationTargets.toArray.sorted.foreach(echo)
298+
failureInstructions.iterator.foreach(echo)
293299
}
294300

295301
this
@@ -301,8 +307,8 @@ trait ParallelTesting {
301307
name.endsWith(".scala") || name.endsWith(".java")
302308
}
303309

304-
private final class PosTest(targets: List[Target], times: Int, threadLimit: Option[Int])
305-
extends Test(targets, times, threadLimit) {
310+
private final class PosTest(targets: List[Target], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
311+
extends Test(targets, times, threadLimit, suppressAllOutput) {
306312
protected def compilationRunnable(target: Target): Runnable = new Runnable {
307313
def run(): Unit = compileTry {
308314
target match {
@@ -345,8 +351,8 @@ trait ParallelTesting {
345351
}
346352
}
347353

348-
private final class RunTest(targets: List[Target], times: Int, threadLimit: Option[Int])
349-
extends Test(targets, times, threadLimit) {
354+
private final class RunTest(targets: List[Target], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
355+
extends Test(targets, times, threadLimit, suppressAllOutput) {
350356
private def verifyOutput(checkFile: JFile, dir: JFile, target: Target, warnings: Int) = try {
351357
// Do classloading magic and running here:
352358
import java.net.{ URL, URLClassLoader }
@@ -374,7 +380,7 @@ trait ParallelTesting {
374380
DiffUtil.mkColoredCodeDiff(exp, act, true)
375381
}.mkString("\n")
376382
val msg = s"\nOutput from run test '$checkFile' did not match expected, output:\n$diff\n"
377-
System.err.println(msg)
383+
echo(msg)
378384
addFailureInstruction(msg)
379385

380386
// Print build instructions to file and summary:
@@ -387,15 +393,15 @@ trait ParallelTesting {
387393
}
388394
catch {
389395
case _: NoSuchMethodException =>
390-
System.err.println(s"\ntest in '$dir' did not contain a main method")
396+
echo(s"\ntest in '$dir' did not contain a main method")
391397
fail()
392398

393399
case _: ClassNotFoundException =>
394-
System.err.println(s"\ntest in '$dir' did was not contained within a `Test` object")
400+
echo(s"\ntest in '$dir' did was not contained within a `Test` object")
395401
fail()
396402

397403
case _: InvocationTargetException =>
398-
System.err.println(s"\nTest in '$dir' might be using args(X) where X > 0")
404+
echo(s"\nTest in '$dir' might be using args(X) where X > 0")
399405
fail()
400406
}
401407

@@ -454,7 +460,7 @@ trait ParallelTesting {
454460

455461
if (errorCount == 0 && hasCheckFile) doVerify()
456462
else if (errorCount > 0) {
457-
System.err.println(s"\nCompilation failed for: '$target'")
463+
echo(s"\nCompilation failed for: '$target'")
458464
val buildInstr = target.buildInstructions(errorCount, warningCount)
459465
addFailureInstruction(buildInstr)
460466
failTarget(target)
@@ -463,8 +469,8 @@ trait ParallelTesting {
463469
}
464470
}
465471

466-
private final class NegTest(targets: List[Target], times: Int, threadLimit: Option[Int])
467-
extends Test(targets, times, threadLimit) {
472+
private final class NegTest(targets: List[Target], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)
473+
extends Test(targets, times, threadLimit, suppressAllOutput) {
468474
protected def compilationRunnable(target: Target): Runnable = new Runnable {
469475
def run(): Unit = compileTry {
470476
// In neg-tests we allow two types of error annotations,
@@ -511,7 +517,7 @@ trait ParallelTesting {
511517
true
512518
}
513519
else {
514-
System.err.println {
520+
echo {
515521
s"Error reported in ${error.pos.source}, but no annotation found"
516522
}
517523
false
@@ -539,19 +545,19 @@ trait ParallelTesting {
539545
}
540546

541547
if (expectedErrors != actualErrors) {
542-
System.err.println {
548+
echo {
543549
s"\nWrong number of errors encountered when compiling $target, expected: $expectedErrors, actual: $actualErrors\n"
544550
}
545551
failTarget(target)
546552
}
547553
else if (hasMissingAnnotations()) {
548-
System.err.println {
554+
echo {
549555
s"\nErrors found on incorrect row numbers when compiling $target"
550556
}
551557
failTarget(target)
552558
}
553559
else if (!errorMap.isEmpty) {
554-
System.err.println {
560+
echo {
555561
s"\nError annotation(s) have {<error position>=<unreported error>}: $errorMap"
556562
}
557563
failTarget(target)
@@ -566,39 +572,64 @@ trait ParallelTesting {
566572
private[ParallelTesting] val targets: List[Target],
567573
private[ParallelTesting] val times: Int,
568574
private[ParallelTesting] val shouldDelete: Boolean,
569-
private[ParallelTesting] val threadLimit: Option[Int]
575+
private[ParallelTesting] val threadLimit: Option[Int],
576+
private[ParallelTesting] val shouldFail: Boolean
570577
) {
578+
import org.junit.Assert.fail
579+
571580
private[ParallelTesting] def this(target: Target) =
572-
this(List(target), 1, true, None)
581+
this(List(target), 1, true, None, false)
573582

574583
private[ParallelTesting] def this(targets: List[Target]) =
575-
this(targets, 1, true, None)
584+
this(targets, 1, true, None, false)
576585

577586
def +(other: CompilationTest) = {
578587
require(other.times == times, "can't combine tests that are meant to be benchmark compiled")
579588
require(other.shouldDelete == shouldDelete, "can't combine tests that differ on deleting output")
580-
new CompilationTest(targets ++ other.targets, times, shouldDelete, threadLimit)
589+
require(other.shouldFail == shouldFail, "can't combine tests that have different expectations on outcome")
590+
new CompilationTest(targets ++ other.targets, times, shouldDelete, threadLimit, shouldFail)
581591
}
582592

583593
def pos(): this.type = {
584-
val runErrors = new PosTest(targets, times, threadLimit).execute().errors
585-
assert(runErrors == 0, s"Expected no errors when compiling")
586-
if (shouldDelete) targets.foreach(t => delete(t.outDir))
587-
this
594+
val test = new PosTest(targets, times, threadLimit, shouldFail).execute()
595+
596+
if (!shouldFail && test.didFail) {
597+
fail(s"Expected no errors when compiling, but found: ${test.errors}")
598+
}
599+
else if (shouldFail && !test.didFail) {
600+
fail("Pos test should have failed, but didn't")
601+
}
602+
603+
cleanup()
588604
}
589605

590606
def neg(): this.type = {
591-
assert(
592-
!(new NegTest(targets, times, threadLimit).execute().didFail),
593-
s"Wrong number of errors encountered when compiling"
594-
)
595-
if (shouldDelete) targets.foreach(t => delete(t.outDir))
596-
this
607+
val test = new NegTest(targets, times, threadLimit, shouldFail).execute()
608+
609+
if (!shouldFail && test.didFail) {
610+
fail("Neg test shouldn't have failed, but did")
611+
}
612+
else if (shouldFail && !test.didFail) {
613+
fail("Neg test should have failed, but did not")
614+
}
615+
616+
cleanup()
597617
}
598618

599619
def run(): this.type = {
600-
val didFail = new RunTest(targets, times, threadLimit).execute().didFail
601-
assert(!didFail, s"Run tests failed")
620+
val test = new RunTest(targets, times, threadLimit, shouldFail).execute()
621+
622+
if (!shouldFail && test.didFail) {
623+
fail("Run test failed, but should not")
624+
}
625+
else if (shouldFail && !test.didFail) {
626+
fail("Run test should have failed, but did not")
627+
}
628+
629+
cleanup()
630+
}
631+
632+
private def cleanup(): this.type = {
602633
if (shouldDelete) targets.foreach(t => delete(t.outDir))
603634
this
604635
}
@@ -617,24 +648,25 @@ trait ParallelTesting {
617648
case target @ SeparateCompilationTarget(dir, _, outDir) =>
618649
target.copy(dir = copyToDir(outDir, dir))
619650
},
620-
times, shouldDelete, threadLimit
651+
times, shouldDelete, threadLimit, shouldFail
621652
)
622653

623654
def times(i: Int): CompilationTest =
624-
new CompilationTest(targets, i, shouldDelete, threadLimit)
655+
new CompilationTest(targets, i, shouldDelete, threadLimit, shouldFail)
625656

626657
def verbose: CompilationTest = new CompilationTest(
627-
targets.map(t => t.withFlags(t.flags ++ Array("-verbose", "-Ylog-classpath"))),
628-
times,
629-
shouldDelete,
630-
threadLimit
658+
targets.map(t => t.withFlags("-verbose", "-Ylog-classpath")),
659+
times, shouldDelete, threadLimit, shouldFail
631660
)
632661

633662
def keepOutput: CompilationTest =
634-
new CompilationTest(targets, times, false, threadLimit)
663+
new CompilationTest(targets, times, false, threadLimit, shouldFail)
664+
665+
def limitThreads(i: Int): CompilationTest =
666+
new CompilationTest(targets, times, shouldDelete, Some(i), shouldFail)
635667

636-
def limitThreads(i: Int) =
637-
new CompilationTest(targets, times, shouldDelete, Some(i))
668+
def expectFailure: CompilationTest =
669+
new CompilationTest(targets, times, shouldDelete, threadLimit, true)
638670

639671
def delete(): Unit = targets.foreach(t => delete(t.outDir))
640672

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Foo { // error
2+
def bar: Int = "LOL"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Foo extends Bar
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Foo {
2+
def bar: Int = "LOL"
3+
4+
// nopos-error
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
def foo: Int = "LOL" // error // error
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test extends Bar {
2+
def main(args: Array[String]): Unit = ()
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
1
2+
2
3+
4
4+
4
5+
5
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
println(1)
4+
println(2)
5+
println(3)
6+
println(4)
7+
println(5)
8+
}
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
1
2+
2
3+
3
4+
4
5+
5
6+
6
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
println(1)
4+
println(2)
5+
println(3)
6+
println(4)
7+
println(5)
8+
}
9+
}

0 commit comments

Comments
 (0)