mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm backend: make JUnit tests work
This commit is contained in:
parent
f532801f38
commit
b087610c2c
|
@ -242,7 +242,7 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
|
|||
return toLowerCaseSystem(codePoint);
|
||||
}
|
||||
|
||||
@Import(module = "runtime", name = "towlower")
|
||||
@Import(module = "teavm", name = "towlower")
|
||||
private static native int toLowerCaseSystem(int codePoint);
|
||||
|
||||
public static char toUpperCase(char ch) {
|
||||
|
@ -258,7 +258,7 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
|
|||
return toUpperCaseSystem(codePoint);
|
||||
}
|
||||
|
||||
@Import(module = "runtime", name = "towupper")
|
||||
@Import(module = "teavm", name = "towupper")
|
||||
private static native int toUpperCaseSystem(int codePoint);
|
||||
|
||||
public static int digit(char ch, int radix) {
|
||||
|
|
|
@ -32,6 +32,6 @@ class TConsoleOutputStreamStderr extends TOutputStream {
|
|||
writeImpl(b);
|
||||
}
|
||||
|
||||
@Import(name = "putwchar", module = "runtime")
|
||||
@Import(name = "putwchar", module = "teavm")
|
||||
static native void writeImpl(int b);
|
||||
}
|
||||
|
|
|
@ -222,15 +222,15 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
|
|||
}
|
||||
|
||||
@JSBody(params = "v", script = "return isNaN(v);")
|
||||
@Import(module = "runtime", name = "isnan")
|
||||
@Import(module = "teavm", name = "isnan")
|
||||
public static native boolean isNaN(double v);
|
||||
|
||||
@JSBody(script = "return NaN;")
|
||||
@Import(module = "runtime", name = "TeaVM_getNaN")
|
||||
@Import(module = "teavm", name = "TeaVM_getNaN")
|
||||
private static native double getNaN();
|
||||
|
||||
@JSBody(params = "v", script = "return !isFinite(v);")
|
||||
@Import(module = "runtime", name = "isinf")
|
||||
@Import(module = "teavm", name = "isinf")
|
||||
public static native boolean isInfinite(double v);
|
||||
|
||||
public static long doubleToRawLongBits(double value) {
|
||||
|
|
|
@ -90,7 +90,7 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
|
|||
}
|
||||
|
||||
@JSBody(params = "v", script = "return isNaN(v);")
|
||||
@Import(module = "runtime", name = "isnan")
|
||||
@Import(module = "teavm", name = "isnan")
|
||||
public static native boolean isNaN(float v);
|
||||
|
||||
public static boolean isInfinite(float v) {
|
||||
|
@ -98,11 +98,11 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
|
|||
}
|
||||
|
||||
@JSBody(params = "v", script = "return isFinite(v);")
|
||||
@Import(module = "runtime", name = "isfinite")
|
||||
@Import(module = "teavm", name = "isfinite")
|
||||
private static native boolean isFinite(float v);
|
||||
|
||||
@JSBody(script = "return NaN;")
|
||||
@Import(module = "runtime", name = "TeaVM_getNaN")
|
||||
@Import(module = "teavm", name = "TeaVM_getNaN")
|
||||
private static native float getNaN();
|
||||
|
||||
public static float parseFloat(TString string) throws TNumberFormatException {
|
||||
|
|
|
@ -26,27 +26,27 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "sin")
|
||||
@Import(module = "teavmMath", name = "sin")
|
||||
public static native double sin(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "cos")
|
||||
@Import(module = "teavmMath", name = "cos")
|
||||
public static native double cos(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "tan")
|
||||
@Import(module = "teavmMath", name = "tan")
|
||||
public static native double tan(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "asin")
|
||||
@Import(module = "teavmMath", name = "asin")
|
||||
public static native double asin(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "acos")
|
||||
@Import(module = "teavmMath", name = "acos")
|
||||
public static native double acos(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "atan")
|
||||
@Import(module = "teavmMath", name = "atan")
|
||||
public static native double atan(double a);
|
||||
|
||||
public static double toRadians(double angdeg) {
|
||||
|
@ -58,11 +58,11 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "exp")
|
||||
@Import(module = "teavmMath", name = "exp")
|
||||
public static native double exp(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "log")
|
||||
@Import(module = "teavmMath", name = "log")
|
||||
public static native double log(double a);
|
||||
|
||||
public static double log10(double a) {
|
||||
|
@ -70,7 +70,7 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "sqrt")
|
||||
@Import(module = "teavmMath", name = "sqrt")
|
||||
public static native double sqrt(double a);
|
||||
|
||||
public static double cbrt(double a) {
|
||||
|
@ -83,15 +83,15 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "ceil")
|
||||
@Import(module = "teavmMath", name = "ceil")
|
||||
public static native double ceil(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "floor")
|
||||
@Import(module = "teavmMath", name = "floor")
|
||||
public static native double floor(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "pow")
|
||||
@Import(module = "teavmMath", name = "pow")
|
||||
public static native double pow(double x, double y);
|
||||
|
||||
public static double rint(double a) {
|
||||
|
@ -99,7 +99,7 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "atan2")
|
||||
@Import(module = "teavmMath", name = "atan2")
|
||||
public static native double atan2(double y, double x);
|
||||
|
||||
public static int round(float a) {
|
||||
|
@ -111,7 +111,7 @@ public final class TMath extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "random")
|
||||
@Import(module = "teavmMath", name = "random")
|
||||
public static native double random();
|
||||
|
||||
public static int min(int a, int b) {
|
||||
|
|
|
@ -114,7 +114,7 @@ public final class TSystem extends TObject {
|
|||
}
|
||||
}
|
||||
|
||||
@Import(name = "currentTimeMillis", module = "runtime")
|
||||
@Import(name = "currentTimeMillis", module = "teavm")
|
||||
private static native double currentTimeMillisWasm();
|
||||
|
||||
@Import(name = "currentTimeMillis")
|
||||
|
|
|
@ -114,6 +114,6 @@ public class TRandom extends TObject implements TSerializable {
|
|||
}
|
||||
|
||||
@JSBody(script = "return Math.random();")
|
||||
@Import(module = "math", name = "random")
|
||||
@Import(module = "teavmMath", name = "random")
|
||||
private static native double random();
|
||||
}
|
||||
|
|
|
@ -73,9 +73,11 @@ public class WasmClassGenerator {
|
|||
DataPrimitives.ADDRESS, /* item type */
|
||||
DataPrimitives.ADDRESS, /* array type */
|
||||
DataPrimitives.INT, /* isInstance function */
|
||||
DataPrimitives.INT, /* init function */
|
||||
DataPrimitives.ADDRESS, /* parent */
|
||||
DataPrimitives.ADDRESS, /* enum values */
|
||||
DataPrimitives.ADDRESS /* layout */);
|
||||
DataPrimitives.ADDRESS, /* layout */
|
||||
DataPrimitives.ADDRESS /* simple name */);
|
||||
private IntegerArray staticGcRoots = new IntegerArray(1);
|
||||
private int staticGcRootsAddress;
|
||||
|
||||
|
@ -87,9 +89,11 @@ public class WasmClassGenerator {
|
|||
private static final int CLASS_ITEM_TYPE = 6;
|
||||
private static final int CLASS_ARRAY_TYPE = 7;
|
||||
private static final int CLASS_IS_INSTANCE = 8;
|
||||
private static final int CLASS_PARENT = 9;
|
||||
private static final int CLASS_ENUM_VALUES = 10;
|
||||
private static final int CLASS_LAYOUT = 11;
|
||||
private static final int CLASS_INIT = 9;
|
||||
private static final int CLASS_PARENT = 10;
|
||||
private static final int CLASS_ENUM_VALUES = 11;
|
||||
private static final int CLASS_LAYOUT = 12;
|
||||
private static final int CLASS_SIMPLE_NAME = 13;
|
||||
|
||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
||||
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
||||
|
@ -170,6 +174,8 @@ public class WasmClassGenerator {
|
|||
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
||||
functionTable.add(Mangling.mangleIsSupertype(type));
|
||||
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
binaryData.data.setInt(CLASS_INIT, -1);
|
||||
binaryData.start = binaryWriter.append(vtableSize > 0 ? wrapper : binaryData.data);
|
||||
|
||||
itemBinaryData.data.setAddress(CLASS_ARRAY_TYPE, binaryData.start);
|
||||
|
@ -181,6 +187,8 @@ public class WasmClassGenerator {
|
|||
value.setInt(CLASS_SIZE, size);
|
||||
value.setInt(CLASS_FLAGS, RuntimeClass.PRIMITIVE);
|
||||
value.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
value.setInt(CLASS_INIT, -1);
|
||||
functionTable.add(Mangling.mangleIsSupertype(type));
|
||||
return value;
|
||||
}
|
||||
|
@ -248,7 +256,16 @@ public class WasmClassGenerator {
|
|||
flags |= RuntimeClass.ENUM;
|
||||
}
|
||||
|
||||
if (cls != null && binaryData.start >= 0
|
||||
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null) {
|
||||
header.setInt(CLASS_INIT, functionTable.size());
|
||||
functionTable.add(Mangling.mangleInitializer(name));
|
||||
} else {
|
||||
header.setInt(CLASS_INIT, -1);
|
||||
}
|
||||
|
||||
header.setInt(CLASS_FLAGS, flags);
|
||||
header.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
|
||||
return vtable != null ? wrapper : header;
|
||||
}
|
||||
|
@ -500,7 +517,7 @@ public class WasmClassGenerator {
|
|||
}
|
||||
|
||||
public boolean hasClinit(String className) {
|
||||
if (isStructure(className)) {
|
||||
if (isStructure(className) || className.equals(Address.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
ClassReader cls = classSource.get(className);
|
||||
|
|
|
@ -35,6 +35,7 @@ public class PlatformIntrinsic implements WasmIntrinsic {
|
|||
case "getPlatformObject":
|
||||
case "asJavaClass":
|
||||
case "getName":
|
||||
case "createQueue":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -48,6 +49,7 @@ public class PlatformIntrinsic implements WasmIntrinsic {
|
|||
case "asJavaClass":
|
||||
return manager.generate(invocation.getArguments().get(0));
|
||||
case "getName":
|
||||
case "createQueue":
|
||||
return new WasmInt32Constant(0);
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2018 Alexey Andreev.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
var TeaVM = TeaVM || {};
|
||||
TeaVM.wasm = function() {
|
||||
let lineBuffer = "";
|
||||
function putwchar(charCode) {
|
||||
if (charCode === 10) {
|
||||
console.log(lineBuffer);
|
||||
lineBuffer = "";
|
||||
} else {
|
||||
lineBuffer += String.fromCharCode(charCode);
|
||||
}
|
||||
}
|
||||
function towlower(code) {
|
||||
return String.fromCharCode(code).toLowerCase().charCodeAt(0);
|
||||
}
|
||||
function towupper(code) {
|
||||
return String.fromCharCode(code).toUpperCase().charCodeAt(0);
|
||||
}
|
||||
function currentTimeMillis() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
||||
function importDefaults(obj) {
|
||||
obj.teavm = {
|
||||
currentTimeMillis: currentTimeMillis,
|
||||
isnan: isNaN,
|
||||
TeaVM_getNaN: function() { return NaN; },
|
||||
isinf: function(n) { return !isFinite(n) },
|
||||
isfinite: isFinite,
|
||||
putwchar: putwchar,
|
||||
towlower: towlower,
|
||||
towupper: towupper
|
||||
};
|
||||
|
||||
obj.teavmMath = Math;
|
||||
}
|
||||
|
||||
function run(path, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
let callback = typeof options.callback !== "undefined" ? options.callback : function() {};
|
||||
let errorCallback = typeof options.errorCallback !== "undefined" ? options.errorCallback : function() {};
|
||||
|
||||
let importObj = {};
|
||||
importDefaults(importObj);
|
||||
if (typeof options.installImports !== "undefined") {
|
||||
options.installImports(importObj);
|
||||
}
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.open("GET", path);
|
||||
|
||||
xhr.onload = function() {
|
||||
let response = xhr.response;
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebAssembly.instantiate(response, importObj).then(function(resultObject) {
|
||||
resultObject.instance.exports.main();
|
||||
callback(resultObject);
|
||||
}).catch(function(error) {
|
||||
console.log("Error loading WebAssembly %o", error);
|
||||
errorCallback(error);
|
||||
});
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
return { importDefaults: importDefaults, run: run };
|
||||
}();
|
|
@ -18,26 +18,39 @@
|
|||
|
||||
window.addEventListener("message", event => {
|
||||
let request = event.data;
|
||||
appendFiles(request.files, 0, () => {
|
||||
launchTest(response => {
|
||||
event.source.postMessage(response, "*");
|
||||
});
|
||||
}, error => {
|
||||
event.source.postMessage({ status: "failed", errorMessage: error }, "*");
|
||||
});
|
||||
switch (request.type) {
|
||||
case "js":
|
||||
appendFiles(request.files, 0, () => {
|
||||
launchTest(response => {
|
||||
event.source.postMessage(response, "*");
|
||||
});
|
||||
}, error => {
|
||||
event.source.postMessage({ status: "failed", errorMessage: error }, "*");
|
||||
});
|
||||
break;
|
||||
case "wasm":
|
||||
appendFiles(request.files.filter(f => f.endsWith(".js")), 0, () => {
|
||||
launchWasmTest(request.files.filter(f => f.endsWith(".wasm"))[0], response => {
|
||||
event.source.postMessage(response, "*");
|
||||
});
|
||||
}, error => {
|
||||
event.source.postMessage({ status: "failed", errorMessage: error }, "*");
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function appendFiles(files, index, callback, errorCallback) {
|
||||
if (index === files.length) {
|
||||
callback();
|
||||
} else {
|
||||
let fileName = "file://" + files[index];
|
||||
let fileName = files[index];
|
||||
let script = document.createElement("script");
|
||||
script.onload = () => {
|
||||
appendFiles(files, index + 1, callback, errorCallback);
|
||||
};
|
||||
script.onerror = () => {
|
||||
errorCallback("failed to load script" + fileName);
|
||||
errorCallback("failed to load script " + fileName);
|
||||
};
|
||||
script.src = fileName;
|
||||
document.body.appendChild(script);
|
||||
|
@ -81,6 +94,44 @@ function launchTest(callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function launchWasmTest(path, callback) {
|
||||
var output = [];
|
||||
var outputBuffer = "";
|
||||
|
||||
function putwchar(charCode) {
|
||||
if (charCode === 10) {
|
||||
switch (outputBuffer) {
|
||||
case "SUCCESS":
|
||||
callback({status: "OK"});
|
||||
break;
|
||||
case "FAILED":
|
||||
callback({
|
||||
status: "failed",
|
||||
errorMessage: output.join("\n")
|
||||
});
|
||||
break;
|
||||
default:
|
||||
output.push(TeaVM_outputBuffer);
|
||||
outputBuffer = "";
|
||||
}
|
||||
} else {
|
||||
outputBuffer += String.fromCharCode(charCode);
|
||||
}
|
||||
}
|
||||
|
||||
TeaVM.wasm.run(path, {
|
||||
installImports: function(o) {
|
||||
o.teavm.putwchar = putwchar;
|
||||
},
|
||||
errorCallback: function(err) {
|
||||
callback({
|
||||
status: "failed",
|
||||
errorMessage: err.message + '\n' + err.stack
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function start() {
|
||||
window.parent.postMessage("ready", "*");
|
||||
}
|
|
@ -16,17 +16,20 @@
|
|||
|
||||
"use strict";
|
||||
import * as fs from "./promise-fs.js";
|
||||
import * as nodePath from "path";
|
||||
import * as http from "http";
|
||||
import {server as WebSocketServer} from "websocket";
|
||||
|
||||
const TEST_FILE_NAME = "test.js";
|
||||
const RUNTIME_FILE_NAME = "runtime.js";
|
||||
const WASM_RUNTIME_FILE_NAME = "test.wasm-runtime.js";
|
||||
const TEST_FILES = [
|
||||
{ file: TEST_FILE_NAME, name: "simple" },
|
||||
{ file: "test-min.js", name: "minified" },
|
||||
{ file: "test-optimized.js", name: "optimized" }
|
||||
{ file: TEST_FILE_NAME, name: "simple", type: "js" },
|
||||
{ file: "test-min.js", name: "minified", type: "js" },
|
||||
{ file: "test-optimized.js", name: "optimized", type: "js" },
|
||||
{ file: "test.wasm", name: "wasm", type: "wasm" },
|
||||
{ file: "test-optimized.wasm", name: "wasm-optimized", type: "wasm" }
|
||||
];
|
||||
const SERVER_PREFIX = "http://localhost:9090/";
|
||||
let totalTests = 0;
|
||||
|
||||
class TestSuite {
|
||||
|
@ -37,20 +40,30 @@ class TestSuite {
|
|||
}
|
||||
}
|
||||
class TestCase {
|
||||
constructor(name, files) {
|
||||
constructor(type, name, files) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.files = files;
|
||||
}
|
||||
}
|
||||
|
||||
let rootDir = process.argv[2];
|
||||
if (rootDir.endsWith("/")) {
|
||||
rootDir = rootDir.substring(0, rootDir.length - 1);
|
||||
}
|
||||
|
||||
async function runAll() {
|
||||
const rootSuite = new TestSuite("root");
|
||||
console.log("Searching tests");
|
||||
await walkDir(process.argv[2], "root", rootSuite);
|
||||
await walkDir("", "root", rootSuite);
|
||||
|
||||
console.log("Running tests");
|
||||
|
||||
const server = http.createServer((request, response) => {
|
||||
if (request.url.endsWith(".js") || request.url.endsWith(".wasm")) {
|
||||
serveFile(rootDir + "/" + request.url, response);
|
||||
return;
|
||||
}
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
});
|
||||
|
@ -94,14 +107,37 @@ async function runAll() {
|
|||
}
|
||||
}
|
||||
|
||||
async function serveFile(path, response) {
|
||||
const stat = await fs.stat(path);
|
||||
const contentType = path.endsWith(".wasm") ? "application/octet-stream" : "text/javascript";
|
||||
if (stat.isFile()) {
|
||||
const content = await fs.readFile(path);
|
||||
response.writeHead(200, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': "*" });
|
||||
response.end(content, 'utf-8');
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
|
||||
async function walkDir(path, name, suite) {
|
||||
const files = await fs.readdir(path);
|
||||
if (files.includes(TEST_FILE_NAME) && files.includes(RUNTIME_FILE_NAME)) {
|
||||
for (const { file: fileName, name: profileName } of TEST_FILES) {
|
||||
const files = await fs.readdir(rootDir + "/" + path);
|
||||
if (files.includes(WASM_RUNTIME_FILE_NAME) || files.includes(RUNTIME_FILE_NAME)) {
|
||||
for (const { file: fileName, name: profileName, type: type } of TEST_FILES) {
|
||||
if (files.includes(fileName)) {
|
||||
suite.testCases.push(new TestCase(
|
||||
name + " " + profileName,
|
||||
[path + "/" + RUNTIME_FILE_NAME, path + "/" + fileName]));
|
||||
switch (type) {
|
||||
case "js":
|
||||
suite.testCases.push(new TestCase(
|
||||
"js", name + " " + profileName,
|
||||
[SERVER_PREFIX + path + "/" + RUNTIME_FILE_NAME, SERVER_PREFIX + path + "/" + fileName]));
|
||||
break;
|
||||
case "wasm":
|
||||
suite.testCases.push(new TestCase(
|
||||
"wasm", name + " " + profileName,
|
||||
[SERVER_PREFIX + path + "/" + WASM_RUNTIME_FILE_NAME,
|
||||
SERVER_PREFIX + path + "/" + fileName]));
|
||||
break;
|
||||
}
|
||||
totalTests++;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +146,7 @@ async function walkDir(path, name, suite) {
|
|||
suite.testSuites.push(childSuite);
|
||||
await Promise.all(files.map(async file => {
|
||||
const filePath = path + "/" + file;
|
||||
const stat = await fs.stat(filePath);
|
||||
const stat = await fs.stat(rootDir + "/" + filePath);
|
||||
if (stat.isDirectory()) {
|
||||
await walkDir(filePath, file, childSuite);
|
||||
}
|
||||
|
@ -148,8 +184,9 @@ class TestRunner {
|
|||
let request = { id: this.requestIdGen++ };
|
||||
request.tests = suite.testCases.map(testCase => {
|
||||
return {
|
||||
type: testCase.type,
|
||||
name: testCase.name,
|
||||
files: testCase.files.map(fileName => nodePath.resolve(process.cwd(), fileName))
|
||||
files: testCase.files
|
||||
};
|
||||
});
|
||||
this.testsRun += suite.testCases.length;
|
||||
|
|
|
@ -17,5 +17,6 @@ package org.teavm.junit;
|
|||
|
||||
enum RunKind {
|
||||
JAVASCRIPT,
|
||||
C
|
||||
C,
|
||||
WASM
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.junit;
|
|||
|
||||
import org.teavm.backend.c.CTarget;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.backend.wasm.WasmTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMOptimizationLevel;
|
||||
import org.teavm.vm.TeaVMTarget;
|
||||
|
@ -79,6 +80,40 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
|
|||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration<WasmTarget> WASM_DEFAULT = new TeaVMTestConfiguration<WasmTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(TeaVM vm) {
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(WasmTarget target) {
|
||||
target.setMinHeapSize(32 * 1024 * 1024);
|
||||
target.setWastEmitted(true);
|
||||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration<WasmTarget> WASM_OPTIMIZED = new TeaVMTestConfiguration<WasmTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "optimized";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(TeaVM vm) {
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(WasmTarget target) {
|
||||
}
|
||||
};
|
||||
|
||||
TeaVMTestConfiguration<CTarget> C_DEFAULT = new TeaVMTestConfiguration<CTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
|
@ -95,11 +130,10 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
TeaVMTestConfiguration<CTarget> C_OPTIMIZED = new TeaVMTestConfiguration<CTarget>() {
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
return "";
|
||||
return "optimized";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.junit.runner.notification.RunNotifier;
|
|||
import org.junit.runners.model.InitializationError;
|
||||
import org.teavm.backend.c.CTarget;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.backend.wasm.WasmTarget;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.DefaultProblemTextConsumer;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
|
@ -78,7 +79,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
private static final String SELENIUM_URL = "teavm.junit.js.selenium.url";
|
||||
private static final String JS_ENABLED = "teavm.junit.js";
|
||||
private static final String C_ENABLED = "teavm.junit.c";
|
||||
private static final String C_COMPILER = "teavm.junit.c-compiler";
|
||||
private static final String WASM_ENABLED = "teavm.junit.wasm";
|
||||
private static final String C_COMPILER = "teavm.junit.c.compiler";
|
||||
private static final String MINIFIED = "teavm.junit.minified";
|
||||
private static final String OPTIMIZED = "teavm.junit.optimized";
|
||||
|
||||
|
@ -275,6 +277,15 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
runs.add(run);
|
||||
}
|
||||
}
|
||||
|
||||
for (TeaVMTestConfiguration<WasmTarget> configuration : getWasmConfigurations()) {
|
||||
TestRun run = compile(child, notifier, RunKind.WASM,
|
||||
m -> compileToWasm(m, configuration, outputPath), onSuccess.get(0));
|
||||
if (run != null) {
|
||||
runs.add(run);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
notifier.fireTestFinished(description);
|
||||
|
@ -414,7 +425,9 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
|
||||
private void copyJsFilesTo(File path) throws IOException {
|
||||
resourceToFile("org/teavm/backend/javascript/runtime.js", new File(path, "runtime.js"));
|
||||
resourceToFile("org/teavm/backend/wasm/wasm-runtime.js", new File(path, "test.wasm-runtime.js"));
|
||||
resourceToFile("teavm-run-test.html", new File(path, "run-test.html"));
|
||||
resourceToFile("teavm-run-test-wasm.html", new File(path, "run-test-wasm.html"));
|
||||
}
|
||||
|
||||
private CompileResult compileToJs(Method method, TeaVMTestConfiguration<JavaScriptTarget> configuration,
|
||||
|
@ -434,6 +447,13 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}, path, ".c");
|
||||
}
|
||||
|
||||
private CompileResult compileToWasm(Method method, TeaVMTestConfiguration<WasmTarget> configuration,
|
||||
File path) {
|
||||
return compileTest(method, configuration, WasmTarget::new, vm -> {
|
||||
vm.entryPoint("main", new MethodReference(TestEntryPoint.class, "main", String[].class, void.class));
|
||||
}, path, ".wasm");
|
||||
}
|
||||
|
||||
private <T extends TeaVMTarget> CompileResult compileTest(Method method, TeaVMTestConfiguration<T> configuration,
|
||||
Supplier<T> targetSupplier, Consumer<TeaVM> preBuild, File path, String extension) {
|
||||
CompileResult result = new CompileResult();
|
||||
|
@ -497,6 +517,17 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
return configurations;
|
||||
}
|
||||
|
||||
private List<TeaVMTestConfiguration<WasmTarget>> getWasmConfigurations() {
|
||||
List<TeaVMTestConfiguration<WasmTarget>> configurations = new ArrayList<>();
|
||||
if (Boolean.getBoolean(WASM_ENABLED)) {
|
||||
configurations.add(TeaVMTestConfiguration.WASM_DEFAULT);
|
||||
if (Boolean.getBoolean(OPTIMIZED)) {
|
||||
configurations.add(TeaVMTestConfiguration.WASM_OPTIMIZED);
|
||||
}
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
|
||||
private List<TeaVMTestConfiguration<CTarget>> getCConfigurations() {
|
||||
List<TeaVMTestConfiguration<CTarget>> configurations = new ArrayList<>();
|
||||
if (Boolean.getBoolean(C_ENABLED)) {
|
||||
|
|
|
@ -39,6 +39,7 @@ final class TestEntryPoint {
|
|||
System.out.println("SUCCESS");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace(System.out);
|
||||
System.out.println("FAILURE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
29
tools/junit/src/main/resources/teavm-run-test-wasm.html
Normal file
29
tools/junit/src/main/resources/teavm-run-test-wasm.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
~ Copyright 2018 Alexey Andreev.
|
||||
~
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>TeaVM JUnit test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="test.wasm-runtime.js"></script>
|
||||
<script type="text/javascript">
|
||||
TeaVM.wasm.run("test.wasm");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user