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    }