/* * 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 test.utils import kotlin.concurrent.AtomicInt import kotlin.native.concurrent.* import kotlin.test.* abstract class AbstractExplicitModeLazyTest { abstract val mode: LazyThreadSafetyMode @Test fun finiteRecursion() { var y = 20 class C { val finiteRecursion: Int by lazy(mode) { if (y < 17) 42 else { y -= 1 finiteRecursion + 1 } } } assertEquals(if (mode == LazyThreadSafetyMode.SYNCHRONIZED) 46 else 42, C().finiteRecursion) } @Test fun captureThis() { class C { val self by lazy(mode) { this } } val self = C() assertEquals(self, self.self) } @Test fun throwException() { class C { val thrower by lazy(mode) { error("failure") } } val self = C() repeat(10) { assertFailsWith { self.thrower } } } @Test fun multiThreadedInit() { val initializerCallCount = AtomicInt(0) class C { val data by lazy(mode) { initializerCallCount.getAndIncrement() Any() } } val self = C() val workers = Array(20) { Worker.start() } val initialized = AtomicInt(0) val canStart = AtomicInt(0) val futures = workers.map { it.execute(TransferMode.SAFE, { Triple(initialized, canStart, self) }) { (initialized, canStart, self) -> initialized.incrementAndGet() while (canStart.value != 1) { } self.data } } while (initialized.value < workers.size) { } canStart.value = 1 val results = mutableSetOf() futures.forEach { results += it.result } if (mode == LazyThreadSafetyMode.SYNCHRONIZED) { assertEquals(1, initializerCallCount.value) } else { assertTrue(initializerCallCount.value > 0) assertTrue(initializerCallCount.value <= workers.size) } assertSame(self.data, results.single()) workers.forEach { it.requestTermination().result } } } class SynchronizedExplicitModeLazyTest : AbstractExplicitModeLazyTest() { override val mode: LazyThreadSafetyMode get() = LazyThreadSafetyMode.SYNCHRONIZED } class PublicationExplicitModeLazyTest : AbstractExplicitModeLazyTest() { override val mode: LazyThreadSafetyMode get() = LazyThreadSafetyMode.PUBLICATION }