-
-
Save dellisd/a1df42787d42b41cd3ce16f573984674 to your computer and use it in GitHub Desktop.
// Part of a multi-module project, hence the rootProject everywhere | |
task copyTestResourcesForJs(type: Copy) { | |
from "$projectDir/src/commonTest/resources" | |
into "${rootProject.buildDir}/js/packages/${rootProject.name}-${project.name}-test/src/commonTest/resources" | |
} | |
jsNodeTest.dependsOn copyTestResourcesForJs |
// Common | |
const val RESOURCE_PATH = "./src/commonTest/resources" | |
expect class Resource(name: String) { | |
val name: String | |
fun exists(): Boolean | |
fun readText(): String | |
} | |
// JVM | |
import java.io.File | |
actual class Resource actual constructor(actual val name: String) { | |
private val file = File("$RESOURCE_PATH/$name") | |
actual fun exists(): Boolean = file.exists() | |
actual fun readText(): String = file.readText() | |
} | |
// Native | |
import kotlinx.cinterop.* | |
import platform.posix.* | |
actual class Resource actual constructor(actual val name: String) { | |
private val file: CPointer<FILE>? = fopen("$RESOURCE_PATH/$name", "r") | |
actual fun exists(): Boolean = file != null | |
actual fun readText(): String { | |
fseek(file, 0, SEEK_END) | |
val size = ftell(file) | |
rewind(file) | |
return memScoped { | |
val tmp = allocArray<ByteVar>(size) | |
fread(tmp, sizeOf<ByteVar>().convert(), size.convert(), file) | |
tmp.toKString() | |
} | |
} | |
} | |
// JS (Node) | |
private external fun require(module: String): dynamic | |
private val fs = require("fs") | |
actual class Resource actual constructor(actual val name: String) { | |
private val path = "$RESOURCE_PATH/$name" | |
actual fun exists(): Boolean = fs.existsSync(path) as Boolean | |
actual fun readText(): String = fs.readFileSync(path, "utf8") as String | |
} |
@Test | |
fun testLength2() { | |
// Located at /src/commonTest/resources/test.json | |
val resource = Resource("test.json") | |
val geometry = resource.readText().toGeometry<LineString>() | |
assertEquals(42.560767589197006, length(geometry, Units.Kilometers)) | |
} |
I haven't had a need to stream the input yet so I haven't really thought much about it, but you could probably use something like Okio and return an implementation of a Source
(or whatever implementation of an InputStream you want to use). You'd just have to adjust the fread
call to read the number of bytes that are requested.
Yesterday I played with this script a bit and it didn't really work for iosX64 target. I guess it's more complicated than that, after all it's not run inside an ios filesystem (although on an m1 mac there should be a way).
That's true. This was built for use in JVM, Native (non-iOS/watchOS/tvOS), and Node environments.
Android Instrumentation tests, those other Apple environments, and Browser environments would require some more work, but I suspect they're not impossible.
It didn't work for me while trying to run tests on iOS. This modification did the job:
// Native
import kotlinx.cinterop.*
import platform.posix.*
actual class Resource actual constructor(actual val name: String) {
private val path = NSBundle.mainBundle.pathForResource("resources/FILE_NAME", "FILE_EXTENSION") ?: ""
private val file: CPointer<FILE>? = fopen(path, "r")
Then, in the build.gradle.kts file:
tasks.register<Copy>("copyiOSTestResources") {
from("src/commonTest/resources")
into("build/bin/iosX64/debugTest/resources")
}
tasks.findByName("iosX64Test")!!.dependsOn("copyiOSTestResources")
This article helped me out a lot: https://developer.squareup.com/blog/kotlin-multiplatform-shared-test-resources/
Cannot you simply specify
private val path = "kotlin/$name"
in the JS implementation of the Resource
class's constructor (i.e. without the need for the copyTestResourcesForJs
Gradle task)?
You helped me a lot with this script, thanks!
Do you maybe know how to read an InputStream (NSInputStream for ios) instead of string directly? Byte operations in Kotlin Native are a great mystery for me ;)