KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > spi > project > support > ant > AntBasedTestUtil


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.spi.project.support.ant;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.InputStreamReader JavaDoc;
30 import java.io.OutputStream JavaDoc;
31 import java.io.OutputStreamWriter JavaDoc;
32 import java.io.Reader JavaDoc;
33 import java.io.Writer JavaDoc;
34 import java.net.URI JavaDoc;
35 import java.net.URISyntaxException JavaDoc;
36 import java.net.URL JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.HashSet JavaDoc;
40 import java.util.List JavaDoc;
41 import java.util.Map JavaDoc;
42 import java.util.Properties JavaDoc;
43 import java.util.Set JavaDoc;
44 import java.util.regex.Matcher JavaDoc;
45 import java.util.regex.Pattern JavaDoc;
46 import java.util.regex.PatternSyntaxException JavaDoc;
47 import javax.swing.Icon JavaDoc;
48 import javax.swing.event.ChangeEvent JavaDoc;
49 import javax.swing.event.ChangeListener JavaDoc;
50 import org.netbeans.api.diff.Difference;
51 import org.netbeans.api.project.Project;
52 import org.netbeans.api.project.ant.AntArtifact;
53 import org.netbeans.modules.diff.builtin.provider.BuiltInDiffProvider;
54 import org.netbeans.modules.project.ant.Util;
55 import org.netbeans.spi.diff.DiffProvider;
56 import org.netbeans.spi.project.AuxiliaryConfiguration;
57 import org.netbeans.api.project.ProjectInformation;
58 import org.netbeans.api.project.ProjectManager;
59 import org.netbeans.spi.project.ant.AntArtifactProvider;
60 import org.netbeans.spi.queries.CollocationQueryImplementation;
61 import org.openide.filesystems.FileObject;
62 import org.openide.util.Lookup;
63 import org.openide.util.lookup.Lookups;
64 import org.openide.xml.XMLUtil;
65 import org.w3c.dom.Document JavaDoc;
66 import org.w3c.dom.Element JavaDoc;
67
68 import org.xml.sax.InputSource JavaDoc;
69 import org.xml.sax.SAXException JavaDoc;
70
71 /**
72  * Test-related utilities for use in ant/project.
73  * @author Jesse Glick
74  */

