View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.util;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.DataInputStream;
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  import java.math.BigDecimal;
26  import java.nio.ByteBuffer;
27  import java.util.Arrays;
28  import java.util.Random;
29  
30  import junit.framework.TestCase;
31  
32  import org.apache.hadoop.hbase.testclassification.SmallTests;
33  import org.apache.hadoop.io.WritableUtils;
34  import org.junit.Assert;
35  import org.junit.experimental.categories.Category;
36  
37  
38  @Category(SmallTests.class)
39  public class TestBytes extends TestCase {
40    public void testNullHashCode() {
41      byte [] b = null;
42      Exception ee = null;
43      try {
44        Bytes.hashCode(b);
45      } catch (Exception e) {
46        ee = e;
47      }
48      assertNotNull(ee);
49    }
50  
51    public void testSplit() throws Exception {
52      byte [] lowest = Bytes.toBytes("AAA");
53      byte [] middle = Bytes.toBytes("CCC");
54      byte [] highest = Bytes.toBytes("EEE");
55      byte [][] parts = Bytes.split(lowest, highest, 1);
56      for (int i = 0; i < parts.length; i++) {
57        System.out.println(Bytes.toString(parts[i]));
58      }
59      assertEquals(3, parts.length);
60      assertTrue(Bytes.equals(parts[1], middle));
61      // Now divide into three parts.  Change highest so split is even.
62      highest = Bytes.toBytes("DDD");
63      parts = Bytes.split(lowest, highest, 2);
64      for (int i = 0; i < parts.length; i++) {
65        System.out.println(Bytes.toString(parts[i]));
66      }
67      assertEquals(4, parts.length);
68      // Assert that 3rd part is 'CCC'.
69      assertTrue(Bytes.equals(parts[2], middle));
70    }
71  
72    public void testSplit2() throws Exception {
73      // More split tests.
74      byte [] lowest = Bytes.toBytes("http://A");
75      byte [] highest = Bytes.toBytes("http://z");
76      byte [] middle = Bytes.toBytes("http://]");
77      byte [][] parts = Bytes.split(lowest, highest, 1);
78      for (int i = 0; i < parts.length; i++) {
79        System.out.println(Bytes.toString(parts[i]));
80      }
81      assertEquals(3, parts.length);
82      assertTrue(Bytes.equals(parts[1], middle));
83    }
84  
85    public void testSplit3() throws Exception {
86      // Test invalid split cases
87      byte [] low = { 1, 1, 1 };
88      byte [] high = { 1, 1, 3 };
89  
90      // If swapped, should throw IAE
91      try {
92        Bytes.split(high, low, 1);
93        assertTrue("Should not be able to split if low > high", false);
94      } catch(IllegalArgumentException iae) {
95        // Correct
96      }
97  
98      // Single split should work
99      byte [][] parts = Bytes.split(low, high, 1);
100     for (int i = 0; i < parts.length; i++) {
101       System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
102     }
103     assertTrue("Returned split should have 3 parts but has " + parts.length, parts.length == 3);
104 
105     // If split more than once, use additional byte to split
106     parts = Bytes.split(low, high, 2);
107     assertTrue("Split with an additional byte", parts != null);
108     assertEquals(parts.length, low.length + 1);
109 
110     // Split 0 times should throw IAE
111     try {
112       parts = Bytes.split(low, high, 0);
113       assertTrue("Should not be able to split 0 times", false);
114     } catch(IllegalArgumentException iae) {
115       // Correct
116     }
117   }
118 
119   public void testToInt() throws Exception {
120     int [] ints = {-1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE};
121     for (int i = 0; i < ints.length; i++) {
122       byte [] b = Bytes.toBytes(ints[i]);
123       assertEquals(ints[i], Bytes.toInt(b));
124       byte [] b2 = bytesWithOffset(b);
125       assertEquals(ints[i], Bytes.toInt(b2, 1));
126       assertEquals(ints[i], Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
127     }
128   }
129 
130   public void testToLong() throws Exception {
131     long [] longs = {-1l, 123l, Long.MIN_VALUE, Long.MAX_VALUE};
132     for (int i = 0; i < longs.length; i++) {
133       byte [] b = Bytes.toBytes(longs[i]);
134       assertEquals(longs[i], Bytes.toLong(b));
135       byte [] b2 = bytesWithOffset(b);
136       assertEquals(longs[i], Bytes.toLong(b2, 1));
137       assertEquals(longs[i], Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
138     }
139   }
140 
141   public void testToFloat() throws Exception {
142     float [] floats = {-1f, 123.123f, Float.MAX_VALUE};
143     for (int i = 0; i < floats.length; i++) {
144       byte [] b = Bytes.toBytes(floats[i]);
145       assertEquals(floats[i], Bytes.toFloat(b));
146       byte [] b2 = bytesWithOffset(b);
147       assertEquals(floats[i], Bytes.toFloat(b2, 1));
148     }
149   }
150 
151   public void testToDouble() throws Exception {
152     double [] doubles = {Double.MIN_VALUE, Double.MAX_VALUE};
153     for (int i = 0; i < doubles.length; i++) {
154       byte [] b = Bytes.toBytes(doubles[i]);
155       assertEquals(doubles[i], Bytes.toDouble(b));
156       byte [] b2 = bytesWithOffset(b);
157       assertEquals(doubles[i], Bytes.toDouble(b2, 1));
158     }
159   }
160 
161   public void testToBigDecimal() throws Exception {
162     BigDecimal [] decimals = {new BigDecimal("-1"), new BigDecimal("123.123"),
163       new BigDecimal("123123123123")};
164     for (int i = 0; i < decimals.length; i++) {
165       byte [] b = Bytes.toBytes(decimals[i]);
166       assertEquals(decimals[i], Bytes.toBigDecimal(b));
167       byte [] b2 = bytesWithOffset(b);
168       assertEquals(decimals[i], Bytes.toBigDecimal(b2, 1, b.length));
169     }
170   }
171 
172   private byte [] bytesWithOffset(byte [] src) {
173     // add one byte in front to test offset
174     byte [] result = new byte[src.length + 1];
175     result[0] = (byte) 0xAA;
176     System.arraycopy(src, 0, result, 1, src.length);
177     return result;
178   }
179 
180   public void testToBytesForByteBuffer() {
181     byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
182     ByteBuffer target = ByteBuffer.wrap(array);
183     target.position(2);
184     target.limit(7);
185 
186     byte[] actual = Bytes.toBytes(target);
187     byte[] expected = { 0, 1, 2, 3, 4, 5, 6 };
188     assertTrue(Arrays.equals(expected,  actual));
189     assertEquals(2, target.position());
190     assertEquals(7, target.limit());
191 
192     ByteBuffer target2 = target.slice();
193     assertEquals(0, target2.position());
194     assertEquals(5, target2.limit());
195 
196     byte[] actual2 = Bytes.toBytes(target2);
197     byte[] expected2 = { 2, 3, 4, 5, 6 };
198     assertTrue(Arrays.equals(expected2, actual2));
199     assertEquals(0, target2.position());
200     assertEquals(5, target2.limit());
201   }
202 
203   public void testGetBytesForByteBuffer() {
204     byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
205     ByteBuffer target = ByteBuffer.wrap(array);
206     target.position(2);
207     target.limit(7);
208 
209     byte[] actual = Bytes.getBytes(target);
210     byte[] expected = { 2, 3, 4, 5, 6 };
211     assertTrue(Arrays.equals(expected,  actual));
212     assertEquals(2, target.position());
213     assertEquals(7, target.limit());
214   }
215 
216   public void testReadAsVLong() throws Exception {
217     long [] longs = {-1l, 123l, Long.MIN_VALUE, Long.MAX_VALUE};
218     for (int i = 0; i < longs.length; i++) {
219       ByteArrayOutputStream baos = new ByteArrayOutputStream();
220       DataOutputStream output = new DataOutputStream(baos);
221       WritableUtils.writeVLong(output, longs[i]);
222       byte[] long_bytes_no_offset = baos.toByteArray();
223       assertEquals(longs[i], Bytes.readAsVLong(long_bytes_no_offset, 0));
224       byte[] long_bytes_with_offset = bytesWithOffset(long_bytes_no_offset);
225       assertEquals(longs[i], Bytes.readAsVLong(long_bytes_with_offset, 1));
226     }
227   }
228 
229   public void testToStringBinaryForBytes() {
230     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
231     String actual = Bytes.toStringBinary(array);
232     String expected = "09azAZ@\\x01";
233     assertEquals(expected, actual);
234 
235     String actual2 = Bytes.toStringBinary(array, 2, 3);
236     String expected2 = "azA";
237     assertEquals(expected2, actual2);
238   }
239 
240   public void testToStringBinaryForArrayBasedByteBuffer() {
241     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
242     ByteBuffer target = ByteBuffer.wrap(array);
243     String actual = Bytes.toStringBinary(target);
244     String expected = "09azAZ@\\x01";
245     assertEquals(expected, actual);
246   }
247 
248   public void testToStringBinaryForReadOnlyByteBuffer() {
249     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
250     ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer();
251     String actual = Bytes.toStringBinary(target);
252     String expected = "09azAZ@\\x01";
253     assertEquals(expected, actual);
254   }
255 
256   public void testBinarySearch() throws Exception {
257     byte [][] arr = {
258         {1},
259         {3},
260         {5},
261         {7},
262         {9},
263         {11},
264         {13},
265         {15},
266     };
267     byte [] key1 = {3,1};
268     byte [] key2 = {4,9};
269     byte [] key2_2 = {4};
270     byte [] key3 = {5,11};
271     byte [] key4 = {0};
272     byte [] key5 = {2};
273 
274     assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1,
275       Bytes.BYTES_RAWCOMPARATOR));
276     assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1,
277       Bytes.BYTES_RAWCOMPARATOR));
278     assertEquals(-(2+1), Arrays.binarySearch(arr, key2_2,
279       Bytes.BYTES_COMPARATOR));
280     assertEquals(-(2+1), Bytes.binarySearch(arr, key2, 0, 1,
281       Bytes.BYTES_RAWCOMPARATOR));
282     assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1,
283       Bytes.BYTES_RAWCOMPARATOR));
284     assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1,
285       Bytes.BYTES_RAWCOMPARATOR));
286     assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1,
287       Bytes.BYTES_RAWCOMPARATOR));
288     assertEquals(-1,
289       Bytes.binarySearch(arr, key4, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
290     assertEquals(-2,
291       Bytes.binarySearch(arr, key5, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
292 
293     // Search for values to the left and to the right of each item in the array.
294     for (int i = 0; i < arr.length; ++i) {
295       assertEquals(-(i + 1), Bytes.binarySearch(arr,
296           new byte[] { (byte) (arr[i][0] - 1) }, 0, 1,
297           Bytes.BYTES_RAWCOMPARATOR));
298       assertEquals(-(i + 2), Bytes.binarySearch(arr,
299           new byte[] { (byte) (arr[i][0] + 1) }, 0, 1,
300           Bytes.BYTES_RAWCOMPARATOR));
301     }
302   }
303 
304   public void testToStringBytesBinaryReversible() {
305     //  let's run test with 1000 randomly generated byte arrays
306     Random rand = new Random(System.currentTimeMillis());
307     byte[] randomBytes = new byte[1000];
308     for (int i = 0; i < 1000; i++) {
309       rand.nextBytes(randomBytes);
310       verifyReversibleForBytes(randomBytes);
311     }
312 
313     //  some specific cases
314     verifyReversibleForBytes(new  byte[] {});
315     verifyReversibleForBytes(new  byte[] {'\\', 'x', 'A', 'D'});
316     verifyReversibleForBytes(new  byte[] {'\\', 'x', 'A', 'D', '\\'});
317   }
318 
319   private void verifyReversibleForBytes(byte[] originalBytes) {
320     String convertedString = Bytes.toStringBinary(originalBytes);
321     byte[] convertedBytes = Bytes.toBytesBinary(convertedString);
322     if (Bytes.compareTo(originalBytes, convertedBytes) != 0) {
323       fail("Not reversible for\nbyte[]: " + Arrays.toString(originalBytes) +
324           ",\nStringBinary: " + convertedString);
325     }
326   }
327 
328   public void testStartsWith() {
329     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
330     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
331     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
332     assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
333     assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
334   }
335 
336   public void testIncrementBytes() throws IOException {
337 
338     assertTrue(checkTestIncrementBytes(10, 1));
339     assertTrue(checkTestIncrementBytes(12, 123435445));
340     assertTrue(checkTestIncrementBytes(124634654, 1));
341     assertTrue(checkTestIncrementBytes(10005460, 5005645));
342     assertTrue(checkTestIncrementBytes(1, -1));
343     assertTrue(checkTestIncrementBytes(10, -1));
344     assertTrue(checkTestIncrementBytes(10, -5));
345     assertTrue(checkTestIncrementBytes(1005435000, -5));
346     assertTrue(checkTestIncrementBytes(10, -43657655));
347     assertTrue(checkTestIncrementBytes(-1, 1));
348     assertTrue(checkTestIncrementBytes(-26, 5034520));
349     assertTrue(checkTestIncrementBytes(-10657200, 5));
350     assertTrue(checkTestIncrementBytes(-12343250, 45376475));
351     assertTrue(checkTestIncrementBytes(-10, -5));
352     assertTrue(checkTestIncrementBytes(-12343250, -5));
353     assertTrue(checkTestIncrementBytes(-12, -34565445));
354     assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
355   }
356 
357   private static boolean checkTestIncrementBytes(long val, long amount)
358   throws IOException {
359     byte[] value = Bytes.toBytes(val);
360     byte [] testValue = {-1, -1, -1, -1, -1, -1, -1, -1};
361     if (value[0] > 0) {
362       testValue = new byte[Bytes.SIZEOF_LONG];
363     }
364     System.arraycopy(value, 0, testValue, testValue.length - value.length,
365         value.length);
366 
367     long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
368 
369     return (Bytes.toLong(testValue) + amount) == incrementResult;
370   }
371 
372   public void testFixedSizeString() throws IOException {
373     ByteArrayOutputStream baos = new ByteArrayOutputStream();
374     DataOutputStream dos = new DataOutputStream(baos);
375     Bytes.writeStringFixedSize(dos, "Hello", 5);
376     Bytes.writeStringFixedSize(dos, "World", 18);
377     Bytes.writeStringFixedSize(dos, "", 9);
378 
379     try {
380       // Use a long dash which is three bytes in UTF-8. If encoding happens
381       // using ISO-8859-1, this will fail.
382       Bytes.writeStringFixedSize(dos, "Too\u2013Long", 9);
383       fail("Exception expected");
384     } catch (IOException ex) {
385       assertEquals(
386           "Trying to write 10 bytes (Too\\xE2\\x80\\x93Long) into a field of " +
387           "length 9", ex.getMessage());
388     }
389 
390     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
391     DataInputStream dis = new DataInputStream(bais);
392     assertEquals("Hello", Bytes.readStringFixedSize(dis, 5));
393     assertEquals("World", Bytes.readStringFixedSize(dis, 18));
394     assertEquals("", Bytes.readStringFixedSize(dis, 9));
395   }
396 
397   public void testCopy() throws Exception {
398     byte [] bytes = Bytes.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
399     byte [] copy =  Bytes.copy(bytes);
400     assertFalse(bytes == copy);
401     assertTrue(Bytes.equals(bytes, copy));
402   }
403 
404   public void testToBytesBinaryTrailingBackslashes() throws Exception {
405     try {
406       Bytes.toBytesBinary("abc\\x00\\x01\\");
407     } catch (StringIndexOutOfBoundsException ex) {
408       fail("Illegal string access: " + ex.getMessage());
409     }
410   }
411 
412   public void testToStringBinary_toBytesBinary_Reversable() throws Exception {
413     String bytes = Bytes.toStringBinary(Bytes.toBytes(2.17));
414     assertEquals(2.17, Bytes.toDouble(Bytes.toBytesBinary(bytes)), 0);        
415   }
416 
417   public void testUnsignedBinarySearch(){
418     byte[] bytes = new byte[]{0,5,123,127,-128,-100,-1};
419     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)5), 1);
420     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)127), 3);
421     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-128), 4);
422     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-100), 5);
423     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-1), 6);
424     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)2), -1-1);
425     Assert.assertEquals(Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-5), -6-1);
426   }
427 
428   public void testUnsignedIncrement(){
429     byte[] a = Bytes.toBytes(0);
430     int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
431     Assert.assertTrue(a2==1);
432 
433     byte[] b = Bytes.toBytes(-1);
434     byte[] actual = Bytes.unsignedCopyAndIncrement(b);
435     Assert.assertNotSame(b, actual);
436     byte[] expected = new byte[]{1,0,0,0,0};
437     Assert.assertArrayEquals(expected, actual);
438 
439     byte[] c = Bytes.toBytes(255);//should wrap to the next significant byte
440     int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
441     Assert.assertTrue(c2==256);
442   }
443   
444   public void testIndexOf() {
445     byte[] array = Bytes.toBytes("hello");
446     assertEquals(1, Bytes.indexOf(array, (byte) 'e'));
447     assertEquals(4, Bytes.indexOf(array, (byte) 'o'));
448     assertEquals(-1, Bytes.indexOf(array, (byte) 'a'));
449     assertEquals(0, Bytes.indexOf(array, Bytes.toBytes("hel")));
450     assertEquals(2, Bytes.indexOf(array, Bytes.toBytes("ll")));
451     assertEquals(-1, Bytes.indexOf(array, Bytes.toBytes("hll")));
452   }
453   
454   public void testContains() {
455     byte[] array = Bytes.toBytes("hello world");
456     assertTrue(Bytes.contains(array, (byte) 'e'));
457     assertTrue(Bytes.contains(array, (byte) 'd'));
458     assertFalse( Bytes.contains(array, (byte) 'a'));
459     assertTrue(Bytes.contains(array, Bytes.toBytes("world")));
460     assertTrue(Bytes.contains(array, Bytes.toBytes("ello")));
461     assertFalse(Bytes.contains(array, Bytes.toBytes("owo")));
462   }
463   
464   public void testZero() {
465     byte[] array = Bytes.toBytes("hello");
466     Bytes.zero(array);
467     for (int i = 0; i < array.length; i++) {
468       assertEquals(0, array[i]);
469     }
470     array = Bytes.toBytes("hello world");
471     Bytes.zero(array, 2, 7);
472     assertFalse(array[0] == 0);
473     assertFalse(array[1] == 0);
474     for (int i = 2; i < 9; i++) {
475       assertEquals(0, array[i]);
476     }
477     for (int i = 9; i < array.length; i++) {
478       assertFalse(array[i] == 0);
479     }
480   }
481 
482   public void testPutBuffer() {
483     byte[] b = new byte[100];
484     for (byte i = 0; i < 100; i++) {
485       Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[]{i}));
486     }
487     for (byte i = 0; i < 100; i++) {
488       Assert.assertEquals(i, b[i]);
489     }
490   }
491 }
492