scala-dev icon indicating copy to clipboard operation
scala-dev copied to clipboard

Testing DSL idea: Use string interpolation to mark positions in source code with strong typing.

Open retronym opened this issue 8 years ago • 2 comments
trafficstars

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.

retronym avatar Jun 08 '17 02:06 retronym

/cc

@fommil (author of https://github.com/ensime/pcplod) @alefas / @pavelfatin who've written a variety of test DSL for IntellIJs typechecker @smarter @DarkDimius for a perspective from dotty

retronym avatar Jun 08 '17 02:06 retronym

Pretty cool, IMO.

dwijnand avatar Oct 16 '20 16:10 dwijnand