KJS: switch to using Nashorn instead of Rhino for JS backend tests
This commit is contained in:
@@ -20,8 +20,7 @@ import com.intellij.openapi.util.io.FileUtil;
|
|||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoFunctionResultChecker;
|
import org.jetbrains.kotlin.js.test.NashornJsTestChecker;
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoUtils;
|
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -59,7 +58,7 @@ public class AntTaskJsTest extends AbstractAntTaskTest {
|
|||||||
|
|
||||||
List<String> filePaths = CollectionsKt.map(fileNames, s -> getOutputFileByName(s).getAbsolutePath());
|
List<String> filePaths = CollectionsKt.map(fileNames, s -> getOutputFileByName(s).getAbsolutePath());
|
||||||
|
|
||||||
RhinoUtils.runRhinoTest(filePaths, new RhinoFunctionResultChecker("out", "foo", "box", "OK", withModuleSystem));
|
NashornJsTestChecker.INSTANCE.check(filePaths, "out", "foo", "box", "OK", withModuleSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doJsAntTestForPostfixPrefix(@Nullable String prefix, @Nullable String postfix) throws Exception {
|
private void doJsAntTestForPostfixPrefix(@Nullable String prefix, @Nullable String postfix) throws Exception {
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ import org.jetbrains.kotlin.js.facade.K2JSTranslator
|
|||||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||||
import org.jetbrains.kotlin.js.facade.TranslationResult
|
import org.jetbrains.kotlin.js.facade.TranslationResult
|
||||||
import org.jetbrains.kotlin.js.facade.TranslationUnit
|
import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoFunctionResultChecker
|
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoUtils
|
|
||||||
import org.jetbrains.kotlin.js.test.utils.DirectiveTestUtils
|
import org.jetbrains.kotlin.js.test.utils.DirectiveTestUtils
|
||||||
import org.jetbrains.kotlin.js.test.utils.JsTestUtils
|
import org.jetbrains.kotlin.js.test.utils.JsTestUtils
|
||||||
import org.jetbrains.kotlin.js.test.utils.verifyAst
|
import org.jetbrains.kotlin.js.test.utils.verifyAst
|
||||||
@@ -165,8 +163,7 @@ abstract class BasicBoxTest(
|
|||||||
expectedResult: String,
|
expectedResult: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
) {
|
) {
|
||||||
val checker = RhinoFunctionResultChecker(testModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
|
NashornJsTestChecker.check(jsFiles, testModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
|
||||||
RhinoUtils.runRhinoTest(jsFiles, checker)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun performAdditionalChecks(generatedJsFiles: List<String>, outputPrefixFile: File?, outputPostfixFile: File?) {}
|
protected open fun performAdditionalChecks(generatedJsFiles: List<String>, outputPrefixFile: File?, outputPostfixFile: File?) {}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.kotlin.js.test
|
||||||
|
|
||||||
|
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
|
||||||
|
import jdk.nashorn.api.scripting.ScriptObjectMirror
|
||||||
|
import jdk.nashorn.internal.runtime.ScriptRuntime
|
||||||
|
import org.junit.Assert
|
||||||
|
import javax.script.Invocable
|
||||||
|
import javax.script.ScriptEngine
|
||||||
|
|
||||||
|
fun createScriptEngine(): ScriptEngine =
|
||||||
|
// TODO use "-strict"
|
||||||
|
NashornScriptEngineFactory().getScriptEngine("--language=es5", "--no-java", "--no-syntax-extensions")
|
||||||
|
|
||||||
|
private fun ScriptEngine.loadFile(path: String) {
|
||||||
|
eval("load('$path');")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ScriptObjectMirror.toMapWithAllMembers(): Map<String, Any?> = getOwnKeys(true).associate { it to this[it] }
|
||||||
|
|
||||||
|
object NashornJsTestChecker {
|
||||||
|
private val SETUP_KOTLIN_OUTPUT = "kotlin.kotlin.io.output = new kotlin.kotlin.io.BufferedOutput();"
|
||||||
|
private val GET_KOTLIN_OUTPUT = "kotlin.kotlin.io.output.buffer;"
|
||||||
|
|
||||||
|
private val engine = createScriptEngineForTest()
|
||||||
|
|
||||||
|
fun check(
|
||||||
|
files: List<String>,
|
||||||
|
testModuleName: String,
|
||||||
|
testPackageName: String?,
|
||||||
|
testFunctionName: String,
|
||||||
|
expectedResult: String,
|
||||||
|
withModuleSystem: Boolean
|
||||||
|
) {
|
||||||
|
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
||||||
|
Assert.assertEquals(expectedResult, actualResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkStdout(files: List<String>, expectedResult: String) {
|
||||||
|
run(files)
|
||||||
|
val actualResult = engine.eval(GET_KOTLIN_OUTPUT)
|
||||||
|
Assert.assertEquals(expectedResult, actualResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun run(files: List<String>) {
|
||||||
|
run(files) { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun run(
|
||||||
|
files: List<String>,
|
||||||
|
testModuleName: String,
|
||||||
|
testPackageName: String?,
|
||||||
|
testFunctionName: String,
|
||||||
|
withModuleSystem: Boolean
|
||||||
|
) = run(files) {
|
||||||
|
val testModule =
|
||||||
|
when {
|
||||||
|
withModuleSystem ->
|
||||||
|
engine.eval(BasicBoxTest.Companion.KOTLIN_TEST_INTERNAL + ".require('" + testModuleName + "')") as ScriptObjectMirror
|
||||||
|
else ->
|
||||||
|
engine.get(testModuleName) as ScriptObjectMirror
|
||||||
|
}
|
||||||
|
|
||||||
|
val testPackage =
|
||||||
|
when {
|
||||||
|
testPackageName === null ->
|
||||||
|
testModule
|
||||||
|
testPackageName.contains(".") ->
|
||||||
|
testPackageName.split(".").fold(testModule) { p, part -> p[part] as ScriptObjectMirror }
|
||||||
|
else ->
|
||||||
|
testModule[testPackageName]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
(engine as Invocable).invokeMethod(testPackage, testFunctionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun run(
|
||||||
|
files: List<String>,
|
||||||
|
f: ScriptEngine.() -> Any?
|
||||||
|
): Any? {
|
||||||
|
val globalObject = engine.eval("this") as ScriptObjectMirror
|
||||||
|
val before = globalObject.toMapWithAllMembers()
|
||||||
|
|
||||||
|
engine.eval(SETUP_KOTLIN_OUTPUT)
|
||||||
|
|
||||||
|
try {
|
||||||
|
files.forEach(engine::loadFile)
|
||||||
|
return engine.f()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
val after = globalObject.toMapWithAllMembers()
|
||||||
|
val diff = after.entries - before.entries
|
||||||
|
|
||||||
|
diff.forEach {
|
||||||
|
globalObject.put(it.key, before[it.key] ?: ScriptRuntime.UNDEFINED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createScriptEngineForTest(): ScriptEngine {
|
||||||
|
val engine = createScriptEngine()
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js",
|
||||||
|
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin.js",
|
||||||
|
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin-test.js"
|
||||||
|
).forEach(engine::loadFile)
|
||||||
|
|
||||||
|
engine.eval("this['kotlin-test'].kotlin.test.overrideAsserter_wbnzx$(new this['kotlin-test'].kotlin.test.DefaultAsserter());")
|
||||||
|
|
||||||
|
return engine
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
|||||||
import org.jetbrains.kotlin.js.parser.parse
|
import org.jetbrains.kotlin.js.parser.parse
|
||||||
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
|
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
|
import org.jetbrains.kotlin.js.test.createScriptEngine
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.rules.TestName
|
import org.junit.rules.TestName
|
||||||
import org.mozilla.javascript.Context
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class BasicOptimizerTest(private var basePath: String) {
|
abstract class BasicOptimizerTest(private var basePath: String) {
|
||||||
@@ -48,21 +48,11 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
|||||||
val unoptimizedCode = FileUtil.loadFile(File(unoptimizedName))
|
val unoptimizedCode = FileUtil.loadFile(File(unoptimizedName))
|
||||||
val optimizedCode = FileUtil.loadFile(File(optimizedName))
|
val optimizedCode = FileUtil.loadFile(File(optimizedName))
|
||||||
|
|
||||||
runFiles(unoptimizedName, optimizedName, unoptimizedCode, optimizedCode)
|
runScript(unoptimizedName, unoptimizedCode)
|
||||||
|
runScript(optimizedName, optimizedCode)
|
||||||
checkOptimizer(unoptimizedCode, optimizedCode)
|
checkOptimizer(unoptimizedCode, optimizedCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runFiles(unoptimizedName: String, optimizedName: String, unoptimizedCode: String, optimizedCode: String) {
|
|
||||||
try {
|
|
||||||
val ctx = Context.enter()
|
|
||||||
runScript(ctx, unoptimizedName, unoptimizedCode)
|
|
||||||
runScript(ctx, optimizedName, optimizedCode)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Context.exit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkOptimizer(unoptimizedCode: String, optimizedCode: String) {
|
private fun checkOptimizer(unoptimizedCode: String, optimizedCode: String) {
|
||||||
val parserScope = JsFunctionScope(JsRootScope(JsProgram()), "<js fun>")
|
val parserScope = JsFunctionScope(JsRootScope(JsProgram()), "<js fun>")
|
||||||
val unoptimizedAst = parse(unoptimizedCode, errorReporter, parserScope)
|
val unoptimizedAst = parse(unoptimizedCode, errorReporter, parserScope)
|
||||||
@@ -133,12 +123,12 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
|||||||
return output.toString()
|
return output.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runScript(ctx: Context, fileName: String, code: String) {
|
private fun runScript(fileName: String, code: String) {
|
||||||
val scope = ctx.initStandardObjects()
|
val engine = createScriptEngine()
|
||||||
ctx.evaluateString(scope, code, fileName, 1, null)
|
engine.eval(code)
|
||||||
val result = ctx.evaluateString(scope, "box()", "unit test", 1, null)
|
val result = engine.eval("box()")
|
||||||
|
|
||||||
Assert.assertEquals("box() function must return 'OK'", "OK", result)
|
Assert.assertEquals("$fileName: box() function must return 'OK'", "OK", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val errorReporter = object : ErrorReporter {
|
private val errorReporter = object : ErrorReporter {
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 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.kotlin.js.test.rhino;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest;
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.test.rhino.RhinoUtils.flushSystemOut;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class RhinoFunctionResultChecker implements RhinoResultChecker {
|
|
||||||
|
|
||||||
private final String moduleId;
|
|
||||||
private final String packageName;
|
|
||||||
private final String functionName;
|
|
||||||
private final Object expectedResult;
|
|
||||||
private final boolean withModuleSystem;
|
|
||||||
|
|
||||||
public RhinoFunctionResultChecker(
|
|
||||||
@NotNull String moduleId,
|
|
||||||
@Nullable String packageName,
|
|
||||||
@NotNull String functionName,
|
|
||||||
@NotNull Object expectedResult,
|
|
||||||
boolean withModuleSystem
|
|
||||||
) {
|
|
||||||
this.moduleId = moduleId;
|
|
||||||
this.packageName = packageName;
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.expectedResult = expectedResult;
|
|
||||||
this.withModuleSystem = withModuleSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void runChecks(Context context, Scriptable scope) throws Exception {
|
|
||||||
Object result = evaluateFunction(context, scope);
|
|
||||||
flushSystemOut(context, scope);
|
|
||||||
assertResultValid(result, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertResultValid(Object result, Context context) {
|
|
||||||
String ecmaVersion = context.getLanguageVersion() == Context.VERSION_1_8 ? "ecma5" : "ecma3";
|
|
||||||
assertEquals("Result of " + packageName + "." + functionName + "() is not what expected (" + ecmaVersion + ")!", expectedResult, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object evaluateFunction(Context cx, Scriptable scope) {
|
|
||||||
return cx.evaluateString(scope, functionCallString(), "function call", 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String functionCallString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
if (withModuleSystem) {
|
|
||||||
sb.append(BasicBoxTest.KOTLIN_TEST_INTERNAL).append(".require('").append(moduleId).append("')");
|
|
||||||
}
|
|
||||||
else if (moduleId.contains(".")) {
|
|
||||||
sb.append("this['").append(moduleId).append("']");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sb.append(moduleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packageName != null) {
|
|
||||||
sb.append('.').append(packageName);
|
|
||||||
}
|
|
||||||
return sb.append(".").append(functionName).append("()").toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.js.test.rhino;
|
|
||||||
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
|
|
||||||
public interface RhinoResultChecker {
|
|
||||||
void runChecks(Context context, Scriptable scope) throws Exception;
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.js.test.rhino;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.test.rhino.RhinoUtils.GET_KOTLIN_OUTPUT;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public final class RhinoSystemOutputChecker implements RhinoResultChecker {
|
|
||||||
|
|
||||||
private final String expectedResult;
|
|
||||||
|
|
||||||
public RhinoSystemOutputChecker(@NotNull String expectedResult) {
|
|
||||||
this.expectedResult = expectedResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void runChecks(@NotNull Context context, @NotNull Scriptable scope)
|
|
||||||
throws Exception {
|
|
||||||
String result = getSystemOutput(context, scope);
|
|
||||||
String trimmedExpected = trimSpace(expectedResult);
|
|
||||||
String trimmedActual = trimSpace(result);
|
|
||||||
|
|
||||||
assertTrue("Returned:\n" + trimmedActual + "END_OF_RETURNED\nExpected:\n" + trimmedExpected
|
|
||||||
+ "END_OF_EXPECTED\n", trimmedExpected.equals(trimmedActual));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String getSystemOutput(@NotNull Context context, @NotNull Scriptable scope) {
|
|
||||||
Object output = context.evaluateString(scope, GET_KOTLIN_OUTPUT, "test", 0, null);
|
|
||||||
RhinoUtils.flushSystemOut(context, scope);
|
|
||||||
assertTrue("Output should be a string.", output instanceof String);
|
|
||||||
return (String) output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String trimSpace(@NotNull String s) {
|
|
||||||
String[] choppedUpString = s.trim().split("\\s");
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String word : choppedUpString) {
|
|
||||||
sb.append(word);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.js.test.rhino;
|
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.kotlin.js.config.EcmaVersion;
|
|
||||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.test.BasicBoxTest.DIST_DIR_JS_PATH;
|
|
||||||
|
|
||||||
public final class RhinoUtils {
|
|
||||||
|
|
||||||
private static final int OPTIMIZATION_OFF = -1;
|
|
||||||
|
|
||||||
private static final String SETUP_KOTLIN_OUTPUT = "kotlin.kotlin.io.output = new kotlin.kotlin.io.BufferedOutput();";
|
|
||||||
private static final String FLUSH_KOTLIN_OUTPUT = "kotlin.kotlin.io.output.flush();";
|
|
||||||
public static final String GET_KOTLIN_OUTPUT = "kotlin.kotlin.io.output.buffer;";
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Map<EcmaVersion, ScriptableObject> versionToScope = ContainerUtil.newHashMap();
|
|
||||||
|
|
||||||
private RhinoUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runFileWithRhino(@NotNull String inputFile,
|
|
||||||
@NotNull Context context,
|
|
||||||
@NotNull Scriptable scope) throws Exception {
|
|
||||||
String result;
|
|
||||||
try {
|
|
||||||
result = FileUtil.loadFile(new File(inputFile), CharsetToolkit.UTF8, true);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
context.setOptimizationLevel(-1);
|
|
||||||
context.evaluateString(scope, result, inputFile, 1, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void runRhinoTest(@NotNull List<String> fileNames, @NotNull RhinoResultChecker checker) throws Exception {
|
|
||||||
EcmaVersion ecmaVersion = EcmaVersion.defaultVersion();
|
|
||||||
Context context = createContext(ecmaVersion);
|
|
||||||
|
|
||||||
context.setOptimizationLevel(OPTIMIZATION_OFF);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Scriptable scope = getScope(ecmaVersion, context);
|
|
||||||
|
|
||||||
context.evaluateString(scope, SETUP_KOTLIN_OUTPUT, "setup kotlin output", 0, null);
|
|
||||||
|
|
||||||
for (String filename : fileNames) {
|
|
||||||
runFileWithRhino(filename, context, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
finishScope(scope);
|
|
||||||
checker.runChecks(context, scope);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Context.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static Scriptable getScope(@NotNull EcmaVersion version, @NotNull Context context) {
|
|
||||||
Scriptable parentScope = getParentScope(version, context);
|
|
||||||
Scriptable scope = context.newObject(parentScope);
|
|
||||||
|
|
||||||
scope.put("kotlin-test", scope, parentScope.get("kotlin-test", parentScope));
|
|
||||||
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void finishScope(@NotNull Scriptable scope) {
|
|
||||||
scope.delete("kotlin-test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static Scriptable getParentScope(@NotNull EcmaVersion version, @NotNull Context context) {
|
|
||||||
return versionToScope.computeIfAbsent(version, v -> initScope(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static ScriptableObject initScope(@NotNull Context context) {
|
|
||||||
ScriptableObject scope = context.initStandardObjects();
|
|
||||||
try {
|
|
||||||
runFileWithRhino(DIST_DIR_JS_PATH + "../../js/js.translator/testData/rhino-polyfills.js", context, scope);
|
|
||||||
runFileWithRhino(DIST_DIR_JS_PATH + "kotlin.js", context, scope);
|
|
||||||
runFileWithRhino(DIST_DIR_JS_PATH + "kotlin-test.js", context, scope);
|
|
||||||
context.evaluateString(scope,
|
|
||||||
"this['kotlin-test'].kotlin.test.overrideAsserter_wbnzx$(new this['kotlin-test'].kotlin.test.DefaultAsserter());",
|
|
||||||
"change asserter to DefaultAsserter", 1, null);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw ExceptionUtilsKt.rethrow(e);
|
|
||||||
}
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO:
|
|
||||||
@NotNull
|
|
||||||
private static Context createContext(@NotNull EcmaVersion ecmaVersion) {
|
|
||||||
Context context = Context.enter();
|
|
||||||
if (ecmaVersion == EcmaVersion.v5) {
|
|
||||||
// actually, currently, doesn't matter because dart doesn't produce js 1.8 code (expression closures)
|
|
||||||
context.setLanguageVersion(Context.VERSION_1_8);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flushSystemOut(@NotNull Context context, @NotNull Scriptable scope) {
|
|
||||||
context.evaluateString(scope, FLUSH_KOTLIN_OUTPUT, "test", 0, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-3
@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.js.test.semantics
|
|||||||
import com.google.common.collect.Lists
|
import com.google.common.collect.Lists
|
||||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoSystemOutputChecker
|
import org.jetbrains.kotlin.js.test.NashornJsTestChecker
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoUtils
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import javax.script.ScriptException
|
||||||
|
|
||||||
abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
||||||
BasicBoxTest.TEST_DATA_DIR_PATH + "/$relativePath/",
|
BasicBoxTest.TEST_DATA_DIR_PATH + "/$relativePath/",
|
||||||
@@ -36,9 +36,10 @@ abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
|||||||
expectedResult: String,
|
expectedResult: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
) {
|
) {
|
||||||
RhinoUtils.runRhinoTest(jsFiles, RhinoSystemOutputChecker(expectedResult))
|
NashornJsTestChecker.checkStdout(jsFiles, expectedResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(ScriptException::class)
|
||||||
protected fun runMainAndCheckOutput(fileName: String, expectedResult: String, vararg args: String) {
|
protected fun runMainAndCheckOutput(fileName: String, expectedResult: String, vararg args: String) {
|
||||||
doTest(pathToTestDir + fileName, expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
doTest(pathToTestDir + fileName, expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.js.test.semantics
|
package org.jetbrains.kotlin.js.test.semantics
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoResultChecker
|
import org.jetbrains.kotlin.js.test.NashornJsTestChecker
|
||||||
import org.jetbrains.kotlin.js.test.rhino.RhinoUtils
|
|
||||||
import org.mozilla.javascript.JavaScriptException
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import javax.script.ScriptException
|
||||||
|
|
||||||
class MultiModuleOrderTest : BasicBoxTest("$TEST_DATA_DIR_PATH/multiModuleOrder/cases/", "$TEST_DATA_DIR_PATH/multiModuleOrder/out/") {
|
class MultiModuleOrderTest : BasicBoxTest("$TEST_DATA_DIR_PATH/multiModuleOrder/cases/", "$TEST_DATA_DIR_PATH/multiModuleOrder/out/") {
|
||||||
fun testPlain() {
|
fun testPlain() {
|
||||||
@@ -42,11 +41,9 @@ class MultiModuleOrderTest : BasicBoxTest("$TEST_DATA_DIR_PATH/multiModuleOrder/
|
|||||||
val mainJsFile = File(parentDir, "$name-main_v5.js").path
|
val mainJsFile = File(parentDir, "$name-main_v5.js").path
|
||||||
val libJsFile = File(parentDir, "$name-lib_v5.js").path
|
val libJsFile = File(parentDir, "$name-lib_v5.js").path
|
||||||
try {
|
try {
|
||||||
RhinoUtils.runRhinoTest(listOf(mainJsFile, libJsFile), RhinoResultChecker { _, _ ->
|
NashornJsTestChecker.run(listOf(mainJsFile, libJsFile))
|
||||||
// don't check anything, expect exception from function
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
catch (e: JavaScriptException) {
|
catch (e: ScriptException) {
|
||||||
val message = e.message!!
|
val message = e.message!!
|
||||||
assertTrue("Exception message should contain reference to dependency (lib)", "'lib'" in message)
|
assertTrue("Exception message should contain reference to dependency (lib)", "'lib'" in message)
|
||||||
assertTrue("Exception message should contain reference to module that failed to load (main)", "'main'" in message)
|
assertTrue("Exception message should contain reference to module that failed to load (main)", "'main'" in message)
|
||||||
|
|||||||
+4
-3
@@ -17,7 +17,8 @@
|
|||||||
package org.jetbrains.kotlin.js.test.semantics;
|
package org.jetbrains.kotlin.js.test.semantics;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.mozilla.javascript.EcmaError;
|
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't really check that this examples work in non-browser environment, so we just check that examples compile and
|
* We can't really check that this examples work in non-browser environment, so we just check that examples compile and
|
||||||
@@ -50,8 +51,8 @@ public final class WebDemoCanvasExamplesTest extends AbstractWebDemoExamplesTest
|
|||||||
runMainAndCheckOutput(filename, "");
|
runMainAndCheckOutput(filename, "");
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
catch (EcmaError e) {
|
catch (ScriptException e) {
|
||||||
String expectedErrorMessage = "ReferenceError: \"" + firstUnknownSymbolEncountered + "\" is not defined.";
|
String expectedErrorMessage = "ReferenceError: \"" + firstUnknownSymbolEncountered + "\" is not defined";
|
||||||
assertTrue("Unexpected error when running compiled canvas examples with rhino.\n" +
|
assertTrue("Unexpected error when running compiled canvas examples with rhino.\n" +
|
||||||
"Expected: " + expectedErrorMessage + "\n" +
|
"Expected: " + expectedErrorMessage + "\n" +
|
||||||
"Actual: " + e.getMessage(),
|
"Actual: " + e.getMessage(),
|
||||||
|
|||||||
+6
-6
@@ -1,9 +1,9 @@
|
|||||||
var Object = createTestObject("Object", 23);
|
var MyObject = createTestObject("MyObject", 23);
|
||||||
extend(Object, {
|
extend(MyObject, {
|
||||||
Object: extend(createTestObject("Object.Object", 123), { AnotherClass : createTestClass("Object.Object.Class", 42, 142) }),
|
Object: extend(createTestObject("MyObject.Object", 123), { AnotherClass : createTestClass("MyObject.Object.Class", 42, 142) }),
|
||||||
Class: createTestClass("Object.Class", 42, 142),
|
Class: createTestClass("MyObject.Class", 42, 142),
|
||||||
Trait : createTestObject("Object.Trait", 324),
|
Trait : createTestObject("MyObject.Trait", 324),
|
||||||
a: createTestObject("Object.a", 34)
|
a: createTestObject("MyObject.a", 34)
|
||||||
});
|
});
|
||||||
|
|
||||||
var SomeClass = function () {};
|
var SomeClass = function () {};
|
||||||
|
|||||||
+21
-21
@@ -3,29 +3,29 @@ package foo
|
|||||||
fun box(): String {
|
fun box(): String {
|
||||||
// in object
|
// in object
|
||||||
|
|
||||||
assertEquals("Object.Object.a", Object.Object.a)
|
assertEquals("MyObject.Object.a", MyObject.Object.a)
|
||||||
assertEquals("Object.Object.b", Object.Object.b)
|
assertEquals("MyObject.Object.b", MyObject.Object.b)
|
||||||
assertEquals(123, Object.Object.test())
|
assertEquals(123, MyObject.Object.test())
|
||||||
|
|
||||||
assertEquals("Object.Object.Class().a", Object.Object.Class("Object.Object.Class().a").a)
|
assertEquals("MyObject.Object.Class().a", MyObject.Object.Class("MyObject.Object.Class().a").a)
|
||||||
assertEquals("Object.Object.Class().b", Object.Object.Class("something").b)
|
assertEquals("MyObject.Object.Class().b", MyObject.Object.Class("something").b)
|
||||||
assertEquals(42, Object.Object.Class("something").test())
|
assertEquals(42, MyObject.Object.Class("something").test())
|
||||||
assertEquals("Object.Object.Class.a", Object.Object.Class.a)
|
assertEquals("MyObject.Object.Class.a", MyObject.Object.Class.a)
|
||||||
assertEquals("Object.Object.Class.b", Object.Object.Class.b)
|
assertEquals("MyObject.Object.Class.b", MyObject.Object.Class.b)
|
||||||
assertEquals(142, Object.Object.Class.test())
|
assertEquals(142, MyObject.Object.Class.test())
|
||||||
|
|
||||||
assertEquals("Object.Class().a", Object.Class("Object.Class().a").a)
|
assertEquals("MyObject.Class().a", MyObject.Class("MyObject.Class().a").a)
|
||||||
assertEquals("Object.Class().b", Object.Class("something").b)
|
assertEquals("MyObject.Class().b", MyObject.Class("something").b)
|
||||||
assertEquals(42, Object.Class("something").test())
|
assertEquals(42, MyObject.Class("something").test())
|
||||||
assertEquals("Object.Class.a", Object.Class.a)
|
assertEquals("MyObject.Class.a", MyObject.Class.a)
|
||||||
assertEquals("Object.Class.b", Object.Class.b)
|
assertEquals("MyObject.Class.b", MyObject.Class.b)
|
||||||
assertEquals(142, Object.Class.test())
|
assertEquals(142, MyObject.Class.test())
|
||||||
|
|
||||||
assertEquals("Object.a.a", Object.a.a)
|
assertEquals("MyObject.a.a", MyObject.a.a)
|
||||||
assertEquals("Object.a.b", Object.a.b)
|
assertEquals("MyObject.a.b", MyObject.a.b)
|
||||||
assertEquals(34, Object.a.test())
|
assertEquals(34, MyObject.a.test())
|
||||||
assertEquals("Object.b", Object.b)
|
assertEquals("MyObject.b", MyObject.b)
|
||||||
assertEquals(23, Object.test())
|
assertEquals(23, MyObject.test())
|
||||||
|
|
||||||
// in class
|
// in class
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ fun box(): String {
|
|||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
external object Object {
|
external object MyObject {
|
||||||
object Object {
|
object Object {
|
||||||
val a: String = definedExternally
|
val a: String = definedExternally
|
||||||
var b: String = definedExternally
|
var b: String = definedExternally
|
||||||
|
|||||||
Vendored
-12
@@ -37,16 +37,4 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch apply to work with TypedArrays if needed.
|
|
||||||
try {
|
|
||||||
(function() {}).apply(null, new Int32Array(0))
|
|
||||||
} catch (e) {
|
|
||||||
var apply = Function.prototype.apply;
|
|
||||||
Object.defineProperty(Function.prototype, 'apply', {
|
|
||||||
value: function(self, array) {
|
|
||||||
return apply.call(this, self, [].slice.call(array));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
@@ -8,5 +8,3 @@ Take one down, pass it around, no more bottles of beer on the wall.
|
|||||||
|
|
||||||
No more bottles of beer on the wall, no more bottles of beer.
|
No more bottles of beer on the wall, no more bottles of beer.
|
||||||
Go to the store and buy some more, 2 bottles of beer on the wall.
|
Go to the store and buy some more, 2 bottles of beer on the wall.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+37
-36
@@ -1,37 +1,38 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>
|
<title>
|
||||||
XML encoding with Kotlin
|
XML encoding with Kotlin
|
||||||
</title>
|
</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>
|
<h1>
|
||||||
XML encoding with Kotlin
|
XML encoding with Kotlin
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
this format can be used as an alternative markup to XML
|
this format can be used as an alternative markup to XML
|
||||||
</p>
|
</p>
|
||||||
<a href="http://jetbrains.com/kotlin">
|
<a href="http://jetbrains.com/kotlin">
|
||||||
Kotlin
|
Kotlin
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
This is some
|
This is some
|
||||||
<b>
|
<b>
|
||||||
mixed
|
mixed
|
||||||
</b>
|
</b>
|
||||||
text. For more see the
|
text. For more see the
|
||||||
<a href="http://jetbrains.com/kotlin">
|
<a href="http://jetbrains.com/kotlin">
|
||||||
Kotlin
|
Kotlin
|
||||||
</a>
|
</a>
|
||||||
project
|
project
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
some text
|
some text
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Command line arguments were:
|
Command line arguments were:
|
||||||
<ul>
|
<ul>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
+39
-38
@@ -1,40 +1,41 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>
|
<title>
|
||||||
XML encoding with Kotlin
|
XML encoding with Kotlin
|
||||||
</title>
|
</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>
|
<h1>
|
||||||
XML encoding with Kotlin
|
XML encoding with Kotlin
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
this format can be used as an alternative markup to XML
|
this format can be used as an alternative markup to XML
|
||||||
</p>
|
</p>
|
||||||
<a href="http://jetbrains.com/kotlin">
|
<a href="http://jetbrains.com/kotlin">
|
||||||
Kotlin
|
Kotlin
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
This is some
|
This is some
|
||||||
<b>
|
<b>
|
||||||
mixed
|
mixed
|
||||||
</b>
|
</b>
|
||||||
text. For more see the
|
text. For more see the
|
||||||
<a href="http://jetbrains.com/kotlin">
|
<a href="http://jetbrains.com/kotlin">
|
||||||
Kotlin
|
Kotlin
|
||||||
</a>
|
</a>
|
||||||
project
|
project
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
some text
|
some text
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Command line arguments were:
|
Command line arguments were:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
over9000
|
over9000
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
+288
-287
@@ -1,323 +1,324 @@
|
|||||||
Step: 1
|
Step: 1
|
||||||
***
|
***
|
||||||
Step: 2
|
Step: 2
|
||||||
*
|
*
|
||||||
Step: 3
|
Step: 3
|
||||||
|
|
||||||
Step: 1
|
Step: 1
|
||||||
|
|
||||||
*
|
*
|
||||||
***
|
***
|
||||||
*
|
*
|
||||||
|
|
||||||
Step: 2
|
Step: 2
|
||||||
|
|
||||||
***
|
***
|
||||||
* *
|
* *
|
||||||
***
|
***
|
||||||
|
|
||||||
Step: 3
|
Step: 3
|
||||||
*
|
*
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
*
|
*
|
||||||
Step: 4
|
Step: 4
|
||||||
*
|
*
|
||||||
***
|
***
|
||||||
** **
|
** **
|
||||||
***
|
***
|
||||||
*
|
*
|
||||||
Step: 5
|
Step: 5
|
||||||
***
|
***
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
***
|
***
|
||||||
Step: 6
|
Step: 6
|
||||||
***
|
***
|
||||||
* * *
|
* * *
|
||||||
*** **
|
*** **
|
||||||
* * *
|
* * *
|
||||||
***
|
***
|
||||||
Step: 7
|
Step: 7
|
||||||
***
|
***
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
***
|
***
|
||||||
Step: 8
|
Step: 8
|
||||||
**
|
**
|
||||||
* * *
|
* * *
|
||||||
*** **
|
*** **
|
||||||
* * *
|
* * *
|
||||||
**
|
**
|
||||||
Step: 9
|
Step: 9
|
||||||
***
|
***
|
||||||
* * *
|
* * *
|
||||||
* * *
|
* * *
|
||||||
* * *
|
* * *
|
||||||
***
|
***
|
||||||
Step: 10
|
Step: 10
|
||||||
***
|
***
|
||||||
* *
|
* *
|
||||||
** * *
|
** * *
|
||||||
* *
|
* *
|
||||||
***
|
***
|
||||||
Step: 1
|
Step: 1
|
||||||
|
|
||||||
*
|
*
|
||||||
* *
|
* *
|
||||||
*
|
*
|
||||||
|
|
||||||
Step: 2
|
Step: 2
|
||||||
|
|
||||||
*
|
*
|
||||||
* *
|
* *
|
||||||
*
|
*
|
||||||
|
|
||||||
Step: 3
|
Step: 3
|
||||||
|
|
||||||
*
|
*
|
||||||
* *
|
* *
|
||||||
*
|
*
|
||||||
|
|
||||||
Step: 1
|
Step: 1
|
||||||
|
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 2
|
Step: 2
|
||||||
|
|
||||||
**
|
**
|
||||||
* *
|
* *
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 3
|
Step: 3
|
||||||
|
|
||||||
**
|
**
|
||||||
* *
|
* *
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 1
|
Step: 1
|
||||||
|
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 2
|
Step: 2
|
||||||
|
|
||||||
**
|
**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 3
|
Step: 3
|
||||||
|
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 4
|
Step: 4
|
||||||
|
|
||||||
**
|
**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 5
|
Step: 5
|
||||||
|
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 6
|
Step: 6
|
||||||
|
|
||||||
**
|
**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
**
|
**
|
||||||
|
|
||||||
Step: 1
|
Step: 1
|
||||||
|
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
|
|
||||||
Step: 2
|
Step: 2
|
||||||
|
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
|
|
||||||
Step: 3
|
Step: 3
|
||||||
|
|
||||||
|
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
|
|
||||||
|
|
||||||
Step: 4
|
Step: 4
|
||||||
|
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
|
|
||||||
Step: 5
|
Step: 5
|
||||||
|
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
|
|
||||||
Step: 6
|
Step: 6
|
||||||
|
|
||||||
|
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
|
|
||||||
|
|
||||||
Step: 7
|
Step: 7
|
||||||
|
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
|
|
||||||
Step: 8
|
Step: 8
|
||||||
|
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
|
|
||||||
** **
|
** **
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
|
|
||||||
Step: 9
|
Step: 9
|
||||||
|
|
||||||
|
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
*** ** ** ***
|
*** ** ** ***
|
||||||
* * * * * *
|
* * * * * *
|
||||||
** **
|
** **
|
||||||
** **
|
** **
|
||||||
|
|
||||||
|
|
||||||
Step: 10
|
Step: 10
|
||||||
|
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
* * * *
|
* * * *
|
||||||
|
|
||||||
*** ***
|
*** ***
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user