Skip to content

Commit e9c4942

Browse files
authored
Merge pull request #1966 from dotty-staging/topic/error-messages-unit-tests
Fix #1965: add proper testing infrastructure for reporting tests
2 parents 75bea8d + 07384ca commit e9c4942

File tree

5 files changed

+121
-4
lines changed

5 files changed

+121
-4
lines changed

compiler/test/dotty/tools/DottyTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import dotc.Compiler
1414

1515
import dotc.core.Phases.Phase
1616

17-
class DottyTest extends ContextEscapeDetection{
17+
trait DottyTest extends ContextEscapeDetection {
1818

1919
dotc.parsing.Scanners // initialize keywords
2020

compiler/test/dotty/tools/DottyTypeStealer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import dotc.core.Contexts.Context
77
import dotc.core.Decorators._
88
import dotc.core.Types.Type
99

10-
object DottyTypeStealer {
10+
object DottyTypeStealer extends DottyTest {
1111
def stealType(source: String, typeStrings: String*): (Context, List[Type]) = {
1212
val dummyName = "x_x_x"
1313
val vals = typeStrings.zipWithIndex.map{case (s, x)=> s"val ${dummyName}$x: $s = ???"}.mkString("\n")
1414
val gatheredSource = s" ${source}\n object A$dummyName {$vals}"
1515
var scontext : Context = null
1616
var tp: List[Type] = null
17-
new DottyTest().checkCompile("frontend",gatheredSource) {
17+
checkCompile("frontend",gatheredSource) {
1818
(tree, context) =>
1919
implicit val ctx = context
2020
val findValDef: (List[ValDef], tpd.Tree) => List[ValDef] =

compiler/test/dotty/tools/dotc/parsing/DocstringTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ trait DocstringTest extends DottyTest {
2727

2828
def checkFrontend(source: String)(docAssert: PartialFunction[Tree[Untyped], Unit]) = {
2929
checkCompile("frontend", source) { (_, ctx) =>
30-
implicit val c = ctx
30+
implicit val c: Context = ctx
3131
(docAssert orElse defaultAssertion)(ctx.compilationUnit.untpdTree)
3232
}
3333
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package dotty.tools
2+
package dotc
3+
package reporting
4+
5+
import diagnostic._
6+
import core.Contexts.Context
7+
8+
import scala.collection.mutable
9+
10+
import org.junit.Assert._
11+
12+
trait ErrorMessagesTest extends DottyTest {
13+
14+
ctx = freshReporter(ctx)
15+
16+
private def freshReporter(ctx: Context) =
17+
ctx.fresh.setReporter(new CapturingReporter)
18+
19+
20+
class Report(messages: List[Message], ictx: Context) {
21+
def expect(f: (Context, List[Message]) => Unit): Unit = {
22+
f(ictx, messages)
23+
}
24+
25+
def expectNoErrors: Unit =
26+
assert(this.isInstanceOf[EmptyReport], "errors found when not expected")
27+
}
28+
29+
class EmptyReport extends Report(Nil, null) {
30+
override def expect(f: (Context, List[Message]) => Unit) =
31+
fail("""|
32+
|Couldn't capture errors from compiled sources, this can happen if
33+
|there are no errors or the compiler crashes.""".stripMargin)
34+
}
35+
36+
class CapturingReporter extends Reporter
37+
with UniqueMessagePositions with HideNonSensicalMessages {
38+
private[this] val buffer = new mutable.ListBuffer[Message]
39+
private[this] var capturedContext: Context = _
40+
41+
def doReport(m: MessageContainer)(implicit ctx: Context) = {
42+
capturedContext = ctx
43+
buffer append m.contained
44+
}
45+
46+
def toReport: Report =
47+
if (capturedContext eq null)
48+
new EmptyReport
49+
else {
50+
val xs = buffer.reverse.toList
51+
buffer.clear()
52+
53+
val ctx = capturedContext
54+
capturedContext = null
55+
56+
new Report(xs, ctx)
57+
}
58+
}
59+
60+
def checkMessages(source: String): Report = {
61+
checkCompile("frontend", source) { (_,ictx) => () }
62+
val rep = ctx.reporter.asInstanceOf[CapturingReporter].toReport
63+
ctx = freshReporter(ctx)
64+
rep
65+
}
66+
67+
def assertMessageCount(expected: Int, messages: List[Message]): Unit =
68+
assertEquals(
69+
expected,
70+
messages.length
71+
)
72+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package dotty.tools
2+
package dotc
3+
package reporting
4+
5+
import core.Contexts.Context
6+
import diagnostic.messages._
7+
8+
import org.junit.Assert._
9+
import org.junit.Test
10+
11+
class ErrorMessagesTests extends ErrorMessagesTest {
12+
// In the case where there are no errors, we can do "expectNoErrors" in the
13+
// `Report`
14+
@Test def noErrors =
15+
checkMessages("""class Foo""")
16+
.expectNoErrors
17+
18+
@Test def typeMismatch =
19+
checkMessages {
20+
"""
21+
|object Foo {
22+
| def bar: String = 1
23+
|}
24+
""".stripMargin
25+
}
26+
.expect { (ictx, messages) =>
27+
implicit val ctx: Context = ictx
28+
val defn = ictx.definitions
29+
30+
// Assert that we only got one error message
31+
assertMessageCount(1, messages)
32+
33+
// Pattern match out the expected error
34+
val TypeMismatch(found, expected, _, _) :: Nil = messages
35+
36+
// The type of the right hand side will actually be the constant 1,
37+
// therefore we check if it "derivesFrom" `IntClass`
38+
assert(found.derivesFrom(defn.IntClass), s"found was: $found")
39+
40+
// The expected type is `scala.String` which we dealias to
41+
// `java.lang.String` and compare with `=:=` to `defn.StringType` which
42+
// is a type reference to `java.lang.String`
43+
assert(expected.dealias =:= defn.StringType, s"expected was: $expected")
44+
}
45+
}

0 commit comments

Comments
 (0)