Missed expect functions for atomics and tests

This commit is contained in:
Andrew Golovashevich 2025-08-22 14:20:55 +03:00
parent 860ffa98e0
commit e8d899928e
10 changed files with 258 additions and 11 deletions

View File

@ -63,10 +63,16 @@ xomrk {
val commonMain by getting {
dependencies {
compileOnly(kotlinStdlibDependency)
implementation(kotlinStdlibDependency)
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.5")
}
}
val commonTest by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test:${this@kotlin.coreLibrariesVersion}")
}
}
val jvmMain by getting {
dependsOn(commonMain)
dependencies {

View File

@ -10,7 +10,7 @@ import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
@OptIn(ManualStateManipulation::class)
@JvmName("use\$kt")
public inline fun <R> CloseableState.use(block: () -> R): R {
public inline fun <R> CloseableState.withUse(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}

View File

@ -0,0 +1,10 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.test.Test
internal class ErrorOnConcurrentAccessStateTest: _CloseableStateExternallySynchronizedAbstractTestSet() {
override fun createState(): CloseableState = ErrorOnConcurrentAccessState()
@Test
fun test() {}
}

View File

@ -0,0 +1,4 @@
package ru.landgrafhomyak.utility.closeable_state
internal class TestThrowable: Throwable("If this throwable isn't caught then test is bad written") {
}

View File

@ -0,0 +1,10 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.test.Test
internal class UsagesCounterTest: _CloseableStateAllowsConcurrencyAbstractTestSet() {
override fun createState(): CloseableState = UsagesCounter()
@Test
fun test() {}
}

View File

@ -0,0 +1,91 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateAbstractTestSet {
abstract fun createState(): CloseableState
@Test
fun testInstantClose() {
this.createState().close()
}
@Test
fun testOneManual() {
val s = this.createState()
s.startUsage()
s.finishUsage()
s.close()
}
@Test
fun testOneAuto() {
val s = this.createState()
s.withUse { }
s.close()
}
@Test
fun testSubsequentManual() {
val s = this.createState()
s.startUsage()
s.finishUsage()
s.startUsage()
s.finishUsage()
s.startUsage()
s.finishUsage()
s.close()
}
@Test
fun testSubsequentAuto() {
val s = this.createState()
s.withUse { }
s.withUse { }
s.withUse { }
s.close()
}
@Test
fun testTryStartSuccess() {
val s = this.createState()
s.tryStartUsage { }
s.finishUsage()
s.close()
}
@Test
fun testTryStartFailed() {
val s = this.createState()
try {
s.tryStartUsage { throw TestThrowable() }
} catch (_: TestThrowable) {
}
s.close()
}
@Test
fun testTryFinishSuccess() {
val s = this.createState()
s.startUsage()
s.tryFinishUsage { }
s.close()
}
@Test
fun testTryFinishFailed() {
val s = this.createState()
s.startUsage()
try {
s.tryFinishUsage { throw TestThrowable() }
} catch (_: TestThrowable) {
}
try {
s.close()
} catch (_: Throwable) {}
s.finishUsage()
s.close()
}
}

View File

@ -0,0 +1,25 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateAllowsConcurrencyAbstractTestSet: _CloseableStateAbstractTestSet() {
abstract override fun createState(): CloseableState
@Test
fun testRecursionManual() {
val s = this.createState()
s.startUsage()
s.startUsage()
s.finishUsage()
s.finishUsage()
s.close()
}
@Test
fun testRecursionAuto() {
val s = this.createState()
s.withUse { s.withUse { } }
s.close()
}
}

View File

@ -0,0 +1,32 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateExternallySynchronizedAbstractTestSet : _CloseableStateAbstractTestSet() {
abstract override fun createState(): CloseableState
@Test
fun testRecursionManual() {
val s = this.createState()
s.startUsage()
try {
s.startUsage()
} catch (_: Throwable) {
}
s.finishUsage()
s.close()
}
@Test
fun testRecursionAuto() {
val s = this.createState()
s.withUse {
try {
s.withUse {}
} catch (_: Throwable) {
}
}
s.close()
}
}

View File

@ -4,9 +4,9 @@ import org.testng.annotations.Test
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.closeable_state.ManualStateManipulation
import ru.landgrafhomyak.utility.closeable_state.UsagesCounter
import ru.landgrafhomyak.utility.closeable_state.use
import ru.landgrafhomyak.utility.closeable_state.withUse
@Test
@Test(enabled = false)
class KotlinStdlibDependencyTest {
@Test
fun testNoKotlinStdlib() {
@ -52,11 +52,11 @@ class KotlinStdlibDependencyTest {
fun testWithRef() {
try {
val refcnt = UsagesCounter()
refcnt.use {
return@use CustomUnit
refcnt.withUse {
return@withUse CustomUnit
}
refcnt.use w1@{
return@w1 refcnt.use w2@{
refcnt.withUse w1@{
return@w1 refcnt.withUse w2@{
return@w2 CustomUnit
}
}
@ -70,7 +70,7 @@ class KotlinStdlibDependencyTest {
fun testWithRef_Err() {
try {
val refcnt = UsagesCounter()
refcnt.use {
refcnt.withUse {
throw CustomTestException()
}
} catch (_: CustomTestException) {

View File

@ -1,8 +1,77 @@
@file:Suppress("USELESS_CAST", "NOTHING_TO_INLINE")
@file:JvmName("AtomicsKt")
package ru.landgrafhomyak.utility.closeable_state.internal
import kotlin.jvm.JvmName
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.AtomicLong as kAtomicLong
import kotlinx.atomicfu.AtomicRef as kAtomicRef
import kotlinx.atomicfu.update
import kotlinx.atomicfu.getAndUpdate
internal actual typealias AtomicLong = kotlinx.atomicfu.AtomicLong
internal actual typealias AtomicReference<T> = kotlinx.atomicfu.AtomicRef<T>
internal actual typealias AtomicLong = kAtomicLong
internal actual typealias AtomicReference<T> = kAtomicRef<T>
internal actual inline fun newAtomicLong(initial: Long): AtomicLong =
atomic(initial)
internal actual inline fun <T> newAtomicRef(initial: T): AtomicReference<T> =
atomic(initial)
internal actual inline fun AtomicLong.get(): Long =
(this as kAtomicLong).value
internal actual inline fun <T> AtomicReference<T>.get(): T =
(this as kAtomicRef).value
internal actual inline fun AtomicLong.update(operator: (Long) -> Long) =
(this as kAtomicLong).update(operator)
internal actual inline fun <T> AtomicReference<T>.update(operator: (T) -> T) =
(this as kAtomicRef).update(operator)
internal actual inline fun AtomicLong.getAndUpdate(operator: (Long) -> Long): Long =
(this as kAtomicLong).getAndUpdate(operator)
internal actual inline fun <T> AtomicReference<T>.getAndUpdate(operator: (T) -> T): T =
(this as kAtomicRef).getAndUpdate(operator)
internal actual inline fun AtomicLong.compareAndSet(expected: Long, newValue: Long): Boolean =
(this as kAtomicLong).compareAndSet(expected, newValue)
internal actual inline fun <T> AtomicReference<T>.compareAndSet(expected: T, newValue: T): Boolean =
(this as kAtomicRef).compareAndSet(expected, newValue)
private fun AtomicLong.compareAndExchange_impl(expected: Long, newValue: Long): Long {
val a = (this as kAtomicLong)
return Misc._compareAndExchange(
get = a::get,
cas = a::compareAndSet,
expected = expected, newValue = newValue
)
}
private fun <T> AtomicReference<T>.compareAndExchange_impl(expected: T, newValue: T): T {
val a = (this as kAtomicRef)
return Misc._compareAndExchange(
get = a::get,
cas = a::compareAndSet,
expected = expected, newValue = newValue
)
}
internal actual inline fun AtomicLong.compareAndExchange(expected: Long, newValue: Long): Long {
return this.compareAndExchange_impl(expected, newValue)
}
internal actual inline fun <T> AtomicReference<T>.compareAndExchange(expected: T, newValue: T): T {
return this.compareAndExchange_impl(expected, newValue)
}