diff --git a/compiler/testData/codegen/box/assert/alwaysDisable.kt b/compiler/testData/codegen/box/assert/alwaysDisable.kt index a8d853a27e4..9cfa7401abc 100644 --- a/compiler/testData/codegen/box/assert/alwaysDisable.kt +++ b/compiler/testData/codegen/box/assert/alwaysDisable.kt @@ -1,13 +1,14 @@ // IGNORE_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_ASSERT // KT-59059 -// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR_ES6 // IGNORE_BACKEND: JS // ASSERTIONS_MODE: always-disable // WITH_STDLIB +@file:Suppress("OPT_IN_USAGE_ERROR") // ExperimentalNativeApi is defined only in Native + fun checkTrue(): Boolean { var hit = false val l = { hit = true; true } diff --git a/compiler/testData/codegen/box/assert/alwaysEnable.kt b/compiler/testData/codegen/box/assert/alwaysEnable.kt index 098d4d643e6..bbb81fbab3c 100644 --- a/compiler/testData/codegen/box/assert/alwaysEnable.kt +++ b/compiler/testData/codegen/box/assert/alwaysEnable.kt @@ -2,7 +2,6 @@ // IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR_ES6 // IGNORE_BACKEND: JS -// IGNORE_NATIVE: optimizationMode=OPT // ASSERTIONS_MODE: always-enable // WITH_STDLIB diff --git a/native/native.tests/testData/standalone/termination/assertFailed.kt b/native/native.tests/testData/standalone/termination/assertFailed.kt deleted file mode 100644 index b98578e847e..00000000000 --- a/native/native.tests/testData/standalone/termination/assertFailed.kt +++ /dev/null @@ -1,8 +0,0 @@ -// EXIT_CODE: !0 -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) - -// TODO: Test running this test with disabled assertions. This requires removing always-enabled -// -enable-assertions from `BasicCompilation`. -fun main() { - assert(false) -} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/assertPassed.kt b/native/native.tests/testData/standalone/termination/assertPassed.kt deleted file mode 100644 index e05888b3943..00000000000 --- a/native/native.tests/testData/standalone/termination/assertPassed.kt +++ /dev/null @@ -1,5 +0,0 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) - -fun main() { - assert(true) -} \ No newline at end of file diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java index 39f060650ed..9cdc683db95 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java @@ -156,18 +156,6 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/termination"), Pattern.compile("^(.+)\\.kt$"), null, true); } - @Test - @TestMetadata("assertFailed.kt") - public void testAssertFailed() throws Exception { - runTest("native/native.tests/testData/standalone/termination/assertFailed.kt"); - } - - @Test - @TestMetadata("assertPassed.kt") - public void testAssertPassed() throws Exception { - runTest("native/native.tests/testData/standalone/termination/assertPassed.kt"); - } - @Test @TestMetadata("exitProcess.kt") public void testExitProcess() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java index 7278133da4c..93f75833544 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java @@ -147,18 +147,6 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/termination"), Pattern.compile("^(.+)\\.kt$"), null, true); } - @Test - @TestMetadata("assertFailed.kt") - public void testAssertFailed() throws Exception { - runTest("native/native.tests/testData/standalone/termination/assertFailed.kt"); - } - - @Test - @TestMetadata("assertPassed.kt") - public void testAssertPassed() throws Exception { - runTest("native/native.tests/testData/standalone/termination/assertPassed.kt"); - } - @Test @TestMetadata("exitProcess.kt") public void testExitProcess() throws Exception { diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt index a076afdff2e..343b86b0240 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt @@ -196,6 +196,26 @@ internal object TestDirectives : SimpleDirectivesContainer() { Note that this directive makes sense only in combination with // KIND: STANDALONE_NO_TR """.trimIndent() ) + + val ASSERTIONS_MODE by enumDirective( + description = """ + Force assertions mode to given value, overriding calculated mode which is derived from cacheMode and optimizationMode. + """.trimIndent() + ) +} + +// mimics class `JVMAssertionsMode` +internal enum class AssertionsMode(val description: String) { + ALWAYS_ENABLE("always-enable"), + ALWAYS_DISABLE("always-disable"), + JVM("jvm"), + LEGACY("legacy"); + + companion object { + val DEFAULT = LEGACY + fun fromStringOrNull(string: String?) = entries.find { it.description == string } + fun fromString(string: String?) = fromStringOrNull(string) ?: DEFAULT + } } internal enum class TestKind { @@ -225,7 +245,11 @@ internal class TestCInteropArgs(cinteropArgs: List) : TestCompilerArgs(e constructor(vararg cinteropArgs: String) : this(cinteropArgs.asList()) } -internal open class TestCompilerArgs(val compilerArgs: List, val cinteropArgs: List = emptyList()) { +internal open class TestCompilerArgs( + val compilerArgs: List, + val cinteropArgs: List = emptyList(), + val assertionsMode: AssertionsMode = AssertionsMode.DEFAULT, +) { constructor(vararg compilerArgs: String) : this(compilerArgs.asList()) private val uniqueCompilerArgs = compilerArgs.toSet() @@ -236,7 +260,9 @@ internal open class TestCompilerArgs(val compilerArgs: List, val cintero operator fun plus(otherCompilerArgs: TestCompilerArgs): TestCompilerArgs = TestCompilerArgs( this.compilerArgs + otherCompilerArgs.compilerArgs, - this.cinteropArgs + otherCompilerArgs.cinteropArgs + this.cinteropArgs + otherCompilerArgs.cinteropArgs, + if (this.assertionsMode == otherCompilerArgs.assertionsMode) this.assertionsMode + else fail { "Cannot add ${this.assertionsMode} and ${otherCompilerArgs.assertionsMode}" }, ) companion object { diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt index ba2159dbaf0..7a6bb1fd4ac 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt @@ -55,7 +55,9 @@ internal abstract class BasicCompilation( private fun ArgsBuilder.applyCommonArgs() { add("-target", targets.testTarget.name) optimizationMode.compilerFlag?.let { compilerFlag -> add(compilerFlag) } - if (optimizationMode != OptimizationMode.OPT) add("-enable-assertions") + if ((freeCompilerArgs.assertionsMode != AssertionsMode.ALWAYS_DISABLE && optimizationMode != OptimizationMode.OPT) || + freeCompilerArgs.assertionsMode == AssertionsMode.ALWAYS_ENABLE) + add("-enable-assertions") add( "-Xverify-ir=error" ) @@ -218,7 +220,7 @@ internal class LibraryCompilation( dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact ) { - override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting(optimizationMode) + override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting(optimizationMode, freeCompilerArgs.assertionsMode) override fun applySpecificArgs(argsBuilder: ArgsBuilder) = with(argsBuilder) { add( @@ -253,7 +255,7 @@ internal class ObjCFrameworkCompilation( dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact ) { - override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting(optimizationMode) + override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting(optimizationMode, freeCompilerArgs.assertionsMode) override fun applySpecificArgs(argsBuilder: ArgsBuilder) = with(argsBuilder) { add( @@ -356,7 +358,7 @@ internal class ExecutableCompilation( expectedArtifact = expectedArtifact ) { private val cacheMode: CacheMode = settings.get() - override val binaryOptions = BinaryOptions.RuntimeAssertionsMode.chooseFor(cacheMode, optimizationMode) + override val binaryOptions = BinaryOptions.RuntimeAssertionsMode.chooseFor(cacheMode, optimizationMode, freeCompilerArgs.assertionsMode) private val partialLinkageConfig: UsedPartialLinkageConfig = settings.get() @@ -552,15 +554,19 @@ internal class CategorizedDependencies(uncategorizedDependencies: Iterable = when (optimizationMode) { - OptimizationMode.OPT -> mapOf() - else -> mapOf("runtimeAssertionsMode" to "panic") + fun defaultForTesting(optimizationMode: OptimizationMode, assertionsMode: AssertionsMode): Map { + val panic = mapOf("runtimeAssertionsMode" to "panic") + return when (assertionsMode) { + AssertionsMode.ALWAYS_ENABLE -> panic + AssertionsMode.ALWAYS_DISABLE -> mapOf() + else -> if (optimizationMode == OptimizationMode.OPT) mapOf() else panic + } } val forUseWithCache: Map = mapOf("runtimeAssertionsMode" to "ignore") - fun chooseFor(cacheMode: CacheMode, optimizationMode: OptimizationMode) = - if (cacheMode.useStaticCacheForDistributionLibraries) forUseWithCache else defaultForTesting(optimizationMode) + fun chooseFor(cacheMode: CacheMode, optimizationMode: OptimizationMode, assertionsMode: AssertionsMode) = + if (cacheMode.useStaticCacheForDistributionLibraries) forUseWithCache else defaultForTesting(optimizationMode, assertionsMode) } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt index 4bf0637f73f..000c7b562e3 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.konan.test.blackbox.support.* import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase.WithTestRunnerExtras +import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.ASSERTIONS_MODE import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.DISABLE_NATIVE import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.DISABLE_NATIVE_K1 import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.DISABLE_NATIVE_K2 @@ -147,7 +148,8 @@ private class ExtTestDataFile( nominalPackageName = computePackageName( testDataBaseDir = testRoots.baseDir, testDataFile = testDataFile - ) + ), + assertionsMode = AssertionsMode.fromString(structure.directives[ASSERTIONS_MODE.name]) ) } @@ -172,8 +174,8 @@ private class ExtTestDataFile( args += "-opt-in=kotlin.native.internal.InternalForKotlinNative" // for `Any.isPermanent()` and `Any.isLocal()` args += "-opt-in=kotlin.native.internal.InternalForKotlinNativeTests" // for ReflectionPackageName val freeCInteropArgs = structure.directives.listValues(FREE_CINTEROP_ARGS.name) - ?.flatMap { it.split(" ") } - return TestCompilerArgs(args, freeCInteropArgs ?: emptyList()) + .orEmpty().flatMap { it.split(" ") } + return TestCompilerArgs(args, freeCInteropArgs, testDataFileSettings.assertionsMode) } fun createTestCase(settings: Settings, sharedModules: ThreadSafeCache): TestCase { @@ -197,6 +199,7 @@ private class ExtTestDataFile( private fun determineIfStandaloneTest(): Boolean = with(structure) { if (directives.contains(NATIVE_STANDALONE_DIRECTIVE)) return true if (directives.contains(FILECHECK_STAGE.name)) return true + if (directives.contains(ASSERTIONS_MODE.name)) return true if (isExpectedFailure) return true // To make the debug of possible failed testruns easier, it makes sense to run dodgy tests alone if (directives.contains(IGNORE_NATIVE.name) || @@ -604,7 +607,8 @@ private class ExtTestDataFileSettings( val optInsForSourceCode: Set, val optInsForCompiler: Set, val generatedSourcesDir: File, - val nominalPackageName: PackageName + val nominalPackageName: PackageName, + val assertionsMode: AssertionsMode, ) private typealias SharedModuleGenerator = (sharedModulesDir: File) -> TestModule.Shared?