/* * Copyright 2010-2020 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.properties.delegation.references import kotlin.reflect.* import kotlin.test.* import kotlin.internal.* import kotlin.native.concurrent.ThreadLocal import kotlin.random.* open class Data(val stringVal: String, var intVar: Int, var builderVar: StringBuilder = StringBuilder("default")) val Data.formattedVal: String get() = "Hello $stringVal" var Data.displacedVar: Int get() = intVar + 2 set(value) { intVar = value - 2 } @ThreadLocal val data = Data("bound string", 42) val topVal: Double get() = 3.14 @ThreadLocal var topVar: ULong = 0xFFFFUL // top-level properties // val to bound val @ThreadLocal val tlValBoundVal by data::stringVal // val to bound var @ThreadLocal val tlValBoundVar by data::intVar // var to bound var @ThreadLocal var tlVarBoundVar by data::intVar // val to top-level val @ThreadLocal val tlValTopLevelVal by ::topVal // val to top-level var @ThreadLocal val tlValTopLevelVar by ::topVar // var to top-level var @ThreadLocal var tlVarTopLevelVar by ::topVar // member properties class DataExt : Data("member string", -1) { // val to top-level val val valTopLevelVal by ::topVal // val to top-level var val valTopLevelVar by ::topVar // var to top-level var var varTopLevelVar by ::topVar // val to bound val val valBoundVal by this::stringVal // val to bound var val valBoundVar by data::intVar // var to bound var var varBoundVar by ::intVar // val to extension val val valExtVal by Data::formattedVal // val to extension var val valExtVar by Data::displacedVar // var to extension var var varExtVar by Data::displacedVar } // extension properties // val to bound val @ThreadLocal val Data.extValBoundVal by data::stringVal // val to bound var @ThreadLocal val Data.extValBoundVar by data::intVar // var to bound var @ThreadLocal var Data.extVarBoundVar by data::intVar // val to top-level val @ThreadLocal val Data.extValTopLevelVal by ::topVal // val to top-level var @ThreadLocal val Data.extValTopLevelVar by ::topVar // var to top-level var @ThreadLocal var Data.extVarTopLevelVar by ::topVar // val to member val @ThreadLocal val Data.extValMemberVal by Data::stringVal // val to member var @ThreadLocal val Data.extValMemberVar by Data::intVar // var to member var @ThreadLocal var Data.extVarMemberVar by Data::intVar // val to extension val @ThreadLocal val Data.extValExtVal by Data::formattedVal // val to extension var @ThreadLocal val Data.extValExtVar by Data::displacedVar // var to extension var @ThreadLocal var Data.extVarExtVar by Data::displacedVar // covariance @ThreadLocal val covariantVal: Number by ::topVal @ThreadLocal val Data.extCovariantVal: CharSequence by Data::builderVar @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") class PropertyReferenceTest { private fun checkDelegate0(delegated: KProperty0<@NoInfer V>, source: KProperty0) { assertEquals(delegated.get(), source.get()) } private fun checkDelegate1(delegated: KProperty0<@NoInfer V>, source: KMutableProperty0, newValue: @NoInfer V) { assertEquals(delegated.get(), source.get()) source.set(newValue) assertEquals(newValue, source.get()) assertEquals(newValue, delegated.get()) } private fun checkDelegate2(delegated: KMutableProperty0<@NoInfer V>, source: KMutableProperty0, newValue1: @NoInfer V, newValue2: @NoInfer V) { assertEquals(delegated.get(), source.get()) source.set(newValue1) assertEquals(newValue1, source.get()) assertEquals(newValue1, delegated.get()) delegated.set(newValue2) assertEquals(newValue2, source.get()) assertEquals(newValue2, delegated.get()) } private fun int(): Int = Random.nextInt() private fun ulong(): ULong = Random.nextULong() @Test fun topLevelProperties() { checkDelegate0(::tlValBoundVal, data::stringVal) checkDelegate1(::tlValBoundVar, data::intVar, int()) checkDelegate2(::tlVarBoundVar, data::intVar, int(), int()) checkDelegate0(::tlValTopLevelVal, ::topVal) checkDelegate1(::tlValTopLevelVar, ::topVar, ulong()) checkDelegate2(::tlVarTopLevelVar, ::topVar, ulong(), ulong()) } @Test fun memberProperties() { val local = DataExt() checkDelegate0(local::valBoundVal, local::stringVal) checkDelegate1(local::valBoundVar, data::intVar, int()) checkDelegate2(local::varBoundVar, local::intVar, int(), int()) checkDelegate0(local::valTopLevelVal, ::topVal) checkDelegate1(local::valTopLevelVar, ::topVar, ulong()) checkDelegate2(local::varTopLevelVar, ::topVar, ulong(), ulong()) checkDelegate0(local::valExtVal, local::formattedVal) checkDelegate1(local::valExtVar, local::displacedVar, int()) checkDelegate2(local::varExtVar, local::displacedVar, int(), int()) } @Test fun extensionProperties() { val local = Data("ext", Int.MAX_VALUE) checkDelegate0(local::extValBoundVal, data::stringVal) checkDelegate1(local::extValBoundVar, data::intVar, int()) checkDelegate2(local::extVarBoundVar, data::intVar, int(), int()) checkDelegate0(local::extValMemberVal, local::stringVal) checkDelegate1(local::extValMemberVar, local::intVar, int()) checkDelegate2(local::extVarMemberVar, local::intVar, int(), int()) checkDelegate0(local::extValTopLevelVal, ::topVal) checkDelegate1(local::extValTopLevelVar, ::topVar, ulong()) checkDelegate2(local::extVarTopLevelVar, ::topVar, ulong(), ulong()) checkDelegate0(local::extValExtVal, local::formattedVal) checkDelegate1(local::extValExtVar, local::displacedVar, int()) checkDelegate2(local::extVarExtVar, local::displacedVar, int(), int()) } @Test fun covariantProperties() { checkDelegate0(::covariantVal, ::topVal) checkDelegate0(data::extCovariantVal, data::builderVar) } }