View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.cp;
18  
19  import static java.util.Locale.*;
20  import static org.apache.juneau.TestUtils.*;
21  import static org.apache.juneau.common.utils.StringUtils.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.nio.file.*;
25  import java.util.*;
26  
27  import org.apache.juneau.*;
28  import org.apache.juneau.cp.sub.*;
29  import org.junit.jupiter.api.*;
30  
31  public class FileFinder_Test extends TestBase {  // NOSONAR - Needs to be public.
32  
33  	private String read(FileFinder ff, String path) throws Exception {
34  		return toUtf8(ff.getStream(path, null).orElse(null));
35  	}
36  
37  	private String read(FileFinder ff, String path, Locale locale) throws Exception {
38  		return toUtf8(ff.getStream(path, locale).orElse(null));
39  	}
40  
41  	//-----------------------------------------------------------------------------------------------------------------
42  	// Basic tests.
43  	//-----------------------------------------------------------------------------------------------------------------
44  
45  	@Test void a01_empty() throws Exception {
46  		var x = FileFinder
47  			.create()
48  			.build();
49  
50  		assertNull(read(x,"files/test1a"));
51  	}
52  
53  	//-----------------------------------------------------------------------------------------------------------------
54  	// File system tests.
55  	//-----------------------------------------------------------------------------------------------------------------
56  
57  	@Test void b01_fileSystem_rootDir() throws Exception {
58  		var x = FileFinder
59  			.create()
60  			.dir(".")
61  			.build();
62  
63  		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
64  
65  		for (var p : patterns) {
66  			assertContains("[home:/files/test1/"+p+"]", read(x,"files/test1/"+p));
67  			assertContains("[home:/files/test1/dir/"+p+"]", read(x,"files/test1/dir/"+p));
68  			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x,"files/test1/dir/dir/"+p));
69  			assertContains("[home:/files/test1/"+p+"]", read(x," / files/test1/"+p+" / "));
70  			assertContains("[home:/files/test1/dir/"+p+"]", read(x," / files/test1/dir/"+p+" / "));
71  			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x," / files/test1/dir/dir/"+p+" / "));
72  		}
73  
74  		var badPatterns = a("files/test1/bad.txt","files/test1/../test1/_a.txt","files/test1/%2E%2E/test1/_a.txt","files/bad.txt",null,"",".","..","%2E","%2E%2E","j.class","k.properties");
75  
76  		for (var p : badPatterns) {
77  			assertNull(read(x,p));
78  		}
79  	}
80  
81  	@Test void b02_fileSystem_subDir() throws Exception {
82  		var x = FileFinder
83  			.create()
84  			.dir("files")
85  			.build();
86  
87  		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
88  
89  		for (var p : patterns) {
90  			assertContains("[home:/files/test1/"+p+"]", read(x,"test1/"+p));
91  			assertContains("[home:/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p));
92  			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p));
93  			assertContains("[home:/files/test1/"+p+"]", read(x,"/test1/"+p+"/"));
94  			assertContains("[home:/files/test1/dir/"+p+"]", read(x,"/test1/dir/"+p+"/"));
95  			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x,"/test1/dir/dir/"+p+"/"));
96  		}
97  
98  		var badPatterns = a("test1/bad.txt","test1/../test1/_a.txt","bad.txt",null,"",".","..");
99  
100 		for (var p : badPatterns) {
101 			assertNull(read(x,p));
102 		}
103 	}
104 
105 	@Test void b03_fileSystem_localized_flat() throws Exception {
106 		var x = FileFinder
107 			.create()
108 			.dir("files")
109 			.build();
110 
111 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
112 		var patterns_ja = a("_a_ja.txt","_b_ja",".c",".d_ja.txt","e_ja.txt","f_ja","g_foo_ja.txt","h.foo_ja.txt","i_foo_ja");
113 		var patterns_ja_JP = a("_a_ja_JP.txt","_b_ja_JP",".c",".d_ja_JP.txt","e_ja_JP.txt","f_ja_JP","g_foo_ja_JP.txt","h.foo_ja_JP.txt","i_foo_ja_JP");
114 
115 		for (var i = 0; i < patterns.length; i++) {
116 			var p = patterns[i];
117 			var p_ja = patterns_ja[i];
118 			var p_ja_JP = patterns_ja_JP[i];
119 
120 			assertContains("[home:/files/test1/"+p+"]", read(x,"test1/"+p,null));
121 			assertContains("[home:/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p,null));
122 			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p,null));
123 			assertContains("[home:/files/test1/"+p+"]", read(x,"/test1/"+p+"/",null));
124 			assertContains("[home:/files/test1/dir/"+p+"]", read(x,"/test1/dir/"+p+"/",null));
125 			assertContains("[home:/files/test1/dir/dir/"+p+"]", read(x,"/test1/dir/dir/"+p+"/",null));
126 
127 			assertContains("[home:/files/test1/"+p_ja+"]", read(x,"test1/"+p,JAPANESE));
128 			assertContains("[home:/files/test1/dir/"+p_ja+"]", read(x,"test1/dir/"+p,JAPANESE));
129 			assertContains("[home:/files/test1/dir/dir/"+p_ja+"]", read(x,"test1/dir/dir/"+p,JAPANESE));
130 			assertContains("[home:/files/test1/"+p_ja+"]", read(x,"/test1/"+p+"/",JAPANESE));
131 			assertContains("[home:/files/test1/dir/"+p_ja+"]", read(x,"/test1/dir/"+p+"/",JAPANESE));
132 			assertContains("[home:/files/test1/dir/dir/"+p_ja+"]", read(x,"/test1/dir/dir/"+p+"/",JAPANESE));
133 
134 			assertContains("[home:/files/test1/"+p_ja_JP+"]", read(x,"test1/"+p,JAPAN));
135 			assertContains("[home:/files/test1/dir/"+p_ja_JP+"]", read(x,"test1/dir/"+p,JAPAN));
136 			assertContains("[home:/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"test1/dir/dir/"+p,JAPAN));
137 			assertContains("[home:/files/test1/"+p_ja_JP+"]", read(x,"/test1/"+p+"/",JAPAN));
138 			assertContains("[home:/files/test1/dir/"+p_ja_JP+"]", read(x,"/test1/dir/"+p+"/",JAPAN));
139 			assertContains("[home:/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"/test1/dir/dir/"+p+"/",JAPAN));
140 		}
141 
142 		var badPatterns = a("test1/bad.txt","test1/../test1/_a.txt","bad.txt",null,"",".","..","j.class","k.properties");
143 
144 		for (var p : badPatterns) {
145 			assertNull(read(x,p,null));
146 			assertNull(read(x,p,JAPANESE));
147 			assertNull(read(x,p,JAPAN));
148 		}
149 	}
150 
151 	@Test void b04_fileSystem_localized_hierarchical() throws Exception {
152 		var x = FileFinder
153 			.create()
154 			.dir("files/test2")
155 			.build();
156 
157 		assertContains("[home:/files/test2/a.txt]", read(x,"a.txt", null));
158 		assertContains("[home:/files/test2/ja/a.txt]", read(x,"a.txt", JAPANESE));
159 		assertContains("[home:/files/test2/ja/JP/a.txt]", read(x,"a.txt", JAPAN));
160 		assertContains("[home:/files/test2/a.txt]", read(x,"/a.txt/", null));
161 		assertContains("[home:/files/test2/ja/a.txt]", read(x,"/a.txt/", JAPANESE));
162 		assertContains("[home:/files/test2/ja/JP/a.txt]", read(x,"/a.txt/", JAPAN));
163 
164 		assertContains("[home:/files/test2/dir/a.txt]", read(x,"dir/a.txt", null));
165 		assertContains("[home:/files/test2/ja/dir/a.txt]", read(x,"dir/a.txt", JAPANESE));
166 		assertContains("[home:/files/test2/ja/JP/dir/a.txt]", read(x,"dir/a.txt", JAPAN));
167 		assertContains("[home:/files/test2/dir/a.txt]", read(x,"/dir/a.txt/", null));
168 		assertContains("[home:/files/test2/ja/dir/a.txt]", read(x,"/dir/a.txt/", JAPANESE));
169 		assertContains("[home:/files/test2/ja/JP/dir/a.txt]", read(x,"/dir/a.txt/", JAPAN));
170 
171 		assertContains("[home:/files/test2/dir/dir/a.txt]", read(x,"dir/dir/a.txt", null));
172 		assertContains("[home:/files/test2/ja/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPANESE));
173 		assertContains("[home:/files/test2/ja/JP/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPAN));
174 		assertContains("[home:/files/test2/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", null));
175 		assertContains("[home:/files/test2/ja/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPANESE));
176 		assertContains("[home:/files/test2/ja/JP/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPAN));
177 	}
178 
179 	//-----------------------------------------------------------------------------------------------------------------
180 	// Classpath tests - Classpath root
181 	//-----------------------------------------------------------------------------------------------------------------
182 
183 	@Test void c01_classpathRoot_rootDir() throws Exception {
184 		var x = FileFinder
185 			.create()
186 			.cp(FileFinder_Test.class, "/", false)
187 			.build();
188 
189 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
190 
191 		for (var p : patterns) {
192 			assertContains("[cp:/files/test1/"+p+"]", read(x,"files/test1/"+p));
193 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x,"files/test1/dir/"+p));
194 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x,"files/test1/dir/dir/"+p));
195 			assertContains("[cp:/files/test1/"+p+"]", read(x," / files/test1/"+p+" / "));
196 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x," / files/test1/dir/"+p+" / "));
197 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x," / files/test1/dir/dir/"+p+" / "));
198 		}
199 
200 		var badPatterns = a("files/test1/bad.txt","files/test1/../test1/_a.txt","files/bad.txt",null,"",".","..","LocalizedFileStore_Test.class");
201 
202 		for (var p : badPatterns) {
203 			assertNull(read(x,p));
204 		}
205 	}
206 
207 	@Test void c02_classpathRoot_subdir() throws Exception {
208 		var x = FileFinder
209 			.create()
210 			.cp(FileFinder_Test.class, "/files", false)
211 			.build();
212 
213 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
214 
215 		for (var p : patterns) {
216 			assertContains("[cp:/files/test1/"+p+"]", read(x,"test1/"+p));
217 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p));
218 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p));
219 			assertContains("[cp:/files/test1/"+p+"]", read(x," / test1/"+p+" / "));
220 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x," / test1/dir/"+p+" / "));
221 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x," / test1/dir/dir/"+p+" / "));
222 		}
223 
224 		var badPatterns = a("files/test1/bad.txt","files/test1/../test1/_a.txt","files/bad.txt",null,"",".","..");
225 
226 		for (var p : badPatterns) {
227 			assertNull(read(x,p));
228 		}
229 	}
230 
231 	@Test void c03_classpathRoot_localized_flat() throws Exception {
232 		var x = FileFinder
233 			.create()
234 			.cp(FileFinder_Test.class, "/files", false)
235 			.build();
236 
237 
238 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
239 		var patterns_ja = a("_a_ja.txt","_b_ja",".c",".d_ja.txt","e_ja.txt","f_ja","g_foo_ja.txt","h.foo_ja.txt","i_foo_ja");
240 		var patterns_ja_JP = a("_a_ja_JP.txt","_b_ja_JP",".c",".d_ja_JP.txt","e_ja_JP.txt","f_ja_JP","g_foo_ja_JP.txt","h.foo_ja_JP.txt","i_foo_ja_JP");
241 
242 		for (var i = 0; i < patterns.length; i++) {
243 			var p = patterns[i];
244 			var p_ja = patterns_ja[i];
245 			var p_ja_JP = patterns_ja_JP[i];
246 
247 			assertContains("[cp:/files/test1/"+p+"]", read(x,"test1/"+p,null));
248 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p,null));
249 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p,null));
250 			assertContains("[cp:/files/test1/"+p+"]", read(x,"/test1/"+p+"/",null));
251 			assertContains("[cp:/files/test1/dir/"+p+"]", read(x,"/test1/dir/"+p+"/",null));
252 			assertContains("[cp:/files/test1/dir/dir/"+p+"]", read(x,"/test1/dir/dir/"+p+"/",null));
253 
254 			assertContains("[cp:/files/test1/"+p_ja+"]", read(x,"test1/"+p,JAPANESE));
255 			assertContains("[cp:/files/test1/dir/"+p_ja+"]", read(x,"test1/dir/"+p,JAPANESE));
256 			assertContains("[cp:/files/test1/dir/dir/"+p_ja+"]", read(x,"test1/dir/dir/"+p,JAPANESE));
257 			assertContains("[cp:/files/test1/"+p_ja+"]", read(x,"/test1/"+p+"/",JAPANESE));
258 			assertContains("[cp:/files/test1/dir/"+p_ja+"]", read(x,"/test1/dir/"+p+"/",JAPANESE));
259 			assertContains("[cp:/files/test1/dir/dir/"+p_ja+"]", read(x,"/test1/dir/dir/"+p+"/",JAPANESE));
260 
261 			assertContains("[cp:/files/test1/"+p_ja_JP+"]", read(x,"test1/"+p,JAPAN));
262 			assertContains("[cp:/files/test1/dir/"+p_ja_JP+"]", read(x,"test1/dir/"+p,JAPAN));
263 			assertContains("[cp:/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"test1/dir/dir/"+p,JAPAN));
264 			assertContains("[cp:/files/test1/"+p_ja_JP+"]", read(x,"/test1/"+p+"/",JAPAN));
265 			assertContains("[cp:/files/test1/dir/"+p_ja_JP+"]", read(x,"/test1/dir/"+p+"/",JAPAN));
266 			assertContains("[cp:/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"/test1/dir/dir/"+p+"/",JAPAN));
267 		}
268 
269 		var badPatterns = a("test1/bad.txt","test1/../test1/_a.txt","bad.txt",null,"",".","..");
270 
271 		for (var p : badPatterns) {
272 			assertNull(read(x,p,null));
273 			assertNull(read(x,p,JAPANESE));
274 			assertNull(read(x,p,JAPAN));
275 		}
276 	}
277 
278 
279 	@Test void c04_classpathRoot_localized_hierarchical() throws Exception {
280 		var x = FileFinder
281 			.create()
282 			.cp(FileFinder_Test.class, "/files/test2", false)
283 			.build();
284 
285 		assertContains("[cp:/files/test2/a.txt]", read(x,"a.txt", null));
286 		assertContains("[cp:/files/test2/ja/a.txt]", read(x,"a.txt", JAPANESE));
287 		assertContains("[cp:/files/test2/ja/JP/a.txt]", read(x,"a.txt", JAPAN));
288 		assertContains("[cp:/files/test2/a.txt]", read(x,"/a.txt/", null));
289 		assertContains("[cp:/files/test2/ja/a.txt]", read(x,"/a.txt/", JAPANESE));
290 		assertContains("[cp:/files/test2/ja/JP/a.txt]", read(x,"/a.txt/", JAPAN));
291 
292 		assertContains("[cp:/files/test2/dir/a.txt]", read(x,"dir/a.txt", null));
293 		assertContains("[cp:/files/test2/ja/dir/a.txt]", read(x,"dir/a.txt", JAPANESE));
294 		assertContains("[cp:/files/test2/ja/JP/dir/a.txt]", read(x,"dir/a.txt", JAPAN));
295 		assertContains("[cp:/files/test2/dir/a.txt]", read(x,"/dir/a.txt/", null));
296 		assertContains("[cp:/files/test2/ja/dir/a.txt]", read(x,"/dir/a.txt/", JAPANESE));
297 		assertContains("[cp:/files/test2/ja/JP/dir/a.txt]", read(x,"/dir/a.txt/", JAPAN));
298 
299 		assertContains("[cp:/files/test2/dir/dir/a.txt]", read(x,"dir/dir/a.txt", null));
300 		assertContains("[cp:/files/test2/ja/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPANESE));
301 		assertContains("[cp:/files/test2/ja/JP/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPAN));
302 		assertContains("[cp:/files/test2/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", null));
303 		assertContains("[cp:/files/test2/ja/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPANESE));
304 		assertContains("[cp:/files/test2/ja/JP/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPAN));
305 	}
306 
307 	//-----------------------------------------------------------------------------------------------------------------
308 	// Classpath tests - Classpath relative
309 	//-----------------------------------------------------------------------------------------------------------------
310 
311 	@Test void d01a_classpathRelative_rootDir() throws Exception {
312 		var x = FileFinder
313 			.create()
314 			.cp(FileFinder_Test.class, "", false)
315 			.build();
316 
317 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
318 
319 		for (var p : patterns) {
320 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"files/test1/"+p));
321 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"files/test1/dir/"+p));
322 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"files/test1/dir/dir/"+p));
323 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x," / files/test1/"+p+" / "));
324 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x," / files/test1/dir/"+p+" / "));
325 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x," / files/test1/dir/dir/"+p+" / "));
326 		}
327 
328 		assertContains("[cp:/org/apache/juneau/cp/_a.txt]", read(x,"_a.txt"));
329 
330 		var badPatterns = a("files/test1/bad.txt","files/test1/../test1/_a.txt","files/bad.txt",null,"",".","..");
331 
332 		for (var p : badPatterns) {
333 			assertNull(read(x,p));
334 		}
335 	}
336 
337 	@Test void d01b_classpathRelative_rootDir_recursive() throws Exception {
338 		var x = FileFinder
339 			.create()
340 			.cp(FileFinder_Test2.class, "", true)
341 			.build();
342 
343 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
344 
345 		for (var p : patterns) {
346 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"files/test1/"+p));
347 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"files/test1/dir/"+p));
348 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"files/test1/dir/dir/"+p));
349 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x," / files/test1/"+p+" / "));
350 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x," / files/test1/dir/"+p+" / "));
351 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x," / files/test1/dir/dir/"+p+" / "));
352 		}
353 	}
354 
355 	@Test void d02a_classpathRelative_subdir() throws Exception {
356 		var x = FileFinder
357 			.create()
358 			.cp(FileFinder_Test.class, "files", false)
359 			.build();
360 
361 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
362 
363 		for (var p : patterns) {
364 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"test1/"+p));
365 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p));
366 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p));
367 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x," / test1/"+p+" / "));
368 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x," / test1/dir/"+p+" / "));
369 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x," / test1/dir/dir/"+p+" / "));
370 		}
371 
372 		var badPatterns = a("files/test1/bad.txt","files/test1/../test1/_a.txt","files/bad.txt",null,"",".","..");
373 
374 		for (var p : badPatterns) {
375 			assertNull(read(x,p));
376 		}
377 	}
378 
379 	@Test void d02b_classpathRelative_subdir_recursive() throws Exception {
380 		var x = FileFinder
381 			.create()
382 			.cp(FileFinder_Test2.class, "files", true)
383 			.build();
384 
385 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
386 
387 		for (var p : patterns) {
388 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"test1/"+p));
389 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p));
390 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p));
391 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x," / test1/"+p+" / "));
392 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x," / test1/dir/"+p+" / "));
393 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x," / test1/dir/dir/"+p+" / "));
394 		}
395 	}
396 
397 	@Test void d03a_classpathRelative_localized_flat() throws Exception {
398 		var x = FileFinder
399 			.create()
400 			.cp(FileFinder_Test.class, "files", false)
401 			.build();
402 
403 
404 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
405 		var patterns_ja = a("_a_ja.txt","_b_ja",".c",".d_ja.txt","e_ja.txt","f_ja","g_foo_ja.txt","h.foo_ja.txt","i_foo_ja");
406 		var patterns_ja_JP = a("_a_ja_JP.txt","_b_ja_JP",".c",".d_ja_JP.txt","e_ja_JP.txt","f_ja_JP","g_foo_ja_JP.txt","h.foo_ja_JP.txt","i_foo_ja_JP");
407 
408 		for (var i = 0; i < patterns.length; i++) {
409 			var p = patterns[i];
410 			var p_ja = patterns_ja[i];
411 			var p_ja_JP = patterns_ja_JP[i];
412 
413 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"test1/"+p,null));
414 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p,null));
415 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p,null));
416 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"/test1/"+p+"/",null));
417 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"/test1/dir/"+p+"/",null));
418 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"/test1/dir/dir/"+p+"/",null));
419 
420 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja+"]", read(x,"test1/"+p,JAPANESE));
421 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja+"]", read(x,"test1/dir/"+p,JAPANESE));
422 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja+"]", read(x,"test1/dir/dir/"+p,JAPANESE));
423 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja+"]", read(x,"/test1/"+p+"/",JAPANESE));
424 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja+"]", read(x,"/test1/dir/"+p+"/",JAPANESE));
425 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja+"]", read(x,"/test1/dir/dir/"+p+"/",JAPANESE));
426 
427 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja_JP+"]", read(x,"test1/"+p,JAPAN));
428 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja_JP+"]", read(x,"test1/dir/"+p,JAPAN));
429 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"test1/dir/dir/"+p,JAPAN));
430 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja_JP+"]", read(x,"/test1/"+p+"/",JAPAN));
431 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja_JP+"]", read(x,"/test1/dir/"+p+"/",JAPAN));
432 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"/test1/dir/dir/"+p+"/",JAPAN));
433 		}
434 
435 		var badPatterns = a("test1/bad.txt","test1/../test1/_a.txt","bad.txt",null,"",".","..");
436 
437 		for (var p : badPatterns) {
438 			assertNull(read(x,p,null));
439 			assertNull(read(x,p,JAPANESE));
440 			assertNull(read(x,p,JAPAN));
441 		}
442 	}
443 
444 	@Test void d03b_classpathRelative_localized_flat_recursive() throws Exception {
445 		var x = FileFinder
446 			.create()
447 			.cp(FileFinder_Test2.class, "files", true)
448 			.build();
449 
450 		var patterns = a("_a.txt","_b",".c",".d.txt","e.txt","f","g_foo.txt","h.foo.txt","i_foo");
451 		var patterns_ja = a("_a_ja.txt","_b_ja",".c",".d_ja.txt","e_ja.txt","f_ja","g_foo_ja.txt","h.foo_ja.txt","i_foo_ja");
452 		var patterns_ja_JP = a("_a_ja_JP.txt","_b_ja_JP",".c",".d_ja_JP.txt","e_ja_JP.txt","f_ja_JP","g_foo_ja_JP.txt","h.foo_ja_JP.txt","i_foo_ja_JP");
453 
454 		for (var i = 0; i < patterns.length; i++) {
455 			var p = patterns[i];
456 			var p_ja = patterns_ja[i];
457 			var p_ja_JP = patterns_ja_JP[i];
458 
459 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"test1/"+p,null));
460 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"test1/dir/"+p,null));
461 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"test1/dir/dir/"+p,null));
462 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p+"]", read(x,"/test1/"+p+"/",null));
463 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p+"]", read(x,"/test1/dir/"+p+"/",null));
464 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p+"]", read(x,"/test1/dir/dir/"+p+"/",null));
465 
466 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja+"]", read(x,"test1/"+p,JAPANESE));
467 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja+"]", read(x,"test1/dir/"+p,JAPANESE));
468 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja+"]", read(x,"test1/dir/dir/"+p,JAPANESE));
469 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja+"]", read(x,"/test1/"+p+"/",JAPANESE));
470 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja+"]", read(x,"/test1/dir/"+p+"/",JAPANESE));
471 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja+"]", read(x,"/test1/dir/dir/"+p+"/",JAPANESE));
472 
473 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja_JP+"]", read(x,"test1/"+p,JAPAN));
474 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja_JP+"]", read(x,"test1/dir/"+p,JAPAN));
475 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"test1/dir/dir/"+p,JAPAN));
476 			assertContains("[cp:/org/apache/juneau/cp/files/test1/"+p_ja_JP+"]", read(x,"/test1/"+p+"/",JAPAN));
477 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/"+p_ja_JP+"]", read(x,"/test1/dir/"+p+"/",JAPAN));
478 			assertContains("[cp:/org/apache/juneau/cp/files/test1/dir/dir/"+p_ja_JP+"]", read(x,"/test1/dir/dir/"+p+"/",JAPAN));
479 		}
480 	}
481 
482 	@Test void d04a_classpathRelative_localized_hierarchical() throws Exception {
483 		var x = FileFinder
484 			.create()
485 			.cp(FileFinder_Test.class, "files/test2", false)
486 			.build();
487 
488 		assertContains("[cp:/org/apache/juneau/cp/files/test2/a.txt]", read(x,"a.txt", null));
489 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/a.txt]", read(x,"a.txt", JAPANESE));
490 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/a.txt]", read(x,"a.txt", JAPAN));
491 		assertContains("[cp:/org/apache/juneau/cp/files/test2/a.txt]", read(x,"/a.txt/", null));
492 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/a.txt]", read(x,"/a.txt/", JAPANESE));
493 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/a.txt]", read(x,"/a.txt/", JAPAN));
494 
495 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/a.txt]", read(x,"dir/a.txt", null));
496 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/a.txt]", read(x,"dir/a.txt", JAPANESE));
497 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/a.txt]", read(x,"dir/a.txt", JAPAN));
498 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/a.txt]", read(x,"/dir/a.txt/", null));
499 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/a.txt]", read(x,"/dir/a.txt/", JAPANESE));
500 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/a.txt]", read(x,"/dir/a.txt/", JAPAN));
501 
502 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/dir/a.txt]", read(x,"dir/dir/a.txt", null));
503 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPANESE));
504 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPAN));
505 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", null));
506 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPANESE));
507 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPAN));
508 	}
509 
510 	@Test void d04b_classpathRelative_localized_hierarchical_recursive() throws Exception {
511 		var x = FileFinder
512 			.create()
513 			.cp(FileFinder_Test2.class, "files/test2", true)
514 			.build();
515 
516 		assertContains("[cp:/org/apache/juneau/cp/files/test2/a.txt]", read(x,"a.txt", null));
517 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/a.txt]", read(x,"a.txt", JAPANESE));
518 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/a.txt]", read(x,"a.txt", JAPAN));
519 		assertContains("[cp:/org/apache/juneau/cp/files/test2/a.txt]", read(x,"/a.txt/", null));
520 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/a.txt]", read(x,"/a.txt/", JAPANESE));
521 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/a.txt]", read(x,"/a.txt/", JAPAN));
522 
523 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/a.txt]", read(x,"dir/a.txt", null));
524 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/a.txt]", read(x,"dir/a.txt", JAPANESE));
525 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/a.txt]", read(x,"dir/a.txt", JAPAN));
526 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/a.txt]", read(x,"/dir/a.txt/", null));
527 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/a.txt]", read(x,"/dir/a.txt/", JAPANESE));
528 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/a.txt]", read(x,"/dir/a.txt/", JAPAN));
529 
530 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/dir/a.txt]", read(x,"dir/dir/a.txt", null));
531 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPANESE));
532 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPAN));
533 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", null));
534 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPANESE));
535 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/dir/a.txt]", read(x,"/dir/dir/a.txt/", JAPAN));
536 
537 		FileFinder
538 			.create()
539 			.cp(FileFinder_Test2.class, "files/test2", true)
540 			.exclude("(?i).*\\.(class|properties)")
541 			.build();
542 	}
543 
544 	@Test void d05_classpathRelative_ignorePattern() throws Exception {
545 		var x = FileFinder
546 			.create()
547 			.cp(FileFinder_Test2.class, "files/test2", true)
548 			.exclude("(?i).*\\.(txt)")
549 			.build();
550 
551 		assertNull(read(x,"a.txt", null));
552 		assertNull(read(x,"a.txt", JAPANESE));
553 		assertNull(read(x,"a.txt", JAPAN));
554 
555 		assertNull(read(x,"dir/a.txt", null));
556 		assertNull(read(x,"dir/a.txt", JAPANESE));
557 		assertNull(read(x,"dir/a.txt", JAPAN));
558 
559 		assertNull(read(x,"dir/dir/a.txt", null));
560 		assertNull(read(x,"dir/dir/a.txt", JAPANESE));
561 		assertNull(read(x,"dir/dir/a.txt", JAPAN));
562 
563 		x = FileFinder
564 			.create()
565 			.cp(FileFinder_Test2.class, "files/test2", true)
566 			.exclude("(?i).*\\.(TXT)")
567 			.build();
568 
569 		assertNull(read(x,"a.txt", null));
570 		assertNull(read(x,"a.txt", JAPANESE));
571 		assertNull(read(x,"a.txt", JAPAN));
572 
573 		assertNull(read(x,"dir/a.txt", null));
574 		assertNull(read(x,"dir/a.txt", JAPANESE));
575 		assertNull(read(x,"dir/a.txt", JAPAN));
576 
577 		assertNull(read(x,"dir/dir/a.txt", null));
578 		assertNull(read(x,"dir/dir/a.txt", JAPANESE));
579 		assertNull(read(x,"dir/dir/a.txt", JAPAN));
580 
581 		x = FileFinder
582 			.create()
583 			.cp(FileFinder_Test2.class, "files/test2", true)
584 			.exclude()
585 			.build();
586 
587 		assertContains("[cp:/org/apache/juneau/cp/files/test2/a.txt]", read(x,"a.txt", null));
588 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/a.txt]", read(x,"a.txt", JAPANESE));
589 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/a.txt]", read(x,"a.txt", JAPAN));
590 
591 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/a.txt]", read(x,"dir/a.txt", null));
592 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/a.txt]", read(x,"dir/a.txt", JAPANESE));
593 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/a.txt]", read(x,"dir/a.txt", JAPAN));
594 
595 		assertContains("[cp:/org/apache/juneau/cp/files/test2/dir/dir/a.txt]", read(x,"dir/dir/a.txt", null));
596 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPANESE));
597 		assertContains("[cp:/org/apache/juneau/cp/files/test2/ja/JP/dir/dir/a.txt]", read(x,"dir/dir/a.txt", JAPAN));
598 	}
599 
600 	//-----------------------------------------------------------------------------------------------------------------
601 	// Other tests
602 	//-----------------------------------------------------------------------------------------------------------------
603 
604 	@Test void e01_localDir_hashCode() {
605 		var s = set(new LocalDir(Paths.get("test")), new LocalDir(Paths.get("test")));
606 		assertSize(1, s);
607 
608 		s = set(new LocalDir(Paths.get("test")), new LocalDir(Paths.get("test","test")));
609 		assertSize(2, s);
610 
611 		s = set(new LocalDir(List.class,null), new LocalDir(List.class,null));
612 		assertSize(1, s);
613 
614 		s = set(new LocalDir(List.class,null), new LocalDir(List.class,"foo"));
615 		assertSize(2, s);
616 
617 		s = set(new LocalDir(List.class,null), new LocalDir(String.class,null));
618 		assertSize(2, s);
619 	}
620 
621 	@Test void e02_caching() throws Exception {
622 		var x = FileFinder
623 			.create()
624 			.dir(".")
625 			.caching(100_000_000)
626 			.build();
627 
628 		assertContains("[home:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
629 		assertContains("[home:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
630 
631 		x = FileFinder
632 			.create()
633 			.dir(".")
634 			.caching(1)
635 			.build();
636 
637 		assertContains("[home:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
638 		assertContains("[home:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
639 
640 		x = FileFinder
641 			.create()
642 			.cp(FileFinder_Test.class, "/", false)
643 			.caching(100_000_000)
644 			.build();
645 
646 		assertContains("[cp:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
647 		assertContains("[cp:/files/test1/_a.txt]", read(x,"files/test1/_a.txt"));
648 	}
649 
650 	@Test void e03_subclassing() {
651 		var x = E03b
652 			.create()
653 			.dir(".")
654 			.caching(100_000_000)
655 			.type(E03b.class)
656 			.build();
657 		assertInstanceOf(E03b.class, x);
658 	}
659 
660 	public static class E03a extends FileFinder.Builder {
661 		protected E03a() {
662 			super(BeanStore.INSTANCE);
663 		}
664 	}
665 	public static class E03b extends BasicFileFinder {
666 		public static E03a create() {
667 			return new E03a();
668 		}
669 		public E03b(E03a x) {
670 			super(x);
671 		}
672 	}
673 }