1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.util;
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.math.BigDecimal;
28  import java.util.Arrays;
29  
30  import junit.framework.TestCase;
31  
32  public class TestBytes extends TestCase {
33    public void testNullHashCode() {
34      byte [] b = null;
35      Exception ee = null;
36      try {
37        Bytes.hashCode(b);
38      } catch (Exception e) {
39        ee = e;
40      }
41      assertNotNull(ee);
42    }
43  
44    public void testSplit() throws Exception {
45      byte [] lowest = Bytes.toBytes("AAA");
46      byte [] middle = Bytes.toBytes("CCC");
47      byte [] highest = Bytes.toBytes("EEE");
48      byte [][] parts = Bytes.split(lowest, highest, 1);
49      for (int i = 0; i < parts.length; i++) {
50        System.out.println(Bytes.toString(parts[i]));
51      }
52      assertEquals(3, parts.length);
53      assertTrue(Bytes.equals(parts[1], middle));
54      // Now divide into three parts.  Change highest so split is even.
55      highest = Bytes.toBytes("DDD");
56      parts = Bytes.split(lowest, highest, 2);
57      for (int i = 0; i < parts.length; i++) {
58        System.out.println(Bytes.toString(parts[i]));
59      }
60      assertEquals(4, parts.length);
61      // Assert that 3rd part is 'CCC'.
62      assertTrue(Bytes.equals(parts[2], middle));
63    }
64  
65    public void testSplit2() throws Exception {
66      // More split tests.
67      byte [] lowest = Bytes.toBytes("http://A");
68      byte [] highest = Bytes.toBytes("http://z");
69      byte [] middle = Bytes.toBytes("http://]");
70      byte [][] parts = Bytes.split(lowest, highest, 1);
71      for (int i = 0; i < parts.length; i++) {
72        System.out.println(Bytes.toString(parts[i]));
73      }
74      assertEquals(3, parts.length);
75      assertTrue(Bytes.equals(parts[1], middle));
76    }
77  
78    public void testSplit3() throws Exception {
79      // Test invalid split cases
80      byte [] low = { 1, 1, 1 };
81      byte [] high = { 1, 1, 3 };
82  
83      // If swapped, should throw IAE
84      try {
85        Bytes.split(high, low, 1);
86        assertTrue("Should not be able to split if low > high", false);
87      } catch(IllegalArgumentException iae) {
88        // Correct
89      }
90  
91      // Single split should work
92      byte [][] parts = Bytes.split(low, high, 1);
93      for (int i = 0; i < parts.length; i++) {
94        System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
95      }
96      assertTrue("Returned split should have 3 parts but has " + parts.length, parts.length == 3);
97  
98      // If split more than once, this should fail
99      parts = Bytes.split(low, high, 2);
100     assertTrue("Returned split but should have failed", parts == null);
101 
102     // Split 0 times should throw IAE
103     try {
104       parts = Bytes.split(low, high, 0);
105       assertTrue("Should not be able to split 0 times", false);
106     } catch(IllegalArgumentException iae) {
107       // Correct
108     }
109   }
110 
111   public void testToInt() throws Exception {
112     int [] ints = {-1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE};
113     for (int i = 0; i < ints.length; i++) {
114       byte [] b = Bytes.toBytes(ints[i]);
115       assertEquals(ints[i], Bytes.toInt(b));
116       byte [] b2 = bytesWithOffset(b);
117       assertEquals(ints[i], Bytes.toInt(b2, 1));
118       assertEquals(ints[i], Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
119     }
120   }
121 
122   public void testToLong() throws Exception {
123     long [] longs = {-1l, 123l, Long.MIN_VALUE, Long.MAX_VALUE};
124     for (int i = 0; i < longs.length; i++) {
125       byte [] b = Bytes.toBytes(longs[i]);
126       assertEquals(longs[i], Bytes.toLong(b));
127       byte [] b2 = bytesWithOffset(b);
128       assertEquals(longs[i], Bytes.toLong(b2, 1));
129       assertEquals(longs[i], Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
130     }
131   }
132 
133   public void testToFloat() throws Exception {
134     float [] floats = {-1f, 123.123f, Float.MAX_VALUE};
135     for (int i = 0; i < floats.length; i++) {
136       byte [] b = Bytes.toBytes(floats[i]);
137       assertEquals(floats[i], Bytes.toFloat(b));
138       byte [] b2 = bytesWithOffset(b);
139       assertEquals(floats[i], Bytes.toFloat(b2, 1));
140     }
141   }
142 
143   public void testToDouble() throws Exception {
144     double [] doubles = {Double.MIN_VALUE, Double.MAX_VALUE};
145     for (int i = 0; i < doubles.length; i++) {
146       byte [] b = Bytes.toBytes(doubles[i]);
147       assertEquals(doubles[i], Bytes.toDouble(b));
148       byte [] b2 = bytesWithOffset(b);
149       assertEquals(doubles[i], Bytes.toDouble(b2, 1));
150     }
151   }
152 
153   public void testToBigDecimal() throws Exception {
154     BigDecimal [] decimals = {new BigDecimal("-1"), new BigDecimal("123.123"),
155       new BigDecimal("123123123123")};
156     for (int i = 0; i < decimals.length; i++) {
157       byte [] b = Bytes.toBytes(decimals[i]);
158       assertEquals(decimals[i], Bytes.toBigDecimal(b));
159       byte [] b2 = bytesWithOffset(b);
160       assertEquals(decimals[i], Bytes.toBigDecimal(b2, 1, b.length));
161     }
162   }
163   
164   private byte [] bytesWithOffset(byte [] src) {
165     // add one byte in front to test offset
166     byte [] result = new byte[src.length + 1];
167     result[0] = (byte) 0xAA;
168     System.arraycopy(src, 0, result, 1, src.length);
169     return result;
170   }
171   
172   public void testBinarySearch() throws Exception {
173     byte [][] arr = {
174         {1},
175         {3},
176         {5},
177         {7},
178         {9},
179         {11},
180         {13},
181         {15},
182     };
183     byte [] key1 = {3,1};
184     byte [] key2 = {4,9};
185     byte [] key2_2 = {4};
186     byte [] key3 = {5,11};
187     byte [] key4 = {0};
188     byte [] key5 = {2};
189 
190     assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1,
191       Bytes.BYTES_RAWCOMPARATOR));
192     assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1,
193       Bytes.BYTES_RAWCOMPARATOR));
194     assertEquals(-(2+1), Arrays.binarySearch(arr, key2_2,
195       Bytes.BYTES_COMPARATOR));
196     assertEquals(-(2+1), Bytes.binarySearch(arr, key2, 0, 1,
197       Bytes.BYTES_RAWCOMPARATOR));
198     assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1,
199       Bytes.BYTES_RAWCOMPARATOR));
200     assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1,
201       Bytes.BYTES_RAWCOMPARATOR));
202     assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1,
203       Bytes.BYTES_RAWCOMPARATOR));
204     assertEquals(-1,
205       Bytes.binarySearch(arr, key4, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
206     assertEquals(-2,
207       Bytes.binarySearch(arr, key5, 0, 1, Bytes.BYTES_RAWCOMPARATOR));
208 
209     // Search for values to the left and to the right of each item in the array.
210     for (int i = 0; i < arr.length; ++i) {
211       assertEquals(-(i + 1), Bytes.binarySearch(arr,
212           new byte[] { (byte) (arr[i][0] - 1) }, 0, 1,
213           Bytes.BYTES_RAWCOMPARATOR));
214       assertEquals(-(i + 2), Bytes.binarySearch(arr,
215           new byte[] { (byte) (arr[i][0] + 1) }, 0, 1,
216           Bytes.BYTES_RAWCOMPARATOR));
217     }
218   }
219 
220   public void testStartsWith() {
221     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
222     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
223     assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
224     assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
225     assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
226   }
227 
228   public void testIncrementBytes() throws IOException {
229 
230     assertTrue(checkTestIncrementBytes(10, 1));
231     assertTrue(checkTestIncrementBytes(12, 123435445));
232     assertTrue(checkTestIncrementBytes(124634654, 1));
233     assertTrue(checkTestIncrementBytes(10005460, 5005645));
234     assertTrue(checkTestIncrementBytes(1, -1));
235     assertTrue(checkTestIncrementBytes(10, -1));
236     assertTrue(checkTestIncrementBytes(10, -5));
237     assertTrue(checkTestIncrementBytes(1005435000, -5));
238     assertTrue(checkTestIncrementBytes(10, -43657655));
239     assertTrue(checkTestIncrementBytes(-1, 1));
240     assertTrue(checkTestIncrementBytes(-26, 5034520));
241     assertTrue(checkTestIncrementBytes(-10657200, 5));
242     assertTrue(checkTestIncrementBytes(-12343250, 45376475));
243     assertTrue(checkTestIncrementBytes(-10, -5));
244     assertTrue(checkTestIncrementBytes(-12343250, -5));
245     assertTrue(checkTestIncrementBytes(-12, -34565445));
246     assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
247   }
248 
249   private static boolean checkTestIncrementBytes(long val, long amount)
250   throws IOException {
251     byte[] value = Bytes.toBytes(val);
252     byte [] testValue = {-1, -1, -1, -1, -1, -1, -1, -1};
253     if (value[0] > 0) {
254       testValue = new byte[Bytes.SIZEOF_LONG];
255     }
256     System.arraycopy(value, 0, testValue, testValue.length - value.length,
257         value.length);
258 
259     long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
260 
261     return (Bytes.toLong(testValue) + amount) == incrementResult;
262   }
263 
264   public void testFixedSizeString() throws IOException {
265     ByteArrayOutputStream baos = new ByteArrayOutputStream();
266     DataOutputStream dos = new DataOutputStream(baos);
267     Bytes.writeStringFixedSize(dos, "Hello", 5);
268     Bytes.writeStringFixedSize(dos, "World", 18);
269     Bytes.writeStringFixedSize(dos, "", 9);
270 
271     try {
272       // Use a long dash which is three bytes in UTF-8. If encoding happens
273       // using ISO-8859-1, this will fail.
274       Bytes.writeStringFixedSize(dos, "Too\u2013Long", 9);
275       fail("Exception expected");
276     } catch (IOException ex) {
277       assertEquals(
278           "Trying to write 10 bytes (Too\\xE2\\x80\\x93Long) into a field of " +
279           "length 9", ex.getMessage());
280     }
281 
282     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
283     DataInputStream dis = new DataInputStream(bais);
284     assertEquals("Hello", Bytes.readStringFixedSize(dis, 5));
285     assertEquals("World", Bytes.readStringFixedSize(dis, 18));
286     assertEquals("", Bytes.readStringFixedSize(dis, 9));
287   }
288 
289 }