test for KT-2177 and jslint
This commit is contained in:
@@ -42,6 +42,7 @@ public abstract class BasicTest extends TestWithEnvironment {
|
||||
private static final String TEST_FILES = "js/js.translator/testFiles/";
|
||||
private static final String CASES = "cases/";
|
||||
private static final String OUT = "out/";
|
||||
public static final String JSLINT_LIB = pathToTestFilesRoot() + "jslint.js";
|
||||
private static final String KOTLIN_JS_LIB = pathToTestFilesRoot() + "kotlin_lib.js";
|
||||
private static final String KOTLIN_JS_LIB_ECMA_3 = pathToTestFilesRoot() + "kotlin_lib_ecma3.js";
|
||||
private static final String KOTLIN_JS_LIB_ECMA_5 = pathToTestFilesRoot() + "kotlin_lib_ecma5.js";
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.jetbrains.k2js.test.rhino;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* @author Sergey Simonchik
|
||||
*/
|
||||
class FunctionWithScope {
|
||||
private final Function fun;
|
||||
private final Scriptable scope;
|
||||
|
||||
FunctionWithScope(@NotNull Function function, @NotNull Scriptable scope) {
|
||||
this.fun = function;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Function getFunction() {
|
||||
return fun;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Scriptable getScope() {
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.jetbrains.k2js.test.rhino;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.Script;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* @author Sergey Simonchik
|
||||
*/
|
||||
class RhinoFunctionManager {
|
||||
private static final Logger LOG = Logger.getInstance(RhinoFunctionManager.class);
|
||||
|
||||
private final ThreadLocal<FunctionWithScope> threadLocalFunction = new ThreadLocal<FunctionWithScope>() {
|
||||
@Override
|
||||
protected FunctionWithScope initialValue() {
|
||||
if (script == null) {
|
||||
synchronized (threadLocalFunction) {
|
||||
if (script == null) {
|
||||
script = compileScript(9);
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractFunctionWithScope(script);
|
||||
}
|
||||
};
|
||||
|
||||
private volatile Script script;
|
||||
|
||||
private final Supplier<String> scriptSourceProvider;
|
||||
private final String functionName;
|
||||
|
||||
public RhinoFunctionManager(@NotNull Supplier<String> scriptSourceProvider,
|
||||
@NotNull String functionName) {
|
||||
this.scriptSourceProvider = scriptSourceProvider;
|
||||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
private Script compileScript(int optimizationLevel) {
|
||||
long startNano = System.nanoTime();
|
||||
Context context = Context.enter();
|
||||
try {
|
||||
context.setOptimizationLevel(optimizationLevel);
|
||||
String scriptSource = scriptSourceProvider.get();
|
||||
return context.compileString(scriptSource, "<" + functionName + " script>", 1, null);
|
||||
}
|
||||
finally {
|
||||
Context.exit();
|
||||
LOG.info(formatMessage(startNano, functionName + " script rhino compilation"));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private FunctionWithScope extractFunctionWithScope(@NotNull Script script) {
|
||||
long startNano = System.nanoTime();
|
||||
Context context = Context.enter();
|
||||
try {
|
||||
Scriptable scope = context.initStandardObjects();
|
||||
script.exec(context, scope);
|
||||
Object jsLintObj = scope.get(functionName, scope);
|
||||
if (jsLintObj instanceof Function) {
|
||||
Function jsLint = (Function) jsLintObj;
|
||||
return new FunctionWithScope(jsLint, scope);
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException(functionName + " is undefined or not a function.");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Context.exit();
|
||||
LOG.info(formatMessage(startNano, functionName + " function extraction"));
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatMessage(long startTimeNano, @NotNull String actionName) {
|
||||
long nanoDuration = System.nanoTime() - startTimeNano;
|
||||
return String.format("[%s] %s took %.2f ms",
|
||||
Thread.currentThread().getName(),
|
||||
actionName,
|
||||
nanoDuration / 1000000.0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionWithScope getFunctionWithScope() {
|
||||
return threadLocalFunction.get();
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,18 @@
|
||||
|
||||
package org.jetbrains.k2js.test.rhino;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.config.EcmaVersion;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.jetbrains.k2js.test.BasicTest;
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -31,6 +36,29 @@ import java.util.Set;
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class RhinoUtils {
|
||||
private static final Set<String> IGNORED_JSLINT_WARNINGS = new THashSet<String>();
|
||||
|
||||
static {
|
||||
// todo dart ast bug
|
||||
IGNORED_JSLINT_WARNINGS.add("Unexpected space between '}' and '('.");
|
||||
// don't read JS, use kotlin and idea debugger ;)
|
||||
IGNORED_JSLINT_WARNINGS.add("Wrap an immediate function invocation in parentheses to assist the reader in understanding that the expression is the result of a function, and not the function itself.");
|
||||
}
|
||||
|
||||
private static final RhinoFunctionManager functionManager = new RhinoFunctionManager(
|
||||
new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
try {
|
||||
return FileUtil.loadFile(new File(BasicTest.JSLINT_LIB));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
"JSLINT"
|
||||
);
|
||||
|
||||
private RhinoUtils() {
|
||||
|
||||
@@ -76,6 +104,62 @@ public final class RhinoUtils {
|
||||
runFileWithRhino(filename, context, scope);
|
||||
}
|
||||
checker.runChecks(context, scope);
|
||||
|
||||
lintIt(context, fileNames.get(fileNames.size() - 1));
|
||||
|
||||
Context.exit();
|
||||
}
|
||||
|
||||
private static void lintIt(Context context, String fileName) throws IOException {
|
||||
NativeObject options = new NativeObject();
|
||||
// todo fix dart ast?
|
||||
options.defineProperty("white", true, ScriptableObject.READONLY);
|
||||
// vars, http://uxebu.com/blog/2010/04/02/one-var-statement-for-one-variable/
|
||||
options.defineProperty("vars", true, ScriptableObject.READONLY);
|
||||
NativeArray globals = new NativeArray(new Object[]{"Kotlin"});
|
||||
options.defineProperty("predef", globals, ScriptableObject.READONLY);
|
||||
|
||||
Object[] args = {FileUtil.loadFile(new File(fileName)), options};
|
||||
FunctionWithScope functionWithScope = functionManager.getFunctionWithScope();
|
||||
Function function = functionWithScope.getFunction();
|
||||
Scriptable scope = functionWithScope.getScope();
|
||||
Object status = function.call(context, scope, scope, args);
|
||||
Boolean noErrors = (Boolean) Context.jsToJava(status, Boolean.class);
|
||||
if (!noErrors) {
|
||||
Object errors = function.get("errors", scope);
|
||||
if (errors == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println(fileName);
|
||||
for (Object errorObj : ((NativeArray) errors)) {
|
||||
if (!(errorObj instanceof NativeObject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NativeObject e = (NativeObject) errorObj;
|
||||
int line = toInt(e.get("line"));
|
||||
int character = toInt(e.get("character"));
|
||||
if (line < 0 || character < 0) {
|
||||
continue;
|
||||
}
|
||||
Object reasonObj = e.get("reason");
|
||||
if (reasonObj instanceof String) {
|
||||
String reason = (String) reasonObj;
|
||||
if (IGNORED_JSLINT_WARNINGS.contains(reason)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println(line + ":" + character + " " + reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int toInt(Object obj) {
|
||||
if (obj instanceof Number) {
|
||||
return ((Number) obj).intValue();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.jetbrains.k2js.test.semantics;
|
||||
|
||||
import org.jetbrains.k2js.config.EcmaVersion;
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
@@ -41,9 +44,13 @@ public final class ObjectTest extends SingleFileTranslationTest {
|
||||
fooBoxTest();
|
||||
}
|
||||
|
||||
public void testObjectInObject() throws Exception {
|
||||
fooBoxTest(EnumSet.noneOf(EcmaVersion.class));
|
||||
}
|
||||
|
||||
|
||||
public void testObjectInheritingFromATrait() throws Exception {
|
||||
fooBoxTest();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
package foo
|
||||
|
||||
object A {
|
||||
val query = object {val status = "complete"}
|
||||
}
|
||||
|
||||
object B {
|
||||
private val ov = "d"
|
||||
val query = object {val status = "complete" + ov}
|
||||
}
|
||||
|
||||
class C {
|
||||
val query = object {val status = "complete"}
|
||||
}
|
||||
|
||||
fun box() = A.query.status == "complete" && B.query.status == "completed" && C().query.status == "completed"
|
||||
|
||||
Reference in New Issue
Block a user