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.net; 019 020 import static org.junit.Assert.assertEquals; 021 import static org.junit.Assert.assertNull; 022 import static org.junit.Assert.fail; 023 024 import java.nio.charset.UnsupportedCharsetException; 025 026 import org.apache.commons.codec.CharEncoding; 027 import org.apache.commons.codec.Charsets; 028 import org.apache.commons.codec.DecoderException; 029 import org.apache.commons.codec.EncoderException; 030 import org.junit.Ignore; 031 import org.junit.Test; 032 033 /** 034 * Quoted-printable codec test cases 035 * 036 * @version $Id: QuotedPrintableCodecTest.html 889935 2013-12-11 05:05:13Z ggregory $ 037 */ 038 public class QuotedPrintableCodecTest { 039 040 static final int SWISS_GERMAN_STUFF_UNICODE [] = { 041 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4 042 }; 043 044 static final int RUSSIAN_STUFF_UNICODE [] = { 045 0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438, 046 0x432, 0x435, 0x442 047 }; 048 049 private String constructString(int [] unicodeChars) { 050 StringBuilder buffer = new StringBuilder(); 051 if (unicodeChars != null) { 052 for (int unicodeChar : unicodeChars) { 053 buffer.append((char)unicodeChar); 054 } 055 } 056 return buffer.toString(); 057 } 058 059 @Test 060 public void testUTF8RoundTrip() throws Exception { 061 062 String ru_msg = constructString(RUSSIAN_STUFF_UNICODE); 063 String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE); 064 065 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 066 067 assertEquals( 068 "=D0=92=D1=81=D0=B5=D0=BC_=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D1=82", 069 qpcodec.encode(ru_msg, CharEncoding.UTF_8) 070 ); 071 assertEquals("Gr=C3=BCezi_z=C3=A4m=C3=A4", qpcodec.encode(ch_msg, CharEncoding.UTF_8)); 072 073 assertEquals(ru_msg, qpcodec.decode(qpcodec.encode(ru_msg, CharEncoding.UTF_8), CharEncoding.UTF_8)); 074 assertEquals(ch_msg, qpcodec.decode(qpcodec.encode(ch_msg, CharEncoding.UTF_8), CharEncoding.UTF_8)); 075 } 076 077 @Test 078 public void testBasicEncodeDecode() throws Exception { 079 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 080 String plain = "= Hello there =\r\n"; 081 String encoded = qpcodec.encode(plain); 082 assertEquals("Basic quoted-printable encoding test", 083 "=3D Hello there =3D=0D=0A", encoded); 084 assertEquals("Basic quoted-printable decoding test", 085 plain, qpcodec.decode(encoded)); 086 } 087 088 @Test 089 public void testSafeCharEncodeDecode() throws Exception { 090 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 091 String plain = "abc123_-.*~!@#$%^&()+{}\"\\;:`,/[]"; 092 String encoded = qpcodec.encode(plain); 093 assertEquals("Safe chars quoted-printable encoding test", 094 plain, encoded); 095 assertEquals("Safe chars quoted-printable decoding test", 096 plain, qpcodec.decode(encoded)); 097 } 098 099 100 @Test 101 public void testUnsafeEncodeDecode() throws Exception { 102 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 103 String plain = "=\r\n"; 104 String encoded = qpcodec.encode(plain); 105 assertEquals("Unsafe chars quoted-printable encoding test", 106 "=3D=0D=0A", encoded); 107 assertEquals("Unsafe chars quoted-printable decoding test", 108 plain, qpcodec.decode(encoded)); 109 } 110 111 @Test 112 public void testEncodeDecodeNull() throws Exception { 113 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 114 assertNull("Null string quoted-printable encoding test", 115 qpcodec.encode((String)null)); 116 assertNull("Null string quoted-printable decoding test", 117 qpcodec.decode((String)null)); 118 } 119 120 121 @Test 122 public void testDecodeInvalid() throws Exception { 123 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 124 try { 125 qpcodec.decode("="); 126 fail("DecoderException should have been thrown"); 127 } catch (DecoderException e) { 128 // Expected. Move on 129 } 130 try { 131 qpcodec.decode("=A"); 132 fail("DecoderException should have been thrown"); 133 } catch (DecoderException e) { 134 // Expected. Move on 135 } 136 try { 137 qpcodec.decode("=WW"); 138 fail("DecoderException should have been thrown"); 139 } catch (DecoderException e) { 140 // Expected. Move on 141 } 142 } 143 144 @Test 145 public void testEncodeNull() throws Exception { 146 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 147 byte[] plain = null; 148 byte[] encoded = qpcodec.encode(plain); 149 assertEquals("Encoding a null string should return null", 150 null, encoded); 151 } 152 153 @Test 154 public void testEncodeUrlWithNullBitSet() throws Exception { 155 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 156 String plain = "1+1 = 2"; 157 String encoded = new String(QuotedPrintableCodec. 158 encodeQuotedPrintable(null, plain.getBytes(Charsets.UTF_8))); 159 assertEquals("Basic quoted-printable encoding test", 160 "1+1 =3D 2", encoded); 161 assertEquals("Basic quoted-printable decoding test", 162 plain, qpcodec.decode(encoded)); 163 164 } 165 166 @Test 167 public void testDecodeWithNullArray() throws Exception { 168 byte[] plain = null; 169 byte[] result = QuotedPrintableCodec.decodeQuotedPrintable( plain ); 170 assertEquals("Result should be null", null, result); 171 } 172 173 @Test 174 public void testEncodeStringWithNull() throws Exception { 175 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 176 String test = null; 177 String result = qpcodec.encode( test, "charset" ); 178 assertEquals("Result should be null", null, result); 179 } 180 181 @Test 182 public void testDecodeStringWithNull() throws Exception { 183 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 184 String test = null; 185 String result = qpcodec.decode( test, "charset" ); 186 assertEquals("Result should be null", null, result); 187 } 188 189 @Test 190 public void testEncodeObjects() throws Exception { 191 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 192 String plain = "1+1 = 2"; 193 String encoded = (String) qpcodec.encode((Object) plain); 194 assertEquals("Basic quoted-printable encoding test", 195 "1+1 =3D 2", encoded); 196 197 byte[] plainBA = plain.getBytes(Charsets.UTF_8); 198 byte[] encodedBA = (byte[]) qpcodec.encode((Object) plainBA); 199 encoded = new String(encodedBA); 200 assertEquals("Basic quoted-printable encoding test", 201 "1+1 =3D 2", encoded); 202 203 Object result = qpcodec.encode((Object) null); 204 assertEquals( "Encoding a null Object should return null", null, result); 205 206 try { 207 Object dObj = new Double(3.0); 208 qpcodec.encode( dObj ); 209 fail( "Trying to url encode a Double object should cause an exception."); 210 } catch (EncoderException ee) { 211 // Exception expected, test segment passes. 212 } 213 } 214 215 @Test(expected=UnsupportedCharsetException.class) 216 public void testInvalidEncoding() { 217 new QuotedPrintableCodec("NONSENSE"); 218 } 219 220 @Test 221 public void testDecodeObjects() throws Exception { 222 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(); 223 String plain = "1+1 =3D 2"; 224 String decoded = (String) qpcodec.decode((Object) plain); 225 assertEquals("Basic quoted-printable decoding test", 226 "1+1 = 2", decoded); 227 228 byte[] plainBA = plain.getBytes(Charsets.UTF_8); 229 byte[] decodedBA = (byte[]) qpcodec.decode((Object) plainBA); 230 decoded = new String(decodedBA); 231 assertEquals("Basic quoted-printable decoding test", 232 "1+1 = 2", decoded); 233 234 Object result = qpcodec.decode((Object) null); 235 assertEquals( "Decoding a null Object should return null", null, result); 236 237 try { 238 Object dObj = new Double(3.0); 239 qpcodec.decode( dObj ); 240 fail( "Trying to url encode a Double object should cause an exception."); 241 } catch (DecoderException ee) { 242 // Exception expected, test segment passes. 243 } 244 } 245 246 @Test 247 public void testDefaultEncoding() throws Exception { 248 String plain = "Hello there!"; 249 QuotedPrintableCodec qpcodec = new QuotedPrintableCodec("UnicodeBig"); 250 qpcodec.encode(plain); // To work around a weird quirk in Java 1.2.2 251 String encoded1 = qpcodec.encode(plain, "UnicodeBig"); 252 String encoded2 = qpcodec.encode(plain); 253 assertEquals(encoded1, encoded2); 254 } 255 256 @Test 257 @Ignore 258 /** 259 * The QuotedPrintableCodec documentation states that this is not supported. 260 * 261 * @throws Exception 262 * @see <a href="https://issues.apache.org/jira/browse/CODEC-121">CODEC-121</a> 263 */ 264 public void testSoftLineBreakDecode() throws Exception { 265 String qpdata = "If you believe that truth=3Dbeauty, then surely=20=\r\nmathematics is the most beautiful branch of philosophy."; 266 String expected = "If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy."; 267 assertEquals(expected, new QuotedPrintableCodec().decode(qpdata)); 268 } 269 270 @Test 271 @Ignore 272 /** 273 * The QuotedPrintableCodec documentation states that this is not supported. 274 * 275 * @throws Exception 276 * @see <a href="https://issues.apache.org/jira/browse/CODEC-121">CODEC-121</a> 277 */ 278 public void testSoftLineBreakEncode() throws Exception { 279 String qpdata = "If you believe that truth=3Dbeauty, then surely=20=\r\nmathematics is the most beautiful branch of philosophy."; 280 String expected = "If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy."; 281 assertEquals(qpdata, new QuotedPrintableCodec().encode(expected)); 282 } 283 }