/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.codec.binary; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Iterator; import java.util.Random; import java.util.Set; import java.util.SortedMap; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; /** * Tests {@link org.apache.commons.codec.binary.Hex}. * * @author Apache Software Foundation * @version $Id: HexTest.java 928757 2010-03-29 12:39:21Z sebb $ */ public class HexTest extends TestCase { private static final String BAD_ENCODING_NAME = "UNKNOWN"; private final static boolean LOG = false; public HexTest(String name) { super(name); } private boolean charsetSanityCheck(String name) { final String source = "the quick brown dog jumped over the lazy fox"; try { byte[] bytes = source.getBytes(name); String str = new String(bytes, name); boolean equals = source.equals(str); if (equals == false) { // Here with: // // Java Sun 1.4.2_19 x86 32-bits on Windows XP // JIS_X0212-1990 // x-JIS0208 // // Java Sun 1.5.0_17 x86 32-bits on Windows XP // JIS_X0212-1990 // x-IBM834 // x-JIS0208 // x-MacDingbat // x-MacSymbol // // Java Sun 1.6.0_14 x86 32-bits // JIS_X0212-1990 // x-IBM834 // x-JIS0208 // x-MacDingbat // x-MacSymbol // log("FAILED charsetSanityCheck=Interesting Java charset oddity: Roundtrip failed for " + name); } return equals; } catch (UnsupportedEncodingException e) { // Should NEVER happen since we are getting the name from the Charset class. if (LOG) { log("FAILED charsetSanityCheck=" + name + ", e=" + e); log(e); } return false; } catch (UnsupportedOperationException e) { // Caught here with: // x-JISAutoDetect on Windows XP and Java Sun 1.4.2_19 x86 32-bits // x-JISAutoDetect on Windows XP and Java Sun 1.5.0_17 x86 32-bits // x-JISAutoDetect on Windows XP and Java Sun 1.6.0_14 x86 32-bits if (LOG) { log("FAILED charsetSanityCheck=" + name + ", e=" + e); log(e); } return false; } } /** * @param data */ private void checkDecodeHexOddCharacters(char[] data) { try { Hex.decodeHex(data); fail("An exception wasn't thrown when trying to decode an odd number of characters"); } catch (DecoderException e) { // Expected exception } } private void log(String s) { if (LOG) { System.out.println(s); System.out.flush(); } } private void log(Throwable t) { if (LOG) { t.printStackTrace(System.out); System.out.flush(); } } public void testCustomCharset() throws UnsupportedEncodingException, DecoderException { SortedMap map = Charset.availableCharsets(); Set keys = map.keySet(); Iterator iterator = keys.iterator(); log("testCustomCharset: Checking " + keys.size() + " charsets..."); while (iterator.hasNext()) { String name = (String) iterator.next(); testCustomCharset(name, "testCustomCharset"); } } /** * @param name * @param parent * TODO * @throws UnsupportedEncodingException * @throws DecoderException */ private void testCustomCharset(String name, String parent) throws UnsupportedEncodingException, DecoderException { if (charsetSanityCheck(name) == false) { return; } log(parent + "=" + name); Hex customCodec = new Hex(name); // source data String sourceString = "Hello World"; byte[] sourceBytes = sourceString.getBytes(name); // test 1 // encode source to hex string to bytes with charset byte[] actualEncodedBytes = customCodec.encode(sourceBytes); // encode source to hex string... String expectedHexString = Hex.encodeHexString(sourceBytes); // ... and get the bytes in the expected charset byte[] expectedHexStringBytes = expectedHexString.getBytes(name); Assert.assertTrue(Arrays.equals(expectedHexStringBytes, actualEncodedBytes)); // test 2 String actualStringFromBytes = new String(actualEncodedBytes, name); assertEquals(name + ", expectedHexString=" + expectedHexString + ", actualStringFromBytes=" + actualStringFromBytes, expectedHexString, actualStringFromBytes); // second test: Hex utf8Codec = new Hex(); expectedHexString = "48656c6c6f20576f726c64"; byte[] decodedUtf8Bytes = (byte[]) utf8Codec.decode(expectedHexString); actualStringFromBytes = new String(decodedUtf8Bytes, utf8Codec.getCharsetName()); // sanity check: assertEquals(name, sourceString, actualStringFromBytes); // actual check: byte[] decodedCustomBytes = customCodec.decode(actualEncodedBytes); actualStringFromBytes = new String(decodedCustomBytes, name); assertEquals(name, sourceString, actualStringFromBytes); } public void testCustomCharsetBadNameEncodeByteArray() throws UnsupportedEncodingException { try { new Hex(BAD_ENCODING_NAME).encode("Hello World".getBytes("UTF-8")); fail("Expected " + IllegalStateException.class.getName()); } catch (IllegalStateException e) { // Expected } } public void testCustomCharsetBadNameEncodeObject() { try { new Hex(BAD_ENCODING_NAME).encode("Hello World"); fail("Expected " + EncoderException.class.getName()); } catch (EncoderException e) { // Expected } } public void testCustomCharsetBadNameDecodeObject() throws UnsupportedEncodingException { try { new Hex(BAD_ENCODING_NAME).decode("Hello World".getBytes("UTF-8")); fail("Expected " + DecoderException.class.getName()); } catch (DecoderException e) { // Expected } } public void testCustomCharsetToString() { assertTrue(new Hex().toString().indexOf(Hex.DEFAULT_CHARSET_NAME) >= 0); } public void testDecodeArrayOddCharacters() { try { new Hex().decode(new byte[]{65}); fail("An exception wasn't thrown when trying to decode an odd number of characters"); } catch (DecoderException e) { // Expected exception } } public void testDecodeBadCharacterPos0() { try { new Hex().decode("q0"); fail("An exception wasn't thrown when trying to decode an illegal character"); } catch (DecoderException e) { // Expected exception } } public void testDecodeBadCharacterPos1() { try { new Hex().decode("0q"); fail("An exception wasn't thrown when trying to decode an illegal character"); } catch (DecoderException e) { // Expected exception } } public void testDecodeClassCastException() { try { new Hex().decode(new int[]{65}); fail("An exception wasn't thrown when trying to decode."); } catch (DecoderException e) { // Expected exception } } public void testDecodeHexOddCharacters1() { checkDecodeHexOddCharacters(new char[]{'A'}); } public void testDecodeHexOddCharacters3() { checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C'}); } public void testDecodeHexOddCharacters5() { checkDecodeHexOddCharacters(new char[]{'A', 'B', 'C', 'D', 'E'}); } public void testDecodeStringOddCharacters() { try { new Hex().decode("6"); fail("An exception wasn't thrown when trying to decode an odd number of characters"); } catch (DecoderException e) { // Expected exception } } public void testDencodeEmpty() throws DecoderException { assertTrue(Arrays.equals(new byte[0], Hex.decodeHex(new char[0]))); assertTrue(Arrays.equals(new byte[0], new Hex().decode(new byte[0]))); assertTrue(Arrays.equals(new byte[0], (byte[]) new Hex().decode(""))); } public void testEncodeClassCastException() { try { new Hex().encode(new int[]{65}); fail("An exception wasn't thrown when trying to encode."); } catch (EncoderException e) { // Expected exception } } public void testEncodeDecodeRandom() throws DecoderException, EncoderException { Random random = new Random(); Hex hex = new Hex(); for (int i = 5; i > 0; i--) { byte[] data = new byte[random.nextInt(10000) + 1]; random.nextBytes(data); // static API char[] encodedChars = Hex.encodeHex(data); byte[] decodedBytes = Hex.decodeHex(encodedChars); assertTrue(Arrays.equals(data, decodedBytes)); // instance API with array parameter byte[] encodedStringBytes = hex.encode(data); decodedBytes = hex.decode(encodedStringBytes); assertTrue(Arrays.equals(data, decodedBytes)); // instance API with char[] (Object) parameter String dataString = new String(encodedChars); char[] encodedStringChars = (char[]) hex.encode(dataString); decodedBytes = (byte[]) hex.decode(encodedStringChars); assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes)); // instance API with String (Object) parameter dataString = new String(encodedChars); encodedStringChars = (char[]) hex.encode(dataString); decodedBytes = (byte[]) hex.decode(new String(encodedStringChars)); assertTrue(Arrays.equals(StringUtils.getBytesUtf8(dataString), decodedBytes)); } } public void testEncodeEmpty() throws EncoderException { assertTrue(Arrays.equals(new char[0], Hex.encodeHex(new byte[0]))); assertTrue(Arrays.equals(new byte[0], new Hex().encode(new byte[0]))); assertTrue(Arrays.equals(new char[0], (char[]) new Hex().encode(""))); } public void testEncodeZeroes() { char[] c = Hex.encodeHex(new byte[36]); assertEquals("000000000000000000000000000000000000000000000000000000000000000000000000", new String(c)); } public void testHelloWorldLowerCaseHex() { byte[] b = StringUtils.getBytesUtf8("Hello World"); final String expected = "48656c6c6f20576f726c64"; char[] actual; actual = Hex.encodeHex(b); assertTrue(expected.equals(new String(actual))); actual = Hex.encodeHex(b, true); assertTrue(expected.equals(new String(actual))); actual = Hex.encodeHex(b, false); assertFalse(expected.equals(new String(actual))); } public void testHelloWorldUpperCaseHex() { byte[] b = StringUtils.getBytesUtf8("Hello World"); final String expected = "48656C6C6F20576F726C64"; char[] actual; actual = Hex.encodeHex(b); assertFalse(expected.equals(new String(actual))); actual = Hex.encodeHex(b, true); assertFalse(expected.equals(new String(actual))); actual = Hex.encodeHex(b, false); assertTrue(expected.equals(new String(actual))); } public void testRequiredCharset() throws UnsupportedEncodingException, DecoderException { testCustomCharset("UTF-8", "testRequiredCharset"); testCustomCharset("UTF-16", "testRequiredCharset"); testCustomCharset("UTF-16BE", "testRequiredCharset"); testCustomCharset("UTF-16LE", "testRequiredCharset"); testCustomCharset("US-ASCII", "testRequiredCharset"); testCustomCharset("ISO8859_1", "testRequiredCharset"); } }