001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.util;
019
020import static org.junit.Assert.assertArrayEquals;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023import static org.junit.Assert.assertNotNull;
024import static org.junit.Assert.assertNotSame;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.io.ByteArrayInputStream;
029import java.io.ByteArrayOutputStream;
030import java.io.DataInputStream;
031import java.io.DataOutputStream;
032import java.io.IOException;
033import java.lang.reflect.Field;
034import java.lang.reflect.Modifier;
035import java.math.BigDecimal;
036import java.nio.ByteBuffer;
037import java.util.ArrayList;
038import java.util.Arrays;
039import java.util.List;
040import java.util.Random;
041import java.util.concurrent.ThreadLocalRandom;
042import org.apache.hadoop.hbase.HBaseClassTestRule;
043import org.apache.hadoop.hbase.testclassification.MediumTests;
044import org.apache.hadoop.hbase.testclassification.MiscTests;
045import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
046import org.apache.hadoop.io.WritableUtils;
047import org.junit.Assert;
048import org.junit.ClassRule;
049import org.junit.Test;
050import org.junit.experimental.categories.Category;
051
052@Category({ MiscTests.class, MediumTests.class })
053public class TestBytes {
054  @ClassRule
055  public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestBytes.class);
056
057  private static void setUnsafe(boolean value) throws Exception {
058    Field field = Bytes.class.getDeclaredField("UNSAFE_UNALIGNED");
059    field.setAccessible(true);
060
061    Field modifiersField = ReflectionUtils.getModifiersField();
062    modifiersField.setAccessible(true);
063    int oldModifiers = field.getModifiers();
064    modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
065    try {
066      field.set(null, value);
067    } finally {
068      modifiersField.setInt(field, oldModifiers);
069    }
070    assertEquals(Bytes.UNSAFE_UNALIGNED, value);
071  }
072
073  @Test
074  public void testShort() throws Exception {
075    testShort(false);
076  }
077
078  @Test
079  public void testShortUnsafe() throws Exception {
080    testShort(true);
081  }
082
083  private static void testShort(boolean unsafe) throws Exception {
084    setUnsafe(unsafe);
085    try {
086      for (short n : Arrays.asList(Short.MIN_VALUE, (short) -100, (short) -1, (short) 0, (short) 1,
087        (short) 300, Short.MAX_VALUE)) {
088        byte[] bytes = Bytes.toBytes(n);
089        assertEquals(Bytes.toShort(bytes, 0, bytes.length), n);
090      }
091    } finally {
092      setUnsafe(HBasePlatformDependent.unaligned());
093    }
094  }
095
096  @Test
097  public void testNullHashCode() {
098    byte[] b = null;
099    Exception ee = null;
100    try {
101      Bytes.hashCode(b);
102    } catch (Exception e) {
103      ee = e;
104    }
105    assertNotNull(ee);
106  }
107
108  @Test
109  public void testAdd() {
110    byte[] a = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
111    byte[] b = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
112    byte[] c = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
113    byte[] result1 = Bytes.add(a, b, c);
114    byte[] result2 = Bytes.add(new byte[][] { a, b, c });
115    assertEquals(0, Bytes.compareTo(result1, result2));
116  }
117
118  @Test
119  public void testSplit() {
120    byte[] lowest = Bytes.toBytes("AAA");
121    byte[] middle = Bytes.toBytes("CCC");
122    byte[] highest = Bytes.toBytes("EEE");
123    byte[][] parts = Bytes.split(lowest, highest, 1);
124    for (byte[] bytes : parts) {
125      System.out.println(Bytes.toString(bytes));
126    }
127    assertEquals(3, parts.length);
128    assertTrue(Bytes.equals(parts[1], middle));
129    // Now divide into three parts. Change highest so split is even.
130    highest = Bytes.toBytes("DDD");
131    parts = Bytes.split(lowest, highest, 2);
132    for (byte[] part : parts) {
133      System.out.println(Bytes.toString(part));
134    }
135    assertEquals(4, parts.length);
136    // Assert that 3rd part is 'CCC'.
137    assertTrue(Bytes.equals(parts[2], middle));
138  }
139
140  @Test
141  public void testSplit2() {
142    // More split tests.
143    byte[] lowest = Bytes.toBytes("http://A");
144    byte[] highest = Bytes.toBytes("http://z");
145    byte[] middle = Bytes.toBytes("http://]");
146    byte[][] parts = Bytes.split(lowest, highest, 1);
147    for (byte[] part : parts) {
148      System.out.println(Bytes.toString(part));
149    }
150    assertEquals(3, parts.length);
151    assertTrue(Bytes.equals(parts[1], middle));
152  }
153
154  @Test
155  public void testSplit3() {
156    // Test invalid split cases
157    byte[] low = { 1, 1, 1 };
158    byte[] high = { 1, 1, 3 };
159
160    // If swapped, should throw IAE
161    try {
162      Bytes.split(high, low, 1);
163      fail("Should not be able to split if low > high");
164    } catch (IllegalArgumentException iae) {
165      // Correct
166    }
167
168    // Single split should work
169    byte[][] parts = Bytes.split(low, high, 1);
170    for (int i = 0; i < parts.length; i++) {
171      System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
172    }
173    assertEquals("Returned split should have 3 parts but has " + parts.length, 3, parts.length);
174
175    // If split more than once, use additional byte to split
176    parts = Bytes.split(low, high, 2);
177    assertNotNull("Split with an additional byte", parts);
178    assertEquals(parts.length, low.length + 1);
179
180    // Split 0 times should throw IAE
181    try {
182      Bytes.split(low, high, 0);
183      fail("Should not be able to split 0 times");
184    } catch (IllegalArgumentException iae) {
185      // Correct
186    }
187  }
188
189  @Test
190  public void testToInt() {
191    int[] ints = { -1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE };
192    for (int anInt : ints) {
193      byte[] b = Bytes.toBytes(anInt);
194      assertEquals(anInt, Bytes.toInt(b));
195      byte[] b2 = bytesWithOffset(b);
196      assertEquals(anInt, Bytes.toInt(b2, 1));
197      assertEquals(anInt, Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
198    }
199  }
200
201  @Test
202  public void testToLong() {
203    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
204    for (long aLong : longs) {
205      byte[] b = Bytes.toBytes(aLong);
206      assertEquals(aLong, Bytes.toLong(b));
207      byte[] b2 = bytesWithOffset(b);
208      assertEquals(aLong, Bytes.toLong(b2, 1));
209      assertEquals(aLong, Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
210    }
211  }
212
213  @Test
214  public void testToFloat() {
215    float[] floats = { -1f, 123.123f, Float.MAX_VALUE };
216    for (float aFloat : floats) {
217      byte[] b = Bytes.toBytes(aFloat);
218      assertEquals(aFloat, Bytes.toFloat(b), 0.0f);
219      byte[] b2 = bytesWithOffset(b);
220      assertEquals(aFloat, Bytes.toFloat(b2, 1), 0.0f);
221    }
222  }
223
224  @Test
225  public void testToDouble() {
226    double[] doubles = { Double.MIN_VALUE, Double.MAX_VALUE };
227    for (double aDouble : doubles) {
228      byte[] b = Bytes.toBytes(aDouble);
229      assertEquals(aDouble, Bytes.toDouble(b), 0.0);
230      byte[] b2 = bytesWithOffset(b);
231      assertEquals(aDouble, Bytes.toDouble(b2, 1), 0.0);
232    }
233  }
234
235  @Test
236  public void testToBigDecimal() {
237    BigDecimal[] decimals =
238      { new BigDecimal("-1"), new BigDecimal("123.123"), new BigDecimal("123123123123") };
239    for (BigDecimal decimal : decimals) {
240      byte[] b = Bytes.toBytes(decimal);
241      assertEquals(decimal, Bytes.toBigDecimal(b));
242      byte[] b2 = bytesWithOffset(b);
243      assertEquals(decimal, Bytes.toBigDecimal(b2, 1, b.length));
244    }
245  }
246
247  private byte[] bytesWithOffset(byte[] src) {
248    // add one byte in front to test offset
249    byte[] result = new byte[src.length + 1];
250    result[0] = (byte) 0xAA;
251    System.arraycopy(src, 0, result, 1, src.length);
252    return result;
253  }
254
255  @Test
256  public void testToBytesForByteBuffer() {
257    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
258    ByteBuffer target = ByteBuffer.wrap(array);
259    target.position(2);
260    target.limit(7);
261
262    byte[] actual = Bytes.toBytes(target);
263    byte[] expected = { 0, 1, 2, 3, 4, 5, 6 };
264    assertArrayEquals(expected, actual);
265    assertEquals(2, target.position());
266    assertEquals(7, target.limit());
267
268    ByteBuffer target2 = target.slice();
269    assertEquals(0, target2.position());
270    assertEquals(5, target2.limit());
271
272    byte[] actual2 = Bytes.toBytes(target2);
273    byte[] expected2 = { 2, 3, 4, 5, 6 };
274    assertArrayEquals(expected2, actual2);
275    assertEquals(0, target2.position());
276    assertEquals(5, target2.limit());
277  }
278
279  @Test
280  public void testGetBytesForByteBuffer() {
281    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
282    ByteBuffer target = ByteBuffer.wrap(array);
283    target.position(2);
284    target.limit(7);
285
286    byte[] actual = Bytes.getBytes(target);
287    byte[] expected = { 2, 3, 4, 5, 6 };
288    assertArrayEquals(expected, actual);
289    assertEquals(2, target.position());
290    assertEquals(7, target.limit());
291  }
292
293  @Test
294  public void testReadAsVLong() throws Exception {
295    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
296    for (long aLong : longs) {
297      ByteArrayOutputStream baos = new ByteArrayOutputStream();
298      DataOutputStream output = new DataOutputStream(baos);
299      WritableUtils.writeVLong(output, aLong);
300      byte[] long_bytes_no_offset = baos.toByteArray();
301      assertEquals(aLong, Bytes.readAsVLong(long_bytes_no_offset, 0));
302      byte[] long_bytes_with_offset = bytesWithOffset(long_bytes_no_offset);
303      assertEquals(aLong, Bytes.readAsVLong(long_bytes_with_offset, 1));
304    }
305  }
306
307  @Test
308  public void testToStringBinaryForBytes() {
309    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
310    String actual = Bytes.toStringBinary(array);
311    String expected = "09azAZ@\\x01";
312    assertEquals(expected, actual);
313
314    String actual2 = Bytes.toStringBinary(array, 2, 3);
315    String expected2 = "azA";
316    assertEquals(expected2, actual2);
317  }
318
319  @Test
320  public void testToStringBinaryForArrayBasedByteBuffer() {
321    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
322    ByteBuffer target = ByteBuffer.wrap(array);
323    String actual = Bytes.toStringBinary(target);
324    String expected = "09azAZ@\\x01";
325    assertEquals(expected, actual);
326  }
327
328  @Test
329  public void testToStringBinaryForReadOnlyByteBuffer() {
330    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
331    ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer();
332    String actual = Bytes.toStringBinary(target);
333    String expected = "09azAZ@\\x01";
334    assertEquals(expected, actual);
335  }
336
337  @Test
338  public void testBinarySearch() {
339    byte[][] arr = { { 1 }, { 3 }, { 5 }, { 7 }, { 9 }, { 11 }, { 13 }, { 15 }, };
340    byte[] key1 = { 3, 1 };
341    byte[] key2 = { 4, 9 };
342    byte[] key2_2 = { 4 };
343    byte[] key3 = { 5, 11 };
344    byte[] key4 = { 0 };
345    byte[] key5 = { 2 };
346
347    assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1));
348    assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1));
349    assertEquals(-(2 + 1), Arrays.binarySearch(arr, key2_2, Bytes.BYTES_COMPARATOR));
350    assertEquals(-(2 + 1), Bytes.binarySearch(arr, key2, 0, 1));
351    assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1));
352    assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1));
353    assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1));
354    assertEquals(-1, Bytes.binarySearch(arr, key4, 0, 1));
355    assertEquals(-2, Bytes.binarySearch(arr, key5, 0, 1));
356
357    // Search for values to the left and to the right of each item in the array.
358    for (int i = 0; i < arr.length; ++i) {
359      assertEquals(-(i + 1), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] - 1) }, 0, 1));
360      assertEquals(-(i + 2), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] + 1) }, 0, 1));
361    }
362  }
363
364  @Test
365  public void testToStringBytesBinaryReversible() {
366    byte[] randomBytes = new byte[1000];
367    for (int i = 0; i < 1000; i++) {
368      Bytes.random(randomBytes);
369      verifyReversibleForBytes(randomBytes);
370    }
371    // some specific cases
372    verifyReversibleForBytes(new byte[] {});
373    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D' });
374    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D', '\\' });
375  }
376
377  private void verifyReversibleForBytes(byte[] originalBytes) {
378    String convertedString = Bytes.toStringBinary(originalBytes);
379    byte[] convertedBytes = Bytes.toBytesBinary(convertedString);
380    if (Bytes.compareTo(originalBytes, convertedBytes) != 0) {
381      fail("Not reversible for\nbyte[]: " + Arrays.toString(originalBytes) + ",\nStringBinary: "
382        + convertedString);
383    }
384  }
385
386  @Test
387  public void testStartsWith() {
388    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
389    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
390    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
391    assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
392    assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
393  }
394
395  @Test
396  public void testIncrementBytes() {
397    assertTrue(checkTestIncrementBytes(10, 1));
398    assertTrue(checkTestIncrementBytes(12, 123435445));
399    assertTrue(checkTestIncrementBytes(124634654, 1));
400    assertTrue(checkTestIncrementBytes(10005460, 5005645));
401    assertTrue(checkTestIncrementBytes(1, -1));
402    assertTrue(checkTestIncrementBytes(10, -1));
403    assertTrue(checkTestIncrementBytes(10, -5));
404    assertTrue(checkTestIncrementBytes(1005435000, -5));
405    assertTrue(checkTestIncrementBytes(10, -43657655));
406    assertTrue(checkTestIncrementBytes(-1, 1));
407    assertTrue(checkTestIncrementBytes(-26, 5034520));
408    assertTrue(checkTestIncrementBytes(-10657200, 5));
409    assertTrue(checkTestIncrementBytes(-12343250, 45376475));
410    assertTrue(checkTestIncrementBytes(-10, -5));
411    assertTrue(checkTestIncrementBytes(-12343250, -5));
412    assertTrue(checkTestIncrementBytes(-12, -34565445));
413    assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
414  }
415
416  private static boolean checkTestIncrementBytes(long val, long amount) {
417    byte[] value = Bytes.toBytes(val);
418    byte[] testValue = { -1, -1, -1, -1, -1, -1, -1, -1 };
419    if (value[0] > 0) {
420      testValue = new byte[Bytes.SIZEOF_LONG];
421    }
422    System.arraycopy(value, 0, testValue, testValue.length - value.length, value.length);
423
424    long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
425
426    return (Bytes.toLong(testValue) + amount) == incrementResult;
427  }
428
429  @Test
430  public void testFixedSizeString() throws IOException {
431    ByteArrayOutputStream baos = new ByteArrayOutputStream();
432    DataOutputStream dos = new DataOutputStream(baos);
433    Bytes.writeStringFixedSize(dos, "Hello", 5);
434    Bytes.writeStringFixedSize(dos, "World", 18);
435    Bytes.writeStringFixedSize(dos, "", 9);
436
437    try {
438      // Use a long dash which is three bytes in UTF-8. If encoding happens
439      // using ISO-8859-1, this will fail.
440      Bytes.writeStringFixedSize(dos, "Too\u2013Long", 9);
441      fail("Exception expected");
442    } catch (IOException ex) {
443      assertEquals(
444        "Trying to write 10 bytes (Too\\xE2\\x80\\x93Long) into a field of " + "length 9",
445        ex.getMessage());
446    }
447
448    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
449    DataInputStream dis = new DataInputStream(bais);
450    assertEquals("Hello", Bytes.readStringFixedSize(dis, 5));
451    assertEquals("World", Bytes.readStringFixedSize(dis, 18));
452    assertEquals("", Bytes.readStringFixedSize(dis, 9));
453  }
454
455  @Test
456  public void testCopy() {
457    byte[] bytes = Bytes.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
458    byte[] copy = Bytes.copy(bytes);
459    assertNotSame(bytes, copy);
460    assertTrue(Bytes.equals(bytes, copy));
461  }
462
463  @Test
464  public void testToBytesBinaryTrailingBackslashes() {
465    try {
466      Bytes.toBytesBinary("abc\\x00\\x01\\");
467    } catch (StringIndexOutOfBoundsException ex) {
468      fail("Illegal string access: " + ex.getMessage());
469    }
470  }
471
472  @Test
473  public void testToStringBinary_toBytesBinary_Reversable() {
474    String bytes = Bytes.toStringBinary(Bytes.toBytes(2.17));
475    assertEquals(2.17, Bytes.toDouble(Bytes.toBytesBinary(bytes)), 0);
476  }
477
478  @Test
479  public void testUnsignedBinarySearch() {
480    byte[] bytes = new byte[] { 0, 5, 123, 127, -128, -100, -1 };
481    Assert.assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 5));
482    Assert.assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 127));
483    Assert.assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -128));
484    Assert.assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -100));
485    Assert.assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -1));
486    Assert.assertEquals(-1 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 2));
487    Assert.assertEquals(-6 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -5));
488  }
489
490  @Test
491  public void testUnsignedIncrement() {
492    byte[] a = Bytes.toBytes(0);
493    int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
494    Assert.assertEquals(1, a2);
495
496    byte[] b = Bytes.toBytes(-1);
497    byte[] actual = Bytes.unsignedCopyAndIncrement(b);
498    Assert.assertNotSame(b, actual);
499    byte[] expected = new byte[] { 1, 0, 0, 0, 0 };
500    assertArrayEquals(expected, actual);
501
502    byte[] c = Bytes.toBytes(255);// should wrap to the next significant byte
503    int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
504    Assert.assertEquals(256, c2);
505  }
506
507  @Test
508  public void testIndexOf() {
509    byte[] array = Bytes.toBytes("hello");
510    assertEquals(1, Bytes.indexOf(array, (byte) 'e'));
511    assertEquals(4, Bytes.indexOf(array, (byte) 'o'));
512    assertEquals(-1, Bytes.indexOf(array, (byte) 'a'));
513    assertEquals(0, Bytes.indexOf(array, Bytes.toBytes("hel")));
514    assertEquals(2, Bytes.indexOf(array, Bytes.toBytes("ll")));
515    assertEquals(-1, Bytes.indexOf(array, Bytes.toBytes("hll")));
516  }
517
518  @Test
519  public void testContains() {
520    byte[] array = Bytes.toBytes("hello world");
521    assertTrue(Bytes.contains(array, (byte) 'e'));
522    assertTrue(Bytes.contains(array, (byte) 'd'));
523    assertFalse(Bytes.contains(array, (byte) 'a'));
524    assertTrue(Bytes.contains(array, Bytes.toBytes("world")));
525    assertTrue(Bytes.contains(array, Bytes.toBytes("ello")));
526    assertFalse(Bytes.contains(array, Bytes.toBytes("owo")));
527  }
528
529  @Test
530  public void testZero() {
531    byte[] array = Bytes.toBytes("hello");
532    Bytes.zero(array);
533    for (byte b : array) {
534      assertEquals(0, b);
535    }
536    array = Bytes.toBytes("hello world");
537    Bytes.zero(array, 2, 7);
538    assertFalse(array[0] == 0);
539    assertFalse(array[1] == 0);
540    for (int i = 2; i < 9; i++) {
541      assertEquals(0, array[i]);
542    }
543    for (int i = 9; i < array.length; i++) {
544      assertFalse(array[i] == 0);
545    }
546  }
547
548  @Test
549  public void testPutBuffer() {
550    byte[] b = new byte[100];
551    for (byte i = 0; i < 100; i++) {
552      Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[] { i }));
553    }
554    for (byte i = 0; i < 100; i++) {
555      Assert.assertEquals(i, b[i]);
556    }
557  }
558
559  @Test
560  public void testToFromHex() {
561    List<String> testStrings = new ArrayList<>(8);
562    testStrings.addAll(Arrays.asList("", "00", "A0", "ff", "FFffFFFFFFFFFF", "12",
563      "0123456789abcdef", "283462839463924623984692834692346ABCDFEDDCA0"));
564    for (String testString : testStrings) {
565      byte[] byteData = Bytes.fromHex(testString);
566      Assert.assertEquals(testString.length() / 2, byteData.length);
567      String result = Bytes.toHex(byteData);
568      Assert.assertTrue(testString.equalsIgnoreCase(result));
569    }
570
571    List<byte[]> testByteData = new ArrayList<>(5);
572    testByteData.addAll(Arrays.asList(new byte[0], new byte[1], new byte[10],
573      new byte[] { 1, 2, 3, 4, 5 }, new byte[] { (byte) 0xFF }));
574    Random rand = ThreadLocalRandom.current();
575    for (int i = 0; i < 20; i++) {
576      byte[] bytes = new byte[rand.nextInt(100)];
577      Bytes.random(bytes);
578      testByteData.add(bytes);
579    }
580
581    for (byte[] testData : testByteData) {
582      String hexString = Bytes.toHex(testData);
583      Assert.assertEquals(testData.length * 2, hexString.length());
584      byte[] result = Bytes.fromHex(hexString);
585      assertArrayEquals(testData, result);
586    }
587  }
588
589  @Test
590  public void testFindCommonPrefix() throws Exception {
591    testFindCommonPrefix(false);
592  }
593
594  @Test
595  public void testFindCommonPrefixUnsafe() throws Exception {
596    testFindCommonPrefix(true);
597  }
598
599  private static void testFindCommonPrefix(boolean unsafe) throws Exception {
600    setUnsafe(unsafe);
601    try {
602      // tests for common prefixes less than 8 bytes in length (i.e. using non-vectorized path)
603      byte[] hello = Bytes.toBytes("hello");
604      byte[] helloWorld = Bytes.toBytes("helloworld");
605
606      assertEquals(5,
607        Bytes.findCommonPrefix(hello, helloWorld, hello.length, helloWorld.length, 0, 0));
608      assertEquals(5, Bytes.findCommonPrefix(hello, hello, hello.length, hello.length, 0, 0));
609      assertEquals(3,
610        Bytes.findCommonPrefix(hello, hello, hello.length - 2, hello.length - 2, 2, 2));
611      assertEquals(0, Bytes.findCommonPrefix(hello, hello, 0, 0, 0, 0));
612
613      // tests for common prefixes greater than 8 bytes in length which may use the vectorized path
614      byte[] hellohello = Bytes.toBytes("hellohello");
615      byte[] hellohellohi = Bytes.toBytes("hellohellohi");
616
617      assertEquals(10, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
618        hellohellohi.length, 0, 0));
619      assertEquals(10, Bytes.findCommonPrefix(hellohellohi, hellohello, hellohellohi.length,
620        hellohello.length, 0, 0));
621      assertEquals(10,
622        Bytes.findCommonPrefix(hellohello, hellohello, hellohello.length, hellohello.length, 0, 0));
623
624      hellohello[2] = 0;
625      assertEquals(2, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
626        hellohellohi.length, 0, 0));
627    } finally {
628      setUnsafe(HBasePlatformDependent.unaligned());
629    }
630  }
631}