Skip to content

Commit f61cc6a

Browse files
committed
[ECO-5338] Created tests package for liveobjects
1. Added test specific dependencies, updated junit, added mockk 2. Added test utils for mocking private classes, fields etc
1 parent ac0ece7 commit f61cc6a

3 files changed

Lines changed: 68 additions & 1 deletion

File tree

gradle/libs.versions.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[versions]
22
agp = "8.5.2"
3-
junit = "4.12"
3+
junit = "4.13.2"
44
gson = "2.9.0"
55
msgpack = "0.8.11"
66
java-websocket = "1.5.3"
@@ -21,6 +21,7 @@ okhttp = "4.12.0"
2121
test-retry = "1.6.0"
2222
kotlin = "2.1.10"
2323
coroutine = "1.9.0"
24+
mockk = "1.13.13"
2425
turbine = "1.2.0"
2526
jetbrains-annoations = "26.0.2"
2627

@@ -47,6 +48,7 @@ android-retrostreams = { group = "net.sourceforge.streamsupport", name = "androi
4748
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
4849
coroutine-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutine" }
4950
coroutine-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutine" }
51+
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
5052
turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" }
5153
jetbrains = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annoations" }
5254

live-objects/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ dependencies {
1212
testImplementation(kotlin("test"))
1313
implementation(libs.coroutine.core)
1414

15+
testImplementation(libs.junit)
16+
testImplementation(libs.mockk)
1517
testImplementation(libs.coroutine.test)
18+
testImplementation(libs.nanohttpd)
19+
testImplementation(libs.turbine)
1620
}
1721

1822
tasks.test {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package io.ably.lib.objects
2+
3+
import java.lang.reflect.Field
4+
import kotlinx.coroutines.Dispatchers
5+
import kotlinx.coroutines.delay
6+
import kotlinx.coroutines.suspendCancellableCoroutine
7+
import kotlinx.coroutines.withContext
8+
import kotlinx.coroutines.withTimeout
9+
10+
suspend fun assertWaiter(timeoutInMs: Long = 10_000, block: suspend () -> Boolean) {
11+
withContext(Dispatchers.Default) {
12+
withTimeout(timeoutInMs) {
13+
do {
14+
val success = block()
15+
delay(100)
16+
} while (!success)
17+
}
18+
}
19+
}
20+
21+
fun Any.setPrivateField(name: String, value: Any?) {
22+
val valueField = javaClass.findField(name)
23+
valueField.isAccessible = true
24+
valueField.set(this, value)
25+
}
26+
27+
fun <T>Any.getPrivateField(name: String): T {
28+
val valueField = javaClass.findField(name)
29+
valueField.isAccessible = true
30+
@Suppress("UNCHECKED_CAST")
31+
return valueField.get(this) as T
32+
}
33+
34+
private fun Class<*>.findField(name: String): Field {
35+
var result = kotlin.runCatching { getDeclaredField(name) }
36+
var currentClass = this
37+
while (result.isFailure && currentClass.superclass != null) // stop when we got field or reached top of class hierarchy
38+
{
39+
currentClass = currentClass.superclass!!
40+
result = kotlin.runCatching { currentClass.getDeclaredField(name) }
41+
}
42+
if (result.isFailure) {
43+
throw result.exceptionOrNull() as Exception
44+
}
45+
return result.getOrNull() as Field
46+
}
47+
48+
suspend fun <T>Any.invokePrivateSuspendMethod(methodName: String, vararg args: Any?) = suspendCancellableCoroutine<T> { cont ->
49+
val suspendMethod = javaClass.declaredMethods.find { it.name == methodName }
50+
suspendMethod?.let {
51+
it.isAccessible = true
52+
it.invoke(this, *args, cont)
53+
}
54+
}
55+
56+
fun <T> Any.invokePrivateMethod(methodName: String, vararg args: Any?): T {
57+
val method = javaClass.declaredMethods.find { it.name == methodName }
58+
method?.isAccessible = true
59+
@Suppress("UNCHECKED_CAST")
60+
return method?.invoke(this, *args) as T
61+
}

0 commit comments

Comments
 (0)