75 public class AntBasedTestUtil {
76     
77     private AntBasedTestUtil() {}
78     
79     /**
80      * Create an AntBasedProjectType instance suitable for testing.
81      * It has the type code <samp>test</samp>.
82      * It uses <samp>&lt;data&gt;</samp> as the configuration data element,
83      * with namespaces <samp>urn:test:shared</samp> and <samp>urn:test:private</samp>.
84      * Loading the project succeeds unless there is a file in it <samp>nbproject/broken</samp>.
85      * The project's methods mostly delegate to the helper; its lookup uses the helper's
86      * supports for ExtensibleMetadataProvider, ActionProvider, and SubprojectProvider,
87      * and also adds an instance of String, namely "hello".
88      * It also puts the AntProjectHelper into its lookup to assist in testing.
89      * <code>build-impl.xml</code> is generated from <code>data/build-impl.xsl</code>
90      * by a ProjectXmlSavedHook using GeneratedFilesHelper.refreshBuildScript.
91      * A ReferenceHelper is also added to its lookup for testing purposes.
92      * An {@link AntArtifactProviderMutable} is added which initially publishes two artifacts:
93      * one of target 'dojar' type 'jar' with artifact ${build.jar};
94      * one of target 'dojavadoc' type 'javadoc' with artifact ${build.javadoc};
95      * both using clean target 'clean'.
96      * A GeneratedFilesHelper is added to its lookup for testing purposes.
97      * @return a project type object for testing purposes
98      */

99     public static AntBasedProjectType testAntBasedProjectType() {
100         return new TestAntBasedProjectType();
101     }
102     
103     /**
104      * You can adjust which artifacts are supplied.
105      */

106     public interface AntArtifactProviderMutable extends AntArtifactProvider {
107         void setBuildArtifacts(AntArtifact[] arts);
108     }
109     
110     private static final class TestAntBasedProjectType implements AntBasedProjectType {
111         
112         TestAntBasedProjectType() {}
113         
114         public String JavaDoc getType() {
115             return "test";
116         }
117         
118         public Project createProject(AntProjectHelper helper) throws IOException JavaDoc {
119             return new TestAntBasedProject(helper);
120         }
121         
122         public String JavaDoc getPrimaryConfigurationDataElementName(boolean shared) {
123             return "data";
124         }
125         
126         public String JavaDoc getPrimaryConfigurationDataElementNamespace(boolean shared) {
127             return shared ? "urn:test:shared" : "urn:test:private";
128         }
129         
130     }
131     
132     private static final class TestAntBasedProject implements Project {
133         
134         private final AntProjectHelper helper;
135         private final ReferenceHelper refHelper;
136         private final GeneratedFilesHelper genFilesHelper;
137         private final Lookup l;
138         
139         TestAntBasedProject(AntProjectHelper helper) throws IOException JavaDoc {
140             if (helper.getProjectDirectory().getFileObject("nbproject/broken") != null) {
141                 throw new IOException JavaDoc("broken");
142             }
143             this.helper = helper;
144             AuxiliaryConfiguration aux = helper.createAuxiliaryConfiguration();
145             refHelper = new ReferenceHelper(helper, aux, helper.getStandardPropertyEvaluator());
146             genFilesHelper = new GeneratedFilesHelper(helper);
147             l = Lookups.fixed(new Object JavaDoc[] {
148                 new TestInfo(),
149                 helper,
150                 refHelper,
151                 genFilesHelper,
152                 aux,
153                 helper.createCacheDirectoryProvider(),
154                 refHelper.createSubprojectProvider(),
155                 new TestAntArtifactProvider(),
156                 new ProjectXmlSavedHook() {
157                     protected void projectXmlSaved() throws IOException JavaDoc {
158                         genFilesHelper.refreshBuildScript(
159                             GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
160                             AntBasedTestUtil.class.getResource("data/build-impl.xsl"),
161                             false);
162                         genFilesHelper.refreshBuildScript(
163                             GeneratedFilesHelper.BUILD_XML_PATH,
164                             testBuildXmlStylesheet(),
165                             false);
166                     }
167                 },
168                 "hello",
169             });
170         }
171         
172         public FileObject getProjectDirectory() {
173             return helper.getProjectDirectory();
174         }
175         
176         public Lookup getLookup() {
177             return l;
178         }
179         
180         public String JavaDoc toString() {
181             return "TestAntBasedProject[" + getProjectDirectory() + "]";
182         }
183         
184         private final class TestInfo implements ProjectInformation {
185             
186             TestInfo() {}
187             
188             private String JavaDoc getText(String JavaDoc elementName) {
189                 Element JavaDoc data = helper.getPrimaryConfigurationData(true);
190                 Element JavaDoc el = Util.findElement(data, elementName, "urn:test:shared");
191                 if (el != null) {
192                     String JavaDoc text = Util.findText(el);
193                     if (text != null) {
194                         return text;
195                     }
196                 }
197                 // Some kind of fallback here.
198
return getProjectDirectory().getNameExt();
199             }
200             
201             public String JavaDoc getName() {
202                 return getText("name");
203             }
204             
205             public String JavaDoc getDisplayName() {
206                 return getText("display-name");
207             }
208             
209             public Icon JavaDoc getIcon() {
210                 return null;
211             }
212             
213             public Project getProject() {
214                 return TestAntBasedProject.this;
215             }
216             
217             public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {}
218             public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {}
219             
220         }
221         
222         private final class TestAntArtifactProvider implements AntArtifactProviderMutable {
223             
224             private AntArtifact[] arts;
225             
226             TestAntArtifactProvider() {}
227             
228             public AntArtifact[] getBuildArtifacts() {
229                 if (arts != null) {
230                     return arts;
231                 }
232                 URI JavaDoc[] uris = null;
233                 try {
234                     uris = new URI JavaDoc[]{new URI JavaDoc("dist/foo.jar"), new URI JavaDoc("dist/bar.jar")};
235                 } catch (URISyntaxException JavaDoc ex) {
236                     ex.printStackTrace();
237                 }
238                 return new AntArtifact[] {
239                     helper.createSimpleAntArtifact("jar", "build.jar", helper.getStandardPropertyEvaluator(), "dojar", "clean"),
240                     helper.createSimpleAntArtifact("javadoc", "build.javadoc", helper.getStandardPropertyEvaluator(), "dojavadoc", "clean"),
241                     new TestAntArtifact(uris, helper),
242                 };
243             }
244             
245             public void setBuildArtifacts(AntArtifact[] arts) {
246                 this.arts = arts;
247             }
248             
249         }
250         
251     }
252     
253     /**
254      * Load a properties file from disk.
255      * @param h a project reference
256      * @param path the relative file path
257      * @return properties available at that location, or null if no such file
258      * @throws IOException if there is any problem loading it
259      */

260     public static Properties JavaDoc slurpProperties(AntProjectHelper h, String JavaDoc path) throws IOException JavaDoc {
261         Properties JavaDoc p = new Properties JavaDoc();
262         File JavaDoc f = h.resolveFile(path);
263         if (!f.isFile()) {
264             return null;
265         }
266         InputStream JavaDoc is = new FileInputStream JavaDoc(f);
267         try {
268             p.load(is);
269         } finally {
270             is.close();
271         }
272         return p;
273     }
274     
275     /**
276      * Load an XML file from disk.
277      * @param h a project reference
278      * @param path the relative file path
279      * @return an XML document available at that location, or null if no such file
280      * @throws IOException if there is any problem loading it
281      * @throws SAXException if it is malformed
282      */

283     public static Document JavaDoc slurpXml(AntProjectHelper h, String JavaDoc path) throws IOException JavaDoc, SAXException JavaDoc {
284         File JavaDoc f = h.resolveFile(path);
285         if (!f.isFile()) {
286             return null;
287         }
288         return XMLUtil.parse(new InputSource JavaDoc(f.toURI().toString()), false, true, Util.defaultErrorHandler(), null);
289     }
290     
291     /**
292      * Load a text file from disk.
293      * Assumes UTF-8 encoding.
294      * @param h a project reference
295      * @param path the relative file path
296      * @return the raw contents of the text file at that point, or null if no such file
297      * @throws IOException if there is any problem loading it
298      */

299     public static String JavaDoc slurpText(AntProjectHelper h, String JavaDoc path) throws IOException JavaDoc {
300         File JavaDoc f = h.resolveFile(path);
301         if (!f.isFile()) {
302             return null;
303         }
304         InputStream JavaDoc is = new FileInputStream JavaDoc(f);
305         try {
306             Reader JavaDoc r = new InputStreamReader JavaDoc(is, "UTF-8");
307             StringBuffer JavaDoc b = new StringBuffer JavaDoc();
308             char[] buf = new char[4096];
309             int read;
310             while ((read = r.read(buf)) != -1) {
311                 b.append(buf, 0, read);
312             }
313             return b.toString();
314         } finally {
315             is.close();
316         }
317     }
318     
319     /**
320      * Get a sample <code>build.xsl</code>.
321      * @return a URL to a stylesheet
322      */

323     public static URL JavaDoc testBuildXmlStylesheet() {
324         return AntBasedTestUtil.class.getResource("data/build.xsl");
325     }
326
327     /**
328      * A sample listener that just collects events it receives.
329      */

330     public static final class TestListener implements AntProjectListener {
331         
332         private final List JavaDoc<AntProjectEvent> events = new ArrayList JavaDoc<AntProjectEvent>();
333         
334         /** Create a new listener. */
335         public TestListener() {}
336         
337         /**
338          * Get a list of received events, in order.
339          * Also clears the list for the next call.
340          * @return an ordered list of Ant project events
341          */

342         public AntProjectEvent[] events() {
343             AntProjectEvent[] evs = events.toArray(new AntProjectEvent[0]);
344             events.clear();
345             return evs;
346         }
347         
348         public void configurationXmlChanged(AntProjectEvent ev) {
349             assert ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH) || ev.getPath().equals(AntProjectHelper.PRIVATE_XML_PATH);
350             events.add(ev);
351         }
352         
353         public void propertiesChanged(AntProjectEvent ev) {
354             assert !ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH) && !ev.getPath().equals(AntProjectHelper.PRIVATE_XML_PATH);
355             events.add(ev);
356         }
357         
358     }
359     
360     /**
361      * Count the number of (line-based) differences between two text files.
362      * The returned count has, in this order:
363      * <ol>
364      * <li>Lines modified between the first and second files.
365      * <li>Lines added in the second file that were not in the first.
366      * <li>Lines removed in the second file that were in the first.
367      * </ol>
368      * It thus serves as a summary of the number of diff lines you would expect
369      * to get from e.g. a version control system doing a normal text checkin.
370      * @param r1 the first file (the reader will not be closed for you)
371      * @param r2 the second file (the reader will not be closed for you)
372      * @return a count of lines modified, added, and removed (resp.)
373      * @throws IOException in case reading from the files failed
374      */

