[kotlin-tooling-core] Allow nullable extra values
The change is binary compatible, but not source compatible. Potential clients like Google might need to adapt a potential `IdeaKotlinExtrasSerializationExtension` implementaiton. Right now, no such implementation is known
This commit is contained in:
committed by
Space Team
parent
622a88ff26
commit
704379934e
+5
-3
@@ -11,9 +11,11 @@ import com.google.protobuf.ByteString
|
||||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.IdeaExtrasProto
|
||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.ideaExtrasProto
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
||||
import org.jetbrains.kotlin.tooling.core.*
|
||||
import org.jetbrains.kotlin.tooling.core.Extras
|
||||
import org.jetbrains.kotlin.tooling.core.MutableExtras
|
||||
import org.jetbrains.kotlin.tooling.core.toMutableExtras
|
||||
import org.jetbrains.kotlin.tooling.core.withValue
|
||||
|
||||
fun Extras.toByteArray(context: IdeaKotlinSerializationContext): ByteArray {
|
||||
return context.IdeaExtrasProto(this).toByteArray()
|
||||
@@ -35,8 +37,8 @@ internal fun IdeaKotlinSerializationContext.IdeaExtrasProto(extras: Extras): Ide
|
||||
val context = this
|
||||
return ideaExtrasProto {
|
||||
extras.entries.forEach { (key, value) ->
|
||||
key as Extras.Key<Any?>
|
||||
val serializer = context.extrasSerializationExtension.serializer(key) ?: return@forEach
|
||||
serializer as IdeaKotlinExtrasSerializer<Any>
|
||||
val serialized = runCatching { serializer.serialize(context, value) ?: return@forEach }.getOrElse { exception ->
|
||||
logger.error("Failed to serialize $key, using ${serializer.javaClass.simpleName}", exception)
|
||||
return@forEach
|
||||
|
||||
+3
-3
@@ -18,10 +18,10 @@ import org.jetbrains.kotlin.tooling.core.Extras
|
||||
* inside the implementation of the given [IdeaKotlinExtrasSerializer]
|
||||
*/
|
||||
interface IdeaKotlinExtrasSerializationExtension {
|
||||
fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>?
|
||||
fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>?
|
||||
|
||||
object Empty : IdeaKotlinExtrasSerializationExtension {
|
||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = null
|
||||
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ private class IdeaKotlinExtrasSerializationExtensionBuilderImpl : IdeaKotlinExtr
|
||||
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
||||
private val map: Map<Extras.Key<*>, IdeaKotlinExtrasSerializer<*>>
|
||||
) : IdeaKotlinExtrasSerializationExtension {
|
||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||
@Suppress("unchecked_cast")
|
||||
return map[key] as? IdeaKotlinExtrasSerializer<T>
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.idea.serialize
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
interface IdeaKotlinExtrasSerializer<T : Any> {
|
||||
interface IdeaKotlinExtrasSerializer<T> {
|
||||
fun serialize(context: IdeaKotlinSerializationContext, value: T): ByteArray?
|
||||
fun deserialize(context: IdeaKotlinSerializationContext, data: ByteArray): T?
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ object TestIdeaExtrasSerializationExtension : IdeaKotlinExtrasSerializationExten
|
||||
val ignoredStringKey = extrasKeyOf<String>("ignored")
|
||||
val anySerializableKey = extrasKeyOf<Any>("serializable")
|
||||
|
||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = when {
|
||||
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = when {
|
||||
key == ignoredStringKey -> null
|
||||
key == anySerializableKey -> IdeaKotlinExtrasSerializer.javaIoSerializable<Any>()
|
||||
key.type == extrasTypeOf<String>() -> IdeaKotlinStringExtrasSerializer
|
||||
|
||||
+5
-5
@@ -6,14 +6,14 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.ide
|
||||
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationLogger
|
||||
import org.jetbrains.kotlin.tooling.core.Extras
|
||||
|
||||
internal fun IdeaKotlinSerializationContext(
|
||||
logger: Logger, extrasSerializationExtensions: List<IdeaKotlinExtrasSerializationExtension>
|
||||
logger: Logger, extrasSerializationExtensions: List<IdeaKotlinExtrasSerializationExtension>,
|
||||
): IdeaKotlinSerializationContext {
|
||||
return IdeaKotlinSerializationContextImpl(
|
||||
extrasSerializationExtension = IdeaKotlinExtrasSerializationExtensionImpl(logger, extrasSerializationExtensions),
|
||||
@@ -23,7 +23,7 @@ internal fun IdeaKotlinSerializationContext(
|
||||
|
||||
private class IdeaKotlinSerializationContextImpl(
|
||||
override val extrasSerializationExtension: IdeaKotlinExtrasSerializationExtension,
|
||||
override val logger: IdeaKotlinSerializationLogger
|
||||
override val logger: IdeaKotlinSerializationLogger,
|
||||
) : IdeaKotlinSerializationContext
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ private class IdeaKotlinSerializationContextImpl(
|
||||
|
||||
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
||||
private val logger: Logger,
|
||||
private val extensions: List<IdeaKotlinExtrasSerializationExtension>
|
||||
private val extensions: List<IdeaKotlinExtrasSerializationExtension>,
|
||||
) : IdeaKotlinExtrasSerializationExtension {
|
||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||
val serializers = extensions.mapNotNull { it.serializer(key) }
|
||||
|
||||
if (serializers.size == 1) {
|
||||
|
||||
@@ -127,6 +127,7 @@ public final class org/jetbrains/kotlin/tooling/core/ExtrasUtilsKt {
|
||||
public static final fun extrasOf ()Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||
public static final fun extrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||
public static final fun getOrPut (Lorg/jetbrains/kotlin/tooling/core/MutableExtras;Lorg/jetbrains/kotlin/tooling/core/Extras$Key;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||
public static final fun getOrPutNullable (Lorg/jetbrains/kotlin/tooling/core/MutableExtras;Lorg/jetbrains/kotlin/tooling/core/Extras$Key;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||
public static final fun mutableExtrasOf ()Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
||||
public static final fun mutableExtrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
||||
public static final fun plus (Lorg/jetbrains/kotlin/tooling/core/Extras;Ljava/lang/Iterable;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||
|
||||
+11
-11
@@ -62,9 +62,9 @@ import java.io.Serializable
|
||||
* .toExtras()
|
||||
* ```
|
||||
*/
|
||||
interface Extras : Collection<Entry<out Any>> {
|
||||
interface Extras : Collection<Entry<*>> {
|
||||
class Type<T> @UnsafeApi("Use 'extrasTypeOf()' instead") @PublishedApi internal constructor(
|
||||
internal val signature: String
|
||||
internal val signature: String,
|
||||
) : Serializable {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@@ -85,7 +85,7 @@ interface Extras : Collection<Entry<out Any>> {
|
||||
}
|
||||
|
||||
/* Not implemented as data class to ensure more controllable binary compatibility */
|
||||
class Key<T : Any> @PublishedApi internal constructor(
|
||||
class Key<T> @PublishedApi internal constructor(
|
||||
val type: Type<T>,
|
||||
val name: String? = null,
|
||||
) : Serializable {
|
||||
@@ -116,8 +116,8 @@ interface Extras : Collection<Entry<out Any>> {
|
||||
fun fromString(stableString: String): Key<*> {
|
||||
@OptIn(UnsafeApi::class) return if (stableString.contains(';')) {
|
||||
val split = stableString.split(';', limit = 2)
|
||||
Key(Type(split[0]), split[1])
|
||||
} else Key(Type(stableString))
|
||||
Key<Any?>(Type(split[0]), split[1])
|
||||
} else Key<Any?>(Type(stableString))
|
||||
}
|
||||
|
||||
private const val serialVersionUID = 0L
|
||||
@@ -125,7 +125,7 @@ interface Extras : Collection<Entry<out Any>> {
|
||||
}
|
||||
|
||||
/* Not implemented as data class to ensure more controllable binary compatibility */
|
||||
class Entry<T : Any>(val key: Key<T>, val value: T) : Serializable {
|
||||
class Entry<T>(val key: Key<T>, val value: T) : Serializable {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Entry<*>) return false
|
||||
@@ -152,22 +152,22 @@ interface Extras : Collection<Entry<out Any>> {
|
||||
|
||||
val keys: Set<Key<*>>
|
||||
val entries: Set<Entry<*>>
|
||||
operator fun <T : Any> get(key: Key<T>): T?
|
||||
operator fun <T> get(key: Key<T>): T?
|
||||
operator fun contains(key: Key<*>): Boolean
|
||||
override fun iterator(): Iterator<Entry<out Any>>
|
||||
override fun iterator(): Iterator<Entry<*>>
|
||||
}
|
||||
|
||||
interface MutableExtras : Extras {
|
||||
/**
|
||||
* @return The previous value or null if no previous value was set
|
||||
*/
|
||||
operator fun <T : Any> set(key: Key<T>, value: T): T?
|
||||
operator fun <T> set(key: Key<T>, value: T): T?
|
||||
|
||||
fun <T : Any> put(entry: Entry<T>): T?
|
||||
fun <T> put(entry: Entry<T>): T?
|
||||
|
||||
fun putAll(from: Iterable<Entry<*>>)
|
||||
|
||||
fun <T : Any> remove(key: Key<T>): T?
|
||||
fun <T> remove(key: Key<T>): T?
|
||||
|
||||
fun clear()
|
||||
}
|
||||
|
||||
+10
-10
@@ -11,7 +11,7 @@ import java.io.Serializable
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
internal class MutableExtrasImpl(
|
||||
initialEntries: Iterable<Entry<*>> = emptyList()
|
||||
initialEntries: Iterable<Entry<*>> = emptyList(),
|
||||
) : MutableExtras, AbstractExtras(), Serializable {
|
||||
|
||||
private val extras: MutableMap<Key<*>, Entry<*>> =
|
||||
@@ -28,11 +28,11 @@ internal class MutableExtrasImpl(
|
||||
|
||||
override fun isEmpty(): Boolean = extras.isEmpty()
|
||||
|
||||
override fun <T : Any> set(key: Key<T>, value: T): T? {
|
||||
override fun <T> set(key: Key<T>, value: T): T? {
|
||||
return put(Entry(key, value))
|
||||
}
|
||||
|
||||
override fun <T : Any> put(entry: Entry<T>): T? {
|
||||
override fun <T> put(entry: Entry<T>): T? {
|
||||
return extras.put(entry.key, entry)?.let { it.value as T }
|
||||
}
|
||||
|
||||
@@ -40,11 +40,11 @@ internal class MutableExtrasImpl(
|
||||
this.extras.putAll(from.associateBy { it.key })
|
||||
}
|
||||
|
||||
override fun <T : Any> get(key: Key<T>): T? {
|
||||
override fun <T> get(key: Key<T>): T? {
|
||||
return extras[key]?.let { it.value as T }
|
||||
}
|
||||
|
||||
override fun <T : Any> remove(key: Key<T>): T? {
|
||||
override fun <T> remove(key: Key<T>): T? {
|
||||
return extras.remove(key)?.let { it.value as T }
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ internal class MutableExtrasImpl(
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
internal class ImmutableExtrasImpl private constructor(
|
||||
private val extras: Map<Key<*>, Entry<*>>
|
||||
private val extras: Map<Key<*>, Entry<*>>,
|
||||
) : AbstractExtras(), Serializable {
|
||||
constructor(extras: Iterable<Entry<*>>) : this(extras.associateBy { it.key })
|
||||
|
||||
@@ -73,7 +73,7 @@ internal class ImmutableExtrasImpl private constructor(
|
||||
|
||||
override val entries: Set<Entry<*>> = extras.values.toSet()
|
||||
|
||||
override fun <T : Any> get(key: Key<T>): T? {
|
||||
override fun <T> get(key: Key<T>): T? {
|
||||
return extras[key]?.let { it.value as T }
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ abstract class AbstractExtras : Extras {
|
||||
override fun containsAll(elements: Collection<Entry<*>>): Boolean =
|
||||
entries.containsAll(elements)
|
||||
|
||||
override fun iterator(): Iterator<Entry<out Any>> = entries.iterator()
|
||||
override fun iterator(): Iterator<Entry<*>> = entries.iterator()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other === this) return true
|
||||
@@ -135,11 +135,11 @@ internal object EmptyExtras : AbstractExtras(), Serializable {
|
||||
|
||||
override fun isEmpty(): Boolean = true
|
||||
|
||||
override fun <T : Any> get(key: Key<T>): T? = null
|
||||
override fun <T> get(key: Key<T>): T? = null
|
||||
|
||||
override fun contains(key: Key<*>): Boolean = false
|
||||
|
||||
override fun contains(element: Entry<out Any>): Boolean = false
|
||||
override fun contains(element: Entry<*>): Boolean = false
|
||||
|
||||
@Suppress("unused") // Necessary for java.io.Serializable stability
|
||||
private const val serialVersionUID = 0L
|
||||
|
||||
+6
-6
@@ -11,19 +11,19 @@ import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface ExtrasProperty<T : Any> {
|
||||
interface ExtrasProperty<T> {
|
||||
val key: Extras.Key<T>
|
||||
}
|
||||
|
||||
val <T : Any> Extras.Key<T>.readWriteProperty get() = extrasReadWriteProperty(this)
|
||||
|
||||
fun <Receiver : HasMutableExtras, T : Any> Extras.Key<T>.lazyProperty(factory: Receiver.() -> T) = extrasLazyProperty(this, factory)
|
||||
fun <Receiver : HasMutableExtras, T> Extras.Key<T>.lazyProperty(factory: Receiver.() -> T) = extrasLazyProperty(this, factory)
|
||||
|
||||
fun <T : Any> extrasReadWriteProperty(key: Extras.Key<T>): ExtrasReadWriteProperty<T> = object : ExtrasReadWriteProperty<T> {
|
||||
override val key: Extras.Key<T> = key
|
||||
}
|
||||
|
||||
fun <Receiver : HasMutableExtras, T : Any> extrasLazyProperty(
|
||||
fun <Receiver : HasMutableExtras, T> extrasLazyProperty(
|
||||
key: Extras.Key<T>, factory: Receiver.() -> T,
|
||||
): ExtrasLazyProperty<Receiver, T> =
|
||||
object : ExtrasLazyProperty<Receiver, T> {
|
||||
@@ -36,7 +36,7 @@ inline fun <reified T : Any> extrasReadWriteProperty(name: String? = null) =
|
||||
extrasReadWriteProperty(extrasKeyOf<T>(name))
|
||||
|
||||
|
||||
inline fun <Receiver : HasMutableExtras, reified T : Any> extrasLazyProperty(name: String? = null, noinline factory: Receiver.() -> T) =
|
||||
inline fun <Receiver : HasMutableExtras, reified T> extrasLazyProperty(name: String? = null, noinline factory: Receiver.() -> T) =
|
||||
extrasLazyProperty(extrasKeyOf(name), factory)
|
||||
|
||||
|
||||
@@ -76,11 +76,11 @@ interface NotNullExtrasReadWriteProperty<T : Any> : ExtrasProperty<T>, ReadWrite
|
||||
}
|
||||
}
|
||||
|
||||
interface ExtrasLazyProperty<Receiver : HasMutableExtras, T : Any> : ExtrasProperty<T>, ReadWriteProperty<Receiver, T> {
|
||||
interface ExtrasLazyProperty<Receiver : HasMutableExtras, T> : ExtrasProperty<T>, ReadWriteProperty<Receiver, T> {
|
||||
val factory: Receiver.() -> T
|
||||
|
||||
override fun getValue(thisRef: Receiver, property: KProperty<*>): T {
|
||||
return thisRef.extras.getOrPut(key) { thisRef.factory() }
|
||||
return thisRef.extras.getOrPutNullable(key) { thisRef.factory() }
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Receiver, property: KProperty<*>, value: T) {
|
||||
|
||||
+10
-3
@@ -26,7 +26,7 @@ import kotlin.reflect.typeOf
|
||||
* extrasKeyOf<String>("a") != extrasKeyOf<Int>("a")
|
||||
* ```
|
||||
*/
|
||||
inline fun <reified T : Any> extrasKeyOf(name: String? = null): Extras.Key<T> =
|
||||
inline fun <reified T> extrasKeyOf(name: String? = null): Extras.Key<T> =
|
||||
Extras.Key(extrasTypeOf(), name)
|
||||
|
||||
fun emptyExtras(): Extras = EmptyExtras
|
||||
@@ -48,7 +48,7 @@ fun Iterable<Extras.Entry<*>>.toExtras(): Extras = ImmutableExtrasImpl(this)
|
||||
|
||||
fun Iterable<Extras.Entry<*>>.toMutableExtras(): MutableExtras = MutableExtrasImpl(this)
|
||||
|
||||
infix fun <T : Any> Extras.Key<T>.withValue(value: T): Extras.Entry<T> = Extras.Entry(this, value)
|
||||
infix fun <T> Extras.Key<T>.withValue(value: T): Extras.Entry<T> = Extras.Entry(this, value)
|
||||
|
||||
operator fun Extras.plus(entry: Extras.Entry<*>): Extras = ImmutableExtrasImpl(this.entries + entry)
|
||||
|
||||
@@ -56,4 +56,11 @@ operator fun Extras.plus(entries: Iterable<Extras.Entry<*>>): Extras = Immutable
|
||||
|
||||
inline fun <T : Any> MutableExtras.getOrPut(key: Extras.Key<T>, defaultValue: () -> T): T {
|
||||
return this[key] ?: defaultValue().also { this[key] = it }
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> MutableExtras.getOrPutNullable(key: Extras.Key<T>, defaultValue: () -> T): T {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (key in this) return this[key] as T
|
||||
return defaultValue().also { this[key] = it }
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.tooling.core
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.test.*
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -18,6 +19,7 @@ class ExtrasPropertyTest {
|
||||
|
||||
private val keyA = extrasKeyOf<Int>("a")
|
||||
private val keyB = extrasKeyOf<Int>("b")
|
||||
private val keyANullable = extrasKeyOf<Int?>("a")
|
||||
|
||||
private val Subject.readA: Int? by keyA.readProperty
|
||||
private val Subject.readB: Int? by keyB.readProperty
|
||||
@@ -171,4 +173,39 @@ class ExtrasPropertyTest {
|
||||
assertEquals("OK", subject2.lazyNullableString)
|
||||
assertEquals(listOf(subject1, subject2), lazyNullableStringInvocations)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - lazyProperty - with nullable key`() {
|
||||
val subject = Subject()
|
||||
val invocationCounter = AtomicInteger(0)
|
||||
|
||||
with(object {
|
||||
val Subject.lazyProperty by keyANullable.lazyProperty {
|
||||
assertEquals(0, invocationCounter.getAndIncrement())
|
||||
null
|
||||
}
|
||||
}) {
|
||||
assertNull(subject.lazyProperty)
|
||||
assertNull(subject.lazyProperty)
|
||||
assertEquals(1, invocationCounter.get())
|
||||
|
||||
invocationCounter.set(0)
|
||||
assertEquals(null, Subject().lazyProperty)
|
||||
assertEquals(1, invocationCounter.get())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - lazyProperty - with nullable key - set key to null manually`() {
|
||||
with(object {
|
||||
val Subject.lazyProperty by keyANullable.lazyProperty {
|
||||
fail("Unexpected call to factory function")
|
||||
}
|
||||
}) {
|
||||
val subject = Subject()
|
||||
subject.extras[keyANullable] = null
|
||||
assertNull(subject.lazyProperty)
|
||||
assertTrue(keyANullable in subject.extras)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+52
-10
@@ -24,22 +24,22 @@ class ExtrasTest {
|
||||
assertNull(extras[extrasKeyOf<String>("a")])
|
||||
assertNull(extras[extrasKeyOf<String>("b")])
|
||||
|
||||
extras[extrasKeyOf()] = "22222"
|
||||
assertEquals("22222", extras[extrasKeyOf()])
|
||||
assertNull(extras[extrasKeyOf("a")])
|
||||
assertNull(extras[extrasKeyOf("b")])
|
||||
extras[extrasKeyOf<String>()] = "22222"
|
||||
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||
assertNull(extras[extrasKeyOf<String>("a")])
|
||||
assertNull(extras[extrasKeyOf<String>("b")])
|
||||
|
||||
extras[extrasKeyOf("a")] = "value a"
|
||||
assertEquals("22222", extras[extrasKeyOf()])
|
||||
assertEquals("value a", extras[extrasKeyOf("a")])
|
||||
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||
assertEquals("value a", extras[extrasKeyOf<String>("a")])
|
||||
assertNull(extras[extrasKeyOf("b")])
|
||||
|
||||
extras[extrasKeyOf("b")] = "value b"
|
||||
assertEquals("22222", extras[extrasKeyOf()])
|
||||
assertEquals("value a", extras[extrasKeyOf("a")])
|
||||
assertEquals("value b", extras[extrasKeyOf("b")])
|
||||
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||
assertEquals("value a", extras[extrasKeyOf<String>("a")])
|
||||
assertEquals("value b", extras[extrasKeyOf<String>("b")])
|
||||
|
||||
assertNull(extras[extrasKeyOf("c")])
|
||||
assertNull(extras[extrasKeyOf<String>("c")])
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -286,4 +286,46 @@ class ExtrasTest {
|
||||
extras
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - extras - nullable key`() {
|
||||
val empty = extrasOf()
|
||||
assertNull(empty[extrasKeyOf<String>()])
|
||||
assertNull(empty[extrasKeyOf<String?>()])
|
||||
|
||||
val nonEmpty = extrasOf(
|
||||
extrasKeyOf<String>() withValue "!",
|
||||
extrasKeyOf<String?>() withValue "?"
|
||||
)
|
||||
|
||||
assertEquals("!", nonEmpty[extrasKeyOf<String>()])
|
||||
assertEquals("?", nonEmpty[extrasKeyOf<String?>()])
|
||||
|
||||
val containsNull = extrasOf(
|
||||
extrasKeyOf<String>() withValue "!",
|
||||
extrasKeyOf<String?>() withValue null
|
||||
)
|
||||
|
||||
assertEquals("!", containsNull[extrasKeyOf<String>()])
|
||||
assertNull(containsNull[extrasKeyOf<String?>()])
|
||||
assertTrue(extrasKeyOf<String?>() in containsNull)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - mutable extras - nullable key`() {
|
||||
val extras = mutableExtrasOf()
|
||||
assertNull(extras[extrasKeyOf<String>()])
|
||||
assertNull(extras[extrasKeyOf<String?>()])
|
||||
|
||||
extras[extrasKeyOf<String>()] = "!"
|
||||
extras[extrasKeyOf<String?>()] = "?"
|
||||
|
||||
assertEquals("!", extras[extrasKeyOf<String>()])
|
||||
assertEquals("?", extras[extrasKeyOf<String?>()])
|
||||
|
||||
extras[extrasKeyOf<String?>()] = null
|
||||
assertEquals("!", extras[extrasKeyOf<String>()])
|
||||
assertNull(extras[extrasKeyOf<String?>()])
|
||||
assertTrue(extrasKeyOf<String?>() in extras)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user