Unverified Commit 97665bb0 authored by Oleksandr Karpovich's avatar Oleksandr Karpovich Committed by GitHub

Skiko interop scope tests (#222)

* add InteropScopeTests.kt (wip)

* add InteropScopeTests.kt (wip - 2)

* add InteropScope tests for `withResult`

* move TestHelpers to test sources + include them in not-release builds

* add interop tests for ShortArray, IntArray, DoubleArray

* update branch after rebase
Co-authored-by: 's avatarOleksandr Karpovich <oleksandr.karpovich@jetbrains.com>
parent f7fe8816
package org.jetbrains.skiko.sample.js
import org.jetbrains.skia.Color
import org.jetbrains.skia.FontMgr
import org.jetbrains.skia.Surface
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
import org.jetbrains.skia.paragraph.ParagraphStyle
import org.jetbrains.skia.paragraph.TextStyle
fun drawParagraphExample(surface: Surface) {
val fontCollection = FontCollection()
.setDefaultFontManager(FontMgr.default)
val p = ParagraphBuilder(ParagraphStyle(), fontCollection)
.pushStyle(
TextStyle().apply {
color = Color.makeRGB(1, 0, 0)
fontSize = 25f
}
)
.addText("Hello World!\nПривет Мир!")
.popStyle()
.build()
p.layout(Float.POSITIVE_INFINITY)
p.paint(surface.canvas, 10f, 10f)
surface.flushAndSubmit()
}
...@@ -105,6 +105,10 @@ val wasmCrossCompile = tasks.register<WasmCrossCompileTask>("wasmCrossCompile") ...@@ -105,6 +105,10 @@ val wasmCrossCompile = tasks.register<WasmCrossCompileTask>("wasmCrossCompile")
sourceFiles = sourceFiles =
project.fileTree("src/jsMain/cpp") { include("**/*.cc") } + project.fileTree("src/jsMain/cpp") { include("**/*.cc") } +
project.fileTree("src/commonMain/cpp") { include("**/*.cc") } project.fileTree("src/commonMain/cpp") { include("**/*.cc") }
if (skiko.includeTestHelpers) {
sourceFiles += project.fileTree("src/commonTest/cpp") { include("**/*.cc") }
}
val skiaAFilesDir = unpackedSkia.resolve("out/${buildType.id}-${osArch.first.id}-${osArch.second.id}") val skiaAFilesDir = unpackedSkia.resolve("out/${buildType.id}-${osArch.first.id}-${osArch.second.id}")
libFiles = project.fileTree(skiaAFilesDir) { include("**/*.a") } libFiles = project.fileTree(skiaAFilesDir) { include("**/*.a") }
...@@ -126,6 +130,17 @@ val wasmCrossCompile = tasks.register<WasmCrossCompileTask>("wasmCrossCompile") ...@@ -126,6 +130,17 @@ val wasmCrossCompile = tasks.register<WasmCrossCompileTask>("wasmCrossCompile")
"--extern-post-js", "--extern-post-js",
skikoJsPrefix.get().asFile.absolutePath, skikoJsPrefix.get().asFile.absolutePath,
)) ))
finalizedBy(replaceSymbolsInSkikoJsOutput)
}
val replaceSymbolsInSkikoJsOutput by project.tasks.registering {
doLast {
val wasmTask = project.tasks.getByName("wasmCrossCompile") as WasmCrossCompileTask
val skikoJsFile: File = wasmTask.outDir.asFile.get().resolve("skiko.js")
val replacedContent = skikoJsFile.readText().replace("_org_jetbrains", "org_jetbrains")
skikoJsFile.writeText(replacedContent)
}
} }
val skiaDir: Provider<File> = run { val skiaDir: Provider<File> = run {
...@@ -239,6 +254,9 @@ kotlin { ...@@ -239,6 +254,9 @@ kotlin {
} }
val macosX64Main by getting { val macosX64Main by getting {
dependsOn(macosMain) dependsOn(macosMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
}
} }
} }
} }
...@@ -418,10 +436,12 @@ val generateVersion = project.tasks.register("generateVersion") { ...@@ -418,10 +436,12 @@ val generateVersion = project.tasks.register("generateVersion") {
// resulting object files into the final native klib. // resulting object files into the final native klib.
project.tasks.register<Exec>("nativeBridgesCompile") { project.tasks.register<Exec>("nativeBridgesCompile") {
dependsOn(skiaDir) dependsOn(skiaDir)
val inputDirs = listOf( val inputDirs = mutableListOf(
"$projectDir/src/nativeMain/cpp/common", "$projectDir/src/nativeMain/cpp/common",
"$projectDir/src/commonMain/cpp" "$projectDir/src/commonMain/cpp"
) ).apply {
if (skiko.includeTestHelpers) add("$projectDir/src/commonTest/cpp/TestHelpers.cc")
}
val outDir = "$buildDir/nativeBridges/obj/$target" val outDir = "$buildDir/nativeBridges/obj/$target"
val srcs = inputDirs val srcs = inputDirs
.findAllFiles(".cc") .findAllFiles(".cc")
...@@ -600,10 +620,15 @@ tasks.withType(LinkSharedLibrary::class.java).configureEach { ...@@ -600,10 +620,15 @@ tasks.withType(LinkSharedLibrary::class.java).configureEach {
} }
extensions.configure<CppLibrary> { extensions.configure<CppLibrary> {
source.from( val paths = mutableListOf(
fileTree("$projectDir/src/jvmMain/cpp/common"), fileTree("$projectDir/src/jvmMain/cpp/common"),
fileTree("$projectDir/src/jvmMain/cpp/${targetOs.id}") fileTree("$projectDir/src/jvmMain/cpp/${targetOs.id}")
) ).apply {
if (skiko.includeTestHelpers) {
add(fileTree("$projectDir/src/jvmTest/cpp/TestHelpers.cc"))
}
}
source.setFrom(paths)
} }
library { library {
...@@ -878,13 +903,18 @@ publishing { ...@@ -878,13 +903,18 @@ publishing {
} }
afterEvaluate { afterEvaluate {
tasks.withType<KotlinCompile>().configureEach { tasks.withType<KotlinCompile>().configureEach { // this one is actually KotlinJvmCompile
dependsOn(generateVersion) dependsOn(generateVersion)
source(generatedKotlin) source(generatedKotlin)
if (name == "compileTestKotlinJvm") { if (name == "compileTestKotlinJvm") {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
} }
}
tasks.withType<KotlinNativeCompile>().configureEach {
dependsOn(generateVersion)
source(generatedKotlin)
if (supportNative) { if (supportNative) {
dependsOn(tasks.getByName("nativeBridgesLink")) dependsOn(tasks.getByName("nativeBridgesLink"))
} }
......
...@@ -96,6 +96,9 @@ class SkikoProperties(private val myProject: Project) { ...@@ -96,6 +96,9 @@ class SkikoProperties(private val myProject: Project) {
val buildType: SkiaBuildType val buildType: SkiaBuildType
get() = if (myProject.findProperty("skiko.debug") == "true") SkiaBuildType.DEBUG else SkiaBuildType.RELEASE get() = if (myProject.findProperty("skiko.debug") == "true") SkiaBuildType.DEBUG else SkiaBuildType.RELEASE
val includeTestHelpers: Boolean
get() = !isRelease
fun skiaReleaseFor(os: OS, arch: Arch, buildType: SkiaBuildType): String { fun skiaReleaseFor(os: OS, arch: Arch, buildType: SkiaBuildType): String {
val target = "${os.id}-${arch.id}" val target = "${os.id}-${arch.id}"
val tag = myProject.property("dependencies.skia.$target") as String val tag = myProject.property("dependencies.skia.$target") as String
......
...@@ -6,7 +6,7 @@ config.browserConsoleLogOptions.level = "debug"; ...@@ -6,7 +6,7 @@ config.browserConsoleLogOptions.level = "debug";
const basePath = config.basePath; const basePath = config.basePath;
const projectPath = path.resolve(basePath, "..", "..", "..", "..", ".."); const projectPath = path.resolve(basePath, "..", "..", "..", "..", "..");
const wasmPath = path.resolve(projectPath, "build", "wasm") const wasmPath = path.resolve(projectPath, "build", "out", "Release-wasm-wasm")
const debug = message => console.log(`[karma-config] ${message}`); const debug = message => console.log(`[karma-config] ${message}`);
......
...@@ -58,6 +58,27 @@ inline fun withResult(result: FloatArray, block: (InteropPointer) -> Unit): Floa ...@@ -58,6 +58,27 @@ inline fun withResult(result: FloatArray, block: (InteropPointer) -> Unit): Floa
result result
} }
inline fun withResult(result: IntArray, block: (InteropPointer) -> Unit): IntArray = interopScope {
val handle = toInterop(result)
block(handle)
handle.fromInterop(result)
result
}
inline fun withResult(result: ShortArray, block: (InteropPointer) -> Unit): ShortArray = interopScope {
val handle = toInterop(result)
block(handle)
handle.fromInterop(result)
result
}
inline fun withResult(result: DoubleArray, block: (InteropPointer) -> Unit): DoubleArray = interopScope {
val handle = toInterop(result)
block(handle)
handle.fromInterop(result)
result
}
inline fun withResult(result: NativePointerArray, block: (InteropPointer) -> Unit): NativePointerArray = interopScope { inline fun withResult(result: NativePointerArray, block: (InteropPointer) -> Unit): NativePointerArray = interopScope {
val handle = toInterop(result) val handle = toInterop(result)
block(handle) block(handle)
......
#include "common.h"
#include <stdint.h>
SKIKO_EXPORT void org_jetbrains_skiko_tests_TestHelpers__1nFillByteArrayOf5(KNativePointer byteArray) {
uint8_t *bytes = reinterpret_cast<uint8_t*>(byteArray);
bytes[0] = 1;
bytes[1] = 2;
bytes[2] = 3;
bytes[3] = 4;
bytes[4] = 5;
}
SKIKO_EXPORT void org_jetbrains_skiko_tests_TestHelpers__1nFillFloatArrayOf5(KNativePointer floatArray) {
float *floats = reinterpret_cast<float*>(floatArray);
floats[0] = 0.0;
floats[1] = 1.1;
floats[2] = 2.2;
floats[3] = 3.3;
floats[4] = -4.4;
}
SKIKO_EXPORT void org_jetbrains_skiko_tests_TestHelpers__1nFillShortArrayOf5(KNativePointer shortArray) {
short *shorts = reinterpret_cast<short*>(shortArray);
shorts[0] = 0;
shorts[1] = 1;
shorts[2] = 2;
shorts[3] = -3;
shorts[4] = 4;
}
SKIKO_EXPORT void org_jetbrains_skiko_tests_TestHelpers__1nFillIntArrayOf5(KNativePointer intArray) {
int *ints = reinterpret_cast<int*>(intArray);
ints[0] = 0;
ints[1] = 1;
ints[2] = -22;
ints[3] = 3;
ints[4] = 4;
}
SKIKO_EXPORT void org_jetbrains_skiko_tests_TestHelpers__1nFillDoubleArrayOf5(KNativePointer doubleArray) {
double *doubles = reinterpret_cast<double*>(doubleArray);
doubles[0] = -0.001;
doubles[1] = 0.00222;
doubles[2] = 2.71828;
doubles[3] = 3.1415;
doubles[4] = 10000000.9991;
}
package org.jetbrains.skia.impl
import org.jetbrains.skiko.tests.TestHelpers
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test
import kotlin.test.assertContentEquals
class InteropScopeCommonTests {
@Test
fun withResultByteArray() = runTest {
val byteArray = ByteArray(5)
TestHelpers()._nFillByteArrayOf5(byteArray)
assertContentEquals(byteArrayOf(1, 2, 3, 4, 5), byteArray)
}
@Test
fun withResultFloatArray() = runTest {
val floatArray = FloatArray(5)
TestHelpers()._nFillFloatArrayOf5(floatArray)
assertContentEquals(floatArrayOf(0.0f, 1.1f, 2.2f, 3.3f, -4.4f), floatArray)
}
@Test
fun withResultShortArray() = runTest {
val shortArray = ShortArray(5)
TestHelpers()._nFillShortArrayOf5(shortArray)
assertContentEquals(shortArrayOf(0, 1, 2, -3, 4), shortArray)
}
@Test
fun withResultIntArray() = runTest {
val intArray = IntArray(5)
TestHelpers()._nFillIntArrayOf5(intArray)
assertContentEquals(intArrayOf(0, 1, -22, 3, 4), intArray)
}
@Test
fun withResultDoubleArray() = runTest {
val doubleArray = DoubleArray(5)
TestHelpers()._nFillDoubleArrayOf5(doubleArray)
assertContentEquals(doubleArrayOf(-0.001, 0.00222, 2.71828, 3.1415, 10000000.9991), doubleArray)
}
}
package org.jetbrains.skiko.tests
import org.jetbrains.skia.ExternalSymbolName
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.Library
import org.jetbrains.skia.impl.withResult
class TestHelpers {
fun _nFillByteArrayOf5(array: ByteArray) {
withResult(array) {
_nFillByteArrayOf5(it)
}
}
fun _nFillFloatArrayOf5(array: FloatArray) {
withResult(array) {
_nFillFloatArrayOf5(it)
}
}
fun _nFillShortArrayOf5(array: ShortArray) {
withResult(array) {
_nFillShortArrayOf5(it)
}
}
fun _nFillIntArrayOf5(array: IntArray) {
withResult(array) {
_nFillIntArrayOf5(it)
}
}
fun _nFillDoubleArrayOf5(array: DoubleArray) {
withResult(array) {
_nFillDoubleArrayOf5(it)
}
}
init {
Library.staticLoad()
}
}
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillByteArrayOf5")
private external fun _nFillByteArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillFloatArrayOf5")
private external fun _nFillFloatArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillShortArrayOf5")
private external fun _nFillShortArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillIntArrayOf5")
private external fun _nFillIntArrayOf5(interopPointer: InteropPointer)
@ExternalSymbolName("org_jetbrains_skiko_tests_TestHelpers__1nFillDoubleArrayOf5")
private external fun _nFillDoubleArrayOf5(interopPointer: InteropPointer)
package org.jetbrains.skiko.tests
expect annotation class IgnoreTestOnJvm()
expect fun runTest(block: suspend () -> Unit)
...@@ -51,7 +51,8 @@ actual class InteropScope actual constructor() { ...@@ -51,7 +51,8 @@ actual class InteropScope actual constructor() {
} }
actual fun InteropPointer.fromInterop(result: CharArray) { actual fun InteropPointer.fromInterop(result: CharArray) {
fromWasm(this@fromInterop, result) val tmp = UTF8ToString(this@fromInterop)
tmp.toCharArray().copyInto(result)
} }
actual fun toInterop(array: ByteArray?): InteropPointer { actual fun toInterop(array: ByteArray?): InteropPointer {
...@@ -118,11 +119,18 @@ actual class InteropScope actual constructor() { ...@@ -118,11 +119,18 @@ actual class InteropScope actual constructor() {
} }
actual fun InteropPointer.fromInterop(result: DoubleArray) { actual fun InteropPointer.fromInterop(result: DoubleArray) {
TODO("implement wasm fromInterop(DoubleArray)") fromWasm(this@fromInterop, result)
} }
actual fun toInterop(array: DoubleArray?): InteropPointer { actual fun toInterop(array: DoubleArray?): InteropPointer {
TODO("implement wasm toInterop(DoubleArray)") return if (array != null) {
val data = _malloc(array.size * 8)
elements.add(data)
toWasm(data, array)
data
} else {
0
}
} }
actual fun InteropPointer.fromInterop(result: ByteArray) { actual fun InteropPointer.fromInterop(result: ByteArray) {
...@@ -141,18 +149,33 @@ actual class InteropScope actual constructor() { ...@@ -141,18 +149,33 @@ actual class InteropScope actual constructor() {
} }
actual fun InteropPointer.fromInterop(result: NativePointerArray) { actual fun InteropPointer.fromInterop(result: NativePointerArray) {
TODO("implement wasm fromInterop(NativePointerArray)") return fromWasm(this@fromInterop, result.backing)
} }
actual fun toInterop(stringArray: Array<String>?): InteropPointer = actual fun toInterop(stringArray: Array<String>?): InteropPointer {
TODO("implement wasm toInterop(Array<String>)") return if (stringArray != null) {
val ptrs = stringArray.map {
toInterop(it)
}.toIntArray()
toInterop(ptrs)
} else {
0
}
}
actual fun InteropPointer.fromInteropNativePointerArray(): NativePointerArray { actual fun InteropPointer.fromInteropNativePointerArray(): NativePointerArray {
TODO("implement wasm fromInteropNativePointerArray") TODO("implement wasm fromInteropNativePointerArray")
} }
actual inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T> = actual inline fun <reified T> InteropPointer.fromInterop(decoder: ArrayInteropDecoder<T>): Array<T> {
TODO("implement wasm fromInteropArray()") val size = decoder.getArraySize(this)
val result = Array<T>(size) {
decoder.getArrayElement(this, it)
}
decoder.disposeArray(this)
return result
}
actual fun release() { actual fun release() {
elements.forEach { elements.forEach {
...@@ -168,48 +191,70 @@ private external fun _free(ptr: NativePointer) ...@@ -168,48 +191,70 @@ private external fun _free(ptr: NativePointer)
private external fun stringToUTF8(str: String, outPtr: NativePointer, maxBytesToWrite: Int) private external fun stringToUTF8(str: String, outPtr: NativePointer, maxBytesToWrite: Int)
private external fun UTF8ToString(ptr: NativePointer): String
private external val HEAPU8: ByteArray private external val HEAPU8: ByteArray
// Data copying routines. // Data copying routines.
private fun toWasm(dest: NativePointer, src: ByteArray) { private fun toWasm(dest: NativePointer, src: ByteArray) {
js("HEAPU8.set(src, dest)") val index = dest
js("HEAPU8.set(src, index)")
} }
private fun toWasm(dest: NativePointer, src: CharArray) { private fun toWasm(dest: NativePointer, src: CharArray) {
js("HEAPU16.set(src, dest)") val index = dest / 2
js("HEAPU16.set(src, index)")
} }
private fun toWasm(dest: NativePointer, src: ShortArray) { private fun toWasm(dest: NativePointer, src: ShortArray) {
js("HEAPU16.set(src, dest)") val index = dest / 2
js("HEAPU16.set(src, index)")
} }
private fun toWasm(dest: NativePointer, src: FloatArray) { private fun toWasm(dest: NativePointer, src: FloatArray) {
js("HEAPU32.set(src, dest)") val index = dest / 4
js("HEAPF32.set(src, index)")
} }
private fun toWasm(dest: NativePointer, src: IntArray) { private fun toWasm(dest: NativePointer, src: DoubleArray) {
js("HEAPU32.set(src, dest)") val index = dest / 8
js("HEAPF64.set(src, index)")
} }
private fun fromWasm(src: NativePointer, result: ByteArray) { private fun toWasm(dest: NativePointer, src: IntArray) {
js("result.set(HEAPU8.subarray(src, result.size))") val index = dest / 4
js("HEAPU32.set(src, index)")
} }
private fun fromWasm(src: NativePointer, result: CharArray) { private fun fromWasm(src: NativePointer, result: ByteArray) {
js("result.set(HEAPU16.subarray(src, result.size))") val startIndex = src
val endIndex = startIndex + result.size
js("result.set(HEAPU8.subarray(startIndex, endIndex))")
} }
private fun fromWasm(src: NativePointer, result: ShortArray) { private fun fromWasm(src: NativePointer, result: ShortArray) {
js("result.set(HEAPU16.subarray(src, result.size))") val startIndex = src / 2
val endIndex = startIndex + result.size
js("result.set(HEAPU16.subarray(startIndex, endIndex))")
} }
private fun fromWasm(src: NativePointer, result: IntArray) { private fun fromWasm(src: NativePointer, result: IntArray) {
js("result.set(HEAPU32.subarray(src, result.size))") val startIndex = src / 4
val endIndex = startIndex + result.size
js("result.set(HEAPU32.subarray(startIndex, endIndex))")
} }
private fun fromWasm(src: NativePointer, result: FloatArray) { private fun fromWasm(src: NativePointer, result: FloatArray) {
js("result.set(HEAPU32.subarray(src, result.size))") val startIndex = src / 4
val endIndex = startIndex + result.size
js("result.set(HEAPF32.subarray(startIndex, endIndex))")
}
private fun fromWasm(src: NativePointer, result: DoubleArray) {
val startIndex = src / 8
val endIndex = startIndex + result.size
js("result.set(HEAPF64.subarray(startIndex, endIndex))")
} }
actual class NativePointerArray actual constructor(size: Int) { actual class NativePointerArray actual constructor(size: Int) {
...@@ -224,4 +269,12 @@ actual class NativePointerArray actual constructor(size: Int) { ...@@ -224,4 +269,12 @@ actual class NativePointerArray actual constructor(size: Int) {
actual val size: Int actual val size: Int
get() = backing.size get() = backing.size
companion object {
internal fun fromIntArray(intArray: IntArray): NativePointerArray {
return NativePointerArray(intArray.size).apply {
intArray.copyInto(backing)
}
}
}
} }
package org.jetbrains.skiko.tests
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
import org.jetbrains.skiko.wasm.await
import org.jetbrains.skiko.wasm.wasmSetup
annotation class DoNothing
actual typealias IgnoreTestOnJvm = DoNothing
actual fun runTest(block: suspend () -> Unit): dynamic = GlobalScope.promise {
wasmSetup.await()
block()
}
...@@ -4,9 +4,6 @@ import kotlinx.coroutines.GlobalScope ...@@ -4,9 +4,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise import kotlinx.coroutines.promise
import kotlin.coroutines.* import kotlin.coroutines.*
import kotlin.js.Promise import kotlin.js.Promise
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
external interface ModuleInterface external interface ModuleInterface
external val Module: ModuleInterface external val Module: ModuleInterface
...@@ -15,7 +12,7 @@ suspend fun <T> Promise<T>.await(): T = suspendCoroutine { cont -> ...@@ -15,7 +12,7 @@ suspend fun <T> Promise<T>.await(): T = suspendCoroutine { cont ->
then({ cont.resume(it) }, { cont.resumeWithException(it) }) then({ cont.resume(it) }, { cont.resumeWithException(it) })
} }
private fun wasmTest(block: () -> Unit) = GlobalScope.promise { internal fun wasmTest(block: () -> Unit) = GlobalScope.promise {
wasmSetup.await() wasmSetup.await()
block.invoke() block.invoke()
} }
......
package org.jetbrains.skia.impl
import org.jetbrains.skiko.tests.runTest
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertContentEquals
class InteropScopeTests {
@Test
fun canCreateInteropScope() {
interopScope { }
}
@Test
fun toInteropString() = runTest {
interopScope {
val s = "HelloWorld!ПриветМир!"
val interopPointer = toInterop(s)
val readArray = CharArray(s.length)
interopPointer.fromInterop(readArray)
assertContentEquals(s.toCharArray(), readArray)
}
}
@Test
fun toInteropFloatArray() = runTest {
interopScope {
val array = floatArrayOf(Float.MIN_VALUE, 2f, -1f, 0f, 1f, Float.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = FloatArray(6)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
fun toInteropByteArray() = runTest {
interopScope {
val array = byteArrayOf(Byte.MIN_VALUE, -2, 3, 0, Byte.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = ByteArray(5)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
fun toInteropShortArray() = runTest {
interopScope {
val array = shortArrayOf(Short.MIN_VALUE, 2, -3, 0, Short.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = ShortArray(5)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
fun toInteropIntArray() = runTest {
interopScope {
val array = intArrayOf(Int.MIN_VALUE, 2, -3, 0, Int.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = IntArray(5)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
@Ignore
fun toInteropLongArray() = runTest {
interopScope {
val array = longArrayOf(Long.MIN_VALUE, -2, 3, 0, Long.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = LongArray(5)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
fun toInteropDoubleArray() = runTest {
interopScope {
val array = doubleArrayOf(Double.MIN_VALUE, 2.0, -3.0, 0.0, Double.MAX_VALUE)
val interopPointer = toInterop(array)
val readArray = DoubleArray(5)
interopPointer.fromInterop(readArray)
assertContentEquals(array, readArray)
}
}
@Test
fun toInteropStringArray() = runTest {
interopScope {
val array = arrayOf("s1", "s2", "s3")
val interopPointer = toInterop(array)
val npa = NativePointerArray(3)
interopPointer.fromInterop(npa)
val res = generateSequence(0) {
it + 1
}.map {
val charArray = CharArray(2)
(npa[it] as InteropPointer).fromInterop(charArray)
charArray.concatToString()
}.take(3).toList().toTypedArray()
assertContentEquals(array, res)
}
}
}
#include <jni.h>
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nFillByteArrayOf5
(JNIEnv* env, jclass jclass, jbyteArray jbarray) {
jbyte *result_bytes = env->GetByteArrayElements(jbarray, NULL);
result_bytes[0] = 1;
result_bytes[1] = 2;
result_bytes[2] = 3;
result_bytes[3] = 4;
result_bytes[4] = 5;
env->ReleaseByteArrayElements(jbarray, result_bytes, 0);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nFillFloatArrayOf5
(JNIEnv* env, jclass jclass, jfloatArray jfarray) {
jfloat *result_float = env->GetFloatArrayElements(jfarray, NULL);
result_float[0] = 0.0;
result_float[1] = 1.1;
result_float[2] = 2.2;
result_float[3] = 3.3;
result_float[4] = -4.4;
env->ReleaseFloatArrayElements(jfarray, result_float, 0);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nFillShortArrayOf5
(JNIEnv* env, jclass jclass, jshortArray jsarray) {
jshort *result_short = env->GetShortArrayElements(jsarray, NULL);
result_short[0] = 0;
result_short[1] = 1;
result_short[2] = 2;
result_short[3] = -3;
result_short[4] = 4;
env->ReleaseShortArrayElements(jsarray, result_short, 0);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nFillIntArrayOf5
(JNIEnv* env, jclass jclass, jintArray jiarray) {
jint *result_int = env->GetIntArrayElements(jiarray, NULL);
result_int[0] = 0;
result_int[1] = 1;
result_int[2] = -22;
result_int[3] = 3;
result_int[4] = 4;
env->ReleaseIntArrayElements(jiarray, result_int, 0);
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skiko_tests_TestHelpersKt__1nFillDoubleArrayOf5
(JNIEnv* env, jclass jclass, jdoubleArray jdarray) {
jdouble *result_double = env->GetDoubleArrayElements(jdarray, NULL);
result_double[0] = -0.001;
result_double[1] = 0.00222;
result_double[2] = 2.71828;
result_double[3] = 3.1415;
result_double[4] = 10000000.9991;
env->ReleaseDoubleArrayElements(jdarray, result_double, 0);
}
package org.jetbrains.skiko.tests
import kotlinx.coroutines.runBlocking
actual typealias IgnoreTestOnJvm = org.junit.Ignore
actual fun runTest(block: suspend () -> Unit) {
runBlocking { block() }
}
package org.jetbrains.skiko.tests
import kotlinx.coroutines.runBlocking
annotation class DoNothing
actual typealias IgnoreTestOnJvm = DoNothing
actual fun runTest(block: suspend () -> Unit) {
runBlocking { block() }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment