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.Test;
023
024/**
025 * Unit test for {@link XmlNameEncoder}
026 *
027 * @author Randall Hauch
028 * @author Horia Chiorean
029 */
030public class XmlNameEncoderTest {
031
032    private XmlNameEncoder encoder = new XmlNameEncoder();
033
034    protected void checkEncoding( String input,
035                                  String expected ) {
036        String output = this.encoder.encode(input);
037        assertThat(output, is(notNullValue()));
038        assertEquals(expected, output);
039        assertThat(output.length(), is(expected.length()));
040        assertThat(output, is(expected));
041
042        checkDecoding(output, input);
043    }
044
045    protected void checkForNoEncoding( String input ) {
046        String output = this.encoder.encode(input);
047        assertThat(output, is(notNullValue()));
048        assertEquals(input, output);
049        assertThat(output.length(), is(input.length()));
050        assertThat(output, is(input));
051
052        checkForNoDecoding(input);
053    }
054
055    protected void checkForNoDecoding( String input ) {
056        String output = this.encoder.decode(input);
057        assertThat(output, is(notNullValue()));
058        assertEquals(input, output);
059        assertThat(output.length(), is(input.length()));
060        assertThat(output, is(input));
061    }
062
063    protected void checkDecoding( String input,
064                                  String output ) {
065        String decoded = this.encoder.decode(input);
066        assertEquals(output, decoded);
067        assertThat(decoded.length(), is(output.length()));
068        assertThat(decoded, is(output));
069    }
070
071    @Test
072    public void shouldNotEncodeUnderscoreIfNotFollowedByLowercaseX() {
073        checkForNoEncoding("Employee_ID");
074        checkForNoEncoding("_Employee_");
075        checkForNoEncoding("Employee__ID");
076    }
077
078    @Test
079    public void shouldEncodeUnderscoreIfFollowedByLowercaseX() {
080        checkEncoding("Employee_x", "Employee_x005f_x");
081        checkEncoding("Employee_x0", "Employee_x005f_x0");
082        checkEncoding("Employee_x0022_", "Employee_x005f_x0022_");
083    }
084
085    @Test
086    public void shouldNotDecodeIfNotValidHexadecimalValue() {
087        checkForNoDecoding("_xH013_");
088    }
089
090    @Test
091    public void shouldNotDecodeIfNotValidEncodedFormat() {
092        checkForNoDecoding("_X0022_"); // No lowercase 'x'
093        checkForNoDecoding("x0022_"); // No leading '_'
094        checkForNoDecoding("_x0022a"); // No trailing '_'
095    }
096
097    @Test
098    public void shouldNotEncodeDigits() {
099        for (char c = '\u0030'; c <= '\u0039'; c++) { // digit
100            checkForNoEncoding("Employee" + c + "xyz");
101        }
102    }
103
104    @Test
105    public void shouldNotEncodeAlphabeticCharacters() {
106        for (char c = '\u0041'; c <= '\u005a'; c++) { // digit
107            checkForNoEncoding("Employee" + c + "xyz");
108        }
109        for (char c = '\u0061'; c <= '\u007a'; c++) { // digit
110            checkForNoEncoding("Employee" + c + "xyz");
111        }
112    }
113
114    @Test
115    public void shouldNotEncodePeriodOrDashOrUnderscoreCharacters() {
116        checkForNoEncoding("Employee.xyz");
117        checkForNoEncoding("Employee-xyz");
118        checkForNoEncoding("Employee:xyz");
119        checkForNoEncoding("Employee_abc");
120    }
121
122    @Test
123    public void shouldDecodeIfCompleteHexadecimal() {
124        checkDecoding("Employee_", "Employee_");
125        checkDecoding("Employee_x", "Employee_x");
126        checkDecoding("Employee_x0", "Employee_x0");
127        checkDecoding("Employee_x00", "Employee_x00");
128        checkDecoding("Employee_x002", "Employee_x002");
129        checkDecoding("Employee_x0022", "Employee_x0022");
130        checkDecoding("_", "_");
131        checkDecoding("_x", "_x");
132        checkDecoding("_x0", "_x0");
133        checkDecoding("_x00", "_x00");
134        checkDecoding("_x002", "_x002");
135        checkDecoding("_x0022", "_x0022");
136    }
137
138    @Test
139    public void shouldEncodeUnderscoreOnlyWhenFollowedByX() {
140        checkEncoding("Employee_xyz", "Employee_x005f_xyz");
141        checkEncoding("Employee_ayz", "Employee_ayz");
142    }
143
144    @Test
145    public void shouldEncodeNonAlphaNumericCharacters() {
146        checkEncoding("Employee!xyz", "Employee_x0021_xyz");
147        checkEncoding("Employee\"xyz", "Employee_x0022_xyz");
148        checkEncoding("Employee#xyz", "Employee_x0023_xyz");
149        checkEncoding("Employee$xyz", "Employee_x0024_xyz");
150        checkEncoding("Employee%xyz", "Employee_x0025_xyz");
151        checkEncoding("Employee&xyz", "Employee_x0026_xyz");
152        checkEncoding("Employee'xyz", "Employee_x0027_xyz");
153        checkEncoding("Employee(xyz", "Employee_x0028_xyz");
154        checkEncoding("Employee)xyz", "Employee_x0029_xyz");
155        checkEncoding("Employee*xyz", "Employee_x002a_xyz");
156        checkEncoding("Employee+xyz", "Employee_x002b_xyz");
157        checkEncoding("Employee,xyz", "Employee_x002c_xyz");
158        checkEncoding("Employee/xyz", "Employee_x002f_xyz");
159        checkEncoding("Employee\u0B9Bxyz", "Employee_x0b9b_xyz");
160    }
161
162    @Test
163    public void shouldEncodeIllegalStartCharacter() {
164        checkEncoding("042b4500-a8bc-4b79-8af0-59fb408ecfa5", "_x0030_42b4500-a8bc-4b79-8af0-59fb408ecfa5");
165        checkEncoding("-42b4500-a8bc-4b79-8af0-59fb408ecfa5", "_x002d_42b4500-a8bc-4b79-8af0-59fb408ecfa5");
166        checkEncoding(".42b4500-a8bc-4b79-8af0-59fb408ecfa5", "_x002e_42b4500-a8bc-4b79-8af0-59fb408ecfa5");
167    }
168
169    @Test
170    public void shouldDecodeIllegalStartCharacter() {
171        checkDecoding("_x0030_42b4500-a8bc-4b79-8af0-59fb408ecfa5", "042b4500-a8bc-4b79-8af0-59fb408ecfa5");
172        checkDecoding("_x002d_42b4500-a8bc-4b79-8af0-59fb408ecfa5", "-42b4500-a8bc-4b79-8af0-59fb408ecfa5");
173        checkDecoding("_x002e_42b4500-a8bc-4b79-8af0-59fb408ecfa5", ".42b4500-a8bc-4b79-8af0-59fb408ecfa5");
174    }
175
176}