KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > io > FileTestBase


1 /*
2  * FileTestBase.java
3  * JUnit based test
4  *
5  * Created on 28. Juli 2005, 11:52
6  */

7 /*
8  * Copyright 2005-2006 Schlichtherle IT Services
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */

22
23 package de.schlichtherle.io;
24
25 import de.schlichtherle.io.archive.spi.ArchiveDriver;
26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.ByteArrayOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.ObjectInputStream JavaDoc;
31 import java.io.ObjectOutputStream JavaDoc;
32 import java.io.OutputStream JavaDoc;
33 import java.io.FileNotFoundException JavaDoc;
34 import java.io.FilenameFilter JavaDoc;
35 import java.io.FileFilter JavaDoc;
36 import java.io.PrintStream JavaDoc;
37 import java.io.RandomAccessFile JavaDoc;
38 import java.lang.ref.Reference JavaDoc;
39 import java.lang.ref.WeakReference JavaDoc;
40 import java.net.URI JavaDoc;
41 import java.util.Arrays JavaDoc;
42 import java.util.HashSet JavaDoc;
43 import java.util.Random JavaDoc;
44 import java.util.Set JavaDoc;
45 import java.util.logging.Logger JavaDoc;
46 import java.util.regex.Matcher JavaDoc;
47 import java.util.regex.Pattern JavaDoc;
48
49 import junit.framework.*;
50
51 /**
52  * @author Christian Schlichtherle
53  */

54 public abstract class FileTestBase extends TestCase {
55
56     private static final Logger JavaDoc logger = Logger.getLogger(
57             FileTestBase.class.getName());
58     
59     private static final java.io.File JavaDoc _tempDir = new java.io.File JavaDoc(
60             System.getProperty("java.io.tmpdir"));
61     
62     private static final Matcher JavaDoc _tempMatcher
63             = Pattern.compile(UpdatingArchiveController.TEMP_FILE_PREFIX
64             + ".*\\" + UpdatingArchiveController.TEMP_FILE_SUFFIX).matcher("");
65     
66     private static final Set JavaDoc totalTemps = new HashSet JavaDoc();
67     
68     private static final java.io.File JavaDoc _baseDir = _tempDir;
69     
70     /** The data to get compressed. */
71     private static final byte[] _data = new byte[100 * 1024]; // enough to waste some heat on CPU cycles
72
static {
73         boolean ea = false;
74         assert ea = true; // NOT ea == true !
75
logger.config("Java assertions " + (ea ? "enabled." : "disabled!"));
76         if (!ea)
77             logger.info("Please enable assertions for additional white box testing.");
78         
79         new Random JavaDoc().nextBytes(_data);
80         logger.config("Created " + _data.length + " bytes of random data.");
81         logger.config("Temp dir for TrueZIP API: " + _tempDir.getPath());
82         logger.config("Default temp dir for unit tests: " + _baseDir.getPath());
83         logger.config("Free memory: " + mb(Runtime.getRuntime().freeMemory()));
84         logger.config("Total memory: " + mb(Runtime.getRuntime().totalMemory()));
85         logger.config("Max memory: " + mb(Runtime.getRuntime().maxMemory()));
86     }
87
88     private static final String JavaDoc mb(long value) {
89         return ((value - 1 + 1024 * 1024) / (1024 * 1024)) + " MB"; // round up
90
}
91
92     protected byte[] data;
93     
94     protected java.io.File JavaDoc baseDir;
95     
96     protected String JavaDoc prefix;
97     
98     /**
99      * The lowercase suffix including the dot which shall be used when
100      * creating ZIP files.
101      */

102     protected String JavaDoc suffix;
103     
104     /** The temporary file to use as a ZIP file. */
105     protected File archive;
106     
107     public FileTestBase(String JavaDoc testName) {
108         super(testName);
109         
110         File.setDefaultArchiveDetector(ArchiveDetector.DEFAULT);
111     }
112     
113     /**
114      * A subclass must override this method to create the {@link #data}
115      * to be zipped.
116      * It must also finally call this superclass implementation to create
117      * the temporary file to be used as a ZIP file.
118      */

119     protected void setUp() throws Exception JavaDoc {
120         if (data == null)
121             data = _data; // (byte[]) _data.clone();
122
if (baseDir == null)
123             baseDir = _baseDir;
124         if (prefix == null)
125             prefix = "tzp-test";
126         if (suffix == null)
127             suffix = ".zip";
128         if (archive == null) {
129             archive = new File(createTempFile(prefix, suffix));
130             assertTrue(archive.delete());
131         }
132         
133         File.setLenient(true); // Restore default
134
}
135     
136     protected void tearDown() throws Exception JavaDoc {
137         data = null;
138         baseDir = null;
139         prefix = null;
140         suffix = null;
141
142         final boolean deleted = archive.delete();
143         if (!deleted && archive.exists()) {
144             logger.warning(archive + " (could not delete)");
145             //zip.deleteOnExit();
146
}
147         archive = null;
148
149         // umount now to delete temps and free memory.
150
// This prevents subsequent warnings about left over temporary files
151
// and removes cached data from the memory, so it helps to start on a
152
// clean sheet of paper with subsequent tests.
153
try {
154             File.umount();
155         } catch (ArchiveException ignored) {
156             // You should never (!) ignore all exceptions thrown by this method.
157
// The reason we do it here is that they are usually after effects
158
// of failed tests and we don't want any exception from the tests
159
// to be overridden by an exception thrown in this clean up method.
160
}
161
162         final String JavaDoc[] temps = _tempDir.list(new FilenameFilter JavaDoc() {
163             public boolean accept(java.io.File JavaDoc dir, String JavaDoc name) {
164                 _tempMatcher.reset(name);
165                 return _tempMatcher.matches();
166             }
167         });
168         assert temps != null;
169         for (int i = 0; i < temps.length; i++) {
170             if (totalTemps.add(temps[i])) {
171                 // If the TrueZIP API itself (rather than this test code)
172
// leaves a temporary file, then that's considered a bug!
173
logger.warning("Bug in TrueZIP API: Temp file found: " + temps[i]);
174             }
175         }
176
177     }
178     
179     public void testNormalize() {
180         logger.fine("testNormalize");
181
182         final java.io.File JavaDoc empty = new java.io.File JavaDoc("");
183         assertEquals(".", File.normalize(empty).getPath());
184
185         testNormalize("a", "./a");
186
187         testNormalize(".", ".");
188         testNormalize("..", "./..");
189         testNormalize("../..", "./../..");
190         testNormalize("../../..", "./../../..");
191         testNormalize("../../..", "./.././.././..");
192         testNormalize("../../..", "././../././../././..");
193         testNormalize("../../..", "./././.././././.././././..");
194
195         testNormalize("..", "..");
196         testNormalize("../..", "../..");
197         testNormalize("../../..", "../../..");
198         testNormalize("../../../..", "../../../..");
199         testNormalize("../../../..", "../.././.././..");
200         testNormalize("../../../..", ".././../././../././..");
201         testNormalize("../../../..", "../././.././././.././././..");
202
203         testNormalize("a", "a");
204         testNormalize(".", "a/..");
205         testNormalize("..", "a/../..");
206         testNormalize("../..", "a/../../..");
207         testNormalize("../..", "a/./.././.././..");
208         testNormalize("../..", "a/././../././../././..");
209         testNormalize("../..", "a/./././.././././.././././..");
210
211         testNormalize("a/b", "a/b");
212         testNormalize("a", "a/b/..");
213         testNormalize(".", "a/b/../..");
214         testNormalize("..", "a/b/../../..");
215         testNormalize("..", "a/b/./.././.././..");
216         testNormalize("..", "a/b/././../././../././..");
217         testNormalize("..", "a/b/./././.././././.././././..");
218
219         testNormalize("a/b/c", "a/b/c");
220         testNormalize("a/b", "a/b/c/..");
221         testNormalize("a", "a/b/c/../..");
222         testNormalize(".", "a/b/c/../../..");
223         testNormalize(".", "a/b/c/./.././.././..");
224         testNormalize(".", "a/b/c/././../././../././..");
225         testNormalize(".", "a/b/c/./././.././././.././././..");
226
227         testNormalize("a/b/c/d", "a/b/c/d");
228         testNormalize("a/b/c", "a/b/c/d/..");
229         testNormalize("a/b", "a/b/c/d/../..");
230         testNormalize("a", "a/b/c/d/../../..");
231         testNormalize("a", "a/b/c/d/./.././.././..");
232         testNormalize("a", "a/b/c/d/././../././../././..");
233         testNormalize("a", "a/b/c/d/./././.././././.././././..");
234     }
235     
236     void testNormalize(String JavaDoc result, final String JavaDoc path) {
237         result = result.replace('/', File.separatorChar);
238         java.io.File JavaDoc file = new java.io.File JavaDoc(path);
239         assertEquals(result, File.normalize(file).getPath());
240         file = new java.io.File JavaDoc(path + '/');
241         assertEquals(result, File.normalize(file).getPath());
242         file = new java.io.File JavaDoc(path + File.separator);
243         assertEquals(result, File.normalize(file).getPath());
244         file = new java.io.File JavaDoc(path + File.separator + ".");
245         assertEquals(result, File.normalize(file).getPath());
246         file = new java.io.File JavaDoc(path + File.separator + "." + File.separator + ".");
247         assertEquals(result, File.normalize(file).getPath());
248         file = new java.io.File JavaDoc(path + File.separator + "." + File.separator + "." + File.separator + ".");
249         assertEquals(result, File.normalize(file).getPath());
250     }
251     
252     public void testNormalizedAbsoluteFile() throws IOException JavaDoc {
253         logger.fine("testNormalizedAbsoluteFile");
254
255         testNormalizedAbsoluteFile("", "");
256         testNormalizedAbsoluteFile(".", ".");
257         testNormalizedAbsoluteFile("..", "..");
258         
259         testNormalizedAbsoluteFile("a", "a");
260         testNormalizedAbsoluteFile("a", "a/.");
261         testNormalizedAbsoluteFile(".", "a/..");
262         testNormalizedAbsoluteFile("b", "a/../b");
263         testNormalizedAbsoluteFile("b", "a/../b/.");
264         testNormalizedAbsoluteFile(".", "a/../b/..");
265         testNormalizedAbsoluteFile("c", "a/../b/../c");
266         testNormalizedAbsoluteFile("c", "a/../b/../c/.");
267         testNormalizedAbsoluteFile(".", "a/../b/../c/..");
268         
269         testNormalizedAbsoluteFile("../a", "../a");
270         testNormalizedAbsoluteFile("../a", "../a/.");
271         testNormalizedAbsoluteFile("..", "../a/..");
272         testNormalizedAbsoluteFile("../b", "../a/../b");
273         testNormalizedAbsoluteFile("../b", "../a/../b/.");
274         testNormalizedAbsoluteFile("..", "../a/../b/..");
275         testNormalizedAbsoluteFile("../c", "../a/../b/../c");
276         testNormalizedAbsoluteFile("../c", "../a/../b/../c/.");
277         testNormalizedAbsoluteFile("..", "../a/../b/../c/..");
278         
279         testNormalizedAbsoluteFile("../a", "../a");
280         testNormalizedAbsoluteFile("../a", "../a/.");
281         testNormalizedAbsoluteFile("../a/b", "../a/b");
282         testNormalizedAbsoluteFile("../a/b", "../a/b/.");
283         testNormalizedAbsoluteFile("../a", "../a/b/..");
284         testNormalizedAbsoluteFile("../a/c", "../a/b/../c");
285         testNormalizedAbsoluteFile("../a/c", "../a/b/../c/.");
286         testNormalizedAbsoluteFile("../a", "../a/b/../c/..");
287     }
288     
289     void testNormalizedAbsoluteFile(final String JavaDoc result, final String JavaDoc path)
290     throws IOException JavaDoc {
291         java.io.File JavaDoc resultFile = new java.io.File JavaDoc(result).getCanonicalFile();
292         java.io.File JavaDoc pathFile = new java.io.File JavaDoc(new File(path).getNormalizedAbsoluteFile().getPath());
293         assertEquals(resultFile, pathFile);
294     }
295     
296     public void testParentConstructor() throws Exception JavaDoc {
297         logger.fine("testParentConstructor");
298
299         // Test normalization and parent+child constructors.
300
// This is not yet a comprehensive test.
301

302         {
303             try {
304                 new File("x", (String JavaDoc) null);
305                 fail("Expected NullPointerException!");
306             } catch (NullPointerException JavaDoc expected) {
307             }
308
309             try {
310                 new File(new File("x"), (String JavaDoc) null);
311                 fail("Expected NullPointerException!");
312             } catch (NullPointerException JavaDoc expected) {
313             }
314         }
315
316         final String JavaDoc fs = File.separator;
317
318         {
319             final File[] files = {
320                 new File(archive, ""),
321                 new File(archive, "."),
322                 new File(archive, "." + fs),
323                 new File(archive, "." + fs + "."),
324                 new File(archive, "." + fs + "." + fs),
325                 new File(archive, "." + fs + "." + fs + "."),
326             };
327             for (int i = 0; i < files.length; i++) {
328                 final File file = files[i];
329                 assertSame(file, file.getInnerArchive());
330                 assertEquals("", file.getInnerEntryName());
331                 assertNull(file.getEnclArchive());
332                 assertNull(file.getEnclEntryName());
333             }
334         }
335
336         {
337             final String JavaDoc innerName = "inner" + suffix;
338             final File inner = new File(archive, innerName);
339             final File[] files = {
340                 new File(inner, ""),
341                 new File(inner, "."),
342                 new File(inner, "." + fs),
343                 new File(inner, "." + fs + "."),
344                 new File(inner, "." + fs + "." + fs),
345                 new File(inner, "." + fs + "." + fs + "."),
346             };
347             for (int i = 0; i < files.length; i++) {
348                 final File file = files[i];
349                 assertSame(file, file.getInnerArchive());
350                 assertEquals("", file.getInnerEntryName());
351                 assertSame(archive, file.getEnclArchive());
352                 assertEquals(innerName, file.getEnclEntryName());
353             }
354         }
355
356         {
357             final String JavaDoc entryName = "entry";
358             final File entry = new File(archive, entryName);
359             final File[] files = {
360                 new File(entry, ""),
361                 new File(entry, "."),
362                 new File(entry, "." + fs),
363                 new File(entry, "." + fs + "."),
364                 new File(entry, "." + fs + "." + fs),
365                 new File(entry, "." + fs + "." + fs + "."),
366             };
367             for (int i = 0; i < files.length; i++) {
368                 final File file = files[i];
369                 assertSame(archive, file.getInnerArchive());
370                 assertEquals(entryName, file.getInnerEntryName());
371                 assertSame(archive, file.getEnclArchive());
372                 assertEquals(entryName, file.getEnclEntryName());
373             }
374         }
375         
376         final File a = new File("outer" + suffix + "/removed" + suffix);
377         File b, c;
378         
379         b = new File("../removed.dir/removed.dir/../../dir/./inner" + suffix);
380         c = new File(a, b.getPath());
381         assertTrue(c.isArchive());
382         assertTrue(c.isEntry());
383         assertEquals("outer" + suffix,
384                 c.getEnclArchive().getPath());
385         assertEquals("dir/inner" + suffix,
386                 c.getEnclEntryName());
387         
388         b = new File("../removed.dir/removed.dir/../../dir/./inner" + suffix);
389         c = new File(a, b.getPath(), ArchiveDetector.NULL);
390         assertFalse(c.isArchive());
391         assertTrue(c.isEntry());
392         assertEquals("outer" + suffix,
393                 c.getInnerArchive().getPath());
394         assertEquals("dir/inner" + suffix,
395                 c.getInnerEntryName());
396         
397         b = new File("../removed.dir/removed.dir/../../dir/./inner"
398                 + suffix + "/removed.dir/removed.dir/../../dir/./test.txt");
399         c = new File(a, b.getPath());
400         assertFalse(c.isArchive());
401         assertTrue(c.isEntry());
402         assertEquals("outer" + suffix + fs + "removed" + suffix + fs + ".."
403                 + fs + "removed.dir" + fs + "removed.dir" + fs + ".." + fs
404                 + ".." + fs + "dir" + fs + "." + fs + "inner" + suffix,
405                 c.getInnerArchive().getPath());
406         assertEquals("dir/inner" + suffix,
407                 c.getInnerArchive().getEnclEntryName());
408     }
409     
410     public void testURIConstructor() throws Exception JavaDoc {
411         logger.fine("testURIConstructor");
412
413         File file;
414         final String JavaDoc fs = File.separator;
415         
416         // Whitespace in path. See issue #1. Thanks to mrudat for submitting this!
417
file = new File(new URI JavaDoc("file", "/with a space", null));
418         assertEquals("with a space", file.getName());
419         assertNull(file.getInnerArchive());
420         assertNull(file.getInnerEntryName());
421         assertNull(file.getEnclArchive());
422         assertNull(file.getEnclEntryName());
423         
424         // No ZIP file in path.
425

426         file = new File(new URI JavaDoc("file", "/a " + suffix + "/b " + suffix + "/", null));
427         assertNull(file.getInnerArchive());
428         assertNull(file.getInnerEntryName());
429         assertNull(file.getEnclArchive());
430         assertNull(file.getEnclEntryName());
431         
432         file = new File(new URI JavaDoc("file", "/a " + suffix + "/b " + suffix + "", null));
433         assertNull(file.getInnerArchive());
434         assertNull(file.getInnerEntryName());
435         assertNull(file.getEnclArchive());
436         assertNull(file.getEnclEntryName());
437         
438         // One ZIP file in path.
439
file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "/b " + suffix + "!/", null));
440         assertSame(file, file.getInnerArchive());
441         assertSame(File.EMPTY, file.getInnerEntryName());
442         assertNull(file.getEnclArchive());
443         assertNull(file.getEnclEntryName());
444         
445         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "/b " + suffix + "!", null));
446         assertSame(file, file.getInnerArchive());
447         assertSame(File.EMPTY, file.getInnerEntryName());
448         assertNull(file.getEnclArchive());
449         assertNull(file.getEnclEntryName());
450         
451         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/b " + suffix + "/", null));
452         assertSame(file.getInnerArchive(), file.getEnclArchive());
453         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
454         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
455         assertEquals("b " + suffix + "", file.getEnclEntryName());
456         
457         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/b " + suffix + "", null));
458         assertSame(file.getInnerArchive(), file.getEnclArchive());
459         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
460         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
461         assertEquals("b " + suffix + "", file.getEnclEntryName());
462         
463         // One ZIP file in path with one redundant jar: scheme.
464

