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[] d = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
114    byte[] result1 = Bytes.add(a, b, c);
115    byte[] result2 = Bytes.add(new byte[][] { a, b, c });
116    assertEquals(0, Bytes.compareTo(result1, result2));
117    byte[] result4 = Bytes.add(result1, d);
118    byte[] result5 = Bytes.add(new byte[][] { result1, d });
119    assertEquals(0, Bytes.compareTo(result1, result2));
120  }
121
122  @Test
123  public void testSplit() {
124    byte[] lowest = Bytes.toBytes("AAA");
125    byte[] middle = Bytes.toBytes("CCC");
126    byte[] highest = Bytes.toBytes("EEE");
127    byte[][] parts = Bytes.split(lowest, highest, 1);
128    for (byte[] bytes : parts) {
129      System.out.println(Bytes.toString(bytes));
130    }
131    assertEquals(3, parts.length);
132    assertTrue(Bytes.equals(parts[1], middle));
133    // Now divide into three parts. Change highest so split is even.
134    highest = Bytes.toBytes("DDD");
135    parts = Bytes.split(lowest, highest, 2);
136    for (byte[] part : parts) {
137      System.out.println(Bytes.toString(part));
138    }
139    assertEquals(4, parts.length);
140    // Assert that 3rd part is 'CCC'.
141    assertTrue(Bytes.equals(parts[2], middle));
142  }
143
144  @Test
145  public void testSplit2() {
146    // More split tests.
147    byte[] lowest = Bytes.toBytes("http://A");
148    byte[] highest = Bytes.toBytes("http://z");
149    byte[] middle = Bytes.toBytes("http://]");
150    byte[][] parts = Bytes.split(lowest, highest, 1);
151    for (byte[] part : parts) {
152      System.out.println(Bytes.toString(part));
153    }
154    assertEquals(3, parts.length);
155    assertTrue(Bytes.equals(parts[1], middle));
156  }
157
158  @Test
159  public void testSplit3() {
160    // Test invalid split cases
161    byte[] low = { 1, 1, 1 };
162    byte[] high = { 1, 1, 3 };
163
164    // If swapped, should throw IAE
165    try {
166      Bytes.split(high, low, 1);
167      fail("Should not be able to split if low > high");
168    } catch (IllegalArgumentException iae) {
169      // Correct
170    }
171
172    // Single split should work
173    byte[][] parts = Bytes.split(low, high, 1);
174    for (int i = 0; i < parts.length; i++) {
175      System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
176    }
177    assertEquals("Returned split should have 3 parts but has " + parts.length, 3, parts.length);
178
179    // If split more than once, use additional byte to split
180    parts = Bytes.split(low, high, 2);
181    assertNotNull("Split with an additional byte", parts);
182    assertEquals(parts.length, low.length + 1);
183
184    // Split 0 times should throw IAE
185    try {
186      Bytes.split(low, high, 0);
187      fail("Should not be able to split 0 times");
188    } catch (IllegalArgumentException iae) {
189      // Correct
190    }
191  }
192
193  @Test
194  public void testToInt() {
195    int[] ints = { -1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE };
196    for (int anInt : ints) {
197      byte[] b = Bytes.toBytes(anInt);
198      assertEquals(anInt, Bytes.toInt(b));
199      byte[] b2 = bytesWithOffset(b);
200      assertEquals(anInt, Bytes.toInt(b2, 1));
201      assertEquals(anInt, Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
202    }
203  }
204
205  @Test
206  public void testToLong() {
207    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
208    for (long aLong : longs) {
209      byte[] b = Bytes.toBytes(aLong);
210      assertEquals(aLong, Bytes.toLong(b));
211      byte[] b2 = bytesWithOffset(b);
212      assertEquals(aLong, Bytes.toLong(b2, 1));
213      assertEquals(aLong, Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
214    }
215  }
216
217  @Test
218  public void testToFloat() {
219    float[] floats = { -1f, 123.123f, Float.MAX_VALUE };
220    for (float aFloat : floats) {
221      byte[] b = Bytes.toBytes(aFloat);
222      assertEquals(aFloat, Bytes.toFloat(b), 0.0f);
223      byte[] b2 = bytesWithOffset(b);
224      assertEquals(aFloat, Bytes.toFloat(b2, 1), 0.0f);
225    }
226  }
227
228  @Test
229  public void testToDouble() {
230    double[] doubles = { Double.MIN_VALUE, Double.MAX_VALUE };
231    for (double aDouble : doubles) {
232      byte[] b = Bytes.toBytes(aDouble);
233      assertEquals(aDouble, Bytes.toDouble(b), 0.0);
234      byte[] b2 = bytesWithOffset(b);
235      assertEquals(aDouble, Bytes.toDouble(b2, 1), 0.0);
236    }
237  }
238
239  @Test
240  public void testToBigDecimal() {
241    BigDecimal[] decimals =
242      { new BigDecimal("-1"), new BigDecimal("123.123"), new BigDecimal("123123123123") };
243    for (BigDecimal decimal : decimals) {
244      byte[] b = Bytes.toBytes(decimal);
245      assertEquals(decimal, Bytes.toBigDecimal(b));
246      byte[] b2 = bytesWithOffset(b);
247      assertEquals(decimal, Bytes.toBigDecimal(b2, 1, b.length));
248    }
249  }
250
251  private byte[] bytesWithOffset(byte[] src) {
252    // add one byte in front to test offset
253    byte[] result = new byte[src.length + 1];
254    result[0] = (byte) 0xAA;
255    System.arraycopy(src, 0, result, 1, src.length);
256    return result;
257  }
258
259  @Test
260  public void testToBytesForByteBuffer() {
261    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
262    ByteBuffer target = ByteBuffer.wrap(array);
263    target.position(2);
264    target.limit(7);
265
266    byte[] actual = Bytes.toBytes(target);
267    byte[] expected = { 0, 1, 2, 3, 4, 5, 6 };
268    assertArrayEquals(expected, actual);
269    assertEquals(2, target.position());
270    assertEquals(7, target.limit());
271
272    ByteBuffer target2 = target.slice();
273    assertEquals(0, target2.position());
274    assertEquals(5, target2.limit());
275
276    byte[] actual2 = Bytes.toBytes(target2);
277    byte[] expected2 = { 2, 3, 4, 5, 6 };
278    assertArrayEquals(expected2, actual2);
279    assertEquals(0, target2.position());
280    assertEquals(5, target2.limit());
281  }
282
283  @Test
284  public void testGetBytesForByteBuffer() {
285    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
286    ByteBuffer target = ByteBuffer.wrap(array);
287    target.position(2);
288    target.limit(7);
289
290    byte[] actual = Bytes.getBytes(target);
291    byte[] expected = { 2, 3, 4, 5, 6 };
292    assertArrayEquals(expected, actual);
293    assertEquals(2, target.position());
294    assertEquals(7, target.limit());
295  }
296
297  @Test
298  public void testReadAsVLong() throws Exception {
299    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
300    for (long aLong : longs) {
301      ByteArrayOutputStream baos = new ByteArrayOutputStream();
302      DataOutputStream output = new DataOutputStream(baos);
303      WritableUtils.writeVLong(output, aLong);
304      byte[] long_bytes_no_offset = baos.toByteArray();
305      assertEquals(aLong, Bytes.readAsVLong(long_bytes_no_offset, 0));
306      byte[] long_bytes_with_offset = bytesWithOffset(long_bytes_no_offset);
307      assertEquals(aLong, Bytes.readAsVLong(long_bytes_with_offset, 1));
308    }
309  }
310
311  @Test
312  public void testToStringBinaryForBytes() {
313    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
314    String actual = Bytes.toStringBinary(array);
315    String expected = "09azAZ@\\x01";
316    assertEquals(expected, actual);
317
318    String actual2 = Bytes.toStringBinary(array, 2, 3);
319    String expected2 = "azA";
320    assertEquals(expected2, actual2);
321  }
322
323  @Test
324  public void testToStringBinaryForArrayBasedByteBuffer() {
325    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
326    ByteBuffer target = ByteBuffer.wrap(array);
327    String actual = Bytes.toStringBinary(target);
328    String expected = "09azAZ@\\x01";
329    assertEquals(expected, actual);
330  }
331
332  @Test
333  public void testToStringBinaryForReadOnlyByteBuffer() {
334    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
335    ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer();
336    String actual = Bytes.toStringBinary(target);
337    String expected = "09azAZ@\\x01";
338    assertEquals(expected, actual);
339  }
340
341  @Test
342  public void testBinarySearch() {
343    byte[][] arr = { { 1 }, { 3 }, { 5 }, { 7 }, { 9 }, { 11 }, { 13 }, { 15 }, };
344    byte[] key1 = { 3, 1 };
345    byte[] key2 = { 4, 9 };
346    byte[] key2_2 = { 4 };
347    byte[] key3 = { 5, 11 };
348    byte[] key4 = { 0 };
349    byte[] key5 = { 2 };
350
351    assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1));
352    assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1));
353    assertEquals(-(2 + 1), Arrays.binarySearch(arr, key2_2, Bytes.BYTES_COMPARATOR));
354    assertEquals(-(2 + 1), Bytes.binarySearch(arr, key2, 0, 1));
355    assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1));
356    assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1));
357    assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1));
358    assertEquals(-1, Bytes.binarySearch(arr, key4, 0, 1));
359    assertEquals(-2, Bytes.binarySearch(arr, key5, 0, 1));
360
361    // Search for values to the left and to the right of each item in the array.
362    for (int i = 0; i < arr.length; ++i) {
363      assertEquals(-(i + 1), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] - 1) }, 0, 1));
364      assertEquals(-(i + 2), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] + 1) }, 0, 1));
365    }
366  }
367
368  @Test
369  public void testToStringBytesBinaryReversible() {
370    byte[] randomBytes = new byte[1000];
371    for (int i = 0; i < 1000; i++) {
372      Bytes.random(randomBytes);
373      verifyReversibleForBytes(randomBytes);
374    }
375    // some specific cases
376    verifyReversibleForBytes(new byte[] {});
377    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D' });
378    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D', '\\' });
379  }
380
381  private void verifyReversibleForBytes(byte[] originalBytes) {
382    String convertedString = Bytes.toStringBinary(originalBytes);
383    byte[] convertedBytes = Bytes.toBytesBinary(convertedString);
384    if (Bytes.compareTo(originalBytes, convertedBytes) != 0) {
385      fail("Not reversible for\nbyte[]: " + Arrays.toString(originalBytes) + ",\nStringBinary: "
386        + convertedString);
387    }
388  }
389
390  @Test
391  public void testStartsWith() {
392    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
393    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
394    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
395    assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
396    assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
397  }
398
399  @Test
400  public void testIncrementBytes() {
401    assertTrue(checkTestIncrementBytes(10, 1));
402    assertTrue(checkTestIncrementBytes(12, 123435445));
403    assertTrue(checkTestIncrementBytes(124634654, 1));
404    assertTrue(checkTestIncrementBytes(10005460, 5005645));
405    assertTrue(checkTestIncrementBytes(1, -1));
406    assertTrue(checkTestIncrementBytes(10, -1));
407    assertTrue(checkTestIncrementBytes(10, -5));
408    assertTrue(checkTestIncrementBytes(1005435000, -5));
409    assertTrue(checkTestIncrementBytes(10, -43657655));
410    assertTrue(checkTestIncrementBytes(-1, 1));
411    assertTrue(checkTestIncrementBytes(-26, 5034520));
412    assertTrue(checkTestIncrementBytes(-10657200, 5));
413    assertTrue(checkTestIncrementBytes(-12343250, 45376475));
414    assertTrue(checkTestIncrementBytes(-10, -5));
415    assertTrue(checkTestIncrementBytes(-12343250, -5));
416    assertTrue(checkTestIncrementBytes(-12, -34565445));
417    assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
418  }
419
420  private static boolean checkTestIncrementBytes(long val, long amount) {
421    byte[] value = Bytes.toBytes(val);
422    byte[] testValue = { -1, -1, -1, -1, -1, -1, -1, -1 };
423    if (value[0] > 0) {
424      testValue = new byte[Bytes.SIZEOF_LONG];
425    }
426    System.arraycopy(value, 0, testValue, testValue.length - value.length, value.length);
427
428    long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
429
430    return (Bytes.toLong(testValue) + amount) == incrementResult;
431  }
432
433  @Test
434  public void testFixedSizeString() throws IOException {
435    ByteArrayOutputStream baos = new ByteArrayOutputStream();
436    DataOutputStream dos = new DataOutputStream(baos);
437    Bytes.writeStringFixedSize(dos, "Hello", 5);
438    Bytes.writeStringFixedSize(dos, "World", 18);
439    Bytes.writeStringFixedSize(dos, "", 9);
440
441    try {
442      // Use a long dash which is three bytes in UTF-8. If encoding happens
443      // using ISO-8859-1, this will fail.
444      Bytes.writeStringFixedSize(dos, "Too\u2013Long", 9);
445      fail("Exception expected");
446    } catch (IOException ex) {
447      assertEquals(
448        "Trying to write 10 bytes (Too\\xE2\\x80\\x93Long) into a field of " + "length 9",
449        ex.getMessage());
450    }
451
452    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
453    DataInputStream dis = new DataInputStream(bais);
454    assertEquals("Hello", Bytes.readStringFixedSize(dis, 5));
455    assertEquals("World", Bytes.readStringFixedSize(dis, 18));
456    assertEquals("", Bytes.readStringFixedSize(dis, 9));
457  }
458
459  @Test
460  public void testCopy() {
461    byte[] bytes = Bytes.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
462    byte[] copy = Bytes.copy(bytes);
463    assertNotSame(bytes, copy);
464    assertTrue(Bytes.equals(bytes, copy));
465  }
466
467  @Test
468  public void testToBytesBinaryTrailingBackslashes() {
469    try {
470      Bytes.toBytesBinary("abc\\x00\\x01\\");
471    } catch (StringIndexOutOfBoundsException ex) {
472      fail("Illegal string access: " + ex.getMessage());
473    }
474  }
475
476  @Test
477  public void testToStringBinary_toBytesBinary_Reversable() {
478    String bytes = Bytes.toStringBinary(Bytes.toBytes(2.17));
479    assertEquals(2.17, Bytes.toDouble(Bytes.toBytesBinary(bytes)), 0);
480  }
481
482  @Test
483  public void testUnsignedBinarySearch() {
484    byte[] bytes = new byte[] { 0, 5, 123, 127, -128, -100, -1 };
485    Assert.assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 5));
486    Assert.assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 127));
487    Assert.assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -128));
488    Assert.assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -100));
489    Assert.assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -1));
490    Assert.assertEquals(-1 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 2));
491    Assert.assertEquals(-6 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -5));
492  }
493
494  @Test
495  public void testUnsignedIncrement() {
496    byte[] a = Bytes.toBytes(0);
497    int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
498    Assert.assertEquals(1, a2);
499
500    byte[] b = Bytes.toBytes(-1);
501    byte[] actual = Bytes.unsignedCopyAndIncrement(b);
502    Assert.assertNotSame(b, actual);
503    byte[] expected = new byte[] { 1, 0, 0, 0, 0 };
504    assertArrayEquals(expected, actual);
505
506    byte[] c = Bytes.toBytes(255);// should wrap to the next significant byte
507    int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
508    Assert.assertEquals(256, c2);
509  }
510
511  @Test
512  public void testIndexOf() {
513    byte[] array = Bytes.toBytes("hello");
514    assertEquals(1, Bytes.indexOf(array, (byte) 'e'));
515    assertEquals(4, Bytes.indexOf(array, (byte) 'o'));
516    assertEquals(-1, Bytes.indexOf(array, (byte) 'a'));
517    assertEquals(0, Bytes.indexOf(array, Bytes.toBytes("hel")));
518    assertEquals(2, Bytes.indexOf(array, Bytes.toBytes("ll")));
519    assertEquals(-1, Bytes.indexOf(array, Bytes.toBytes("hll")));
520  }
521
522  @Test
523  public void testContains() {
524    byte[] array = Bytes.toBytes("hello world");
525    assertTrue(Bytes.contains(array, (byte) 'e'));
526    assertTrue(Bytes.contains(array, (byte) 'd'));
527    assertFalse(Bytes.contains(array, (byte) 'a'));
528    assertTrue(Bytes.contains(array, Bytes.toBytes("world")));
529    assertTrue(Bytes.contains(array, Bytes.toBytes("ello")));
530    assertFalse(Bytes.contains(array, Bytes.toBytes("owo")));
531  }
532
533  @Test
534  public void testZero() {
535    byte[] array = Bytes.toBytes("hello");
536    Bytes.zero(array);
537    for (byte b : array) {
538      assertEquals(0, b);
539    }
540    array = Bytes.toBytes("hello world");
541    Bytes.zero(array, 2, 7);
542    assertFalse(array[0] == 0);
543    assertFalse(array[1] == 0);
544    for (int i = 2; i < 9; i++) {
545      assertEquals(0, array[i]);
546    }
547    for (int i = 9; i < array.length; i++) {
548      assertFalse(array[i] == 0);
549    }
550  }
551
552  @Test
553  public void testPutBuffer() {
554    byte[] b = new byte[100];
555    for (byte i = 0; i < 100; i++) {
556      Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[] { i }));
557    }
558    for (byte i = 0; i < 100; i++) {
559      Assert.assertEquals(i, b[i]);
560    }
561  }
562
563  @Test
564  public void testToFromHex() {
565    List<String> testStrings = new ArrayList<>(8);
566    testStrings.addAll(Arrays.asList("", "00", "A0", "ff", "FFffFFFFFFFFFF", "12",
567      "0123456789abcdef", "283462839463924623984692834692346ABCDFEDDCA0"));
568    for (String testString : testStrings) {
569      byte[] byteData = Bytes.fromHex(testString);
570      Assert.assertEquals(testString.length() / 2, byteData.length);
571      String result = Bytes.toHex(byteData);
572      Assert.assertTrue(testString.equalsIgnoreCase(result));
573    }
574
575    List<byte[]> testByteData = new ArrayList<>(5);
576    testByteData.addAll(Arrays.asList(new byte[0], new byte[1], new byte[10],
577      new byte[] { 1, 2, 3, 4, 5 }, new byte[] { (byte) 0xFF }));
578    Random rand = ThreadLocalRandom.current();
579    for (int i = 0; i < 20; i++) {
580      byte[] bytes = new byte[rand.nextInt(100)];
581      Bytes.random(bytes);
582      testByteData.add(bytes);
583    }
584
585    for (byte[] testData : testByteData) {
586      String hexString = Bytes.toHex(testData);
587      Assert.assertEquals(testData.length * 2, hexString.length());
588      byte[] result = Bytes.fromHex(hexString);
589      assertArrayEquals(testData, result);
590    }
591  }
592}