/** * Copyright (c) 2011-2014 Exxeleron GmbH * * 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 com.exxeleron.qjava; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.junit.Test; public class TestQReader { private static final double DELTA = 0.1; @Test public void testDeserialization() throws IOException, QException { final QExpressions qe = new QExpressions("src/test/resources/QExpressions.out"); for ( final String expr : qe.getExpressions() ) { final ByteOutputStream writer = new ByteOutputStream(); final byte[] binaryExpr = qe.getBinaryExpression(expr); writer.writeByte((byte) 1); // little endian writer.writeByte((byte) 0); writer.writeByte((byte) 0); writer.writeByte((byte) 0); writer.writeInt(binaryExpr.length + 8); writer.write(binaryExpr); writer.flush(); final QReader reader = new DefaultQReader(); reader.setStream(new DataInputStream(new ByteArrayInputStream(writer.toByteArray()))); reader.setEncoding("ISO-8859-1"); try { final Object obj = reader.read(false).getData(); if ( obj != null && obj.getClass().isArray() ) { arrayEquals("Deserialization failed for q expression: " + expr, qe.getReferenceObject(expr), obj); } else { assertEquals("Deserialization failed for q expression: " + expr, qe.getReferenceObject(expr), obj); } } catch ( final QException e ) { final Object ref = qe.getReferenceObject(expr); if ( ref instanceof QException ) { assertEquals("Deserialization failed for q expression: " + expr, ((QException) ref).getMessage(), e.getMessage()); } else { throw e; } } finally { writer.close(); } } } private static class FunctionMock extends QFunction { FunctionMock() { super((byte) 0); } @Override public boolean equals( final Object obj ) { return obj instanceof QFunction; } @Override public int hashCode() { return 0; } } @Test public void testFunctionsDeserialization() throws IOException, QException { final QExpressions qe = new QExpressions("src/test/resources/QExpressionsFunctions.out"); @SuppressWarnings("serial") final Map<String, Object> ref = new HashMap<String, Object>() { { put("{x+y}[3]", new QProjection(new Object[] { new QLambda("{x+y}"), 3L })); put("insert [1]", new QProjection(new Object[] { new FunctionMock(), 1L })); put("xbar", new QLambda("k){x*y div x:$[16h=abs[@x];\"j\"$x;x]}")); put("not", new FunctionMock()); put("and", new FunctionMock()); put("md5", new QProjection(new Object[] { new FunctionMock(), -15L })); put("any", new FunctionMock()); put("save", new FunctionMock()); put("raze", new FunctionMock()); put("sums", new FunctionMock()); put("prev", new FunctionMock()); } }; for ( final String expr : qe.getExpressions() ) { final ByteOutputStream writer = new ByteOutputStream(); final byte[] binaryExpr = qe.getBinaryExpression(expr); writer.writeByte((byte) 1); // little endian writer.writeByte((byte) 0); writer.writeByte((byte) 0); writer.writeByte((byte) 0); writer.writeInt(binaryExpr.length + 8); writer.write(binaryExpr); writer.flush(); final QReader reader = new DefaultQReader(); reader.setStream(new DataInputStream(new ByteArrayInputStream(writer.toByteArray()))); reader.setEncoding("ISO-8859-1"); try { final Object obj = reader.read(false).getData(); final Object refValue = ref.get(expr); if ( refValue instanceof QProjection ) { final QProjection pr = (QProjection) refValue; final QProjection pa = (QProjection) obj; final int length = pr.getParameters().length; for ( int i = 0; i < length; i++ ) { assertEquals("Deserialization failed for q expression: " + expr, pr.getParameters()[i], pa.getParameters()[i]); } } else { assertEquals("Deserialization failed for q expression: " + expr, refValue, obj); } } finally { writer.close(); } } } @Test public void testCompressedDeserialization() throws IOException, QException { final QExpressions qe = new QExpressions("src/test/resources/QCompressedExpressions.out"); final Map<String, Object> reference = new HashMap<String, Object>(); final String[] q1000 = new String[1000]; final Object[] q200 = new Object[] { new int[200], new int[200], new String[200] }; for ( int i = 0; i < q1000.length; i++ ) { q1000[i] = "q"; } for ( int i = 0; i < 200; i++ ) { ((int[]) q200[0])[i] = i; ((int[]) q200[1])[i] = i + 25; ((String[]) q200[2])[i] = "a"; } reference.put("1000#`q", q1000); reference.put("([] q:1000#`q)", new QTable(new String[] { "q" }, new Object[] { q1000 })); reference.put("([] a:til 200;b:25+til 200;c:200#`a)", new QTable(new String[] { "a", "b", "c" }, q200)); for ( final String expr : qe.getExpressions() ) { final ByteOutputStream writer = new ByteOutputStream(); final byte[] binaryExpr = qe.getBinaryExpression(expr); writer.writeByte((byte) 1); // little endian writer.writeByte((byte) 0); writer.writeByte((byte) 1); // compressed writer.writeByte((byte) 0); writer.writeInt(binaryExpr.length + 8); writer.write(binaryExpr); writer.flush(); final QReader reader = new DefaultQReader(); reader.setStream(new DataInputStream(new ByteArrayInputStream(writer.toByteArray()))); reader.setEncoding("ISO-8859-1"); final Object obj = reader.read(false).getData(); if ( obj != null && obj.getClass().isArray() ) { arrayEquals("Deserialization failed for q expression: " + expr, reference.get(expr), obj); } else { assertEquals("Deserialization failed for q expression: " + expr, reference.get(expr), obj); } writer.close(); } } private static void arrayEquals( final String message, final Object ref, final Object obj ) { if ( obj instanceof Object[] && ref instanceof Object[] ) { assertArrayEquals(message, (Object[]) ref, (Object[]) obj); } else if ( obj instanceof byte[] && ref instanceof byte[] ) { assertArrayEquals(message, (byte[]) ref, (byte[]) obj); } else if ( obj instanceof short[] && ref instanceof short[] ) { assertArrayEquals(message, (short[]) ref, (short[]) obj); } else if ( obj instanceof int[] && ref instanceof int[] ) { assertArrayEquals(message, (int[]) ref, (int[]) obj); } else if ( obj instanceof long[] && ref instanceof long[] ) { assertArrayEquals(message, (long[]) ref, (long[]) obj); } else if ( obj instanceof char[] && ref instanceof char[] ) { assertArrayEquals(message, (char[]) ref, (char[]) obj); } else if ( obj instanceof float[] && ref instanceof float[] ) { assertEquals(((float[]) ref).length, ((float[]) obj).length); for ( int i = 0; i < ((float[]) ref).length; i++ ) { assertEquals(((float[]) ref)[i], ((float[]) obj)[i], DELTA); } } else if ( obj instanceof double[] && ref instanceof double[] ) { assertEquals(((double[]) ref).length, ((double[]) obj).length); for ( int i = 0; i < ((double[]) ref).length; i++ ) { assertEquals(((double[]) ref)[i], ((double[]) obj)[i], DELTA); } } else if ( obj instanceof boolean[] && ref instanceof boolean[] ) { assertEquals(((boolean[]) ref).length, ((boolean[]) obj).length); for ( int i = 0; i < ((boolean[]) ref).length; i++ ) { assertEquals(((boolean[]) ref)[i], ((boolean[]) obj)[i]); } } else { fail("Array type mismatch for: " + message); } } }