465         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "/b " + suffix + "!/", null));
466         assertSame(file, file.getInnerArchive());
467         assertSame(File.EMPTY, file.getInnerEntryName());
468         assertNull(file.getEnclArchive());
469         assertNull(file.getEnclEntryName());
470         
471         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "/b " + suffix + "!", null));
472         assertSame(file, file.getInnerArchive());
473         assertSame(File.EMPTY, file.getInnerEntryName());
474         assertNull(file.getEnclArchive());
475         assertNull(file.getEnclEntryName());
476         
477         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "/", null));
478         assertSame(file.getInnerArchive(), file.getEnclArchive());
479         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
480         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
481         assertEquals("b " + suffix + "", file.getEnclEntryName());
482         
483         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "", null));
484         assertSame(file.getInnerArchive(), file.getEnclArchive());
485         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
486         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
487         assertEquals("b " + suffix + "", file.getEnclEntryName());
488         
489         // One ZIP file in path with two redundant jar: schemes.
490

491         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "/b " + suffix + "!/", null));
492         assertSame(file, file.getInnerArchive());
493         assertSame(File.EMPTY, file.getInnerEntryName());
494         assertNull(file.getEnclArchive());
495         assertNull(file.getEnclEntryName());
496         
497         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "/b " + suffix + "!", null));
498         assertSame(file, file.getInnerArchive());
499         assertSame(File.EMPTY, file.getInnerEntryName());
500         assertNull(file.getEnclArchive());
501         assertNull(file.getEnclEntryName());
502         
503         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "/", null));
504         assertSame(file.getInnerArchive(), file.getEnclArchive());
505         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
506         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
507         assertEquals("b " + suffix + "", file.getEnclEntryName());
508         
509         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "", null));
510         assertSame(file.getInnerArchive(), file.getEnclArchive());
511         assertSame(file.getInnerEntryName(), file.getEnclEntryName());
512         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
513         assertEquals("b " + suffix + "", file.getEnclEntryName());
514         
515         // Two ZIP files in path.
516

