KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > layers > WritableXMLFileSystemTest


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.apisupport.project.layers;
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import org.netbeans.modules.apisupport.project.TestBase;
32 import org.openide.filesystems.FileAttributeEvent;
33 import org.openide.filesystems.FileChangeListener;
34 import org.openide.filesystems.FileEvent;
35 import org.openide.filesystems.FileLock;
36 import org.openide.filesystems.FileObject;
37 import org.openide.filesystems.FileRenameEvent;
38 import org.openide.filesystems.FileSystem;
39 import org.openide.filesystems.FileUtil;
40 import org.openide.filesystems.MultiFileSystem;
41 import org.openide.loaders.DataFolder;
42 import org.openide.loaders.DataObject;
43
44 /**
45  * Test functionality of {@link WritableXMLFileSystem}.
46  * @author Jesse Glick
47  */

48 public class WritableXMLFileSystemTest extends LayerTestBase {
49     
50     public WritableXMLFileSystemTest(String JavaDoc name) {
51         super(name);
52     }
53     
54     public void testBasicStructureReads() throws Exception JavaDoc {
55         FileSystem fs = new Layer("<file name='x'/>").read();
56         FileObject[] top = fs.getRoot().getChildren();
57         assertEquals(1, top.length);
58         FileObject x = top[0];
59         assertEquals("x", x.getNameExt());
60         assertEquals(0L, x.getSize());
61         assertTrue(x.isData());
62         fs = new Layer("<folder name='x'><file name='y'/></folder><file name='z'/>").read();
63         top = fs.getRoot().getChildren();
64         assertEquals(2, top.length);
65         FileObject z = fs.findResource("z");
66         assertNotNull(z);
67         assertTrue(z.isData());
68         FileObject y = fs.findResource("x/y");
69         assertNotNull(y);
70         assertTrue(y.isData());
71         x = fs.findResource("x");
72         assertEquals(x, y.getParent());
73         assertTrue(x.isFolder());
74         assertEquals(1, x.getChildren().length);
75     }
76     
77     public void testExternalFileReads() throws Exception JavaDoc {
78         FileSystem fs = new Layer("<file name='x' url='x.txt'/>", Collections.singletonMap("x.txt", "stuff")).read();
79         FileObject x = fs.findResource("x");
80         assertNotNull(x);
81         assertTrue(x.isData());
82         assertEquals(5L, x.getSize());
83         assertEquals("stuff", TestBase.slurp(x));
84         fs = new Layer("<file name='x' url='subdir/x.txt'/>", Collections.singletonMap("subdir/x.txt", "more stuff")).read();
85         x = fs.findResource("x");
86         assertNotNull(x);
87         assertEquals("more stuff", TestBase.slurp(x));
88         // XXX check that using a nbres: or nbresloc: URL protocol works here too (if we specify a classpath)
89
}
90     
91     public void testSimpleAttributeReads() throws Exception JavaDoc {
92         FileSystem fs = new Layer("<file name='x'><attr name='a' stringvalue='v'/> <attr name='b' urlvalue='file:/nothing'/></file> " +
93                 "<folder name='y'> <file name='ignore'/><attr name='a' boolvalue='true'/><!--ignore--></folder>").read();
94         FileObject x = fs.findResource("x");
95         assertEquals(new HashSet JavaDoc(Arrays.asList(new String JavaDoc[] {"a", "b"})), new HashSet JavaDoc(Collections.list(x.getAttributes())));
96         assertEquals("v", x.getAttribute("a"));
97         assertEquals(new URL JavaDoc("file:/nothing"), x.getAttribute("b"));
98         assertEquals(null, x.getAttribute("dummy"));
99         FileObject y = fs.findResource("y");
100         assertEquals(Collections.singletonList("a"), Collections.list(y.getAttributes()));
101         assertEquals(Boolean.TRUE, y.getAttribute("a"));
102         fs = new Layer("<attr name='a' stringvalue='This \\u0007 is a beep!'/>").read();
103         assertEquals("Unicode escapes handled correctly (for non-XML-encodable chars)", "This \u0007 is a beep!", fs.getRoot().getAttribute("a"));
104         fs = new Layer("<attr name='a' stringvalue='\\ - \\u - \\u123 - \\uxyzw'/>").read();
105         assertEquals("Malformed escapes also handled", "\\ - \\u - \\u123 - \\uxyzw", fs.getRoot().getAttribute("a"));
106         fs = new Layer("<attr name='a' urlvalue='yadayada'/>").read();
107         assertEquals("Malformed URLs also handled", null, fs.getRoot().getAttribute("a"));
108         // XXX test other attr types: byte, short, int, long, float, double, char
109
}
110     
111     public void testCodeAttributeReads() throws Exception JavaDoc {
112         FileSystem fs = new Layer("<file name='x'><attr name='a' stringvalue='v'/><attr name='b' newvalue='some.Class'/> " +
113                 "<attr name='c' methodvalue='some.Class.m'/></file>").read();
114         FileObject x = fs.findResource("x");
115         assertEquals("v", x.getAttribute("literal:a"));
116         assertEquals("new:some.Class", x.getAttribute("literal:b"));
117         assertEquals("method:some.Class.m", x.getAttribute("literal:c"));
118         // XXX serial:blahblahblah
119
// XXX test actually loading method, new, serial as interpreted objects with a classpath
120
}
121     
122     public void testCreateNewFolder() throws Exception JavaDoc {
123         Layer l = new Layer("");
124         FileSystem fs = l.read();
125         FileObject x = fs.getRoot().createFolder("x");
126         assertEquals("in-memory write worked", 1, fs.getRoot().getChildren().length);
127         assertEquals("wrote correct content for top-level folder", " <folder name=\"x\"/>\n", l.write());
128         x.createFolder("y");
129         assertEquals("wrote correct content for 2nd-level folder", " <folder name=\"x\">\n <folder name=\"y\"/>\n </folder>\n", l.write());
130         l = new Layer(" <folder name=\"original\"/>\n");
131         fs = l.read();
132         fs.getRoot().createFolder("aardvark");
133         fs.getRoot().createFolder("xyzzy");
134         assertEquals("alphabetized new folders", " <folder name=\"aardvark\"/>\n <folder name=\"original\"/>\n <folder name=\"xyzzy\"/>\n", l.write());
135     }
136     
137     public void testCreateNewEmptyFile() throws Exception JavaDoc {
138         Layer l = new Layer("");
139         FileSystem fs = l.read();
140         FileUtil.createData(fs.getRoot(), "Menu/Tools/foo");
141         FileUtil.createData(fs.getRoot(), "Menu/Tools/bar");
142         FileUtil.createFolder(fs.getRoot(), "Menu/Tools/baz");
143         assertEquals("correct files written",
144                 " <folder name=\"Menu\">\n" +
145                 " <folder name=\"Tools\">\n" +
146                 " <file name=\"bar\"/>\n" +
147                 " <folder name=\"baz\"/>\n" +
148                 " <file name=\"foo\"/>\n" +
149                 " </folder>\n" +
150                 " </folder>\n",
151                 l.write());
152         assertEquals("no external files created", Collections.EMPTY_MAP, l.files());
153     }
154     
155     public void testCreateFileWithContents() throws Exception JavaDoc {
156         Layer l = new Layer("");
157         FileSystem fs = l.read();
158         FileObject f = FileUtil.createData(fs.getRoot(), "Templates/Other/Foo.java");
159         f.setAttribute("hello", "there");
160         TestBase.dump(f, "some stuff");
161         String JavaDoc xml =
162                 " <folder name=\"Templates\">\n" +
163                 " <folder name=\"Other\">\n" +
164                 // We never want to create *.java files since they would be compiled.
165
" <file name=\"Foo.java\" url=\"Foo_java\">\n" +
166                 " <attr name=\"hello\" stringvalue=\"there\"/>\n" +
167                 " </file>\n" +
168                 " </folder>\n" +
169                 " </folder>\n";
170         assertEquals("correct XML written", xml, l.write());
171         Map JavaDoc m = new HashMap JavaDoc();
172         m.put("Foo_java", "some stuff");
173         assertEquals("one external file created in " + l, m, l.files());
174         TestBase.dump(f, "new stuff");
175         assertEquals("same XML as before", xml, l.write());
176         m.put("Foo_java", "new stuff");
177         assertEquals("different external file", m, l.files());
178         f = FileUtil.createData(fs.getRoot(), "Templates/Other2/Foo.java");
179         TestBase.dump(f, "unrelated stuff");
180         f = FileUtil.createData(fs.getRoot(), "Templates/Other2/Bar.xml");
181         TestBase.dump(f, "unrelated XML stuff");
182         f = FileUtil.createData(fs.getRoot(), "Services/foo.settings");
183         TestBase.dump(f, "scary stuff");
184         xml =
185                 " <folder name=\"Services\">\n" +
186                 // *.settings are also potentially dangerous in module sources, so rename them.
187
" <file name=\"foo.settings\" url=\"fooSettings.xml\"/>\n" +
188                 " </folder>\n" +
189                 " <folder name=\"Templates\">\n" +
190                 " <folder name=\"Other\">\n" +
191                 " <file name=\"Foo.java\" url=\"Foo_java\">\n" +
192                 " <attr name=\"hello\" stringvalue=\"there\"/>\n" +
193                 " </file>\n" +
194                 " </folder>\n" +
195                 " <folder name=\"Other2\">\n" +
196                 // But *.xml files and other things are generally OK.
197
" <file name=\"Bar.xml\" url=\"Bar.xml\"/>\n" +
198                 " <file name=\"Foo.java\" url=\"Foo_1_java\"/>\n" +
199                 " </folder>\n" +
200                 " </folder>\n";
201         assertEquals("right XML written for remaining files", xml, l.write());
202         m.put("Foo_1_java", "unrelated stuff");
203         m.put("Bar.xml", "unrelated XML stuff");
204         m.put("fooSettings.xml", "scary stuff");
205         assertEquals("right external files", m, l.files());
206         l = new Layer("", Collections.singletonMap("file.txt", "existing stuff"));
207         fs = l.read();
208         f = FileUtil.createData(fs.getRoot(), "wherever/file.txt");
209         TestBase.dump(f, "unrelated stuff");
210         xml =
211                 " <folder name=\"wherever\">\n" +
212                 // Need to pick a different location even though there is no conflict inside the layer.
213
// Also should use a suffix before file extension.
214
" <file name=\"file.txt\" url=\"file_1.txt\"/>\n" +
215                 " </folder>\n";
216         assertEquals("wrote new file contents to non-clobbering location", xml, l.write());
217         m.clear();
218         m.put("file.txt", "existing stuff");
219         m.put("file_1.txt", "unrelated stuff");
220         assertEquals("right external files", m, l.files());
221         l = new Layer("");
222         fs = l.read();
223         f = FileUtil.createData(fs.getRoot(), "one/bare");
224         TestBase.dump(f, "bare #1");
225         f = FileUtil.createData(fs.getRoot(), "two/bare");
226         TestBase.dump(f, "bare #2");
227         f = FileUtil.createData(fs.getRoot(), "three/bare");
228         TestBase.dump(f, "bare #3");
229         xml =
230                 " <folder name=\"one\">\n" +
231                 " <file name=\"bare\" url=\"bare\"/>\n" +
232                 " </folder>\n" +
233                 // Note alpha ordering.
234
" <folder name=\"three\">\n" +
235                 // Count _1, _2, _3, ...
236
" <file name=\"bare\" url=\"bare_2\"/>\n" +
237                 " </folder>\n" +
238                 " <folder name=\"two\">\n" +
239                 // No extension here, fine.
240
" <file name=\"bare\" url=\"bare_1\"/>\n" +
241                 " </folder>\n";
242         assertEquals("right counter usage", xml, l.write());
243         m.clear();
244         m.put("bare", "bare #1");
245         m.put("bare_1", "bare #2");
246         m.put("bare_2", "bare #3");
247         assertEquals("right external files", m, l.files());
248     }
249     // XXX testReplaceExistingInlineContent
250

251     public void testAddAttributes() throws Exception JavaDoc {
252         Layer l = new Layer("");
253         FileSystem fs = l.read();
254         FileObject f = fs.getRoot().createFolder("f");
255         f.createData("b");
256         FileObject a = f.createData("a");
257         f.createData("c");
258         a.setAttribute("x", "v1");
259         a.setAttribute("y", new URL JavaDoc("file:/v2"));
260         f.setAttribute("a/b", Boolean.TRUE);
261         f.setAttribute("b/c", Boolean.TRUE);
262         f.setAttribute("misc", "whatever");
263         assertEquals("correct attrs written",
264                 " <folder name=\"f\">\n" +
265                 " <attr name=\"misc\" stringvalue=\"whatever\"/>\n" +
266                 " <file name=\"a\">\n" +
267                 " <attr name=\"x\" stringvalue=\"v1\"/>\n" +
268                 " <attr name=\"y\" urlvalue=\"file:/v2\"/>\n" +
269                 " </file>\n" +
270                 " <attr name=\"a/b\" boolvalue=\"true\"/>\n" +
271                 " <file name=\"b\"/>\n" +
272                 " <attr name=\"b/c\" boolvalue=\"true\"/>\n" +
273                 " <file name=\"c\"/>\n" +
274                 " </folder>\n",
275                 l.write());
276         // XXX test also string values w/ dangerous chars
277
}
278     
279     public void testDeleteReplaceAttributes() throws Exception JavaDoc {
280         Layer l = new Layer(
281                 " <file name=\"x\">\n" +
282                 " <attr name=\"foo\" stringvalue=\"bar\"/>\n" +
283                 " </file>\n");
284         FileSystem fs = l.read();
285         FileObject x = fs.findResource("x");
286         x.setAttribute("foo", Boolean.TRUE);
287         assertEquals("replaced attr",
288                 " <file name=\"x\">\n" +
289                 " <attr name=\"foo\" boolvalue=\"true\"/>\n" +
290                 " </file>\n",
291                 l.write());
292         x.setAttribute("foo", null);
293         assertEquals("deleted attr",
294                 " <file name=\"x\"/>\n",
295                 l.write());
296         x.setAttribute("foo", null);
297         assertEquals("cannot delete attr twice",
298                 " <file name=\"x\"/>\n",
299                 l.write());
300         /* Now this stores x/y=false instead... OK?
301         fs.getRoot().createData("y");
302         fs.getRoot().setAttribute("x/y", Boolean.TRUE);
303         fs.getRoot().setAttribute("x/y", null);
304         assertEquals("deleted ordering attr",
305                 " <file name=\"x\"/>\n" +
306                 " <file name=\"y\"/>\n",
307                 l.write());
308          */

309     }
310     
311     public void testCodeAttributeWrites() throws Exception JavaDoc {
312         Layer l = new Layer("");
313         FileSystem fs = l.read();
314         FileObject x = fs.getRoot().createData("x");
315         x.setAttribute("nv", "newvalue:org.foo.Clazz");
316         x.setAttribute("mv", "methodvalue:org.foo.Clazz.create");
317         assertEquals("special attrs written to XML",
318                 " <file name=\"x\">\n" +
319                 " <attr name=\"mv\" methodvalue=\"org.foo.Clazz.create\"/>\n" +
320                 " <attr name=\"nv\" newvalue=\"org.foo.Clazz\"/>\n" +
321                 " </file>\n",
322                 l.write());
323     }
324     
325     public void testOpenideFolderOrder() throws Exception JavaDoc {
326         Layer l = new Layer("");
327         FileSystem fs = l.read();
328         FileObject r = fs.getRoot();
329         FileObject a = r.createData("a");
330         FileObject b = r.createData("b");
331         FileObject f = r.createFolder("f");
332         FileObject c = f.createData("c");
333         FileObject d = f.createData("d");
334         FileObject e = f.createData("e");
335         DataFolder.findFolder(r).setOrder(new DataObject[] {DataObject.find(a), DataObject.find(b)});
336         DataFolder.findFolder(f).setOrder(new DataObject[] {DataObject.find(c), DataObject.find(d), DataObject.find(e)});
337         assertEquals("correct ordering XML",
338                 " <file name=\"a\"/>\n" +
339                 " <attr name=\"a/b\" boolvalue=\"true\"/>\n" +
340                 " <file name=\"b\"/>\n" +
341                 " <folder name=\"f\">\n" +
342                 " <file name=\"c\"/>\n" +
343                 " <attr name=\"c/d\" boolvalue=\"true\"/>\n" +
344                 " <file name=\"d\"/>\n" +
345                 " <attr name=\"d/e\" boolvalue=\"true\"/>\n" +
346                 " <file name=\"e\"/>\n" +
347                 " </folder>\n",
348                 l.write());
349         l = new Layer("");
350         fs = l.read();
351         r = fs.getRoot();
352         b = r.createData("b");
353         c = r.createFolder("c");
354         r.setAttribute("c/b", Boolean.TRUE);
355         r.setAttribute("d/c", Boolean.TRUE);
356         r.setAttribute("b/a", Boolean.TRUE);
357         assertEquals("ordering attrs reorder entries in a folder",
358                 " <attr name=\"d/c\" boolvalue=\"true\"/>\n" +
359                 " <folder name=\"c\"/>\n" +
360                 " <attr name=\"c/b\" boolvalue=\"true\"/>\n" +
361                 " <file name=\"b\"/>\n" +
362                 " <attr name=\"b/a\" boolvalue=\"true\"/>\n",
363                 l.write());
364         l = new Layer("");
365         fs = l.read();
366         r = fs.getRoot();
367         FileObject main = r.createData("main");
368         FileObject before = r.createData("s-before");
369         r.setAttribute("pre/s-before", Boolean.TRUE);
370         r.setAttribute("s-before/main", Boolean.TRUE);
371         assertEquals(
372                 " <attr name=\"pre/s-before\" boolvalue=\"true\"/>\n" +
373                 " <file name=\"s-before\"/>\n" +
374                 " <attr name=\"s-before/main\" boolvalue=\"true\"/>\n" +
375                 " <file name=\"main\"/>\n",
376                 l.write());
377         // XXX probably need even more sophisticated tests to really cover WXMLFS.resort!
378
l = new Layer("");
379         fs = l.read();
380         FileUtil.createData(fs.getRoot(), "f/two");
381         FileSystem ro = FileUtil.createMemoryFileSystem();
382         f = ro.getRoot().createFolder("f");
383         f.createData("one");
384         f.setAttribute("one/three", Boolean.TRUE);
385         f.createData("three");
386         f.createData("four");
387         f.setAttribute("three/four", Boolean.TRUE);
388         FileSystem merge = new MultiFileSystem(new FileSystem[] {fs, ro});
389         DataObject one = DataObject.find(merge.findResource("f/one"));
390         DataObject two = DataObject.find(merge.findResource("f/two"));
391         DataObject three = DataObject.find(merge.findResource("f/three"));
392         DataObject four = DataObject.find(merge.findResource("f/four"));
393         DataFolder.findFolder(merge.findResource("f")).setOrder(new DataObject[] {one, two, three, four});
394         assertEquals("correct insertion of new file into existing folder",
395                 " <folder name=\"f\">\n" +
396                 " <attr name=\"one/two\" boolvalue=\"true\"/>\n" +
397                 " <file name=\"two\"/>\n" +
398                 " <attr name=\"two/three\" boolvalue=\"true\"/>\n" +
399                 " </folder>\n",
400                 l.write());
401         l = new Layer("");
402         fs = l.read();
403         FileUtil.createData(fs.getRoot(), "f/two");
404         merge = new MultiFileSystem(new FileSystem[] {fs, ro});
405         assertEquals(Boolean.TRUE, merge.findResource("f").getAttribute("one/three"));
406         one = DataObject.find(merge.findResource("f/one"));
407         two = DataObject.find(merge.findResource("f/two"));
408         three = DataObject.find(merge.findResource("f/three"));
409         four = DataObject.find(merge.findResource("f/four"));
410         DataFolder.findFolder(merge.findResource("f")).setOrder(new DataObject[] {four, three, two, one});
411         assertEquals("correct insertion of new file into existing folder w/ override of old order",
412                 " <folder name=\"f\">\n" +
413                 " <attr name=\"three/two\" boolvalue=\"true\"/>\n" +
414                 " <file name=\"two\"/>\n" +
415                 " <attr name=\"two/one\" boolvalue=\"true\"/>\n" +
416                 //XXX cannot get this to work: " <attr name=\"four/three\" boolvalue=\"true\"/>\n" +
417
" <attr name=\"three/four\" boolvalue=\"false\"/>\n" +
418                 " <attr name=\"one/three\" boolvalue=\"false\"/>\n" +
419                 " </folder>\n",
420                 l.write());
421         // XXX but inserting new item in a new position *twice* does not work... sigh... can it be fixed?
422
}
423     
424     public void testDeleteFileOrFolder() throws Exception JavaDoc {
425         Layer l = new Layer("");
426         FileSystem fs = l.read();
427         FileObject f = fs.getRoot().createFolder("f");
428         FileObject x = f.createData("x");
429         x.setAttribute("foo", "bar");
430         TestBase.dump(x, "stuff");
431         FileObject y = FileUtil.createData(fs.getRoot(), "y");
432         x.delete();
433         assertEquals("one file and one folder left",
434                 " <folder name=\"f\"/>\n" +
435                 " <file name=\"y\"/>\n",
436                 l.write());
437         assertEquals("no external files left", Collections.EMPTY_MAP, l.files());
438         f.delete();
439         assertEquals("one file left",
440                 " <file name=\"y\"/>\n",
441                 l.write());
442         y.delete();
443         assertEquals("layer now empty again", "", l.write());
444         l = new Layer("");
445         fs = l.read();
446         f = fs.getRoot().createFolder("f");
447         x = f.createData("x");
448         TestBase.dump(x, "stuff");
449         f.delete();
450         assertEquals("layer empty again", "", l.write());
451         assertEquals("no external files left even after only implicitly deleting file", Collections.EMPTY_MAP, l.files());
452         // XXX should any associated ordering attrs also be deleted? not acc. to spec, but often handy...
453
l = new Layer("");
454         fs = l.read();
455         FileObject a = fs.getRoot().createData("a");
456         FileObject b = fs.getRoot().createData("b");
457         FileObject c = fs.getRoot().createData("c");
458         FileObject d = fs.getRoot().createData("d");
459         a.delete();
460         assertEquals("right indentation cleanup for deletion of first child",
461                 " <file name=\"b\"/>\n" +
462                 " <file name=\"c\"/>\n" +
463                 " <file name=\"d\"/>\n",
464                 l.write());
465         c.delete();
466         assertEquals("right indentation cleanup for deletion of interior child",
467                 " <file name=\"b\"/>\n" +
468                 " <file name=\"d\"/>\n",
469                 l.write());
470         d.delete();
471         assertEquals("right indentation cleanup for deletion of last child",
472                 " <file name=\"b\"/>\n",
473                 l.write());
474     }
475     
476     public void testRename() throws Exception JavaDoc {
477         Layer l = new Layer(" <folder name=\"folder1\">\n <file name=\"file1.txt\">\n <attr name=\"a\" stringvalue=\"v\"/>\n </file>\n </folder>\n");
478         FileSystem fs = l.read();
479         FileObject f = fs.findResource("folder1");
480         assertNotNull(f);
481         FileLock lock = f.lock();
482         f.rename(lock, "folder2", null);
483         lock.releaseLock();
484         f = fs.findResource("folder2/file1.txt");
485         assertNotNull(f);
486         lock = f.lock();
487         f.rename(lock, "file2.txt", null);
488         lock.releaseLock();
489         assertEquals("#63989: correct rename handling", " <folder name=\"folder2\">\n <file name=\"file2.txt\">\n <attr name=\"a\" stringvalue=\"v\"/>\n </file>\n </folder>\n", l.write());
490         // XXX should any associated ordering attrs also be renamed? might be pleasant...
491
}
492     
493     public void testSomeFormattingPreserved() throws Exception JavaDoc {
494         String JavaDoc orig = " <file name=\"orig\"><!-- hi --><attr name=\"a\" boolvalue=\"true\"/>" +
495                 "<attr boolvalue=\"true\" name=\"b\"/></file>\n";
496         Layer l = new Layer(orig);
497         FileSystem fs = l.read();
498         fs.getRoot().createData("aardvark");
499         fs.getRoot().createData("zyzzyva");
500         assertEquals("kept original XML intact",
501                 " <file name=\"aardvark\"/>\n" +
502                 orig +
503                 " <file name=\"zyzzyva\"/>\n",
504                 l.write());
505         // XXX what doesn't work: space before />, unusual whitespace between attrs, ...
506
// This is a job for TAX to improve on. Currently uses Xerces XNI parser,
507
// which discards some formatting info when constructing its model.
508
// Not as much as using DOM + serialization, but some.
509
}
510     
511     public void testStructuralModificationsFired() throws Exception JavaDoc {
512         Layer l = new Layer("<folder name='f'/><file name='x'/>");
513         FileSystem fs = l.read();
514         Listener fcl = new Listener();
515         fs.addFileChangeListener(fcl);
516         FileUtil.createData(fs.getRoot(), "a");
517         FileUtil.createData(fs.getRoot(), "f/b");
518         fs.findResource("x").delete();
519         assertEquals("expected things fired",
520                 new HashSet JavaDoc(Arrays.asList(new String JavaDoc[] {"a", "f/b", "x"})),
521                         fcl.changes());
522     }
523
524     public void testTextualModificationsFired() throws Exception JavaDoc {
525         Layer l = new Layer("<folder name='f'><file name='x'/></folder><file name='y'/>");
526         FileSystem fs = l.read();
527         Listener fcl = new Listener();
528         fs.addFileChangeListener(fcl);
529         l.edit("<folder name='f'/><file name='y'/><file name='z'/>");
530         Set JavaDoc/*<String>*/ changes = fcl.changes();
531         //System.err.println("changes=" + changes);
532
/* XXX does not work; fires too much... why?
533         assertEquals("expected things fired",
534                 new HashSet(Arrays.asList(new String[] {"f/x", "z"})),
535                         changes);
536          */

537         assertTrue("something fired", !changes.isEmpty());
538         assertNull(fs.findResource("f/x"));
539         assertNotNull(fs.findResource("z"));
540         l.edit("<folder name='f'><file name='x2'/></folder><file name='y'/><file name='z'/>");
541         /* XXX fails just on JDK 1.4... why?
542         changes = fcl.changes();
543         //System.err.println("changes=" + changes);
544         assertTrue("something fired #2", !changes.isEmpty());
545          */

546         assertNotNull(fs.findResource("f/x2"));
547         assertNotNull(fs.findResource("z"));
548     }
549     
550     public void testExternalFileChangesRefired() throws Exception JavaDoc {
551         Layer l = new Layer("");
552         FileSystem fs = l.read();
553         FileObject foo = fs.getRoot().createData("foo");
554         TestBase.dump(foo, "foo text");
555         long start = foo.lastModified().getTime();
556         assertEquals(start, l.externalLastModified("foo"));
557         Thread.sleep(1000L); // make sure the timestamp actually changed
558
Listener fcl = new Listener();
559         fs.addFileChangeListener(fcl);
560         l.editExternal("foo", "new text");
561         long end = foo.lastModified().getTime();
562         assertEquals(end, l.externalLastModified("foo"));
563         assertTrue("foo was touched", end > start);
564         assertEquals("expected things fired",
565                 Collections.singleton("foo"),
566                         fcl.changes());
567     }
568     
569     public void testHeapUsage() throws Exception JavaDoc {
570         Layer l = new Layer("");
571         FileSystem fs = l.read();
572         Object JavaDoc buffer = new byte[(int) (Runtime.getRuntime().freeMemory() * 2 / 3)];
573         int count = 1000;
574         int bytesPerFile = 4000; // found by trial and error, but seems tolerable
575
for (int i = 0; i < count; i++) {
576             try {
577                 fs.getRoot().createData("file" + i);
578             } catch (OutOfMemoryError JavaDoc e) {
579                 fail("Ran out of heap on file #" + i);
580             }
581         }
582         assertSize("Filesystem not too big", count * bytesPerFile, l);
583     }
584     
585     /**
586      * Handle for working with an XML layer.
587      */

588     private final class Layer {
589         private final File JavaDoc folder;
590         private final FileObject f;
591         private LayerUtils.SavableTreeEditorCookie cookie;
592         /**
593          * Create a layer from a fixed bit of filesystem-DTD XML.
594          * Omit the <filesystem>...</> tag and just give the contents.
595          * But if you want to check formatting later using {@link #write()},
596          * you should use 4-space indents and a newline after every element.
597          */

598         public Layer(String JavaDoc xml) throws Exception JavaDoc {
599             folder = makeFolder();
600             f = makeLayer(xml);
601         }
602         /**
603          * Create a layer from XML plus external file contents.
604          * The map's keys are relative disk filenames, and values are contents.
605          */

606         public Layer(String JavaDoc xml, Map JavaDoc/*<String,String>*/ files) throws Exception JavaDoc {
607             this(xml);
608             Iterator JavaDoc it = files.entrySet().iterator();
609             while (it.hasNext()) {
610                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
611                 String JavaDoc fname = (String JavaDoc) entry.getKey();
612                 String JavaDoc contents = (String JavaDoc) entry.getValue();
613                 File JavaDoc f = new File JavaDoc(folder, fname.replace('/', File.separatorChar));
614                 f.getParentFile().mkdirs();
615                 TestBase.dump(f, contents);
616             }
617         }
618         private File JavaDoc makeFolder() throws Exception JavaDoc {
619             File JavaDoc f = File.createTempFile("layerdata", "", getWorkDir());
620             f.delete();
621             f.mkdir();
622             return f;
623         }
624         private final String JavaDoc HEADER =
625                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
626                 "<!DOCTYPE filesystem PUBLIC \"-//NetBeans//DTD Filesystem 1.1//EN\" \"http://www.netbeans.org/dtds/filesystem-1_1.dtd\">\n" +
627                 "<filesystem>\n";
628         private final String JavaDoc FOOTER = "</filesystem>\n";
629         private FileObject makeLayer(String JavaDoc xml) throws Exception JavaDoc {
630             File JavaDoc f = new File JavaDoc(folder, "layer.xml");
631             TestBase.dump(f, HEADER + xml + FOOTER);
632             return FileUtil.toFileObject(f);
633         }
634         /**
635          * Read the filesystem from the layer.
636          */

637         public WritableXMLFileSystem read() throws Exception JavaDoc {
638             cookie = LayerUtils.cookieForFile(f);
639             return new WritableXMLFileSystem(f.getURL(), cookie, null);
640         }
641         /**
642          * Write the filesystem to the layer and retrieve the new contents.
643          * The header and footer are removed for you, but not other whitespace.
644          */

645         public String JavaDoc write() throws Exception JavaDoc {
646             cookie.save();
647             String JavaDoc raw = TestBase.slurp(f);
648             assertTrue("unexpected header in '" + raw + "'", raw.startsWith(HEADER));
649             assertTrue("unexpected footer in '" + raw + "'", raw.endsWith(FOOTER));
650             return raw.substring(HEADER.length(), raw.length() - FOOTER.length());
651         }
652         /**
653          * Edit the text of the layer.
654          */

655         public void edit(String JavaDoc newText) throws Exception JavaDoc {
656             TestBase.dump(f, HEADER + newText + FOOTER);
657         }
658         /**
659          * Edit a referenced external file.
660          */

661         public void editExternal(String JavaDoc path, String JavaDoc newText) throws Exception JavaDoc {
662             assert !path.equals("layer.xml");
663             File JavaDoc f = new File JavaDoc(folder, path.replace('/', File.separatorChar));
664             assert f.isFile();
665             TestBase.dump(FileUtil.toFileObject(f), newText);
666         }
667         public long externalLastModified(String JavaDoc path) {
668             File JavaDoc f = new File JavaDoc(folder, path.replace('/', File.separatorChar));
669             return FileUtil.toFileObject(f).lastModified().getTime();
670         }
671         /**
672          * Get extra files besides layer.xml which were written to.
673          * Keys are relative file paths and values are file contents.
674          */

675         public Map JavaDoc/*<String,String>*/ files() throws IOException JavaDoc {
676             Map JavaDoc m = new HashMap JavaDoc();
677             traverse(m, folder, "");
678             return m;
679         }
680         private void traverse(Map JavaDoc m, File JavaDoc folder, String JavaDoc prefix) throws IOException JavaDoc {
681             String JavaDoc[] kids = folder.list();
682             if (kids == null) {
683                 throw new IOException JavaDoc(folder.toString());
684             }
685             for (int i = 0; i < kids.length; i++) {
686                 String JavaDoc path = prefix + kids[i];
687                 if (path.equals("layer.xml")) {
688                     continue;
689                 }
690                 File JavaDoc f = new File JavaDoc(folder, kids[i]);
691                 if (f.isDirectory()) {
692                     traverse(m, f, prefix + kids[i] + '/');
693                 } else {
694                     m.put(path, TestBase.slurp(f));
695                 }
696             }
697         }
698         public String JavaDoc toString() {
699             return "Layer[" + folder + "]";
700         }
701     }
702     
703     private static final class Listener implements FileChangeListener {
704         
705         private Set JavaDoc/*<String>*/ changes = new HashSet JavaDoc();
706         
707         public Listener() {}
708         
709         public Set JavaDoc/*<String>*/ changes() {
710             Set JavaDoc _changes = changes;
711             changes = new HashSet JavaDoc();
712             return _changes;
713         }
714         
715         public void fileFolderCreated(FileEvent fe) {
716             changed(fe);
717         }
718         public void fileDataCreated(FileEvent fe) {
719             changed(fe);
720         }
721         public void fileChanged(FileEvent fe) {
722             changed(fe);
723         }
724         public void fileDeleted(FileEvent fe) {
725             changed(fe);
726         }
727         public void fileRenamed(FileRenameEvent fe) {
728             changed(fe);
729         }
730         public void fileAttributeChanged(FileAttributeEvent fe) {
731             changed(fe);
732         }
733         
734         private void changed(FileEvent fe) {
735             changes.add(fe.getFile().getPath());
736         }
737         
738     }
739     
740 }
741
Popular Tags