Continued work on TemplateLanguage configuration and new file extensions: Renamed...
[freemarker.git] / freemarker-core-test / src / test / java / org / apache / freemarker / core / util / StringUtilsTest.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.freemarker.core.util;
21
22 import static junit.framework.TestCase.assertNull;
23 import static org.junit.Assert.*;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertSame;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29
30 import java.io.IOException;
31 import java.io.StringWriter;
32 import java.util.regex.Pattern;
33
34 import org.hamcrest.Matchers;
35 import org.junit.Test;
36
37 public class StringUtilsTest {
38
39 @Test
40 public void testV2319() {
41 assertEquals("\\n\\r\\f\\b\\t\\x00\\x19", _StringUtils.javaScriptStringEnc("\n\r\f\b\t\u0000\u0019"));
42 }
43
44 @Test
45 public void testControlChars() {
46 assertEsc(
47 "\n\r\f\b\t \u0000\u0019\u001F \u007F\u0080\u009F \u2028\u2029",
48 "\\n\\r\\f\\b\\t \\x00\\x19\\x1F \\x7F\\x80\\x9F \\u2028\\u2029",
49 "\\n\\r\\f\\b\\t \\u0000\\u0019\\u001F \\u007F\\u0080\\u009F \\u2028\\u2029");
50 }
51
52 @Test
53 public void testHtmlChars() {
54 assertEsc(
55 "<safe>/>->]> </foo> <!-- --> <![CDATA[ ]]> <?php?>",
56 "<safe>/>->]> <\\/foo> \\x3C!-- --\\> \\x3C![CDATA[ ]]\\> \\x3C?php?>",
57 "<safe>/>->]> <\\/foo> \\u003C!-- --\\u003E \\u003C![CDATA[ ]]\\u003E \\u003C?php?>");
58 assertEsc("<!c", "\\x3C!c", "\\u003C!c");
59 assertEsc("c<!", "c\\x3C!", "c\\u003C!");
60 assertEsc("c<", "c\\x3C", "c\\u003C");
61 assertEsc("c<c", "c<c", "c<c");
62 assertEsc("<c", "<c", "<c");
63 assertEsc(">", "\\>", "\\u003E");
64 assertEsc("->", "-\\>", "-\\u003E");
65 assertEsc("-->", "--\\>", "--\\u003E");
66 assertEsc("c-->", "c--\\>", "c--\\u003E");
67 assertEsc("-->c", "--\\>c", "--\\u003Ec");
68 assertEsc("]>", "]\\>", "]\\u003E");
69 assertEsc("]]>", "]]\\>", "]]\\u003E");
70 assertEsc("c]]>", "c]]\\>", "c]]\\u003E");
71 assertEsc("]]>c", "]]\\>c", "]]\\u003Ec");
72 assertEsc("c->", "c->", "c->");
73 assertEsc("c>", "c>", "c>");
74 assertEsc("-->", "--\\>", "--\\u003E");
75 assertEsc("/", "\\/", "\\/");
76 assertEsc("/c", "\\/c", "\\/c");
77 assertEsc("</", "<\\/", "<\\/");
78 assertEsc("</c", "<\\/c", "<\\/c");
79 assertEsc("c/", "c/", "c/");
80 }
81
82 @Test
83 public void testJSChars() {
84 assertEsc("\"", "\\\"", "\\\"");
85 assertEsc("'", "\\'", "'");
86 assertEsc("\\", "\\\\", "\\\\");
87 }
88
89 @Test
90 public void testSameStringsReturned() {
91 String s = "==> I/m <safe>!";
92 assertTrue(s == _StringUtils.jsStringEnc(s, false)); // "==" because is must return the same object
93 assertTrue(s == _StringUtils.jsStringEnc(s, true));
94
95 s = "";
96 assertTrue(s == _StringUtils.jsStringEnc(s, false));
97 assertTrue(s == _StringUtils.jsStringEnc(s, true));
98
99 s = "\u00E1rv\u00EDzt\u0171r\u0151 \u3020";
100 assertEquals(s, _StringUtils.jsStringEnc(s, false));
101 assertTrue(s == _StringUtils.jsStringEnc(s, false));
102 assertTrue(s == _StringUtils.jsStringEnc(s, true));
103 }
104
105 @Test
106 public void testOneOffs() {
107 assertEsc("c\"c\"cc\"\"c", "c\\\"c\\\"cc\\\"\\\"c", "c\\\"c\\\"cc\\\"\\\"c");
108 assertEsc("\"c\"cc\"", "\\\"c\\\"cc\\\"", "\\\"c\\\"cc\\\"");
109 assertEsc("c/c/cc//c", "c/c/cc//c", "c/c/cc//c");
110 assertEsc("c<c<cc<<c", "c<c<cc<<c", "c<c<cc<<c");
111 assertEsc("/<", "\\/\\x3C", "\\/\\u003C");
112 assertEsc(">", "\\>", "\\u003E");
113 assertEsc("]>", "]\\>", "]\\u003E");
114 assertEsc("->", "-\\>", "-\\u003E");
115 }
116
117 private void assertEsc(String s, String javaScript, String json) {
118 assertEquals(javaScript, _StringUtils.jsStringEnc(s, false));
119 assertEquals(json, _StringUtils.jsStringEnc(s, true));
120 }
121
122 @Test
123 public void testTrim() {
124 assertSame(_CollectionUtils.EMPTY_CHAR_ARRAY, _StringUtils.trim(_CollectionUtils.EMPTY_CHAR_ARRAY));
125 assertSame(_CollectionUtils.EMPTY_CHAR_ARRAY, _StringUtils.trim(" \t\u0001 ".toCharArray()));
126 {
127 char[] cs = "foo".toCharArray();
128 assertSame(cs, cs);
129 }
130 assertArrayEquals("foo".toCharArray(), _StringUtils.trim("foo ".toCharArray()));
131 assertArrayEquals("foo".toCharArray(), _StringUtils.trim(" foo".toCharArray()));
132 assertArrayEquals("foo".toCharArray(), _StringUtils.trim(" foo ".toCharArray()));
133 assertArrayEquals("foo".toCharArray(), _StringUtils.trim("\t\tfoo \r\n".toCharArray()));
134 assertArrayEquals("x".toCharArray(), _StringUtils.trim(" x ".toCharArray()));
135 assertArrayEquals("x y z".toCharArray(), _StringUtils.trim(" x y z ".toCharArray()));
136 }
137
138 @Test
139 public void testIsTrimmedToEmpty() {
140 assertTrue(_StringUtils.isTrimmableToEmpty("".toCharArray()));
141 assertTrue(_StringUtils.isTrimmableToEmpty("\r\r\n\u0001".toCharArray()));
142 assertFalse(_StringUtils.isTrimmableToEmpty("x".toCharArray()));
143 assertFalse(_StringUtils.isTrimmableToEmpty(" x ".toCharArray()));
144 }
145
146 @Test
147 public void testJQuote() {
148 assertEquals("null", _StringUtils.jQuote(null));
149 assertEquals("\"foo\"", _StringUtils.jQuote("foo"));
150 assertEquals("\"123\"", _StringUtils.jQuote(Integer.valueOf(123)));
151 assertEquals("\"foo's \\\"bar\\\"\"",
152 _StringUtils.jQuote("foo's \"bar\""));
153 assertEquals("\"\\n\\r\\t\\u0001\"",
154 _StringUtils.jQuote("\n\r\t\u0001"));
155 assertEquals("\"<\\nb\\rc\\td\\u0001>\"",
156 _StringUtils.jQuote("<\nb\rc\td\u0001>"));
157 }
158
159 @Test
160 public void testJQuoteNoXSS() {
161 assertEquals("null", _StringUtils.jQuoteNoXSS(null));
162 assertEquals("\"foo\"", _StringUtils.jQuoteNoXSS("foo"));
163 assertEquals("\"123\"", _StringUtils.jQuoteNoXSS(Integer.valueOf(123)));
164 assertEquals("\"foo's \\\"bar\\\"\"",
165 _StringUtils.jQuoteNoXSS("foo's \"bar\""));
166 assertEquals("\"\\n\\r\\t\\u0001\"",
167 _StringUtils.jQuoteNoXSS("\n\r\t\u0001"));
168 assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
169 _StringUtils.jQuoteNoXSS("<\nb\rc\td\u0001>"));
170 assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
171 _StringUtils.jQuoteNoXSS((Object) "<\nb\rc\td\u0001>"));
172 }
173
174 @Test
175 public void testGlobToRegularExpression() {
176 assertGlobMatches("a/b/c.f3ah", "a/b/c.f3ah");
177 assertGlobDoesNotMatch("/a/b/cxftl", "/a/b/c.f3ah", "a/b/C.f3ah");
178
179 assertGlobMatches("a/b/*.f3ah", "a/b/.f3ah", "a/b/x.f3ah", "a/b/xx.f3ah");
180 assertGlobDoesNotMatch("a/b/*.f3ah", "a/c/x.f3ah", "a/b/c/x.f3ah", "/a/b/x.f3ah", "a/b/xxftl");
181
182 assertGlobMatches("a/b/?.f3ah", "a/b/x.f3ah");
183 assertGlobDoesNotMatch("a/b/?.f3ah", "a/c/x.f3ah", "a/b/.f3ah", "a/b/xx.f3ah", "a/b/xxftl");
184
185 assertGlobMatches("a/**/c.f3ah", "a/b/c.f3ah", "a/c.f3ah", "a/b/b2/b3/c.f3ah", "a//c.f3ah");
186 assertGlobDoesNotMatch("a/**/c.f3ah", "x/b/c.f3ah", "a/b/x.f3ah");
187
188 assertGlobMatches("**/c.f3ah", "a/b/c.f3ah", "c.f3ah", "/c.f3ah", "///c.f3ah");
189 assertGlobDoesNotMatch("**/c.f3ah", "a/b/x.f3ah");
190
191 assertGlobMatches("a/b/**", "a/b/c.f3ah", "a/b/c2/c.f3ah", "a/b/", "a/b/c/");
192 assertGlobDoesNotMatch("a/b.f3ah");
193
194 assertGlobMatches("**", "a/b/c.f3ah", "");
195
196 assertGlobMatches("\\[\\{\\*\\?\\}\\]\\\\", "[{*?}]\\");
197 assertGlobDoesNotMatch("\\[\\{\\*\\?\\}\\]\\\\", "[{xx}]\\");
198
199 assertGlobMatches("a/b/\\?.f3ah", "a/b/?.f3ah");
200 assertGlobDoesNotMatch("a/b/\\?.f3ah", "a/b/x.f3ah");
201
202 assertGlobMatches("\\?\\?.f3ah", "??.f3ah");
203 assertGlobMatches("\\\\\\\\", "\\\\");
204 assertGlobMatches("\\\\\\\\?", "\\\\x");
205 assertGlobMatches("x\\", "x");
206
207 assertGlobMatches("???*", "123", "1234", "12345");
208 assertGlobDoesNotMatch("???*", "12", "1", "");
209
210 assertGlobMatches("**/a??/b*.f3ah", "a11/b1.f3ah", "x/a11/b123.f3ah", "x/y/a11/b.f3ah");
211 assertGlobDoesNotMatch("**/a??/b*.f3ah", "a1/b1.f3ah", "x/a11/c123.f3ah");
212
213 assertFalse(_StringUtils.globToRegularExpression("ab*").matcher("aBc").matches());
214 assertTrue(_StringUtils.globToRegularExpression("ab*", true).matcher("aBc").matches());
215 assertTrue(_StringUtils.globToRegularExpression("ab", true).matcher("aB").matches());
216 assertTrue(_StringUtils.globToRegularExpression("\u00E1b*", true).matcher("\u00C1bc").matches());
217
218 try {
219 _StringUtils.globToRegularExpression("x**/y");
220 fail();
221 } catch (IllegalArgumentException e) {
222 assertThat(e.getMessage(), Matchers.containsString("**"));
223 }
224
225 try {
226 _StringUtils.globToRegularExpression("**y");
227 fail();
228 } catch (IllegalArgumentException e) {
229 assertThat(e.getMessage(), Matchers.containsString("**"));
230 }
231
232 try {
233 _StringUtils.globToRegularExpression("[ab]c");
234 fail();
235 } catch (IllegalArgumentException e) {
236 assertThat(e.getMessage(), Matchers.containsString("unsupported"));
237 }
238
239 try {
240 _StringUtils.globToRegularExpression("{aa,bb}c");
241 fail();
242 } catch (IllegalArgumentException e) {
243 assertThat(e.getMessage(), Matchers.containsString("unsupported"));
244 }
245 }
246
247 private void assertGlobMatches(String glob, String... ss) {
248 Pattern pattern = _StringUtils.globToRegularExpression(glob);
249 for (String s : ss) {
250 if (!pattern.matcher(s).matches()) {
251 fail("Glob " + glob + " (regexp: " + pattern + ") doesn't match " + s);
252 }
253 }
254 }
255
256 private void assertGlobDoesNotMatch(String glob, String... ss) {
257 Pattern pattern = _StringUtils.globToRegularExpression(glob);
258 for (String s : ss) {
259 if (pattern.matcher(s).matches()) {
260 fail("Glob " + glob + " (regexp: " + pattern + ") matches " + s);
261 }
262 }
263 }
264
265 @Test
266 public void testHTMLEnc() {
267 String s = "";
268 assertSame(s, _StringUtils.XMLEncNA(s));
269
270 s = "asd";
271 assertSame(s, _StringUtils.XMLEncNA(s));
272
273 assertEquals("a&amp;b&lt;c&gt;d&quot;e'f", _StringUtils.XMLEncNA("a&b<c>d\"e'f"));
274 assertEquals("&lt;", _StringUtils.XMLEncNA("<"));
275 assertEquals("&lt;a", _StringUtils.XMLEncNA("<a"));
276 assertEquals("&lt;a&gt;", _StringUtils.XMLEncNA("<a>"));
277 assertEquals("a&gt;", _StringUtils.XMLEncNA("a>"));
278 assertEquals("&lt;&gt;", _StringUtils.XMLEncNA("<>"));
279 assertEquals("a&lt;&gt;b", _StringUtils.XMLEncNA("a<>b"));
280 }
281
282 @Test
283 public void testXHTMLEnc() throws IOException {
284 String s = "";
285 assertSame(s, _StringUtils.XHTMLEnc(s));
286
287 s = "asd";
288 assertSame(s, _StringUtils.XHTMLEnc(s));
289
290 testXHTMLEnc("a&amp;b&lt;c&gt;d&quot;e&#39;f", "a&b<c>d\"e'f");
291 testXHTMLEnc("&lt;", "<");
292 testXHTMLEnc("&lt;a", "<a");
293 testXHTMLEnc("&lt;a&gt;", "<a>");
294 testXHTMLEnc("a&gt;", "a>");
295 testXHTMLEnc("&lt;&gt;", "<>");
296 testXHTMLEnc("a&lt;&gt;b", "a<>b");
297 }
298
299 private void testXHTMLEnc(String expected, String in) throws IOException {
300 assertEquals(expected, _StringUtils.XHTMLEnc(in));
301
302 StringWriter sw = new StringWriter();
303 _StringUtils.XHTMLEnc(in, sw);
304 assertEquals(expected, sw.toString());
305 }
306
307 @Test
308 public void testXMLEnc() throws IOException {
309 String s = "";
310 assertSame(s, _StringUtils.XMLEnc(s));
311
312 s = "asd";
313 assertSame(s, _StringUtils.XMLEnc(s));
314
315 testXMLEnc("a&amp;b&lt;c&gt;d&quot;e&apos;f", "a&b<c>d\"e'f");
316 testXMLEnc("&lt;", "<");
317 testXMLEnc("&lt;a", "<a");
318 testXMLEnc("&lt;a&gt;", "<a>");
319 testXMLEnc("a&gt;", "a>");
320 testXMLEnc("&lt;&gt;", "<>");
321 testXMLEnc("a&lt;&gt;b", "a<>b");
322 }
323
324 private void testXMLEnc(String expected, String in) throws IOException {
325 assertEquals(expected, _StringUtils.XMLEnc(in));
326
327 StringWriter sw = new StringWriter();
328 _StringUtils.XMLEnc(in, sw);
329 assertEquals(expected, sw.toString());
330 }
331
332 @Test
333 public void testXMLEncQAttr() throws IOException {
334 String s = "";
335 assertSame(s, _StringUtils.XMLEncQAttr(s));
336
337 s = "asd";
338 assertSame(s, _StringUtils.XMLEncQAttr(s));
339
340 assertEquals("a&amp;b&lt;c>d&quot;e'f", _StringUtils.XMLEncQAttr("a&b<c>d\"e'f"));
341 assertEquals("&lt;", _StringUtils.XMLEncQAttr("<"));
342 assertEquals("&lt;a", _StringUtils.XMLEncQAttr("<a"));
343 assertEquals("&lt;a>", _StringUtils.XMLEncQAttr("<a>"));
344 assertEquals("a>", _StringUtils.XMLEncQAttr("a>"));
345 assertEquals("&lt;>", _StringUtils.XMLEncQAttr("<>"));
346 assertEquals("a&lt;>b", _StringUtils.XMLEncQAttr("a<>b"));
347 }
348
349 @Test
350 public void testXMLEncNQG() throws IOException {
351 String s = "";
352 assertSame(s, _StringUtils.XMLEncNQG(s));
353
354 s = "asd";
355 assertSame(s, _StringUtils.XMLEncNQG(s));
356
357 assertEquals("a&amp;b&lt;c>d\"e'f", _StringUtils.XMLEncNQG("a&b<c>d\"e'f"));
358 assertEquals("&lt;", _StringUtils.XMLEncNQG("<"));
359 assertEquals("&lt;a", _StringUtils.XMLEncNQG("<a"));
360 assertEquals("&lt;a>", _StringUtils.XMLEncNQG("<a>"));
361 assertEquals("a>", _StringUtils.XMLEncNQG("a>"));
362 assertEquals("&lt;>", _StringUtils.XMLEncNQG("<>"));
363 assertEquals("a&lt;>b", _StringUtils.XMLEncNQG("a<>b"));
364
365 assertEquals("&gt;", _StringUtils.XMLEncNQG(">"));
366 assertEquals("]&gt;", _StringUtils.XMLEncNQG("]>"));
367 assertEquals("]]&gt;", _StringUtils.XMLEncNQG("]]>"));
368 assertEquals("x]]&gt;", _StringUtils.XMLEncNQG("x]]>"));
369 assertEquals("x]>", _StringUtils.XMLEncNQG("x]>"));
370 assertEquals("]x>", _StringUtils.XMLEncNQG("]x>"));
371 }
372
373 @Test
374 public void testRTFEnc() throws IOException {
375 String s = "";
376 assertSame(s, _StringUtils.RTFEnc(s));
377
378 s = "asd";
379 assertSame(s, _StringUtils.RTFEnc(s));
380
381 testRTFEnc("a\\{b\\}c\\\\d", "a{b}c\\d");
382 testRTFEnc("\\{", "{");
383 testRTFEnc("\\{a", "{a");
384 testRTFEnc("\\{a\\}", "{a}");
385 testRTFEnc("a\\}", "a}");
386 testRTFEnc("\\{\\}", "{}");
387 testRTFEnc("a\\{\\}b", "a{}b");
388 }
389
390 private void testRTFEnc(String expected, String in) throws IOException {
391 assertEquals(expected, _StringUtils.RTFEnc(in));
392
393 StringWriter sw = new StringWriter();
394 _StringUtils.RTFEnc(in, sw);
395 assertEquals(expected, sw.toString());
396 }
397
398 @Test
399 public void testNormalizeEOLs() {
400 assertNull(_StringUtils.normalizeEOLs(null));
401 assertEquals("", _StringUtils.normalizeEOLs(""));
402 assertEquals("x", _StringUtils.normalizeEOLs("x"));
403 assertEquals("x\ny", _StringUtils.normalizeEOLs("x\ny"));
404 assertEquals("x\ny", _StringUtils.normalizeEOLs("x\r\ny"));
405 assertEquals("x\ny", _StringUtils.normalizeEOLs("x\ry"));
406 assertEquals("\n\n\n\n\n\n", _StringUtils.normalizeEOLs("\n\r\r\r\n\r\n\r"));
407 }
408
409 @Test
410 public void snakeCaseToCamelCase() {
411 assertNull(_StringUtils.snakeCaseToCamelCase(null));
412 assertEquals("", _StringUtils.snakeCaseToCamelCase(""));
413 assertEquals("x", _StringUtils.snakeCaseToCamelCase("x"));
414 assertEquals("xxx", _StringUtils.snakeCaseToCamelCase("xXx"));
415 assertEquals("fooBar", _StringUtils.snakeCaseToCamelCase("foo_bar"));
416 assertEquals("fooBar", _StringUtils.snakeCaseToCamelCase("FOO_BAR"));
417 assertEquals("fooBar", _StringUtils.snakeCaseToCamelCase("_foo__bar_"));
418 assertEquals("aBC", _StringUtils.snakeCaseToCamelCase("a_b_c"));
419 }
420
421 }