/* * Copyright 2015 S. Webber * * 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.oakgp.node; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.oakgp.Arguments.createArguments; import static org.oakgp.Assignments.createAssignments; import static org.oakgp.TestUtils.createVariable; import static org.oakgp.TestUtils.integerConstant; import static org.oakgp.TestUtils.readNode; import static org.oakgp.Type.integerType; import static org.oakgp.function.math.IntegerUtils.INTEGER_UTILS; import org.junit.Test; import org.oakgp.Arguments; import org.oakgp.Assignments; import org.oakgp.function.Function; import org.oakgp.function.Signature; public class FunctionNodeTest { @Test public void testConstructors() { Function function = INTEGER_UTILS.getMultiply(); ConstantNode arg1 = integerConstant(42); VariableNode arg2 = createVariable(0); // construct using Node array FunctionNode n1 = new FunctionNode(function, arg1, arg2); // Construct using Arguments Arguments arguments = createArguments(arg1, arg2); FunctionNode n2 = new FunctionNode(function, arguments); // assert the result is the same assertEquals(n1, n2); } @Test public void testEvaluate() { Function function = INTEGER_UTILS.getMultiply(); Arguments arguments = createArguments(integerConstant(42), createVariable(0)); FunctionNode functionNode = new FunctionNode(function, arguments); assertSame(function, functionNode.getFunction()); assertSame(arguments, functionNode.getArguments()); Assignments assignments = createAssignments(3); assertEquals(126, functionNode.evaluate(assignments)); } @Test public void testCountAndHeight() { assertCountAndHeight("(* 7 7)", 3, 2); assertCountAndHeight("(* (+ 8 9) 7)", 5, 3); assertCountAndHeight("(* 7 (+ 8 9))", 5, 3); assertCountAndHeight("(zero? (+ (* 4 5) (- 6 (+ 7 8))))", 10, 5); assertCountAndHeight("(zero? (+ (- 6 (+ 7 8)) (* 4 5)))", 10, 5); assertCountAndHeight("(if (zero? v0) v1 v2)", 5, 3); assertCountAndHeight("(if (zero? v0) v1 (+ v0 (* v1 v2)))", 9, 4); assertCountAndHeight("(if (zero? v0) (+ v0 (* v1 v2)) v1)", 9, 4); } private void assertCountAndHeight(String expression, int nodeCount, int height) { Node n = readNode(expression); assertEquals(nodeCount, n.getNodeCount()); assertEquals(height, n.getHeight()); } @Test public void testGetType() { FunctionNode n = createFunctionNode(); assertSame(integerType(), n.getType()); } @Test public void testEqualsAndHashCode1() { final FunctionNode n1 = createFunctionNode(); final FunctionNode n2 = createFunctionNode(); assertNotSame(n1, n2); // just to sanity check createFunctionNode() doesn't return cached versions assertEquals(n1, n1); assertEquals(n1.hashCode(), n2.hashCode()); assertEquals(n1, n2); assertEquals(n2, n1); } @Test public void testEqualsAndHashCode2() { Node n1 = readNode("(* 288 v1)"); Node n2 = readNode("(* 288 v1)"); assertNotSame(n1, n2); // just to sanity check readNode doesn't return cached versions assertEquals(n1, n1); assertEquals(n1, n2); assertEquals(n2, n1); assertEquals(n1.hashCode(), n2.hashCode()); } @Test public void testNotEquals() { Function add = INTEGER_UTILS.getAdd(); final FunctionNode n = new FunctionNode(add, createVariable(0), integerConstant(7)); // verify (sanity-check) that equals will return true when it should assertEquals(n, new FunctionNode(add, createVariable(0), integerConstant(7))); // test different function Function multiply = INTEGER_UTILS.getMultiply(); assertNotEquals(n, new FunctionNode(multiply, createVariable(0), integerConstant(7))); // test different first argument assertNotEquals(n, new FunctionNode(add, createVariable(1), integerConstant(7))); // test different second argument assertNotEquals(n, new FunctionNode(add, createVariable(0), integerConstant(6))); // test same arguments but different order assertNotEquals(n, new FunctionNode(add, integerConstant(7), createVariable(0))); // test wrong arguments but different order assertNotEquals(n, new FunctionNode(add, integerConstant(0), createVariable(7))); // test extra argument assertNotEquals(n, new FunctionNode(add, createVariable(0), integerConstant(7), integerConstant(7))); // test one less argument assertNotEquals(n, new FunctionNode(add, createVariable(0))); // test no arguments assertNotEquals(n, new FunctionNode(add)); // test not equal to other Node implementations assertNotEquals(n, integerConstant(7)); // test not equal to other non-Node instances assertNotEquals(n, new Object()); assertFalse(n.equals(null)); } /** * Tests that for two {@code FunctionNode} instances to be considered equal they must share the same instance of {@code Function} (i.e. it is not enough for * them to have separate instances of the same {@code Function} class). */ @Test public void testEqualityRequiresSameFunctionInstance() { class DummyFunction implements Function { @Override public Object evaluate(Arguments arguments, Assignments assignments) { throw new UnsupportedOperationException(); } @Override public Signature getSignature() { throw new UnsupportedOperationException(); } } Function f1 = new DummyFunction(); Function f2 = new DummyFunction(); Arguments arguments = Arguments.createArguments(integerConstant(1)); FunctionNode fn1 = new FunctionNode(f1, arguments); FunctionNode fn2 = new FunctionNode(f2, arguments); assertSame(f1.getClass(), f2.getClass()); assertNotEquals(fn1, fn2); } @Test public void testHashCode() { // In Java the following results in two lists that have the same hashCode (even though they are different); // List a = new ArrayList(); // a.add(Arrays.asList(9, 1)); // a.add(Arrays.asList(2, 9)); // // List b = new ArrayList(); // b.add(Arrays.asList(9, 2)); // b.add(Arrays.asList(1, 9)); // // assertEquals(a.hashCode(), b.hashCode()); // This is also true of Clojure's PersistentVector: // user=> (def x [[9 1] [2 9]]) // #'user/x // user=> (def y [[9 2] [1 9]]) // #'user/y // user=> (.hashCode x) // 40464 // user=> (.hashCode y) // 40464 // test that result of reading the following expressions is nodes with different hash codes: Node n1 = readNode("(- (- (* -1 v3) 0) (- 13 v1))"); Node n2 = readNode("(- (- (* -1 v3) 13) (- 0 v1))"); assertNotEquals(n1.hashCode(), n2.hashCode()); } @Test public void testLargeNumberOfArguments() { Node[] args = new Node[1000]; for (int i = 0; i < args.length; i++) { args[i] = integerConstant(i); } FunctionNode n = new FunctionNode(mock(Function.class), args); assertEquals(args.length, n.getArguments().getArgCount()); for (int i = 0; i < args.length; i++) { assertSame(args[i], n.getArguments().getArg(i)); } } /** Returns representation of: {@code (x*y)+z+1} */ private FunctionNode createFunctionNode() { return new FunctionNode(INTEGER_UTILS.getAdd(), new FunctionNode(INTEGER_UTILS.getMultiply(), createVariable(0), createVariable(1)), new FunctionNode( INTEGER_UTILS.getAdd(), createVariable(2), integerConstant(1))); } }