[K/JS] test: add @file:JsExport tests for each @JsExport test + auto-generate TypeScript export tests.

This commit is contained in:
Artem Kobzar
2022-08-26 09:51:59 +00:00
committed by Space
parent d65775ca1a
commit dbda8dcad1
139 changed files with 4242 additions and 31 deletions
@@ -0,0 +1,28 @@
// TARGET_BACKEND: JS_IR
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: bridge_saving_after_export
// FILE: lib.kt
@file:JsExport
open class A<T> {
open fun foo(value: T): T = value
}
class B: A<String>() {
override fun foo(value: String): String = value
}
// FILE: test.js
function box() {
var a = new this["bridge_saving_after_export"].A()
var aFoo = a.foo("ok")
if (aFoo != "ok") return "fail 1"
var b = new this["bridge_saving_after_export"].B()
var bFoo = b.foo("ok")
if (bFoo != "ok") return "fail 2"
return "OK"
}
@@ -0,0 +1,20 @@
// IGNORE_FIR
// KT-49225
// RUN_PLAIN_BOX_FUNCTION
// IGNORE_BACKEND: JS
// SPLIT_PER_MODULE
// MODULE: lib
// FILE: koo.kt
value class Koo(val koo: String = "OK")
// FILE: bar.kt
@file:JsExport
class Bar(val koo: Koo = Koo())
// MODULE: main(lib)
// FILE: main.js
function box() {
return new kotlin_lib.Bar().koo;
}
@@ -0,0 +1,32 @@
// FILE: lib.kt
@file:JsExport
class Foo(internal val constructorParameter: String) {
internal val nonDefaultAccessor: String
get() = "hello"
internal val defaultAccessor: String = constructorParameter + "!"
}
enum class Bar(internal val constructorParameter: String) {
A("a");
internal val nonDefaultAccessor: String
get() = "hello"
internal val defaultAccessor: String = constructorParameter + "!"
}
// FILE: main.kt
fun box(): String {
val foo = Foo("foo")
if (foo.constructorParameter != "foo") return "fail1"
if (foo.nonDefaultAccessor != "hello") return "fail2"
if (foo.defaultAccessor != "foo!") return "fail3"
if (Bar.A.constructorParameter != "a") return "fail4"
if (Bar.A.nonDefaultAccessor != "hello") return "fail5"
if (Bar.A.defaultAccessor != "a!") return "fail6"
return "OK"
}
@@ -0,0 +1,98 @@
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: export_enum_class
// FILE: lib.kt
@file:JsExport
enum class Foo(val constructorParameter: String) {
A("aConstructorParameter"),
B("bConstructorParameter");
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
companion object {
val baz = "baz"
}
}
enum class Bar {
A,
B {
var d = "d"
init {
d = "d2"
}
fun huh() = "huh"
};
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
}
class OuterClass {
enum class NestedEnum {
A,
B;
}
}
// FILE: test.js
function box() {
if (this["export_enum_class"].Foo.A !== this["export_enum_class"].Foo.A) return "fail1"
if (this["export_enum_class"].Foo.B !== this["export_enum_class"].Foo.B) return "fail2"
if (this["export_enum_class"].Foo.Companion.baz !== "baz") return "fail3"
if (this["export_enum_class"].Foo.A.foo !== 0) return "fail4"
if (this["export_enum_class"].Foo.B.foo !== 1) return "fail5"
if (this["export_enum_class"].Foo.A.bar("A") !== "A") return "fail6"
if (this["export_enum_class"].Foo.B.bar("B") !== "B") return "fail7"
if (this["export_enum_class"].Foo.A.bay() !== "A") return "fail8"
if (this["export_enum_class"].Foo.B.bay() !== "B") return "fail9"
if (this["export_enum_class"].Foo.A.constructorParameter !== "aConstructorParameter") return "fail10"
if (this["export_enum_class"].Foo.B.constructorParameter !== "bConstructorParameter") return "fail11"
if (this["export_enum_class"].Bar.A.foo !== 0) return "fail12"
if (this["export_enum_class"].Bar.B.foo !== 1) return "fail13"
if (this["export_enum_class"].Bar.A.bar("A") !== "A") return "fail14"
if (this["export_enum_class"].Bar.B.bar("B") !== "B") return "fail15"
if (this["export_enum_class"].Bar.A.bay() !== "A") return "fail15"
if (this["export_enum_class"].Bar.B.bay() !== "B") return "fail16"
if (this["export_enum_class"].Bar.B.constructor.prototype.hasOwnProperty('d')) return "fail17"
if (this["export_enum_class"].Bar.B.constructor.prototype.hasOwnProperty('huh')) return "fail18"
if (this["export_enum_class"].Foo.valueOf("A") !== this["export_enum_class"].Foo.A) return "fail19"
if (this["export_enum_class"].Foo.valueOf("B") !== this["export_enum_class"].Foo.B) return "fail20"
if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.A) === -1) return "fail21"
if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.B) === -1) return "fail22"
if (this["export_enum_class"].Foo.A.name !== "A") return "fail23"
if (this["export_enum_class"].Foo.B.name !== "B") return "fail24"
if (this["export_enum_class"].Foo.A.ordinal !== 0) return "fail25"
if (this["export_enum_class"].Foo.B.ordinal !== 1) return "fail26"
if (this["export_enum_class"].OuterClass.NestedEnum.A.name !== "A") return "fail27"
if (this["export_enum_class"].OuterClass.NestedEnum.B.name !== "B") return "fail28"
if (this["export_enum_class"].OuterClass.NestedEnum.A.ordinal !== 0) return "fail29"
if (this["export_enum_class"].OuterClass.NestedEnum.B.ordinal !== 1) return "fail30"
return "OK"
}
@@ -0,0 +1,96 @@
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: export_interface
// FILE: not_exported.kt
interface ParentI {
val str: String
}
interface ExtendedI: I {
fun bar(): Int
}
open class NotExportedClass(override var value: Int) : ExtendedI {
override var variable: Int = value
override open fun foo(): String = "Not Exported"
override val str: String = "test 1"
override open fun bar(): Int = 42
}
// FILE: exportes.kt
@file:JsExport
interface I : ParentI {
val value: Int
var variable: Int
fun foo(): String
}
class ExportedClass(override val value: Int) : ExtendedI {
override var variable: Int = value
override fun foo(): String = "Exported"
override val str: String = "test 2"
override open fun bar(): Int = 43
}
class AnotherOne : NotExportedClass(42) {
override fun foo(): String = "Another One Exported"
}
fun generateNotExported(value: Int): NotExportedClass {
return NotExportedClass(value)
}
fun consume(i: I): String {
return "Value is ${i.value}, variable is ${i.variable} and result is '${i.foo()}'"
}
// FILE: test.js
function box() {
const { I, ExportedClass, AnotherOne, generateNotExported, consume } = this["export_interface"]
if (I !== undefined) return "Fail: module should not export interface in runtime"
const exported = new ExportedClass(1)
const another = new AnotherOne()
const notExported = generateNotExported (3)
if (exported.foo() !== "Exported") return "Fail: foo function was not generated for ExportedClass"
if (another.foo() !== "Another One Exported") return "Fail: foo function was not generated for AnotherOne"
if (notExported.foo() !== "Not Exported") return "Fail: foo function was not generated for NotExportedClass"
if (exported.value !== 1) return "Fail: value getter was not generated for ExportedClass"
if (another.value !== 42) return "Fail: value getter was not generated for AnotherOne"
if (notExported.value !== 3) return "Fail: value getter was not generated for NotExportedClass"
if (exported.variable !== 1) return "Fail: variable getter was not generated for ExportedClass"
if (another.variable !== 42) return "Fail: variable getter was not generated for AnotherOne"
if (notExported.variable !== 3) return "Fail: variable getter was not generated for NotExportedClass"
exported.variable = 101
another.variable = 102
notExported.variable = 103
if (exported.variable !== 101) return "Fail: variable setter was not generated for ExportedClass"
if (another.variable !== 102) return "Fail: variable setter was not generated for AnotherOne"
if (notExported.variable !== 103) return "Fail: variable setter was not generated for NotExportedClass"
notExported.value = 42
if (notExported.value !== 3) return "Fail: value setter was generated for NotExportedClass, but it shouldn't"
if (consume(exported) !== "Value is 1, variable is 101 and result is 'Exported'") return "Fail: methods or fields of ExportedClass was mangled"
if (consume(another) !== "Value is 42, variable is 102 and result is 'Another One Exported'") return "Fail: methods or fields of AnotherOne was mangled"
if (consume(notExported) !== "Value is 3, variable is 103 and result is 'Not Exported'") return "Fail: methods or fields of NotExported was mangled"
if (notExported.str !== undefined) return "Fail: str should not exist inside NotExportedClass"
if (exported.str !== undefined) return "Fail: str should not exist inside ExportedClass"
if (notExported.bar !== undefined) return "Fail: bar should not exist inside NotExportedClass"
if (exported.bar !== undefined) return "Fail: bar should not exist inside ExportedClass"
return "OK"
}
@@ -0,0 +1,47 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// SKIP_DCE_DRIVEN
// MODULE: export_nested_class
// FILE: lib.kt
@file:JsExport
abstract class A {
abstract fun foo(k: String): String
}
class B {
class Foo : A() {
override fun foo(k: String): String {
return "O" + k
}
fun bar(k: String): String {
return foo(k)
}
}
}
object MyObject {
class A {
fun valueA() = "OK"
}
class B {
fun valueB() = "OK"
}
class C {
fun valueC() = "OK"
}
}
// FILE: test.js
function box() {
if (new this["export_nested_class"].B.Foo().bar("K") != "OK") return "fail 1";
if (new this["export_nested_class"].MyObject.A().valueA() != "OK") return "fail 2";
if (new this["export_nested_class"].MyObject.B().valueB() != "OK") return "fail 3";
if (new this["export_nested_class"].MyObject.C().valueC() != "OK") return "fail 4";
return "OK"
}
@@ -0,0 +1,72 @@
// EXPECTED_REACHABLE_NODES: 1265
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// SKIP_MINIFICATION
// SKIP_DCE_DRIVEN
// SKIP_NODE_JS
// See KT-43783
// MODULE: nestedObjectExport
// FILE: lib.kt
@file:JsExport
class Abc {
companion object AbcCompanion {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
class Foo {
companion object {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
sealed class MyEnum(val name: String) {
object A: MyEnum("A")
object B: MyEnum("B")
object C: MyEnum("C")
}
object MyObject {
object A {
fun valueA() = "OK"
}
object B {
fun valueB() = "OK"
}
object C {
fun valueC() = "OK"
}
}
// FILE: test.js
function box() {
const abcCompanion = nestedObjectExport.Abc.AbcCompanion;
if (abcCompanion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (abcCompanion.prop != 'Companion object property OK') return 'companion object property failure';
const justCompanion = nestedObjectExport.Foo.Companion;
if (justCompanion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (justCompanion.prop != 'Companion object property OK') return 'companion object property failure';
if (nestedObjectExport.MyEnum.A.name != 'A') return 'MyEnum.A failure';
if (nestedObjectExport.MyEnum.B.name != 'B') return 'MyEnum.B failure';
if (nestedObjectExport.MyEnum.C.name != 'C') return 'MyEnum.C failure';
if (nestedObjectExport.MyObject.A.valueA() != "OK") return 'MyObject.A failure';
if (nestedObjectExport.MyObject.B.valueB() != "OK") return 'MyObject.B failure';
if (nestedObjectExport.MyObject.C.valueC() != "OK") return 'MyObject.C failure';
return 'OK';
}
@@ -0,0 +1,66 @@
// EXPECTED_REACHABLE_NODES: 1265
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// SKIP_MINIFICATION
// SKIP_NODE_JS
// SKIP_DCE_DRIVEN
// MODULE: exportProtectedMembers
// FILE: lib.kt
@file:JsExport
open class Foo protected constructor() {
protected fun bar(): String = "protected method"
private var _baz: String = "baz"
protected var baz: String
get() = _baz
set(value) {
_baz = value
}
protected val bazReadOnly: String
get() = _baz
protected val quux: String = "quux"
protected var quuz: String = "quuz"
protected class NestedClass {
val prop: String = "nested class property"
}
protected object NestedObject {
val prop: String = "nested object property"
}
protected companion object {
val prop: String = "companion object property"
}
}
// FILE: test.js
function box() {
foo = new exportProtectedMembers.Foo();
if (foo.bar() != 'protected method') return 'failed to call protected method';
if (foo.baz != 'baz') return 'failed to read `baz`';
if (foo.bazReadOnly != 'baz') return 'failed to read `bazReadOnly`';
foo.baz = 'beer';
if (foo.baz != 'beer') return 'failed to write protected var';
if (foo.bazReadOnly != 'beer') return 'unexpected value of `bazReadOnly` after modifying `baz`';
if (foo.quux != 'quux') return 'failed to read `quux`';
if (foo.quuz != 'quuz') return 'failed to read `quuz`';
foo.quuz = 'ale';
if (foo.quuz != 'ale') return 'failed to write `quuz`';
nestedClass = new exportProtectedMembers.Foo.NestedClass()
if (nestedClass.prop != 'nested class property')
return 'failed to read protected class property'
if (exportProtectedMembers.Foo.NestedObject.prop != 'nested object property')
return 'failed to read protected nested object property'
if (exportProtectedMembers.Foo.Companion.prop != 'companion object property')
return 'failed to read protected companion object property'
return 'OK';
}
@@ -0,0 +1,17 @@
// EXPECTED_REACHABLE_NODES: 1270
// SKIP_MINIFICATION
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// SKIP_NODE_JS
// MODULE: non_identifier_module_name
// FILE: lib.kt
@file:JsExport
@JsName("foo")
public fun foo(k: String): String = "O$k"
// FILE: test.js
function box() {
return this["non_identifier_module_name"].foo("K");
}
@@ -0,0 +1,41 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: overriden_chain_non_export_intermediate
// FILE: not_exported.kt
abstract class B : A() {
abstract fun baz(): String
override fun foo(): String = "foo"
}
// FILE: exported.kt
@file:JsExport
abstract class A {
abstract fun foo(): String
abstract fun bar(): String
}
class C : B() {
override fun bar(): String = "bar"
override fun baz(): String = "baz"
fun bay(): String = "bay"
}
// FILE: test.js
function box() {
return test(new this["overriden_chain_non_export_intermediate"].C());
}
function test(c) {
if (c.foo() === "foo" && c.bar() === "bar" && c.bay() == "bay") return "OK"
return "fail"
}
@@ -0,0 +1,45 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: lib
// FILE: not_exported.kt
external abstract class Foo {
abstract fun o(): String
}
abstract class Bar : Foo() {
@JsName("oStable")
abstract fun String.o(): String
override fun o(): String {
return "O".o()
}
}
// FILE: exported.kt
@file:JsExport
class Baz : Bar() {
override fun String.o(): String {
return this
}
}
// FILE: test.js
function Foo() {}
Foo.prototype.k = function() {
return "K"
}
function box() {
return test(new this["lib"].Baz());
}
function test(foo) {
const oStable = foo.oStable("OK")
if (oStable !== "OK") return "false: " + oStable
return foo.o() + foo.k()
}
@@ -0,0 +1,17 @@
// IGNORE_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1270
// SKIP_MINIFICATION
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: if
// FILE: lib.kt
@file:JsExport
@JsName("foo")
public fun foo(k: String): String = "O$k"
// FILE: test.js
function box() {
return this["if"].foo("K");
}