View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.binary;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.io.UnsupportedEncodingException;
26  import java.nio.charset.Charset;
27  import java.nio.charset.UnsupportedCharsetException;
28  import java.util.Arrays;
29  import java.util.Random;
30  
31  import org.junit.Assert;
32  
33  import org.apache.commons.codec.DecoderException;
34  import org.apache.commons.codec.EncoderException;
35  import org.junit.Test;
36  
37  /**
38   * Tests {@link org.apache.commons.codec.binary.Hex}.
39   *
40   * @version $Id: HexTest.html 889935 2013-12-11 05:05:13Z ggregory $
41   */
42  public class HexTest {
43  
44      private static final String BAD_ENCODING_NAME = "UNKNOWN";
45  
46      private final static boolean LOG = false;
47  
48      private boolean charsetSanityCheck(final String name) {
49          final String source = "the quick brown dog jumped over the lazy fox";
50          try {
51              final byte[] bytes = source.getBytes(name);
52              final String str = new String(bytes, name);
53              final boolean equals = source.equals(str);
54              if (equals == false) {
55                  // Here with:
56                  //
57                  // Java Sun 1.4.2_19 x86 32-bits on Windows XP
58                  // JIS_X0212-1990
59                  // x-JIS0208
60                  //
61                  // Java Sun 1.5.0_17 x86 32-bits on Windows XP
62                  // JIS_X0212-1990
63                  // x-IBM834
64                  // x-JIS0208
65                  // x-MacDingbat
66                  // x-MacSymbol
67                  //
68                  // Java Sun 1.6.0_14 x86 32-bits
69                  // JIS_X0212-1990
70                  // x-IBM834
71                  // x-JIS0208
72                  // x-MacDingbat
73                  // x-MacSymbol
74                  //
75                  log("FAILED charsetSanityCheck=Interesting Java charset oddity: Roundtrip failed for " + name);
76              }
77              return equals;
78          } catch (final UnsupportedEncodingException e) {
79              // Should NEVER happen since we are getting the name from the Charset class.
80              if (LOG) {
81                  log("FAILED charsetSanityCheck=" + name + ", e=" + e);
82                  log(e);
83              }
84              return false;
85          } catch (final UnsupportedOperationException e) {
86              // Caught here with:
87              // x-JISAutoDetect on Windows XP and Java Sun 1.4.2_19 x86 32-bits
88              // x-JISAutoDetect on Windows XP and Java Sun 1.5.0_17 x86 32-bits
89              // x-JISAutoDetect on Windows XP and Java Sun 1.6.0_14 x86 32-bits
90              if (LOG) {
91                  log("FAILED charsetSanityCheck=" + name + ", e=" + e);
92                  log(e);
93              }
94              return false;
95          }
96      }
97  
98      /**
99       * @param data
100      */
101     private void checkDecodeHexOddCharacters(final char[] data) {
102         try {
103             Hex.decodeHex(data);
104             fail("An exception wasn't thrown when trying to decode an odd number of characters");
105         } catch (final DecoderException e) {
106             // Expected exception
107         }
108     }
109 
110     private void log(final String s) {
111         if (LOG) {
112             System.out.println(s);
113             System.out.flush();
114         }
115     }
116 
117     private void log(final Throwable t) {
118         if (LOG) {
119             t.printStackTrace(System.out);
120             System.out.flush();
121         }
122     }
123 
124     @Test
125     public void testCustomCharset() throws UnsupportedEncodingException, DecoderException {
126         for (final String name : Charset.availableCharsets().keySet()) {
127             testCustomCharset(name, "testCustomCharset");
128         }
129     }
130 
131     /**
132      * @param name
133      * @param parent
134      *            TODO
135      * @throws UnsupportedEncodingException
136      * @throws DecoderException
137      */
138     private void testCustomCharset(final String name, final String parent) throws UnsupportedEncodingException, DecoderException {
139         if (charsetSanityCheck(name) == false) {
140             return;
141         }
142         log(parent + "=" + name);
143         final Hex customCodec = new Hex(name);
144         // source data
145         final String sourceString = "Hello World";
146         final byte[] sourceBytes = sourceString.getBytes(name);
147         // test 1
148         // encode source to hex string to bytes with charset
149         final byte[] actualEncodedBytes = customCodec.encode(sourceBytes);
150         // encode source to hex string...
151         String expectedHexString = Hex.encodeHexString(sourceBytes);
152         // ... and get the bytes in the expected charset
153         final byte[] expectedHexStringBytes = expectedHexString.getBytes(name);
154         Assert.assertTrue(Arrays.equals(expectedHexStringBytes, actualEncodedBytes));
155         // test 2
156         String actualStringFromBytes = new String(actualEncodedBytes, name);
157         assertEquals(name + ", expectedHexString=" + expectedHexString + ", actualStringFromBytes=" + actualStringFromBytes,
158                 expectedHexString, actualStringFromBytes);
159         // second test:
160         final Hex utf8Codec = new Hex();
161         expectedHexString = "48656c6c6f20576f726c64";
162         final byte[] decodedUtf8Bytes = (byte[]) utf8Codec.decode(expectedHexString);
163         actualStringFromBytes = new String(decodedUtf8Bytes, utf8Codec.getCharset());
164         // sanity check:
165         assertEquals(name, sourceString, actualStringFromBytes);
166         // actual check:
167         final byte[] decodedCustomBytes = customCodec.decode(actualEncodedBytes);
168         actualStringFromBytes = new String(decodedCustomBytes, name);
169         assertEquals(name, sourceString, actualStringFromBytes);
170     }
171 
172     @Test(expected=UnsupportedCharsetException.class)
173     public void testCustomCharsetBadName() {
174         new Hex(BAD_ENCODING_NAME);
175     }
176 
177     @Test
178     public void testCustomCharsetToString() {
179         assertTrue(new Hex().toString().indexOf(Hex.DEFAULT_CHARSET_NAME) >= 0);
180     }
181 
182     @Test
183     public void testDecodeArrayOddCharacters() {
184         try {
185             new Hex().decode(new byte[]{65});
186             fail("An exception wasn't thrown when trying to decode an odd number of characters");
187         } catch (final DecoderException e) {
188             // Expected exception
189         }
190     }
191 
192     @Test
193     public void testDecodeBadCharacterPos0() {
194         try {
195             new Hex().decode("q0");
196             fail("An exception wasn't thrown when trying to decode an illegal character");
197         } catch (final DecoderException e) {
198             // Expected exception
199         }
200     }
201 
202     @Test
203     public void testDecodeBadCharacterPos1() {
204         try {
205             new Hex().decode("0q");
206             fail("An exception wasn't thrown when trying to decode an illegal character");
207         } catch (final DecoderException e) {
208             // Expected exception
209         }
210     }
211 
212     @Test
213     public void testDecodeClassCastException() {
214         try {
215             new Hex().decode(new int[]{65});
216             fail("An exception wasn't thrown when trying to decode.");
217         } catch (final DecoderException e) {
218             // Expected exception
219         }
220     }
221 
222     @Test
223     public void testDecodeHexOddCharacters1() {
224         checkDecodeHexOddCharacters(new char[]{'A'});
225     }
226 
227     @Test
228     public void testDecodeHexOddCharacters3() {
229         checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C'});
230     }
231 
232     @Test
233     public void testDecodeHexOddCharacters5() {
234         checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C', 'D', 'E'});
235     }
236 
237     @Test
238     public void testDecodeStringOddCharacters() {
239         try {
240             new Hex().decode("6");
241             fail("An exception wasn't thrown when trying to decode an odd number of characters");
242         } catch (final DecoderException e) {
243             // Expected exception
244         }
245     }
246 
247     @Test
248     public void testDencodeEmpty() throws DecoderException {
249         assertTrue(Arrays.equals(new byte[0], Hex.decodeHex(new char[0])));
250         assertTrue(Arrays.equals(new byte[0], new Hex().decode(new byte[0])));
251         assertTrue(Arrays.equals(new byte[0], (byte[]) new Hex().decode("")));
252     }
253 
254     @Test
255     public void testEncodeClassCastException() {
256         try {
257             new Hex().encode(new int[]{65});
258             fail("An exception wasn't thrown when trying to encode.");
259         } catch (final EncoderException e) {
260             // Expected exception
261         }
262     }
263 
264     @Test
265     public void testEncodeDecodeRandom() throws DecoderException, EncoderException {
266         final Random random = new Random();
267 
268         final Hex hex = new Hex();
269         for (int i = 5; i > 0; i--) {
270             final byte[] data = new byte[random.nextInt(10000) + 1];
271             random.nextBytes(data);
272 
273             // static API
274             final char[] encodedChars = Hex.encodeHex(data);
275             byte[] decodedBytes = Hex.decodeHex(encodedChars);
276             assertTrue(Arrays.equals(data, decodedBytes));
277 
278             // instance API with array parameter
279             final byte[] encodedStringBytes = hex.encode(data);
280             decodedBytes = hex.decode(encodedStringBytes);
281             assertTrue(Arrays.equals(data, decodedBytes));
282 
283             // instance API with char[] (Object) parameter
284             String dataString = new String(encodedChars);
285             char[] encodedStringChars = (char[]) hex.encode(dataString);
286             decodedBytes = (byte[]) hex.decode(encodedStringChars);
287             assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes));
288 
289             // instance API with String (Object) parameter
290             dataString = new String(encodedChars);
291             encodedStringChars = (char[]) hex.encode(dataString);
292             decodedBytes = (byte[]) hex.decode(new String(encodedStringChars));
293             assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes));
294         }
295     }
296 
297     @Test
298     public void testEncodeEmpty() throws EncoderException {
299         assertTrue(Arrays.equals(new char[0], Hex.encodeHex(new byte[0])));
300         assertTrue(Arrays.equals(new byte[0], new Hex().encode(new byte[0])));
301         assertTrue(Arrays.equals(new char[0], (char[]) new Hex().encode("")));
302     }
303 
304     @Test
305     public void testEncodeZeroes() {
306         final char[] c = Hex.encodeHex(new byte[36]);
307         assertEquals("000000000000000000000000000000000000000000000000000000000000000000000000", new String(c));
308     }
309 
310     @Test
311     public void testHelloWorldLowerCaseHex() {
312         final byte[] b = StringUtils.getBytesUtf8("Hello World");
313         final String expected = "48656c6c6f20576f726c64";
314         char[] actual;
315         actual = Hex.encodeHex(b);
316         assertEquals(expected, new String(actual));
317         actual = Hex.encodeHex(b, true);
318         assertEquals(expected, new String(actual));
319         actual = Hex.encodeHex(b, false);
320         assertFalse(expected.equals(new String(actual)));
321     }
322 
323     @Test
324     public void testHelloWorldUpperCaseHex() {
325         final byte[] b = StringUtils.getBytesUtf8("Hello World");
326         final String expected = "48656C6C6F20576F726C64";
327         char[] actual;
328         actual = Hex.encodeHex(b);
329         assertFalse(expected.equals(new String(actual)));
330         actual = Hex.encodeHex(b, true);
331         assertFalse(expected.equals(new String(actual)));
332         actual = Hex.encodeHex(b, false);
333         assertTrue(expected.equals(new String(actual)));
334     }
335 
336     @Test
337     public void testRequiredCharset() throws UnsupportedEncodingException, DecoderException {
338         testCustomCharset("UTF-8", "testRequiredCharset");
339         testCustomCharset("UTF-16", "testRequiredCharset");
340         testCustomCharset("UTF-16BE", "testRequiredCharset");
341         testCustomCharset("UTF-16LE", "testRequiredCharset");
342         testCustomCharset("US-ASCII", "testRequiredCharset");
343         testCustomCharset("ISO8859_1", "testRequiredCharset");
344     }
345 }