package org.apache.lucene.util; /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.util.Random; import java.nio.CharBuffer; import java.nio.ByteBuffer; public class TestIndexableBinaryStringTools extends LuceneTestCase { private static final int NUM_RANDOM_TESTS = 20000; private static final int MAX_RANDOM_BINARY_LENGTH = 300; public void testSingleBinaryRoundTrip() { byte[] binary = new byte[] { (byte)0x23, (byte)0x98, (byte)0x13, (byte)0xE4, (byte)0x76, (byte)0x41, (byte)0xB2, (byte)0xC9, (byte)0x7F, (byte)0x0A, (byte)0xA6, (byte)0xD8 }; ByteBuffer binaryBuf = ByteBuffer.wrap(binary); CharBuffer encoded = IndexableBinaryStringTools.encode(binaryBuf); ByteBuffer decoded = IndexableBinaryStringTools.decode(encoded); assertEquals("Round trip decode/decode returned different results:" + System.getProperty("line.separator") + "original: " + binaryDump(binaryBuf) + System.getProperty("line.separator") + " encoded: " + charArrayDump(encoded) + System.getProperty("line.separator") + " decoded: " + binaryDump(decoded), binaryBuf, decoded); } public void testEncodedSortability() { Random random = newRandom(); byte[] originalArray1 = new byte[MAX_RANDOM_BINARY_LENGTH]; ByteBuffer originalBuf1 = ByteBuffer.wrap(originalArray1); char[] originalString1 = new char[MAX_RANDOM_BINARY_LENGTH]; CharBuffer originalStringBuf1 = CharBuffer.wrap(originalString1); char[] encoded1 = new char[IndexableBinaryStringTools.getEncodedLength(originalBuf1)]; CharBuffer encodedBuf1 = CharBuffer.wrap(encoded1); byte[] original2 = new byte[MAX_RANDOM_BINARY_LENGTH]; ByteBuffer originalBuf2 = ByteBuffer.wrap(original2); char[] originalString2 = new char[MAX_RANDOM_BINARY_LENGTH]; CharBuffer originalStringBuf2 = CharBuffer.wrap(originalString2); char[] encoded2 = new char[IndexableBinaryStringTools.getEncodedLength(originalBuf2)]; CharBuffer encodedBuf2 = CharBuffer.wrap(encoded2); for (int testNum = 0 ; testNum < NUM_RANDOM_TESTS ; ++testNum) { int numBytes1 = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1; // Min == 1 originalBuf1.limit(numBytes1); originalStringBuf1.limit(numBytes1); for (int byteNum = 0 ; byteNum < numBytes1 ; ++byteNum) { int randomInt = random.nextInt(0x100); originalArray1[byteNum] = (byte) randomInt; originalString1[byteNum] = (char)randomInt; } int numBytes2 = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1; // Min == 1 originalBuf2.limit(numBytes2); originalStringBuf2.limit(numBytes2); for (int byteNum = 0 ; byteNum < numBytes2 ; ++byteNum) { int randomInt = random.nextInt(0x100); original2[byteNum] = (byte)randomInt; originalString2[byteNum] = (char)randomInt; } int originalComparison = originalStringBuf1.compareTo(originalStringBuf2); originalComparison = originalComparison < 0 ? -1 : originalComparison > 0 ? 1 : 0; IndexableBinaryStringTools.encode(originalBuf1, encodedBuf1); IndexableBinaryStringTools.encode(originalBuf2, encodedBuf2); int encodedComparison = encodedBuf1.compareTo(encodedBuf2); encodedComparison = encodedComparison < 0 ? -1 : encodedComparison > 0 ? 1 : 0; assertEquals("Test #" + (testNum + 1) + ": Original bytes and encoded chars compare differently:" + System.getProperty("line.separator") + " binary 1: " + binaryDump(originalBuf1) + System.getProperty("line.separator") + " binary 2: " + binaryDump(originalBuf2) + System.getProperty("line.separator") + "encoded 1: " + charArrayDump(encodedBuf1) + System.getProperty("line.separator") + "encoded 2: " + charArrayDump(encodedBuf2) + System.getProperty("line.separator"), originalComparison, encodedComparison); } } public void testEmptyInput() { byte[] binary = new byte[0]; CharBuffer encoded = IndexableBinaryStringTools.encode(ByteBuffer.wrap(binary)); ByteBuffer decoded = IndexableBinaryStringTools.decode(encoded); assertNotNull("decode() returned null", decoded); assertEquals("decoded empty input was not empty", decoded.limit(), 0); } public void testAllNullInput() { byte[] binary = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ByteBuffer binaryBuf = ByteBuffer.wrap(binary); CharBuffer encoded = IndexableBinaryStringTools.encode(binaryBuf); assertNotNull("encode() returned null", encoded); ByteBuffer decodedBuf = IndexableBinaryStringTools.decode(encoded); assertNotNull("decode() returned null", decodedBuf); assertEquals("Round trip decode/decode returned different results:" + System.getProperty("line.separator") + " original: " + binaryDump(binaryBuf) + System.getProperty("line.separator") + "decodedBuf: " + binaryDump(decodedBuf), binaryBuf, decodedBuf); } public void testRandomBinaryRoundTrip() { Random random = newRandom(); byte[] binary = new byte[MAX_RANDOM_BINARY_LENGTH]; ByteBuffer binaryBuf = ByteBuffer.wrap(binary); char[] encoded = new char[IndexableBinaryStringTools.getEncodedLength(binaryBuf)]; CharBuffer encodedBuf = CharBuffer.wrap(encoded); byte[] decoded = new byte[MAX_RANDOM_BINARY_LENGTH]; ByteBuffer decodedBuf = ByteBuffer.wrap(decoded); for (int testNum = 0 ; testNum < NUM_RANDOM_TESTS ; ++testNum) { int numBytes = random.nextInt(MAX_RANDOM_BINARY_LENGTH - 1) + 1 ; // Min == 1 binaryBuf.limit(numBytes); for (int byteNum = 0 ; byteNum < numBytes ; ++byteNum) { binary[byteNum] = (byte)random.nextInt(0x100); } IndexableBinaryStringTools.encode(binaryBuf, encodedBuf); IndexableBinaryStringTools.decode(encodedBuf, decodedBuf); assertEquals("Test #" + (testNum + 1) + ": Round trip decode/decode returned different results:" + System.getProperty("line.separator") + " original: " + binaryDump(binaryBuf) + System.getProperty("line.separator") + "encodedBuf: " + charArrayDump(encodedBuf) + System.getProperty("line.separator") + "decodedBuf: " + binaryDump(decodedBuf), binaryBuf, decodedBuf); } } public String binaryDump(ByteBuffer binaryBuf) { StringBuilder buf = new StringBuilder(); int numBytes = binaryBuf.limit() - binaryBuf.arrayOffset(); byte[] binary = binaryBuf.array(); for (int byteNum = 0 ; byteNum < numBytes ; ++byteNum) { String hex = Integer.toHexString((int)binary[byteNum] & 0xFF); if (hex.length() == 1) { buf.append('0'); } buf.append(hex.toUpperCase()); if (byteNum < numBytes - 1) { buf.append(' '); } } return buf.toString(); } public String charArrayDump(CharBuffer charBuf) { StringBuilder buf = new StringBuilder(); int numBytes = charBuf.limit() - charBuf.arrayOffset(); char[] charArray = charBuf.array(); for (int charNum = 0 ; charNum < numBytes ; ++charNum) { String hex = Integer.toHexString((int)charArray[charNum]); for (int digit = 0 ; digit < 4 - hex.length() ; ++digit) { buf.append('0'); } buf.append(hex.toUpperCase()); if (charNum < numBytes - 1) { buf.append(' '); } } return buf.toString(); } }