Skip to content

Commit 4f5ae4c

Browse files
committed
test: add in a CodeActionTest suite
1 parent 3a6c368 commit 4f5ae4c

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package dotty.tools.dotc.reporting
2+
3+
import dotty.tools.DottyTest
4+
import dotty.tools.dotc.rewrites.Rewrites
5+
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch
6+
import dotty.tools.dotc.util.SourceFile
7+
8+
import scala.annotation.tailrec
9+
import scala.jdk.CollectionConverters.*
10+
import scala.runtime.Scala3RunTime.assertFailed
11+
12+
import org.junit.Assert._
13+
import org.junit.Test
14+
15+
/** This is a test suite that is meant to test the actions attached to the
16+
* diagnostic for a given code snippet.
17+
*/
18+
class CodeActionTest extends DottyTest:
19+
20+
@Test def convertToFunctionValue =
21+
checkCodeAction(
22+
"""|object Test:
23+
| def x: Int = 3
24+
| val test = x _
25+
|""".stripMargin,
26+
"Rewrite to function value",
27+
"""|object Test:
28+
| def x: Int = 3
29+
| val test = (() => x)
30+
|""".stripMargin
31+
)
32+
33+
// Make sure we're not using the default reporter, which is the ConsoleReporter,
34+
// meaning they will get reported in the test run and that's it.
35+
private def newContext =
36+
val rep = new StoreReporter(null) with UniqueMessagePositions with HideNonSensicalMessages
37+
initialCtx.setReporter(rep).withoutColors
38+
39+
private def checkCodeAction(code: String, title: String, expected: String) =
40+
ctx = newContext
41+
val source = SourceFile.virtual("test", code).content
42+
val runCtx = checkCompile("typer", code) { (_, _) => () }
43+
val diagnostics = runCtx.reporter.removeBufferedMessages
44+
assertEquals(diagnostics.size, 1)
45+
46+
val diagnostic = diagnostics.head
47+
val actions = diagnostic.msg.actions.asScala.toList
48+
assertEquals(actions.size, 1)
49+
50+
// TODO account for more than 1 action
51+
val action = actions.head
52+
assertEquals(action.title, title)
53+
val patches = action.patches.asScala.toList
54+
if patches.nonEmpty then
55+
patches.reduceLeft: (p1, p2) =>
56+
assert(p1.srcPos.span.end <= p2.srcPos.span.start, s"overlapping patches $p1 and $p2")
57+
p2
58+
else assertFailed("Expected a patch attatched to this action, but it was empty")
59+
60+
val delta = patches
61+
.map: patch =>
62+
patch.replacement.length - (patch.srcPos.end - patch.srcPos.start)
63+
.sum
64+
65+
val result = new Array[Char](source.length + delta)
66+
67+
@tailrec def loop(ps: List[ActionPatch], inIdx: Int, outIdx: Int): Unit =
68+
def copy(upTo: Int): Int =
69+
val untouched = upTo - inIdx
70+
System.arraycopy(source, inIdx, result, outIdx, untouched)
71+
outIdx + untouched
72+
73+
ps match
74+
case patch @ ActionPatch(srcPos, replacement) :: ps1 =>
75+
val outNew = copy(srcPos.start)
76+
replacement.copyToArray(result, outNew)
77+
loop(ps1, srcPos.end, outNew + replacement.length)
78+
case Nil =>
79+
val outNew = copy(source.length)
80+
assert(outNew == result.length, s"$outNew != ${result.length}")
81+
82+
loop(patches, 0, 0)
83+
assertEquals(result.mkString, expected)

0 commit comments

Comments
 (0)