[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.internals.VERBOSE_DIAGNOSTIC_SEPARATOR
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@@ -17,31 +16,54 @@ fun BaseGradleIT.CompiledProject.assertHasDiagnostic(diagnosticFactory: ToolingD
|
||||
output.assertHasDiagnostic(diagnosticFactory, withSubstring)
|
||||
}
|
||||
|
||||
fun BaseGradleIT.CompiledProject.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory) {
|
||||
output.assertNoDiagnostic(diagnosticFactory)
|
||||
fun BaseGradleIT.CompiledProject.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||
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) {
|
||||
val diagnosticMessage = extractVerboselyRenderedDiagnostic(diagnosticFactory, this)
|
||||
assertNotNull(diagnosticMessage) { "Diagnostic with id=${diagnosticFactory.id} not found" }
|
||||
val diagnosticsMessages = extractVerboselyRenderedDiagnostics(diagnosticFactory, this)
|
||||
assertTrue(diagnosticsMessages.isNotEmpty(), "Diagnostic with id=${diagnosticFactory.id} not found. Full text output:\n\n" + this)
|
||||
if (withSubstring != null) {
|
||||
assertTrue(
|
||||
withSubstring in diagnosticMessage,
|
||||
diagnosticsMessages.any { withSubstring in it },
|
||||
"Diagnostic ${diagnosticFactory.id} doesn't have expected substring $withSubstring. " +
|
||||
"Actual diagnostic message:\n" +
|
||||
diagnosticMessage
|
||||
"Actual diagnostic messages with that ID:\n" +
|
||||
diagnosticsMessages.joinToString(separator = "\n") +
|
||||
"\nFull text output:\n\n" +
|
||||
this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory) {
|
||||
val diagnosticMessage = extractVerboselyRenderedDiagnostic(diagnosticFactory, this)
|
||||
assertNull(
|
||||
diagnosticMessage,
|
||||
"Diagnostic with id=${diagnosticFactory.id} was expected to be absent, but was reported. " +
|
||||
"Actual diagnostic message: \n" +
|
||||
diagnosticMessage
|
||||
)
|
||||
fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withSubstring: String? = null) {
|
||||
val diagnosticMessages = extractVerboselyRenderedDiagnostics(diagnosticFactory, this)
|
||||
if (withSubstring != null) {
|
||||
val matchedWithSubstring = diagnosticMessages.find { withSubstring in it }
|
||||
assertNull(
|
||||
matchedWithSubstring,
|
||||
"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
|
||||
Text"
|
||||
*/
|
||||
private fun extractVerboselyRenderedDiagnostic(diagnostic: ToolingDiagnosticFactory, fromText: String): String? {
|
||||
val diagnosticStartIndex = fromText.indexOf("[${diagnostic.id}")
|
||||
private fun extractVerboselyRenderedDiagnostics(diagnostic: ToolingDiagnosticFactory, fromText: String): List<String> {
|
||||
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
|
||||
|
||||
val diagnosticHeaderEnd = fromText.indexOf("]", startIndex = diagnosticStartIndex)
|
||||
@@ -121,7 +158,10 @@ private fun extractVerboselyRenderedDiagnostic(diagnostic: ToolingDiagnosticFact
|
||||
|
||||
val diagnosticSeparatorStartIndex = fromText.indexOf(VERBOSE_DIAGNOSTIC_SEPARATOR, startIndex = diagnosticStartIndex)
|
||||
// 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"
|
||||
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.diagnostics
|
||||
|
||||
import org.gradle.api.InvalidUserCodeException
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.*
|
||||
|
||||
@@ -24,8 +25,7 @@ internal fun renderReportedDiagnostic(
|
||||
|
||||
ERROR -> logger.error("e: ${diagnostic.render(isVerbose)}\n")
|
||||
|
||||
FATAL ->
|
||||
error("Internal error: FATAL diagnostics throw an exception immediately in KotlinToolingDiagnosticsCollector")
|
||||
FATAL -> throw InvalidUserCodeException(diagnostic.render(isVerbose))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user