517         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/", null));
518         assertSame(file, file.getInnerArchive());
519         assertSame(File.EMPTY, file.getInnerEntryName());
520         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
521         assertEquals("b " + suffix + "", file.getEnclEntryName());
522         
523         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!", null));
524         assertSame(file, file.getInnerArchive());
525         assertSame(File.EMPTY, file.getInnerEntryName());
526         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
527         assertEquals("b " + suffix + "", file.getEnclEntryName());
528         
529         // One ZIP file in path with one misleading '!' in path.
530

531         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/b " + suffix + "!/", null));
532         assertSame(file, file.getInnerArchive());
533         assertSame(File.EMPTY, file.getInnerEntryName());
534         assertNull(file.getEnclArchive());
535         assertNull(file.getEnclEntryName());
536         
537         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/b " + suffix + "!", null));
538         assertSame(file, file.getInnerArchive());
539         assertSame(File.EMPTY, file.getInnerEntryName());
540         assertNull(file.getEnclArchive());
541         assertNull(file.getEnclEntryName());
542         
543         // Three ZIP files in path with one ZIP file removed by normalization.
544

545         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!/", null));
546         assertSame(file, file.getInnerArchive());
547         assertSame(File.EMPTY, file.getInnerEntryName());
548         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
549         assertEquals("c " + suffix + "", file.getEnclEntryName());
550         
551         file = new File(new URI JavaDoc("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!", null));
552         assertSame(file, file.getInnerArchive());
553         assertSame(File.EMPTY, file.getInnerEntryName());
554         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
555         assertEquals("c " + suffix + "", file.getEnclEntryName());
556         
557         // Three ZIP files in path with one ZIP file removed by normalization
558
// and hence one redundant jar: scheme.
559

560         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!/", null));
561         assertSame(file, file.getInnerArchive());
562         assertSame(File.EMPTY, file.getInnerEntryName());
563         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
564         assertEquals("c " + suffix + "", file.getEnclEntryName());
565         
566         file = new File(new URI JavaDoc("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!", null));
567         assertSame(file, file.getInnerArchive());
568         assertSame(File.EMPTY, file.getInnerEntryName());
569         assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath());
570         assertEquals("c " + suffix + "", file.getEnclEntryName());
571         
572         // One ZIP file in path which is removed by normalization.
573

574         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/../b " + suffix + "/", null));
575         assertNull(file.getInnerArchive());
576         assertNull(file.getInnerEntryName());
577         assertNull(file.getEnclArchive());
578         assertNull(file.getEnclEntryName());
579         
580         file = new File(new URI JavaDoc("jar", "file:/a " + suffix + "!/../b " + suffix + "", null));
581         assertNull(file.getInnerArchive());
582         assertNull(file.getInnerEntryName());
583         assertNull(file.getEnclArchive());
584         assertNull(file.getEnclEntryName());
585     }
586
587     public void testSerialization() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
588         logger.fine("testSerialization");
589
590         // Preamble.
591
final File inner = new File(archive, "inner" + suffix);
592         assertTrue(archive.isArchive());
593         assertTrue(inner.isArchive());
594
595         // Serialize.
596
final ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
597         final ObjectOutputStream JavaDoc out = new ObjectOutputStream JavaDoc(bos);
598         out.writeObject(inner);
599         out.close();
600
601         // Deserialize.
602
final ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(bos.toByteArray());
603         final ObjectInputStream JavaDoc in = new ObjectInputStream JavaDoc(bis);
604         final File inner2 = (File) in.readObject();
605         final File archive2 = (File) inner2.getParentFile();
606         in.close();
607
608         assertNotSame(inner, inner2);
609         assertNotSame(archive, archive2);
610
611         //
612
// Test details of the persistet object graph - part of this is
613
// repeated in the tests for DefaultArchiveDetector.
614
//
615

616         // Assert that controllers haven't been persistet.
617
final ArchiveController innerController = inner.getArchiveController();
618         final ArchiveController archiveController = archive.getArchiveController();
619         final ArchiveController inner2Controller = inner2.getArchiveController();
620         final ArchiveController archive2Controller = archive2.getArchiveController();
621         assertSame(innerController, inner2Controller);
622         assertSame(archiveController, archive2Controller);
623
624         // Assert that detectors have been persistet.
625
final ArchiveDetector innerDetector = inner.getArchiveDetector();
626         final ArchiveDetector archiveDetector = archive.getArchiveDetector();
627         final ArchiveDetector inner2Detector = inner2.getArchiveDetector();
628         final ArchiveDetector archive2Detector = archive2.getArchiveDetector();
629         assertNotSame(innerDetector, inner2Detector);
630         assertNotSame(archiveDetector, archive2Detector);
631
632         // Assert that drivers have been persistet.
633
final ArchiveDriver innerDriver = innerDetector.getArchiveDriver(inner.getPath());
634         final ArchiveDriver archiveDriver = archiveDetector.getArchiveDriver(archive.getPath());
635         final ArchiveDriver inner2Driver = inner2Detector.getArchiveDriver(inner2.getPath());
636         final ArchiveDriver archive2Driver = archive2Detector.getArchiveDriver(archive2.getPath());
637         assertNotSame(innerDriver, inner2Driver);
638         assertNotSame(archiveDriver, archive2Driver);
639
640         // Test that the controllers have been reconfigured with the new drivers.
641
// Note that this is only possible because the file systems haven't
642
// been touched yet (well, they haven't even been mounted).
643
final ArchiveDriver innerControllerDriver = innerController.getDriver();
644         final ArchiveDriver archiveControllerDriver = archiveController.getDriver();
645         assertSame(innerControllerDriver, inner2Driver);
646         assertSame(archiveControllerDriver, archive2Driver);
647     }
648
649     public void testGetOutermostArchive() {
650         logger.fine("testGetOutermostArchive");
651
652         File file = new File("abc/def" + suffix + "/efg" + suffix + "/hij" + suffix + "/test.txt");
653         assertEquals(new java.io.File JavaDoc("abc/def" + suffix), file.getTopLevelArchive());
654     }
655     
656     /**
657      * Test of equals method, of class de.schlichtherle.io.File.
658      */

659     public void testEqualsAndHashCode() {
660         logger.fine("testEqualsAndHashCode");
661
662         final boolean win = File.separatorChar == '\\'; // Windoze?
663

664         assertFalse(new File("dir/test.txt").equals(new File("dir" + suffix + "/test.txt")));
665         assertFalse(new File("dir" + suffix + "/test.txt").equals(new File("dir/test.txt")));
666         assertEquals(new File("dir" + suffix + "/test.txt", ArchiveDetector.NULL), new File("dir" + suffix + "/test.txt"));
667         assertEquals(new File("dir" + suffix + "/test.txt"), new File("dir" + suffix + "/test.txt", ArchiveDetector.NULL));
668         testEqualsAndHashCode(
669                 new File(win ? "c:\\any.txt" : "/any.txt"),
670                 new File(win ? "C:\\ANY.TXT" : "/ANY.TXT"));
671         testEqualsAndHashCode(
672                 new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt"),
673                 new File(win ? "C:\\ANY" + suffix.toUpperCase() + "\\test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt"));
674         testEqualsAndHashCode(
675                 new File(win ? "c:/any" + suffix + "/test.txt" : "/any" + suffix + "/test.txt"),
676                 new File(win ? "C:\\ANY" + suffix.toUpperCase() + "\\test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt"));
677         testEqualsAndHashCode(
678                 new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt"),
679                 new File(win ? "C:/ANY" + suffix.toUpperCase() + "/test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt"));
680         testEqualsAndHashCode(
681                 new File(win ? "c:/any" + suffix + "/test.txt" : "/any" + suffix + "/test.txt"),
682                 new File(win ? "C:/ANY" + suffix.toUpperCase() + "/test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt"));
683         if (win) {
684             testEqualsAndHashCode(
685                     new File("\\\\localhost\\any" + suffix + "\\test.txt"),
686                     new File("\\\\LOCALHOST\\ANY" + suffix.toUpperCase() + "\\test.txt"));
687             testEqualsAndHashCode(
688                     new File("//localhost/any" + suffix + "/test.txt"),
689                     new File("\\\\LOCALHOST\\ANY" + suffix.toUpperCase() + "\\test.txt"));
690             testEqualsAndHashCode(
691                     new File("\\\\localhost\\any" + suffix + "\\test.txt"),
692                     new File("//LOCALHOST/ANY" + suffix.toUpperCase() + "/test.txt"));
693             testEqualsAndHashCode(
694                     new File("//localhost/any" + suffix + "/test.txt"),
695                     new File("//LOCALHOST/ANY" + suffix.toUpperCase() + "/test.txt"));
696         }
697         final File l = new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt");
698         final File u = new File(win ? "c:\\any" + suffix + "\\TEST.TXT" : "/any" + suffix + "/TEST.TXT");
699         assertFalse(l.equals(u));
700         assertFalse(u.equals(l));
701     }
702     
703     void testEqualsAndHashCode(File a, File b) {
704         if (File.separatorChar == '\\') {
705             assertTrue(a.equals(b));
706             assertTrue(b.equals(a));
707             assertEquals(a.hashCode(), b.hashCode());
708         } else {
709             assertFalse(a.equals(b));
710             assertFalse(b.equals(a));
711         }
712         assertEquals(a.hashCode(), a.hashCode()); // multiple calls need to yield the same value
713
assertEquals(b.hashCode(), b.hashCode());
714     }
715     
716     public void testGetParentFile() {
717         logger.fine("testGetParentFile");
718
719         File abcdefgh = new File("a/b" + suffix + "/c/d/e" + suffix + "/f" + suffix + "/g/h" + suffix + "");
720         File abcdefg = (File) abcdefgh.getParentFile();
721         File abcdef = (File) abcdefg .getParentFile();
722         File abcde = (File) abcdef .getParentFile();
723         File abcd = (File) abcde .getParentFile();
724         File abc = (File) abcd .getParentFile();
725         File ab = (File) abc .getParentFile();
726         File a = (File) ab .getParentFile();
727         File n = (File) a .getParentFile();
728         assertEquals(abcdefgh.getInnerArchive(), abcdefgh);
729         assertEquals(abcdefgh.getEnclArchive() , abcdef);
730         assertEquals(abcdefg .getInnerArchive(), abcdef);
731         assertEquals(abcdefg .getEnclArchive() , abcdef);
732         assertEquals(abcdef .getInnerArchive(), abcdef);
733         assertEquals(abcdef .getEnclArchive() , abcde);
734         assertEquals(abcde .getInnerArchive(), abcde);
735         assertEquals(abcde .getEnclArchive() , ab);
736         assertEquals(abcd .getInnerArchive(), ab);
737         assertEquals(abcd .getEnclArchive() , ab);
738         assertEquals(abc .getInnerArchive(), ab);
739         assertEquals(abc .getEnclArchive() , ab);
740         assertEquals(ab .getInnerArchive(), ab);
741         assertEquals(ab .getEnclArchive() , null);
742         assertEquals(a .getInnerArchive(), null);
743         assertEquals(a .getEnclArchive() , null);
744         assertNull(n);
745     }
746
747     /**
748      * Test of isWritableOrCreatable method, of class de.schlichtherle.io.ArchiveController.
749      * <p>
750      * Note that this test is not quite correctly designed: It tests the
751      * operating system rather than the method.
752      */

