/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Jan 16, 2007
*/
package com.bigdata.btree;
import junit.framework.TestCase2;
import com.bigdata.btree.keys.IKeyBuilder;
import com.bigdata.btree.keys.KeyBuilder;
import com.bigdata.util.BytesUtil;
/**
* Test suite for low-level operations on variable length byte[]s.
*
* @see BytesUtil
*
* @todo test with JNI integration.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestBytesUtil extends TestCase2 {
/**
*
*/
public TestBytesUtil() {
}
/**
* @param name
*/
public TestBytesUtil(String name) {
super(name);
}
public void test_getByteCount() {
try {
BytesUtil.getByteCount(null);
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
try {
BytesUtil.getByteCount("");
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
try {
BytesUtil.getByteCount("3x");
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
try {
BytesUtil.getByteCount("x2");
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
assertEquals(3, BytesUtil.getByteCount("3"));
assertEquals(3 * 1024L, BytesUtil.getByteCount("3k"));
assertEquals(3 * 1024L, BytesUtil.getByteCount("3kb"));
assertEquals(3 * 1024L, BytesUtil.getByteCount("3K"));
assertEquals(3 * 1024L, BytesUtil.getByteCount("3KB"));
assertEquals(3 * 1024L, BytesUtil.getByteCount("3Kb"));
assertEquals(3 * 1024 * 1024L, BytesUtil.getByteCount("3m"));
assertEquals(3 * 1024 * 1024L, BytesUtil.getByteCount("3mb"));
assertEquals(3 * 1024 * 1024L, BytesUtil.getByteCount("3M"));
assertEquals(3 * 1024 * 1024L, BytesUtil.getByteCount("3MB"));
assertEquals(3 * 1024 * 1024L, BytesUtil.getByteCount("3Mb"));
assertEquals(3 * 1024 * 1024 * 1024L, BytesUtil.getByteCount("3g"));
assertEquals(3 * 1024 * 1024 * 1024L, BytesUtil.getByteCount("3gb"));
assertEquals(3 * 1024 * 1024 * 1024L, BytesUtil.getByteCount("3G"));
assertEquals(3 * 1024 * 1024 * 1024L, BytesUtil.getByteCount("3GB"));
assertEquals(3 * 1024 * 1024 * 1024L, BytesUtil.getByteCount("3Gb"));
}
/**
* A byte has a signed value between -128 and 127.
*
* Note: we need to compare bytes as unsigned values. You can convert to a
* signed integer using
*
* <pre>
* byte b = ...;
* int signed_b = b & 0xff;
* </pre>
*/
public void test_compareBytesSigned() {
byte bmin = Byte.MIN_VALUE;
byte b0 = 0;
byte bmax = Byte.MAX_VALUE;
assertEquals(-128,bmin);
assertEquals(127,bmax);
// signed byte comparisons.
assertTrue(bmin<b0);
assertTrue(bmin<bmax);
assertTrue(b0<bmax);
// unsigned byte comparisons.
assertTrue((bmin&0xff)>bmax);
assertTrue((bmax&0xff)>b0);
}
/**
* Test comparison of two variable length signed byte[]s.
*/
public void test_compareBytes() {
/*
* test version with no offsets.
*/
assertEquals(0, BytesUtil.compareBytes(//
new byte[] { 1, 3, 2 },
new byte[] { 1, 3, 2 }));
// differ at index := 2 and a<b.
assertTrue(BytesUtil.compareBytes(//
new byte[] { 1, 3 }, //
new byte[] { 1, 3, 2 }//
) < 0);
// differ at index := 2 and a>b.
assertTrue(BytesUtil.compareBytes(//
new byte[] { 1, 3, 2 },//
new byte[] { 1, 3 }//
) > 0);
/*
* validate comparator treat bytes as unsigned. -1 expressed as a
* unsigned byte is larger than the largest signed byte.
*/
assertTrue(BytesUtil.compareBytes(//
new byte[] { -1 },//
new byte[] { Byte.MAX_VALUE }//
) > 0);
}
/**
* Test of unsigned byte[] comparison with explicit offset into each array
* and #of bytes to consider from that offset for each array.
*/
public void test_compareBytesWithOffsetAndLength() {
/*
* test with zero offsets and true lengths.
*/
assertEquals(0, BytesUtil.compareBytesWithLenAndOffset(//
0, 3, new byte[] { 1, 3, 2 },//
0, 3, new byte[] { 1, 3, 2 }//
));
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
0, 2, new byte[] { 1, 3 },//
0, 3, new byte[] { 1, 3, 2 }//
) < 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
0, 3, new byte[] { 1, 3, 2 },//
0, 2, new byte[] { 1, 3 }//
) > 0);
/*
* test with non-zero offsets and all remaining bytes are compared.
*/
assertEquals(0, BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { 9, 1, 3, 2 },//
0, 3, new byte[] { 1, 3, 2 }//
));
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 2, new byte[] { 9, 1, 3 },//
0, 3, new byte[] { 1, 3, 2 }//
) < 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { -9, 1, 3, 2 },//
0, 2, new byte[] { 1, 3 }//
) > 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { 9, 1, 3, 2 },//
0, 4, new byte[] { 1, 3, 2, 1 }//
) < 0);
/*
* test with non-zero offsets and only some of the remaining bytes are
* compared.
*/
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 2, new byte[] { 9, 1, 3, 2 },// using {1,3}
0, 2, new byte[] { 1, 3, 3, 1 }// using {1,3}
) == 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 2, new byte[] { 9, 1, 3, 2 },// using {1,3}
0, 3, new byte[] { 1, 3, 3, 1 }// using {1,3,3}
) < 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { 9, 1, 3, 2 },// using {1,3,2}
0, 2, new byte[] { 1, 3, 3, 1 }// using {1,3}
) > 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { 9, 1, 3, 2 },// using {1,3,2}
0, 3, new byte[] { 1, 3, 3, 1 }// using {1,3,3}
) < 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
1, 3, new byte[] { 9, 1, 3, 2 },// using {1,3,2}
0, 4, new byte[] { 1, 3, 3, 1 }// using {1,3,3,1}
) < 0);
assertTrue(BytesUtil.compareBytesWithLenAndOffset(//
0, 4, new byte[] { 9, 1, 3, 2 },// using {9,1,3,2}
0, 4, new byte[] { 1, 3, 3, 1 }// using {1,3,3,1}
) > 0);
}
/**
* Test method that returns the length of the longest common prefix for two
* keys.
*/
public void test_getPrefixLength() {
assertEquals(0, BytesUtil.getPrefixLength(new byte[] { 1 },
new byte[] { 2 }));
assertEquals(1, BytesUtil.getPrefixLength(new byte[] { 1 },
new byte[] { 1 }));
assertEquals(2, BytesUtil.getPrefixLength(new byte[] { 1, 2, 3 },
new byte[] { 1, 2, 4 }));
assertEquals(2, BytesUtil.getPrefixLength(new byte[] { 1, 2 },
new byte[] { 1, 2, 4 }));
}
/**
* Test method that returns the longest common prefix for two keys.
*/
public void test_getPrefix() {
assertEquals(new byte[] {}, BytesUtil.getPrefix(new byte[] { 1 },
new byte[] { 2 }));
assertEquals(new byte[] { 1 }, BytesUtil.getPrefix(new byte[] { 1 },
new byte[] { 1 }));
assertEquals(new byte[] { 1, 2 }, BytesUtil.getPrefix(new byte[] { 1,
2, 3 }, new byte[] { 1, 2, 4 }));
assertEquals(new byte[] { 1, 2 }, BytesUtil.getPrefix(
new byte[] { 1, 2 }, new byte[] { 1, 2, 4 }));
}
/**
* Verify the semantics of the successor of a byte[] and that the successor
* is computed correctly by {@link BytesUtil#successor(byte[])}.
*/
public void test_successor() {
/*
* verify that compareBytes believes that the successor is formed by
* appending a zero(0) byte.
*/
assertTrue(BytesUtil.compareBytes(new byte[]{}, new byte[]{0})<0);
assertTrue(BytesUtil.compareBytes(new byte[]{1}, new byte[]{1,0})<0);
assertTrue(BytesUtil.compareBytes(new byte[]{1,0}, new byte[]{2})<0);
assertTrue(BytesUtil.compareBytes(new byte[]{minSignedByte}, new byte[]{0})>0);
assertTrue(BytesUtil.compareBytes(new byte[]{maxSignedByte}, new byte[]{0})>0);
{
byte[] zero = new byte[] { 0 };
byte[] a = new byte[1];
for (int i = minSignedByte; i <= maxSignedByte; i++) {
a[0] = (byte) (i & 0xff);
if(a[0]==zero[0]) continue; // skip over zero.
assertTrue(BytesUtil.compareBytes(a, zero) > 0);
}
}
// successor of an empty byte[].
assertEquals(new byte[]{0}, BytesUtil.successor(new byte[]{}));
// successor of a non-empty byte[].
assertEquals(new byte[]{1,3,1,0}, BytesUtil.successor(new byte[]{1,3,1}));
}
final private byte maxSignedByte = 127;
final private byte minSignedByte = -128;
/**
* Test logic to add one to an unsigned byte in Java. A byte in Java is a
* signed value, so we have to convert to and from a signed quantity with a
* larger range in order to do this operation.
*
* 127 is the maximum value for a signed byte.
*
* Adding 1 to 127 produces the bit pattern for -128. Contining to add one
* to -128 progresses the value to -127, -126, -125, ..., -1. The bit
* pattern for -1 is 0xff, which is 255 when interpreted as an unsigned
* byte.
*
* A safe operation for adding one to an unsigned byte must first check
* whether the value of the byte is -1, in which case adding one would cause
* overflow and result in a bit pattern of all zeros.
*
* @see http://en.wikipedia.org/wiki/Two's_complement
*/
public void test_unsignedByteInc() {
assertEquals( (byte)-128, (byte)((((byte) 127) & 0xff) + 1));
assertEquals( (byte)-127, (byte)((((byte)-128) & 0xff) + 1));
byte b = 0;
byte[] seq = new byte[256];
int n = 0;
seq[n++] = b;
while( b != -1 ) {
b = (byte)(((b) & 0xff) + 1);
seq[n++] = b;
}
if(log.isInfoEnabled())
log.info(BytesUtil.toString(seq));
/*
* verify bytes in sequence corresponding to [0:255] when interpreted as
* integers having a sufficent range to express the values.
*/
for(int i=0; i<255; i++) {
assertEquals(i, (seq[i] & 0xff));
}
}
/**
* Test method that chooses the shortest key that is less than one key but
* greater than another.
*/
public void test_getSeparatorKey() {
/*
* Bigbird, Burt, Cookiemonster, Ernie, Snuffleopogus
*/
{
// instance does not support unicode
IKeyBuilder keyBuilder = KeyBuilder.newInstance();
// first key for new right sibling : convert ASCII to byte[].
byte[] givenKey = keyBuilder.reset().appendASCII("CookieMonster").getKey();
assertEquals('C',(char)KeyBuilder.decodeByte(givenKey[0]));
// last key for current node (prior key): convert ASCII to byte[].
byte[] priorKey = keyBuilder.reset().appendASCII("Ernie").getKey();
byte[] separatorKey = BytesUtil.getSeparatorKey(givenKey,priorKey);
assertEquals(1,separatorKey.length);
assertEquals('C',(char)KeyBuilder.decodeByte(separatorKey[0]));
}
/*
* Tests where the keys are in the correct order and differ only in the
* last byte of the _givenKey_, including the case where the prior key
* is a prefix of the given key and is lacking only the last byte of the
* given key. In this case the givenKey is always returned to the caller
* (by reference).
*/
{
byte[] givenKey = new byte[]{1,2,2};
assertTrue(givenKey == BytesUtil.getSeparatorKey(givenKey, new byte[]{1,2,1}));
assertTrue(givenKey == BytesUtil.getSeparatorKey(givenKey, new byte[]{1,2,1,2}));
assertTrue(givenKey == BytesUtil.getSeparatorKey(givenKey, new byte[]{1,2,0}));
assertTrue(givenKey == BytesUtil.getSeparatorKey(givenKey, new byte[]{1,2,0,2}));
assertTrue(givenKey == BytesUtil.getSeparatorKey(givenKey, new byte[]{1,2}));
}
/*
* Edge case. The prior key is an empty byte[].
*/
{
byte[] given = new byte[]{7};
byte[] prior = new byte[]{};
assertEquals(given, // separator
BytesUtil.getSeparatorKey(//
given,//
prior //
));
}
/*
* Tests in which there is a zero length shared prefix. In this case the
* separator is always byte[1] and contains the first byte from the
* given key.
*/
{
assertEquals(new byte[] {3}, // separator
BytesUtil.getSeparatorKey(//
new byte[] { 3, 5, 7 },// given
new byte[] { 1, 5, 7 }// prior
));
assertEquals(new byte[] {7}, // separator
BytesUtil.getSeparatorKey(//
new byte[] { 7 },// given
new byte[] { 5, 1 }// prior
));
}
/*
* Tests in which there is a non-zero length shared prefix but the keys
* differ before the last byte. In this case the separator is formed
* from all bytes in the shared prefix plus the next byte from the given
* key.
*/
{
assertEquals(new byte[] {7, 1}, // separator
BytesUtil.getSeparatorKey(//
new byte[] { 7, 1, 3 },// given
new byte[] { 7, } // prior
));
assertEquals(new byte[] {7, 1, 1}, // separator
BytesUtil.getSeparatorKey(//
new byte[] { 7, 1, 1, 3 },// given
new byte[] { 7, 1 } // prior
));
}
}
public void test_getSeparatorKey_correctRejection() {
try { // null parameter.
BytesUtil.getSeparatorKey(null, new byte[]{2});
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
try { // null parameter.
BytesUtil.getSeparatorKey(new byte[]{2},null);
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
try { // same reference (so givenKey and priorKey must be equal).
byte[] tmp = new byte[]{2};
BytesUtil.getSeparatorKey(tmp,tmp);
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
/*
* I have commented out the rest of the correct rejection tests. This
* makes the code must more complex in getSeparatorKey() and you have to
* compare bytes as unsigned values to get it right, which adds to the
* complexity again. I don't see the need for these tests since the
* B+Tree is never presenting the arguments out of order - the various
* stress tests demonstrate that it correctly maintains its order
* regardless.
*/
// /*
// * given [1,2,3] and [1,2] , prefixLength=2 -- ok.
// * given [1,2,3] and [1,2,2] , prefixLength=2 -- ok.
// * given [1,2,3] and [1,2,2,3], prefixLength=2 -- ok.
// * given [1,2,3] and [1,2,3] , prefixLength=3 -- keys out of order.
// * given [1,2,3] and [1,2,4] , prefixLength=2 -- keys out of order.
// * given [1,3] and [1,2,4] , prefixLength=1 -- ok.
// */
// BytesUtil.getSeparatorKey(new byte[]{1,2,3},new byte[]{1,2}); // legal
// BytesUtil.getSeparatorKey(new byte[]{1,2,3},new byte[]{1,2,2}); // legal
// BytesUtil.getSeparatorKey(new byte[]{1,2,3},new byte[]{1,2,2,3}); // legal
// try { // keys out of order.
// BytesUtil.getSeparatorKey(new byte[]{1,2,3},new byte[]{1,2,3}); // illegal
// fail("Expecting: "+IllegalArgumentException.class);
// } catch(IllegalArgumentException ex) {
// System.err.println("Ignoring expected exception: "+ex);
// }
// try { // keys out of order.
// BytesUtil.getSeparatorKey(new byte[]{1,2,3},new byte[]{1,2,4}); // illegal
// fail("Expecting: "+IllegalArgumentException.class);
// } catch(IllegalArgumentException ex) {
// System.err.println("Ignoring expected exception: "+ex);
// }
// BytesUtil.getSeparatorKey(new byte[]{1,3},new byte[]{1,2,4}); // legal
}
/**
* A series of test cases for binary search for a "key" in an array of keys
* with an adjustable base (starting offset) and length (#of members). This
* tests for "key not found" resulting in a variety of insertion points
* (including before and after all records in the array) as well as for key
* found at a variety of locations. The first and last members of the array
* are then "hidden" by shifting the base and reducing the #of declared
* array elements and the tests are repeated in the new context to verify
* that the base and nmem parameters are correctly respected.
*/
public void test_binarySearch01()
{
final int capacity = 5;
final byte[][] keys = new byte[ capacity ][];
int base = 0;
int nmem = 5;
// The general formula for the record offset is:
//
// offset := sizeof(record) * ( index - 1 )
//
// The general formula for the insertion point is:
//
// insert := - ( offset + 1 )
//
// where [offset] is the offset of the record before which the
// new record should be inserted.
int i = 0;
keys[ i ++ ] = new byte[]{ 5 }; // offset := 0, insert before := -1
keys[ i ++ ] = new byte[]{ 7 }; // offset := 1, insert before := -2
keys[ i ++ ] = new byte[]{ 9 }; // offset := 2, insert before := -3
keys[ i ++ ] = new byte[]{ 11 }; // offset := 3, insert before := -4
keys[ i ++ ] = new byte[]{ 13 }; // offset := 4, insert before := -5
// insert after := -6
//
// verify offset of record found.
//
// Verify finds the first record in the array.
assertEquals
( 0,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 5 }
)
);
// Verify finds the 2nd record in the array.
assertEquals
( 1,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 7 }
)
);
// Verify finds the penultimate record in the array.
assertEquals
( 3,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 11 }
)
);
// Verify finds the last record in the array.
assertEquals
( 4,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 13 }
)
);
//
// verify insertion points (key not found).
//
// Verify insertion point for key less than any value in the
// array.
assertEquals
( -1,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 4 }
)
);
// Verify insertion point for key between first and 2nd
// records.
assertEquals
( -2,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 6 }
)
);
// Verify insertion point for key between penultimate and last
// records.
assertEquals
( -5,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 12 }
)
);
// Verify insertion point for key greater than the last record.
assertEquals
( -6,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 14 }
)
);
//
// Shift the array base and the #of members so that only the
// three records in the middle of the array are "exposed" to
// the search and then do a series of tests to verify that the
// [base] and [nmem] parameters are being correctly respected.
//
base++; // hides the first record.
nmem -= 2; // hides the last record (we have to
// subtract two since we are actually
// hiding two members).
//
// Verify offset of "hidden" records, which now qualify as
// "not found".
//
// Verify does not find the first record in the array (which
// is now "hidden").
assertEquals
( -2,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 5 }
)
);
// Verify does not find the last record in the array (which is
// now hidden).
assertEquals
( -5,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 13 }
)
);
//
// verify offset of record found.
//
// Verify finds the 2nd record in the array (the first that is
// now visible).
assertEquals
( 1,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 7 }
)
);
// Verify finds the 3rd record in the array (the 2nd that is
// now visible).
assertEquals
( 2,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 9 }
)
);
// Verify finds the penultimate record in the array (the 3rd
// and last that is now visibile).
assertEquals
( 3,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 11 }
)
);
//
// verify insertion points (keys not found in either the
// hidden or the full array).
//
// buf[ i ++ ] = 7L ; // offset := 1, insert before := -2
// buf[ i ++ ] = 9L ; // offset := 2, insert before := -3
// buf[ i ++ ] = 11L ; // offset := 3, insert before := -4
// insert after := -5
// Verify insertion point for key less than any value in the
// array.
assertEquals
( -2,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 6 }
)
);
// Verify insertion point for key between first and 2nd
// visible records.
assertEquals
( -3,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 8 }
)
);
// Verify insertion point for key between 2nd and 3rd visible
// records.
assertEquals
( -4,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 10 }
)
);
// Verify insertion point for key afer the last visible
// record.
assertEquals
( -5,
BytesUtil.binarySearch
( keys, base, nmem, new byte[]{ 12 }
)
);
}
/*
* Bit operations
*/
public void test_bitFlagByteLength() {
assertEquals(0,BytesUtil.bitFlagByteLength(0));
assertEquals(1,BytesUtil.bitFlagByteLength(1));
assertEquals(1,BytesUtil.bitFlagByteLength(2));
assertEquals(1,BytesUtil.bitFlagByteLength(3));
assertEquals(1,BytesUtil.bitFlagByteLength(4));
assertEquals(1,BytesUtil.bitFlagByteLength(5));
assertEquals(1,BytesUtil.bitFlagByteLength(6));
assertEquals(1,BytesUtil.bitFlagByteLength(7));
assertEquals(1,BytesUtil.bitFlagByteLength(8));
assertEquals(2,BytesUtil.bitFlagByteLength(9));
}
public void test_bitSetTest() {
final int nbits = 12;
for (long bitIndex = 0; bitIndex < nbits; bitIndex++) {
final byte[] buf = new byte[BytesUtil.bitFlagByteLength(nbits)];
// should be clear
assertEquals("get(" + bitIndex + ")", false, BytesUtil.getBit(buf,
bitIndex));
// set
assertEquals("set(" + bitIndex + ")", false, BytesUtil.setBit(buf,
bitIndex, true));
// should be set.
assertEquals("get(" + bitIndex + ")", true, BytesUtil.getBit(buf,
bitIndex));
// clear
assertEquals("set(" + bitIndex + ")", true, BytesUtil.setBit(buf,
bitIndex, false));
// should be clear
assertEquals("get(" + bitIndex + ")", false, BytesUtil.getBit(buf,
bitIndex));
}
}
/**
* Correct rejection tests for {@link BytesUtil#getMSBMask(int)}
*/
public void test_getMaskBits_correctRejection() {
try {
BytesUtil.getMSBMask(-1);
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
// ignore
}
try {
BytesUtil.getMSBMask(33);
fail("Expecting: "+IllegalArgumentException.class);
} catch(IllegalArgumentException ex) {
// ignore
}
}
/**
* Unit test for {@link BytesUtil#getMSBMask(int)}
*/
public void test_getMaskBits() {
assertEquals(0x00000000, getMSBMask(0));
assertEquals(0x80000000, getMSBMask(1));
assertEquals(0xc0000000, getMSBMask(2));
assertEquals(0xe0000000, getMSBMask(3));
assertEquals(0xf0000000, getMSBMask(4));
assertEquals(0xf8000000, getMSBMask(5));
assertEquals(0xfc000000, getMSBMask(6));
assertEquals(0xfe000000, getMSBMask(7));
assertEquals(0xff000000, getMSBMask(8));
assertEquals(0xff800000, getMSBMask(9));
assertEquals(0xffc00000, getMSBMask(10));
assertEquals(0xffe00000, getMSBMask(11));
assertEquals(0xfff00000, getMSBMask(12));
assertEquals(0xfff80000, getMSBMask(13));
assertEquals(0xfffc0000, getMSBMask(14));
assertEquals(0xfffe0000, getMSBMask(15));
assertEquals(0xffff0000, getMSBMask(16));
assertEquals(0xffff8000, getMSBMask(17));
assertEquals(0xffffc000, getMSBMask(18));
assertEquals(0xffffe000, getMSBMask(19));
assertEquals(0xfffff000, getMSBMask(20));
assertEquals(0xfffff800, getMSBMask(21));
assertEquals(0xfffffc00, getMSBMask(22));
assertEquals(0xfffffe00, getMSBMask(23));
assertEquals(0xffffff00, getMSBMask(24));
assertEquals(0xffffff80, getMSBMask(25));
assertEquals(0xffffffc0, getMSBMask(26));
assertEquals(0xffffffe0, getMSBMask(27));
assertEquals(0xfffffff0, getMSBMask(28));
assertEquals(0xfffffff8, getMSBMask(29));
assertEquals(0xfffffffc, getMSBMask(30));
assertEquals(0xfffffffe, getMSBMask(31));
assertEquals(0xffffffff, getMSBMask(32));
}
/**
* Test help logs the {@link BytesUtil#getMSBMask(int)} results for
* inspection.
*
* @param nbits
* The #of bits whose MSB mask is desired.
*
* @return The MSB mask.
*/
private int getMSBMask(final int nbits) {
final int mask = BytesUtil.getMSBMask(nbits);
if(log.isInfoEnabled()) {
System.err.printf("%2d : [%32s]\n", nbits, Integer.toBinaryString(mask));
}
return mask;
}
/**
* Unit test for {@link BytesUtil#maskOffMSB(int, int)}
*/
public void test_maskOff() {
assertEquals(0x00000003, BytesUtil.maskOffMSB(0xffffffff/* key */, 2/* nbits */));
assertEquals(0x00000003, BytesUtil.maskOffMSB(0xc0000000/* key */, 2/* nbits */));
assertEquals(0x00000006, BytesUtil.maskOffMSB(0xc0000000/* key */, 3/* nbits */));
assertEquals(0x0000000c, BytesUtil.maskOffMSB(0xc0000000/* key */, 4/* nbits */));
assertEquals(0x00000018, BytesUtil.maskOffMSB(0xc0000000/* key */, 5/* nbits */));
}
/*
* toBitString() tests.
*/
public void test_toBitString_correctRejection() {
try {
BytesUtil.toBitString(null);
fail("Expecting: " + IllegalArgumentException.class);
} catch (IllegalArgumentException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
public void test_toBitString_emptyByteArray() {
// zero length byte[] => zero length bit string.
assertEquals("", BytesUtil.toBitString(new byte[0]));
}
public void test_toBitString_oneByte() {
assertEquals("00000000", BytesUtil.toBitString(new byte[] { 0 }));
assertEquals("00000001", BytesUtil.toBitString(new byte[] { 1 << 0 }));
assertEquals("00000010", BytesUtil.toBitString(new byte[] { 1 << 1 }));
assertEquals("00000100", BytesUtil.toBitString(new byte[] { 1 << 2 }));
assertEquals("00001000", BytesUtil.toBitString(new byte[] { 1 << 3 }));
assertEquals("00010000", BytesUtil.toBitString(new byte[] { 1 << 4 }));
assertEquals("00100000", BytesUtil.toBitString(new byte[] { 1 << 5 }));
assertEquals("01000000", BytesUtil.toBitString(new byte[] { 1 << 6 }));
assertEquals("10000000", BytesUtil.toBitString(new byte[] { (byte) (1 << 7) }));
}
public void test_toBitString_twoBytes() {
assertEquals("00000010" + "00100000", BytesUtil.toBitString(new byte[] { 1 << 1,
1 << 5 }));
}
public void testMaskOffLSB() {
final int v1 = 0x07;
assertTrue(BytesUtil.maskOffLSB(v1, 0) == 0);
assertTrue(BytesUtil.maskOffLSB(v1, 1) == 0x01);
assertTrue(BytesUtil.maskOffLSB(v1, 2) == 0x03);
assertTrue(BytesUtil.maskOffLSB(v1, 3) == 0x07);
assertTrue(BytesUtil.maskOffLSB(v1, 4) == 0x07);
final int v2 = 0x70;
assertTrue(BytesUtil.maskOffLSB(v2, 4) == 0);
assertTrue(BytesUtil.maskOffLSB(v2, 5) == 0x10);
assertTrue(BytesUtil.maskOffLSB(v2, 6) == 0x30);
assertTrue(BytesUtil.maskOffLSB(v2, 7) == 0x70);
assertTrue(BytesUtil.maskOffLSB(v2, 8) == 0x70);
}
}