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 static org.junit.Assert.assertArrayEquals;
21  
22  import java.io.ByteArrayInputStream;
23  import java.io.ByteArrayOutputStream;
24  import java.io.DataInputStream;
25  import java.io.DataOutputStream;
26  import java.io.IOException;
27  import java.lang.reflect.Field;
28  import java.lang.reflect.Modifier;
29  import java.math.BigDecimal;
30  import java.nio.ByteBuffer;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.List;
34  import java.util.Random;
35  
36  import junit.framework.TestCase;
37  
38  import org.apache.hadoop.hbase.testclassification.SmallTests;
39  import org.apache.hadoop.io.WritableUtils;
40  import org.junit.Assert;
41  import org.junit.experimental.categories.Category;
42  
43  @Category(SmallTests.class)
44  public class TestBytes extends TestCase {
45    private static void setUnsafe(boolean value) throws Exception {
46      Field field = Bytes.class.getDeclaredField("UNSAFE_UNALIGNED");
47      field.setAccessible(true);
48      Field modifiersField = Field.class.getDeclaredField("modifiers");
49      modifiersField.setAccessible(true);
50      int oldModifiers = field.getModifiers();
51      modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
52      try {
53        field.set(null, value);
54      } finally {
55        modifiersField.setInt(field, oldModifiers);
56      }
57      assertEquals(Bytes.UNSAFE_UNALIGNED, value);
58    }
59  
60    public void testShort() throws Exception  {
61      testShort(false);
62    }
63  
64    public void testShortUnsafe() throws Exception  {
65      testShort(true);
66    }
67  
68    private static void testShort(boolean unsafe) throws Exception  {
69      setUnsafe(unsafe);
70      try {
71        for (short n : Arrays.asList(
72                Short.MIN_VALUE,
73                (short) -100,
74                (short) -1,
75                (short) 0,
76                (short) 1,
77                (short) 300,
78                Short.MAX_VALUE)) {
79          byte[] bytes = Bytes.toBytes(n);
80          assertEquals(Bytes.toShort(bytes, 0, bytes.length), n);
81        }
82      } finally {
83        setUnsafe(UnsafeAvailChecker.unaligned());
84      }
85    }
86  
87    public void testNullHashCode() {
88      byte [] b = null;
89      Exception ee = null;
90      try {
91        Bytes.hashCode(b);
92      } catch (Exception e) {
93        ee = e;
94      }
95      assertNotNull(ee);
96    }
97  
98    public void testAdd() {
99      byte[] a = {0,0,0,0,0,0,0,0,0,0};
100     byte[] b = {1,1,1,1,1,1,1,1,1,1,1};
101     byte[] c = {2,2,2,2,2,2,2,2,2,2,2,2};
102     byte[] d = {3,3,3,3,3,3,3,3,3,3,3,3,3};
103     byte[] result1 = Bytes.add(a, b, c);
104     byte[] result2 = Bytes.add(new byte[][] {a, b, c});
105     assertEquals(0, Bytes.compareTo(result1, result2));
106     byte[] result4 = Bytes.add(result1, d);
107     byte[] result5 = Bytes.add(new byte[][] {result1, d});
108     assertEquals(0, Bytes.compareTo(result1, result2));
109   }
110 
111   public void testSplit() {
112     byte[] lowest = Bytes.toBytes("AAA");
113     byte[] middle = Bytes.toBytes("CCC");
114     byte[] highest = Bytes.toBytes("EEE");
115     byte[][] parts = Bytes.split(lowest, highest, 1);
116     for (byte[] bytes : parts) {
117       System.out.println(Bytes.toString(bytes));
118     }
119     assertEquals(3, parts.length);
120     assertTrue(Bytes.equals(parts[1], middle));
121     // Now divide into three parts.  Change highest so split is even.
122     highest = Bytes.toBytes("DDD");
123     parts = Bytes.split(lowest, highest, 2);
124     for (byte[] part : parts) {
125       System.out.println(Bytes.toString(part));
126     }
127     assertEquals(4, parts.length);
128     // Assert that 3rd part is 'CCC'.
129     assertTrue(Bytes.equals(parts[2], middle));
130   }
131 
132   public void testSplit2() {
133     // More split tests.
134     byte [] lowest = Bytes.toBytes("http://A");
135     byte [] highest = Bytes.toBytes("http://z");
136     byte [] middle = Bytes.toBytes("http://]");
137     byte [][] parts = Bytes.split(lowest, highest, 1);
138     for (byte[] part : parts) {
139       System.out.println(Bytes.toString(part));
140     }
141     assertEquals(3, parts.length);
142     assertTrue(Bytes.equals(parts[1], middle));
143   }
144 
145   public void testSplit3() {
146     // Test invalid split cases
147     byte[] low = { 1, 1, 1 };
148     byte[] high = { 1, 1, 3 };
149 
150     // If swapped, should throw IAE
151     try {
152       Bytes.split(high, low, 1);
153       fail("Should not be able to split if low > high");
154     } catch(IllegalArgumentException iae) {
155       // Correct
156     }
157 
158     // Single split should work
159     byte[][] parts = Bytes.split(low, high, 1);
160     for (int i = 0; i < parts.length; i++) {
161       System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
162     }
163     assertEquals("Returned split should have 3 parts but has " + parts.length, 3, parts.length);
164 
165     // If split more than once, use additional byte to split
166     parts = Bytes.split(low, high, 2);
167     assertNotNull("Split with an additional byte", parts);
168     assertEquals(parts.length, low.length + 1);
169 
170     // Split 0 times should throw IAE
171     try {
172       Bytes.split(low, high, 0);
173       fail("Should not be able to split 0 times");
174     } catch(IllegalArgumentException iae) {
175       // Correct
176     }
177   }
178 
179   public void testToInt() {
180     int[] ints = { -1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE };
181     for (int anInt : ints) {
182       byte[] b = Bytes.toBytes(anInt);
183       assertEquals(anInt, Bytes.toInt(b));
184       byte[] b2 = bytesWithOffset(b);
185       assertEquals(anInt, Bytes.toInt(b2, 1));
186       assertEquals(anInt, Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
187     }
188   }
189 
190   public void testToLong() {
191     long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
192     for (long aLong : longs) {
193       byte[] b = Bytes.toBytes(aLong);
194       assertEquals(aLong, Bytes.toLong(b));
195       byte[] b2 = bytesWithOffset(b);
196       assertEquals(aLong, Bytes.toLong(b2, 1));
197       assertEquals(aLong, Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
198     }
199   }
200 
201   public void testToFloat() {
202     float[] floats = { -1f, 123.123f, Float.MAX_VALUE };
203     for (float aFloat : floats) {
204       byte[] b = Bytes.toBytes(aFloat);
205       assertEquals(aFloat, Bytes.toFloat(b), 0.0f);
206       byte[] b2 = bytesWithOffset(b);
207       assertEquals(aFloat, Bytes.toFloat(b2, 1), 0.0f);
208     }
209   }
210 
211   public void testToDouble() {
212     double [] doubles = {Double.MIN_VALUE, Double.MAX_VALUE};
213     for (double aDouble : doubles) {
214       byte[] b = Bytes.toBytes(aDouble);
215       assertEquals(aDouble, Bytes.toDouble(b), 0.0);
216       byte[] b2 = bytesWithOffset(b);
217       assertEquals(aDouble, Bytes.toDouble(b2, 1), 0.0);
218     }
219   }
220 
221   public void testToBigDecimal() {
222     BigDecimal[] decimals = { new BigDecimal("-1"), new BigDecimal("123.123"),
223       new BigDecimal("123123123123") };
224     for (BigDecimal decimal : decimals) {
225       byte[] b = Bytes.toBytes(decimal);
226       assertEquals(decimal, Bytes.toBigDecimal(b));
227       byte[] b2 = bytesWithOffset(b);
228       assertEquals(decimal, Bytes.toBigDecimal(b2, 1, b.length));
229     }
230   }
231 
232   private byte[] bytesWithOffset(byte[] src) {
233     // add one byte in front to test offset
234     byte [] result = new byte[src.length + 1];
235     result[0] = (byte) 0xAA;
236     System.arraycopy(src, 0, result, 1, src.length);
237     return result;
238   }
239 
240   public void testToBytesForByteBuffer() {
241     byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
242     ByteBuffer target = ByteBuffer.wrap(array);
243     target.position(2);
244     target.limit(7);
245 
246     byte[] actual = Bytes.toBytes(target);
247     byte[] expected = { 0, 1, 2, 3, 4, 5, 6 };
248     assertArrayEquals(expected, actual);
249     assertEquals(2, target.position());
250     assertEquals(7, target.limit());
251 
252     ByteBuffer target2 = target.slice();
253     assertEquals(0, target2.position());
254     assertEquals(5, target2.limit());
255 
256     byte[] actual2 = Bytes.toBytes(target2);
257     byte[] expected2 = { 2, 3, 4, 5, 6 };
258     assertArrayEquals(expected2, actual2);
259     assertEquals(0, target2.position());
260     assertEquals(5, target2.limit());
261   }
262 
263   public void testGetBytesForByteBuffer() {
264     byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
265     ByteBuffer target = ByteBuffer.wrap(array);
266     target.position(2);
267     target.limit(7);
268 
269     byte[] actual = Bytes.getBytes(target);
270     byte[] expected = { 2, 3, 4, 5, 6 };
271     assertArrayEquals(expected, actual);
272     assertEquals(2, target.position());
273     assertEquals(7, target.limit());
274   }
275 
276   public void testReadAsVLong() throws Exception {
277     long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
278     for (long aLong : longs) {
279       ByteArrayOutputStream baos = new ByteArrayOutputStream();
280       DataOutputStream output = new DataOutputStream(baos);
281       WritableUtils.writeVLong(output, aLong);
282       byte[] long_bytes_no_offset = baos.toByteArray();
283       assertEquals(aLong, Bytes.readAsVLong(long_bytes_no_offset, 0));
284       byte[] long_bytes_with_offset = bytesWithOffset(long_bytes_no_offset);
285       assertEquals(aLong, Bytes.readAsVLong(long_bytes_with_offset, 1));
286     }
287   }
288 
289   public void testToStringBinaryForBytes() {
290     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
291     String actual = Bytes.toStringBinary(array);
292     String expected = "09azAZ@\\x01";
293     assertEquals(expected, actual);
294 
295     String actual2 = Bytes.toStringBinary(array, 2, 3);
296     String expected2 = "azA";
297     assertEquals(expected2, actual2);
298   }
299 
300   public void testToStringBinaryForArrayBasedByteBuffer() {
301     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
302     ByteBuffer target = ByteBuffer.wrap(array);
303     String actual = Bytes.toStringBinary(target);
304     String expected = "09azAZ@\\x01";
305     assertEquals(expected, actual);
306   }
307 
308   public void testToStringBinaryForReadOnlyByteBuffer() {
309     byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
310     ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer();
311     String actual = Bytes.toStringBinary(target);
312     String expected = "09azAZ@\\x01";
313     assertEquals(expected, actual);
314   }
315 
316   public void testBinarySearch() {
317     byte[][] arr = {
318         { 1 },
319         { 3 },
320         { 5 },
321         { 7 },
322         { 9 },
323         { 11 },
324         { 13 },
325         { 15 },
326     };
327     byte[] key1 = { 3, 1 };
328     byte[] key2 = { 4, 9 };
329     byte[] key2_2 = { 4 };
330     byte[] key3 = { 5, 11 };
331     byte[] key4 = { 0 };
332     byte[] key5 = { 2 };
333 
334     assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1,
335       Bytes.BYTES_RAWCOMPARATOR));
336     assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1,
337       Bytes.BYTES_RAWCOMPARATOR));
338     assertEquals(-(2+1), Arrays.binarySearch(arr, key2_2,
339       Bytes.BYTES_COMPARATOR));
340     assertEquals(-(2+1), Bytes.binarySearch(arr, key2, 0, 1,
341       Bytes.BYTES_RAWCOMPARATOR));
342     assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1,
343       Bytes.BYTES_RAWCOMPARATOR));
344     assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1,
345       Bytes.BYTES_RAWCOMPARATOR));
346     assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1,
347       Bytes.BYTES_RAWCOMPARATOR));
348     assertEquals(-1,
349       Bytes.binarySearch(arr, key4, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
350     assertEquals(-2,
351       Bytes.binarySearch(arr, key5, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
352 
353     // Search for values to the left and to the right of each item in the array.
354     for (int i = 0; i < arr.length; ++i) {
355       assertEquals(-(i + 1), Bytes.binarySearch(arr,
356           new byte[] { (byte) (arr[i][0] - 1) }, 0, 1,
357           Bytes.BYTES_RAWCOMPARATOR));
358       assertEquals(-(i + 2), Bytes.binarySearch(arr,
359           new byte[] { (byte) (arr[i][0] + 1) }, 0, 1,
360           Bytes.BYTES_RAWCOMPARATOR));
361     }
362   }
363 
364   public void testToStringBytesBinaryReversible() {
365     //  let's run test with 1000 randomly generated byte arrays
366     Random rand = new Random(System.currentTimeMillis());
367     byte[] randomBytes = new byte[1000];
368     for (int i = 0; i < 1000; i++) {
369       rand.nextBytes(randomBytes);
370       verifyReversibleForBytes(randomBytes);
371     }
372 
373     //  some specific cases
374     verifyReversibleForBytes(new  byte[] {});
375     verifyReversibleForBytes(new  byte[] {'\\', 'x', 'A', 'D'});
376     verifyReversibleForBytes(new  byte[] {'\\', 'x', 'A', 'D', '\\'});
377   }
378 
379   private void verifyReversibleForBytes(byte[] originalBytes) {
380     String convertedString = Bytes.toStringBinary(originalBytes);
381     byte[] convertedBytes = Bytes.toBytesBinary(convertedString);
382     if (Bytes.compareTo(originalBytes, convertedBytes) != 0) {
383       fail("Not reversible for\nbyte[]: " + Arrays.toString(originalBytes) +
384           ",\nStringBinary: " + convertedString);
385     }
386   }
387 
388   public void testStartsWith() {
389     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
390     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
391     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
392     assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
393     assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
394   }
395 
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,
423         value.length);
424 
425     long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
426 
427     return (Bytes.toLong(testValue) + amount) == incrementResult;
428   }
429 
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 " +
445           "length 9", 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   public void testCopy() {
456     byte[] bytes = Bytes.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
457     byte[] copy =  Bytes.copy(bytes);
458     assertNotSame(bytes, copy);
459     assertTrue(Bytes.equals(bytes, copy));
460   }
461 
462   public void testToBytesBinaryTrailingBackslashes() {
463     try {
464       Bytes.toBytesBinary("abc\\x00\\x01\\");
465     } catch (StringIndexOutOfBoundsException ex) {
466       fail("Illegal string access: " + ex.getMessage());
467     }
468   }
469 
470   public void testToStringBinary_toBytesBinary_Reversable() {
471     String bytes = Bytes.toStringBinary(Bytes.toBytes(2.17));
472     assertEquals(2.17, Bytes.toDouble(Bytes.toBytesBinary(bytes)), 0);
473   }
474 
475   public void testUnsignedBinarySearch(){
476     byte[] bytes = new byte[] { 0,5,123,127,-128,-100,-1 };
477     Assert.assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)5));
478     Assert.assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)127));
479     Assert.assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-128));
480     Assert.assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-100));
481     Assert.assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-1));
482     Assert.assertEquals(-1-1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)2));
483     Assert.assertEquals(-6-1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte)-5));
484   }
485 
486   public void testUnsignedIncrement(){
487     byte[] a = Bytes.toBytes(0);
488     int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
489     Assert.assertEquals(1, a2);
490 
491     byte[] b = Bytes.toBytes(-1);
492     byte[] actual = Bytes.unsignedCopyAndIncrement(b);
493     Assert.assertNotSame(b, actual);
494     byte[] expected = new byte[]{1,0,0,0,0};
495     assertArrayEquals(expected, actual);
496 
497     byte[] c = Bytes.toBytes(255);//should wrap to the next significant byte
498     int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
499     Assert.assertEquals(256, c2);
500   }
501 
502   public void testIndexOf() {
503     byte[] array = Bytes.toBytes("hello");
504     assertEquals(1, Bytes.indexOf(array, (byte) 'e'));
505     assertEquals(4, Bytes.indexOf(array, (byte) 'o'));
506     assertEquals(-1, Bytes.indexOf(array, (byte) 'a'));
507     assertEquals(0, Bytes.indexOf(array, Bytes.toBytes("hel")));
508     assertEquals(2, Bytes.indexOf(array, Bytes.toBytes("ll")));
509     assertEquals(-1, Bytes.indexOf(array, Bytes.toBytes("hll")));
510   }
511 
512   public void testContains() {
513     byte[] array = Bytes.toBytes("hello world");
514     assertTrue(Bytes.contains(array, (byte) 'e'));
515     assertTrue(Bytes.contains(array, (byte) 'd'));
516     assertFalse(Bytes.contains(array, (byte) 'a'));
517     assertTrue(Bytes.contains(array, Bytes.toBytes("world")));
518     assertTrue(Bytes.contains(array, Bytes.toBytes("ello")));
519     assertFalse(Bytes.contains(array, Bytes.toBytes("owo")));
520   }
521 
522   public void testZero() {
523     byte[] array = Bytes.toBytes("hello");
524     Bytes.zero(array);
525     for (byte b : array) {
526       assertEquals(0, b);
527     }
528     array = Bytes.toBytes("hello world");
529     Bytes.zero(array, 2, 7);
530     assertFalse(array[0] == 0);
531     assertFalse(array[1] == 0);
532     for (int i = 2; i < 9; i++) {
533       assertEquals(0, array[i]);
534     }
535     for (int i = 9; i < array.length; i++) {
536       assertFalse(array[i] == 0);
537     }
538   }
539 
540   public void testPutBuffer() {
541     byte[] b = new byte[100];
542     for (byte i = 0; i < 100; i++) {
543       Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[] { i }));
544     }
545     for (byte i = 0; i < 100; i++) {
546       Assert.assertEquals(i, b[i]);
547     }
548   }
549 
550   public void testToFromHex() {
551     List<String> testStrings = new ArrayList<>();
552     testStrings.addAll(Arrays.asList("", "00", "A0", "ff", "FFffFFFFFFFFFF", "12",
553       "0123456789abcdef", "283462839463924623984692834692346ABCDFEDDCA0"));
554     for (String testString : testStrings) {
555       byte[] byteData = Bytes.fromHex(testString);
556       Assert.assertEquals(testString.length() / 2, byteData.length);
557       String result = Bytes.toHex(byteData);
558       Assert.assertTrue(testString.equalsIgnoreCase(result));
559     }
560 
561     List<byte[]> testByteData = new ArrayList<>(Arrays.asList(new byte[0], new byte[1],
562       new byte[10], new byte[] { 1, 2, 3, 4, 5 }, new byte[] { (byte) 0xFF }));
563     Random r = new Random();
564     for (int i = 0; i < 20; i++) {
565       byte[] bytes = new byte[r.nextInt(100)];
566       r.nextBytes(bytes);
567       testByteData.add(bytes);
568     }
569 
570     for (byte[] testData : testByteData) {
571       String hexString = Bytes.toHex(testData);
572       Assert.assertEquals(testData.length * 2, hexString.length());
573       byte[] result = Bytes.fromHex(hexString);
574       assertArrayEquals(testData, result);
575     }
576   }
577 }