375     public static int[] countTextDiffs(Reader JavaDoc r1, Reader JavaDoc r2) throws IOException JavaDoc {
376         DiffProvider dp = new BuiltInDiffProvider();
377         Difference[] diffs = dp.computeDiff(r1, r2);
378         int[] count = new int[3];
379         for (int i = 0; i < diffs.length; i++) {
380             switch (diffs[i].getType()) {
381                 case Difference.CHANGE:
382                     count[0] += Math.max(diffs[i].getFirstEnd() - diffs[i].getFirstStart()+1, diffs[i].getSecondEnd() - diffs[i].getSecondStart()+1);
383                     break;
384                 case Difference.ADD:
385                     count[1] += (diffs[i].getSecondEnd() - diffs[i].getSecondStart()+1);
386                     break;
387                 case Difference.DELETE:
388                     count[2] += (diffs[i].getFirstEnd() - diffs[i].getFirstStart()+1);
389                     break;
390                 default:
391                     assert false : diffs[i];
392             }
393         }
394         return count;
395     }
396     
397     /**
398      * Get a sample file collocation query provider.
399      * Files under the supplied root are normally considered to be collocated.
400      * However the subdirectory <samp>separate<samp> (if it exists) forms its own root.
401      * And the subdirectory <samp>transient</samp> (if it exists) does not form a root,
402      * but any files in there are not considered collocated with anything.
403      */

