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 018 package org.apache.commons.codec.binary; 019 020 import static org.junit.Assert.assertEquals; 021 import static org.junit.Assert.assertFalse; 022 import static org.junit.Assert.assertTrue; 023 import static org.junit.Assert.fail; 024 025 import java.io.UnsupportedEncodingException; 026 import java.nio.charset.Charset; 027 import java.nio.charset.UnsupportedCharsetException; 028 import java.util.Arrays; 029 import java.util.Random; 030 031 import junit.framework.Assert; 032 033 import org.apache.commons.codec.DecoderException; 034 import org.apache.commons.codec.EncoderException; 035 import org.junit.Test; 036 037 /** 038 * Tests {@link org.apache.commons.codec.binary.Hex}. 039 * 040 * @version $Id: HexTest.html 889935 2013-12-11 05:05:13Z ggregory $ 041 */ 042 public 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(String name) { 049 final String source = "the quick brown dog jumped over the lazy fox"; 050 try { 051 byte[] bytes = source.getBytes(name); 052 String str = new String(bytes, name); 053 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 (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 (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(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 (DecoderException e) { 106 // Expected exception 107 } 108 } 109 110 private void log(String s) { 111 if (LOG) { 112 System.out.println(s); 113 System.out.flush(); 114 } 115 } 116 117 private void log(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 (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(String name, String parent) throws UnsupportedEncodingException, DecoderException { 139 if (charsetSanityCheck(name) == false) { 140 return; 141 } 142 log(parent + "=" + name); 143 Hex customCodec = new Hex(name); 144 // source data 145 String sourceString = "Hello World"; 146 byte[] sourceBytes = sourceString.getBytes(name); 147 // test 1 148 // encode source to hex string to bytes with charset 149 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 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 Hex utf8Codec = new Hex(); 161 expectedHexString = "48656c6c6f20576f726c64"; 162 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 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 (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 (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 (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 (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 (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 (EncoderException e) { 260 // Expected exception 261 } 262 } 263 264 @Test 265 public void testEncodeDecodeRandom() throws DecoderException, EncoderException { 266 Random random = new Random(); 267 268 Hex hex = new Hex(); 269 for (int i = 5; i > 0; i--) { 270 byte[] data = new byte[random.nextInt(10000) + 1]; 271 random.nextBytes(data); 272 273 // static API 274 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 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 char[] c = Hex.encodeHex(new byte[36]); 307 assertEquals("000000000000000000000000000000000000000000000000000000000000000000000000", new String(c)); 308 } 309 310 @Test 311 public void testHelloWorldLowerCaseHex() { 312 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 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 }