753     public void testIsWritableOrCreatable() throws IOException JavaDoc {
754         logger.fine("testIsWritableOrCreatable");
755
756         final java.io.File JavaDoc file = createTempFile(prefix, null);
757         
758         boolean result = File.isWritableOrCreatable(file);
759         assertTrue(result);
760
761         boolean total = true;
762         final FileInputStream fin = new FileInputStream(file);
763         try {
764             result = File.isWritableOrCreatable(file);
765             total &= result;
766         } finally {
767             fin.close();
768         }
769         if (!result)
770             logger.finer("Overwriting a file which has an open FileInputStream is not tolerated!");
771
772         final String JavaDoc[] modes = { "r", "rw", "rws", "rwd" };
773         for (int i = 0, l = modes.length; i < l; i++) {
774             final String JavaDoc mode = modes[i];
775             final RandomAccessFile JavaDoc raf = new RandomAccessFile JavaDoc(file, mode);
776             try {
777                 result = File.isWritableOrCreatable(file);
778                 total &= result;
779             } finally {
780                 raf.close();
781             }
782             if (!result)
783                 logger.finer("Overwriting a file which has an open RandomAccessFile in \"" + mode + "\" mode is not tolerated!");
784         }
785         
786         if (!total)
787             logger.finer(
788                     "Applications should ALWAYS close their streams or you may face strange 'errors'.\n"
789                     + "Note that this issue is NOT AT ALL specific to TrueZIP, but rather imposed by this platform!");
790         
791         assertTrue(file.delete());
792     }
793
794     public void testFalsePositives() throws IOException JavaDoc {
795         logger.fine("testFalsePositives");
796
797         testFalsePositive(archive);
798         
799         // Dito for entry.
800
final File entry = new File(archive, "entry" + suffix);
801         
802         assertTrue(archive.mkdir());
803         testFalsePositive(entry);
804         assertTrue(archive.delete());
805         
806         assertTrue(getNonArchiveFile(archive).mkdir());
807         testFalsePositive(entry);
808         assertTrue(archive.delete());
809     }
810     
811     void testFalsePositive(File file) throws IOException JavaDoc {
812         assert file.isArchive();
813         
814         // Note that file's parent directory may be a false positive directory!
815

816         // Create false positive file.
817

818         OutputStream JavaDoc os = new FileOutputStream(file);
819         try {
820             os.write(data);
821         } finally {
822             os.close();
823         }
824         
825         assertTrue(file.exists());
826         assertFalse(file.isDirectory());
827         assertTrue(file.isFile());
828         assertEquals(data.length, file.length());
829         assertTrue(0 != file.lastModified());
830         
831         testDelete(file);
832         
833         // Create false positive directory.
834

835         assertTrue(getNonArchiveFile(file).mkdir());
836         assertTrue(file.exists());
837         assertTrue(file.isDirectory());
838         assertFalse(file.isFile());
839         //assertEquals(0, file.length());
840
assertTrue(0 != file.lastModified());
841         
842         testDelete(file);
843         
844         // Create regular ZIP file.
845

846         assertTrue(file.mkdir());
847         assertTrue(getNonArchiveFile(file).isFile());
848         assertTrue(file.exists());
849         assertTrue(file.isDirectory());
850         assertFalse(file.isFile());
851         //assertEquals(0, file.length());
852
assertTrue(0 != file.lastModified());
853         
854         testDelete(file);
855     }
856     
857     void testDelete(File file) throws IOException JavaDoc {
858         assertTrue(file.delete());
859         assertFalse(file.exists());
860         assertFalse(file.isDirectory());
861         assertFalse(file.isFile());
862         assertEquals(0, file.length());
863         assertFalse(0 != file.lastModified());
864     }
865     
866     public void testCreateNewFile()
867     throws IOException JavaDoc{
868         logger.fine("testCreateNewFile");
869
870         createNewPlainFile();
871         createNewSmartFile();
872     }
873     
874     void createNewPlainFile()
875     throws IOException JavaDoc {
876         final java.io.File JavaDoc zip = createTempFile(prefix, suffix);
877         assertTrue(zip.delete());
878         final java.io.File JavaDoc file1 = new java.io.File JavaDoc(zip, "test.txt");
879         final java.io.File JavaDoc file2 = new java.io.File JavaDoc(file1, "test.txt");
880         try {
881             file1.createNewFile();
882             fail("Creating a file in a non-existent directory should throw an IOException!");
883         } catch (IOException JavaDoc ok) {
884             // This is exactly what we expect here!
885
}
886         testCreateNewFile(zip, file1, file2);
887     }
888     
889     void createNewSmartFile()
890     throws IOException JavaDoc {
891         final java.io.File JavaDoc file1 = new File(archive, "test.txt");
892         final java.io.File JavaDoc file2 = new File(file1, "test.txt");
893         
894         File.setLenient(false);
895         try {
896             file1.createNewFile();
897             fail("Creating a file in a non-existent directory should throw an IOException!");
898         } catch (IOException JavaDoc ok) {
899             // This is exactly what we expect here!
900
}
901         testCreateNewFile(archive, file1, file2);
902         
903         File.setLenient(true);
904         testCreateNewFile(archive, file1, file2);
905     }
906     
907     void testCreateNewFile(
908             final java.io.File JavaDoc dir,
909             final java.io.File JavaDoc file1,
910             final java.io.File JavaDoc file2)
911             throws IOException JavaDoc {
912         assertFalse(dir.exists());
913         
914         assertTrue(dir.mkdir());
915         assertTrue(dir.exists());
916         assertTrue(dir.isDirectory());
917         assertFalse(dir.isFile());
918         assertEquals(0, file1.length());
919         
920         assertTrue(file1.createNewFile());
921         assertTrue(file1.exists());
922         assertFalse(file1.isDirectory());
923         assertTrue(file1.isFile());
924         assertEquals(0, file1.length());
925         
926         try {
927             file2.createNewFile();
928             fail("Creating a file in another file should throw an IOException!");
929         } catch (IOException JavaDoc ok) {
930             // This is exactly what we expect here!
931
}
932         
933         assertTrue(file1.delete()); // OK now!
934
assertFalse(file1.exists());
935         assertFalse(file1.isDirectory());
936         assertFalse(file1.isFile());
937         assertEquals(0, file1.length());
938         
939         assertTrue(dir.delete());
940         assertFalse(dir.exists());
941         assertFalse(dir.isDirectory());
942         assertFalse(dir.isFile());
943         assertEquals(0, dir.length());
944     }
945     
946     public void testFileOutputStream2Directory()
947     throws IOException JavaDoc {
948         logger.fine("testFileOutputStream2Directory");
949
950         final File dir = new File(createTempFile(prefix, ".dir"));
951         assertTrue(dir.delete());
952         assertTrue(dir.mkdir());
953         try {
954             new FileOutputStream(dir).close();
955             fail("Writing to a directory should not be possible!");
956         } catch (FileNotFoundException JavaDoc ok) {
957             // This is exactly what we expect here!
958
}
959         assertTrue(dir.delete());
960         
961         // Repeated writing to a file which looks like a ZIP file,
962
// but actually isn't, must be possible.
963
final OutputStream JavaDoc out = new FileOutputStream(archive);
964         out.write(data);
965         out.close();
966         new FileOutputStream(archive).close();
967         assertTrue(archive.delete());
968         
969         // Now we really create this as a ZIP file and so subsequent writing to
970
// it must fail.
971
assertTrue(archive.mkdir());
972         try {
973             new FileOutputStream(archive).close();
974             fail("Writing to files with a ZIP file suffix should not be possible!");
975         } catch (FileNotFoundException JavaDoc ok) {
976             // This is exactly what we expect here!
977
}
978         //assertTrue(zip.delete());
979

980         final File zipDir = new File(archive, "test");
981         assertTrue(zipDir.mkdirs());
982         try {
983             new FileOutputStream(zipDir).close();
984             fail("Writing to a directory within a ZIP file should not be possible!");
985         } catch (FileNotFoundException JavaDoc ok) {
986             // This is exactly what we expect here!
987

988         }
989         assertTrue(zipDir.delete());
990         
991         final File zipZip = new File(archive, "inner" + suffix);
992         final File zipZipDir = new File(zipZip, "test");
993         assertTrue(zipZipDir.mkdirs());
994         try {
995             new FileOutputStream(zipZipDir).close();
996             fail("Writing to a directory within a ZIP file should not be possible!");
997         } catch (FileNotFoundException JavaDoc ok) {
998             // This is exactly what we expect here!
999
}
1000        assertTrue(zipZipDir.delete());
1001        assertTrue(zipZip.delete());
1002    }
1003    
1004    public void testStrictFileOutputStream()
1005    throws IOException JavaDoc {
1006        logger.fine("testStrictFileOutputStream");
1007
1008        File file = new File(archive, "test.txt");
1009        
1010        File.setLenient(false);
1011        try {
1012            testFileOutputStream(file);
1013            fail("Creating missing parent ZIP directories should be impossible when File.isLenient() is not set!");
1014        } catch (IOException JavaDoc ok) {
1015            // This is exactly what we expect here!
1016
}
1017        
1018        assertTrue(archive.mkdir());
1019        testFileOutputStream(file);
1020        assertTrue(archive.delete());
1021    }
1022    
1023    public void testLenientFileOutputStream()
1024    throws IOException JavaDoc {
1025        logger.fine("testLenientFileOutputStream");
1026
1027        File file = new File(archive, "dir/inner" + suffix + "/dir/test.txt");
1028        
1029        testFileOutputStream(file);
1030        
1031        assertFalse(archive.delete()); // directory not empty!
1032
File.umount(); // allow external modifications!
1033
assertTrue(new java.io.File JavaDoc(archive.getPath()).delete()); // use plain file to delete instead!
1034
assertFalse(archive.exists());
1035        assertFalse(archive.isDirectory());
1036        assertFalse(archive.isFile());
1037        assertEquals(0, archive.length());
1038    }
1039    
1040    void testFileOutputStream(File file)
1041    throws IOException JavaDoc {
1042        final byte[] message = "Hello World!\r\n".getBytes();
1043        
1044        final FileOutputStream fos = new FileOutputStream(file);
1045        assertTrue(file.exists());
1046        assertFalse(file.isDirectory());
1047        assertTrue(file.isFile());
1048        assertEquals(0, file.length());
1049        fos.write(message);
1050        assertEquals(0, file.length());
1051        fos.flush();
1052        assertEquals(0, file.length());
1053        fos.close();
1054        assertTrue(file.exists());
1055        assertFalse(file.isDirectory());
1056        assertTrue(file.isFile());
1057        assertEquals(message.length, file.length());
1058        
1059        assertFalse(file.createNewFile());
1060        
1061        assertTrue(file.delete());
1062        assertFalse(file.exists());
1063        assertFalse(file.isDirectory());
1064        assertFalse(file.isFile());
1065        assertEquals(0, file.length());
1066    }
1067    
1068    public void testBusyFileInputStream()
1069    throws IOException JavaDoc {
1070        logger.fine("testBusyFileInputStream");
1071
1072        File file1 = new File(archive, "file1");
1073        File file2 = new File(archive, "file2");
1074        
1075        // Test open output streams.
1076
assertTrue(file1.createNewFile());
1077        File.update(); // ensure file1 is really present in the ZIP file
1078
assertTrue(file2.createNewFile());
1079        FileInputStream fisA = new FileInputStream(file1);
1080        try {
1081            FileInputStream fisB = new FileInputStream(file2);
1082            fail("Accessing file2 was expected to fail because an auto update needs to be done but the ZIP file is busy on input for fis1!");
1083        } catch (FileBusyException expected) {
1084        }
1085        assertFalse(file2.catFrom(fisA)); // fails for same reason.
1086

1087        // fis1 is still open!
1088
try {
1089            File.update(); // forces closing of fis1
1090
fail("ArchiveWarningException expected!");
1091        } catch (ArchiveBusyWarningException expected) {
1092            // Warning about fis1 still being used.
1093
}
1094        assertTrue(file2.isFile());
1095        if (!file2.catFrom(fisA)) // fis1 may be invalidated after update!
1096
assertFalse(file2.exists()); // previous op has removed file2!
1097

1098        // Open file2 as stream and let the garbage collection close the stream automatically.
1099
FileInputStream fisB = new FileInputStream(file1);
1100        //fis2.close();
1101
fisB = null;
1102        System.gc();
1103        try {
1104            Thread.sleep(100);
1105        } catch (InterruptedException JavaDoc ignored) {
1106        }
1107        
1108        // This update should complete without any exception if the garbage
1109
// collector did his job.
1110
try {
1111            File.umount(); // allow external modifications!
1112
} catch (ArchiveBusyWarningException failure) {
1113            fail("The garbage collector hasn't been collecting an open stream. If this is only happening occasionally, you can safely ignore it.");
1114        }
1115        
1116        assertTrue(getNonArchiveFile(archive).delete());
1117        // Closing the invalidated stream explicitly should be OK.
1118
fisA.close();
1119        
1120        // Cleanup.
1121
assertFalse(file2.delete()); // already deleted externally
1122
assertFalse(file2.exists());
1123        assertFalse(file1.delete());
1124        assertFalse(file1.exists());
1125    }
1126    
1127    public void testBusyFileOutputStream()
1128    throws IOException JavaDoc {
1129        logger.fine("testBusyFileOutputStream");
1130
1131        File file1 = new File(archive, "file1");
1132        File file2 = new File(archive, "file2");
1133        
1134        // Ensure that there are two entries in the archive.
1135
// This is used later to check whether the update operation knows
1136
// how to deal with updating an archive for which there is still
1137
// an open output stream.
1138
FileOutputStream fosA = new FileOutputStream(file1);
1139        File.cat(new ByteArrayInputStream JavaDoc(data), fosA);
1140        fosA.close();
1141        
1142        fosA = new FileOutputStream(file2);
1143        File.cat(new ByteArrayInputStream JavaDoc(data), fosA);
1144        fosA.close();
1145        
1146        File.update(); // ensure two entries in the archive
1147

1148        fosA = new FileOutputStream(file1);
1149        File.cat(new ByteArrayInputStream JavaDoc(data), fosA);
1150        
1151        // fosA is still open!
1152
try {
1153            FileOutputStream fosB = new FileOutputStream(file1);
1154        } catch (FileBusyException busy) {
1155            // This is actually an implementation detail which may change in
1156
// a future version.
1157
assertTrue(busy.getCause() instanceof ArchiveBusyException);
1158        }
1159        
1160        // fosA is still open!
1161
try {
1162            FileOutputStream fosB = new FileOutputStream(file2);
1163            logger.fine("This archive driver DOES support concurrent writing of different entries in the same archive file.");
1164        } catch (FileBusyException busy) {
1165            //assertTrue(busy.getCause() instanceof OutputArchiveBusyException);
1166
logger.fine("This archive driver does NOT support concurrent writing of different entries in the same archive file.");
1167        }
1168        
1169        // fosA is still open!
1170
File.cat(new ByteArrayInputStream JavaDoc(data), fosA); // write again
1171

1172        try {
1173            File.update(); // forces closing of all streams
1174
fail("Output stream should have been forced to close!");
1175        } catch (ArchiveBusyWarningException expected) {
1176        }
1177        
1178        try {
1179            File.cat(new ByteArrayInputStream JavaDoc(data), fosA); // write again
1180
fail("Output stream should have been forcibly closed!");
1181        } catch (IOException JavaDoc expected) {
1182        }
1183        
1184        // The stream has been forcibly closed by File.update().
1185
// Another close is OK, though!
1186
fosA.close();
1187        
1188        // Reopen stream and let the garbage collection close the stream automatically.
1189
fosA = new FileOutputStream(file1);
1190        fosA = null;
1191        System.gc();
1192        try {
1193            Thread.sleep(100);
1194        } catch (InterruptedException JavaDoc ignored) {
1195        }
1196        
1197        // This update should complete without any exception if the garbage
1198
// collector did his job.
1199
try {
1200            File.update();
1201        } catch (ArchiveBusyWarningException failure) {
1202            fail("The garbage collector hasn't been collecting an open stream. If this is only happening occasionally, you can safely ignore it.");
1203        }
1204        
1205        // Cleanup.
1206
assertTrue(file2.delete());
1207        assertFalse(file2.exists());
1208        assertTrue(file1.delete());
1209        assertFalse(file1.exists());
1210    }
1211    
1212    public void testMkdir()
1213    throws IOException JavaDoc {
1214        logger.fine("testMkdir");
1215
1216        final File dir1 = archive;
1217        final File dir2 = new File(dir1, "dir");
1218        final File dir3 = new File(dir2, "inner" + suffix);
1219        final File dir4 = new File(dir3, "dir");
1220        final File dir5 = new File(dir4, "nuts" + suffix);
1221        final File dir6 = new File(dir5, "dir");
1222        
1223        File.setLenient(true);
1224        
1225        assertTrue(dir6.mkdir()); // create all at once! note zip is in current directory!
1226

1227        assertFalse(dir6.mkdir()); // exists already!
1228
assertFalse(dir5.mkdir()); // exists already!
1229
assertFalse(dir4.mkdir()); // exists already!
1230
assertFalse(dir3.mkdir()); // exists already!
1231
assertFalse(dir2.mkdir()); // exists already!
1232
assertFalse(dir1.mkdir()); // exists already!
1233

1234        assertTrue(dir6.delete());
1235        assertTrue(dir5.delete());
1236        assertTrue(dir4.delete());
1237        assertTrue(dir3.delete());
1238        assertTrue(dir2.delete());
1239        assertTrue(dir1.delete());
1240        
1241        File.setLenient(false);
1242        
1243        assertFalse(dir6.mkdir());
1244        assertFalse(dir5.mkdir());
1245        assertFalse(dir4.mkdir());
1246        assertFalse(dir3.mkdir());
1247        assertFalse(dir2.mkdir());
1248        
1249        assertTrue(dir1.mkdir());
1250        assertTrue(dir2.mkdir());
1251        assertTrue(dir3.mkdir());
1252        assertTrue(dir4.mkdir());
1253        assertTrue(dir5.mkdir());
1254        assertTrue(dir6.mkdir());
1255        
1256        assertTrue(dir6.delete());
1257        assertTrue(dir5.delete());
1258        assertTrue(dir4.delete());
1259        assertTrue(dir3.delete());
1260        assertTrue(dir2.delete());
1261        assertTrue(dir1.delete());
1262    }
1263    
1264    public void testDirectoryTree()
1265    throws IOException JavaDoc {
1266        logger.fine("testDirectoryTree");
1267
1268        testDirectoryTree(
1269                new File("."), // base directory
1270
new File("dir/inner" + suffix + "/dir/outer" + suffix + "/" + archive.getName())); // this path is reversed!!!
1271
}
1272    
1273    void testDirectoryTree(File basePath, File reversePath)
1274    throws IOException JavaDoc {
1275        if (reversePath == null) {
1276            // We're at the leaf of the directory tree.
1277
final File test = new File(basePath, "test.txt");
1278            //testCreateNewFile(basePath, test);
1279
testFileOutputStream(test);
1280            return;
1281        }
1282        assertFalse(".".equals(reversePath.getPath()));
1283        assertFalse("..".equals(reversePath.getPath()));
1284        
1285        final File member = new File(basePath, reversePath.getName());
1286        final boolean created = member.mkdir();
1287        final File children = (File) reversePath.getParentFile();
1288        testDirectoryTree(member, children);
1289        testListFiles(basePath, member.getName());
1290        assertTrue(member.exists());
1291        assertTrue(member.isDirectory());
1292        assertFalse(member.isFile());
1293        if (member.isArchive())
1294            assertEquals(0, member.length());
1295        if (created) {
1296            assertTrue(member.delete());
1297            assertFalse(member.exists());
1298            assertFalse(member.isDirectory());
1299            assertFalse(member.isFile());
1300            assertEquals(0, member.length());
1301        }
1302    }
1303    
1304    void testListFiles(File dir, String JavaDoc entry) {
1305        java.io.File JavaDoc[] files = dir.listFiles();
1306        //assertTrue(files instanceof File[]); // not true
1307
boolean found = false;
1308        for (int i = 0, l = files.length; i < l; i++) {
1309            File file = (File) files[i];
1310            assertTrue(file instanceof File);
1311            if (file.getName().equals(entry))
1312                found = true;
1313        }
1314        if (!found)
1315            fail("No such entry: " + entry);
1316    }
1317    
1318    public void testCat()
1319    throws IOException JavaDoc {
1320        logger.fine("testCat");
1321
1322        try {
1323            testCat(archive);
1324            fail("Writing to files with a ZIP file suffix should not be possible!");
1325        } catch (AssertionFailedError ok) {
1326            // This is exactly what we expect here!
1327
}
1328        
1329        final File zipTest = new File(archive, "test");
1330        testCat(zipTest);
1331        
1332        final File zipZip = new File(archive, "inner" + suffix);
1333        final File zipZipTest = new File(zipZip, "test");
1334        testCat(zipZipTest);
1335        assertTrue(zipZip.delete());
1336        assertTrue(archive.delete());
1337    }
1338    
1339    void testCat(final File file)
1340    throws IOException JavaDoc {
1341        testCatFrom(file);
1342        testCatTo(file);
1343        assertTrue(file.delete());
1344    }
1345    
1346    void testCatFrom(final File file)
1347    throws IOException JavaDoc {
1348        final InputStream JavaDoc in = new ByteArrayInputStream JavaDoc(data);
1349        try {
1350            assertTrue(file.catFrom(in));
1351        } finally {
1352            in.close();
1353        }
1354    }
1355    
1356    void testCatTo(final File file)
1357    throws IOException JavaDoc {
1358        final ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc(data.length);
1359        try {
1360            assertTrue(file.catTo(out));
1361        } finally {
1362            out.close();
1363        }
1364        assertTrue(Arrays.equals(data, out.toByteArray()));
1365    }
1366
1367    public void testCopyContainingOrSameFiles() throws IOException JavaDoc {
1368        logger.fine("testCopyContainingOrSameFiles");
1369
1370        assert !archive.exists();
1371
1372        final File dir = (File) archive.getParentFile();
1373        assertNotNull(dir);
1374        final File entry = new File(archive, "entry");
1375
1376        testCopyContainingOrSameFiles1(dir, archive);
1377        testCopyContainingOrSameFiles1(archive, entry);
1378
1379        assertTrue(entry.catFrom(new ByteArrayInputStream JavaDoc(data)));
1380
1381        testCopyContainingOrSameFiles1(dir, archive);
1382        testCopyContainingOrSameFiles1(archive, entry);
1383        
1384        assertTrue(archive.deleteAll());
1385    }
1386
1387    public void testCopyContainingOrSameFiles1(
1388            final File a,
1389            final File b)
1390    throws IOException JavaDoc {
1391        testCopyContainingOrSameFiles2(a, b);
1392        testCopyContainingOrSameFiles2(a.getCanOrAbsFile(), b);
1393        testCopyContainingOrSameFiles2(a, b.getCanOrAbsFile());
1394        testCopyContainingOrSameFiles2(a.getCanOrAbsFile(), b.getCanOrAbsFile());
1395    }
1396
1397    public void testCopyContainingOrSameFiles2(
1398            final File a,
1399            final File b)
1400    throws IOException JavaDoc {
1401        try {
1402            File.cp(a, a);
1403            fail("Expected SameFileException");
1404        } catch (ContainsFileException sfe) {
1405        }
1406        try {
1407            File.cp(a, b);
1408            fail("Expected FileNotFoundException");
1409        } catch (FileNotFoundException JavaDoc fnfe) {
1410        }
1411        try {
1412            File.cp(b, a);
1413            fail("Expected FileNotFoundException");
1414        } catch (FileNotFoundException JavaDoc fnfe) {
1415        }
1416        try {
1417            File.cp(b, b);
1418            fail("Expected SameFileException");
1419        } catch (ContainsFileException sfe) {
1420        }
1421    }
1422
1423    public void testCopy()
1424    throws IOException JavaDoc {
1425        logger.fine("testCopy");
1426
1427        final File archive1 = archive;
1428        final File archive2 = new File(archive1, "inner" + suffix);
1429        final File archive3 = new File(archive2, "nuts" + suffix);
1430
1431        testCopy(archive1, archive2, archive3, "a", "b");
1432    }
1433
1434    public void testCopyFalsePositives()
1435    throws IOException JavaDoc {
1436        logger.fine("testCopyFalsePositives");
1437
1438        final File archive0 = archive;
1439        final File archive1 = new File(archive0, "inner" + suffix);
1440        final File archive2 = new File(archive1, "nuts" + suffix);
1441
1442        final File archives[][] = {
1443            {
1444                getNonArchiveFile(archive0),
1445                getNonArchiveFile(archive1),
1446                getNonArchiveFile(archive2),
1447            }, {
1448                getNonArchiveFile(archive0),
1449                getNonArchiveFile(archive1),
1450                archive2,
1451            }, {
1452                getNonArchiveFile(archive0),
1453                archive1,
1454                getNonArchiveFile(archive2),
1455            }, {
1456                getNonArchiveFile(archive0),
1457                archive1,
1458                archive2,
1459            }, {
1460                archive0,
1461                getNonArchiveFile(archive1),
1462                getNonArchiveFile(archive2),
1463            }, {
1464                archive0,
1465                getNonArchiveFile(archive1),
1466                archive2,
1467            }, {
1468                archive0,
1469                archive1,
1470                getNonArchiveFile(archive2),
1471            }
1472        };
1473
1474        for (int i = 0; i < archives.length; i++) {
1475            assertTrue(archives[i][0].mkdir());
1476            assertTrue(archives[i][1].mkdir());
1477            assertTrue(archives[i][2].mkdir());
1478
1479            testCopy(archive0, archive1, archive2, "a" + suffix, "b" + suffix);
1480            
1481            File.umount(); // clean to avoid side effects when reconfiguring archive detection
1482
}
1483    }
1484
1485    private static final File getNonArchiveFile(File file) {
1486        return ArchiveDetector.NULL.createFile(
1487                file.getParentFile(), file.getName());
1488    }
1489
1490    public void testCopy(
1491            final File archive0,
1492            final File archive1,
1493            final File archive2,
1494            final String JavaDoc entryA,
1495            final String JavaDoc entryB)
1496    throws IOException JavaDoc {
1497        final File zip0a = new File(archive0, entryA);
1498        final File zip0b = new File(archive0, entryB);
1499        final File zip1a = new File(archive1, entryA);
1500        final File zip1b = new File(archive1, entryB);
1501        final File zip2a = new File(archive2, entryA);
1502        final File zip2b = new File(archive2, entryB);
1503        
1504        for (int i = 2; i >= 1; i--) {
1505            testCopy(zip0a, zip0b);
1506            testCopy(zip0a, zip1a);
1507            testCopy(zip0a, zip1b);
1508            testCopy(zip0a, zip2a);
1509            testCopy(zip0a, zip2b);
1510            
1511            testCopy(zip0b, zip0a);
1512            testCopy(zip0b, zip1a);
1513            testCopy(zip0b, zip1b);
1514            testCopy(zip0b, zip2a);
1515            testCopy(zip0b, zip2b);
1516            
1517            testCopy(zip1a, zip0a);
1518            testCopy(zip1a, zip0b);
1519            testCopy(zip1a, zip1b);
1520            testCopy(zip1a, zip2a);
1521            testCopy(zip1a, zip2b);
1522            
1523            testCopy(zip1b, zip0a);
1524            testCopy(zip1b, zip0b);
1525            testCopy(zip1b, zip1a);
1526            testCopy(zip1b, zip2a);
1527            testCopy(zip1b, zip2b);
1528            
1529            testCopy(zip2a, zip0a);
1530            testCopy(zip2a, zip0b);
1531            testCopy(zip2a, zip1a);
1532            testCopy(zip2a, zip1b);
1533            testCopy(zip2a, zip2b);
1534            
1535            testCopy(zip2b, zip0a);
1536            testCopy(zip2b, zip0b);
1537            testCopy(zip2b, zip1a);
1538            testCopy(zip2b, zip1b);
1539            testCopy(zip2b, zip2a);
1540        }
1541        
1542        assertTrue(archive2.delete());
1543        assertTrue(archive1.delete());
1544        assertTrue(archive0.delete());
1545    }
1546    
1547    final void testCopy(File a, File b)
1548    throws IOException JavaDoc {
1549        testCopy(a, b, 2000); // works in ZIP and all other archive types currently supported
1550
}
1551    
1552    void testCopy(final File a, final File b, final long granularity)
1553    throws IOException JavaDoc {
1554        // Create a with old timestamp.
1555
{
1556            final OutputStream JavaDoc out = new FileOutputStream(a);
1557            try {
1558                out.write(data);
1559            } finally {
1560                out.close();
1561            }
1562            a.setLastModified(System.currentTimeMillis() - granularity);
1563        }
1564
1565        // Test copyFrom.
1566
assertTrue(b.copyFrom(a));
1567        assertEquals(a.length(), b.length());
1568        assertTrue(a.lastModified() != b.lastModified());
1569        assertTrue(b.archiveCopyFrom(a));
1570        assertEquals(a.length(), b.length());
1571        assertEquals(
1572                (a.lastModified() / granularity) * granularity,
1573                (b.lastModified() / granularity) * granularity);
1574        
1575        // Test copyTo.
1576
assertTrue(b.copyTo(a)); // updates timestamp
1577
assertEquals(a.length(), b.length());
1578        assertTrue(a.lastModified() != b.lastModified());
1579        assertTrue(b.archiveCopyTo(a));
1580        assertEquals(a.length(), b.length());
1581        assertEquals(
1582                (a.lastModified() / granularity) * granularity,
1583                (b.lastModified() / granularity) * granularity);
1584        
1585        // Check result.
1586
{
1587            final ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc(data.length);
1588            assertTrue(a.copyTo(out));
1589            assertTrue(Arrays.equals(data, out.toByteArray()));
1590        }
1591        
1592        // Cleanup.
1593
assertTrue(a.delete());
1594        assertTrue(b.delete());
1595    }
1596
1597    public void testListPerformance()
1598    throws IOException JavaDoc {
1599        logger.fine("testListPerformance");
1600
1601        assertTrue(archive.mkdir());
1602
1603        int i, j;
1604        long time;
1605
1606        time = System.currentTimeMillis();
1607        for (i = 0; i < 100; i++) {
1608            File file = new File(archive, "" + i);
1609            assertTrue(file.createNewFile());
1610        }
1611        time = System.currentTimeMillis() - time;
1612        logger.finer("Time required to create " + i + " zip file entries: " + time + "ms");
1613
1614        time = System.currentTimeMillis();
1615        for (j = 0; j < 100; j++) {
1616            archive.listFiles((FilenameFilter JavaDoc) null);
1617        }
1618        time = System.currentTimeMillis() - time;
1619        logger.finer("Time required to list these entries " + j + " times using a nullary FilenameFilter: " + time + "ms");
1620
1621        time = System.currentTimeMillis();
1622        for (j = 0; j < 100; j++) {
1623            archive.listFiles((FileFilter JavaDoc) null);
1624        }
1625        time = System.currentTimeMillis() - time;
1626        logger.finer("Time required to list these entries " + j + " times using a nullary FileFilter: " + time + "ms");
1627
1628        assertFalse(archive.delete()); // directory not empty!
1629
File.umount(); // allow external modifications!
1630
assertTrue(new java.io.File JavaDoc(archive.getPath()).delete()); // use plain file to delete instead!
1631
assertFalse(archive.exists());
1632        assertFalse(archive.isDirectory());
1633        assertFalse(archive.isFile());
1634        assertEquals(0, archive.length());
1635    }
1636
1637    // This test needs to be redesigned: It primarily lacks a clear intention.
1638
/*public void testGarbageCollection()
1639    throws Throwable {
1640        logger.fine("testGarbageCollection");
1641
1642        // Preamble:
1643        {
1644            Object obj = new Object();
1645            Reference ref = new WeakReference(obj);
1646            obj = null;
1647            System.gc(); // Assumption doesn't work without this!
1648            //System.runFinalization(); // doesn't work!
1649            assert ref.get() == null;
1650        }
1651        
1652        // Test:
1653        try {
1654            File file = new File(archive);
1655            for (int i = 0; i < 100; i++) {
1656                file = new File(file, i + suffix);
1657                assertTrue(file.mkdir());
1658            }
1659        } catch (Throwable failure) {
1660            // This could be an OOME with CBZip2OutputStream from Ant 1.7.0RC1!
1661            File.umount(); // exceptions thrown here take precedence!
1662            throw failure;
1663        }
1664        // Note that though the file chain is now eligible for garbage
1665        // collection, the associated archive controllers are not since they
1666        // have dirty file systems.
1667        
1668        // Now set the system under stress so that the garbage collector will
1669        // most likely reclaim the chain of file objects and the archive
1670        // controllers once they have been updated.
1671        // Note that ArchiveController.finalize() is called in no particular
1672        // order, i.e. the object graph is completely ignored! :-o
1673        byte[] buf1 = new byte[10 * 1024 * 1024];
1674        System.gc();
1675        byte[] buf2 = new byte[10 * 1024 * 1024];
1676        File.umount(); // allow external modifications!
1677        byte[] buf3 = new byte[10 * 1024 * 1024];
1678        System.gc();
1679        byte[] buf4 = new byte[10 * 1024 * 1024];
1680        
1681        assertTrue(archive.deleteAll());
1682    }*/

