001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.codec.binary; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.UnsupportedEncodingException; 026import java.nio.charset.Charset; 027import java.nio.charset.UnsupportedCharsetException; 028import java.util.Arrays; 029import java.util.Random; 030 031import org.junit.Assert; 032 033import org.apache.commons.codec.DecoderException; 034import org.apache.commons.codec.EncoderException; 035import org.junit.Test; 036 037/** 038 * Tests {@link org.apache.commons.codec.binary.Hex}. 039 * 040 * @version $Id: HexTest.html 891688 2013-12-24 20:49:46Z ggregory $ 041 */ 042public class HexTest { 043 044 private static final String BAD_ENCODING_NAME = "UNKNOWN"; 045 046 private final static boolean LOG = false; 047 048 private boolean charsetSanityCheck(final String name) { 049 final String source = "the quick brown dog jumped over the lazy fox"; 050 try { 051 final byte[] bytes = source.getBytes(name); 052 final String str = new String(bytes, name); 053 final boolean equals = source.equals(str); 054 if (equals == false) { 055 // Here with: 056 // 057 // Java Sun 1.4.2_19 x86 32-bits on Windows XP 058 // JIS_X0212-1990 059 // x-JIS0208 060 // 061 // Java Sun 1.5.0_17 x86 32-bits on Windows XP 062 // JIS_X0212-1990 063 // x-IBM834 064 // x-JIS0208 065 // x-MacDingbat 066 // x-MacSymbol 067 // 068 // Java Sun 1.6.0_14 x86 32-bits 069 // JIS_X0212-1990 070 // x-IBM834 071 // x-JIS0208 072 // x-MacDingbat 073 // x-MacSymbol 074 // 075 log("FAILED charsetSanityCheck=Interesting Java charset oddity: Roundtrip failed for " + name); 076 } 077 return equals; 078 } catch (final UnsupportedEncodingException e) { 079 // Should NEVER happen since we are getting the name from the Charset class. 080 if (LOG) { 081 log("FAILED charsetSanityCheck=" + name + ", e=" + e); 082 log(e); 083 } 084 return false; 085 } catch (final UnsupportedOperationException e) { 086 // Caught here with: 087 // x-JISAutoDetect on Windows XP and Java Sun 1.4.2_19 x86 32-bits 088 // x-JISAutoDetect on Windows XP and Java Sun 1.5.0_17 x86 32-bits 089 // x-JISAutoDetect on Windows XP and Java Sun 1.6.0_14 x86 32-bits 090 if (LOG) { 091 log("FAILED charsetSanityCheck=" + name + ", e=" + e); 092 log(e); 093 } 094 return false; 095 } 096 } 097 098 /** 099 * @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 * @throws UnsupportedEncodingException 135 * @throws DecoderException 136 */ 137 private void testCustomCharset(final String name, final String parent) throws UnsupportedEncodingException, DecoderException { 138 if (charsetSanityCheck(name) == false) { 139 return; 140 } 141 log(parent + "=" + name); 142 final Hex customCodec = new Hex(name); 143 // source data 144 final String sourceString = "Hello World"; 145 final byte[] sourceBytes = sourceString.getBytes(name); 146 // test 1 147 // encode source to hex string to bytes with charset 148 final byte[] actualEncodedBytes = customCodec.encode(sourceBytes); 149 // encode source to hex string... 150 String expectedHexString = Hex.encodeHexString(sourceBytes); 151 // ... and get the bytes in the expected charset 152 final byte[] expectedHexStringBytes = expectedHexString.getBytes(name); 153 Assert.assertTrue(Arrays.equals(expectedHexStringBytes, actualEncodedBytes)); 154 // test 2 155 String actualStringFromBytes = new String(actualEncodedBytes, name); 156 assertEquals(name + ", expectedHexString=" + expectedHexString + ", actualStringFromBytes=" + actualStringFromBytes, 157 expectedHexString, actualStringFromBytes); 158 // second test: 159 final Hex utf8Codec = new Hex(); 160 expectedHexString = "48656c6c6f20576f726c64"; 161 final byte[] decodedUtf8Bytes = (byte[]) utf8Codec.decode(expectedHexString); 162 actualStringFromBytes = new String(decodedUtf8Bytes, utf8Codec.getCharset()); 163 // sanity check: 164 assertEquals(name, sourceString, actualStringFromBytes); 165 // actual check: 166 final byte[] decodedCustomBytes = customCodec.decode(actualEncodedBytes); 167 actualStringFromBytes = new String(decodedCustomBytes, name); 168 assertEquals(name, sourceString, actualStringFromBytes); 169 } 170 171 @Test(expected=UnsupportedCharsetException.class) 172 public void testCustomCharsetBadName() { 173 new Hex(BAD_ENCODING_NAME); 174 } 175 176 @Test 177 public void testCustomCharsetToString() { 178 assertTrue(new Hex().toString().indexOf(Hex.DEFAULT_CHARSET_NAME) >= 0); 179 } 180 181 @Test 182 public void testDecodeArrayOddCharacters() { 183 try { 184 new Hex().decode(new byte[]{65}); 185 fail("An exception wasn't thrown when trying to decode an odd number of characters"); 186 } catch (final DecoderException e) { 187 // Expected exception 188 } 189 } 190 191 @Test 192 public void testDecodeBadCharacterPos0() { 193 try { 194 new Hex().decode("q0"); 195 fail("An exception wasn't thrown when trying to decode an illegal character"); 196 } catch (final DecoderException e) { 197 // Expected exception 198 } 199 } 200 201 @Test 202 public void testDecodeBadCharacterPos1() { 203 try { 204 new Hex().decode("0q"); 205 fail("An exception wasn't thrown when trying to decode an illegal character"); 206 } catch (final DecoderException e) { 207 // Expected exception 208 } 209 } 210 211 @Test 212 public void testDecodeClassCastException() { 213 try { 214 new Hex().decode(new int[]{65}); 215 fail("An exception wasn't thrown when trying to decode."); 216 } catch (final DecoderException e) { 217 // Expected exception 218 } 219 } 220 221 @Test 222 public void testDecodeHexOddCharacters1() { 223 checkDecodeHexOddCharacters(new char[]{'A'}); 224 } 225 226 @Test 227 public void testDecodeHexOddCharacters3() { 228 checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C'}); 229 } 230 231 @Test 232 public void testDecodeHexOddCharacters5() { 233 checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C', 'D', 'E'}); 234 } 235 236 @Test 237 public void testDecodeStringOddCharacters() { 238 try { 239 new Hex().decode("6"); 240 fail("An exception wasn't thrown when trying to decode an odd number of characters"); 241 } catch (final DecoderException e) { 242 // Expected exception 243 } 244 } 245 246 @Test 247 public void testDencodeEmpty() throws DecoderException { 248 assertTrue(Arrays.equals(new byte[0], Hex.decodeHex(new char[0]))); 249 assertTrue(Arrays.equals(new byte[0], new Hex().decode(new byte[0]))); 250 assertTrue(Arrays.equals(new byte[0], (byte[]) new Hex().decode(""))); 251 } 252 253 @Test 254 public void testEncodeClassCastException() { 255 try { 256 new Hex().encode(new int[]{65}); 257 fail("An exception wasn't thrown when trying to encode."); 258 } catch (final EncoderException e) { 259 // Expected exception 260 } 261 } 262 263 @Test 264 public void testEncodeDecodeRandom() throws DecoderException, EncoderException { 265 final Random random = new Random(); 266 267 final Hex hex = new Hex(); 268 for (int i = 5; i > 0; i--) { 269 final byte[] data = new byte[random.nextInt(10000) + 1]; 270 random.nextBytes(data); 271 272 // static API 273 final char[] encodedChars = Hex.encodeHex(data); 274 byte[] decodedBytes = Hex.decodeHex(encodedChars); 275 assertTrue(Arrays.equals(data, decodedBytes)); 276 277 // instance API with array parameter 278 final byte[] encodedStringBytes = hex.encode(data); 279 decodedBytes = hex.decode(encodedStringBytes); 280 assertTrue(Arrays.equals(data, decodedBytes)); 281 282 // instance API with char[] (Object) parameter 283 String dataString = new String(encodedChars); 284 char[] encodedStringChars = (char[]) hex.encode(dataString); 285 decodedBytes = (byte[]) hex.decode(encodedStringChars); 286 assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes)); 287 288 // instance API with String (Object) parameter 289 dataString = new String(encodedChars); 290 encodedStringChars = (char[]) hex.encode(dataString); 291 decodedBytes = (byte[]) hex.decode(new String(encodedStringChars)); 292 assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes)); 293 } 294 } 295 296 @Test 297 public void testEncodeEmpty() throws EncoderException { 298 assertTrue(Arrays.equals(new char[0], Hex.encodeHex(new byte[0]))); 299 assertTrue(Arrays.equals(new byte[0], new Hex().encode(new byte[0]))); 300 assertTrue(Arrays.equals(new char[0], (char[]) new Hex().encode(""))); 301 } 302 303 @Test 304 public void testEncodeZeroes() { 305 final char[] c = Hex.encodeHex(new byte[36]); 306 assertEquals("000000000000000000000000000000000000000000000000000000000000000000000000", new String(c)); 307 } 308 309 @Test 310 public void testHelloWorldLowerCaseHex() { 311 final byte[] b = StringUtils.getBytesUtf8("Hello World"); 312 final String expected = "48656c6c6f20576f726c64"; 313 char[] actual; 314 actual = Hex.encodeHex(b); 315 assertEquals(expected, new String(actual)); 316 actual = Hex.encodeHex(b, true); 317 assertEquals(expected, new String(actual)); 318 actual = Hex.encodeHex(b, false); 319 assertFalse(expected.equals(new String(actual))); 320 } 321 322 @Test 323 public void testHelloWorldUpperCaseHex() { 324 final byte[] b = StringUtils.getBytesUtf8("Hello World"); 325 final String expected = "48656C6C6F20576F726C64"; 326 char[] actual; 327 actual = Hex.encodeHex(b); 328 assertFalse(expected.equals(new String(actual))); 329 actual = Hex.encodeHex(b, true); 330 assertFalse(expected.equals(new String(actual))); 331 actual = Hex.encodeHex(b, false); 332 assertTrue(expected.equals(new String(actual))); 333 } 334 335 @Test 336 public void testRequiredCharset() throws UnsupportedEncodingException, DecoderException { 337 testCustomCharset("UTF-8", "testRequiredCharset"); 338 testCustomCharset("UTF-16", "testRequiredCharset"); 339 testCustomCharset("UTF-16BE", "testRequiredCharset"); 340 testCustomCharset("UTF-16LE", "testRequiredCharset"); 341 testCustomCharset("US-ASCII", "testRequiredCharset"); 342 testCustomCharset("ISO8859_1", "testRequiredCharset"); 343 } 344}