Add junit rule for testing with node.

This commit is contained in:
Volker Berlin 2017-04-02 22:26:53 +02:00
parent ffafeea189
commit 18841cf83d
2 changed files with 186 additions and 0 deletions

View File

@ -0,0 +1,163 @@
/*
* Copyright 2017 Volker Berlin (i-net software)
*
* 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 de.inetsoftware.jwebassembly;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import org.junit.rules.TemporaryFolder;
/**
* A Junit Rule that compile the given classes and compare the results from node and Java.
*
* @author Volker Berlin
*/
public class WasmNodeRule extends TemporaryFolder {
private final Class<?>[] classes;
private File wasmFile;
private File scriptFile;
/**
* Compile the given classes to a Wasm and save it to a file.
*
* @param classes
* list of classes to compile
*/
public WasmNodeRule( Class<?>... classes ) {
if( classes == null || classes.length == 0 ) {
throw new IllegalArgumentException( "You need to set minimum one test class" );
}
this.classes = classes;
}
/**
* {@inheritDoc}
*/
@Override
protected void before() throws Throwable {
super.before();
try {
wasmFile = newFile( "test.wasm" );
JWebAssembly wasm = new JWebAssembly();
for( Class<?> clazz : classes ) {
URL url = clazz.getResource( '/' + clazz.getName().replace( '.', '/' ) + ".class" );
wasm.addFile( url );
}
wasm.compileToBinary( wasmFile );
scriptFile = newFile( "test.js" );
URL scriptUrl = getClass().getResource( "nodetest.js" );
String expected = readStream( scriptUrl.openStream() );
expected = expected.replace( "{test.wasm}", wasmFile.getAbsolutePath().replace( '\\', '/' ) );
try (FileOutputStream scriptStream = new FileOutputStream( scriptFile )) {
scriptStream.write( expected.getBytes( StandardCharsets.UTF_8 ) );
}
} catch( Exception ex ) {
throwException( ex );
}
}
/**
* Run a test single test. It run the method in Java and call it via node in the WenAssembly. If the result are
* different it fire an error.
*
* @param methodName
* the method name of the test.
* @param params
* the parameters for the method
*/
public void test( String methodName, Object... params ) {
try {
Class<?>[] types = new Class[params.length];
for( int i = 0; i < types.length; i++ ) {
Class<?> type = params[i].getClass();
switch( type.getName() ) {
case "java.lang.Integer":
type = int.class;
break;
}
types[i] = type;
}
Method method = null;
for( int i = 0; i < classes.length; i++ ) {
try {
Class<?> clazz = classes[i];
method = clazz.getDeclaredMethod( methodName, types );
} catch( NoSuchMethodException ex ) {
if( i == classes.length - 1 ) {
throw ex;
}
}
}
method.setAccessible( true );
Object expected = method.invoke( null, params );
String command = System.getProperty( "node.dir" );
command = command == null ? "node" : command + "/node";
ProcessBuilder processBuilder =
new ProcessBuilder( command, scriptFile.getAbsolutePath(), methodName );
for( int i = 0; i < params.length; i++ ) {
processBuilder.command().add( String.valueOf( params[i] ) );
}
Process process = processBuilder.start();
int exitCode = process.waitFor();
String result = readStream( process.getInputStream() );
if( exitCode != 0 ) {
String errorMessage = readStream( process.getErrorStream() );
assertEquals( errorMessage, 0, exitCode );
}
assertEquals( String.valueOf( expected ), result );
} catch( Exception ex ) {
throwException( ex );
}
}
/**
* Reads a stream into a String.
*
* @param input
* the InputStream
* @return the string
*/
public static String readStream( InputStream input ) {
try (Scanner scanner = new Scanner( input ).useDelimiter( "\\A" ) ) {
return scanner.hasNext() ? scanner.next() : "";
}
}
/**
* Throw any exception independent of signatures
*
* @param exception
* the exception
* @throws T
* a generic helper
*/
public static <T extends Throwable> void throwException( Throwable exception ) throws T {
throw (T)exception;
}
}

View File

@ -0,0 +1,23 @@
#!/usr/bin/env node
var nodeFS = require('fs');
var filename = '{test.wasm}';
var ret = nodeFS['readFileSync'](filename);
function instantiate(bytes, imports) {
return WebAssembly.compile(bytes).then(
m => new WebAssembly.Instance(m, imports), reason => console.log(reason) );
}
var dependencies = {
"global": {},
"env": {}
};
dependencies["global.Math"] = Math;
instantiate( ret, dependencies ).then(
instance => console.log( instance.exports[process.argv[2]]( process.argv.slice(3) ) ),
reason => console.log(reason)
);