From 79cebfadf8703afe9bf28786bc4df1af348c876e Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" <bronee@gmail.com> Date: Thu, 5 Oct 2006 03:54:20 +0000 Subject: Moved raw package out of spi package. --- .../com/amazon/carbonado/raw/TestDataEncoding.java | 515 +++++++++++++ .../amazon/carbonado/raw/TestEncodingStrategy.java | 857 +++++++++++++++++++++ .../com/amazon/carbonado/raw/TestKeyEncoding.java | 571 ++++++++++++++ .../amazon/carbonado/spi/raw/TestDataEncoding.java | 515 ------------- .../carbonado/spi/raw/TestEncodingStrategy.java | 857 --------------------- .../amazon/carbonado/spi/raw/TestKeyEncoding.java | 571 -------------- 6 files changed, 1943 insertions(+), 1943 deletions(-) create mode 100644 src/test/java/com/amazon/carbonado/raw/TestDataEncoding.java create mode 100644 src/test/java/com/amazon/carbonado/raw/TestEncodingStrategy.java create mode 100644 src/test/java/com/amazon/carbonado/raw/TestKeyEncoding.java delete mode 100644 src/test/java/com/amazon/carbonado/spi/raw/TestDataEncoding.java delete mode 100644 src/test/java/com/amazon/carbonado/spi/raw/TestEncodingStrategy.java delete mode 100644 src/test/java/com/amazon/carbonado/spi/raw/TestKeyEncoding.java (limited to 'src/test') diff --git a/src/test/java/com/amazon/carbonado/raw/TestDataEncoding.java b/src/test/java/com/amazon/carbonado/raw/TestDataEncoding.java new file mode 100644 index 0000000..bff5820 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/raw/TestDataEncoding.java @@ -0,0 +1,515 @@ +/* + * Copyright 2006 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * 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.amazon.carbonado.raw; + +import java.util.Random; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test case for {@link DataEncoder} and {@link DataDecoder}. + * <p> + * It generates random data values, checks that the decoding produces the + * original results, and it checks that the order of the encoded bytes matches + * the order of the original data values. + * + * @author Brian S O'Neill + */ +public class TestDataEncoding extends TestCase { + private static final int SHORT_TEST = 100; + private static final int MEDIUM_TEST = 500; + private static final int LONG_TEST = 1000; + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestDataEncoding.class); + } + + /** + * @return -1, 0, or 1 + */ + static int byteArrayCompare(byte[] aa, byte[] ab) { + int len = Math.min(aa.length, ab.length); + int result = byteArrayCompare(aa, ab, len); + if (result == 0 && aa.length != ab.length) { + if (aa.length == len) { + return -1; + } + if (ab.length == len) { + return 1; + } + } + return result; + } + + /** + * @return -1, 0, or 1 + */ + static int byteArrayCompare(byte[] aa, byte[] ab, int len) { + for (int i=0; i<len; i++) { + int a = aa[i] & 0xff; + int b = ab[i] & 0xff; + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + } + return 0; + } + + /** + * @return -1, 0, or 1 + */ + static int byteArrayOrNullCompare(byte[] aa, byte[] ab) { + if (aa == null) { + if (ab == null) { + return 0; + } else { + return 1; + } + } else if (ab == null) { + return -1; + } else { + return byteArrayCompare(aa, ab); + } + } + + /** + * @return -1, 0, or 1 + */ + static int byteArrayOrNullCompare(byte[] aa, byte[] ab, int len) { + if (aa == null) { + if (ab == null) { + return 0; + } else { + return 1; + } + } else if (ab == null) { + return -1; + } else { + return byteArrayCompare(aa, ab, len); + } + } + + /** + * @return -1, 0, or 1 + */ + static <C extends Comparable> int compare(C a, C b) { + if (a == null) { + if (b == null) { + return 0; + } else { + return 1; + } + } else if (b == null) { + return -1; + } else { + return Integer.signum(a.compareTo(b)); + } + } + + private final long mSeed; + + private Random mRandom; + + public TestDataEncoding(String name) { + super(name); + mSeed = 5399777425345431L; + } + + protected void setUp() { + mRandom = new Random(mSeed); + } + + protected void tearDown() { + } + + public void test_boolean() throws Exception { + byte[] bytes = new byte[1]; + boolean lastValue = false; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + boolean value = mRandom.nextBoolean(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeBoolean(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Boolean() throws Exception { + byte[] bytes = new byte[1]; + Boolean lastValue = false; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Boolean value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = mRandom.nextBoolean(); + } + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeBooleanObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_byte() throws Exception { + byte[] bytes = new byte[1]; + byte lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + byte value = (byte) mRandom.nextInt(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeByte(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Byte() throws Exception { + byte[] bytes = new byte[2]; + Byte lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Byte value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, DataEncoder.encode(value, bytes, 0)); + } else { + value = (byte) mRandom.nextInt(); + assertEquals(2, DataEncoder.encode(value, bytes, 0)); + } + assertEquals(value, DataDecoder.decodeByteObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_short() throws Exception { + byte[] bytes = new byte[2]; + short lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + short value = (short) mRandom.nextInt(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeShort(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Short() throws Exception { + byte[] bytes = new byte[3]; + Short lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Short value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, DataEncoder.encode(value, bytes, 0)); + } else { + value = (short) mRandom.nextInt(); + assertEquals(3, DataEncoder.encode(value, bytes, 0)); + } + assertEquals(value, DataDecoder.decodeShortObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_char() throws Exception { + byte[] bytes = new byte[2]; + char lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + char value = (char) mRandom.nextInt(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeChar(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Character() throws Exception { + byte[] bytes = new byte[3]; + Character lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Character value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, DataEncoder.encode(value, bytes, 0)); + } else { + value = (char) mRandom.nextInt(); + assertEquals(3, DataEncoder.encode(value, bytes, 0)); + } + assertEquals(value, DataDecoder.decodeCharacterObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_int() throws Exception { + byte[] bytes = new byte[4]; + int lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + int value = mRandom.nextInt(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeInt(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Integer() throws Exception { + byte[] bytes = new byte[5]; + Integer lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Integer value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, DataEncoder.encode(value, bytes, 0)); + } else { + value = mRandom.nextInt(); + assertEquals(5, DataEncoder.encode(value, bytes, 0)); + } + assertEquals(value, DataDecoder.decodeIntegerObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_long() throws Exception { + byte[] bytes = new byte[8]; + long lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + long value = mRandom.nextLong(); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeLong(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Long() throws Exception { + byte[] bytes = new byte[9]; + Long lastValue = 0L; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Long value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, DataEncoder.encode(value, bytes, 0)); + } else { + value = mRandom.nextLong(); + assertEquals(9, DataEncoder.encode(value, bytes, 0)); + } + assertEquals(value, DataDecoder.decodeLongObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_float() throws Exception { + byte[] bytes = new byte[4]; + float lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + float value = Float.intBitsToFloat(mRandom.nextInt()); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeFloat(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Float() throws Exception { + byte[] bytes = new byte[4]; + Float lastValue = 0f; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + Float value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = Float.intBitsToFloat(mRandom.nextInt()); + } + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeFloatObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_double() throws Exception { + byte[] bytes = new byte[8]; + double lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + double value = Double.longBitsToDouble(mRandom.nextLong()); + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeDouble(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_Double() throws Exception { + byte[] bytes = new byte[8]; + Double lastValue = 0d; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + Double value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = Double.longBitsToDouble(mRandom.nextLong()); + } + DataEncoder.encode(value, bytes, 0); + assertEquals(value, DataDecoder.decodeDoubleObj(bytes, 0)); + if (lastBytes != null) { + int sgn = compare(value, lastValue); + assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_String() throws Exception { + String[] ref = new String[1]; + for (int i=0; i<SHORT_TEST; i++) { + String value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + int length; + switch (mRandom.nextInt(15)) { + default: + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + length = mRandom.nextInt(100); + break; + case 8: case 9: case 10: case 11: + length = mRandom.nextInt(200); + break; + case 12: case 13: + length = mRandom.nextInt(20000); + break; + case 14: + length = mRandom.nextInt(3000000); + break; + } + char[] chars = new char[length]; + for (int j=0; j<length; j++) { + char c; + switch (mRandom.nextInt(7)) { + default: + case 0: case 1: case 2: case 3: + c = (char) mRandom.nextInt(128); + break; + case 4: case 5: + c = (char) mRandom.nextInt(4000); + break; + case 6: + c = (char) mRandom.nextInt(); + break; + } + chars[j] = c; + } + value = new String(chars); + } + + byte[] bytes = new byte[DataEncoder.calculateEncodedStringLength(value)]; + assertEquals(bytes.length, DataEncoder.encode(value, bytes, 0)); + assertEquals(bytes.length, DataDecoder.decodeString(bytes, 0, ref)); + assertEquals(value, ref[0]); + } + } +} diff --git a/src/test/java/com/amazon/carbonado/raw/TestEncodingStrategy.java b/src/test/java/com/amazon/carbonado/raw/TestEncodingStrategy.java new file mode 100644 index 0000000..11a4eca --- /dev/null +++ b/src/test/java/com/amazon/carbonado/raw/TestEncodingStrategy.java @@ -0,0 +1,857 @@ +/* + * Copyright 2006 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * 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.amazon.carbonado.raw; + +import java.lang.reflect.*; +import java.util.*; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.cojen.classfile.*; +import org.cojen.util.*; + +import com.amazon.carbonado.*; +import com.amazon.carbonado.info.*; +import com.amazon.carbonado.spi.*; + +/** + * Test case for {@link GenericEncodingStrategy}. + * <p> + * It generates random selections of properties, encodes with random values, + * and checks that the decoding produces the original results. In addition, the + * proper ordering of encoded keys is checked. + * + * @author Brian S O'Neill + */ +public class TestEncodingStrategy extends TestCase { + private static final int SHORT_TEST = 100; + private static final int MEDIUM_TEST = 500; + private static final int LONG_TEST = 1000; + + private static final int ENCODE_OBJECT_ARRAY = 0; + private static final int DECODE_OBJECT_ARRAY = 1; + private static final int ENCODE_OBJECT_ARRAY_PARTIAL = 2; + + private static final int BOGUS_GENERATION = 99; + + // Make sure BOGUS_GENERATION is not included. + private static final int[] GENERATIONS = {-1, 0, 1, 2, 127, 128, 129, Integer.MAX_VALUE}; + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestEncodingStrategy.class); + } + + private final long mSeed; + private final StorableProperty<TestStorable>[] mProperties; + + private Random mRandom; + + public TestEncodingStrategy(String name) { + super(name); + mSeed = 986184829029842L; + Collection<? extends StorableProperty<TestStorable>> properties = + StorableIntrospector.examine(TestStorable.class).getAllProperties().values(); + mProperties = properties.toArray(new StorableProperty[0]); + } + + protected void setUp() { + mRandom = new Random(mSeed); + } + + protected void tearDown() { + } + + public void test_dataEncoding_noProperties() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_noProperties(0, 0, generation); + } + } + + public void test_dataEncoding_noProperties_prefix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_noProperties(5, 0, generation); + } + } + + public void test_dataEncoding_noProperties_suffix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_noProperties(0, 7, generation); + } + } + + public void test_dataEncoding_noProperties_prefixAndSuffix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_noProperties(5, 7, generation); + } + } + + private void test_dataEncoding_noProperties(int prefix, int suffix, int generation) + throws Exception + { + GenericEncodingStrategy strategy = new GenericEncodingStrategy + (TestStorable.class, null, 0, 0, prefix, suffix); + + Method[] methods = generateCodecMethods + (strategy, new StorableProperty[0], null, generation); + + byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {new Object[0]}); + + int generationPrefix; + if (generation < 0) { + generationPrefix = 0; + } else if (generation < 128) { + generationPrefix = 1; + } else { + generationPrefix = 4; + } + + assertEquals(encoded.length, prefix + generationPrefix + suffix); + + if (generation >= 0) { + if (generationPrefix == 1) { + assertEquals(generation, encoded[prefix]); + } else { + int actualGeneration = DataDecoder.decodeInt(encoded, prefix); + assertEquals(generation, actualGeneration); + } + } + + // Decode should not throw an exception. + methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); + + // Generation mismatch should throw an exception. + if (generation >= 0) { + encoded[prefix] = BOGUS_GENERATION; + try { + methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); + fail(); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof CorruptEncodingException) { + CorruptEncodingException cee = (CorruptEncodingException) cause; + // Make sure error message includes actual generation. + assertTrue(cee.getMessage().indexOf(String.valueOf(BOGUS_GENERATION)) >= 0); + } else { + throw e; + } + } + } + } + + public void test_dataEncoding_multipleProperties() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_multipleProperties(0, 0, generation); + } + } + + public void test_dataEncoding_multipleProperties_prefix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_multipleProperties(5, 0, generation); + } + } + + public void test_dataEncoding_multipleProperties_suffix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_multipleProperties(0, 7, generation); + } + } + + public void test_dataEncoding_multipleProperties_prefixAndSuffix() throws Exception { + for (int generation : GENERATIONS) { + test_dataEncoding_multipleProperties(5, 7, generation); + } + } + + /** + * @param generation when non-negative, encode a storable layout generation + * value in one or four bytes. + */ + private void test_dataEncoding_multipleProperties(int prefix, int suffix, int generation) + throws Exception + { + GenericEncodingStrategy strategy = new GenericEncodingStrategy + (TestStorable.class, null, 0, 0, prefix, suffix); + + for (int i=0; i<SHORT_TEST; i++) { + StorableProperty<TestStorable>[] properties = selectProperties(1, 50); + + Method[] methods = generateCodecMethods(strategy, properties, null, generation); + Object[] values = selectPropertyValues(properties); + + byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {values}); + + int generationPrefix; + if (generation < 0) { + generationPrefix = 0; + } else if (generation < 128) { + generationPrefix = 1; + } else { + generationPrefix = 4; + } + + assertTrue(encoded.length > (prefix + generationPrefix + suffix)); + + if (generation >= 0) { + if (generationPrefix == 1) { + assertEquals(generation, encoded[prefix]); + } else { + int actualGeneration = DataDecoder.decodeInt(encoded, prefix); + assertEquals(generation, actualGeneration); + } + } + + if (prefix > 0) { + // Fill in with data which should be ignored by decoder. + for (int p=0; p<prefix; p++) { + encoded[p] = (byte) mRandom.nextInt(); + } + } + + if (suffix > 0) { + // Fill in with data which should be ignored by decoder. + for (int p=0; p<suffix; p++) { + encoded[encoded.length - p - 1] = (byte) mRandom.nextInt(); + } + } + + Object[] decodedValues = new Object[values.length]; + methods[DECODE_OBJECT_ARRAY].invoke(null, decodedValues, encoded); + + for (int j=0; j<properties.length; j++) { + Object a = values[j]; + Object b = decodedValues[j]; + if (properties[j].getType() == byte[].class) { + assertTrue(0 == TestDataEncoding.byteArrayOrNullCompare + ((byte[]) a, (byte[]) b)); + } else { + assertEquals(a, b); + } + } + + // Generation mismatch should throw an exception. + if (generation >= 0) { + encoded[prefix] = BOGUS_GENERATION; + try { + methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); + fail(); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof CorruptEncodingException) { + CorruptEncodingException cee = (CorruptEncodingException) cause; + // Make sure error message includes actual generation. + assertTrue + (cee.getMessage().indexOf(String.valueOf(BOGUS_GENERATION)) >= 0); + } else { + throw e; + } + } + } + } + } + + public void test_keyEncoding_noProperties() throws Exception { + test_keyEncoding_noProperties(0, 0); + } + + public void test_keyEncoding_noProperties_prefix() throws Exception { + test_keyEncoding_noProperties(5, 0); + } + + public void test_keyEncoding_noProperties_suffix() throws Exception { + test_keyEncoding_noProperties(0, 7); + } + + public void test_keyEncoding_noProperties_prefixAndSuffix() throws Exception { + test_keyEncoding_noProperties(5, 7); + } + + private void test_keyEncoding_noProperties(int prefix, int suffix) throws Exception { + GenericEncodingStrategy strategy = new GenericEncodingStrategy + (TestStorable.class, null, prefix, suffix, 0, 0); + + Method[] methods = generateCodecMethods + (strategy, new StorableProperty[0], new Direction[0], -1); + + // Encode should return an empty array. + byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {new Object[0]}); + assertEquals(encoded.length, prefix + suffix); + + // Decode should not throw an exception. + methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); + } + + public void test_keyEncoding_multipleProperties() throws Exception { + test_keyEncoding_multipleProperties(0, 0); + } + + public void test_keyEncoding_multipleProperties_prefix() throws Exception { + test_keyEncoding_multipleProperties(5, 0); + } + + public void test_keyEncoding_multipleProperties_suffix() throws Exception { + test_keyEncoding_multipleProperties(0, 7); + } + + public void test_keyEncoding_multipleProperties_prefixAndSuffix() throws Exception { + test_keyEncoding_multipleProperties(5, 7); + } + + private void test_keyEncoding_multipleProperties(int prefix, int suffix) throws Exception { + GenericEncodingStrategy strategy = new GenericEncodingStrategy + (TestStorable.class, null, prefix, suffix, 0, 0); + + for (int i=0; i<MEDIUM_TEST; i++) { + StorableProperty<TestStorable>[] properties = selectProperties(1, 50); + Direction[] directions = selectDirections(properties.length); + + Method[] methods = generateCodecMethods(strategy, properties, directions, -1); + Object[] values = selectPropertyValues(properties); + + byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {values}); + + assertTrue(encoded.length > (prefix + suffix)); + + // Encode using partial encoding method, but do all + // properties. Ensure that the encoding is exactly the same. + byte[] encoded2 = (byte[]) methods[ENCODE_OBJECT_ARRAY_PARTIAL] + .invoke(null, new Object[] {values, 0, properties.length}); + assertTrue(Arrays.equals(encoded, encoded2)); + + if (prefix > 0) { + // Fill in with data which should be ignored by decoder. + for (int p=0; p<prefix; p++) { + encoded[p] = (byte) mRandom.nextInt(); + } + } + + if (suffix > 0) { + // Fill in with data which should be ignored by decoder. + for (int p=0; p<suffix; p++) { + encoded[encoded.length - p - 1] = (byte) mRandom.nextInt(); + } + } + + Object[] decodedValues = new Object[values.length]; + methods[DECODE_OBJECT_ARRAY].invoke(null, decodedValues, encoded); + + for (int j=0; j<properties.length; j++) { + Object a = values[j]; + Object b = decodedValues[j]; + if (properties[j].getType() == byte[].class) { + assertTrue(0 == TestDataEncoding.byteArrayOrNullCompare + ((byte[]) a, (byte[]) b)); + } else { + assertEquals(a, b); + } + } + + // Now test partial encoding of keys. + + // Clear out random affixes, since we don't need specific values + // anymore and it interferes with next test. + if (prefix > 0) { + for (int p=0; p<prefix; p++) { + encoded[p] = 0; + } + } + if (suffix > 0) { + for (int p=0; p<suffix; p++) { + encoded[encoded.length - p - 1] = 0; + } + } + + for (int j=0; j<SHORT_TEST; j++) { + int start, end; + if (properties.length == 1) { + start = 0; + end = 1; + } else { + start = mRandom.nextInt(properties.length - 1); + // Partial encoding doesn't support zero properties, so + // ensure randomly selected stride is more than zero. + int stride; + do { + stride = mRandom.nextInt(properties.length - start); + } while (stride == 0); + end = start + stride + 1; + } + + Object[] partialValues = new Object[end - start]; + System.arraycopy(values, start, partialValues, 0, partialValues.length); + + byte[] partial = (byte[]) methods[ENCODE_OBJECT_ARRAY_PARTIAL] + .invoke(null, new Object[] {partialValues, start, end}); + + // Partial key must be substring of full key. + int searchStart = start == 0 ? 0 : prefix; + int index = indexOf(encoded, searchStart, encoded.length - searchStart, + partial, 0, partial.length, 0); + + if (start == 0) { + assertEquals(0, index); + } else { + assertTrue(index > 0); + } + + if (properties.length == 1) { + break; + } + } + } + } + + public void test_keyEncoding_ordering() throws Exception { + GenericEncodingStrategy strategy = + new GenericEncodingStrategy(TestStorable.class, null, 0, 0, 0, 0); + + for (int i=0; i<MEDIUM_TEST; i++) { + StorableProperty<TestStorable>[] properties = selectProperties(1, 50); + Direction[] directions = selectDirections(properties.length); + Method[] methods = generateCodecMethods(strategy, properties, directions, -1); + + Object[] values_1 = selectPropertyValues(properties); + byte[] encoded_1 = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {values_1}); + + Object[] values_2 = selectPropertyValues(properties); + byte[] encoded_2 = (byte[]) methods[ENCODE_OBJECT_ARRAY] + .invoke(null, new Object[] {values_2}); + + int byteOrder = TestDataEncoding.byteArrayCompare(encoded_1, encoded_2); + int valueOrder = compareValues(properties, directions, values_1, values_2); + + assertEquals(valueOrder, byteOrder); + } + } + + private int compareValues(StorableProperty<?>[] properties, Direction[] directions, + Object[] values_1, Object[] values_2) { + int length = directions.length; + for (int i=0; i<length; i++) { + StorableProperty<?> property = properties[i]; + Direction direction = directions[i]; + + Object value_1 = values_1[i]; + Object value_2 = values_2[i]; + + int result; + if (property.getType() == byte[].class) { + result = TestDataEncoding.byteArrayOrNullCompare + ((byte[]) value_1, (byte[]) value_2); + } else { + if (value_1 == null) { + if (value_2 == null) { + result = 0; + } else { + result = 1; + } + } else if (value_2 == null) { + result = -1; + } else { + result = Integer.signum(((Comparable) value_1).compareTo(value_2)); + } + } + + if (result != 0) { + if (direction == Direction.DESCENDING) { + result = -result; + } + return result; + } + } + + return 0; + } + + // Method taken from String class and modified a bit. + private static int indexOf(byte[] source, int sourceOffset, int sourceCount, + byte[] target, int targetOffset, int targetCount, + int fromIndex) { + if (fromIndex >= sourceCount) { + return (targetCount == 0 ? sourceCount : -1); + } + if (fromIndex < 0) { + fromIndex = 0; + } + if (targetCount == 0) { + return fromIndex; + } + + byte first = target[targetOffset]; + int max = sourceOffset + (sourceCount - targetCount); + + for (int i = sourceOffset + fromIndex; i <= max; i++) { + // Look for first byte. + if (source[i] != first) { + while (++i <= max && source[i] != first); + } + + // Found first byte, now look at the rest of v2 + if (i <= max) { + int j = i + 1; + int end = j + targetCount - 1; + for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); + + if (j == end) { + // Found whole string. + return i - sourceOffset; + } + } + } + return -1; + } + + /** + * First method is the encoder, second is the decoder. Both methods are + * static. Encoder accepts an object array of property values, and it + * returns a byte array. Decoder accepts an object array to receive + * property values, an encoded byte array, and it returns void. + * + * <p>If generating key encoding and the property count is more than zero, + * then third element in array is a key encoder that supports partial + * encoding. In addition to the object array argument, it also accepts an + * int start and an int end argument. The start of the range is inclusive, + * and the end is exclusive. + * + * @param directions when supplied, build key encoding/decoding. Otherwise, + * build data encoding/decoding. + * @param generation when non-negative, encode a storable layout generation + * value in one or four bytes. + */ + private Method[] generateCodecMethods(GenericEncodingStrategy strategy, + StorableProperty<TestStorable>[] properties, + Direction[] directions, + int generation) + throws Exception + { + ClassInjector ci = ClassInjector.create(TestStorable.class.getName(), null); + ClassFile cf = new ClassFile(ci.getClassName()); + cf.markSynthetic(); + cf.setTarget("1.5"); + + cf.addDefaultConstructor(); + + TypeDesc byteArrayType = TypeDesc.forClass(byte[].class); + TypeDesc objectArrayType = TypeDesc.forClass(Object[].class); + + // Build encode method. + MethodInfo mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "encode", byteArrayType, + new TypeDesc[] {objectArrayType}); + CodeBuilder b = new CodeBuilder(mi); + LocalVariable encodedVar; + if (directions != null) { + OrderedProperty<TestStorable>[] ordered = + makeOrderedProperties(properties, directions); + encodedVar = + strategy.buildKeyEncoding(b, ordered, b.getParameter(0), null, false, null, null); + } else { + encodedVar = strategy.buildDataEncoding + (b, properties, b.getParameter(0), null, false, generation); + } + b.loadLocal(encodedVar); + b.returnValue(byteArrayType); + + // Build decode method. + mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "decode", null, + new TypeDesc[] {objectArrayType, byteArrayType}); + b = new CodeBuilder(mi); + if (directions != null) { + OrderedProperty<TestStorable>[] ordered = + makeOrderedProperties(properties, directions); + strategy.buildKeyDecoding + (b, ordered, b.getParameter(0), null, false, b.getParameter(1)); + } else { + strategy.buildDataDecoding + (b, properties, b.getParameter(0), null, false, + generation, null, b.getParameter(1)); + } + b.returnVoid(); + + if (directions != null && properties.length > 0) { + // Build encode partial key method. + mi = cf.addMethod + (Modifiers.PUBLIC_STATIC, "encodePartial", byteArrayType, + new TypeDesc[] {objectArrayType, TypeDesc.INT, TypeDesc.INT}); + b = new CodeBuilder(mi); + OrderedProperty<TestStorable>[] ordered = + makeOrderedProperties(properties, directions); + encodedVar = + strategy.buildKeyEncoding(b, ordered, b.getParameter(0), null, false, + b.getParameter(1), b.getParameter(2)); + b.loadLocal(encodedVar); + b.returnValue(byteArrayType); + } + + Class<?> clazz = ci.defineClass(cf); + + Method encode = clazz.getMethod("encode", Object[].class); + Method decode = clazz.getMethod("decode", Object[].class, byte[].class); + Method encodePartial = null; + if (directions != null && properties.length > 0) { + encodePartial = clazz.getMethod("encodePartial", Object[].class, int.class, int.class); + } + + Method[] methods = new Method[3]; + methods[ENCODE_OBJECT_ARRAY] = encode; + methods[DECODE_OBJECT_ARRAY] = decode; + methods[ENCODE_OBJECT_ARRAY_PARTIAL] = encodePartial; + + return methods; + } + + private StorableProperty<TestStorable>[] selectProperties(int minCount, int maxCount) { + int length = (minCount == maxCount) ? minCount + : (mRandom.nextInt(maxCount - minCount + 1) + minCount); + + StorableProperty<TestStorable>[] selection = new StorableProperty[length]; + + for (int i=length; --i>=0; ) { + selection[i] = mProperties[mRandom.nextInt(mProperties.length)]; + } + + return selection; + } + + private Direction[] selectDirections(int count) { + Direction[] directions = new Direction[count]; + + for (int i=count; --i>=0; ) { + Direction dir; + switch (mRandom.nextInt(3)) { + default: + dir = Direction.UNSPECIFIED; + break; + case 1: + dir = Direction.ASCENDING; + break; + case 2: + dir = Direction.DESCENDING; + break; + } + directions[i] = dir; + } + + return directions; + } + + private OrderedProperty<TestStorable>[] makeOrderedProperties + (StorableProperty<TestStorable>[] properties, Direction[] directions) { + + int length = properties.length; + OrderedProperty<TestStorable>[] ordered = new OrderedProperty[length]; + for (int i=length; --i>=0; ) { + ordered[i] = OrderedProperty.get(properties[i], directions[i]); + } + + return ordered; + } + + /** + * Returns an array of the same size with randomly selected values filled + * in that match the property type. + */ + private Object[] selectPropertyValues(StorableProperty<?>[] properties) { + int length = properties.length; + Object[] values = new Object[length]; + + for (int i=length; --i>=0; ) { + StorableProperty<?> property = properties[i]; + TypeDesc type = TypeDesc.forClass(property.getType()); + + Object value; + + if (property.isNullable() && mRandom.nextInt(100) == 0) { + value = null; + } else { + TypeDesc prim = type.toPrimitiveType(); + if (prim != null) { + switch (prim.getTypeCode()) { + case TypeDesc.BOOLEAN_CODE: default: + value = mRandom.nextBoolean(); + break; + case TypeDesc.CHAR_CODE: + value = (char) mRandom.nextInt(); + break; + case TypeDesc.FLOAT_CODE: + value = Float.intBitsToFloat(mRandom.nextInt()); + break; + case TypeDesc.DOUBLE_CODE: + value = Double.longBitsToDouble(mRandom.nextLong()); + break; + case TypeDesc.BYTE_CODE: + value = (byte) mRandom.nextInt(); + break; + case TypeDesc.SHORT_CODE: + value = (short) mRandom.nextInt(); + break; + case TypeDesc.INT_CODE: + value = mRandom.nextInt(); + break; + case TypeDesc.LONG_CODE: + value = mRandom.nextLong(); + break; + } + } else if (type == TypeDesc.STRING) { + int len = mRandom.nextInt(100); + StringBuilder sb = new StringBuilder(len); + for (int j=0; j<len; j++) { + sb.append((char) mRandom.nextInt()); + } + value = sb.toString(); + } else { + int len = mRandom.nextInt(100); + byte[] bytes = new byte[len]; + for (int j=0; j<len; j++) { + bytes[j] = (byte) mRandom.nextInt(); + } + value = bytes; + } + } + + values[i] = value; + } + + return values; + } + + /** + * Just a collection of storable properties. At least one property defined + * per supported type. + */ + @PrimaryKey("byte") // I don't really care what the primary key is. + public static interface TestStorable extends Storable { + byte getByte(); + + void setByte(byte b); + + Byte getByteObj(); + + void setByteObj(Byte b); + + @Nullable + Byte getNullableByteObj(); + + void setNullableByteObj(Byte b); + + short getShort(); + + void setShort(short s); + + Short getShortObj(); + + void setShortObj(Short s); + + @Nullable + Short getNullableShortObj(); + + void setNullableShortObj(Short s); + + char getChar(); + + void setChar(char c); + + Character getCharacterObj(); + + void setCharacterObj(Character c); + + @Nullable + Character getNullableCharacterObj(); + + void setNullableCharacterObj(Character c); + + int getInt(); + + void setInt(int i); + + Integer getIntegerObj(); + + void setIntegerObj(Integer obj); + + @Nullable + Integer getNullableIntegerObj(); + + void setNullableIntegerObj(Integer obj); + + long getLong(); + + void setLong(long i); + + Long getLongObj(); + + void setLongObj(Long i); + + @Nullable + Long getNullableLongObj(); + + void setNullableLongObj(Long i); + + float getFloat(); + + void setFloat(float f); + + Float getFloatObj(); + + void setFloatObj(Float f); + + @Nullable + Float getNullableFloatObj(); + + void setNullableFloatObj(Float f); + + double getDouble(); + + void setDouble(double d); + + Double getDoubleObj(); + + void setDoubleObj(Double d); + + @Nullable + Double getNullableDoubleObj(); + + void setNullableDoubleObj(Double d); + + byte[] getByteArray(); + + void setByteArray(byte[] b); + + @Nullable + byte[] getNullableByteArray(); + + void setNullableByteArray(byte[] b); + + String getString(); + + void setString(String s); + + @Nullable + String getNullableString(); + + void setNullableString(String s); + } +} diff --git a/src/test/java/com/amazon/carbonado/raw/TestKeyEncoding.java b/src/test/java/com/amazon/carbonado/raw/TestKeyEncoding.java new file mode 100644 index 0000000..3dba00e --- /dev/null +++ b/src/test/java/com/amazon/carbonado/raw/TestKeyEncoding.java @@ -0,0 +1,571 @@ +/* + * Copyright 2006 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * 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.amazon.carbonado.raw; + +import java.util.Random; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test case for {@link KeyEncoder} and {@link KeyDecoder}. + * <p> + * It generates random data values, checks that the decoding produces the + * original results, and it checks that the order of the encoded bytes matches + * the order of the original data values. + * + * @author Brian S O'Neill + */ +public class TestKeyEncoding extends TestCase { + private static final int SHORT_TEST = 100; + private static final int MEDIUM_TEST = 500; + private static final int LONG_TEST = 1000; + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestKeyEncoding.class); + } + + private final long mSeed; + + private Random mRandom; + + public TestKeyEncoding(String name) { + super(name); + mSeed = 5399777425345431L; + } + + protected void setUp() { + mRandom = new Random(mSeed); + } + + protected void tearDown() { + } + + public void test_booleanDesc() throws Exception { + byte[] bytes = new byte[1]; + boolean lastValue = false; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + boolean value = mRandom.nextBoolean(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeBooleanDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_BooleanDesc() throws Exception { + byte[] bytes = new byte[1]; + Boolean lastValue = false; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Boolean value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = mRandom.nextBoolean(); + } + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeBooleanObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_byteDesc() throws Exception { + byte[] bytes = new byte[1]; + byte lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + byte value = (byte) mRandom.nextInt(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeByteDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_ByteDesc() throws Exception { + byte[] bytes = new byte[2]; + Byte lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Byte value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); + } else { + value = (byte) mRandom.nextInt(); + assertEquals(2, KeyEncoder.encodeDesc(value, bytes, 0)); + } + assertEquals(value, KeyDecoder.decodeByteObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_shortDesc() throws Exception { + byte[] bytes = new byte[2]; + short lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + short value = (short) mRandom.nextInt(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeShortDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_ShortDesc() throws Exception { + byte[] bytes = new byte[3]; + Short lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Short value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); + } else { + value = (short) mRandom.nextInt(); + assertEquals(3, KeyEncoder.encodeDesc(value, bytes, 0)); + } + assertEquals(value, KeyDecoder.decodeShortObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_charDesc() throws Exception { + byte[] bytes = new byte[2]; + char lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + char value = (char) mRandom.nextInt(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeCharDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_CharacterDesc() throws Exception { + byte[] bytes = new byte[3]; + Character lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Character value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); + } else { + value = (char) mRandom.nextInt(); + assertEquals(3, KeyEncoder.encodeDesc(value, bytes, 0)); + } + assertEquals(value, KeyDecoder.decodeCharacterObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_intDesc() throws Exception { + byte[] bytes = new byte[4]; + int lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + int value = mRandom.nextInt(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeIntDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_IntegerDesc() throws Exception { + byte[] bytes = new byte[5]; + Integer lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Integer value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); + } else { + value = mRandom.nextInt(); + assertEquals(5, KeyEncoder.encodeDesc(value, bytes, 0)); + } + assertEquals(value, KeyDecoder.decodeIntegerObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_longDesc() throws Exception { + byte[] bytes = new byte[8]; + long lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + long value = mRandom.nextLong(); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeLongDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_LongDesc() throws Exception { + byte[] bytes = new byte[9]; + Long lastValue = 0L; + byte[] lastBytes = null; + for (int i=0; i<SHORT_TEST; i++) { + Long value; + if (mRandom.nextInt(10) == 1) { + value = null; + assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); + } else { + value = mRandom.nextLong(); + assertEquals(9, KeyEncoder.encodeDesc(value, bytes, 0)); + } + assertEquals(value, KeyDecoder.decodeLongObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_floatDesc() throws Exception { + byte[] bytes = new byte[4]; + float lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + float value = Float.intBitsToFloat(mRandom.nextInt()); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeFloatDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_FloatDesc() throws Exception { + byte[] bytes = new byte[4]; + Float lastValue = 0f; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + Float value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = Float.intBitsToFloat(mRandom.nextInt()); + } + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeFloatObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_doubleDesc() throws Exception { + byte[] bytes = new byte[8]; + double lastValue = 0; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + double value = Double.longBitsToDouble(mRandom.nextLong()); + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeDoubleDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_DoubleDesc() throws Exception { + byte[] bytes = new byte[8]; + Double lastValue = 0d; + byte[] lastBytes = null; + for (int i=0; i<LONG_TEST; i++) { + Double value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + value = Double.longBitsToDouble(mRandom.nextLong()); + } + KeyEncoder.encodeDesc(value, bytes, 0); + assertEquals(value, KeyDecoder.decodeDoubleObjDesc(bytes, 0)); + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_String() throws Exception { + String lastValue = null; + byte[] lastBytes = null; + String[] ref = new String[1]; + for (int i=0; i<SHORT_TEST; i++) { + String value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + int length; + switch (mRandom.nextInt(15)) { + default: + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + length = mRandom.nextInt(100); + break; + case 8: case 9: case 10: case 11: + length = mRandom.nextInt(200); + break; + case 12: case 13: + length = mRandom.nextInt(20000); + break; + case 14: + length = mRandom.nextInt(3000000); + break; + } + char[] chars = new char[length]; + for (int j=0; j<length; j++) { + char c; + switch (mRandom.nextInt(7)) { + default: + case 0: case 1: case 2: case 3: + c = (char) mRandom.nextInt(128); + break; + case 4: case 5: + c = (char) mRandom.nextInt(4000); + break; + case 6: + c = (char) mRandom.nextInt(); + break; + } + chars[j] = c; + } + value = new String(chars); + } + + byte[] bytes = new byte[KeyEncoder.calculateEncodedStringLength(value)]; + assertEquals(bytes.length, KeyEncoder.encode(value, bytes, 0)); + assertEquals(bytes.length, KeyDecoder.decodeString(bytes, 0, ref)); + assertEquals(value, ref[0]); + + if (lastBytes != null) { + int sgn = TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_StringDesc() throws Exception { + String lastValue = null; + byte[] lastBytes = null; + String[] ref = new String[1]; + for (int i=0; i<SHORT_TEST; i++) { + String value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + int length; + switch (mRandom.nextInt(15)) { + default: + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + length = mRandom.nextInt(100); + break; + case 8: case 9: case 10: case 11: + length = mRandom.nextInt(200); + break; + case 12: case 13: + length = mRandom.nextInt(20000); + break; + case 14: + length = mRandom.nextInt(3000000); + break; + } + char[] chars = new char[length]; + for (int j=0; j<length; j++) { + char c; + switch (mRandom.nextInt(7)) { + default: + case 0: case 1: case 2: case 3: + c = (char) mRandom.nextInt(128); + break; + case 4: case 5: + c = (char) mRandom.nextInt(4000); + break; + case 6: + c = (char) mRandom.nextInt(); + break; + } + chars[j] = c; + } + value = new String(chars); + } + + byte[] bytes = new byte[KeyEncoder.calculateEncodedStringLength(value)]; + assertEquals(bytes.length, KeyEncoder.encodeDesc(value, bytes, 0)); + assertEquals(bytes.length, KeyDecoder.decodeStringDesc(bytes, 0, ref)); + assertEquals(value, ref[0]); + + + if (lastBytes != null) { + int sgn = -TestDataEncoding.compare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_byteArray() throws Exception { + byte[] lastValue = null; + byte[] lastBytes = null; + byte[][] ref = new byte[1][]; + for (int i=0; i<LONG_TEST; i++) { + byte[] value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + int length = mRandom.nextInt(4000); + value = new byte[length]; + for (int j=0; j<length; j++) { + value[j] = (byte) mRandom.nextInt(); + } + } + + byte[] bytes = new byte[KeyEncoder.calculateEncodedLength(value)]; + assertEquals(bytes.length, KeyEncoder.encode(value, bytes, 0)); + assertEquals(bytes.length, KeyDecoder.decode(bytes, 0, ref)); + if (ref[0] == null) { + assertEquals(value, null); + } else if (value == null) { + assertEquals(value, ref[0]); + } else { + assertEquals(0, TestDataEncoding.byteArrayCompare(value, ref[0], value.length)); + } + + if (lastBytes != null) { + int sgn = TestDataEncoding.byteArrayOrNullCompare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } + + public void test_byteArrayDesc() throws Exception { + byte[] lastValue = null; + byte[] lastBytes = null; + byte[][] ref = new byte[1][]; + for (int i=0; i<LONG_TEST; i++) { + byte[] value; + if (mRandom.nextInt(10) == 1) { + value = null; + } else { + int length = mRandom.nextInt(4000); + value = new byte[length]; + for (int j=0; j<length; j++) { + value[j] = (byte) mRandom.nextInt(); + } + } + + byte[] bytes = new byte[KeyEncoder.calculateEncodedLength(value)]; + assertEquals(bytes.length, KeyEncoder.encodeDesc(value, bytes, 0)); + assertEquals(bytes.length, KeyDecoder.decodeDesc(bytes, 0, ref)); + if (ref[0] == null) { + assertEquals(value, null); + } else if (value == null) { + assertEquals(value, ref[0]); + } else { + assertEquals(0, TestDataEncoding.byteArrayCompare(value, ref[0], value.length)); + } + + if (lastBytes != null) { + int sgn = -TestDataEncoding.byteArrayOrNullCompare(value, lastValue); + assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); + } + lastValue = value; + lastBytes = bytes.clone(); + } + } +} diff --git a/src/test/java/com/amazon/carbonado/spi/raw/TestDataEncoding.java b/src/test/java/com/amazon/carbonado/spi/raw/TestDataEncoding.java deleted file mode 100644 index 783a71e..0000000 --- a/src/test/java/com/amazon/carbonado/spi/raw/TestDataEncoding.java +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright 2006 Amazon Technologies, Inc. or its affiliates. - * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks - * of Amazon Technologies, Inc. or its affiliates. All rights reserved. - * - * 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.amazon.carbonado.spi.raw; - -import java.util.Random; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Test case for {@link DataEncoder} and {@link DataDecoder}. - * <p> - * It generates random data values, checks that the decoding produces the - * original results, and it checks that the order of the encoded bytes matches - * the order of the original data values. - * - * @author Brian S O'Neill - */ -public class TestDataEncoding extends TestCase { - private static final int SHORT_TEST = 100; - private static final int MEDIUM_TEST = 500; - private static final int LONG_TEST = 1000; - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static TestSuite suite() { - return new TestSuite(TestDataEncoding.class); - } - - /** - * @return -1, 0, or 1 - */ - static int byteArrayCompare(byte[] aa, byte[] ab) { - int len = Math.min(aa.length, ab.length); - int result = byteArrayCompare(aa, ab, len); - if (result == 0 && aa.length != ab.length) { - if (aa.length == len) { - return -1; - } - if (ab.length == len) { - return 1; - } - } - return result; - } - - /** - * @return -1, 0, or 1 - */ - static int byteArrayCompare(byte[] aa, byte[] ab, int len) { - for (int i=0; i<len; i++) { - int a = aa[i] & 0xff; - int b = ab[i] & 0xff; - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - } - return 0; - } - - /** - * @return -1, 0, or 1 - */ - static int byteArrayOrNullCompare(byte[] aa, byte[] ab) { - if (aa == null) { - if (ab == null) { - return 0; - } else { - return 1; - } - } else if (ab == null) { - return -1; - } else { - return byteArrayCompare(aa, ab); - } - } - - /** - * @return -1, 0, or 1 - */ - static int byteArrayOrNullCompare(byte[] aa, byte[] ab, int len) { - if (aa == null) { - if (ab == null) { - return 0; - } else { - return 1; - } - } else if (ab == null) { - return -1; - } else { - return byteArrayCompare(aa, ab, len); - } - } - - /** - * @return -1, 0, or 1 - */ - static <C extends Comparable> int compare(C a, C b) { - if (a == null) { - if (b == null) { - return 0; - } else { - return 1; - } - } else if (b == null) { - return -1; - } else { - return Integer.signum(a.compareTo(b)); - } - } - - private final long mSeed; - - private Random mRandom; - - public TestDataEncoding(String name) { - super(name); - mSeed = 5399777425345431L; - } - - protected void setUp() { - mRandom = new Random(mSeed); - } - - protected void tearDown() { - } - - public void test_boolean() throws Exception { - byte[] bytes = new byte[1]; - boolean lastValue = false; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - boolean value = mRandom.nextBoolean(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeBoolean(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Boolean() throws Exception { - byte[] bytes = new byte[1]; - Boolean lastValue = false; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Boolean value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = mRandom.nextBoolean(); - } - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeBooleanObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_byte() throws Exception { - byte[] bytes = new byte[1]; - byte lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - byte value = (byte) mRandom.nextInt(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeByte(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Byte() throws Exception { - byte[] bytes = new byte[2]; - Byte lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Byte value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, DataEncoder.encode(value, bytes, 0)); - } else { - value = (byte) mRandom.nextInt(); - assertEquals(2, DataEncoder.encode(value, bytes, 0)); - } - assertEquals(value, DataDecoder.decodeByteObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_short() throws Exception { - byte[] bytes = new byte[2]; - short lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - short value = (short) mRandom.nextInt(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeShort(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Short() throws Exception { - byte[] bytes = new byte[3]; - Short lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Short value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, DataEncoder.encode(value, bytes, 0)); - } else { - value = (short) mRandom.nextInt(); - assertEquals(3, DataEncoder.encode(value, bytes, 0)); - } - assertEquals(value, DataDecoder.decodeShortObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_char() throws Exception { - byte[] bytes = new byte[2]; - char lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - char value = (char) mRandom.nextInt(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeChar(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Character() throws Exception { - byte[] bytes = new byte[3]; - Character lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Character value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, DataEncoder.encode(value, bytes, 0)); - } else { - value = (char) mRandom.nextInt(); - assertEquals(3, DataEncoder.encode(value, bytes, 0)); - } - assertEquals(value, DataDecoder.decodeCharacterObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_int() throws Exception { - byte[] bytes = new byte[4]; - int lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - int value = mRandom.nextInt(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeInt(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Integer() throws Exception { - byte[] bytes = new byte[5]; - Integer lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Integer value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, DataEncoder.encode(value, bytes, 0)); - } else { - value = mRandom.nextInt(); - assertEquals(5, DataEncoder.encode(value, bytes, 0)); - } - assertEquals(value, DataDecoder.decodeIntegerObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_long() throws Exception { - byte[] bytes = new byte[8]; - long lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - long value = mRandom.nextLong(); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeLong(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Long() throws Exception { - byte[] bytes = new byte[9]; - Long lastValue = 0L; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Long value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, DataEncoder.encode(value, bytes, 0)); - } else { - value = mRandom.nextLong(); - assertEquals(9, DataEncoder.encode(value, bytes, 0)); - } - assertEquals(value, DataDecoder.decodeLongObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_float() throws Exception { - byte[] bytes = new byte[4]; - float lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - float value = Float.intBitsToFloat(mRandom.nextInt()); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeFloat(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Float() throws Exception { - byte[] bytes = new byte[4]; - Float lastValue = 0f; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - Float value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = Float.intBitsToFloat(mRandom.nextInt()); - } - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeFloatObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_double() throws Exception { - byte[] bytes = new byte[8]; - double lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - double value = Double.longBitsToDouble(mRandom.nextLong()); - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeDouble(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_Double() throws Exception { - byte[] bytes = new byte[8]; - Double lastValue = 0d; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - Double value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = Double.longBitsToDouble(mRandom.nextLong()); - } - DataEncoder.encode(value, bytes, 0); - assertEquals(value, DataDecoder.decodeDoubleObj(bytes, 0)); - if (lastBytes != null) { - int sgn = compare(value, lastValue); - assertEquals(sgn, byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_String() throws Exception { - String[] ref = new String[1]; - for (int i=0; i<SHORT_TEST; i++) { - String value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - int length; - switch (mRandom.nextInt(15)) { - default: - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - length = mRandom.nextInt(100); - break; - case 8: case 9: case 10: case 11: - length = mRandom.nextInt(200); - break; - case 12: case 13: - length = mRandom.nextInt(20000); - break; - case 14: - length = mRandom.nextInt(3000000); - break; - } - char[] chars = new char[length]; - for (int j=0; j<length; j++) { - char c; - switch (mRandom.nextInt(7)) { - default: - case 0: case 1: case 2: case 3: - c = (char) mRandom.nextInt(128); - break; - case 4: case 5: - c = (char) mRandom.nextInt(4000); - break; - case 6: - c = (char) mRandom.nextInt(); - break; - } - chars[j] = c; - } - value = new String(chars); - } - - byte[] bytes = new byte[DataEncoder.calculateEncodedStringLength(value)]; - assertEquals(bytes.length, DataEncoder.encode(value, bytes, 0)); - assertEquals(bytes.length, DataDecoder.decodeString(bytes, 0, ref)); - assertEquals(value, ref[0]); - } - } -} diff --git a/src/test/java/com/amazon/carbonado/spi/raw/TestEncodingStrategy.java b/src/test/java/com/amazon/carbonado/spi/raw/TestEncodingStrategy.java deleted file mode 100644 index 514df34..0000000 --- a/src/test/java/com/amazon/carbonado/spi/raw/TestEncodingStrategy.java +++ /dev/null @@ -1,857 +0,0 @@ -/* - * Copyright 2006 Amazon Technologies, Inc. or its affiliates. - * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks - * of Amazon Technologies, Inc. or its affiliates. All rights reserved. - * - * 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.amazon.carbonado.spi.raw; - -import java.lang.reflect.*; -import java.util.*; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import org.cojen.classfile.*; -import org.cojen.util.*; - -import com.amazon.carbonado.*; -import com.amazon.carbonado.info.*; -import com.amazon.carbonado.spi.*; - -/** - * Test case for {@link GenericEncodingStrategy}. - * <p> - * It generates random selections of properties, encodes with random values, - * and checks that the decoding produces the original results. In addition, the - * proper ordering of encoded keys is checked. - * - * @author Brian S O'Neill - */ -public class TestEncodingStrategy extends TestCase { - private static final int SHORT_TEST = 100; - private static final int MEDIUM_TEST = 500; - private static final int LONG_TEST = 1000; - - private static final int ENCODE_OBJECT_ARRAY = 0; - private static final int DECODE_OBJECT_ARRAY = 1; - private static final int ENCODE_OBJECT_ARRAY_PARTIAL = 2; - - private static final int BOGUS_GENERATION = 99; - - // Make sure BOGUS_GENERATION is not included. - private static final int[] GENERATIONS = {-1, 0, 1, 2, 127, 128, 129, Integer.MAX_VALUE}; - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static TestSuite suite() { - return new TestSuite(TestEncodingStrategy.class); - } - - private final long mSeed; - private final StorableProperty<TestStorable>[] mProperties; - - private Random mRandom; - - public TestEncodingStrategy(String name) { - super(name); - mSeed = 986184829029842L; - Collection<? extends StorableProperty<TestStorable>> properties = - StorableIntrospector.examine(TestStorable.class).getAllProperties().values(); - mProperties = properties.toArray(new StorableProperty[0]); - } - - protected void setUp() { - mRandom = new Random(mSeed); - } - - protected void tearDown() { - } - - public void test_dataEncoding_noProperties() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_noProperties(0, 0, generation); - } - } - - public void test_dataEncoding_noProperties_prefix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_noProperties(5, 0, generation); - } - } - - public void test_dataEncoding_noProperties_suffix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_noProperties(0, 7, generation); - } - } - - public void test_dataEncoding_noProperties_prefixAndSuffix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_noProperties(5, 7, generation); - } - } - - private void test_dataEncoding_noProperties(int prefix, int suffix, int generation) - throws Exception - { - GenericEncodingStrategy strategy = new GenericEncodingStrategy - (TestStorable.class, null, 0, 0, prefix, suffix); - - Method[] methods = generateCodecMethods - (strategy, new StorableProperty[0], null, generation); - - byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {new Object[0]}); - - int generationPrefix; - if (generation < 0) { - generationPrefix = 0; - } else if (generation < 128) { - generationPrefix = 1; - } else { - generationPrefix = 4; - } - - assertEquals(encoded.length, prefix + generationPrefix + suffix); - - if (generation >= 0) { - if (generationPrefix == 1) { - assertEquals(generation, encoded[prefix]); - } else { - int actualGeneration = DataDecoder.decodeInt(encoded, prefix); - assertEquals(generation, actualGeneration); - } - } - - // Decode should not throw an exception. - methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); - - // Generation mismatch should throw an exception. - if (generation >= 0) { - encoded[prefix] = BOGUS_GENERATION; - try { - methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); - fail(); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof CorruptEncodingException) { - CorruptEncodingException cee = (CorruptEncodingException) cause; - // Make sure error message includes actual generation. - assertTrue(cee.getMessage().indexOf(String.valueOf(BOGUS_GENERATION)) >= 0); - } else { - throw e; - } - } - } - } - - public void test_dataEncoding_multipleProperties() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_multipleProperties(0, 0, generation); - } - } - - public void test_dataEncoding_multipleProperties_prefix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_multipleProperties(5, 0, generation); - } - } - - public void test_dataEncoding_multipleProperties_suffix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_multipleProperties(0, 7, generation); - } - } - - public void test_dataEncoding_multipleProperties_prefixAndSuffix() throws Exception { - for (int generation : GENERATIONS) { - test_dataEncoding_multipleProperties(5, 7, generation); - } - } - - /** - * @param generation when non-negative, encode a storable layout generation - * value in one or four bytes. - */ - private void test_dataEncoding_multipleProperties(int prefix, int suffix, int generation) - throws Exception - { - GenericEncodingStrategy strategy = new GenericEncodingStrategy - (TestStorable.class, null, 0, 0, prefix, suffix); - - for (int i=0; i<SHORT_TEST; i++) { - StorableProperty<TestStorable>[] properties = selectProperties(1, 50); - - Method[] methods = generateCodecMethods(strategy, properties, null, generation); - Object[] values = selectPropertyValues(properties); - - byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {values}); - - int generationPrefix; - if (generation < 0) { - generationPrefix = 0; - } else if (generation < 128) { - generationPrefix = 1; - } else { - generationPrefix = 4; - } - - assertTrue(encoded.length > (prefix + generationPrefix + suffix)); - - if (generation >= 0) { - if (generationPrefix == 1) { - assertEquals(generation, encoded[prefix]); - } else { - int actualGeneration = DataDecoder.decodeInt(encoded, prefix); - assertEquals(generation, actualGeneration); - } - } - - if (prefix > 0) { - // Fill in with data which should be ignored by decoder. - for (int p=0; p<prefix; p++) { - encoded[p] = (byte) mRandom.nextInt(); - } - } - - if (suffix > 0) { - // Fill in with data which should be ignored by decoder. - for (int p=0; p<suffix; p++) { - encoded[encoded.length - p - 1] = (byte) mRandom.nextInt(); - } - } - - Object[] decodedValues = new Object[values.length]; - methods[DECODE_OBJECT_ARRAY].invoke(null, decodedValues, encoded); - - for (int j=0; j<properties.length; j++) { - Object a = values[j]; - Object b = decodedValues[j]; - if (properties[j].getType() == byte[].class) { - assertTrue(0 == TestDataEncoding.byteArrayOrNullCompare - ((byte[]) a, (byte[]) b)); - } else { - assertEquals(a, b); - } - } - - // Generation mismatch should throw an exception. - if (generation >= 0) { - encoded[prefix] = BOGUS_GENERATION; - try { - methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); - fail(); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof CorruptEncodingException) { - CorruptEncodingException cee = (CorruptEncodingException) cause; - // Make sure error message includes actual generation. - assertTrue - (cee.getMessage().indexOf(String.valueOf(BOGUS_GENERATION)) >= 0); - } else { - throw e; - } - } - } - } - } - - public void test_keyEncoding_noProperties() throws Exception { - test_keyEncoding_noProperties(0, 0); - } - - public void test_keyEncoding_noProperties_prefix() throws Exception { - test_keyEncoding_noProperties(5, 0); - } - - public void test_keyEncoding_noProperties_suffix() throws Exception { - test_keyEncoding_noProperties(0, 7); - } - - public void test_keyEncoding_noProperties_prefixAndSuffix() throws Exception { - test_keyEncoding_noProperties(5, 7); - } - - private void test_keyEncoding_noProperties(int prefix, int suffix) throws Exception { - GenericEncodingStrategy strategy = new GenericEncodingStrategy - (TestStorable.class, null, prefix, suffix, 0, 0); - - Method[] methods = generateCodecMethods - (strategy, new StorableProperty[0], new Direction[0], -1); - - // Encode should return an empty array. - byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {new Object[0]}); - assertEquals(encoded.length, prefix + suffix); - - // Decode should not throw an exception. - methods[DECODE_OBJECT_ARRAY].invoke(null, new Object[0], encoded); - } - - public void test_keyEncoding_multipleProperties() throws Exception { - test_keyEncoding_multipleProperties(0, 0); - } - - public void test_keyEncoding_multipleProperties_prefix() throws Exception { - test_keyEncoding_multipleProperties(5, 0); - } - - public void test_keyEncoding_multipleProperties_suffix() throws Exception { - test_keyEncoding_multipleProperties(0, 7); - } - - public void test_keyEncoding_multipleProperties_prefixAndSuffix() throws Exception { - test_keyEncoding_multipleProperties(5, 7); - } - - private void test_keyEncoding_multipleProperties(int prefix, int suffix) throws Exception { - GenericEncodingStrategy strategy = new GenericEncodingStrategy - (TestStorable.class, null, prefix, suffix, 0, 0); - - for (int i=0; i<MEDIUM_TEST; i++) { - StorableProperty<TestStorable>[] properties = selectProperties(1, 50); - Direction[] directions = selectDirections(properties.length); - - Method[] methods = generateCodecMethods(strategy, properties, directions, -1); - Object[] values = selectPropertyValues(properties); - - byte[] encoded = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {values}); - - assertTrue(encoded.length > (prefix + suffix)); - - // Encode using partial encoding method, but do all - // properties. Ensure that the encoding is exactly the same. - byte[] encoded2 = (byte[]) methods[ENCODE_OBJECT_ARRAY_PARTIAL] - .invoke(null, new Object[] {values, 0, properties.length}); - assertTrue(Arrays.equals(encoded, encoded2)); - - if (prefix > 0) { - // Fill in with data which should be ignored by decoder. - for (int p=0; p<prefix; p++) { - encoded[p] = (byte) mRandom.nextInt(); - } - } - - if (suffix > 0) { - // Fill in with data which should be ignored by decoder. - for (int p=0; p<suffix; p++) { - encoded[encoded.length - p - 1] = (byte) mRandom.nextInt(); - } - } - - Object[] decodedValues = new Object[values.length]; - methods[DECODE_OBJECT_ARRAY].invoke(null, decodedValues, encoded); - - for (int j=0; j<properties.length; j++) { - Object a = values[j]; - Object b = decodedValues[j]; - if (properties[j].getType() == byte[].class) { - assertTrue(0 == TestDataEncoding.byteArrayOrNullCompare - ((byte[]) a, (byte[]) b)); - } else { - assertEquals(a, b); - } - } - - // Now test partial encoding of keys. - - // Clear out random affixes, since we don't need specific values - // anymore and it interferes with next test. - if (prefix > 0) { - for (int p=0; p<prefix; p++) { - encoded[p] = 0; - } - } - if (suffix > 0) { - for (int p=0; p<suffix; p++) { - encoded[encoded.length - p - 1] = 0; - } - } - - for (int j=0; j<SHORT_TEST; j++) { - int start, end; - if (properties.length == 1) { - start = 0; - end = 1; - } else { - start = mRandom.nextInt(properties.length - 1); - // Partial encoding doesn't support zero properties, so - // ensure randomly selected stride is more than zero. - int stride; - do { - stride = mRandom.nextInt(properties.length - start); - } while (stride == 0); - end = start + stride + 1; - } - - Object[] partialValues = new Object[end - start]; - System.arraycopy(values, start, partialValues, 0, partialValues.length); - - byte[] partial = (byte[]) methods[ENCODE_OBJECT_ARRAY_PARTIAL] - .invoke(null, new Object[] {partialValues, start, end}); - - // Partial key must be substring of full key. - int searchStart = start == 0 ? 0 : prefix; - int index = indexOf(encoded, searchStart, encoded.length - searchStart, - partial, 0, partial.length, 0); - - if (start == 0) { - assertEquals(0, index); - } else { - assertTrue(index > 0); - } - - if (properties.length == 1) { - break; - } - } - } - } - - public void test_keyEncoding_ordering() throws Exception { - GenericEncodingStrategy strategy = - new GenericEncodingStrategy(TestStorable.class, null, 0, 0, 0, 0); - - for (int i=0; i<MEDIUM_TEST; i++) { - StorableProperty<TestStorable>[] properties = selectProperties(1, 50); - Direction[] directions = selectDirections(properties.length); - Method[] methods = generateCodecMethods(strategy, properties, directions, -1); - - Object[] values_1 = selectPropertyValues(properties); - byte[] encoded_1 = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {values_1}); - - Object[] values_2 = selectPropertyValues(properties); - byte[] encoded_2 = (byte[]) methods[ENCODE_OBJECT_ARRAY] - .invoke(null, new Object[] {values_2}); - - int byteOrder = TestDataEncoding.byteArrayCompare(encoded_1, encoded_2); - int valueOrder = compareValues(properties, directions, values_1, values_2); - - assertEquals(valueOrder, byteOrder); - } - } - - private int compareValues(StorableProperty<?>[] properties, Direction[] directions, - Object[] values_1, Object[] values_2) { - int length = directions.length; - for (int i=0; i<length; i++) { - StorableProperty<?> property = properties[i]; - Direction direction = directions[i]; - - Object value_1 = values_1[i]; - Object value_2 = values_2[i]; - - int result; - if (property.getType() == byte[].class) { - result = TestDataEncoding.byteArrayOrNullCompare - ((byte[]) value_1, (byte[]) value_2); - } else { - if (value_1 == null) { - if (value_2 == null) { - result = 0; - } else { - result = 1; - } - } else if (value_2 == null) { - result = -1; - } else { - result = Integer.signum(((Comparable) value_1).compareTo(value_2)); - } - } - - if (result != 0) { - if (direction == Direction.DESCENDING) { - result = -result; - } - return result; - } - } - - return 0; - } - - // Method taken from String class and modified a bit. - private static int indexOf(byte[] source, int sourceOffset, int sourceCount, - byte[] target, int targetOffset, int targetCount, - int fromIndex) { - if (fromIndex >= sourceCount) { - return (targetCount == 0 ? sourceCount : -1); - } - if (fromIndex < 0) { - fromIndex = 0; - } - if (targetCount == 0) { - return fromIndex; - } - - byte first = target[targetOffset]; - int max = sourceOffset + (sourceCount - targetCount); - - for (int i = sourceOffset + fromIndex; i <= max; i++) { - // Look for first byte. - if (source[i] != first) { - while (++i <= max && source[i] != first); - } - - // Found first byte, now look at the rest of v2 - if (i <= max) { - int j = i + 1; - int end = j + targetCount - 1; - for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); - - if (j == end) { - // Found whole string. - return i - sourceOffset; - } - } - } - return -1; - } - - /** - * First method is the encoder, second is the decoder. Both methods are - * static. Encoder accepts an object array of property values, and it - * returns a byte array. Decoder accepts an object array to receive - * property values, an encoded byte array, and it returns void. - * - * <p>If generating key encoding and the property count is more than zero, - * then third element in array is a key encoder that supports partial - * encoding. In addition to the object array argument, it also accepts an - * int start and an int end argument. The start of the range is inclusive, - * and the end is exclusive. - * - * @param directions when supplied, build key encoding/decoding. Otherwise, - * build data encoding/decoding. - * @param generation when non-negative, encode a storable layout generation - * value in one or four bytes. - */ - private Method[] generateCodecMethods(GenericEncodingStrategy strategy, - StorableProperty<TestStorable>[] properties, - Direction[] directions, - int generation) - throws Exception - { - ClassInjector ci = ClassInjector.create(TestStorable.class.getName(), null); - ClassFile cf = new ClassFile(ci.getClassName()); - cf.markSynthetic(); - cf.setTarget("1.5"); - - cf.addDefaultConstructor(); - - TypeDesc byteArrayType = TypeDesc.forClass(byte[].class); - TypeDesc objectArrayType = TypeDesc.forClass(Object[].class); - - // Build encode method. - MethodInfo mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "encode", byteArrayType, - new TypeDesc[] {objectArrayType}); - CodeBuilder b = new CodeBuilder(mi); - LocalVariable encodedVar; - if (directions != null) { - OrderedProperty<TestStorable>[] ordered = - makeOrderedProperties(properties, directions); - encodedVar = - strategy.buildKeyEncoding(b, ordered, b.getParameter(0), null, false, null, null); - } else { - encodedVar = strategy.buildDataEncoding - (b, properties, b.getParameter(0), null, false, generation); - } - b.loadLocal(encodedVar); - b.returnValue(byteArrayType); - - // Build decode method. - mi = cf.addMethod(Modifiers.PUBLIC_STATIC, "decode", null, - new TypeDesc[] {objectArrayType, byteArrayType}); - b = new CodeBuilder(mi); - if (directions != null) { - OrderedProperty<TestStorable>[] ordered = - makeOrderedProperties(properties, directions); - strategy.buildKeyDecoding - (b, ordered, b.getParameter(0), null, false, b.getParameter(1)); - } else { - strategy.buildDataDecoding - (b, properties, b.getParameter(0), null, false, - generation, null, b.getParameter(1)); - } - b.returnVoid(); - - if (directions != null && properties.length > 0) { - // Build encode partial key method. - mi = cf.addMethod - (Modifiers.PUBLIC_STATIC, "encodePartial", byteArrayType, - new TypeDesc[] {objectArrayType, TypeDesc.INT, TypeDesc.INT}); - b = new CodeBuilder(mi); - OrderedProperty<TestStorable>[] ordered = - makeOrderedProperties(properties, directions); - encodedVar = - strategy.buildKeyEncoding(b, ordered, b.getParameter(0), null, false, - b.getParameter(1), b.getParameter(2)); - b.loadLocal(encodedVar); - b.returnValue(byteArrayType); - } - - Class<?> clazz = ci.defineClass(cf); - - Method encode = clazz.getMethod("encode", Object[].class); - Method decode = clazz.getMethod("decode", Object[].class, byte[].class); - Method encodePartial = null; - if (directions != null && properties.length > 0) { - encodePartial = clazz.getMethod("encodePartial", Object[].class, int.class, int.class); - } - - Method[] methods = new Method[3]; - methods[ENCODE_OBJECT_ARRAY] = encode; - methods[DECODE_OBJECT_ARRAY] = decode; - methods[ENCODE_OBJECT_ARRAY_PARTIAL] = encodePartial; - - return methods; - } - - private StorableProperty<TestStorable>[] selectProperties(int minCount, int maxCount) { - int length = (minCount == maxCount) ? minCount - : (mRandom.nextInt(maxCount - minCount + 1) + minCount); - - StorableProperty<TestStorable>[] selection = new StorableProperty[length]; - - for (int i=length; --i>=0; ) { - selection[i] = mProperties[mRandom.nextInt(mProperties.length)]; - } - - return selection; - } - - private Direction[] selectDirections(int count) { - Direction[] directions = new Direction[count]; - - for (int i=count; --i>=0; ) { - Direction dir; - switch (mRandom.nextInt(3)) { - default: - dir = Direction.UNSPECIFIED; - break; - case 1: - dir = Direction.ASCENDING; - break; - case 2: - dir = Direction.DESCENDING; - break; - } - directions[i] = dir; - } - - return directions; - } - - private OrderedProperty<TestStorable>[] makeOrderedProperties - (StorableProperty<TestStorable>[] properties, Direction[] directions) { - - int length = properties.length; - OrderedProperty<TestStorable>[] ordered = new OrderedProperty[length]; - for (int i=length; --i>=0; ) { - ordered[i] = OrderedProperty.get(properties[i], directions[i]); - } - - return ordered; - } - - /** - * Returns an array of the same size with randomly selected values filled - * in that match the property type. - */ - private Object[] selectPropertyValues(StorableProperty<?>[] properties) { - int length = properties.length; - Object[] values = new Object[length]; - - for (int i=length; --i>=0; ) { - StorableProperty<?> property = properties[i]; - TypeDesc type = TypeDesc.forClass(property.getType()); - - Object value; - - if (property.isNullable() && mRandom.nextInt(100) == 0) { - value = null; - } else { - TypeDesc prim = type.toPrimitiveType(); - if (prim != null) { - switch (prim.getTypeCode()) { - case TypeDesc.BOOLEAN_CODE: default: - value = mRandom.nextBoolean(); - break; - case TypeDesc.CHAR_CODE: - value = (char) mRandom.nextInt(); - break; - case TypeDesc.FLOAT_CODE: - value = Float.intBitsToFloat(mRandom.nextInt()); - break; - case TypeDesc.DOUBLE_CODE: - value = Double.longBitsToDouble(mRandom.nextLong()); - break; - case TypeDesc.BYTE_CODE: - value = (byte) mRandom.nextInt(); - break; - case TypeDesc.SHORT_CODE: - value = (short) mRandom.nextInt(); - break; - case TypeDesc.INT_CODE: - value = mRandom.nextInt(); - break; - case TypeDesc.LONG_CODE: - value = mRandom.nextLong(); - break; - } - } else if (type == TypeDesc.STRING) { - int len = mRandom.nextInt(100); - StringBuilder sb = new StringBuilder(len); - for (int j=0; j<len; j++) { - sb.append((char) mRandom.nextInt()); - } - value = sb.toString(); - } else { - int len = mRandom.nextInt(100); - byte[] bytes = new byte[len]; - for (int j=0; j<len; j++) { - bytes[j] = (byte) mRandom.nextInt(); - } - value = bytes; - } - } - - values[i] = value; - } - - return values; - } - - /** - * Just a collection of storable properties. At least one property defined - * per supported type. - */ - @PrimaryKey("byte") // I don't really care what the primary key is. - public static interface TestStorable extends Storable { - byte getByte(); - - void setByte(byte b); - - Byte getByteObj(); - - void setByteObj(Byte b); - - @Nullable - Byte getNullableByteObj(); - - void setNullableByteObj(Byte b); - - short getShort(); - - void setShort(short s); - - Short getShortObj(); - - void setShortObj(Short s); - - @Nullable - Short getNullableShortObj(); - - void setNullableShortObj(Short s); - - char getChar(); - - void setChar(char c); - - Character getCharacterObj(); - - void setCharacterObj(Character c); - - @Nullable - Character getNullableCharacterObj(); - - void setNullableCharacterObj(Character c); - - int getInt(); - - void setInt(int i); - - Integer getIntegerObj(); - - void setIntegerObj(Integer obj); - - @Nullable - Integer getNullableIntegerObj(); - - void setNullableIntegerObj(Integer obj); - - long getLong(); - - void setLong(long i); - - Long getLongObj(); - - void setLongObj(Long i); - - @Nullable - Long getNullableLongObj(); - - void setNullableLongObj(Long i); - - float getFloat(); - - void setFloat(float f); - - Float getFloatObj(); - - void setFloatObj(Float f); - - @Nullable - Float getNullableFloatObj(); - - void setNullableFloatObj(Float f); - - double getDouble(); - - void setDouble(double d); - - Double getDoubleObj(); - - void setDoubleObj(Double d); - - @Nullable - Double getNullableDoubleObj(); - - void setNullableDoubleObj(Double d); - - byte[] getByteArray(); - - void setByteArray(byte[] b); - - @Nullable - byte[] getNullableByteArray(); - - void setNullableByteArray(byte[] b); - - String getString(); - - void setString(String s); - - @Nullable - String getNullableString(); - - void setNullableString(String s); - } -} diff --git a/src/test/java/com/amazon/carbonado/spi/raw/TestKeyEncoding.java b/src/test/java/com/amazon/carbonado/spi/raw/TestKeyEncoding.java deleted file mode 100644 index ae09c92..0000000 --- a/src/test/java/com/amazon/carbonado/spi/raw/TestKeyEncoding.java +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright 2006 Amazon Technologies, Inc. or its affiliates. - * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks - * of Amazon Technologies, Inc. or its affiliates. All rights reserved. - * - * 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.amazon.carbonado.spi.raw; - -import java.util.Random; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Test case for {@link KeyEncoder} and {@link KeyDecoder}. - * <p> - * It generates random data values, checks that the decoding produces the - * original results, and it checks that the order of the encoded bytes matches - * the order of the original data values. - * - * @author Brian S O'Neill - */ -public class TestKeyEncoding extends TestCase { - private static final int SHORT_TEST = 100; - private static final int MEDIUM_TEST = 500; - private static final int LONG_TEST = 1000; - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static TestSuite suite() { - return new TestSuite(TestKeyEncoding.class); - } - - private final long mSeed; - - private Random mRandom; - - public TestKeyEncoding(String name) { - super(name); - mSeed = 5399777425345431L; - } - - protected void setUp() { - mRandom = new Random(mSeed); - } - - protected void tearDown() { - } - - public void test_booleanDesc() throws Exception { - byte[] bytes = new byte[1]; - boolean lastValue = false; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - boolean value = mRandom.nextBoolean(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeBooleanDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_BooleanDesc() throws Exception { - byte[] bytes = new byte[1]; - Boolean lastValue = false; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Boolean value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = mRandom.nextBoolean(); - } - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeBooleanObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_byteDesc() throws Exception { - byte[] bytes = new byte[1]; - byte lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - byte value = (byte) mRandom.nextInt(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeByteDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_ByteDesc() throws Exception { - byte[] bytes = new byte[2]; - Byte lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Byte value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); - } else { - value = (byte) mRandom.nextInt(); - assertEquals(2, KeyEncoder.encodeDesc(value, bytes, 0)); - } - assertEquals(value, KeyDecoder.decodeByteObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_shortDesc() throws Exception { - byte[] bytes = new byte[2]; - short lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - short value = (short) mRandom.nextInt(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeShortDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_ShortDesc() throws Exception { - byte[] bytes = new byte[3]; - Short lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Short value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); - } else { - value = (short) mRandom.nextInt(); - assertEquals(3, KeyEncoder.encodeDesc(value, bytes, 0)); - } - assertEquals(value, KeyDecoder.decodeShortObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_charDesc() throws Exception { - byte[] bytes = new byte[2]; - char lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - char value = (char) mRandom.nextInt(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeCharDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_CharacterDesc() throws Exception { - byte[] bytes = new byte[3]; - Character lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Character value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); - } else { - value = (char) mRandom.nextInt(); - assertEquals(3, KeyEncoder.encodeDesc(value, bytes, 0)); - } - assertEquals(value, KeyDecoder.decodeCharacterObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_intDesc() throws Exception { - byte[] bytes = new byte[4]; - int lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - int value = mRandom.nextInt(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeIntDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_IntegerDesc() throws Exception { - byte[] bytes = new byte[5]; - Integer lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Integer value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); - } else { - value = mRandom.nextInt(); - assertEquals(5, KeyEncoder.encodeDesc(value, bytes, 0)); - } - assertEquals(value, KeyDecoder.decodeIntegerObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_longDesc() throws Exception { - byte[] bytes = new byte[8]; - long lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - long value = mRandom.nextLong(); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeLongDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_LongDesc() throws Exception { - byte[] bytes = new byte[9]; - Long lastValue = 0L; - byte[] lastBytes = null; - for (int i=0; i<SHORT_TEST; i++) { - Long value; - if (mRandom.nextInt(10) == 1) { - value = null; - assertEquals(1, KeyEncoder.encodeDesc(value, bytes, 0)); - } else { - value = mRandom.nextLong(); - assertEquals(9, KeyEncoder.encodeDesc(value, bytes, 0)); - } - assertEquals(value, KeyDecoder.decodeLongObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_floatDesc() throws Exception { - byte[] bytes = new byte[4]; - float lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - float value = Float.intBitsToFloat(mRandom.nextInt()); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeFloatDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_FloatDesc() throws Exception { - byte[] bytes = new byte[4]; - Float lastValue = 0f; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - Float value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = Float.intBitsToFloat(mRandom.nextInt()); - } - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeFloatObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_doubleDesc() throws Exception { - byte[] bytes = new byte[8]; - double lastValue = 0; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - double value = Double.longBitsToDouble(mRandom.nextLong()); - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeDoubleDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_DoubleDesc() throws Exception { - byte[] bytes = new byte[8]; - Double lastValue = 0d; - byte[] lastBytes = null; - for (int i=0; i<LONG_TEST; i++) { - Double value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - value = Double.longBitsToDouble(mRandom.nextLong()); - } - KeyEncoder.encodeDesc(value, bytes, 0); - assertEquals(value, KeyDecoder.decodeDoubleObjDesc(bytes, 0)); - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_String() throws Exception { - String lastValue = null; - byte[] lastBytes = null; - String[] ref = new String[1]; - for (int i=0; i<SHORT_TEST; i++) { - String value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - int length; - switch (mRandom.nextInt(15)) { - default: - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - length = mRandom.nextInt(100); - break; - case 8: case 9: case 10: case 11: - length = mRandom.nextInt(200); - break; - case 12: case 13: - length = mRandom.nextInt(20000); - break; - case 14: - length = mRandom.nextInt(3000000); - break; - } - char[] chars = new char[length]; - for (int j=0; j<length; j++) { - char c; - switch (mRandom.nextInt(7)) { - default: - case 0: case 1: case 2: case 3: - c = (char) mRandom.nextInt(128); - break; - case 4: case 5: - c = (char) mRandom.nextInt(4000); - break; - case 6: - c = (char) mRandom.nextInt(); - break; - } - chars[j] = c; - } - value = new String(chars); - } - - byte[] bytes = new byte[KeyEncoder.calculateEncodedStringLength(value)]; - assertEquals(bytes.length, KeyEncoder.encode(value, bytes, 0)); - assertEquals(bytes.length, KeyDecoder.decodeString(bytes, 0, ref)); - assertEquals(value, ref[0]); - - if (lastBytes != null) { - int sgn = TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_StringDesc() throws Exception { - String lastValue = null; - byte[] lastBytes = null; - String[] ref = new String[1]; - for (int i=0; i<SHORT_TEST; i++) { - String value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - int length; - switch (mRandom.nextInt(15)) { - default: - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - length = mRandom.nextInt(100); - break; - case 8: case 9: case 10: case 11: - length = mRandom.nextInt(200); - break; - case 12: case 13: - length = mRandom.nextInt(20000); - break; - case 14: - length = mRandom.nextInt(3000000); - break; - } - char[] chars = new char[length]; - for (int j=0; j<length; j++) { - char c; - switch (mRandom.nextInt(7)) { - default: - case 0: case 1: case 2: case 3: - c = (char) mRandom.nextInt(128); - break; - case 4: case 5: - c = (char) mRandom.nextInt(4000); - break; - case 6: - c = (char) mRandom.nextInt(); - break; - } - chars[j] = c; - } - value = new String(chars); - } - - byte[] bytes = new byte[KeyEncoder.calculateEncodedStringLength(value)]; - assertEquals(bytes.length, KeyEncoder.encodeDesc(value, bytes, 0)); - assertEquals(bytes.length, KeyDecoder.decodeStringDesc(bytes, 0, ref)); - assertEquals(value, ref[0]); - - - if (lastBytes != null) { - int sgn = -TestDataEncoding.compare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_byteArray() throws Exception { - byte[] lastValue = null; - byte[] lastBytes = null; - byte[][] ref = new byte[1][]; - for (int i=0; i<LONG_TEST; i++) { - byte[] value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - int length = mRandom.nextInt(4000); - value = new byte[length]; - for (int j=0; j<length; j++) { - value[j] = (byte) mRandom.nextInt(); - } - } - - byte[] bytes = new byte[KeyEncoder.calculateEncodedLength(value)]; - assertEquals(bytes.length, KeyEncoder.encode(value, bytes, 0)); - assertEquals(bytes.length, KeyDecoder.decode(bytes, 0, ref)); - if (ref[0] == null) { - assertEquals(value, null); - } else if (value == null) { - assertEquals(value, ref[0]); - } else { - assertEquals(0, TestDataEncoding.byteArrayCompare(value, ref[0], value.length)); - } - - if (lastBytes != null) { - int sgn = TestDataEncoding.byteArrayOrNullCompare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } - - public void test_byteArrayDesc() throws Exception { - byte[] lastValue = null; - byte[] lastBytes = null; - byte[][] ref = new byte[1][]; - for (int i=0; i<LONG_TEST; i++) { - byte[] value; - if (mRandom.nextInt(10) == 1) { - value = null; - } else { - int length = mRandom.nextInt(4000); - value = new byte[length]; - for (int j=0; j<length; j++) { - value[j] = (byte) mRandom.nextInt(); - } - } - - byte[] bytes = new byte[KeyEncoder.calculateEncodedLength(value)]; - assertEquals(bytes.length, KeyEncoder.encodeDesc(value, bytes, 0)); - assertEquals(bytes.length, KeyDecoder.decodeDesc(bytes, 0, ref)); - if (ref[0] == null) { - assertEquals(value, null); - } else if (value == null) { - assertEquals(value, ref[0]); - } else { - assertEquals(0, TestDataEncoding.byteArrayCompare(value, ref[0], value.length)); - } - - if (lastBytes != null) { - int sgn = -TestDataEncoding.byteArrayOrNullCompare(value, lastValue); - assertEquals(sgn, TestDataEncoding.byteArrayCompare(bytes, lastBytes)); - } - lastValue = value; - lastBytes = bytes.clone(); - } - } -} -- cgit v1.2.3