404     public static CollocationQueryImplementation testCollocationQueryImplementation(File JavaDoc root) {
405         return new TestCollocationQueryImplementation(root);
406     }
407     
408     private static final class TestCollocationQueryImplementation implements CollocationQueryImplementation {
409         
410         private final File JavaDoc root;
411         private final String JavaDoc rootPath;
412         private final File JavaDoc separate;
413         private final String JavaDoc separatePath;
414         private final String JavaDoc transientPath;
415         
416         TestCollocationQueryImplementation(File JavaDoc root) {
417             this.root = root;
418             rootPath = root.getAbsolutePath();
419             separate = new File JavaDoc(root, "separate");
420             separatePath = separate.getAbsolutePath();
421             transientPath = new File JavaDoc(root, "transient").getAbsolutePath();
422         }
423         
424         public boolean areCollocated(File JavaDoc file1, File JavaDoc file2) {
425             File JavaDoc root1 = findRoot(file1);
426             if (root1 == null) {
427                 return false;
428             } else {
429                 return root1.equals(findRoot(file2));
430             }
431         }
432         
433         public File JavaDoc findRoot(File JavaDoc file) {
434             String JavaDoc path = file.getAbsolutePath();
435             if (!path.startsWith(rootPath)) {
436                 return null;
437             }
438             if (path.startsWith(separatePath)) {
439                 return separate;
440             }
441             if (path.startsWith(transientPath)) {
442                 return null;
443             }
444             return root;
445         }
446         
447     }
448     
449     /**
450      * Replace all occurrences of a given string in a file with a new string.
451      * UTF-8 encoding is assumed.
452      * @param f the file to modify
453      * @param from the search string
454      * @param to the replacement string
455      * @return a count of how many occurrences were replaced
456      * @throws IOException in case reading or writing the file failed
457      */

