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.net;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.fail;
023
024import java.io.UnsupportedEncodingException;
025
026import org.apache.commons.codec.CharEncoding;
027import org.apache.commons.codec.Charsets;
028import org.apache.commons.codec.DecoderException;
029import org.apache.commons.codec.EncoderException;
030import org.junit.Test;
031
032/**
033 * URL codec test cases
034 *
035 * @version $Id: URLCodecTest.html 891688 2013-12-24 20:49:46Z ggregory $
036 */
037public class URLCodecTest {
038
039    static final int SWISS_GERMAN_STUFF_UNICODE [] = {
040        0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
041    };
042
043    static final int RUSSIAN_STUFF_UNICODE [] = {
044        0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
045        0x432, 0x435, 0x442
046    };
047
048    private void validateState(final URLCodec urlCodec) {
049        // no tests for now.
050    }
051
052    private String constructString(final int [] unicodeChars) {
053        final StringBuilder buffer = new StringBuilder();
054        if (unicodeChars != null) {
055            for (final int unicodeChar : unicodeChars) {
056                buffer.append((char)unicodeChar);
057            }
058        }
059        return buffer.toString();
060    }
061
062    @Test
063    public void testUTF8RoundTrip() throws Exception {
064
065        final String ru_msg = constructString(RUSSIAN_STUFF_UNICODE);
066        final String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE);
067
068        final URLCodec urlCodec = new URLCodec();
069        this.validateState(urlCodec);
070
071        assertEquals(
072            "%D0%92%D1%81%D0%B5%D0%BC_%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82",
073            urlCodec.encode(ru_msg, CharEncoding.UTF_8)
074        );
075        assertEquals("Gr%C3%BCezi_z%C3%A4m%C3%A4", urlCodec.encode(ch_msg, CharEncoding.UTF_8));
076
077        assertEquals(ru_msg, urlCodec.decode(urlCodec.encode(ru_msg, CharEncoding.UTF_8), CharEncoding.UTF_8));
078        assertEquals(ch_msg, urlCodec.decode(urlCodec.encode(ch_msg, CharEncoding.UTF_8), CharEncoding.UTF_8));
079        this.validateState(urlCodec);
080    }
081
082    @Test
083    public void testBasicEncodeDecode() throws Exception {
084        final URLCodec urlCodec = new URLCodec();
085        final String plain = "Hello there!";
086        final String encoded = urlCodec.encode(plain);
087        assertEquals("Basic URL encoding test",
088            "Hello+there%21", encoded);
089        assertEquals("Basic URL decoding test",
090            plain, urlCodec.decode(encoded));
091        this.validateState(urlCodec);
092    }
093
094
095    @Test
096    public void testSafeCharEncodeDecode() throws Exception {
097        final URLCodec urlCodec = new URLCodec();
098        final String plain = "abc123_-.*";
099        final String encoded = urlCodec.encode(plain);
100        assertEquals("Safe chars URL encoding test",
101            plain, encoded);
102        assertEquals("Safe chars URL decoding test",
103            plain, urlCodec.decode(encoded));
104        this.validateState(urlCodec);
105    }
106
107
108    @Test
109    public void testUnsafeEncodeDecode() throws Exception {
110        final URLCodec urlCodec = new URLCodec();
111        final String plain = "~!@#$%^&()+{}\"\\;:`,/[]";
112        final String encoded = urlCodec.encode(plain);
113        assertEquals("Unsafe chars URL encoding test",
114            "%7E%21%40%23%24%25%5E%26%28%29%2B%7B%7D%22%5C%3B%3A%60%2C%2F%5B%5D", encoded);
115        assertEquals("Unsafe chars URL decoding test",
116            plain, urlCodec.decode(encoded));
117        this.validateState(urlCodec);
118    }
119
120
121    @Test
122    public void testEncodeDecodeNull() throws Exception {
123        final URLCodec urlCodec = new URLCodec();
124        assertNull("Null string URL encoding test",
125            urlCodec.encode((String)null));
126        assertNull("Null string URL decoding test",
127            urlCodec.decode((String)null));
128        this.validateState(urlCodec);
129    }
130
131
132    @Test
133    public void testDecodeInvalid() throws Exception {
134        final URLCodec urlCodec = new URLCodec();
135        try {
136            urlCodec.decode("%");
137            fail("DecoderException should have been thrown");
138        } catch (final DecoderException e) {
139            // Expected. Move on
140        }
141        try {
142            urlCodec.decode("%A");
143            fail("DecoderException should have been thrown");
144        } catch (final DecoderException e) {
145            // Expected. Move on
146        }
147        try {
148            // Bad 1st char after %
149            urlCodec.decode("%WW");
150            fail("DecoderException should have been thrown");
151        } catch (final DecoderException e) {
152            // Expected. Move on
153        }
154        try {
155            // Bad 2nd char after %
156            urlCodec.decode("%0W");
157            fail("DecoderException should have been thrown");
158        } catch (final DecoderException e) {
159            // Expected. Move on
160        }
161        this.validateState(urlCodec);
162    }
163
164    @Test
165    public void testDecodeInvalidContent() throws UnsupportedEncodingException, DecoderException {
166        final String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE);
167        final URLCodec urlCodec = new URLCodec();
168        final byte[] input = ch_msg.getBytes("ISO-8859-1");
169        final byte[] output = urlCodec.decode(input);
170        assertEquals(input.length, output.length);
171        for (int i = 0; i < input.length; i++) {
172            assertEquals(input[i], output[i]);
173        }
174        this.validateState(urlCodec);
175    }
176
177    @Test
178    public void testEncodeNull() throws Exception {
179        final URLCodec urlCodec = new URLCodec();
180        final byte[] plain = null;
181        final byte[] encoded = urlCodec.encode(plain);
182        assertEquals("Encoding a null string should return null",
183            null, encoded);
184        this.validateState(urlCodec);
185    }
186
187    @Test
188    public void testEncodeUrlWithNullBitSet() throws Exception {
189        final URLCodec urlCodec = new URLCodec();
190        final String plain = "Hello there!";
191        final String encoded = new String( URLCodec.encodeUrl(null, plain.getBytes(Charsets.UTF_8)));
192        assertEquals("Basic URL encoding test",
193            "Hello+there%21", encoded);
194        assertEquals("Basic URL decoding test",
195            plain, urlCodec.decode(encoded));
196        this.validateState(urlCodec);
197    }
198
199    @Test
200    public void testDecodeWithNullArray() throws Exception {
201        final byte[] plain = null;
202        final byte[] result = URLCodec.decodeUrl( plain );
203        assertEquals("Result should be null", null, result);
204    }
205
206    @Test
207    public void testEncodeStringWithNull() throws Exception {
208        final URLCodec urlCodec = new URLCodec();
209        final String test = null;
210        final String result = urlCodec.encode( test, "charset" );
211        assertEquals("Result should be null", null, result);
212    }
213
214    @Test
215    public void testDecodeStringWithNull() throws Exception {
216        final URLCodec urlCodec = new URLCodec();
217        final String test = null;
218        final String result = urlCodec.decode( test, "charset" );
219        assertEquals("Result should be null", null, result);
220    }
221
222    @Test
223    public void testEncodeObjects() throws Exception {
224        final URLCodec urlCodec = new URLCodec();
225        final String plain = "Hello there!";
226        String encoded = (String) urlCodec.encode((Object) plain);
227        assertEquals("Basic URL encoding test",
228            "Hello+there%21", encoded);
229
230        final byte[] plainBA = plain.getBytes(Charsets.UTF_8);
231        final byte[] encodedBA = (byte[]) urlCodec.encode((Object) plainBA);
232        encoded = new String(encodedBA);
233        assertEquals("Basic URL encoding test",
234            "Hello+there%21", encoded);
235
236        final Object result = urlCodec.encode((Object) null);
237        assertEquals( "Encoding a null Object should return null", null, result);
238
239        try {
240            final Object dObj = new Double(3.0);
241            urlCodec.encode( dObj );
242            fail( "Trying to url encode a Double object should cause an exception.");
243        } catch (final EncoderException ee) {
244            // Exception expected, test segment passes.
245        }
246        this.validateState(urlCodec);
247    }
248
249    @Test
250    public void testInvalidEncoding() {
251        final URLCodec urlCodec = new URLCodec("NONSENSE");
252        final String plain = "Hello there!";
253        try {
254            urlCodec.encode(plain);
255            fail("We set the encoding to a bogus NONSENSE vlaue, this shouldn't have worked.");
256        } catch (final EncoderException ee) {
257            // Exception expected, test segment passes.
258        }
259        try {
260            urlCodec.decode(plain);
261            fail("We set the encoding to a bogus NONSENSE vlaue, this shouldn't have worked.");
262        } catch (final DecoderException ee) {
263            // Exception expected, test segment passes.
264        }
265        this.validateState(urlCodec);
266    }
267
268    @Test
269    public void testDecodeObjects() throws Exception {
270        final URLCodec urlCodec = new URLCodec();
271        final String plain = "Hello+there%21";
272        String decoded = (String) urlCodec.decode((Object) plain);
273        assertEquals("Basic URL decoding test",
274            "Hello there!", decoded);
275
276        final byte[] plainBA = plain.getBytes(Charsets.UTF_8);
277        final byte[] decodedBA = (byte[]) urlCodec.decode((Object) plainBA);
278        decoded = new String(decodedBA);
279        assertEquals("Basic URL decoding test",
280            "Hello there!", decoded);
281
282        final Object result = urlCodec.decode((Object) null);
283        assertEquals( "Decoding a null Object should return null", null, result);
284
285        try {
286            final Object dObj = new Double(3.0);
287            urlCodec.decode( dObj );
288            fail( "Trying to url encode a Double object should cause an exception.");
289        } catch (final DecoderException ee) {
290            // Exception expected, test segment passes.
291        }
292        this.validateState(urlCodec);
293    }
294
295    @Test
296    public void testDefaultEncoding() throws Exception {
297        final String plain = "Hello there!";
298        final URLCodec urlCodec = new URLCodec("UnicodeBig");
299        urlCodec.encode(plain); // To work around a weird quirk in Java 1.2.2
300        final String encoded1 = urlCodec.encode(plain, "UnicodeBig");
301        final String encoded2 = urlCodec.encode(plain);
302        assertEquals(encoded1, encoded2);
303        this.validateState(urlCodec);
304    }
305}