Add tests for analyze return type in REPL IDE services
also refactor existing tests infrastructure
This commit is contained in:
committed by
Ilya Chernikov
parent
8a1b44cc2b
commit
7cde9b4355
+81
-41
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.scripting.ide_services.test_util.toList
|
|||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
|
|
||||||
class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
||||||
@@ -43,7 +45,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
code = "v.mema."
|
code = "v.mema."
|
||||||
cursor = 7
|
cursor = 7
|
||||||
expect {
|
expect {
|
||||||
completionsMode(ComparisonType.INCLUDES)
|
completions.mode(ComparisonType.INCLUDES)
|
||||||
addCompletion("memx", "memx", "Int", "property")
|
addCompletion("memx", "memx", "Int", "property")
|
||||||
addCompletion("memy", "memy", "String", "property")
|
addCompletion("memy", "memy", "String", "property")
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
code = testCode
|
code = testCode
|
||||||
cursor = testCursor ?: testCode.length
|
cursor = testCursor ?: testCode.length
|
||||||
expect {
|
expect {
|
||||||
completionsMode(ComparisonType.EQUALS)
|
completions.mode(ComparisonType.EQUALS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
cursor = 17
|
cursor = 17
|
||||||
code = "import java.lang."
|
code = "import java.lang."
|
||||||
expect {
|
expect {
|
||||||
completionsMode(ComparisonType.INCLUDES)
|
completions.mode(ComparisonType.INCLUDES)
|
||||||
addCompletion("Process", "Process", " (java.lang)", "class")
|
addCompletion("Process", "Process", " (java.lang)", "class")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +175,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
val v = BClass("KKK", AClass(5, "25"))
|
val v = BClass("KKK", AClass(5, "25"))
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
expect {
|
expect {
|
||||||
errorsMode(ComparisonType.EQUALS)
|
errors.mode(ComparisonType.EQUALS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +216,21 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestConf {
|
@Test
|
||||||
|
fun testAnalyze() = test {
|
||||||
|
run {
|
||||||
|
code = """
|
||||||
|
val foo = 42
|
||||||
|
foo
|
||||||
|
""".trimIndent()
|
||||||
|
expect {
|
||||||
|
errors.mode(ComparisonType.EQUALS)
|
||||||
|
resultType = "Int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestConf {
|
||||||
private val runs = mutableListOf<Run>()
|
private val runs = mutableListOf<Run>()
|
||||||
|
|
||||||
fun run(setup: (Run).() -> Unit) {
|
fun run(setup: (Run).() -> Unit) {
|
||||||
@@ -258,29 +274,13 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Expected(private val run: Run) {
|
class Expected(private val run: Run) {
|
||||||
private val variants = mutableListOf<SourceCodeCompletionVariant>()
|
val completions = ExpectedList<SourceCodeCompletionVariant>(run::doComplete)
|
||||||
private var _completionsMode: ComparisonType = ComparisonType.DONT_CHECK
|
|
||||||
fun completionsMode(mode: ComparisonType) {
|
|
||||||
_completionsMode = mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addCompletion(text: String, displayText: String, tail: String, icon: String) {
|
fun addCompletion(text: String, displayText: String, tail: String, icon: String) {
|
||||||
if (_completionsMode == ComparisonType.DONT_CHECK)
|
completions.add(SourceCodeCompletionVariant(text, displayText, tail, icon))
|
||||||
_completionsMode = ComparisonType.EQUALS
|
|
||||||
run.doComplete
|
|
||||||
variants.add(SourceCodeCompletionVariant(text, displayText, tail, icon))
|
|
||||||
}
|
|
||||||
|
|
||||||
private val errors = mutableListOf<ScriptDiagnostic>()
|
|
||||||
private var _errorsMode: ComparisonType = ComparisonType.DONT_CHECK
|
|
||||||
fun errorsMode(mode: ComparisonType) {
|
|
||||||
_errorsMode = mode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val errors = ExpectedList<ScriptDiagnostic>(run::doErrorCheck)
|
||||||
fun addError(startLine: Int, startCol: Int, endLine: Int, endCol: Int, message: String, severity: String) {
|
fun addError(startLine: Int, startCol: Int, endLine: Int, endCol: Int, message: String, severity: String) {
|
||||||
if (_errorsMode == ComparisonType.DONT_CHECK)
|
|
||||||
_errorsMode = ComparisonType.EQUALS
|
|
||||||
run.doErrorCheck
|
|
||||||
errors.add(
|
errors.add(
|
||||||
ScriptDiagnostic(
|
ScriptDiagnostic(
|
||||||
ScriptDiagnostic.unspecifiedError,
|
ScriptDiagnostic.unspecifiedError,
|
||||||
@@ -294,8 +294,10 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resultType: String? by ExpectedNullableVar(run::doErrorCheck)
|
||||||
|
|
||||||
fun collect(): ExpectedResult {
|
fun collect(): ExpectedResult {
|
||||||
return ExpectedResult(variants, _completionsMode, errors, _errorsMode)
|
return ExpectedResult(completions, errors, resultType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,12 +319,46 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
val code: String,
|
val code: String,
|
||||||
val doCompile: Boolean,
|
val doCompile: Boolean,
|
||||||
val doComplete: Boolean,
|
val doComplete: Boolean,
|
||||||
val doErrorCheck: Boolean
|
val doErrorCheck: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class ExpectedList<T>(private val runProperty: KProperty0<Unit>) {
|
||||||
|
val list = mutableListOf<T>()
|
||||||
|
|
||||||
|
private var _compMode = ComparisonType.DONT_CHECK
|
||||||
|
fun mode() = _compMode
|
||||||
|
fun mode(mode: ComparisonType) {
|
||||||
|
_compMode = mode
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(elem: T) {
|
||||||
|
if (_compMode == ComparisonType.DONT_CHECK)
|
||||||
|
_compMode = ComparisonType.EQUALS
|
||||||
|
runProperty.get()
|
||||||
|
list.add(elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExpectedNullableVar<T>(private val runProperty: KProperty0<Unit>) {
|
||||||
|
private var variable: T? = null
|
||||||
|
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? = variable
|
||||||
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||||
|
runProperty.get()
|
||||||
|
variable = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class ExpectedResult(
|
data class ExpectedResult(
|
||||||
val completions: List<SourceCodeCompletionVariant>, val completionsCompType: ComparisonType,
|
val completions: ExpectedList<SourceCodeCompletionVariant>,
|
||||||
val errors: List<ScriptDiagnostic>, val errorsCompType: ComparisonType
|
val errors: ExpectedList<ScriptDiagnostic>,
|
||||||
|
val resultType: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ActualResult(
|
||||||
|
val completions: List<SourceCodeCompletionVariant>,
|
||||||
|
val errors: List<ScriptDiagnostic>,
|
||||||
|
val resultType: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val currentLineCounter = AtomicInteger()
|
private val currentLineCounter = AtomicInteger()
|
||||||
@@ -336,9 +372,9 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
private suspend fun evaluateInRepl(
|
private suspend fun evaluateInRepl(
|
||||||
compilationConfiguration: ScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration,
|
||||||
snippets: List<RunRequest>
|
snippets: List<RunRequest>
|
||||||
): List<ResultWithDiagnostics<Pair<List<SourceCodeCompletionVariant>, List<ScriptDiagnostic>>>> {
|
): List<ResultWithDiagnostics<ActualResult>> {
|
||||||
val compiler = KJvmReplCompilerWithIdeServices()
|
val compiler = KJvmReplCompilerWithIdeServices()
|
||||||
return snippets.map { (cursor, snippetText, doComplile, doComplete, doErrorCheck) ->
|
return snippets.map { (cursor, snippetText, doCompile, doComplete, doErrorCheck) ->
|
||||||
val pos = SourceCode.Position(0, 0, cursor)
|
val pos = SourceCode.Position(0, 0, cursor)
|
||||||
val codeLine = nextCodeLine(snippetText)
|
val codeLine = nextCodeLine(snippetText)
|
||||||
val completionRes = if (doComplete && cursor != null) {
|
val completionRes = if (doComplete && cursor != null) {
|
||||||
@@ -348,19 +384,22 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val errorsRes = if (doErrorCheck) {
|
val analysisResult = if (doErrorCheck) {
|
||||||
val codeLineForErrorCheck = nextCodeLine(snippetText)
|
val codeLineForErrorCheck = nextCodeLine(snippetText)
|
||||||
compiler.analyze(codeLineForErrorCheck, SourceCode.Position(0, 0), compilationConfiguration).toList()
|
compiler.analyze(codeLineForErrorCheck, SourceCode.Position(0, 0), compilationConfiguration).valueOrNull()
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
null
|
||||||
}
|
}?: ReplAnalyzerResult()
|
||||||
|
|
||||||
if (doComplile) {
|
val errorsSequence = analysisResult[ReplAnalyzerResult.analysisDiagnostics]!!
|
||||||
|
val resultType = analysisResult[ReplAnalyzerResult.renderedResultType]
|
||||||
|
|
||||||
|
if (doCompile) {
|
||||||
val codeLineForCompilation = nextCodeLine(snippetText)
|
val codeLineForCompilation = nextCodeLine(snippetText)
|
||||||
compiler.compile(codeLineForCompilation, compilationConfiguration)
|
compiler.compile(codeLineForCompilation, compilationConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair(completionRes, errorsRes).asSuccess()
|
ActualResult(completionRes, errorsSequence.toList(), resultType).asSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,14 +429,15 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
|
|||||||
when (res) {
|
when (res) {
|
||||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||||
is ResultWithDiagnostics.Success -> {
|
is ResultWithDiagnostics.Success -> {
|
||||||
val (expectedCompletions, completionsCompType, expectedErrors, errorsCompType) = expectedIter.next()
|
val (expectedCompletions, expectedErrors, expectedResultType) = expectedIter.next()
|
||||||
val (completionsRes, errorsRes) = res.value
|
val (completionsRes, errorsRes, resultType) = res.value
|
||||||
|
|
||||||
checkLists(index, "completions", expectedCompletions, completionsRes, completionsCompType)
|
checkLists(index, "completions", expectedCompletions.list, completionsRes, expectedCompletions.mode())
|
||||||
val expectedErrorsWithPath = expectedErrors.map {
|
val expectedErrorsWithPath = expectedErrors.list.map {
|
||||||
it.copy(sourcePath = errorsRes.firstOrNull()?.sourcePath)
|
it.copy(sourcePath = errorsRes.firstOrNull()?.sourcePath)
|
||||||
}
|
}
|
||||||
checkLists(index, "errors", expectedErrorsWithPath, errorsRes, errorsCompType)
|
checkLists(index, "errors", expectedErrorsWithPath, errorsRes, expectedErrors.mode())
|
||||||
|
assertEquals("Analysis result types are different", expectedResultType, resultType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user