package joinery.js;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import joinery.DataFrame;
import joinery.impl.Shell;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;
import org.mozilla.javascript.WrappedException;
public class JavascriptExpressionSuite
extends Suite {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface JavascriptResource {
public String name();
}
private static List<Runner> runnersFromJs(final Class<?> cls)
throws InitializationError, IOException {
final JavascriptResource js = cls.getAnnotation(JavascriptResource.class);
final List<Runner> runners = new LinkedList<>();
try (final LineNumberReader reader = new LineNumberReader(
new InputStreamReader(ClassLoader.getSystemResourceAsStream(js.name())))) {
while (true) {
final String expr = reader.readLine();
final int line = reader.getLineNumber();
if (expr == null) {
break;
}
if (!expr.trim().isEmpty() && !expr.trim().startsWith("//")) {
runners.add(new Runner() {
@Override
public Description getDescription() {
final String[] parts = expr.split(" *; *");
final String desc = parts[parts.length - 1];
return Description.createTestDescription(cls,
String.format("%s:%s => %s", js.name(), line, desc), js);
}
@Override
public void run(final RunNotifier notifier) {
notifier.fireTestStarted(getDescription());
// should really do something more generic here
// instead of hard-coded setup, explicit
// data frame construction...
System.setIn(new ByteArrayInputStream(
String.format("tmp = frames[0]; df = frames[1]; %s;", expr).getBytes()));
try {
final DataFrame<Object> df = DataFrame.readCsv(ClassLoader.getSystemResourceAsStream("grouping.csv"));
final Object result = Shell.repl(Arrays.asList(new DataFrame<>(), df));
if (result instanceof WrappedException) {
throw WrappedException.class.cast(result).getWrappedException();
} else if (result instanceof Throwable) {
throw Throwable.class.cast(result);
}
org.junit.Assert.assertFalse(result == null);
} catch (final IOException ioe) {
notifier.fireTestAssumptionFailed(new Failure(getDescription(), ioe));
} catch (final AssertionError err) {
notifier.fireTestFailure(new Failure(getDescription(), err));
} catch (final Throwable ex) {
notifier.fireTestFailure(new Failure(getDescription(), ex));
} finally {
notifier.fireTestFinished(getDescription());
}
}
});
}
}
}
return runners;
}
public JavascriptExpressionSuite(final Class<?> cls, final RunnerBuilder builder)
throws InitializationError, IOException {
super(cls, runnersFromJs(cls));
}
}