JS backend: added jsCode test cases
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
$TESTDATA_DIR$/jsCodeError.kt
|
||||
-output
|
||||
$TEMP_DIR$/out.js
|
||||
@@ -0,0 +1,2 @@
|
||||
fun f1(): Unit = js("var = 10;")
|
||||
fun f2(): Unit = js("""var = 10;""")
|
||||
@@ -0,0 +1,3 @@
|
||||
ERROR: compiler/testData/cli/js/jsCodeError.kt: (1, 25) JavaScript: missing variable name
|
||||
ERROR: compiler/testData/cli/js/jsCodeError.kt: (2, 27) JavaScript: missing variable name
|
||||
COMPILATION_ERROR
|
||||
@@ -0,0 +1,3 @@
|
||||
$TESTDATA_DIR$/jsCodeNotLiteralError.kt
|
||||
-output
|
||||
$TEMP_DIR$/out.js
|
||||
@@ -0,0 +1,3 @@
|
||||
val s = "1 + 1;"
|
||||
fun two(): Int = js(s)
|
||||
fun three(): Int = js("1" + "+ 2;")
|
||||
@@ -0,0 +1,3 @@
|
||||
ERROR: compiler/testData/cli/js/jsCodeNotLiteralError.kt: (2, 18) Argument must be string literal
|
||||
ERROR: compiler/testData/cli/js/jsCodeNotLiteralError.kt: (3, 20) Argument must be string literal
|
||||
COMPILATION_ERROR
|
||||
@@ -0,0 +1,3 @@
|
||||
$TESTDATA_DIR$/jsCodeWarning.kt
|
||||
-output
|
||||
$TEMP_DIR$/out.js
|
||||
@@ -0,0 +1 @@
|
||||
fun main(args: Array<String>): Unit = js("var a = 08;")
|
||||
@@ -0,0 +1,2 @@
|
||||
WARNING: compiler/testData/cli/js/jsCodeWarning.kt: (1, 50) JavaScript: illegal octal literal digit 8; interpreting it as a decimal digit
|
||||
OK
|
||||
@@ -156,6 +156,24 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cli/js"), Pattern.compile("^(.+)\\.args$"), false);
|
||||
}
|
||||
|
||||
@TestMetadata("jsCodeError.args")
|
||||
public void testJsCodeError() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/js/jsCodeError.args");
|
||||
doJsTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("jsCodeNotLiteralError.args")
|
||||
public void testJsCodeNotLiteralError() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/js/jsCodeNotLiteralError.args");
|
||||
doJsTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("jsCodeWarning.args")
|
||||
public void testJsCodeWarning() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/js/jsCodeWarning.args");
|
||||
doJsTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("jsExtraHelp.args")
|
||||
public void testJsExtraHelp() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/js/jsExtraHelp.args");
|
||||
|
||||
@@ -90,4 +90,19 @@ public class K2JsCliTest extends CliBaseTest {
|
||||
|
||||
Assert.assertFalse(new File(tmpdir.getTmpDir(), "out.js").isFile());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsCodeError() throws Exception {
|
||||
executeCompilerCompareOutputJS();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsCodeWarning() throws Exception {
|
||||
executeCompilerCompareOutputJS();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsCodeNotLiteralError() throws Exception {
|
||||
executeCompilerCompareOutputJS();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.test.semantics;
|
||||
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationWithDirectivesTest;
|
||||
|
||||
public final class JsCodeTest extends SingleFileTranslationWithDirectivesTest {
|
||||
|
||||
public JsCodeTest() {
|
||||
super("jsCode/");
|
||||
}
|
||||
|
||||
public void testQuotes() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testLiteral() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testFunction() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testObject() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testOperators() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testIf() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testSwitch() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testDoWhile() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testWhile() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testFor() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testForIn() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testInvocation() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testBreak() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testContinue() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testLabel() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testLabelSiblingClash() throws Exception {
|
||||
checkFooBoxIsOkWithDirectives();
|
||||
}
|
||||
|
||||
public void testLabelNestedClash() throws Exception {
|
||||
checkFooBoxIsOkWithDirectives();
|
||||
}
|
||||
|
||||
public void testTryCatchFinally() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testCatchScope() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testObjectScopes() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
fun box(): String {
|
||||
var c: Int = 0
|
||||
|
||||
js("""
|
||||
for (var i = 0; i < 10; i++) {
|
||||
c = i;
|
||||
|
||||
if (i === 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(3, c)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package foo
|
||||
|
||||
fun test(action: ()->Unit): String = js("""
|
||||
var e = { message: "ok" };
|
||||
|
||||
try {
|
||||
action();
|
||||
} catch (e) {
|
||||
return e.message;
|
||||
}
|
||||
|
||||
return e.message;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("ok", test {})
|
||||
assertEquals("not ok", test { throw Exception("not ok") })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
fun box(): String {
|
||||
var c: Int = 0
|
||||
|
||||
js("""
|
||||
for (var i = 1; i < 6; i++) {
|
||||
if (i % 2 === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(3, c)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
fun factorial(n: Int): Int = js("""
|
||||
var result = 1;
|
||||
var i = 0;
|
||||
|
||||
do {
|
||||
result *= ++i;
|
||||
} while(i < n);
|
||||
|
||||
return result;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(24, factorial(4))
|
||||
assertEquals(120, factorial(5))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package foo
|
||||
|
||||
fun factorial(n: Int): Int = js("""
|
||||
var result = 1;
|
||||
|
||||
for (var i = 1; i <= n; i++) {
|
||||
result *= i;
|
||||
}
|
||||
|
||||
return result;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(24, factorial(4))
|
||||
assertEquals(120, factorial(5))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package foo
|
||||
|
||||
fun countKeys(a: Array<Int>): Int = js("""
|
||||
var result = 0;
|
||||
|
||||
for (var key in a) {
|
||||
result += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(3, countKeys(array(1,2,3)))
|
||||
assertEquals(4, countKeys(array(1,2,3,4)))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package foo
|
||||
|
||||
fun callWithArgs(sumFunc: (Int, Int) -> Int, a: Int, b: Int): Int {
|
||||
return sumFunc(a, b)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val kotlinSum: (Int, Int) -> Int = {(a, b) -> a + b}
|
||||
val jsSum: (Int, Int) -> Int = js("function (a, b) { return a + b; }")
|
||||
assertEquals(callWithArgs(kotlinSum, 1, 2), callWithArgs(jsSum, 1, 2))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package foo
|
||||
|
||||
fun testIf(flag: Boolean): Int = js("""
|
||||
if (flag)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
""")
|
||||
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(1, testIf(true))
|
||||
assertEquals(-1, testIf(false))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package foo
|
||||
|
||||
fun run<A, B, C>(a: A, b: B, func: (A, B) -> C): C = js("func(a, b)")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(3, run(1, 2) {(a, b) -> a + b})
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package foo
|
||||
|
||||
fun testLabelledBlock() {
|
||||
var c: Int = 0
|
||||
|
||||
js("""
|
||||
block: {
|
||||
c = 1;
|
||||
break block;
|
||||
c = 2;
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(1, c, "testLabelledBlock")
|
||||
}
|
||||
|
||||
fun testBreakInFor() {
|
||||
var c: Int = 0
|
||||
|
||||
js("""
|
||||
outer: for (var i = 0; i < 10; i++) {
|
||||
for (var j = 0; j < 10; j++) {
|
||||
if (i === 1) {
|
||||
break outer;
|
||||
}
|
||||
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(10, c, "testBreakInFor")
|
||||
}
|
||||
|
||||
fun testContinueInFor() {
|
||||
var c: Int = 0
|
||||
|
||||
js("""
|
||||
outer: for (var i = 0; i < 10; i++) {
|
||||
for (var j = 0; j < 10; j++) {
|
||||
if (i >= 1) {
|
||||
continue outer;
|
||||
}
|
||||
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(10, c, "testContinueInFor")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testLabelledBlock()
|
||||
testBreakInFor()
|
||||
testContinueInFor()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package foo
|
||||
|
||||
// CHECK_LABELS_COUNT: function=box name=block count=1
|
||||
// CHECK_LABELS_COUNT: function=box name=block_0 count=1
|
||||
|
||||
fun box(): String {
|
||||
var i = 0
|
||||
var j = 0
|
||||
|
||||
js("""
|
||||
block: {
|
||||
i++;
|
||||
|
||||
block: {
|
||||
j++;
|
||||
break block;
|
||||
j++;
|
||||
}
|
||||
|
||||
break block;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
""")
|
||||
|
||||
assertEquals(1, i, "i")
|
||||
assertEquals(1, j, "j")
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package foo
|
||||
|
||||
// CHECK_LABELS_COUNT: function=box name=block count=2
|
||||
|
||||
fun box(): String {
|
||||
var i = 0
|
||||
var j = 0
|
||||
|
||||
js("""
|
||||
block: {
|
||||
i++;
|
||||
break block;
|
||||
i++;
|
||||
}
|
||||
|
||||
block: {
|
||||
j++;
|
||||
break block;
|
||||
j++;
|
||||
}
|
||||
""")
|
||||
|
||||
assertEquals(1, i, "i")
|
||||
assertEquals(1, j, "j")
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package foo
|
||||
|
||||
native trait HasName {
|
||||
val name: String
|
||||
}
|
||||
|
||||
fun assertArrayEquals<T>(expected: Array<T>, actual: Array<T>) {
|
||||
val expectedSize = expected.size
|
||||
val actualSize = actual.size
|
||||
|
||||
if (expectedSize != actualSize) {
|
||||
throw Exception("expected size -- $expectedSize, actual size -- $actualSize")
|
||||
}
|
||||
|
||||
for (i in 0..expectedSize) {
|
||||
val expectedIth = expected[i]
|
||||
val actualIth = actual[i]
|
||||
|
||||
if (expected[i] != actual[i]) {
|
||||
throw Exception("expected[$i] -- $expectedIth, actual[$i] -- $actualIth")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(10, js("10"), "Int")
|
||||
assertEquals(10.5, js("10.5"), "Float")
|
||||
assertEquals("10", js("'10'"), "String")
|
||||
assertEquals(true, js("true"), "True")
|
||||
assertEquals(false, js("false"), "False")
|
||||
|
||||
val obj: HasName = js("({name: 'OBJ'})")
|
||||
assertEquals("OBJ", obj.name, "Object")
|
||||
|
||||
assertArrayEquals(array(1, 2, 3), js("[1, 2, 3]"))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package foo
|
||||
|
||||
native trait Summizer {
|
||||
fun sum(a: Int, b: Int): Int
|
||||
}
|
||||
|
||||
fun getSummizer(): Summizer = js("""
|
||||
var summizer = {
|
||||
sum: function(a, b) { return a + b;}
|
||||
};
|
||||
|
||||
return summizer;
|
||||
""");
|
||||
|
||||
fun box(): String {
|
||||
val summizer = getSummizer()
|
||||
assertEquals(3, summizer.sum(1, 2))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package foo
|
||||
|
||||
native trait Summizer {
|
||||
fun sum(a: Int, b: Int): Int
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val summizer1: Summizer = js("({ sum: function(a, b) { return a + b; }})")
|
||||
assertEquals(3, summizer1.sum(1, 2), "summizer1")
|
||||
|
||||
val summizer2: Summizer = js("({ sum: function(a, b) { return a + b; }})")
|
||||
assertEquals(3, summizer2.sum(1, 2), "summizer2")
|
||||
|
||||
return "OK";
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package foo
|
||||
|
||||
data class A(val value: Int)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(-1, js("-1"), "- (unary)")
|
||||
assertEquals(1, js("+'1'"), "+ (unary)")
|
||||
|
||||
assertEquals(1, js("2 - 1"), "- (binary)")
|
||||
assertEquals(3, js("2 + 1"), "+ (binary)")
|
||||
assertEquals(10, js("2 * 5"), "*")
|
||||
assertEquals(5, js("10 / 2"), "/")
|
||||
assertEquals(1, js("11 % 2"), "%")
|
||||
|
||||
assertEquals(36, js("9 << 2"), "<<")
|
||||
assertEquals(2, js("9 >> 2"), ">>")
|
||||
assertEquals(1073741821, js("-9 >>> 2"), ">>>")
|
||||
assertEquals(0, js("0 & 1"), "&")
|
||||
assertEquals(1, js("0 | 1"), "|")
|
||||
assertEquals(1, js("0 ^ 1"), "^")
|
||||
assertEquals(-2, js("~1"), "~")
|
||||
|
||||
var i = 2
|
||||
assertEquals(1, js("--i"), "-- prefix")
|
||||
assertEquals(1, js("i--"), "-- postfix (1)")
|
||||
assertEquals(0, js("i"), "-- postfix (0)")
|
||||
assertEquals(1, js("++i"), "++ prefix")
|
||||
assertEquals(1, js("i++"), "++ postfix (1)")
|
||||
assertEquals(2, js("i"), "++ postfix (0)")
|
||||
|
||||
assertEquals(true , js("true || false"), "||")
|
||||
assertEquals(false , js("true && false"), "&&")
|
||||
assertEquals(false , js("!true"), "!")
|
||||
|
||||
assertEquals(true , js("1 < 2"), "<")
|
||||
assertEquals(false, js("1 > 2"), ">")
|
||||
assertEquals(true, js("1 <= 2"), "<=")
|
||||
assertEquals(false, js("1 >= 2"), ">=")
|
||||
|
||||
assertEquals(false, js("2 === '2'"), "===")
|
||||
assertEquals(true, js("2 !== '2'"), "!==")
|
||||
assertEquals(true, js("2 == '2'"), "==")
|
||||
assertEquals(false, js("2 != '2'"), "!=")
|
||||
|
||||
assertEquals("odd", js("(1 % 2 === 0)?'even':'odd'"), "?:")
|
||||
assertEquals("even", js("(4 % 2 === 0)?'even':'odd'"), "?:")
|
||||
assertEquals(3, js("1,2,3"), ", (comma)")
|
||||
|
||||
var j = 0
|
||||
assertEquals(1, js("j = 1"), "=")
|
||||
assertEquals(3, js("j += 2"), "+=")
|
||||
assertEquals(2, js("j -= 1"), "-=")
|
||||
assertEquals(14, js("j *= 7"), "*=")
|
||||
assertEquals(7, js("j /= 2"), "/=")
|
||||
assertEquals(1, js("j %= 2"), "%=")
|
||||
|
||||
assertEquals(Unit, js("(void 0)"), "void")
|
||||
assertEquals(true, js("'key' in {'key': 10}"), "in")
|
||||
assertEquals("string", js("typeof 'str'"), "typeof")
|
||||
assertEquals(A(2), js("new _.foo.A(2)"), "new")
|
||||
assertEquals(true, js("new String('str') instanceof String"), "instanceof")
|
||||
|
||||
var s: Any = js("({key: 10})")
|
||||
assertEquals(Unit, js("delete s.key, s.key"), "delete")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package foo
|
||||
|
||||
fun singleQuoted(i: Int): Int = js("return i")
|
||||
fun tripleQuoted(i: Int): Int = js("""return i""")
|
||||
fun tripleQuotedInnerQuotes(i: Int): String = js("""return "i"""")
|
||||
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(0, singleQuoted(0))
|
||||
assertEquals(0, tripleQuoted(0))
|
||||
assertEquals("i", tripleQuotedInnerQuotes(0))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package foo
|
||||
|
||||
fun testSwitch(number: Int): String = js("""
|
||||
var result;
|
||||
|
||||
switch(number) {
|
||||
case 1:
|
||||
result = "one";
|
||||
break;
|
||||
case 2:
|
||||
result = "two";
|
||||
break;
|
||||
default:
|
||||
result = "don't know";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("one", testSwitch(1))
|
||||
assertEquals("two", testSwitch(2))
|
||||
assertEquals("don't know", testSwitch(3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package foo
|
||||
|
||||
class Counter {
|
||||
var count: Int = 0
|
||||
|
||||
public fun inc() {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
fun test(c: Counter, ex: Exception): Unit = js("""
|
||||
try {
|
||||
throw ex;
|
||||
} catch (e) {
|
||||
c.inc()
|
||||
} finally {
|
||||
c.inc()
|
||||
}
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
val c = Counter()
|
||||
test(c, NullPointerException())
|
||||
assertEquals(2, c.count)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
fun factorial(n: Int): Int = js("""
|
||||
var result = 1;
|
||||
var i = 1;
|
||||
|
||||
while(i <= n) {
|
||||
result *= i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
""")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(24, factorial(4))
|
||||
assertEquals(120, factorial(5))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user