Add tests for analyze return type in REPL IDE services

also refactor existing tests infrastructure
This commit is contained in:
Ilya Muradyan
2020-05-06 04:55:47 +03:00
committed by Ilya Chernikov
parent 8a1b44cc2b
commit 7cde9b4355
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.scripting.ide_services.test_util.toList
import org.junit.Assert
import org.junit.Test
import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.script.experimental.api.*
class ReplCompletionAndErrorsAnalysisTest : TestCase() {
@@ -43,7 +45,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
code = "v.mema."
cursor = 7
expect {
completionsMode(ComparisonType.INCLUDES)
completions.mode(ComparisonType.INCLUDES)
addCompletion("memx", "memx", "Int", "property")
addCompletion("memy", "memy", "String", "property")
}
@@ -69,7 +71,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
code = testCode
cursor = testCursor ?: testCode.length
expect {
completionsMode(ComparisonType.EQUALS)
completions.mode(ComparisonType.EQUALS)
}
}
@@ -97,7 +99,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
cursor = 17
code = "import java.lang."
expect {
completionsMode(ComparisonType.INCLUDES)
completions.mode(ComparisonType.INCLUDES)
addCompletion("Process", "Process", " (java.lang)", "class")
}
}
@@ -173,7 +175,7 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
val v = BClass("KKK", AClass(5, "25"))
""".trimIndent()
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>()
fun run(setup: (Run).() -> Unit) {
@@ -258,29 +274,13 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
}
class Expected(private val run: Run) {
private val variants = mutableListOf<SourceCodeCompletionVariant>()
private var _completionsMode: ComparisonType = ComparisonType.DONT_CHECK
fun completionsMode(mode: ComparisonType) {
_completionsMode = mode
}
val completions = ExpectedList<SourceCodeCompletionVariant>(run::doComplete)
fun addCompletion(text: String, displayText: String, tail: String, icon: String) {
if (_completionsMode == ComparisonType.DONT_CHECK)
_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
completions.add(SourceCodeCompletionVariant(text, displayText, tail, icon))
}
val errors = ExpectedList<ScriptDiagnostic>(run::doErrorCheck)
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(
ScriptDiagnostic(
ScriptDiagnostic.unspecifiedError,
@@ -294,8 +294,10 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
)
}
var resultType: String? by ExpectedNullableVar(run::doErrorCheck)
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 doCompile: 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(
val completions: List<SourceCodeCompletionVariant>, val completionsCompType: ComparisonType,
val errors: List<ScriptDiagnostic>, val errorsCompType: ComparisonType
val completions: ExpectedList<SourceCodeCompletionVariant>,
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()
@@ -336,9 +372,9 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
private suspend fun evaluateInRepl(
compilationConfiguration: ScriptCompilationConfiguration,
snippets: List<RunRequest>
): List<ResultWithDiagnostics<Pair<List<SourceCodeCompletionVariant>, List<ScriptDiagnostic>>>> {
): List<ResultWithDiagnostics<ActualResult>> {
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 codeLine = nextCodeLine(snippetText)
val completionRes = if (doComplete && cursor != null) {
@@ -348,19 +384,22 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
emptyList()
}
val errorsRes = if (doErrorCheck) {
val analysisResult = if (doErrorCheck) {
val codeLineForErrorCheck = nextCodeLine(snippetText)
compiler.analyze(codeLineForErrorCheck, SourceCode.Position(0, 0), compilationConfiguration).toList()
compiler.analyze(codeLineForErrorCheck, SourceCode.Position(0, 0), compilationConfiguration).valueOrNull()
} else {
emptyList()
}
null
}?: ReplAnalyzerResult()
if (doComplile) {
val errorsSequence = analysisResult[ReplAnalyzerResult.analysisDiagnostics]!!
val resultType = analysisResult[ReplAnalyzerResult.renderedResultType]
if (doCompile) {
val codeLineForCompilation = nextCodeLine(snippetText)
compiler.compile(codeLineForCompilation, compilationConfiguration)
}
Pair(completionRes, errorsRes).asSuccess()
ActualResult(completionRes, errorsSequence.toList(), resultType).asSuccess()
}
}
@@ -390,14 +429,15 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() {
when (res) {
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
is ResultWithDiagnostics.Success -> {
val (expectedCompletions, completionsCompType, expectedErrors, errorsCompType) = expectedIter.next()
val (completionsRes, errorsRes) = res.value
val (expectedCompletions, expectedErrors, expectedResultType) = expectedIter.next()
val (completionsRes, errorsRes, resultType) = res.value
checkLists(index, "completions", expectedCompletions, completionsRes, completionsCompType)
val expectedErrorsWithPath = expectedErrors.map {
checkLists(index, "completions", expectedCompletions.list, completionsRes, expectedCompletions.mode())
val expectedErrorsWithPath = expectedErrors.list.map {
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)
}
}
}