[Gradle] Improve diagnostics-related test assertions
- Allow matching substring for 'assertNoDiagnostic' as well - Better handling of cases when multiple diagnostics with the same ID are reported (properly look for one 'withSubstring' if provided)
This commit is contained in:
+59
-19
@@ -9,7 +9,6 @@ import org.gradle.testkit.runner.BuildResult
|
|||||||
import org.jetbrains.kotlin.gradle.BaseGradleIT
|
import org.jetbrains.kotlin.gradle.BaseGradleIT
|
||||||
import org.jetbrains.kotlin.gradle.internals.VERBOSE_DIAGNOSTIC_SEPARATOR
|
import org.jetbrains.kotlin.gradle.internals.VERBOSE_DIAGNOSTIC_SEPARATOR
|
||||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory
|
||||||
import kotlin.test.assertNotNull
|
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@@ -17,31 +16,54 @@ fun BaseGradleIT.CompiledProject.assertHasDiagnostic(diagnosticFactory: ToolingD
|
|||||||
output.assertHasDiagnostic(diagnosticFactory, withSubstring)
|
output.assertHasDiagnostic(diagnosticFactory, withSubstring)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BaseGradleIT.CompiledProject.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory) {
|
fun BaseGradleIT.CompiledProject.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||||
output.assertNoDiagnostic(diagnosticFactory)
|
output.assertNoDiagnostic(diagnosticFactory, withSubstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BuildResult.assertHasDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||||
|
output.assertHasDiagnostic(diagnosticFactory, withSubstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BuildResult.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||||
|
output.assertNoDiagnostic(diagnosticFactory, withSubstring)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.assertHasDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
fun String.assertHasDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||||
val diagnosticMessage = extractVerboselyRenderedDiagnostic(diagnosticFactory, this)
|
val diagnosticsMessages = extractVerboselyRenderedDiagnostics(diagnosticFactory, this)
|
||||||
assertNotNull(diagnosticMessage) { "Diagnostic with id=${diagnosticFactory.id} not found" }
|
assertTrue(diagnosticsMessages.isNotEmpty(), "Diagnostic with id=${diagnosticFactory.id} not found. Full text output:\n\n" + this)
|
||||||
if (withSubstring != null) {
|
if (withSubstring != null) {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
withSubstring in diagnosticMessage,
|
diagnosticsMessages.any { withSubstring in it },
|
||||||
"Diagnostic ${diagnosticFactory.id} doesn't have expected substring $withSubstring. " +
|
"Diagnostic ${diagnosticFactory.id} doesn't have expected substring $withSubstring. " +
|
||||||
"Actual diagnostic message:\n" +
|
"Actual diagnostic messages with that ID:\n" +
|
||||||
diagnosticMessage
|
diagnosticsMessages.joinToString(separator = "\n") +
|
||||||
|
"\nFull text output:\n\n" +
|
||||||
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory) {
|
fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||||
val diagnosticMessage = extractVerboselyRenderedDiagnostic(diagnosticFactory, this)
|
val diagnosticMessages = extractVerboselyRenderedDiagnostics(diagnosticFactory, this)
|
||||||
assertNull(
|
if (withSubstring != null) {
|
||||||
diagnosticMessage,
|
val matchedWithSubstring = diagnosticMessages.find { withSubstring in it }
|
||||||
"Diagnostic with id=${diagnosticFactory.id} was expected to be absent, but was reported. " +
|
assertNull(
|
||||||
"Actual diagnostic message: \n" +
|
matchedWithSubstring,
|
||||||
diagnosticMessage
|
"Diagnostic with id=${diagnosticFactory.id} and substring '${withSubstring}' was expected to be absent, but was reported. " +
|
||||||
)
|
"Actual diagnostic message: \n" +
|
||||||
|
matchedWithSubstring +
|
||||||
|
"\nFull text output:\n\n" +
|
||||||
|
this
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
assertTrue(
|
||||||
|
diagnosticMessages.isEmpty(),
|
||||||
|
"Expected no diagnostics with id=${diagnosticFactory.id}, but some were reported:\n" +
|
||||||
|
diagnosticMessages.joinToString(separator = "\n") +
|
||||||
|
"\nFull text output:\n\n" +
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,8 +134,23 @@ private val DIAGNOSTIC_START_REGEX = """\s*[we]:\s*\[[^\[]*].*""".toRegex()
|
|||||||
Multiline
|
Multiline
|
||||||
Text"
|
Text"
|
||||||
*/
|
*/
|
||||||
private fun extractVerboselyRenderedDiagnostic(diagnostic: ToolingDiagnosticFactory, fromText: String): String? {
|
private fun extractVerboselyRenderedDiagnostics(diagnostic: ToolingDiagnosticFactory, fromText: String): List<String> {
|
||||||
val diagnosticStartIndex = fromText.indexOf("[${diagnostic.id}")
|
var parsedPrefix = 0
|
||||||
|
|
||||||
|
return generateSequence {
|
||||||
|
extractNextVerboselyRenderedDiagnosticAndIndex(diagnostic, fromText, startIndex = parsedPrefix)
|
||||||
|
?.also { (_, newPrefix) -> parsedPrefix = newPrefix }
|
||||||
|
?.first
|
||||||
|
}.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns diagnostic substring + index of the first symbol after the diagnostic message
|
||||||
|
private fun extractNextVerboselyRenderedDiagnosticAndIndex(
|
||||||
|
diagnostic: ToolingDiagnosticFactory,
|
||||||
|
fromText: String,
|
||||||
|
startIndex: Int,
|
||||||
|
): Pair<String, Int>? {
|
||||||
|
val diagnosticStartIndex = fromText.indexOf("[${diagnostic.id}", startIndex)
|
||||||
if (diagnosticStartIndex == -1) return null
|
if (diagnosticStartIndex == -1) return null
|
||||||
|
|
||||||
val diagnosticHeaderEnd = fromText.indexOf("]", startIndex = diagnosticStartIndex)
|
val diagnosticHeaderEnd = fromText.indexOf("]", startIndex = diagnosticStartIndex)
|
||||||
@@ -121,7 +158,10 @@ private fun extractVerboselyRenderedDiagnostic(diagnostic: ToolingDiagnosticFact
|
|||||||
|
|
||||||
val diagnosticSeparatorStartIndex = fromText.indexOf(VERBOSE_DIAGNOSTIC_SEPARATOR, startIndex = diagnosticStartIndex)
|
val diagnosticSeparatorStartIndex = fromText.indexOf(VERBOSE_DIAGNOSTIC_SEPARATOR, startIndex = diagnosticStartIndex)
|
||||||
// NB: substring's endIndex is exclusive, which gives us exactly the message
|
// NB: substring's endIndex is exclusive, which gives us exactly the message
|
||||||
return fromText.substring(diagnosticMessageStart, diagnosticSeparatorStartIndex).trim { it.isWhitespace() || it == '\n' }
|
val diagnosticMessage = fromText.substring(diagnosticMessageStart, diagnosticSeparatorStartIndex)
|
||||||
|
.trim { it.isWhitespace() || it == '\n' }
|
||||||
|
val indexOfFirstSymbolAfterSeparator = diagnosticSeparatorStartIndex + VERBOSE_DIAGNOSTIC_SEPARATOR.length
|
||||||
|
return diagnosticMessage to indexOfFirstSymbolAfterSeparator
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val CONFIGURE_PROJECT_PREFIX = "> Configure project"
|
private const val CONFIGURE_PROJECT_PREFIX = "> Configure project"
|
||||||
|
|||||||
+2
-2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.plugin.diagnostics
|
package org.jetbrains.kotlin.gradle.plugin.diagnostics
|
||||||
|
|
||||||
|
import org.gradle.api.InvalidUserCodeException
|
||||||
import org.gradle.api.logging.Logger
|
import org.gradle.api.logging.Logger
|
||||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.*
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.*
|
||||||
|
|
||||||
@@ -24,8 +25,7 @@ internal fun renderReportedDiagnostic(
|
|||||||
|
|
||||||
ERROR -> logger.error("e: ${diagnostic.render(isVerbose)}\n")
|
ERROR -> logger.error("e: ${diagnostic.render(isVerbose)}\n")
|
||||||
|
|
||||||
FATAL ->
|
FATAL -> throw InvalidUserCodeException(diagnostic.render(isVerbose))
|
||||||
error("Internal error: FATAL diagnostics throw an exception immediately in KotlinToolingDiagnosticsCollector")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user