001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.text;
017
018import static org.hamcrest.core.Is.is;
019import static org.hamcrest.core.IsNull.notNullValue;
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertThat;
022import org.junit.Before;
023import org.junit.Test;
024import org.modeshape.common.FixFor;
025
026/**
027 * @author Randall Hauch
028 */
029public class UrlEncoderTest {
030
031    private UrlEncoder encoder = new UrlEncoder();
032
033    @Before
034    public void beforeEach() {
035    }
036
037    protected void checkEncoding( String input, String expected ) {
038        String output = this.encoder.encode(input);
039        assertThat(output, is(notNullValue()));
040        assertEquals(expected, output);
041        assertThat(output.length(), is(expected.length()));
042        assertThat(output, is(expected));
043
044        checkDecoding(output, input);
045    }
046
047    protected void checkForNoEncoding( String input ) {
048        String output = this.encoder.encode(input);
049        assertThat(output, is(notNullValue()));
050        assertEquals(input, output);
051        assertThat(output.length(), is(input.length()));
052        assertThat(output, is(input));
053
054        checkDecoding(output, input);
055    }
056
057    protected void checkDecoding( String input, String output ) {
058        String decoded = this.encoder.decode(input);
059        assertEquals(output, decoded);
060        assertThat(decoded.length(), is(output.length()));
061        assertThat(decoded, is(output));
062    }
063
064    @Test
065    public void shouldNotEncodeForwardSlashByDefault() {
066        checkEncoding("/", "%2f");
067        this.encoder.setSlashEncoded(false);
068        checkForNoEncoding("/");
069    }
070
071    @Test
072    public void shouldEncodePercent() {
073        checkEncoding("%", "%25");
074        this.encoder.setSlashEncoded(false);
075        checkEncoding("%", "%25");
076    }
077
078    @Test
079    public void shouldNotEncodeAlphabeticCharacters() {
080        checkForNoEncoding("abcdefghijklmnopqrstuvwxyz");
081        checkForNoEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
082        this.encoder.setSlashEncoded(false);
083        checkForNoEncoding("abcdefghijklmnopqrstuvwxyz");
084        checkForNoEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
085    }
086
087    @Test
088    public void shouldNotEncodeNumericCharacters() {
089        checkForNoEncoding("0123456789");
090        this.encoder.setSlashEncoded(false);
091        checkForNoEncoding("0123456789");
092    }
093
094    @Test
095    public void shouldNotEncodeReservedPunctuationCharacters() {
096        checkForNoEncoding("-_.!~*\'()");
097        this.encoder.setSlashEncoded(false);
098        checkForNoEncoding("-_.!~*\'()");
099    }
100
101    @Test
102    public void shouldNotDecodePercentIfNotFollowedByValidHexNumber() {
103        checkDecoding("%", "%");
104        checkDecoding("%2", "%2");
105        checkDecoding("%2G", "%2G");
106        checkDecoding("%2f", "/");
107        checkDecoding("%25", "%");
108    }
109
110    @Test
111    public void shouldEncodeSpaceUsingHexFormat() {
112        checkEncoding(" ", "%20");
113    }
114
115    @Test
116    public void shouldEncodePunctuationUsingHexFormat() {
117        checkEncoding("`", "%60");
118        checkEncoding("@", "%40");
119        checkEncoding("#", "%23");
120        checkEncoding("$", "%24");
121        checkEncoding("^", "%5e");
122        checkEncoding("&", "%26");
123        checkEncoding("{", "%7b");
124        checkEncoding("[", "%5b");
125        checkEncoding("}", "%7d");
126        checkEncoding("]", "%5d");
127        checkEncoding("|", "%7c");
128        checkEncoding(":", "%3a");
129        checkEncoding(";", "%3b");
130        checkEncoding("\"", "%22");
131        checkEncoding("<", "%3c");
132        checkEncoding(",", "%2c");
133        checkEncoding(">", "%3e");
134        checkEncoding("?", "%3f");
135    }
136
137    @Test
138    public void shouldEncodeAndDecodeUrlsCorrectly() {
139        this.encoder.setSlashEncoded(false);
140        checkEncoding("http://acme.com/this is %something?get=true;something=false", "http%3a//acme.com/this%20is%20%25something%3fget%3dtrue%3bsomething%3dfalse");
141    }
142
143    @Test
144    @FixFor( "MODE-2258" )
145    public void shouldEncodeNonReservedNonAsciiCharacter() {
146        this.encoder.setSlashEncoded(false);
147        checkEncoding(":Тест:的", "%3a%d0%a2%d0%b5%d1%81%d1%82%3a%e7%9a%84");
148    }
149}