/* * 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. */ package org.apache.solr.util.hll; import java.util.Random; import org.apache.lucene.util.LuceneTestCase; import org.junit.Test; import static com.carrotsearch.randomizedtesting.RandomizedTest.*; /** * Unit and smoke tests for {@link BigEndianAscendingWordDeserializer}. */ public class BigEndianAscendingWordDeserializerTest extends LuceneTestCase { /** * Error checking tests for constructor. */ @Test public void constructorErrorTest() { // word length too small try { new BigEndianAscendingWordDeserializer(0/*wordLength, below minimum of 1*/, 0/*bytePadding, arbitrary*/, new byte[1]/*bytes, arbitrary, not used here*/); fail("Should complain about too-short words."); } catch(final IllegalArgumentException e) { assertTrue(e.getMessage().contains("Word length must be")); } // word length too large try { new BigEndianAscendingWordDeserializer(65/*wordLength, above maximum of 64*/, 0/*bytePadding, arbitrary*/, new byte[1]/*bytes, arbitrary, not used here*/); fail("Should complain about too-long words."); } catch(final IllegalArgumentException e) { assertTrue(e.getMessage().contains("Word length must be")); } // byte padding negative try { new BigEndianAscendingWordDeserializer(5/*wordLength, arbitrary*/, -1/*bytePadding, too small*/, new byte[1]/*bytes, arbitrary, not used here*/); fail("Should complain about negative byte padding."); } catch(final IllegalArgumentException e) { assertTrue(e.getMessage().contains("Byte padding must be")); } } /** * Smoke test using 64-bit short words and special word values. */ @Test public void smokeTest64BitWord() { final BigEndianAscendingWordSerializer serializer = new BigEndianAscendingWordSerializer(64/*wordLength*/, 5/*wordCount*/, 0/*bytePadding, arbitrary*/); // Check that the sign bit is being preserved. serializer.writeWord(-1L); serializer.writeWord(-112894714L); // Check "special" values serializer.writeWord(0L); serializer.writeWord(Long.MAX_VALUE); serializer.writeWord(Long.MIN_VALUE); final byte[] bytes = serializer.getBytes(); final BigEndianAscendingWordDeserializer deserializer = new BigEndianAscendingWordDeserializer(64/*wordLength*/, 0/*bytePadding*/, bytes); assertEquals(deserializer.totalWordCount(), 5/*wordCount*/); assertEquals(deserializer.readWord(), -1L); assertEquals(deserializer.readWord(), -112894714L); assertEquals(deserializer.readWord(), 0L); assertEquals(deserializer.readWord(), Long.MAX_VALUE); assertEquals(deserializer.readWord(), Long.MIN_VALUE); } /** * A smoke/fuzz test for ascending (from zero) word values. */ @Test public void ascendingSmokeTest() { for(int wordLength=5; wordLength<65; wordLength++) { runAscendingTest(wordLength, 3/*bytePadding, arbitrary*/, 100000/*wordCount, arbitrary*/); } } /** * A smoke/fuzz test for random word values. */ @Test public void randomSmokeTest() { for(int wordLength=5; wordLength<65; wordLength++) { runRandomTest(wordLength, 3/*bytePadding, arbitrary*/, 100000/*wordCount, arbitrary*/); } } // ------------------------------------------------------------------------ /** * Runs a test which serializes and deserializes random word values. * * @param wordLength the length of words to test * @param bytePadding the number of bytes padding the byte array * @param wordCount the number of word values to test */ private static void runRandomTest(final int wordLength, final int bytePadding, final int wordCount) { final long seed = randomLong(); final Random random = new Random(seed); final Random verificationRandom = new Random(seed); final long wordMask; if(wordLength == 64) { wordMask = ~0L; } else { wordMask = (1L << wordLength) - 1L; } final BigEndianAscendingWordSerializer serializer = new BigEndianAscendingWordSerializer(wordLength/*wordLength, arbitrary*/, wordCount, bytePadding/*bytePadding, arbitrary*/); for(int i=0; i<wordCount; i++) { final long value = random.nextLong() & wordMask; serializer.writeWord(value); } final byte[] bytes = serializer.getBytes(); final BigEndianAscendingWordDeserializer deserializer = new BigEndianAscendingWordDeserializer(wordLength, bytePadding, bytes); assertEquals(deserializer.totalWordCount(), wordCount); for(int i=0; i<wordCount; i++) { assertEquals(deserializer.readWord(), (verificationRandom.nextLong() & wordMask)); } } /** * Runs a test which serializes and deserializes ascending (from zero) word values. * * @param wordLength the length of words to test * @param bytePadding the number of bytes padding the byte array * @param wordCount the number of word values to test */ private static void runAscendingTest(final int wordLength, final int bytePadding, final int wordCount) { final long wordMask; if(wordLength == 64) { wordMask = ~0L; } else { wordMask = (1L << wordLength) - 1L; } final BigEndianAscendingWordSerializer serializer = new BigEndianAscendingWordSerializer(wordLength/*wordLength, arbitrary*/, wordCount, bytePadding/*bytePadding, arbitrary*/); for(long i=0; i<wordCount; i++) { serializer.writeWord(i & wordMask); } final byte[] bytes = serializer.getBytes(); final BigEndianAscendingWordDeserializer deserializer = new BigEndianAscendingWordDeserializer(wordLength, bytePadding, bytes); assertEquals(deserializer.totalWordCount(), wordCount); for(long i=0; i<wordCount; i++) { assertEquals(deserializer.readWord(), i & wordMask); } } }