/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.api.dsl.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
/**
* Utility class to provide some test helper functions.
*/
class TestHelper {
// make nodes replacable
public static <T extends Node> T createRoot(final T node) {
new RootNode(null) {
@Child T child = node;
@Override
public Object execute(VirtualFrame frame) {
return null;
}
}.adoptChildren();
return node;
}
private static ArgumentNode[] arguments(int count) {
ArgumentNode[] nodes = new ArgumentNode[count];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new ArgumentNode(i);
}
return nodes;
}
static <E extends ValueNode> E createNode(NodeFactory<E> factory, boolean prefixConstants, Object... constants) {
ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size());
List<Object> argumentList = new ArrayList<>();
if (prefixConstants) {
argumentList.addAll(Arrays.asList(constants));
}
if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass())) {
argumentList.add(argumentNodes);
} else {
argumentList.addAll(Arrays.asList(argumentNodes));
}
if (!prefixConstants) {
argumentList.addAll(Arrays.asList(constants));
}
return factory.createNode(argumentList.toArray(new Object[argumentList.size()]));
}
static <E extends ValueNode> TestRootNode<E> createRoot(NodeFactory<E> factory, Object... constants) {
TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, false, constants));
rootNode.adoptChildren();
return rootNode;
}
static <E extends ValueNode> TestRootNode<E> createRootPrefix(NodeFactory<E> factory, boolean prefixConstants, Object... constants) {
TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, prefixConstants, constants));
rootNode.adoptChildren();
return rootNode;
}
static CallTarget createCallTarget(ValueNode node) {
return createCallTarget(new TestRootNode<>(node));
}
static CallTarget createCallTarget(TestRootNode<? extends ValueNode> node) {
return Truffle.getRuntime().createCallTarget(node);
}
static RootCallTarget createCallTarget(NodeFactory<? extends ValueNode> factory, Object... constants) {
return Truffle.getRuntime().createCallTarget(createRoot(factory, constants));
}
static boolean assertionsEnabled() {
boolean assertOn = false;
// *assigns* true if assertions are on.
assert (assertOn = true) == true;
return assertOn;
}
@SuppressWarnings("unchecked")
static <T extends ValueNode> T getNode(CallTarget target) {
return ((TestRootNode<T>) ((RootCallTarget) target).getRootNode()).getNode();
}
static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
return node.execute(Truffle.getRuntime().createVirtualFrame(values, node.getFrameDescriptor()));
}
static Object[] array(Object... val) {
return val;
}
static <E> List<List<E>> permutations(List<E> list) {
return permutations(new ArrayList<E>(), list, new ArrayList<List<E>>());
}
static Object[][] permutations(Object... list) {
List<List<Object>> permutations = permutations(Arrays.asList(list));
Object[][] a = new Object[permutations.size()][];
int index = 0;
for (List<Object> p : permutations) {
a[index] = p.toArray(new Object[p.size()]);
index++;
}
return a;
}
static <E> List<List<E>> permutations(List<E> prefix, List<E> suffix, List<List<E>> output) {
if (suffix.size() == 1) {
ArrayList<E> newElement = new ArrayList<>(prefix);
newElement.addAll(suffix);
output.add(newElement);
return output;
}
for (int i = 0; i < suffix.size(); i++) {
List<E> newPrefix = new ArrayList<>(prefix);
newPrefix.add(suffix.get(i));
List<E> newSuffix = new ArrayList<>(suffix);
newSuffix.remove(i);
permutations(newPrefix, newSuffix, output);
}
return output;
}
static void assertRuns(NodeFactory<? extends ValueNode> factory, Object[] testValues, Object[] result) {
assertRuns(factory, testValues, result, null);
}
/* Methods tests all test values in combinational order. */
static void assertRuns(NodeFactory<? extends ValueNode> factory, Object[] testValues, Object[] result, ExecutionListener listener) {
// test each run by its own.
for (int i = 0; i < testValues.length; i++) {
assertValue(createRoot(factory), 0, testValues[i], result[i], listener, true);
}
// test all combinations of the test values
List<Object> testValuesList = Arrays.asList(testValues);
List<List<Object>> permuts = permutations(testValuesList);
for (List<Object> list : permuts) {
TestRootNode<?> root = createRoot(factory);
int index = 0;
for (Object object : list) {
assertValue(root, index, object, result[testValuesList.indexOf(object)], listener, index == list.size() - 1);
index++;
}
}
}
static void assertValue(TestRootNode<? extends ValueNode> root, int index, Object value, Object result, ExecutionListener listener, boolean last) {
Object actualResult = null;
if (result instanceof Class && Throwable.class.isAssignableFrom((Class<?>) result)) {
try {
if (value instanceof Object[]) {
actualResult = executeWith(root, (Object[]) value);
} else {
actualResult = executeWith(root, value);
}
fail(String.format("Exception %s expected but not occured.", result.getClass()));
} catch (Throwable e) {
actualResult = e;
if (!e.getClass().isAssignableFrom(((Class<?>) result))) {
e.printStackTrace();
fail(String.format("Incompatible exception class thrown. Expected %s but was %s.", result.toString(), e.getClass()));
}
}
} else if (value instanceof Object[]) {
actualResult = executeWith(root, (Object[]) value);
assertEquals(result, actualResult);
} else {
actualResult = executeWith(root, value);
assertEquals(result, actualResult);
}
if (listener != null) {
listener.afterExecution(root, index, value, result, actualResult, last);
}
}
public static final class LogListener implements ExecutionListener {
public void afterExecution(TestRootNode<? extends ValueNode> node, int index, Object value, Object expectedResult, Object actualResult, boolean last) {
System.out.printf("Run %3d Node:%-20s Parameters: %10s Expected: %10s Result %10s%n", index, node.getNode().getClass().getSimpleName(), value, expectedResult, actualResult);
}
}
interface ExecutionListener {
void afterExecution(TestRootNode<? extends ValueNode> node, int index, Object value, Object expectedResult, Object actualResult, boolean last);
}
}