Continued work on TemplateLanguage configuration and new file extensions: Renamed...
[freemarker.git] / freemarker-core-test / src / test / java / org / apache / freemarker / core / templateresolver / TemplateNameFormatTest.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.templateresolver;
21
22 import static org.apache.freemarker.test.hamcerst.Matchers.*;
23 import static org.hamcrest.Matchers.*;
24 import static org.junit.Assert.*;
25
26 import java.io.IOException;
27 import java.util.Locale;
28
29 import org.apache.freemarker.core.Configuration;
30 import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
31 import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
32 import org.apache.freemarker.test.TestConfigurationBuilder;
33 import org.junit.Test;
34
35
36 public class TemplateNameFormatTest {
37
38 @Test
39 public void testToRootBasedName() throws MalformedTemplateNameException {
40 final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE;
41
42 // Relative paths:
43 // - No scheme:
44 assertEquals("a/b", tnf.toRootBasedName("a/", "b"));
45 assertEquals("/a/b", tnf.toRootBasedName("/a/", "b"));
46 assertEquals("a/b", tnf.toRootBasedName("a/f", "b"));
47 assertEquals("/a/b", tnf.toRootBasedName("/a/f", "b"));
48 // - Scheme:
49 assertEquals("s://a/b", tnf.toRootBasedName("s://a/", "b"));
50 assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/", "b"));
51 assertEquals("s://a/b", tnf.toRootBasedName("s://a/f", "b"));
52 assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/f", "b"));
53 assertEquals("s://b", tnf.toRootBasedName("s://f", "b"));
54 assertEquals("s:///b", tnf.toRootBasedName("s:///f", "b"));
55 assertEquals("s:b", tnf.toRootBasedName("s:f", "b"));
56 assertEquals("s:/b", tnf.toRootBasedName("s:/f", "b"));
57 assertEquals("s:b", tnf.toRootBasedName("s:f", "/b"));
58 assertEquals("s:b", tnf.toRootBasedName("s:/f", "/b"));
59 assertEquals("s:f/b", tnf.toRootBasedName("s:f/", "b"));
60 assertEquals("s:/f/b", tnf.toRootBasedName("s:/f/", "b"));
61 assertEquals("s:b", tnf.toRootBasedName("s:f/", "/b"));
62 assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
63 assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
64 assertEquals("b", tnf.toRootBasedName("a/s://f/", "/b"));
65
66 // Absolute paths:
67 // - No scheme:
68 assertEquals("b", tnf.toRootBasedName("a/", "/b"));
69 assertEquals("b", tnf.toRootBasedName("/a/", "/b"));
70 assertEquals("b", tnf.toRootBasedName("a/s:/f/", "/b"));
71 // - Scheme:
72 assertEquals("s://b", tnf.toRootBasedName("s://x/", "/b"));
73 assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b"));
74
75 // Schemed absolute paths:
76 assertEquals("s://b", tnf.toRootBasedName("a/", "s://b"));
77 assertEquals("s://b", tnf.toRootBasedName("i://a/", "s://b"));
78 }
79
80 @Test
81 public void testNormalizeRootBasedName() throws MalformedTemplateNameException {
82 final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE;
83
84 assertEquals("", tnf.normalizeRootBasedName(""));
85 for (String lead : new String[] { "", "/" }) {
86 assertEquals("foo", tnf.normalizeRootBasedName(lead + "foo"));
87 assertEquals("foo", tnf.normalizeRootBasedName(lead + "./foo"));
88 assertEquals("foo", tnf.normalizeRootBasedName(lead + "./././foo"));
89 assertEquals("foo", tnf.normalizeRootBasedName(lead + "bar/../foo"));
90 assertEquals("a/b/", tnf.normalizeRootBasedName("a/b/"));
91 assertEquals("a/", tnf.normalizeRootBasedName("a/b/../"));
92 assertEquals("a/c../..d/e*/*f", tnf.normalizeRootBasedName("a/c../..d/e*/*f"));
93 assertEquals("", tnf.normalizeRootBasedName(""));
94 assertEquals("foo/bar/*", tnf.normalizeRootBasedName("foo/bar/*"));
95 assertEquals("schema://", tnf.normalizeRootBasedName("schema://"));
96
97 assertThrowsWithBackingOutException(lead + "bar/../../x/foo", tnf);
98 assertThrowsWithBackingOutException(lead + "../x", tnf);
99 assertThrowsWithBackingOutException(lead + "../../../x", tnf);
100 assertThrowsWithBackingOutException(lead + "../../../x", tnf);
101 assertThrowsWithBackingOutException("x://../../../foo", tnf);
102
103 {
104 final String name = lead + "foo\u0000";
105 try {
106 tnf.normalizeRootBasedName(name);
107 fail();
108 } catch (MalformedTemplateNameException e) {
109 assertEquals(name, e.getTemplateName());
110
111 assertThat(e.getMalformednessDescription(), containsStringIgnoringCase("null character"));
112 }
113 }
114 }
115
116 // ".." and "."
117 assertEquals("foo", tnf.normalizeRootBasedName("bar/./../foo"));
118
119 assertThrowsWithBackingOutException("../../foo", tnf);
120 assertThrowsWithBackingOutException("../../../../foo", tnf);
121
122 // ".." and "*"
123 assertEquals("a/*/foo", tnf.normalizeRootBasedName("a/b/*/../foo"));
124 //
125 assertEquals("foo", tnf.normalizeRootBasedName("a/b/*/../../foo"));
126 //
127 assertThrowsWithBackingOutException("a/b/*/../../../foo", tnf);
128 //
129 assertEquals("a/*/foo", tnf.normalizeRootBasedName("a/b/*/*/../foo"));
130 //
131 assertEquals("a/b/*/foo", tnf.normalizeRootBasedName("a/b/*/c/*/../foo"));
132 //
133 assertEquals("a/b/*/foo", tnf.normalizeRootBasedName("a/b/*/c/d/*/../../foo"));
134 //
135 assertEquals("a/*/b/*/foo", tnf.normalizeRootBasedName("a/*//b/*/c/d/*/../../foo"));
136 //
137 assertEquals("", tnf.normalizeRootBasedName("a/../*"));
138 //
139 assertEquals("", tnf.normalizeRootBasedName("a/../*/"));
140
141 // ".." and "scheme"
142 assertThrowsWithBackingOutException("x://../foo", tnf);
143 //
144 assertThrowsWithBackingOutException("x://../../foo", tnf);
145 //
146 assertThrowsWithBackingOutException("x:../foo", tnf);
147 //
148 assertThrowsWithBackingOutException("x:../../foo", tnf);
149
150 // Tricky cases with terminating "/":
151 assertEquals("", tnf.normalizeRootBasedName("/"));
152 // Terminating "/.." (produces terminating "/"):
153 assertEquals("foo/", tnf.normalizeRootBasedName("foo/bar/.."));
154 // Terminating "/." (produces terminating "/"):
155 assertEquals("foo/bar/", tnf.normalizeRootBasedName("foo/bar/."));
156
157 // Lonely "."
158 assertEquals("", tnf.normalizeRootBasedName("."));
159 // Lonely ".."
160 assertThrowsWithBackingOutException("..", tnf);
161 // Lonely "*"
162
163 // Eliminating redundant "//":
164 assertEquals("foo/bar", tnf.normalizeRootBasedName("foo//bar"));
165 //
166 assertEquals("foo/bar/baaz/wombat", tnf.normalizeRootBasedName("////foo//bar///baaz////wombat"));
167 //
168 assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme://foo"));
169 //
170 assertEquals("scheme://foo/x/y", tnf.normalizeRootBasedName("scheme://foo//x/y"));
171 //
172 assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme:///foo"));
173 //
174 assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme:////foo"));
175
176 // Eliminating redundant "*"-s:
177 assertEquals("a/*/b", tnf.normalizeRootBasedName("a/*/*/b"));
178 //
179 assertEquals("a/*/b", tnf.normalizeRootBasedName("a/*/*/*/b"));
180 //
181 assertEquals("b", tnf.normalizeRootBasedName("*/*/b"));
182 //
183 assertEquals("b", tnf.normalizeRootBasedName("/*/*/b"));
184 //
185 assertEquals("b/*", tnf.normalizeRootBasedName("b/*/*"));
186 //
187 assertEquals("b/*", tnf.normalizeRootBasedName("b/*/*/*"));
188 //
189 assertEquals("a/*/b/*/c", tnf.normalizeRootBasedName("*/a/*/b/*/*/c"));
190
191 assertEquals("s:a/b", tnf.normalizeRootBasedName("s:a/b"));
192 assertEquals("s:a/b", tnf.normalizeRootBasedName("s:/a/b"));
193 assertEquals("s://a/b", tnf.normalizeRootBasedName("s://a/b"));
194 assertEquals("s://a/b", tnf.normalizeRootBasedName("s:///a/b"));
195 assertEquals("s://a/b", tnf.normalizeRootBasedName("s:////a/b"));
196
197 // Illegal use a of ":":
198 assertNormRBNameThrowsColonException("a/b:c/d", tnf);
199 assertNormRBNameThrowsColonException("a/b:/..", tnf);
200 }
201
202 @Test
203 public void testRootBasedNameToAbsoluteName() throws MalformedTemplateNameException {
204 final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE;
205
206 assertEquals("/foo/bar", tnf.rootBasedNameToAbsoluteName("foo/bar"));
207 assertEquals("scheme://foo/bar", tnf.rootBasedNameToAbsoluteName("scheme://foo/bar"));
208 assertEquals("/foo/bar", tnf.rootBasedNameToAbsoluteName("/foo/bar"));
209 // Lenient handling of malformed rootBasedName:
210 assertEquals("/a/b://c/d", tnf.rootBasedNameToAbsoluteName("a/b://c/d"));
211 assertEquals("b:/c/d", tnf.rootBasedNameToAbsoluteName("b:/c/d"));
212 assertEquals("b:c/d", tnf.rootBasedNameToAbsoluteName("b:c/d"));
213 }
214
215 @Test
216 public void testBackslashNotAllowed() throws IOException {
217 Configuration cfg = new TestConfigurationBuilder()
218 .templateLoader(new ByteArrayTemplateLoader())
219 .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
220 .build();
221 try {
222 cfg.getTemplate("././foo\\bar.f3ah", Locale.US);
223 fail();
224 } catch (MalformedTemplateNameException e) {
225 assertThat(e.getMessage(), containsStringIgnoringCase("backslash"));
226 }
227
228 }
229
230 private void assertThrowsWithBackingOutException(final String name, final TemplateNameFormat tnf) {
231 try {
232 tnf.normalizeRootBasedName(name);
233 fail();
234 } catch (MalformedTemplateNameException e) {
235 assertEquals(name, e.getTemplateName());
236 assertBackingOutFromRootException(e);
237 }
238 }
239
240 private void assertNormRBNameThrowsColonException(final String name, final TemplateNameFormat tnf)
241 throws MalformedTemplateNameException {
242 try {
243 tnf.normalizeRootBasedName(name);
244 fail();
245 } catch (MalformedTemplateNameException e) {
246 assertEquals(name, e.getTemplateName());
247 assertColonException(e);
248 }
249 }
250
251 private void assertBackingOutFromRootException(MalformedTemplateNameException e) {
252 assertThat(e.getMessage(), containsStringIgnoringCase("backing out"));
253 }
254
255 private void assertColonException(MalformedTemplateNameException e) {
256 assertThat(e.getMessage(), containsString("':'"));
257 }
258
259 }