From 87873f98240fbf8da1e2067c8a2298b7ab2b5eaf Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Wed, 1 Dec 2021 12:09:12 +0300 Subject: [PATCH] [Native][tests] Extract GTest report verification logic --- .../support/runner/LocalTestRunner.kt | 50 +++---------- .../konan/blackboxtest/support/util/GTest.kt | 72 +++++++++++++++++++ 2 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/GTest.kt diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/LocalTestRunner.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/LocalTestRunner.kt index 8ebafaceed3..5a5fd482532 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/LocalTestRunner.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/LocalTestRunner.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.runner import com.intellij.openapi.util.text.StringUtilRt.convertLineSeparators import org.jetbrains.kotlin.konan.blackboxtest.support.* +import org.jetbrains.kotlin.konan.blackboxtest.support.util.parseGTestReport import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import kotlin.time.Duration @@ -55,46 +56,22 @@ internal class LocalTestRunner( } private fun verifyTestWithGTestRunner() { - val testStatuses = hashMapOf>() - val cleanStdOut = StringBuilder() + val testReport = parseGTestReport(runResult.output.stdOut) - var expectStatusLine = false - runResult.output.stdOut.lines().forEach { line -> - when { - expectStatusLine -> { - val matcher = GTEST_STATUS_LINE_REGEX.matchEntire(line) - if (matcher != null) { - // Read the line with test status. - val testStatus = matcher.groupValues[1] - val testName = matcher.groupValues[2] - testStatuses.getOrPut(testStatus) { hashSetOf() } += testName - expectStatusLine = false - } else { - // If current line is not a status line then it could be only the line with the process' output. - cleanStdOut.appendLine(line) - } - } - line.startsWith(GTEST_RUN_LINE_PREFIX) -> { - expectStatusLine = true // Next line contains either test status. - } - else -> Unit - } - } + verifyExpectation(!testReport.isEmpty()) { "No tests have been executed." } - verifyExpectation(testStatuses.isNotEmpty()) { "No tests have been executed." } - - val passedTests = testStatuses[GTEST_STATUS_OK]?.size ?: 0 - verifyExpectation(passedTests > 0) { "No passed tests." } + val passedTests = testReport.getPassedTests() + verifyExpectation(passedTests.isNotEmpty()) { "No passed tests." } testRun.runParameters.get { - val excessiveTests = testStatuses.getValue(GTEST_STATUS_OK).filter { testName -> !testMatches(testName) } + val excessiveTests = passedTests.filter { testName -> !testMatches(testName) } verifyExpectation(excessiveTests.isEmpty()) { "Excessive tests have been executed: $excessiveTests." } } - val failedTests = (testStatuses - GTEST_STATUS_OK).values.sumOf { it.size } - verifyExpectation(0, failedTests) { "There are failed tests." } + val failedTests = testReport.getFailedTests().size + verifyExpectation(0, failedTests) { "There are $failedTests failed tests." } - verifyOutputData(mergedOutput = cleanStdOut.toString() + runResult.output.stdErr) + verifyOutputData(mergedOutput = testReport.cleanStdOut + runResult.output.stdErr) } private fun verifyPlainTest() = verifyOutputData(mergedOutput = runResult.output.stdOut + runResult.output.stdErr) @@ -107,13 +84,4 @@ internal class LocalTestRunner( } } } - - companion object { - private const val GTEST_RUN_LINE_PREFIX = "[ RUN ]" - private val GTEST_STATUS_LINE_REGEX = Regex("^\\[\\s+([A-Z]+)\\s+]\\s+(\\S+)\\s+.*") - private const val GTEST_STATUS_OK = "OK" - } } - -private typealias TestStatus = String -private typealias TestName = String diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/GTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/GTest.kt new file mode 100644 index 00000000000..16b90d300e3 --- /dev/null +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/GTest.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.konan.blackboxtest.support.util + +internal typealias TestName = String +internal typealias TestStatus = String + +internal class GTestReport( + private val testStatuses: Map>, + val cleanStdOut: String +) { + fun getPassedTests(): Collection = testStatuses[STATUS_OK].orEmpty() + fun getFailedTests(): Collection = (testStatuses - STATUS_OK).flatMap { it.value } + + fun isEmpty(): Boolean = testStatuses.isEmpty() + + companion object { + private const val STATUS_OK = "OK" + } +} + +/** + * Parses GTest reports like this: + * + * [==========] Running 2 tests from 1 test cases. + * [----------] Global test environment set-up. + * [----------] 2 tests from sample.test.SampleTestKt + * [ RUN ] sample.test.SampleTestKt.one + * [ OK ] sample.test.SampleTestKt.one (0 ms) + * [ RUN ] sample.test.SampleTestKt.two + * [ OK ] sample.test.SampleTestKt.two (0 ms) + * [----------] 2 tests from sample.test.SampleTestKt (0 ms total) + * + * [----------] Global test environment tear-down + * [==========] 2 tests from 1 test cases ran. (0 ms total) + * [ PASSED ] 2 tests. + */ +internal fun parseGTestReport(stdOut: String): GTestReport { + val testStatuses = hashMapOf>() + val cleanStdOut = StringBuilder() + + var expectStatusLine = false + stdOut.lineSequence().forEach { line -> + when { + expectStatusLine -> { + val matcher = STATUS_LINE_REGEX.matchEntire(line) + if (matcher != null) { + // Read the line with test status. + val testStatus = matcher.groupValues[1] + val testName = matcher.groupValues[2] + testStatuses.getOrPut(testStatus) { hashSetOf() } += testName + expectStatusLine = false + } else { + // If current line is not a status line then it could be only the line with the process' output. + cleanStdOut.appendLine(line) + } + } + line.matches(RUN_LINE_REGEX) -> { + expectStatusLine = true // Next line contains either test status. + } + else -> Unit + } + } + + return GTestReport(testStatuses, cleanStdOut.toString()) +} + +private val RUN_LINE_REGEX = Regex("""^\[\s+RUN\s+]\s+.*""") +private val STATUS_LINE_REGEX = Regex("""^\[\s+([A-Z]+)\s+]\s+(\S+)\s+.*""")