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