1683
1684    public void testIllegalDeleteEntryWithOpenStream() throws IOException JavaDoc {
1685        logger.fine("testIllegalDeleteEntryWithOpenStream");
1686
1687        final File entry1 = new File(archive, "entry1");
1688        final File entry2 = new File(archive, "entry2");
1689
1690        final OutputStream JavaDoc out1 = new FileOutputStream(entry1);
1691        try {
1692            assertFalse(entry1.delete());
1693            out1.write(data);
1694            assertFalse(archive.deleteAll());
1695        } finally {
1696            out1.close();
1697        }
1698
1699        final OutputStream JavaDoc out2 = new FileOutputStream(entry2);
1700        try {
1701            assertFalse(entry2.delete());
1702            out2.write(data);
1703            assertFalse(archive.deleteAll());
1704        } finally {
1705            out2.close();
1706        }
1707
1708        final InputStream JavaDoc in1 = new FileInputStream(entry1); // does an auto update!
1709
try {
1710            final InputStream JavaDoc in2 = new FileInputStream(entry2);
1711            try {
1712                assertTrue(entry2.delete());
1713                final ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc(data.length);
1714                try {
1715                    File.cat(in2, out);
1716                } finally {
1717                    out.close();
1718                }
1719                assertTrue(Arrays.equals(data, out.toByteArray()));
1720                assertFalse(archive.deleteAll());
1721            } finally {
1722                in2.close();
1723            }
1724            
1725            assertFalse(entry1.delete()); // deleted within archive.deleteAll()!
1726
final ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc(data.length);
1727            try {
1728                File.cat(in1, out);
1729            } finally {
1730                out.close();
1731            }
1732            assertTrue(Arrays.equals(data, out.toByteArray()));
1733            assertFalse(archive.deleteAll());
1734        } finally {
1735            in1.close();
1736        }
1737
1738        assertTrue(archive.deleteAll());
1739        assertFalse(getPlainFile(archive).exists());
1740    }
1741
1742    public void testRenameValidArchive()
1743    throws IOException JavaDoc {
1744        logger.fine("testRenameValidArchive");
1745
1746        // Create a regular archive with a single archive entry which
1747
// contains a creative greeting message.
1748
final OutputStream JavaDoc out = new FileOutputStream(new File(archive, "entry"));
1749        try {
1750            new PrintStream JavaDoc(out, true).println("Hello World!");
1751        } finally {
1752            out.close(); // ALWAYS close streams!
1753
}
1754
1755        testRenameArchiveToTemp(archive);
1756    }
1757
1758    public void testRenameFalsePositive()
1759    throws IOException JavaDoc {
1760        logger.fine("testRenameFalsePositive");
1761
1762        // Create false positive archive.
1763
// Note that archive is a File instance which returns isArchive()
1764
// == true, so we must create a new File instance which is guaranteed
1765
// to ignore the archive suffix in the path.
1766
// Furthermore, data is an array containing random data
1767
// - not a regular archive.
1768
// So upon completion of this step, the object "archive" refers to a
1769
// false positive.
1770
final File tmp = new File(archive.getPath(), ArchiveDetector.NULL);
1771        final InputStream JavaDoc in = new ByteArrayInputStream JavaDoc(data);
1772        try {
1773            assertTrue(tmp.copyFrom(in));
1774        } finally {
1775            in.close(); // ALWAYS close streams!
1776
}
1777
1778        testRenameArchiveToTemp(archive);
1779    }
1780
1781    public void testRenameArchiveToTemp(final File archive)
1782    throws IOException JavaDoc {
1783        assert archive.isArchive(); // regular archive or false positive
1784
assert !archive.isEntry(); // not enclosed in another archive
1785

1786        // Create a temporary path.
1787
File tmp = new File(createTempFile(prefix, null));
1788        assertTrue(tmp.delete());
1789        assertFalse(tmp.exists());
1790        assertFalse(getPlainFile(tmp).exists());
1791
1792        // Now rename the archive to the temporary path.
1793
// Depending on the true state of the object "archive", this will
1794
// either create a directory (iff archive is a regular archive) or a
1795
// plain file (iff archive is false positive).
1796
assertTrue(archive.renameTo(tmp));
1797        assertFalse(archive.exists());
1798        assertFalse(getPlainFile(archive).exists());
1799
1800        // Now delete resulting temporary file.
1801
assertTrue(tmp.deleteAll());
1802        assertFalse(tmp.exists());
1803        assertFalse(getPlainFile(tmp).exists());
1804    }
1805
1806    public void testRenameRecursively()
1807    throws IOException JavaDoc {
1808        logger.fine("testRenameRecursively");
1809
1810        final File zap = new File(createTempFile(prefix, suffix));
1811        final File zip2 = new File(archive, "inner" + suffix);
1812        final File zip3 = new File(zip2, "nuts" + suffix);
1813        final File zip1a = new File(archive, "a");
1814        final File zip1b = new File(archive, "b");
1815        final File zip2a = new File(zip2, "a");
1816        final File zip2b = new File(zip2, "b");
1817        final File zip3a = new File(zip3, "a");
1818        final File zip3b = new File(zip3, "b");
1819        
1820        assertTrue(zap.delete());
1821        
1822        testCatFrom(zip1a);
1823        
1824        for (int i = 2; i >= 1; i--) {
1825            testRenameTo(zip1a, zip1b);
1826            testRenameTo(zip1b, zip2a);
1827            testRenameTo(zip2a, zip2b);
1828            testRenameTo(zip2b, zip3a);
1829            testRenameTo(zip3a, zip3b);
1830            testRenameTo(zip3b, zip3a);
1831            testRenameTo(zip3a, zip2b);
1832            testRenameTo(zip2b, zip2a);
1833            testRenameTo(zip2a, zip1b);
1834            testRenameTo(zip1b, zip1a);
1835        }
1836        
1837        testRenameTo(archive, zap);
1838        testRenameTo(zap, archive);
1839        assertTrue(zip3.delete());
1840        assertTrue(zip2.delete());
1841        testCatTo(zip1a);
1842        assertTrue(zip1a.delete());
1843        assertTrue(archive.delete());
1844    }
1845
1846    void testRenameTo(File src, File dst) {
1847        assertTrue(src.exists());
1848        if (!src.isEntry())
1849            assertTrue(getPlainFile(src).exists());
1850        assertFalse(dst.exists());
1851        if (!dst.isEntry())
1852            assertFalse(getPlainFile(dst).exists());
1853        assertTrue(src.renameTo(dst)); // !strict
1854
assertFalse(src.exists());
1855        if (!src.isEntry())
1856            assertFalse(getPlainFile(src).exists());
1857        assertTrue(dst.exists());
1858        if (!dst.isEntry())
1859            assertTrue(getPlainFile(dst).exists());
1860    }
1861
1862    private static java.io.File JavaDoc getPlainFile(final File file) {
1863        return new java.io.File JavaDoc(file.getPath());
1864    }
1865
1866    private static final String JavaDoc[] members = {
1867        "A directory member",
1868        "Another directory member",
1869        "Yet another directory member",
1870    };
1871    
1872    public void testListFiles() throws IOException JavaDoc {
1873        logger.fine("testListFiles");
1874
1875        java.io.File JavaDoc dir = createTempFile(prefix, suffix);
1876        File dir2 = new File(dir);
1877        
1878        assertTrue(dir.delete());
1879        assertTrue(dir.mkdir());
1880        
1881        for (int i = members.length; --i >= 0; ) {
1882            assertTrue(new java.io.File JavaDoc(dir, members[i]).createNewFile());
1883        }
1884        
1885        java.io.File JavaDoc[] files = dir.listFiles();
1886        java.io.File JavaDoc[] files2 = dir2.listFiles();
1887        
1888        assertEquals(files.length, files2.length);
1889        
1890        for (int i = 0, l = files.length; i < l; i++) {
1891            assertTrue(!(files[i] instanceof File));
1892            assertTrue(files2[i] instanceof File);
1893            assertEquals(files[i].getPath(), files2[i].getPath());
1894        }
1895        
1896        assertTrue(dir2.deleteAll());
1897    }
1898
1899    public void testMultithreadedSingleArchiveMultipleEntriesReading()
1900    throws Exception JavaDoc {
1901        logger.fine("testMultithreadedSingleArchiveMultipleEntriesReading");
1902
1903        testMultithreadedSingleArchiveMultipleEntriesReading(20, 20);
1904    }
1905    
1906    /**
1907     * Creates a test archive file with the given number of entries and then
1908     * creates the given number of threads where each of them reads all these
1909     * entries.
1910     *
1911     * @param nEntries The number of ZIP file entries to be created.
1912     * @param nThreads The number of threads to be created.
1913     */

