blob: e0e67c6edcb44c62252d843eab67eaa8d54828e2 [file]
// TARGET_BACKEND: WASM
// WITH_STDLIB
// FILE: test.kt
@JsExport
fun concatAndSlice(prefix: String, value: String, suffix: String): String =
(prefix + value + suffix).substring(prefix.length, prefix.length + value.length)
@JsExport
fun codeUnitAt(value: String, index: Int): Int =
value[index].code
@JsExport
fun makeFromChars(): String =
charArrayOf('A', '\u0000', '\uD83D', '\uDE80', 'Z').concatToString()
@JsExport
fun compareAndCopyThroughChars(lhs: String, rhs: String): String {
if (lhs != rhs) return "not equal"
if (lhs.compareTo(rhs) != 0) return "not zero"
val chars = CharArray(lhs.length)
lhs.toCharArray(chars, 0, 0, lhs.length)
return chars.concatToString()
}
private fun jsCodeStringRoundTrip(value: String): String =
js("value")
@JsExport
fun roundTripThroughJsCode(value: String): String =
jsCodeStringRoundTrip(value)
fun box(): String = "OK"
// FILE: entry.mjs
import { importObject } from "./index.import-object.mjs";
import { box, codeUnitAt, compareAndCopyThroughChars, concatAndSlice, makeFromChars, roundTripThroughJsCode } from "./index.mjs";
function artifactUrl(name) {
return import.meta.url.substring(0, import.meta.url.lastIndexOf("/") + 1) + name;
}
// js-string builtins are existing in single-module/multi-module mode in stdlib module
// ownerBase should resolve to either test directory (whole-program mode),
// or to stdlib directory (single-module/multi-module)
const indexImportObjectSource = read(artifactUrl("index.import-object.mjs"));
let ownerBase = "./index";
const stdlibImport = indexImportObjectSource.match(/from\s*['"]([^'"]*kotlin-kotlin-stdlib)\.mjs['"]/);
if (stdlibImport != null) {
ownerBase = stdlibImport[1];
}
const wrapperSource = read(artifactUrl("index.mjs"));
const ownerSource = read(artifactUrl(ownerBase + ".mjs"));
const ownerImportObjectSource = read(artifactUrl(ownerBase + ".import-object.mjs"));
if (!ownerSource.includes("builtins: ['js-string']")) {
throw "owner index.mjs does not request js-string builtins";
}
if (!wrapperSource.includes("importedStringConstants: \"'\"")) {
throw "index.mjs does not request imported string constants";
}
if (!ownerImportObjectSource.includes("StringConstantsProxy")) {
throw "owner import-object does not define StringConstantsProxy";
}
if (!ownerImportObjectSource.includes("'wasm:js-string'")) {
throw "owner import-object does not import wasm:js-string";
}
const jsStringBuiltins = await import(artifactUrl(ownerBase + ".js-builtins.mjs"));
const ownerImportObject = (await import(artifactUrl(ownerBase + ".import-object.mjs"))).importObject;
const requiredBuiltins = [
"length",
"concat",
"charCodeAt",
"substring",
"compare",
"equals",
"fromCharCodeArray",
"intoCharCodeArray",
];
for (const name of requiredBuiltins) {
if (typeof jsStringBuiltins[name] !== "function") {
throw `Missing js-string builtin export: ${name}`;
}
}
if (ownerImportObject["wasm:js-string"] !== jsStringBuiltins) {
throw "importObject does not wire wasm:js-string to the js-builtins module";
}
const stringConstants = importObject["'"];
if (stringConstants == null) {
throw "Missing imported string constants proxy";
}
const importedConstant = "A'\u0000B🚀";
if (stringConstants[importedConstant] !== importedConstant) {
throw "StringConstantsProxy does not return imported string constants";
}
if (box() !== "OK") {
throw "Kotlin box failed";
}
const edge = "A\u0000🚀e\u0301Z";
if (concatAndSlice("<<", edge, ">>") !== edge) {
throw "concat/substring builtins path failed";
}
if (codeUnitAt(edge, 2) !== edge.charCodeAt(2)) {
throw "charCodeAt builtin path failed";
}
if (makeFromChars() !== "A\u0000🚀Z") {
throw "fromCharCodeArray builtin path failed";
}
if (compareAndCopyThroughChars(edge, edge) !== edge) {
throw "equals/compare/intoCharCodeArray builtin path failed";
}
if (roundTripThroughJsCode(edge) !== edge) {
throw "js_code string roundtrip failed";
}