/
InternalPlatform.kt
166 lines (142 loc) · 5.88 KB
/
InternalPlatform.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package io.mockk.impl
import io.mockk.InternalPlatformDsl
import io.mockk.MockKException
import io.mockk.StackElement
import io.mockk.boxedClass
import io.mockk.boxedValue
import io.mockk.impl.platform.CommonIdentityHashMapOf
import io.mockk.impl.platform.CommonRef
import io.mockk.impl.platform.JvmWeakConcurrentMap
import java.lang.ref.WeakReference
import java.lang.reflect.Modifier
import java.util.Collections
import java.util.Collections.synchronizedList
import java.util.Locale
import kotlin.reflect.KClass
import kotlin.reflect.full.cast
actual object InternalPlatform {
actual fun time(): Long = System.nanoTime()
actual fun ref(obj: Any): Ref = CommonRef(obj)
actual fun hkd(obj: Any): String = Integer.toHexString(InternalPlatformDsl.identityHashCode(obj))
actual fun isPassedByValue(cls: KClass<*>): Boolean {
return when (cls) {
java.lang.Boolean::class -> true
java.lang.Byte::class -> true
java.lang.Short::class -> true
java.lang.Character::class -> true
java.lang.Integer::class -> true
java.lang.Long::class -> true
java.lang.Float::class -> true
java.lang.Double::class -> true
java.lang.String::class -> true
else -> false
}
}
actual fun <K, V> MutableMap<K, V>.customComputeIfAbsent(key: K, valueFunc: (K) -> V): V {
val value = get(key)
return if (value == null) {
val newValue = valueFunc(key)
put(key, newValue)
newValue
} else {
value
}
}
actual fun <K, V> weakMap(): MutableMap<K, V> = JvmWeakConcurrentMap()
actual fun <K, V> identityMap(): MutableMap<K, V> = CommonIdentityHashMapOf()
actual fun <T> synchronizedMutableList(): MutableList<T> {
return synchronizedList(mutableListOf<T>())
}
actual fun <K, V> synchronizedMutableMap(): MutableMap<K, V> = Collections.synchronizedMap(hashMapOf())
actual fun packRef(arg: Any?): Any? {
return when {
arg == null -> null
isPassedByValue(arg.boxedClass()) -> arg.boxedValue()
else -> ref(arg)
}
}
actual fun prettifyRecordingException(ex: Throwable): Throwable {
return when {
ex is ClassCastException ->
MockKException(
when {
ex.message == null ->
"Class cast exception happened.\n" +
"WARN: 'message' property in ClassCastException provided by JVM is null, autohinting is not possible. \n" +
"This is most probably happening due to Java optimization enabled. \n" +
"You can use `hint` before call or use -XX:-OmitStackTraceInFastThrow to disable this optimization behaviour and make autohiniting work. \n" +
"For example in gradle use: \n" +
"\n" +
"test {\n" +
" jvmArgs '-XX:-OmitStackTraceInFastThrow'\n" +
"}"
else -> "Class cast exception happened.\n" +
"Probably type information was erased.\n" +
"In this case use `hint` before call to specify " +
"exact return type of a method.\n"
}, ex
)
ex is NoClassDefFoundError &&
ex.message?.contains("kotlinx/coroutines/") ?: false ->
MockKException(
"Add coroutines support artifact 'org.jetbrains.kotlinx:kotlinx-coroutines-core' to your project ",
ex
)
else -> ex
}
}
actual fun <T : Any> copyFields(to: T, from: T) {
fun copy(to: Any, from: Any, cls: Class<*>) {
for (field in cls.declaredFields) {
if (Modifier.isStatic(field.modifiers)) {
continue
}
if (isRunningAndroidInstrumentationTest() && field.name.startsWith("shadow$")) {
continue
}
InternalPlatformDsl.makeAccessible(field)
val value = field.get(from)
field.set(to, value)
}
if (cls.superclass != null) {
copy(to, from, cls.superclass)
}
}
copy(to, from, from::class.java)
}
actual fun captureStackTrace(): () -> List<StackElement> {
val ex = Exception("Stack trace")
return {
val stack = ex.stackTrace ?: arrayOf<StackTraceElement>()
stack.map {
StackElement(
it.className ?: "-",
it.fileName ?: "-",
it.methodName ?: "-",
it.lineNumber,
it.isNativeMethod
)
}
}
}
actual fun weakRef(value: Any): WeakRef {
val weakRef = WeakReference<Any>(value)
return object : WeakRef {
override val value: Any?
get() = weakRef.get()
}
}
actual fun multiNotifier(): MultiNotifier = JvmMultiNotifier()
actual inline fun <T> synchronized(obj: Any, block: () -> T) = kotlin.synchronized(obj, block)
inline fun <reified T : Any> loadPlugin(className: String, msg: String = "") =
try {
T::class.cast(Class.forName(className).getDeclaredConstructor().newInstance())
} catch (ex: Exception) {
throw MockKException("Failed to load plugin. $className $msg", ex)
}
fun isRunningAndroidInstrumentationTest(): Boolean {
return System.getProperty("java.vendor", "")
.lowercase(Locale.US)
.contains("android")
}
}