1914    private void testMultithreadedSingleArchiveMultipleEntriesReading(final int nEntries, final int nThreads)
1915    throws Exception JavaDoc {
1916        // Create test archive file.
1917
createTestArchive(nEntries);
1918        
1919        // Define thread class to enumerate and read all entries.
1920
class CheckAllEntriesThread extends Thread JavaDoc {
1921            Throwable JavaDoc failure;
1922            
1923            public void run() {
1924                try {
1925                    checkArchiveEntries(archive, nEntries);
1926                } catch (Throwable JavaDoc t) {
1927                    failure = t;
1928                }
1929            }
1930        } // class CheckAllEntriesThread
1931

1932        // Create and start all threads.
1933
final CheckAllEntriesThread[] threads = new CheckAllEntriesThread[nThreads];
1934        for (int i = 0; i < nThreads; i++) {
1935            final CheckAllEntriesThread thread = new CheckAllEntriesThread();
1936            thread.start();
1937            threads[i] = thread;
1938        }
1939        
1940        // Wait for all threads until done.
1941
for (int i = 0; i < nThreads; i++) {
1942            final CheckAllEntriesThread thread = threads[i];
1943            thread.join();
1944            if (thread.failure != null)
1945                throw new Exception JavaDoc(thread.failure);
1946        }
1947        
1948        assertTrue(archive.deleteAll());
1949    }
1950    
1951    private void createTestArchive(final int nEntries) throws IOException JavaDoc {
1952        for (int i = 0; i < nEntries; i++) {
1953            final File entry = new File(archive + File.separator + i);
1954            final OutputStream JavaDoc out = new FileOutputStream(entry);
1955            try {
1956                out.write(data);
1957            } finally {
1958                out.close();
1959            }
1960        }
1961    }
1962    
1963    private void checkArchiveEntries(final File archive, int nEntries)
1964    throws IOException JavaDoc {
1965        final java.io.File JavaDoc[] entries = archive.listFiles();
1966        assertEquals(nEntries, entries.length);
1967        final byte[] buf = new byte[4096];
1968        for (int i = 0, l = entries.length; i < l; i++) {
1969            final File entry = (File) entries[i];
1970            // Read full entry and check the contents.
1971
final InputStream JavaDoc in = new FileInputStream(entry);
1972            try {
1973                int off = 0;
1974                int read;
1975                do {
1976                    read = in.read(buf);
1977                    if (read < 0)
1978                        break;
1979                    assertTrue(read > 0);
1980                    assertTrue(de.schlichtherle.util.Arrays.equals(
1981                            data, off, buf, 0, read));
1982                    off += read;
1983                } while (true);
1984                assertEquals(-1, read);
1985                assertEquals(off, data.length);
1986                assertEquals(0, in.read(new byte[0]));
1987            } finally {
1988                in.close();
1989            }
1990        }
1991    }
1992    
1993    public void testMultithreadedSingleArchiveMultipleEntriesWriting()
1994    throws Exception JavaDoc {
1995        logger.fine("testMultithreadedSingleArchiveMultipleEntriesWriting");
1996
1997        testMultithreadedSingleArchiveMultipleEntriesWriting(archive, 20, false);
1998        testMultithreadedSingleArchiveMultipleEntriesWriting(archive, 20, true);
1999    }
2000    
2001    private void testMultithreadedSingleArchiveMultipleEntriesWriting(
2002            final File archive,
2003            final int nThreads,
2004            final boolean wait)
2005            throws Exception JavaDoc {
2006        assertTrue(File.isLenient());
2007        
2008        class WritingThread extends Thread JavaDoc {
2009            final int i;
2010            Throwable JavaDoc failure;
2011            
2012            WritingThread(int i) {
2013                this.i = i;
2014            }
2015            
2016            public void run() {
2017                try {
2018                    final File file = new File(archive, i + "");
2019                    OutputStream JavaDoc out;
2020                    while (true) {
2021                        try {
2022                            out = new FileOutputStream(file);
2023                            break;
2024                        } catch (FileBusyException busy) {
2025                            continue;
2026                        }
2027                    }
2028                    try {
2029                        out.write(data);
2030                    } finally {
2031                        out.close();
2032                    }
2033                    try {
2034                        File.update(wait, false, wait, false);
2035                    } catch (ArchiveBusyException mayHappen) {
2036                        // Some other thread is busy updating an archive.
2037
// If we are waiting, then this could never happen.
2038
// Otherwise, silently ignore this exception and
2039
// accept that the archive may not have been
2040
// updated to disk.
2041
// Note that no data is lost, this exception just
2042
// signals that the corresponding archive hasn't
2043
// been updated - a future call may still succeed.
2044
if (wait)
2045                            throw new AssertionError JavaDoc(mayHappen);
2046                    }
2047                } catch (Throwable JavaDoc exception) {
2048                    failure = exception;
2049                }
2050            }
2051        } // class WritingThread
2052

2053        // Create and start all threads.
2054
final WritingThread[] threads = new WritingThread[nThreads];
2055        for (int i = 0; i < nThreads; i++) {
2056            final WritingThread thread = new WritingThread(i);
2057            thread.start();
2058            threads[i] = thread;
2059        }
2060        
2061        // Wait for all threads to finish.
2062
for (int i = 0; i < nThreads; i++) {
2063            final WritingThread thread = threads[i];
2064            thread.join();
2065            if (thread.failure != null)
2066                throw new Exception JavaDoc(thread.failure);
2067        }
2068        
2069        checkArchiveEntries(archive, nThreads);
2070        assertTrue(archive.deleteAll());
2071    }
2072    
2073    public void testMultithreadedMultipleArchivesSingleEntryWriting()
2074    throws Exception JavaDoc {
2075        logger.fine("testMultithreadedMultipleArchivesSingleEntryWriting");
2076
2077        testMultithreadedMultipleArchivesSingleEntryWriting(20, false);
2078        testMultithreadedMultipleArchivesSingleEntryWriting(20, true);
2079    }
2080    
2081    private void testMultithreadedMultipleArchivesSingleEntryWriting(
2082            final int nThreads, final boolean updateIndividually)
2083            throws Exception JavaDoc {
2084        assertTrue(File.isLenient());
2085        
2086        class WritingThread extends Thread JavaDoc {
2087            Throwable JavaDoc failure;
2088            
2089            public void run() {
2090                try {
2091                    final File archive = new File(createTempFile(prefix, suffix));
2092                    assertTrue(archive.delete());
2093                    final File file = new File(archive, "entry");
2094                    try {
2095                        final OutputStream JavaDoc out = new FileOutputStream(file);
2096                        try {
2097                            out.write(data);
2098                        } finally {
2099                            out.close();
2100                        }
2101                        try {
2102                            if (updateIndividually)
2103                                File.update(archive);
2104                            else
2105                                File.update(false);
2106                        } catch (ArchiveBusyException mayHappen) {
2107                            // Some other thread is busy updating an archive.
2108
// If we are updating individually, then this
2109
// could never happen.
2110
// Otherwise, silently ignore this exception and
2111
// accept that the archive may not have been
2112
// updated to disk.
2113
// Note that no data is lost, this exception just
2114
// signals that the corresponding archive hasn't
2115
// been updated - a future call may still succeed.
2116
if (updateIndividually)
2117                                throw new AssertionError JavaDoc(mayHappen);
2118                        }
2119                    } finally {
2120                        assertTrue(archive.deleteAll());
2121                    }
2122                } catch (Throwable JavaDoc exception) {
2123                    failure = exception;
2124                }
2125            }
2126        } // class WritingThread
2127

2128        // Create and start all threads.
2129
final WritingThread[] threads = new WritingThread[nThreads];
2130        for (int i = 0; i < nThreads; i++) {
2131            final WritingThread thread = new WritingThread();
2132            thread.start();
2133            threads[i] = thread;
2134        }
2135        
2136        // Wait for all threads to finish.
2137
for (int i = 0; i < nThreads; i++) {
2138            final WritingThread thread = threads[i];
2139            thread.join();
2140            if (thread.failure != null)
2141                throw new Exception JavaDoc(thread.failure);
2142        }
2143    }
2144
2145    private java.io.File JavaDoc createTempFile(
2146            String JavaDoc prefix,
2147            String JavaDoc suffix)
2148    throws IOException JavaDoc {
2149        return File.createTempFile(prefix, suffix, baseDir).getCanonicalFile();
2150    }
2151}
2152
Popular Tags