diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 86ef9dfe833..910f5d1a28b 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4284,32 +4284,68 @@ + + + + + + - - - - + + + + - - - - + + + + - + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt index d1f27e93d7a..9ed2ad24351 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt @@ -267,6 +267,16 @@ fun main() { } } + // Atomicfu compiler plugin native tests. + testGroup("plugins/atomicfu/atomicfu-compiler/test", "plugins/atomicfu/atomicfu-compiler/testData") { + testClass( + suiteTestClassName = "AtomicfuNativeTestGenerated", + annotations = listOf(atomicfuNative(), provider()) + ) { + model("nativeBox") + } + } + generateTestGroupSuiteWithJUnit5 { testGroup("native/native.tests/tests-gen", "compiler/util-klib-abi/testData") { testClass( @@ -345,4 +355,4 @@ private fun debugger() = annotation(Tag::class.java, "debugger") private fun infrastructure() = annotation(Tag::class.java, "infrastructure") private fun k1libContents() = annotation(Tag::class.java, "k1libContents") private fun k2libContents() = annotation(Tag::class.java, "k2libContents") -private fun atomicfu() = annotation(Tag::class.java, "atomicfu") +private fun atomicfuNative() = annotation(Tag::class.java, "atomicfu-native") diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt index ad794c7770b..8bfde34aefe 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt @@ -56,6 +56,7 @@ internal class EnforcedProperties(testClass: Class<*>) { internal enum class ClassLevelProperty(shortName: String) { TEST_TARGET("target"), TEST_MODE("mode"), + COMPILER_PLUGINS("compilerPlugins"), CUSTOM_KLIBS("customKlibs"), FORCE_STANDALONE("forceStandalone"), COMPILE_ONLY("compileOnly"), diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt index 66a13d03887..1a7d4425e20 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt @@ -190,6 +190,7 @@ private object NativeTestSupport { output += sanitizer output += CacheMode::class to cacheMode output += computeTestMode(enforcedProperties) + output += computeCompilerPlugins(enforcedProperties) output += computeCustomKlibs(enforcedProperties) output += computeForcedStandaloneTestKind(enforcedProperties) output += computeForcedNoopTestRunner(enforcedProperties) @@ -277,6 +278,15 @@ private object NativeTestSupport { private fun computeTestMode(enforcedProperties: EnforcedProperties): TestMode = ClassLevelProperty.TEST_MODE.readValue(enforcedProperties, TestMode.values(), default = TestMode.TWO_STAGE_MULTI_MODULE) + private fun computeCompilerPlugins(enforcedProperties: EnforcedProperties): CompilerPlugins = + CompilerPlugins( + ClassLevelProperty.COMPILER_PLUGINS.readValue( + enforcedProperties, + { it.split(':', ';').mapToSet(::File) }, + default = emptySet() + ) + ) + private fun computeCustomKlibs(enforcedProperties: EnforcedProperties): CustomKlibs = CustomKlibs( ClassLevelProperty.CUSTOM_KLIBS.readValue( diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt index 3592d065e36..be259142566 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt @@ -35,6 +35,7 @@ internal abstract class BasicCompilation( private val optimizationMode: OptimizationMode, private val compilerOutputInterceptor: CompilerOutputInterceptor, protected val freeCompilerArgs: TestCompilerArgs, + protected val compilerPlugins: CompilerPlugins, protected val dependencies: CategorizedDependencies, protected val expectedArtifact: A ) : TestCompilation() { @@ -67,6 +68,10 @@ internal abstract class BasicCompilation( add(freeCompilerArgs.compilerArgs) } + private fun ArgsBuilder.applyCompilerPlugins() { + add(compilerPlugins.compilerPluginJars) { compilerPluginJar -> "-Xplugin=${compilerPluginJar.path}" } + } + private fun ArgsBuilder.applySources() { addFlattenedTwice(sourceModules, { it.files }) { it.location.path } } @@ -79,6 +84,7 @@ internal abstract class BasicCompilation( applySpecificArgs(this) applyDependencies(this) applyFreeArgs() + applyCompilerPlugins() applySources() } @@ -135,6 +141,7 @@ internal abstract class SourceBasedCompilation( private val allocator: Allocator, private val pipelineType: PipelineType, freeCompilerArgs: TestCompilerArgs, + compilerPlugins: CompilerPlugins, override val sourceModules: Collection, dependencies: CategorizedDependencies, expectedArtifact: A @@ -145,6 +152,7 @@ internal abstract class SourceBasedCompilation( optimizationMode = optimizationMode, compilerOutputInterceptor = compilerOutputInterceptor, freeCompilerArgs = freeCompilerArgs, + compilerPlugins = compilerPlugins, dependencies = dependencies, expectedArtifact = expectedArtifact ) { @@ -197,6 +205,7 @@ internal class LibraryCompilation( allocator = settings.get(), pipelineType = settings.get(), freeCompilerArgs = freeCompilerArgs, + compilerPlugins = settings.get(), sourceModules = sourceModules, dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact @@ -231,6 +240,7 @@ internal class ObjCFrameworkCompilation( allocator = settings.get(), pipelineType = settings.getStageDependentPipelineType(), freeCompilerArgs = freeCompilerArgs, + compilerPlugins = settings.get(), sourceModules = sourceModules, dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact @@ -317,6 +327,7 @@ internal class ExecutableCompilation( allocator = settings.get(), pipelineType = settings.getStageDependentPipelineType(), freeCompilerArgs = freeCompilerArgs, + compilerPlugins = settings.get(), sourceModules = sourceModules, dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact @@ -409,6 +420,7 @@ internal class StaticCacheCompilation( optimizationMode = settings.get(), compilerOutputInterceptor = settings.get(), freeCompilerArgs = freeCompilerArgs, + compilerPlugins = settings.get(), dependencies = CategorizedDependencies(dependencies), expectedArtifact = expectedArtifact ) { diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt index 2e810ba377c..aa5a8d40f21 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt @@ -77,6 +77,19 @@ internal enum class TestMode(private val description: String) { override fun toString() = description } +/** + * Kotlin compiler plugins to be used together with the the Kotlin/Native compiler. + */ +@JvmInline +internal value class CompilerPlugins(val compilerPluginJars: Set) { + init { + val invalidJars = compilerPluginJars.filterNot { it.isDirectory || (it.isFile && it.extension == "jar") } + assertTrue(invalidJars.isEmpty()) { + "There are invalid compiler plugin JARs that should be passed for the Kotlin/Native compiler: ${invalidJars.joinToString { "[$it]" }}" + } + } +} + /** * The set of custom (external) klibs that should be passed to the Kotlin/Native compiler. */ diff --git a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts index 627468bca8f..2e1e572faf5 100644 --- a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts +++ b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts @@ -41,8 +41,6 @@ val atomicfuNativeKlib by configurations.creating { attribute(KotlinNativeTarget.konanTargetAttribute, nativeTargetName) attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) attribute(KotlinPlatformType.attribute, KotlinPlatformType.native) - // todo: don't add platform specific attribute - attribute(KotlinNativeTarget.konanTargetAttribute, org.jetbrains.kotlin.konan.target.KonanTarget.MACOS_X64.toString()) } } @@ -54,6 +52,8 @@ val atomicfuJsIrRuntimeForTests by configurations.creating { } } +val atomicfuCompilerPluginForTests by configurations.creating + repositories { mavenCentral() } @@ -105,7 +105,7 @@ dependencies { testImplementation(projectTests(":compiler:tests-common")) testImplementation(projectTests(":compiler:tests-common-new")) testImplementation(projectTests(":compiler:test-infrastructure")) - testCompileOnly("org.jetbrains.kotlinx:atomicfu:0.17.1") // todo: do not hardcode atomicfu version + testCompileOnly("org.jetbrains.kotlinx:atomicfu:0.21.0") testApiJUnit5() @@ -114,10 +114,32 @@ dependencies { testRuntimeOnly(project(":compiler:backend-common")) testRuntimeOnly(commonDependency("org.fusesource.jansi", "jansi")) - atomicfuJsClasspath("org.jetbrains.kotlinx:atomicfu-js:0.17.1") { isTransitive = false } + atomicfuJsClasspath("org.jetbrains.kotlinx:atomicfu-js:0.21.0") { isTransitive = false } atomicfuJsIrRuntimeForTests(project(":kotlinx-atomicfu-runtime")) { isTransitive = false } - atomicfuJvmClasspath("org.jetbrains.kotlinx:atomicfu:0.17.1") { isTransitive = false } - atomicfuNativeKlib("org.jetbrains.kotlinx:atomicfu:0.17.1") { isTransitive = false } + atomicfuJvmClasspath("org.jetbrains.kotlinx:atomicfu:0.21.0") { isTransitive = false } + atomicfuNativeKlib("org.jetbrains.kotlinx:atomicfu:0.21.0") { isTransitive = false } + atomicfuCompilerPluginForTests(project(":kotlin-atomicfu-compiler-plugin")) + // Implicit dependencies on native artifacts to run native tests on CI + implicitDependencies("org.jetbrains.kotlinx:atomicfu-linuxx64:0.21.0") { + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) + } + } + implicitDependencies("org.jetbrains.kotlinx:atomicfu-macosarm64:0.21.0"){ + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) + } + } + implicitDependencies("org.jetbrains.kotlinx:atomicfu-macosx64:0.21.0"){ + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) + } + } + implicitDependencies("org.jetbrains.kotlinx:atomicfu-mingwx64:0.21.0"){ + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) + } + } embedded(project(":kotlinx-atomicfu-runtime")) { attributes { @@ -128,7 +150,7 @@ dependencies { isTransitive = false } - testImplementation("org.jetbrains.kotlinx:atomicfu:0.17.1") + testImplementation("org.jetbrains.kotlinx:atomicfu:0.21.0") testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.1") } @@ -146,7 +168,10 @@ testsJar() useD8Plugin() projectTest(jUnitMode = JUnitMode.JUnit5) { - useJUnitPlatform() + useJUnitPlatform { + // Exclude all tests with the "atomicfu-native" tag. They should be launched by another test task. + excludeTags("atomicfu-native") + } useJsIrBoxTests(version = version, buildDir = "$buildDir/") workingDir = rootDir @@ -154,6 +179,12 @@ projectTest(jUnitMode = JUnitMode.JUnit5) { dependsOn(":dist") dependsOn(atomicfuJsIrRuntimeForTests) + // Depend on the test task that launches Native tests so that it will also run together with tests + // for all other targets if K/N is enabled + if (kotlinBuildProperties.isKotlinNativeEnabled) { + dependsOn(nativeTest) + } + val localAtomicfuJsIrRuntimeForTests: FileCollection = atomicfuJsIrRuntimeForTests val localAtomicfuJsClasspath: FileCollection = atomicfuJsClasspath val localAtomicfuJvmClasspath: FileCollection = atomicfuJvmClasspath @@ -168,10 +199,11 @@ projectTest(jUnitMode = JUnitMode.JUnit5) { publish() standardPublicJars() -val nativeBoxTest = nativeTest( - taskName = "nativeBoxTest", - tag = "atomicfu", +val nativeTest = nativeTest( + taskName = "nativeTest", + tag = "atomicfu-native", // Include all tests with the "atomicfu-native" tag. requirePlatformLibs = true, - customDependencies = listOf(atomicfuJvmClasspath), - customKlibDependencies = listOf(atomicfuNativeKlib) + customCompilerDependencies = listOf(atomicfuJvmClasspath), + customTestDependencies = listOf(atomicfuNativeKlib), + compilerPluginDependencies = listOf(atomicfuCompilerPluginForTests) ) diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java new file mode 100644 index 00000000000..4b6b64e5bb9 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java @@ -0,0 +1,276 @@ +/* + * Copyright 2010-2023 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; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.junit.jupiter.api.Tag; +import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox") +@TestDataPath("$PROJECT_ROOT") +@Tag("atomicfu-native") +@UseStandardTestCaseGroupProvider() +public class AtomicfuNativeTestGenerated extends AbstractNativeBlackBoxTest { + @Test + public void testAllFilesPresentInNativeBox() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Atomic_extensions { + @Test + public void testAllFilesPresentInAtomic_extensions() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ArrayInlineExtensionTest.kt") + public void testArrayInlineExtensionTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt"); + } + + @Test + @TestMetadata("ArrayLoopTest.kt") + public void testArrayLoopTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt"); + } + + @Test + @TestMetadata("ComplexLoopTest.kt") + public void testComplexLoopTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt"); + } + + @Test + @TestMetadata("ExtensionLoopTest.kt") + public void testExtensionLoopTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt"); + } + + @Test + @TestMetadata("ExtensionsTest.kt") + public void testExtensionsTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt"); + } + + @Test + @TestMetadata("InlineExtensionWithTypeParameterTest.kt") + public void testInlineExtensionWithTypeParameterTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt"); + } + + @Test + @TestMetadata("LambdaTest.kt") + public void testLambdaTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt"); + } + + @Test + @TestMetadata("LockFreeIntBitsTest.kt") + public void testLockFreeIntBitsTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt"); + } + + @Test + @TestMetadata("LockTest.kt") + public void testLockTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt"); + } + + @Test + @TestMetadata("ParameterizedInlineFunExtensionTest.kt") + public void testParameterizedInlineFunExtensionTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt"); + } + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Atomics_basic { + @Test + public void testAllFilesPresentInAtomics_basic() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ArithmeticTest.kt") + public void testArithmeticTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt"); + } + + @Test + @TestMetadata("AtomicArrayTest.kt") + public void testAtomicArrayTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt"); + } + + @Test + @TestMetadata("IndexArrayElementGetterTest.kt") + public void testIndexArrayElementGetterTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt"); + } + + @Test + @TestMetadata("InitializationOrderTest.kt") + public void testInitializationOrderTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt"); + } + + @Test + @TestMetadata("LateinitPropertiesTest.kt") + public void testLateinitPropertiesTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt"); + } + + @Test + @TestMetadata("LockFreeLongCounterTest.kt") + public void testLockFreeLongCounterTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt"); + } + + @Test + @TestMetadata("LockFreeQueueTest.kt") + public void testLockFreeQueueTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt"); + } + + @Test + @TestMetadata("LockFreeStackTest.kt") + public void testLockFreeStackTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt"); + } + + @Test + @TestMetadata("LoopTest.kt") + public void testLoopTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt"); + } + + @Test + @TestMetadata("MultiInitTest.kt") + public void testMultiInitTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt"); + } + + @Test + @TestMetadata("ScopeTest.kt") + public void testScopeTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt"); + } + + @Test + @TestMetadata("SimpleLockTest.kt") + public void testSimpleLockTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt"); + } + + @Test + @TestMetadata("UncheckedCastTest.kt") + public void testUncheckedCastTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt"); + } + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Delegated { + @Test + public void testAllFilesPresentInDelegated() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("DelegatedPropertiesTest.kt") + public void testDelegatedPropertiesTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt"); + } + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Locks { + @Test + public void testAllFilesPresentInLocks() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("ReentrantLockTest.kt") + public void testReentrantLockTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt"); + } + + @Test + @TestMetadata("SynchronizedObjectTest.kt") + public void testSynchronizedObjectTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt"); + } + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Top_level { + @Test + public void testAllFilesPresentInTop_level() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("FieldInObjectTest.kt") + public void testFieldInObjectTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt"); + } + + @Test + @TestMetadata("TopLevelTest.kt") + public void testTopLevelTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt"); + } + } + + @Nested + @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace") + @TestDataPath("$PROJECT_ROOT") + @Tag("atomicfu-native") + @UseStandardTestCaseGroupProvider() + public class Trace { + @Test + public void testAllFilesPresentInTrace() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("TraceTest.kt") + public void testTraceTest() throws Exception { + runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt"); + } + } +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt new file mode 100644 index 00000000000..154381d28f4 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt @@ -0,0 +1,228 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class AtomicIntArrayInlineExtensionTest { + private val intArr = AtomicIntArray(10) + private val a = atomic(0) + + private inline fun casLoop(to: Int): Int { + intArr[0].loop { cur -> + if (intArr[0].compareAndSet(cur, to)) return intArr[0].value + return 777 + } + } + + private inline fun casLoopExpression(to: Int): Int = intArr[3].loop { cur -> + if (intArr[3].compareAndSet(cur, to)) return intArr[3].value + return 777 + } + + private inline fun AtomicInt.extensionLoop(to: Int): Int { + loop { cur -> + if (compareAndSet(cur, to)) return value + return 777 + } + } + + private inline fun AtomicInt.extensionLoopExpression(to: Int): Int = loop { cur -> + lazySet(cur + 10) + return if (compareAndSet(cur, to)) value else incrementAndGet() + } + + private inline fun AtomicInt.extensionLoopMixedReceivers(first: Int, second: Int, index: Int): Int { + loop { cur -> + compareAndSet(cur, first) + intArr[index].compareAndSet(first, second) + return value + } + } + + private inline fun AtomicInt.extensionLoopRecursive(to: Int): Int { + loop { cur -> + compareAndSet(cur, to) + a.extensionLoop(5) + return value + } + } + + private inline fun AtomicInt.foo(to: Int): Int { + loop { cur -> + if (compareAndSet(cur, to)) return 777 + else return value + } + } + + private inline fun AtomicInt.bar(delta: Int): Int { + return foo(value + delta) + } + + fun test() { + assertEquals(5, casLoop(5)) + assertEquals(6, casLoopExpression(6)) + assertEquals(66, intArr[1].extensionLoop(66)) + assertEquals(66, intArr[2].extensionLoop(66)) + assertEquals(77, intArr[1].extensionLoopExpression(777)) + assertEquals(99, intArr[1].extensionLoopMixedReceivers(88, 99, 1)) + assertEquals(100, intArr[1].extensionLoopRecursive(100)) + assertEquals(777, intArr[1].bar(100)) + } +} + +class AtomicLongArrayInlineExtensionTest { + private val longArr = AtomicLongArray(10) + private val a = atomic(0L) + + private inline fun casLoop(to: Long): Long { + longArr[0].loop { cur -> + if (longArr[0].compareAndSet(cur, to)) return longArr[0].value + return 777L + } + } + + private inline fun casLoopExpression(to: Long): Long = longArr[3].loop { cur -> + if (longArr[3].compareAndSet(cur, to)) return longArr[3].value + return 777L + } + + private inline fun AtomicLong.extensionLoop(to: Long): Long { + loop { cur -> + if (compareAndSet(cur, to)) return value + return 777L + } + } + + private inline fun AtomicLong.extensionLoopExpression(to: Long): Long = loop { cur -> + lazySet(cur + 10L) + return if (compareAndSet(cur, to)) value else incrementAndGet() + } + + private inline fun AtomicLong.extensionLoopMixedReceivers(first: Long, second: Long, index: Int): Long { + loop { cur -> + compareAndSet(cur, first) + longArr[index].compareAndSet(first, second) + return value + } + } + + private inline fun AtomicLong.extensionLoopRecursive(to: Long): Long { + loop { cur -> + compareAndSet(cur, to) + a.extensionLoop(5L) + return value + } + } + + private inline fun AtomicLong.foo(to: Long): Long { + loop { cur -> + if (compareAndSet(cur, to)) return 777L + else return value + } + } + + private inline fun AtomicLong.bar(delta: Long): Long { + return foo(value + delta) + } + + fun test() { + assertEquals(5L, casLoop(5L)) + assertEquals(6L, casLoopExpression(6L)) + assertEquals(66L, longArr[1].extensionLoop(66L)) + assertEquals(66L, longArr[2].extensionLoop(66L)) + assertEquals(77L, longArr[1].extensionLoopExpression(777L)) + assertEquals(99L, longArr[1].extensionLoopMixedReceivers(88L, 99L, 1)) + assertEquals(100L, longArr[1].extensionLoopRecursive(100L)) + assertEquals(777L, longArr[1].bar(100L)) + } +} + +class AtomicBooleanArrayInlineExtensionTest { + private val booleanArr = AtomicBooleanArray(10) + + private inline fun casLoop(to: Boolean): Boolean { + booleanArr[0].loop { cur -> + if (booleanArr[0].compareAndSet(cur, to)) return booleanArr[0].value + } + } + + private inline fun casLoopExpression(to: Boolean): Boolean = booleanArr[3].loop { cur -> + if (booleanArr[3].compareAndSet(cur, to)) return booleanArr[3].value + } + + private inline fun AtomicBoolean.extensionLoop(to: Boolean): Boolean { + loop { cur -> + if (compareAndSet(cur, to)) return value + } + } + + private inline fun AtomicBoolean.extensionLoopExpression(to: Boolean): Boolean = loop { cur -> + lazySet(false) + return if (compareAndSet(cur, to)) value else !value + } + + private inline fun AtomicBoolean.extensionLoopMixedReceivers(first: Boolean, second: Boolean, index: Int): Boolean { + loop { cur -> + compareAndSet(cur, first) + booleanArr[index].compareAndSet(first, second) + return value + } + } + + fun test() { + assertEquals(true, casLoop(true)) + assertEquals(true, casLoopExpression(true)) + assertEquals(true, booleanArr[1].extensionLoop(true)) + assertEquals(true, booleanArr[1].extensionLoopExpression(true)) + assertEquals(false, booleanArr[7].extensionLoopMixedReceivers(true, false, 7)) + } +} + +class AtomicRefArrayInlineExtensionTest { + private val refArr = atomicArrayOfNulls(10) + private val a = atomic(0L) + + private inline fun casLoop(to: String): String? { + refArr[0].loop { cur -> + if (refArr[0].compareAndSet(cur, to)) return refArr[0].value + } + } + + private inline fun casLoopExpression(to: String): String? = refArr[3].loop { cur -> + if (refArr[3].compareAndSet(cur, to)) return refArr[3].value + } + + private inline fun AtomicRef.extensionLoop(to: String): String? { + loop { cur -> + if (compareAndSet(cur, to)) return value + else "incorrect" + } + } + + private inline fun AtomicRef.extensionLoopExpression(to: String): String? = loop { cur -> + lazySet("aaa") + return if (compareAndSet(cur, to)) value else "CAS_failed" + } + + private inline fun AtomicRef.extensionLoopMixedReceivers(first: String, second: String, index: Int): String? { + loop { cur -> + compareAndSet(cur, first) + refArr[index].compareAndSet(first, second) + return value + } + } + + fun test() { + assertEquals("aaa", casLoop("aaa")) + assertEquals("bbb", casLoopExpression("bbb")) + assertEquals("ccc", refArr[1].extensionLoop("ccc")) + assertEquals("CAS_failed", refArr[1].extensionLoopExpression("ccc")) + assertEquals("bbb", refArr[7].extensionLoopMixedReceivers("aaa", "bbb", 7)) + } +} + +@Test +fun box() { + AtomicIntArrayInlineExtensionTest().test() + AtomicLongArrayInlineExtensionTest().test() + AtomicBooleanArrayInlineExtensionTest().test() + AtomicRefArrayInlineExtensionTest().test() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt new file mode 100644 index 00000000000..d216fe3446f --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt @@ -0,0 +1,127 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class AtomicIntArrayAtomicfuInlineFunctionsTest { + private val intArr = AtomicIntArray(10) + + fun testSetArrayElementValueInLoop() { + intArr[0].loop { cur -> + assertTrue(intArr[0].compareAndSet(cur, 555)) + assertEquals(555, intArr[0].value) + return + } + } + + private fun action(cur: Int): Int = cur * 1000 + + fun testArrayElementUpdate() { + intArr[0].lazySet(5) + intArr[0].update { cur -> action(cur) } + assertEquals(intArr[0].value, 5000) + } + + fun testArrayElementGetAndUpdate() { + intArr[0].lazySet(5) + assertEquals(intArr[0].getAndUpdate{ cur -> action(cur) }, 5) + assertEquals(intArr[0].value, 5000) + } + + fun testArrayElementUpdateAndGet() { + intArr[0].lazySet(5) + assertEquals(intArr[0].updateAndGet{ cur -> action(cur) }, 5000) + } + + fun test() { + testSetArrayElementValueInLoop() + testArrayElementUpdate() + testArrayElementGetAndUpdate() + testArrayElementUpdateAndGet() + } +} + +class AtomicBooleanArrayAtomicfuInlineFunctionsTest { + private val booleanArr = AtomicBooleanArray(10) + + fun testSetArrayElementValueInLoop() { + booleanArr[0].loop { cur -> + assertTrue(booleanArr[0].compareAndSet(cur, true)) + assertEquals(true, booleanArr[0].value) + return + } + } + + private fun action(cur: Boolean) = !cur + + fun testArrayElementUpdate() { + booleanArr[0].lazySet(true) + booleanArr[0].update{ cur -> action(cur) } + assertEquals(booleanArr[0].value, false) + } + + fun testArrayElementGetAndUpdate() { + booleanArr[0].lazySet(true) + assertEquals(booleanArr[0].getAndUpdate{ cur -> action(cur) }, true) + assertEquals(booleanArr[0].value, false) + } + + fun testArrayElementUpdateAndGet() { + booleanArr[0].lazySet(true) + assertEquals(booleanArr[0].updateAndGet{ cur -> action(cur) }, false) + } + + fun test() { + testSetArrayElementValueInLoop() + testArrayElementUpdate() + testArrayElementGetAndUpdate() + testArrayElementUpdateAndGet() + } +} + +class AtomicArrayAtomicfuInlineFunctionsTest { + private val anyArr = atomicArrayOfNulls(5) + private val refArr = atomicArrayOfNulls(5) + + private data class Box(val n: Int) + + fun testSetArrayElementValueInLoop() { + anyArr[0].loop { cur -> + assertTrue(anyArr[0].compareAndSet(cur, IntArray(5))) + return + } + } + + private fun action(cur: Box?) = cur?.let { Box(cur.n * 10) } + + fun testArrayElementUpdate() { + refArr[0].lazySet(Box(5)) + refArr[0].update { cur -> cur?.let { Box(cur.n * 10) } } + assertEquals(refArr[0].value!!.n, 50) + } + + fun testArrayElementGetAndUpdate() { + refArr[0].lazySet(Box(5)) + assertEquals(refArr[0].getAndUpdate { cur -> action(cur) }!!.n, 5) + assertEquals(refArr[0].value!!.n, 50) + } + + fun testArrayElementUpdateAndGet() { + refArr[0].lazySet(Box(5)) + assertEquals(refArr[0].updateAndGet { cur -> action(cur) }!!.n, 50) + } + + fun test() { + testSetArrayElementValueInLoop() + testArrayElementUpdate() + testArrayElementGetAndUpdate() + testArrayElementUpdateAndGet() + } +} + + + +@Test +fun box() { + AtomicIntArrayAtomicfuInlineFunctionsTest().test() + AtomicBooleanArrayAtomicfuInlineFunctionsTest().test() + AtomicArrayAtomicfuInlineFunctionsTest().test() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt new file mode 100644 index 00000000000..4732ebc3982 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt @@ -0,0 +1,75 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +private val topLevelA = atomic(0) + +class ComplexLoopTest { + private val a = atomic(10) + private val long = atomic(6757L) + private val b = atomic(11) + private val c = atomic(12) + private val r = atomic("aaa") + private val intArr = AtomicIntArray(10) + + private inline fun AtomicInt.fooInt() { + loop { cur -> + if (compareAndSet(cur, 67)) return + } + } + + private inline fun AtomicLong.fooLong() { + loop { cur -> + if (compareAndSet(cur, 67L)) return + } + } + + private inline fun embeddedLoops(to: Int): Int = + a.loop { aValue -> + if (!a.compareAndSet(aValue, to)) return 666 + b.loop { bValue -> + return if (b.compareAndSet(bValue, to)) a.value + b.value else 777 + } + } + + private inline fun AtomicInt.extensionEmbeddedLoops(to: Int): Int = + loop { cur1 -> + compareAndSet(cur1, to) + loop { cur2 -> + return cur2 + } + } + + private inline fun embeddedUpdate(to: Int): Int = + a.loop { aValue -> + a.compareAndSet(aValue, to) + return a.updateAndGet { cur -> cur + 100 } + } + + private inline fun AtomicRef.extesntionEmbeddedRefUpdate(to: String): String = + loop { value -> + compareAndSet(value, to) + return updateAndGet { cur -> "${cur}AAA" } + } + + fun test() { + a.fooInt() + assertEquals(67, a.value) + b.fooInt() + assertEquals(67, b.value) + c.fooInt() + assertEquals(67, c.value) + long.fooLong() + assertEquals(67L, long.value) + assertEquals(24, embeddedLoops(12)) + assertEquals(77, c.extensionEmbeddedLoops(77)) + assertEquals(66, intArr[0].extensionEmbeddedLoops(66)) + assertEquals(166, embeddedUpdate(66)) + assertEquals("bbbAAA", r.extesntionEmbeddedRefUpdate("bbb")) + } +} + +@Test +fun testComplexLoopTest() { + val testClass = ComplexLoopTest() + testClass.test() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt new file mode 100644 index 00000000000..d57018eecac --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt @@ -0,0 +1,92 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class ExtensionLoopTest { + private val a = atomic(0) + private val b = atomic(true) + private val l = atomic(5000000000) + private val r = atomic(A("aaaa")) + private val rs = atomic("bbbb") + + class A(val s: String) + + private inline fun casLoop(to: Int): Int { + a.loop { cur -> + if (a.compareAndSet(cur, to)) return a.value + return 777 + } + } + + private inline fun casLoopExpression(to: Int): Int = a.loop { cur -> + if (a.compareAndSet(cur, to)) return a.value + return 777 + } + + private inline fun AtomicInt.extensionLoop(to: Int): Int { + loop { cur -> + if (compareAndSet(cur, to)) return value + return 777 + } + } + + private inline fun AtomicInt.extensionLoopExpression(to: Int): Int = loop { cur -> + lazySet(cur + 10) + return if (compareAndSet(cur, to)) value + 1 else incrementAndGet() + } + + private inline fun AtomicInt.extensionLoopRecursive(to: Int): Int { + loop { cur -> + compareAndSet(cur, to) + extensionLoop(5) + return value + } + } + + private inline fun AtomicInt.foo(to: Int): Int { + loop { cur -> + if (compareAndSet(cur, to)) return 777 + else return value + } + } + + private inline fun AtomicInt.bar(delta: Int): Int { + return foo(value + delta) + } + + private inline fun AtomicInt.extensionEmbeddedLoops(to: Int): Int = + loop { cur1 -> + compareAndSet(value, to) + loop { cur2 -> + return cur2 + } + } + + fun testIntExtensionLoops() { + assertEquals(5, casLoop(5)) + assertEquals(45, a.extensionEmbeddedLoops(45)) + assertEquals(6, casLoopExpression(6)) + assertEquals(17, a.extensionLoopExpression(777)) + assertEquals(66, a.extensionLoop(66)) + assertEquals(5, a.extensionLoopRecursive(100)) + assertEquals(777, a.bar(100)) + } +} + + +private val ref = atomic("aaa") + +private inline fun AtomicRef.topLevelExtensionLoop(to: String): String = loop { cur -> + lazySet(cur + to) + return value +} + +fun testTopLevelExtensionLoop() { + assertEquals("aaattt", ref.topLevelExtensionLoop("ttt")) +} + +@Test +fun testExtensionLoop() { + val testClass = ExtensionLoopTest() + testClass.testIntExtensionLoops() + testTopLevelExtensionLoop() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt new file mode 100644 index 00000000000..f7355303600 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt @@ -0,0 +1,114 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class ExtensionsTest { + private val a = atomic(0) + private val l = atomic(0L) + private val s = atomic(null) + private val b = atomic(true) + + fun testScopedFieldGetters() { + check(a.value == 0) + val update = 3 + a.lazySet(update) + check(a.compareAndSet(update, 8)) + a.lazySet(1) + check(a.value == 1) + check(a.getAndSet(2) == 1) + check(a.value == 2) + check(a.getAndIncrement() == 2) + check(a.value == 3) + check(a.getAndDecrement() == 3) + check(a.value == 2) + check(a.getAndAdd(2) == 2) + check(a.value == 4) + check(a.addAndGet(3) == 7) + check(a.value == 7) + check(a.incrementAndGet() == 8) + check(a.value == 8) + check(a.decrementAndGet() == 7) + check(a.value == 7) + check(a.compareAndSet(7, 10)) + } + + private inline fun AtomicInt.intExtensionArithmetic() { + value = 0 + check(value == 0) + val update = 3 + lazySet(update) + check(compareAndSet(update, 8)) + lazySet(1) + check(value == 1) + check(getAndSet(2) == 1) + check(value == 2) + check(getAndIncrement() == 2) + check(value == 3) + check(getAndDecrement() == 3) + check(value == 2) + check(getAndAdd(2) == 2) + check(value == 4) + check(addAndGet(3) == 7) + check(value == 7) + check(incrementAndGet() == 8) + check(value == 8) + check(decrementAndGet() == 7) + check(value == 7) + check(compareAndSet(7, 10)) + check(compareAndSet(value, 55)) + check(value == 55) + } + + private inline fun AtomicLong.longExtensionArithmetic() { + value = 2424920024888888848 + check(value == 2424920024888888848) + lazySet(8424920024888888848) + check(value == 8424920024888888848) + check(getAndSet(8924920024888888848) == 8424920024888888848) + check(value == 8924920024888888848) + check(incrementAndGet() == 8924920024888888849) // fails + check(value == 8924920024888888849) + check(getAndDecrement() == 8924920024888888849) + check(value == 8924920024888888848) + check(getAndAdd(100000000000000000) == 8924920024888888848) + check(value == 9024920024888888848) + check(addAndGet(-9223372036854775807) == -198452011965886959) + check(value == -198452011965886959) + check(incrementAndGet() == -198452011965886958) + check(value == -198452011965886958) + check(decrementAndGet() == -198452011965886959) + check(value == -198452011965886959) + } + + private inline fun AtomicRef.refExtension() { + value = "aaa" + check(value == "aaa") + lazySet("bb") + check(value == "bb") + check(getAndSet("ccc") == "bb") + check(value == "ccc") + } + + private inline fun AtomicBoolean.booleanExtensionArithmetic() { + value = false + check(!value) + lazySet(true) + check(value) + check(getAndSet(true)) + check(compareAndSet(value, false)) + check(!value) + } + + fun testExtension() { + a.intExtensionArithmetic() + l.longExtensionArithmetic() + s.refExtension() + b.booleanExtensionArithmetic() + } +} + +@Test +fun box() { + val testClass = ExtensionsTest() + testClass.testScopedFieldGetters() + testClass.testExtension() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt new file mode 100644 index 00000000000..3f151af9fbf --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt @@ -0,0 +1,33 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class InlineExtensionWithTypeParameterTest { + abstract class Segment>(val id: Int) + class SemaphoreSegment(id: Int) : Segment(id) + + private inline fun > AtomicRef.foo( + id: Int, + startFrom: S + ): Int { + lazySet(startFrom) + return value.getSegmentId() + } + + private inline fun > S.getSegmentId(): Int { + var cur: S = this + return cur.id + } + + private val sref = atomic(SemaphoreSegment(0)) + + fun testInlineExtensionWithTypeParameter() { + val s = SemaphoreSegment(77) + assertEquals(77, sref.foo(0, s)) + } +} + +@Test +fun box() { + val testClass = InlineExtensionWithTypeParameterTest() + testClass.testInlineExtensionWithTypeParameter() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt new file mode 100644 index 00000000000..4bb558874d0 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt @@ -0,0 +1,52 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LambdaTest { + private val a = atomic(0) + private val rs = atomic("bbbb") + + private inline fun inlineLambda( + arg: T, + crossinline block: (T) -> Unit + ) = block(arg) + + fun loopInLambda1(to: Int) = inlineLambda(to) sc@ { arg -> + a.loop { value -> + a.compareAndSet(value, arg) + return@sc + } + } + + fun loopInLambda2(to: Int) = inlineLambda(to) { arg1 -> + inlineLambda(arg1) sc@ { arg2 -> + a.loop { value -> + a.compareAndSet(value, arg2) + return@sc + } + } + } + + fun loopInLambda2Ref(to: String) = inlineLambda(to) { arg1 -> + inlineLambda(arg1) sc@ { arg2 -> + rs.loop { value -> + rs.compareAndSet(value, arg2) + return@sc + } + } + } + + fun test() { + loopInLambda1(34) + assertEquals(34, a.value) + loopInLambda1(77) + assertEquals(77, a.value) + loopInLambda2Ref("bbb") + assertEquals("bbb", rs.value) + } +} + +@Test +fun box() { + val testClass = LambdaTest() + testClass.test() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt new file mode 100644 index 00000000000..7b7e7358d06 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt @@ -0,0 +1,57 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LockFreeIntBitsTest { + fun testBasic() { + val bs = LockFreeIntBits() + assertTrue(!bs[0]) + assertTrue(bs.bitSet(0)) + assertTrue(bs[0]) + assertTrue(!bs.bitSet(0)) + + assertTrue(!bs[1]) + assertTrue(bs.bitSet(1)) + assertTrue(bs[1]) + assertTrue(!bs.bitSet(1)) + assertTrue(!bs.bitSet(0)) + + assertTrue(bs[0]) + assertTrue(bs.bitClear(0)) + assertTrue(!bs.bitClear(0)) + + assertTrue(bs[1]) + } +} + +class LockFreeIntBits { + private val bits = atomic(0) + + private fun Int.mask() = 1 shl this + + operator fun get(index: Int): Boolean = bits.value and index.mask() != 0 + + // User-defined private inline function + private inline fun bitUpdate(check: (Int) -> Boolean, upd: (Int) -> Int): Boolean { + bits.update { + if (check(it)) return false + upd(it) + } + return true + } + + fun bitSet(index: Int): Boolean { + val mask = index.mask() + return bitUpdate({ it and mask != 0 }, { it or mask }) + } + + fun bitClear(index: Int): Boolean { + val mask = index.mask() + return bitUpdate({ it and mask == 0 }, { it and mask.inv() }) + } +} + +@Test +fun box() { + val testClass = LockFreeIntBitsTest() + testClass.testBasic() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt new file mode 100644 index 00000000000..f9c1b7b4877 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt @@ -0,0 +1,29 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LockTest { + private val inProgressLock = atomic(false) + + fun testLock() { + var result = "" + if (inProgressLock.tryAcquire()) { + result = "OK" + } + assertEquals("OK", result) + } +} + +// This function will be removed by transformer +@Suppress("NOTHING_TO_INLINE") +private inline fun AtomicBoolean.tryAcquire(): Boolean = compareAndSet(false, true) + +// This function is here to test if the Kotlin metadata still consistent after transform +// It is used in ReflectionTest, DO NOT REMOVE +@Suppress("UNUSED_PARAMETER") +fun String.reflectionTest(mapParam: Map): List = error("no impl") + +@Test +fun box() { + val testClass = LockTest() + testClass.testLock() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt new file mode 100644 index 00000000000..8841f87e644 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt @@ -0,0 +1,28 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class ParameterizedInlineFunExtensionTest { + + private inline fun AtomicRef.foo(res1: S, res2: S, foo: (S) -> S): S { + val res = bar(res1, res2) + return res + } + + private inline fun AtomicRef.bar(res1: S, res2: S): S { + return res2 + } + + private val tail = atomic("aaa") + + fun testClose() { + assertEquals("bbb", tail.bar("aaa", "bbb")) + val res = tail.foo("bbb", "ccc") { s -> s } + assertEquals("ccc", res) + } +} + +@Test +fun testParameterizedInlineFunExtensionTest() { + val testClass = ParameterizedInlineFunExtensionTest() + testClass.testClose() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt new file mode 100644 index 00000000000..e2e6e9d1757 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt @@ -0,0 +1,130 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class IntArithmetic { + private val _x = atomic(0) + val x get() = _x.value + + private val local = atomic(0) + + private fun testGetValue() { + _x.value = 5 + assertEquals(5, _x.value) + var aValue = _x.value + assertEquals(5, aValue) + assertEquals(5, x) + + local.value = 555 + aValue = local.value + assertEquals(aValue, local.value) + } + + private fun testAtomicCallPlaces() { + _x.value = 5 + _x.compareAndSet(5, 42) + val res = _x.compareAndSet(42, 45) + assertTrue(res) + assertTrue(_x.compareAndSet(45, 77)) + assertFalse(_x.compareAndSet(95, 77)) + assertTrue(_x.compareAndSet(77, 88)) + } + + private fun testInt() { + _x.value = 0 + assertEquals(0, x) + val update = 3 + assertEquals(0, _x.getAndSet(update)) + assertTrue(_x.compareAndSet(update, 8)) + _x.lazySet(1) + assertEquals(1, x) + assertEquals(1, _x.getAndSet(2)) + assertEquals(2, x) + assertEquals(2, _x.getAndIncrement()) + assertEquals(3, x) + assertEquals(3, _x.getAndDecrement()) + assertEquals(2, x) + assertEquals(2, _x.getAndAdd(2)) + assertEquals(4, x) + assertEquals(7, _x.addAndGet(3)) + assertEquals(7, x) + assertEquals(8, _x.incrementAndGet()) + assertEquals(8, x) + assertEquals(7, _x.decrementAndGet()) + assertEquals(7, x) + assertTrue(_x.compareAndSet(7, 10)) + } + + fun test() { + testGetValue() + testAtomicCallPlaces() + testInt() + } +} + +class LongArithmetic { + private val _x = atomic(4294967296) + val x get() = _x.value + private val y = atomic(5000000000) + private val z = atomic(2424920024888888848) + private val max = atomic(9223372036854775807) + + fun testLong() { + assertEquals(2424920024888888848, z.value) + z.lazySet(8424920024888888848) + assertEquals(8424920024888888848, z.value) + assertEquals(8424920024888888848, z.getAndSet(8924920024888888848)) + assertEquals(8924920024888888848, z.value) + assertEquals(8924920024888888849, z.incrementAndGet()) + assertEquals(8924920024888888849, z.value) + assertEquals(8924920024888888849, z.getAndDecrement()) + assertEquals(8924920024888888848, z.value) + assertEquals(8924920024888888848, z.getAndAdd(100000000000000000)) + assertEquals(9024920024888888848, z.value) + assertEquals(-198452011965886959, z.addAndGet(-9223372036854775807)) + assertEquals(-198452011965886959, z.value) + assertEquals(-198452011965886958, z.incrementAndGet()) + assertEquals(-198452011965886958, z.value) + assertEquals(-198452011965886959, z.decrementAndGet()) + assertEquals(-198452011965886959, z.value) + } +} + +class BooleanArithmetic { + private val _x = atomic(false) + val x get() = _x.value + + fun testBoolean() { + assertEquals(false, _x.value) + assertFalse(x) + _x.lazySet(true) + assertTrue(x) + assertTrue(_x.getAndSet(true)) + assertTrue(_x.compareAndSet(true, false)) + assertFalse(x) + } +} + +class ReferenceArithmetic { + private val _x = atomic(null) + + fun testReference() { + _x.value = "aaa" + assertEquals("aaa", _x.value) + _x.lazySet("bb") + assertEquals("bb", _x.value) + assertEquals("bb", _x.getAndSet("ccc")) + assertEquals("ccc", _x.value) + } +} + +@Test +fun test() { + val intClass = IntArithmetic() + intClass.test() + val longClass = LongArithmetic() + longClass.testLong() + val booleanClass = BooleanArithmetic() + booleanClass.testBoolean() + val refClass = ReferenceArithmetic() + refClass.testReference() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt new file mode 100644 index 00000000000..9feae853170 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt @@ -0,0 +1,109 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class AtomicArrayTest { + + fun testIntArray() { + val A = AtomicArrayClass() + assertTrue(A.intArr[0].compareAndSet(0, 3)) + assertEquals(0, A.intArr[1].value) + A.intArr[0].lazySet(5) + assertEquals(5, A.intArr[0].value + A.intArr[1].value + A.intArr[2].value) + assertTrue(A.intArr[0].compareAndSet(5, 10)) + assertEquals(10, A.intArr[0].getAndDecrement()) + assertEquals(9, A.intArr[0].value) + A.intArr[2].value = 2 + assertEquals(2, A.intArr[2].value) + assertTrue(A.intArr[2].compareAndSet(2, 34)) + assertEquals(34, A.intArr[2].value) + } + + fun testLongArray() { + val A = AtomicArrayClass() + A.longArr[0].value = 2424920024888888848 + assertEquals(2424920024888888848, A.longArr[0].value) + A.longArr[0].lazySet(8424920024888888848) + assertEquals(8424920024888888848, A.longArr[0].value) + val ac = A.longArr[0].value + A.longArr[3].value = ac + assertEquals(8424920024888888848, A.longArr[3].getAndSet(8924920024888888848)) + assertEquals(8924920024888888848, A.longArr[3].value) + val ac1 = A.longArr[3].value + A.longArr[4].value = ac1 + assertEquals(8924920024888888849, A.longArr[4].incrementAndGet()) + assertEquals(8924920024888888849, A.longArr[4].value) + assertEquals(8924920024888888849, A.longArr[4].getAndDecrement()) + assertEquals(8924920024888888848, A.longArr[4].value) + A.longArr[4].value = 8924920024888888848 + assertEquals(8924920024888888848, A.longArr[4].getAndAdd(100000000000000000)) + val ac2 = A.longArr[4].value + A.longArr[1].value = ac2 + assertEquals(9024920024888888848, A.longArr[1].value) + assertEquals(-198452011965886959, A.longArr[1].addAndGet(-9223372036854775807)) + assertEquals(-198452011965886959, A.longArr[1].value) + assertEquals(-198452011965886958, A.longArr[1].incrementAndGet()) + assertEquals(-198452011965886958, A.longArr[1].value) + assertEquals(-198452011965886959, A.longArr[1].decrementAndGet()) + assertEquals(-198452011965886959, A.longArr[1].value) + } + + fun testBooleanArray() { + val A = AtomicArrayClass() + assertFalse(A.booleanArr[1].value) + assertTrue(A.booleanArr[1].compareAndSet(false, true)) + A.booleanArr[0].lazySet(true) + assertFalse(A.booleanArr[2].getAndSet(true)) + assertTrue(A.booleanArr[0].value && A.booleanArr[1].value && A.booleanArr[2].value) + A.booleanArr[0].value = false + assertFalse(A.booleanArr[0].value) + } + + fun testRefArray() { + val A = AtomicArrayClass() + val a2 = ARef(2) + val a3 = ARef(3) + A.refArr[0].value = a2 + assertEquals(2, A.refArr[0].value!!.n) + assertTrue(A.refArr[0].compareAndSet(a2, a3)) + assertEquals(3, A.refArr[0].value!!.n) + val r0 = A.refArr[0].value + A.refArr[3].value = r0 + assertEquals(3, A.refArr[3].value!!.n) + val a = A.a.value + assertTrue(A.refArr[3].compareAndSet(a3, a)) + } + + fun testAnyArray() { + val A = AtomicArrayClass() + val s1 = "aaa" + val s2 = "bbb" + A.anyArr[0].value = s1 + assertEquals("aaa", A.anyArr[0].value) + assertTrue(A.anyArr[0].compareAndSet(s1, s2)) + assertEquals("bbb", A.anyArr[0].value) + val r0 = A.anyArr[0].value + A.anyArr[3].value = r0 + assertEquals("bbb", A.anyArr[3].value) + } +} + +private class AtomicArrayClass { + val intArr = AtomicIntArray(10) + val longArr = AtomicLongArray(10) + val booleanArr = AtomicBooleanArray(10) + val refArr = atomicArrayOfNulls(10) + val anyArr = atomicArrayOfNulls(10) + internal val a = atomic(ARef(8)) +} + +data class ARef(val n: Int) + +@Test +fun test() { + val testClass = AtomicArrayTest() + testClass.testIntArray() + testClass.testLongArray() + testClass.testBooleanArray() + testClass.testRefArray() + testClass.testAnyArray() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt new file mode 100644 index 00000000000..21391296ff4 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt @@ -0,0 +1,32 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class IndexArrayElementGetterTest { + private val clazz = AtomicArrayClass() + + fun fib(a: Int): Int = if (a == 0 || a == 1) a else fib(a - 1) + fib(a - 2) + + fun testIndexArrayElementGetting() { + clazz.intArr[8].value = 3 + val i = fib(4) + val j = fib(5) + assertEquals(3, clazz.intArr[i + j].value) + assertEquals(3, clazz.intArr[fib(4) + fib(5)].value) + clazz.longArr[3].value = 100 + assertEquals(100, clazz.longArr[fib(6) - fib(5)].value) + assertEquals(100, clazz.longArr[(fib(6) + fib(4)) % 8].value) + assertEquals(100, clazz.longArr[(fib(6) + fib(4)) % 8].value) + assertEquals(100, clazz.longArr[(fib(4) + fib(5)) % fib(5)].value) + } + + private class AtomicArrayClass { + val intArr = AtomicIntArray(10) + val longArr = AtomicLongArray(10) + } +} + +@Test +fun box() { + val testClass = IndexArrayElementGetterTest() + testClass.testIndexArrayElementGetting() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt new file mode 100644 index 00000000000..3be4c4013de --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt @@ -0,0 +1,33 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +private class AAA { + private val _counter = atomic(5L) + val counterValue: Long get() = _counter.value + val delegateCounterValue by _counter + val lateInitInt: AtomicInt + val intArr: AtomicIntArray + + // test ensures that transformation does not change the order of initialization + init { + lateInitInt = atomic(10) + assertTrue(lateInitInt.compareAndSet(10, 100)) + assertEquals(100, lateInitInt.value) + intArr = AtomicIntArray(10) + intArr[0].value = 10 + assertTrue(intArr[0].compareAndSet(10, 100)) + intArr[1].value = 20 + } + + init { + assertEquals(5L, _counter.value) + assertEquals(5L,counterValue) + assertEquals(5L, delegateCounterValue) + assertEquals(120, intArr[0].value + intArr[1].value) + } +} + +@Test +fun box() { + val intClass = AAA() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt new file mode 100644 index 00000000000..1a56f806c46 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt @@ -0,0 +1,38 @@ +import kotlinx.atomicfu.* +import kotlinx.atomicfu.locks.* +import kotlin.test.* + +class LateinitPropertiesTest { + private val a: AtomicInt + private val head: AtomicRef + private val dataRef: AtomicRef + private val lateIntArr: AtomicIntArray + private val lateRefArr: AtomicArray + + private class Data(val n: Int) + + init { + a = atomic(0) + head = atomic("AAA") + lateIntArr = AtomicIntArray(55) + val data = Data(77) + dataRef = atomic(data) + val size = 10 + lateRefArr = atomicArrayOfNulls(size) + } + + fun test() { + assertEquals(0, a.value) + assertTrue(head.compareAndSet("AAA", "BBB")) + assertEquals("BBB", head.value) + assertEquals(0, lateIntArr[35].value) + assertEquals(77, dataRef.value.n) + assertEquals(null, lateRefArr[5].value) + } +} + +@Test +fun box() { + val testClass = LateinitPropertiesTest() + testClass.test() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt new file mode 100644 index 00000000000..dbc5f86c008 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt @@ -0,0 +1,61 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LockFreeLongCounterTest { + private inline fun testWith(g: LockFreeLongCounter.() -> Long) { + val c = LockFreeLongCounter() + assertEquals(0L, c.g()) + assertEquals(1L, c.increment()) + assertEquals(1L, c.g()) + assertEquals(2L, c.increment()) + assertEquals(2L, c.g()) + } + + fun testBasic() = testWith { get() } + + fun testGetInner() = testWith { getInner() } + + fun testAdd2() { + val c = LockFreeLongCounter() + c.add2() + assertEquals(2L, c.get()) + c.add2() + assertEquals(4L, c.get()) + } + + fun testSetM2() { + val c = LockFreeLongCounter() + c.setM2() + assertEquals(-2L, c.get()) + } +} + +class LockFreeLongCounter { + private val counter = atomic(0L) + + fun get(): Long = counter.value + + fun increment(): Long = counter.incrementAndGet() + + fun add2() = counter.getAndAdd(2) + + fun setM2() { + counter.value = -2L // LDC instruction here + } + + fun getInner(): Long = Inner().getFromOuter() + + // testing how an inner class can get access to it + private inner class Inner { + fun getFromOuter(): Long = counter.value + } +} + +@Test +fun box() { + val testClass = LockFreeLongCounterTest() + testClass.testBasic() + testClass.testAdd2() + testClass.testSetM2() + testClass.testGetInner() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt new file mode 100644 index 00000000000..42151442090 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt @@ -0,0 +1,55 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LockFreeQueueTest { + fun testBasic() { + val q = LockFreeQueue() + assertEquals(-1, q.dequeue()) + q.enqueue(42) + assertEquals(42, q.dequeue()) + assertEquals(-1, q.dequeue()) + q.enqueue(1) + q.enqueue(2) + assertEquals(1, q.dequeue()) + assertEquals(2, q.dequeue()) + assertEquals(-1, q.dequeue()) + } +} + +// MS-queue +public class LockFreeQueue { + private val head = atomic(Node(0)) + private val tail = atomic(head.value) + + private class Node(val value: Int) { + val next = atomic(null) + } + + public fun enqueue(value: Int) { + val node = Node(value) + tail.loop { curTail -> + val curNext = curTail.next.value + if (curNext != null) { + tail.compareAndSet(curTail, curNext) + return@loop + } + if (curTail.next.compareAndSet(null, node)) { + tail.compareAndSet(curTail, node) + return + } + } + } + + public fun dequeue(): Int { + head.loop { curHead -> + val next = curHead.next.value ?: return -1 + if (head.compareAndSet(curHead, next)) return next.value + } + } +} + +@Test +fun box() { + val testClass = LockFreeQueueTest() + testClass.testBasic() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt new file mode 100644 index 00000000000..89512d3f15a --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt @@ -0,0 +1,70 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LockFreeStackTest { + fun testClear() { + val s = LockFreeStack() + assertTrue(s.isEmpty()) + s.pushLoop("A") + assertTrue(!s.isEmpty()) + s.clear() + assertTrue(s.isEmpty()) + } + + fun testPushPopLoop() { + val s = LockFreeStack() + assertTrue(s.isEmpty()) + s.pushLoop("A") + assertTrue(!s.isEmpty()) + assertEquals("A", s.popLoop()) + assertTrue(s.isEmpty()) + } + + fun testPushPopUpdate() { + val s = LockFreeStack() + assertTrue(s.isEmpty()) + s.pushUpdate("A") + assertTrue(!s.isEmpty()) + assertEquals("A", s.popUpdate()) + assertTrue(s.isEmpty()) + } +} + +class LockFreeStack { + private val top = atomic?>(null) + + private class Node(val value: T, val next: Node?) + + fun isEmpty() = top.value == null + + fun clear() { top.value = null } + + fun pushLoop(value: T) { + top.loop { cur -> + val upd = Node(value, cur) + if (top.compareAndSet(cur, upd)) return + } + } + + fun popLoop(): T? { + top.loop { cur -> + if (cur == null) return null + if (top.compareAndSet(cur, cur.next)) return cur.value + } + } + + fun pushUpdate(value: T) { + top.update { cur -> Node(value, cur) } + } + + fun popUpdate(): T? = + top.getAndUpdate { cur -> cur?.next } ?.value +} + +@Test +fun box() { + val testClass = LockFreeStackTest() + testClass.testClear() + testClass.testPushPopLoop() + testClass.testPushPopUpdate() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt new file mode 100644 index 00000000000..a614935cefb --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt @@ -0,0 +1,128 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class LoopTest { + private val a = atomic(0) + private val a1 = atomic(1) + private val b = atomic(true) + private val l = atomic(5000000000L) + private val r = atomic(A("aaaa")) + private val rs = atomic("bbbb") + + class A(val s: String) + + fun atomicfuIntLoopTest() { + a.loop { value -> + if (a.compareAndSet(value, 777)) { + assertEquals(777, a.value) + return + } + } + } + + fun atomicfuBooleanLoopTest() { + b.loop { value -> + assertTrue(value) + if (!b.value) return + if (b.compareAndSet(value, false)) { + return + } + } + } + + fun atomicfuLongLoopTest() { + l.loop { cur -> + if (l.compareAndSet(5000000003, 9000000000)) { + return + } else { + l.incrementAndGet() + } + } + } + + fun atomicfuRefLoopTest() { + r.loop { cur -> + assertEquals("aaaa", cur.s) + if (r.compareAndSet(cur, A("bbbb"))) { + return + } + } + } + + fun atomicfuLoopTest() { + atomicfuIntLoopTest() + assertEquals(777, a.value) + atomicfuBooleanLoopTest() + assertFalse(b.value) + atomicfuLongLoopTest() + assertEquals(9000000000, l.value) + atomicfuRefLoopTest() + assertEquals("bbbb", r.value.s) + } + + fun atomicfuUpdateTest() { + a.value = 0 + a.update { value -> + val newValue = value + 1000 + if (newValue >= 0) Int.MAX_VALUE else newValue + } + assertEquals(Int.MAX_VALUE, a.value) + b.update { true } + assertEquals(true, b.value) + assertTrue(b.value) + l.value = 0L + l.update { cur -> + val newValue = cur + 1000 + if (newValue >= 0L) Long.MAX_VALUE else newValue + } + assertEquals(Long.MAX_VALUE, l.value) + r.lazySet(A("aaaa")) + r.update { cur -> + A("cccc${cur.s}") + } + assertEquals("ccccaaaa", r.value.s) + } + + fun atomicfuUpdateAndGetTest() { + val res1 = a.updateAndGet { value -> + if (value >= 0) Int.MAX_VALUE else value + } + assertEquals(Int.MAX_VALUE, res1) + assertEquals(true, b.updateAndGet { true }) + assertEquals(Long.MAX_VALUE, l.updateAndGet { cur -> + if (cur >= 0L) Long.MAX_VALUE else cur + }) + r.lazySet(A("aaaa")) + val res3 = r.updateAndGet { cur -> + A("cccc${cur.s}") + } + assertEquals("ccccaaaa", res3.s) + } + + fun atomicfuGetAndUpdateTest() { + a.getAndUpdate { value -> + if (value >= 0) Int.MAX_VALUE else value + } + assertEquals(Int.MAX_VALUE, a.value) + b.getAndUpdate { true } + assertTrue(b.value) + l.getAndUpdate { cur -> + if (cur >= 0L) Long.MAX_VALUE else cur + } + assertEquals(Long.MAX_VALUE, l.value) + r.lazySet(A("aaaa")) + r.getAndUpdate { cur -> + A("cccc${cur.s}") + } + assertEquals("ccccaaaa", r.value.s) + } +} + +@Test +fun box() { + val testClass = LoopTest() + testClass.atomicfuLoopTest() + testClass.atomicfuUpdateTest() + testClass.atomicfuUpdateAndGetTest() + testClass.atomicfuGetAndUpdateTest() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt new file mode 100644 index 00000000000..d2e808b861e --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt @@ -0,0 +1,30 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class MultiInitTest { + fun testBasic() { + val t = MultiInit() + check(t.incA() == 1) + check(t.incA() == 2) + check(t.incB() == 1) + check(t.incB() == 2) + } +} + +class MultiInit { + private val a = atomic(0) + private val b = atomic(0) + + fun incA() = a.incrementAndGet() + fun incB() = b.incrementAndGet() + + companion object { + fun foo() {} // just to force some clinit in outer file + } +} + +@Test +fun box() { + val testClass = MultiInitTest() + testClass.testBasic() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt new file mode 100644 index 00000000000..24407586f64 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt @@ -0,0 +1,45 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class AA(val value: Int) { + val b = B(value + 1) + val c = C(D(E(value + 1))) + + fun updateToB(affected: Any): Boolean { + (affected as AtomicState).state.compareAndSet(this, b) + return (affected.state.value is B && (affected.state.value as B).value == value + 1) + } + + fun manyProperties(affected: Any): Boolean { + (affected as AtomicState).state.compareAndSet(this, c.d.e) + return (affected.state.value is E && (affected.state.value as E).x == value + 1) + } +} + +class B (val value: Int) + +class C (val d: D) +class D (val e: E) +class E (val x: Int) + + +private class AtomicState(value: Any) { + val state = atomic(value) +} + +class ScopeTest { + fun scopeTest() { + val a = AA(0) + val affected: Any = AtomicState(a) + check(a.updateToB(affected)) + val a1 = AA(0) + val affected1: Any = AtomicState(a1) + check(a1.manyProperties(affected1)) + } +} + +@Test +fun box() { + val testClass = ScopeTest() + testClass.scopeTest() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt new file mode 100644 index 00000000000..d1b51b031df --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt @@ -0,0 +1,36 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class SimpleLockTest { + fun withLock() { + val lock = SimpleLock() + val result = lock.withLock { + "OK" + } + assertEquals("OK", result) + } +} + +class SimpleLock { + private val _locked = atomic(0) + + fun withLock(block: () -> T): T { + // this contrieves construct triggers Kotlin compiler to reuse local variable slot #2 for + // the exception in `finally` clause + try { + _locked.loop { locked -> + check(locked == 0) + if (!_locked.compareAndSet(0, 1)) return@loop // continue + return block() + } + } finally { + _locked.value = 0 + } + } +} + +@Test +fun box() { + val testClass = SimpleLockTest() + testClass.withLock() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt new file mode 100644 index 00000000000..637b9719951 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt @@ -0,0 +1,54 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +private val topLevelS = atomic(arrayOf("A", "B")) + +class UncheckedCastTest { + private val s = atomic("AAA") + private val bs = atomic(null) + + @Suppress("UNCHECKED_CAST") + fun testAtomicValUncheckedCast() { + assertEquals((s as AtomicRef).value, "AAA") + bs.lazySet(arrayOf(arrayOf(Box(1), Box(2)))) + assertEquals((bs as AtomicRef>>).value[0]!![0].b * 10, 10) + } + + @Suppress("UNCHECKED_CAST") + fun testTopLevelValUnchekedCast() { + assertEquals((topLevelS as AtomicRef>).value[1], "B") + } + + private data class Box(val b: Int) + + @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") + private inline fun AtomicRef.getString(): String = + (this as AtomicRef).value + + fun testInlineFunc() { + assertEquals("AAA", s.getString()) + } + + private val a = atomicArrayOfNulls(10) + + fun testArrayValueUncheckedCast() { + a[0].value = "OK" + @Suppress("UNCHECKED_CAST") + assertEquals("OK", (a[0] as AtomicRef).value) + } + + fun testArrayValueUncheckedCastInlineFunc() { + a[0].value = "OK" + assertEquals("OK", a[0].getString()) + } +} + +@Test +fun box() { + val testClass = UncheckedCastTest() + testClass.testAtomicValUncheckedCast() + testClass.testTopLevelValUnchekedCast() + testClass.testArrayValueUncheckedCast() + testClass.testArrayValueUncheckedCastInlineFunc() + testClass.testInlineFunc() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt new file mode 100644 index 00000000000..67d847b53b8 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt @@ -0,0 +1,150 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +private val _topLevelInt = atomic(42) +var topLevelInt: Int by _topLevelInt + +private var topLevelVolatile by atomic(56) + +class DelegatedProperties { + // Delegated properties should be declared in the same scope as the original atomic values + private val _a = atomic(42) + var a: Int by _a + private var privateA: Int by _a + + private val _l = atomic(55555555555) + private var l: Long by _l + + private val _b = atomic(false) + private var b: Boolean by _b + + private val _ref = atomic(A(B(77))) + private var ref: A by _ref + + private var vInt by atomic(77) + + private var vLong by atomic(777777777) + + private var vBoolean by atomic(false) + + private var vRef by atomic(A(B(77))) + + class A (val b: B) + class B (val n: Int) + + fun testDelegatedAtomicInt() { + assertEquals(42, a) + assertEquals(42, privateA) + _a.compareAndSet(42, 56) + assertEquals(56, a) + assertEquals(56, privateA) + a = 77 + _a.compareAndSet(77, 66) + privateA = 88 + _a.compareAndSet(88, 66) + assertEquals(66, _a.value) + assertEquals(66, a) + assertEquals(66, privateA) + + val aValue = a + privateA + assertEquals(132, aValue) + } + + fun testDelegatedAtomicLong() { + assertEquals(55555555555, l) + _l.getAndIncrement() + assertEquals(55555555556, l) + l = 7777777777777 + assertTrue(_l.compareAndSet(7777777777777, 66666666666)) + assertEquals(66666666666, _l.value) + assertEquals(66666666666, l) + } + + fun testDelegatedAtomicBoolean() { + assertEquals(false, b) + _b.lazySet(true) + assertEquals(true, b) + b = false + assertTrue(_b.compareAndSet(false, true)) + assertEquals(true, _b.value) + assertEquals(true, b) + } + + fun testDelegatedAtomicRef() { + assertEquals(77, ref.b.n) + _ref.lazySet(A(B(66))) + assertEquals(66, ref.b.n) + assertTrue(_ref.compareAndSet(_ref.value, A(B(56)))) + assertEquals(56, ref.b.n) + ref = A(B(99)) + assertEquals(99, _ref.value.b.n) + } + + fun testVolatileInt() { + assertEquals(77, vInt) + vInt = 55 + assertEquals(110, vInt * 2) + } + + fun testVolatileLong() { + assertEquals(777777777, vLong) + vLong = 55 + assertEquals(55, vLong) + } + + fun testVolatileBoolean() { + assertEquals(false, vBoolean) + vBoolean = true + assertEquals(true, vBoolean) + } + + fun testVolatileRef() { + assertEquals(77, vRef.b.n) + vRef = A(B(99)) + assertEquals(99, vRef.b.n) + } + + fun testDelegatedVariablesFlow() { + _a.lazySet(55) + assertEquals(55, _a.value) + assertEquals(55, a) + var aValue = a + assertEquals(55, aValue) + } + + fun test() { + testDelegatedAtomicInt() + testDelegatedAtomicLong() + testDelegatedAtomicBoolean() + testDelegatedAtomicRef() + testVolatileInt() + testVolatileBoolean() + testVolatileLong() + testVolatileRef() + testDelegatedVariablesFlow() + } +} + +fun testTopLevelDelegatedProperties() { + assertEquals(42, topLevelInt) + _topLevelInt.compareAndSet(42, 56) + assertEquals(56, topLevelInt) + topLevelInt = 77 + _topLevelInt.compareAndSet(77, 66) + assertEquals(66, _topLevelInt.value) + assertEquals(66, topLevelInt) +} + +fun testTopLevelVolatileProperties() { + assertEquals(56, topLevelVolatile) + topLevelVolatile = 55 + assertEquals(110, topLevelVolatile * 2) +} + +@Test +fun box() { + val testClass = DelegatedProperties() + testClass.test() + testTopLevelDelegatedProperties() + testTopLevelVolatileProperties() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt new file mode 100644 index 00000000000..1f070d8191a --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt @@ -0,0 +1,22 @@ +import kotlinx.atomicfu.locks.* +import kotlin.test.* + +class ReentrantLockFieldTest { + private val lock = reentrantLock() + private var state = 0 + + fun testLock() { + lock.withLock { + state = 1 + } + assertEquals(1, state) + assertTrue(lock.tryLock()) + lock.unlock() + } +} + +@Test +fun box() { + val testClass = ReentrantLockFieldTest() + testClass.testLock() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt new file mode 100644 index 00000000000..87df2af2463 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt @@ -0,0 +1,21 @@ +import kotlinx.atomicfu.locks.* +import kotlin.test.* + +class SynchronizedObjectTest : SynchronizedObject() { + + fun testSync() { + val result = synchronized(this) { bar() } + assertEquals("OK", result) + } + + private fun bar(): String = + synchronized(this) { + "OK" + } +} + +@Test +fun box() { + val testClass = SynchronizedObjectTest() + testClass.testSync() +} \ No newline at end of file diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt new file mode 100644 index 00000000000..2e6a11a3451 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt @@ -0,0 +1,67 @@ +import kotlinx.atomicfu.* +import kotlin.test.* +import kotlin.random.* + +private object Provider { + private val port = atomic(Random.nextInt(20, 90) * 100) + fun next(): Int = port.incrementAndGet() + + private val _l = atomic(2424920024888888848) + fun getL() = _l.incrementAndGet() + + val _ref = atomic(null) + + val _x = atomic(false) + + val intArr = AtomicIntArray(10) + val longArr = AtomicLongArray(10) + val refArr = atomicArrayOfNulls(5) +} + +private object DelegatedProvider { + internal val _a = atomic(42) + var a: Int by _a + + var vInt by atomic(77) +} + +private fun testFieldInObject() { + val port = Provider.next() + assertEquals(port + 1, Provider.next()) + + assertEquals(2424920024888888849, Provider.getL()) + + Provider._ref.compareAndSet(null, "abc") + assertEquals("abc", Provider._ref.value) + + assertFalse(Provider._x.value) + + Provider.intArr[8].value = 454 + assertEquals(455, Provider.intArr[8].incrementAndGet()) + + Provider.longArr[8].value = 4544096409680468 + assertEquals(4544096409680470, Provider.longArr[8].addAndGet(2)) + + Provider.refArr[1].value = Provider._ref.value + assertEquals("abc", Provider.refArr[1].value) +} + +private fun testDelegatedPropertiesInObject() { + assertEquals(42, DelegatedProvider.a) + DelegatedProvider._a.compareAndSet(42, 56) + assertEquals(56, DelegatedProvider.a) + DelegatedProvider.a = 77 + DelegatedProvider._a.compareAndSet(77, 66) + assertEquals(66, DelegatedProvider._a.value) + assertEquals(66, DelegatedProvider.a) + + assertEquals(77, DelegatedProvider.vInt) + DelegatedProvider.vInt = 55 + assertEquals(110, DelegatedProvider.vInt * 2) +} + +@Test +fun box() { + testFieldInObject() + testDelegatedPropertiesInObject() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt new file mode 100644 index 00000000000..e823cc6a7d2 --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt @@ -0,0 +1,182 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +private val a = atomic(0) +private val b = atomic(2424920024888888848) +private val c = atomic(true) +private val abcNode = atomic(ANode(BNode(CNode(8)))) +private val any = atomic(null) + +internal val a_internal = atomic(0) +internal val b_internal = atomic(2424920024888888848) +internal val c_internal = atomic(true) +internal val abcNode_internal = atomic(ANode(BNode(CNode(8)))) +internal val any_internal = atomic(null) + +private val intArr = AtomicIntArray(3) +private val longArr = AtomicLongArray(5) +private val booleanArr = AtomicBooleanArray(4) +private val refArr = atomicArrayOfNulls>>(5) +private val anyRefArr = atomicArrayOfNulls(10) + +private val stringAtomicNullArr = atomicArrayOfNulls(10) + +class TopLevelPrimitiveTest { + + fun testTopLevelInt() { + assertEquals(0, a.value) + assertEquals(0, a.getAndSet(3)) + assertTrue(a.compareAndSet(3, 8)) + a.lazySet(1) + assertEquals(1, a.value) + assertEquals(1, a.getAndSet(2)) + assertEquals(2, a.value) + assertEquals(2, a.getAndIncrement()) + assertEquals(3, a.value) + assertEquals(3, a.getAndDecrement()) + assertEquals(2, a.value) + assertEquals(2, a.getAndAdd(2)) + assertEquals(4, a.value) + assertEquals(7, a.addAndGet(3)) + assertEquals(7, a.value) + assertEquals(8, a.incrementAndGet()) + assertEquals(8, a.value) + assertEquals(7, a.decrementAndGet()) + assertEquals(7, a.value) + assertTrue(a.compareAndSet(7, 10)) + } + + fun testTopLevelLong() { + assertEquals(2424920024888888848, b.value) + b.lazySet(8424920024888888848) + assertEquals(8424920024888888848, b.value) + assertEquals(8424920024888888848, b.getAndSet(8924920024888888848)) + assertEquals(8924920024888888848, b.value) + assertEquals(8924920024888888849, b.incrementAndGet()) + assertEquals(8924920024888888849, b.value) + assertEquals(8924920024888888849, b.getAndDecrement()) + assertEquals(8924920024888888848, b.value) + assertEquals(8924920024888888848, b.getAndAdd(100000000000000000)) + assertEquals(9024920024888888848, b.value) + assertEquals(-198452011965886959, b.addAndGet(-9223372036854775807)) + assertEquals(-198452011965886959, b.value) + assertEquals(-198452011965886958, b.incrementAndGet()) + assertEquals(-198452011965886958, b.value) + assertEquals(-198452011965886959, b.decrementAndGet()) + assertEquals(-198452011965886959, b.value) + } + + fun testTopLevelBoolean() { + assertTrue(c.value) + c.lazySet(false) + assertFalse(c.value) + assertTrue(!c.getAndSet(true)) + assertTrue(c.compareAndSet(true, false)) + assertFalse(c.value) + } + + fun testTopLevelRef() { + assertEquals(8, abcNode.value.b.c.d) + val newNode = ANode(BNode(CNode(76))) + assertEquals(8, abcNode.getAndSet(newNode).b.c.d) + assertEquals(76, abcNode.value.b.c.d) + val l = IntArray(4){i -> i} + any.lazySet(l) + assertEquals(2, (any.value as IntArray)[2]) + } + + fun testTopLevelArrayOfNulls() { + assertEquals(null, stringAtomicNullArr[0].value) + assertTrue(stringAtomicNullArr[0].compareAndSet(null, "aa")) + stringAtomicNullArr[1].lazySet("aa") + assertTrue(stringAtomicNullArr[0].value == stringAtomicNullArr[1].value) + } +} + +class TopLevelArrayTest { + + fun testIntArray() { + assertTrue(intArr[0].compareAndSet(0, 3)) + assertEquals(0, intArr[1].value) + intArr[0].lazySet(5) + assertEquals(5, intArr[0].value + intArr[1].value + intArr[2].value) + assertTrue(intArr[0].compareAndSet(5, 10)) + assertEquals(10, intArr[0].getAndDecrement()) + assertEquals(9, intArr[0].value) + intArr[2].value = 2 + assertEquals(2, intArr[2].value) + assertTrue(intArr[2].compareAndSet(2, 34)) + assertEquals(34, intArr[2].value) + } + + fun testLongArray() { + longArr[0].value = 2424920024888888848 + assertEquals(2424920024888888848, longArr[0].value) + longArr[0].lazySet(8424920024888888848) + assertEquals(8424920024888888848, longArr[0].value) + val ac = longArr[0].value + longArr[3].value = ac + assertEquals(8424920024888888848, longArr[3].getAndSet(8924920024888888848)) + assertEquals(8924920024888888848, longArr[3].value) + val ac1 = longArr[3].value + longArr[4].value = ac1 + assertEquals(8924920024888888849, longArr[4].incrementAndGet()) + assertEquals(8924920024888888849, longArr[4].value) + assertEquals(8924920024888888849, longArr[4].getAndDecrement()) + assertEquals(8924920024888888848, longArr[4].value) + longArr[4].value = 8924920024888888848 + assertEquals(8924920024888888848, longArr[4].getAndAdd(100000000000000000)) + val ac2 = longArr[4].value + longArr[1].value = ac2 + assertEquals(9024920024888888848, longArr[1].value) + assertEquals(-198452011965886959, longArr[1].addAndGet(-9223372036854775807)) + assertEquals(-198452011965886959, longArr[1].value) + assertEquals(-198452011965886958, longArr[1].incrementAndGet()) + assertEquals(-198452011965886958, longArr[1].value) + assertEquals(-198452011965886959, longArr[1].decrementAndGet()) + assertEquals(-198452011965886959, longArr[1].value) + } + + fun testBooleanArray() { + assertFalse(booleanArr[1].value) + booleanArr[1].compareAndSet(false, true) + booleanArr[0].lazySet(true) + assertFalse(booleanArr[2].getAndSet(true)) + assertTrue(booleanArr[0].value && booleanArr[1].value && booleanArr[2].value) + } + + @Suppress("UNCHECKED_CAST") + fun testRefArray() { + val a2 = ANode(BNode(CNode(2))) + val a3 = ANode(BNode(CNode(3))) + refArr[0].value = a2 + assertEquals(2, refArr[0].value!!.b.c.d) + assertTrue(refArr[0].compareAndSet(a2, a3)) + assertEquals(3, refArr[0].value!!.b.c.d) + val r0 = refArr[0].value + refArr[3].value = r0 + assertEquals(3, refArr[3].value!!.b.c.d) + val a = abcNode.value + assertTrue(refArr[3].compareAndSet(a3, a)) + } +} + +data class ANode(val b: T) +data class BNode(val c: T) +data class CNode(val d: Int) + +@Test +fun box() { + val primitiveTest = TopLevelPrimitiveTest() + primitiveTest.testTopLevelInt() + primitiveTest.testTopLevelLong() + primitiveTest.testTopLevelBoolean() + primitiveTest.testTopLevelRef() + primitiveTest.testTopLevelArrayOfNulls() + + val arrayTest = TopLevelArrayTest() + arrayTest.testIntArray() + arrayTest.testLongArray() + arrayTest.testBooleanArray() + arrayTest.testRefArray() +} diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt new file mode 100644 index 00000000000..8567a991c8c --- /dev/null +++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt @@ -0,0 +1,106 @@ +import kotlinx.atomicfu.* +import kotlin.test.* + +class TraceTest { + private val defaultTrace = Trace() + private val a1 = atomic(5, defaultTrace) + + private val traceWithSize = Trace(30) + private val a2 = atomic(1, traceWithSize) + + private val traceWithFormat = Trace(format = TraceFormat { i, text -> "[$i: $text]" }) + private val a = atomic(0, traceWithFormat) + + private val traceWithSizeAndFormat = Trace(30, TraceFormat { id, text -> "$id: $text"}) + private val a3 = atomic(2) + + private val shortTrace = Trace(4) + private val s = atomic(0, shortTrace.named("s")) + + fun testDefaultTrace() { + val oldValue = a1.value + defaultTrace { "before CAS value = $oldValue" } + val res = a1.compareAndSet(oldValue, oldValue * 10) + val newValue = a1.value + defaultTrace { "after CAS value = $newValue" } + } + + fun testTraceWithSize() { + val oldValue = a2.value + traceWithSize { "before CAS value = $oldValue" } + assertTrue(a2.compareAndSet(oldValue, oldValue * 10)) + traceWithSize { "after CAS value = ${a2.value}" } + traceWithSize { "before getAndDecrement value = ${a2.value}" } + a2.getAndDecrement() + assertEquals(9, a2.value) + traceWithSize { "after getAndDecrement value = ${a2.value}" } + } + + fun testTraceWithFormat() { + val oldValue = a3.value + traceWithFormat { "before CAS value = $oldValue" } + assertTrue(a3.compareAndSet(oldValue, oldValue * 10)) + traceWithFormat { "after CAS value = ${a3.value}" } + traceWithFormat { "before getAndDecrement value = ${a3.value}" } + a3.getAndDecrement() + assertEquals(19, a3.value) + traceWithFormat { "after getAndDecrement value = ${a3.value}" } + } + + fun testNamedTrace() { + s.value = 5 + shortTrace { "before CAS value = ${s.value}" } + s.compareAndSet(5, -2) + assertEquals(-2, s.value) + shortTrace { "after CAS value = ${s.value}" } + } + + private enum class Status { START, END } + + fun testMultipleAppend() { + val i = 1 + traceWithFormat.append(i, Status.START) + assertEquals(0, a.value) + a.incrementAndGet() + traceWithFormat.append(i, a.value, "incAndGet") + assertEquals(1, a.value) + a.lazySet(10) + traceWithFormat.append(i, a.value, "lazySet") + assertEquals(10, a.value) + traceWithFormat.append(i, Status.END) + } + + fun testTraceInBlock() { + a1.lazySet(5) + if (a1.value == 5) { + defaultTrace { "Value checked" } + if (a1.compareAndSet(5, 10)) { + defaultTrace { "CAS succeeded" } + } + } + assertEquals(10, a1.value) + while (true) { + if (a1.value == 10) { + defaultTrace.append("Value checked", a1.value) + a1.value = 15 + break + } else { + defaultTrace.append("Wrong value", a1.value) + } + } + } + + fun test() { + testDefaultTrace() + testTraceWithSize() + testTraceWithFormat() + testNamedTrace() + testMultipleAppend() + testTraceInBlock() + } +} + +@Test +fun box() { + TraceTest().test() +} \ No newline at end of file diff --git a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt index 5ffaa58d46f..379b6e2d508 100644 --- a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt +++ b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt @@ -12,6 +12,7 @@ private enum class TestProperty(shortName: String) { // effect on other Gradle tasks (ex: :kotlin-native:dist) that might be executed along with test task. KOTLIN_NATIVE_HOME("nativeHome"), COMPILER_CLASSPATH("compilerClasspath"), + COMPILER_PLUGINS("compilerPlugins"), CUSTOM_KLIBS("customKlibs"), TEST_TARGET("target"), TEST_MODE("mode"), @@ -77,12 +78,23 @@ private class ComputedTestProperties(private val task: Test) { private fun Test.ComputedTestProperties(init: ComputedTestProperties.() -> Unit): ComputedTestProperties = ComputedTestProperties(this).apply { init() } +/** + * @param taskName Name of Gradle task. + * @param tag Optional JUnit test tag. See https://junit.org/junit5/docs/current/user-guide/#writing-tests-tagging-and-filtering + * @param requirePlatformLibs Where platform KLIBs from the Kotlin/Native distribution are required for running this test. + * @param customCompilerDependencies The [Configuration]s that provide additional JARs to be added to the compiler's classpath. + * @param customTestDependencies The [Configuration]s that provide KLIBs to be added to Kotlin/Native compiler dependencies list + * along with Kotlin/Native stdlib KLIB and Kotlin/Native platform KLIBs (the latter only if [requirePlatformLibs] is `true`). + * @param compilerPluginDependencies The [Configuration]s that provide compiler plugins to be enabled for the Kotlin/Native compiler + * for the duration of test execution. + */ fun Project.nativeTest( taskName: String, tag: String?, requirePlatformLibs: Boolean = false, - customDependencies: List = emptyList(), - customKlibDependencies: List = emptyList() + customCompilerDependencies: List = emptyList(), + customTestDependencies: List = emptyList(), + compilerPluginDependencies: List = emptyList() ) = projectTest( taskName, jUnitMode = JUnitMode.JUnit5, @@ -141,7 +153,7 @@ fun Project.nativeTest( else null - customDependencies.forEach(::dependsOn) + customCompilerDependencies.forEach(::dependsOn) lazyClassPath { if (customNativeHome == null) { @@ -151,13 +163,18 @@ fun Project.nativeTest( this += file(customNativeHome).resolve("konan/lib/trove4j.jar") } - customDependencies.flatMapTo(this) { it.files } + customCompilerDependencies.flatMapTo(this) { it.files } } } + computeLazy(COMPILER_PLUGINS) { + compilerPluginDependencies.forEach(::dependsOn) + lazyClassPath { compilerPluginDependencies.flatMapTo(this) { it.files } } + } + computeLazy(CUSTOM_KLIBS) { - customKlibDependencies.forEach(::dependsOn) - lazyClassPath { customKlibDependencies.flatMapTo(this) { it.files } } + customTestDependencies.forEach(::dependsOn) + lazyClassPath { customTestDependencies.flatMapTo(this) { it.files } } } // Pass Gradle properties as JVM properties so test process can read them.