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