Open
Description
I've been toying with an idea to use string interpolation to embed have strongly typed positioned assertions in fragments of source code within JUnit tests. Documenting this here for discussion.
scala> class TestContext() {
| val markers = scala.collection.mutable.Buffer[Pos]()
| final class Pos() {
| markers += this
| var pos: Int = -1
| def hasCompletions(alts: String*): this.type = {
| // this.assertions += () => this.global.completionsAt(pos).containsAll(alts)
| this
| }
| def check(): Unit = ()
| }
| def check() = markers.foreach(_.check)
| implicit class StringContext_code(private val value: StringContext) {
| def code(names: Pos*): String = {
| var pos = 0
| value.parts.zipWithIndex.foreach { case (part, i) =>
| pos += part.length
| if (i > 0) names(i - 1).pos = pos
| }
| value.parts.mkString
| }
| }
| }
defined class TestContext
scala> def mkContext = new TestContext()
mkContext: TestContext
scala>
scala> val c = mkContext; import c._
c: TestContext = TestContext@14c99bf6
import c._
scala> val m1, m2, m3 = new Pos
m1: c.Pos = TestContext$Pos@661e1399
m2: c.Pos = TestContext$Pos@3ffd4b12
m3: c.Pos = TestContext$Pos@424f02b8
scala> val code: String =
| code"""
| class C {
| def foo = "".reverse${m1}.reverse$m2.rev${m3.hasCompletions("reverse")}
| }
| """
code: String =
"
class C {
def foo = "".reverse.reverse.rev
}
"
scala> m2.hasCompletions("charAt")
res0: m2.type = TestContext$Pos@3ffd4b12
scala> c.markers.foreach(m => println(m.pos))
49
53
64
scala> c.check()
This is an alternative to the "magic comment markers" used in the presentation compiler tests, and is more general than the approach taken in https://github.com/scala/scala/blob/2.12.x/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala#L31
Different test use cases could add extension methods to Pos
to work with different fragments of testing DSL.