458     public static int replaceInFile(File JavaDoc f, String JavaDoc from, String JavaDoc to) throws IOException JavaDoc {
459         StringBuffer JavaDoc b = new StringBuffer JavaDoc((int)f.length());
460         InputStream JavaDoc is = new FileInputStream JavaDoc(f);
461         try {
462             Reader JavaDoc r = new InputStreamReader JavaDoc(is, "UTF-8");
463             char[] buf = new char[4096];
464             int i;
465             while ((i = r.read(buf)) != -1) {
466                 b.append(buf, 0, i);
467             }
468         } finally {
469             is.close();
470         }
471        String JavaDoc s = b.toString();
472        String JavaDoc rx = "\\Q" + from + "\\E";
473        Pattern JavaDoc patt;
474        try {
475            patt = Pattern.compile(rx);
476        } catch (PatternSyntaxException JavaDoc e) {
477            assert false : e;
478            return -1;
479        }
480        Matcher JavaDoc m = patt.matcher(s);
481        int count = 0;
482        while (m.find()) {
483            count++;
484        }
485        String JavaDoc s2 = s.replaceAll(rx, to);
486        assert s2.length() - s.length() == count * (to.length() - from.length());
487        OutputStream JavaDoc os = new FileOutputStream JavaDoc(f);
488        try {
489            Writer JavaDoc w = new OutputStreamWriter JavaDoc(os, "UTF-8");
490            w.write(s2);
491            w.flush();
492        } finally {
493            os.close();
494        }
495        return count;
496     }
497     
498     public static final class TestPCL implements PropertyChangeListener JavaDoc {
499         
500         public final Set JavaDoc<String JavaDoc> changed = new HashSet JavaDoc<String JavaDoc>();
501         public final Map JavaDoc<String JavaDoc,String JavaDoc> newvals = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
502         public final Map JavaDoc<String JavaDoc,String JavaDoc> oldvals = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
503         
504         public TestPCL() {}
505         
506         public void reset() {
507             changed.clear();
508             newvals.clear();
509             oldvals.clear();
510         }
511         
512         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
513             String JavaDoc prop = evt.getPropertyName();
514             String JavaDoc nue = (String JavaDoc)evt.getNewValue();
515             String JavaDoc old = (String JavaDoc)evt.getOldValue();
516             changed.add(prop);
517             if (prop != null) {
518                 newvals.put(prop, nue);
519                 oldvals.put(prop, old);
520             } else {
521                 assert nue == null : "null prop name -> null new value";
522                 assert old == null : "null prop name -> null old value";
523             }
524         }
525         
526     }
527     
528     /**
529      * Change listener that can be polled.
530      * Handles asynchronous changes.
531      */

532     public static final class TestCL implements ChangeListener JavaDoc {
533         
534         private boolean fired;
535         
536         public TestCL() {}
537         
538         public synchronized void stateChanged(ChangeEvent JavaDoc e) {
539             fired = true;
540             notify();
541         }
542         
543         /**
544          * Check whether a change has occurred by now (do not block).
545          * Also resets the flag so the next call will expect a new change.
546          * @return true if a change has occurred
547          */

548         public synchronized boolean expect() {
549             boolean f = fired;
550             fired = false;
551             return f;
552         }
553         
554         /**
555          * Check whether a change has occurred by now or occurs within some time.
556          * Also resets the flag so the next call will expect a new change.
557          * @param timeout a maximum amount of time to wait, in milliseconds
558          * @return true if a change has occurred
559          */

560         public synchronized boolean expect(long timeout) throws InterruptedException JavaDoc {
561             if (!fired) {
562                 wait(timeout);
563             }
564             return expect();
565         }
566         
567     }
568
569     public static class TestAntArtifact extends AntArtifact {
570
571         private URI JavaDoc[] uris;
572         private Project p;
573         private AntProjectHelper h;
574
575         public TestAntArtifact(URI JavaDoc[] uris, AntProjectHelper h) {
576             this.uris = uris;
577             try {
578                 this.p = ProjectManager.getDefault().findProject(h.getProjectDirectory());
579             } catch ( Exception JavaDoc e) {
580                 e.printStackTrace();
581             }
582             this.h = h;
583         }
584
585         public String JavaDoc getType() {
586             return "multi-jar"; // NOI18N
587
}
588
589         public File JavaDoc getScriptLocation() {
590             return h.resolveFile(GeneratedFilesHelper.BUILD_XML_PATH);
591         }
592
593         public String JavaDoc getTargetName() {
594             return "build"; // NOI18N
595
}
596
597         public String JavaDoc getCleanTargetName() {
598             return "clean"; // NOI18N
599
}
600         
601         public URI JavaDoc[] getArtifactLocations() {
602             return uris;
603         }
604
605         public Project getProject() {
606             return p;
607         }
608
609     }
610
611     public static final class TestMutablePropertyProvider implements PropertyProvider {
612
613         public final Map JavaDoc<String JavaDoc,String JavaDoc> defs;
614         private final List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
615
616         public TestMutablePropertyProvider(Map JavaDoc<String JavaDoc,String JavaDoc> defs) {
617             this.defs = defs;
618         }
619
620         public void mutated() {
621             ChangeEvent JavaDoc ev = new ChangeEvent JavaDoc(this);
622             for (ChangeListener JavaDoc l : listeners) {
623                 l.stateChanged(ev);
624             }
625         }
626
627         public Map JavaDoc<String JavaDoc,String JavaDoc> getProperties() {
628             return defs;
629         }
630
631         public void addChangeListener(ChangeListener JavaDoc l) {
632             listeners.add(l);
633         }
634
635         public void removeChangeListener(ChangeListener JavaDoc l) {
636             listeners.remove(l);
637         }
638
639     }
640
641 }
642
Popular Tags