/* * 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.serialize; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.oakgp.TestUtils.createVariable; import static org.oakgp.TestUtils.readNode; import static org.oakgp.TestUtils.readNodes; import static org.oakgp.Type.integerToBooleanFunctionType; import static org.oakgp.Type.integerType; import static org.oakgp.Type.type; import static org.oakgp.util.Void.VOID; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; import org.junit.Test; import org.oakgp.Arguments; import org.oakgp.function.Function; import org.oakgp.function.classify.IsPositive; import org.oakgp.node.ConstantNode; import org.oakgp.node.FunctionNode; import org.oakgp.node.Node; import org.oakgp.node.VariableNode; import org.oakgp.primitive.VariableSet; public class NodeReaderTest { @Test public void testIsEndOfStream() throws IOException { try (NodeReader nr = new NodeReader("1 2 3", new Function[0], new ConstantNode[0], VariableSet.createVariableSet())) { assertFalse(nr.isEndOfStream()); nr.readNode(); assertFalse(nr.isEndOfStream()); nr.readNode(); assertFalse(nr.isEndOfStream()); nr.readNode(); assertTrue(nr.isEndOfStream()); try { nr.readNode(); fail(); } catch (IllegalStateException e) { // expected } } } @Test public void testZero() { assertParseLiteral(0); } @Test public void testNegativeConstantNode() { assertParseLiteral(-9); } @Test public void testSingleCharacterConstantNode() { assertParseLiteral(4); } @Test public void testMulipleCharacterConstantNode() { assertParseLiteral(42); } @Test public void testInteger() { assertParseLiteral("42", 42); assertParseLiteral("2147483647", Integer.MAX_VALUE); assertParseLiteral("-2147483648", Integer.MIN_VALUE); } @Test public void testLong() { assertParseLiteral("42L", 42L); assertParseLiteral("9223372036854775807L", Long.MAX_VALUE); assertParseLiteral("-9223372036854775808L", Long.MIN_VALUE); } @Test public void testDouble() { assertParseLiteral("42.0", 42d); assertParseLiteral("42.5", 42.5d); assertParseLiteral("1.7976931348623157E308", Double.MAX_VALUE); assertParseLiteral("4.9E-324", Double.MIN_VALUE); } @Test public void testBigInteger() { assertParseLiteral("42I", new BigInteger("42")); assertParseLiteral("9223372036854775807I", BigInteger.valueOf(Long.MAX_VALUE)); assertParseLiteral("-9223372036854775808I", BigInteger.valueOf(Long.MIN_VALUE)); } @Test public void testBigDecimal() { assertParseLiteral("42D", new BigDecimal("42")); assertParseLiteral("42.5D", new BigDecimal("42.5")); assertParseLiteral("1.7976931348623157E308D", BigDecimal.valueOf(Double.MAX_VALUE)); assertParseLiteral("4.9E-324D", BigDecimal.valueOf(Double.MIN_VALUE)); } /** Tests that, when available, parser uses constants defined in BigDecimal. */ @Test public void testBigDecimalReuse() { assertSame(BigDecimal.ZERO, readConstant("0D").evaluate(null)); assertSame(BigDecimal.ONE, readConstant("1D").evaluate(null)); assertSame(BigDecimal.TEN, readConstant("10D").evaluate(null)); } /** Tests that, when available, parser uses constants defined in BigInteger. */ @Test public void testBigIntegerReuse() { assertSame(BigInteger.ZERO, readConstant("0I").evaluate(null)); assertSame(BigInteger.ONE, readConstant("1I").evaluate(null)); assertSame(BigInteger.TEN, readConstant("10I").evaluate(null)); } @Test public void testTrue() { assertParseLiteral(Boolean.TRUE); } @Test public void testFalse() { assertParseLiteral(Boolean.FALSE); } @Test public void testVoid() { assertParseLiteral("void", VOID); } @Test public void testSingleWordString() { assertParseLiteral("\"hello\"", "hello"); } @Test public void testMultiWordString() { assertParseLiteral("\"Hello, world!\"", "Hello, world!"); } @Test public void testFunctionSymbol() { // TODO test functions with other types. e.g. +/Add assertParseFunction("pos?", IsPositive.class); } @Test public void testEmptyArray() { assertParseLiteral("[]", Arguments.createArguments()); } @Test public void testTypeArray() { Arguments expected = Arguments.createArguments(new ConstantNode(9, integerType()), new ConstantNode(2, integerType()), createVariable(0), new ConstantNode(7, integerType())); assertParseLiteral("[9 2 v0 7]", expected); } @Test public void testMixedTypeArray() { assertReadException("[true 9 false v0]", "Mixed type array elements: boolean and integer"); } @Test public void testSingleDigitIdVariableNode() { assertParseVariable(1); } @Test public void testMultipleDigitIdVariableNode() { assertParseVariable(78); } @Test public void testFunctionNodeSpecifiedBySymbol() { assertParseFunction("(+ 7 21)"); } @Test public void testFunctionNodeWithFunctionNodeArguments() { assertParseFunction("(+ (- v0 587) (* 43 v1))"); } @Test public void testEmptyString() { String input = ""; List<Node> outputs = readNodes(input); assertTrue(outputs.isEmpty()); } @Test public void testWhitespace() { String input = " \r\n\t\t "; List<Node> outputs = readNodes(input); assertTrue(outputs.isEmpty()); } @Test public void testPadded() { String input = " \r\n42\t\t "; assertParseLiteral(input, 42); } @Test public void testConstantNode() throws IOException { String input = "TEST"; ConstantNode expected = new ConstantNode(input, type("testConstantNode")); try (NodeReader r = new NodeReader(input, new Function[0], new ConstantNode[] { expected }, VariableSet.createVariableSet())) { Node actual = r.readNode(); assertSame(expected, actual); } } @Test public void testUnknown() throws IOException { String input = "TEST"; try (NodeReader r = new NodeReader(input, new Function[0], new ConstantNode[0], VariableSet.createVariableSet())) { r.readNode(); fail(); } catch (IllegalArgumentException e) { // expected assertEquals("Could not find version of function: TEST in: []", e.getMessage()); } } @Test public void testMulipleNodes() { String[] inputs = { "6", "(+ v0 v1)", "42", "v0", "(+ 1 2)", "v98" }; String combinedInput = " " + inputs[0] + inputs[1] + inputs[2] + " " + inputs[3] + "\n\r\t\t\t" + inputs[4] + " \n " + inputs[5] + "\r\n"; List<Node> outputs = readNodes(combinedInput); assertEquals(inputs.length, outputs.size()); for (int i = 0; i < inputs.length; i++) { assertEquals(inputs[i], outputs.get(i).toString()); } } @Test public void testValidDisplayName() { assertValidDisplayName("x"); assertValidDisplayName("X"); assertValidDisplayName("hello"); assertValidDisplayName("?x_Y-z!"); // can start with a - as long as the second character is not a number assertValidDisplayName("-->"); // can include numbers as long as they are not the first character assertValidDisplayName("i5"); } @Test public void testInvalidDisplayName() { // must contain at least one character assertInvalidDisplayName(null); assertInvalidDisplayName(""); // no white space assertInvalidDisplayName(" "); assertInvalidDisplayName("hel lo"); assertInvalidDisplayName("x "); assertInvalidDisplayName(" x"); assertInvalidDisplayName("x\n"); assertInvalidDisplayName("\tx"); // cannot start with a number, or with a minus sign followed by a number assertInvalidDisplayName("-9"); assertInvalidDisplayName("9i"); } private void assertValidDisplayName(String displayName) { assertIsValidDisplayName(displayName, true); } private void assertInvalidDisplayName(String displayName) { assertIsValidDisplayName(displayName, false); } private void assertIsValidDisplayName(String displayName, boolean isValid) { assertEquals(isValid, NodeReader.isValidDisplayName(displayName)); } private void assertParseLiteral(Object expected) { assertParseLiteral(expected.toString(), expected); } private void assertParseLiteral(String input, Object expected) { Node output = readConstant(input); assertSame(expected.getClass(), output.evaluate(null).getClass()); assertEquals(expected.toString(), output.toString()); assertEquals(expected, output.evaluate(null)); } private void assertParseFunction(String input, Class<? extends Function> expected) { Node output = readConstant(input); assertSame(integerToBooleanFunctionType(), output.getType()); assertEquals(expected, ((ConstantNode) output).evaluate(null).getClass()); } private void assertParseVariable(int id) { String input = "v" + id; Node output = readNode(input); assertSame(VariableNode.class, output.getClass()); assertEquals(id, ((VariableNode) output).getId()); assertEquals(input, output.toString()); } private void assertParseFunction(String input) { Node output = readNode(input); assertSame(FunctionNode.class, output.getClass()); assertEquals(input, output.toString()); } private void assertReadException(String input, String expectedMessage) { try { readNode(input); fail(); } catch (RuntimeException e) { assertEquals(expectedMessage, e.getMessage()); } } private ConstantNode readConstant(String input) { Node output = readNode(input); assertSame(ConstantNode.class, output.getClass()); return (ConstantNode) output; } }