001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.project.ui;
043:
044: import java.io.IOException;
045: import java.net.MalformedURLException;
046: import java.net.URL;
047: import java.util.HashSet;
048: import java.util.Iterator;
049: import java.util.Set;
050: import javax.swing.text.BadLocationException;
051: import org.netbeans.api.project.Project;
052: import org.netbeans.api.project.ProjectManager;
053: import org.netbeans.junit.MockServices;
054: import org.netbeans.junit.NbTestCase;
055: import org.netbeans.modules.project.ui.actions.TestSupport;
056: import org.netbeans.spi.project.AuxiliaryConfiguration;
057: import org.openide.cookies.EditorCookie;
058: import org.openide.filesystems.FileObject;
059: import org.openide.filesystems.FileUtil;
060: import org.openide.filesystems.URLMapper;
061: import org.openide.filesystems.XMLFileSystem;
062: import org.openide.loaders.DataObject;
063: import org.openide.loaders.DataObjectNotFoundException;
064: import org.openide.text.CloneableEditorSupport;
065: import org.openide.util.Lookup;
066: import org.openide.util.lookup.Lookups;
067: import org.openide.windows.CloneableTopComponent;
068: import org.openide.windows.TopComponent;
069: import org.openide.windows.WindowManager;
070: import org.w3c.dom.Element;
071: import org.w3c.dom.NodeList;
072:
073: /** Tests storing and reloading project's documents in case of open/close project.
074: *
075: * @author Jiri Rechtacek
076: */
077: public class ProjectUtilitiesTest extends NbTestCase {
078:
079: /* XXX for some reason this makes tests fail, not sure why:
080: static {
081: System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false");
082: }
083: /**/
084:
085: private static final String NAVIGATOR_MODE = "navigator";
086:
087: DataObject do1_1_open, do1_2_open, do1_3_close, do1_4_close;
088: DataObject do2_1_open;
089: Project project1, project2;
090: Set<DataObject> openFilesSet = new HashSet<DataObject>();
091: TopComponent tc1_1, tc1_2, tc2_1, tc1_1_navigator;
092:
093: public ProjectUtilitiesTest(String testName) {
094: super (testName);
095: }
096:
097: protected boolean runInEQ() {
098: return true;
099: }
100:
101: protected void setUp() throws Exception {
102: super .setUp();
103: MockServices.setServices(TestSupport.TestProjectFactory.class,
104: ProjectUtilitiesDummyWindowManager.class);
105:
106: clearWorkDir();
107:
108: FileObject workDir = FileUtil.toFileObject(getWorkDir());
109:
110: //Mode mode = WindowManager.getDefault ().createWorkspace ("TestHelper").createMode (CloneableEditorSupport.EDITOR_MODE, CloneableEditorSupport.EDITOR_MODE, null);
111:
112: FileObject p1 = TestSupport.createTestProject(workDir,
113: "project1");
114: FileObject f1_1 = p1.createData("f1_1.java");
115: FileObject f1_2 = p1.createData("f1_2.java");
116: FileObject f1_3 = p1.createData("f1_3.java");
117: FileObject f1_4 = p1.createData("f1_4.java");
118: do1_1_open = DataObject.find(f1_1);
119: do1_2_open = DataObject.find(f1_2);
120: do1_3_close = DataObject.find(f1_3);
121: do1_4_close = DataObject.find(f1_4);
122: openFilesSet.add(do1_1_open);
123: openFilesSet.add(do1_2_open);
124:
125: project1 = ProjectManager.getDefault().findProject(p1);
126: ((TestSupport.TestProject) project1).setLookup(Lookups
127: .singleton(TestSupport.createAuxiliaryConfiguration()));
128:
129: FileObject p2 = TestSupport.createTestProject(workDir,
130: "project2");
131: FileObject f2_1 = p2.createData("f2_1.java");
132: do2_1_open = DataObject.find(f2_1);
133:
134: project2 = ProjectManager.getDefault().findProject(p2);
135: ((TestSupport.TestProject) project2).setLookup(Lookups
136: .singleton(TestSupport.createAuxiliaryConfiguration()));
137:
138: //it will be necessary to dock the top components into the "editor" and "navigator" modes, so they need to be created:
139: createMode(CloneableEditorSupport.EDITOR_MODE);
140: createMode(NAVIGATOR_MODE);
141: (tc1_1 = new SimpleTopComponent(do1_1_open,
142: CloneableEditorSupport.EDITOR_MODE)).open();
143: (tc1_2 = new SimpleTopComponent(do1_2_open,
144: CloneableEditorSupport.EDITOR_MODE)).open();
145: (tc2_1 = new SimpleTopComponent(do2_1_open,
146: CloneableEditorSupport.EDITOR_MODE)).open();
147: (tc1_1_navigator = new SimpleTopComponent2(do1_1_open,
148: NAVIGATOR_MODE)).open();
149:
150: ExitDialog.SAVE_ALL_UNCONDITIONALLY = true;
151: }
152:
153: @SuppressWarnings("deprecation")
154: private static void createMode(String name) {
155: WindowManager.getDefault().getWorkspaces()[0].createMode(name,
156: name, null);
157: }
158:
159: public void testCloseAllDocuments() {
160: closeProjectWithOpenedFiles();
161: }
162:
163: private void closeProjectWithOpenedFiles() {
164: AuxiliaryConfiguration aux = project1.getLookup().lookup(
165: AuxiliaryConfiguration.class);
166: assertNotNull(
167: "AuxiliaryConfiguration must be present if project's lookup",
168: aux);
169:
170: Element openFilesEl = aux.getConfigurationFragment(
171: ProjectUtilities.OPEN_FILES_ELEMENT,
172: ProjectUtilities.OPEN_FILES_NS, false);
173: if (openFilesEl != null) {
174: assertEquals("OpenFiles element is empty or null.", 0,
175: openFilesEl.getChildNodes().getLength());
176: }
177:
178: Project[] projects = new Project[] { project1 };
179:
180: if (ProjectUtilities.closeAllDocuments(projects, false)) {
181: OpenProjectList.getDefault().close(projects, false);
182: }
183:
184: openFilesEl = aux.getConfigurationFragment(
185: ProjectUtilities.OPEN_FILES_ELEMENT,
186: ProjectUtilities.OPEN_FILES_NS, false);
187: assertNotNull(
188: "OPEN_FILES_ELEMENT found in the private configuration.",
189: openFilesEl);
190:
191: NodeList list = openFilesEl
192: .getElementsByTagName(ProjectUtilities.FILE_ELEMENT);
193:
194: assertNotNull("FILE_ELEMENT must be present", list);
195: assertTrue(
196: "Same count of FILE_ELEMENTs and open files, elements count "
197: + list.getLength(), openFilesSet.size() == list
198: .getLength());
199:
200: for (int i = 0; i < list.getLength(); i++) {
201: String url = list.item(i).getChildNodes().item(0)
202: .getNodeValue();
203: FileObject fo = null;
204: try {
205: fo = URLMapper.findFileObject(new URL(url));
206: assertNotNull("Found file for URL " + url, fo);
207: DataObject dobj = DataObject.find(fo);
208: assertTrue(dobj
209: + " is present in the set of open files.",
210: openFilesSet.contains(dobj));
211: assertNotSame("The closed file are not present.",
212: do1_3_close, dobj);
213: assertNotSame(
214: "The open file of other project is not present.",
215: do2_1_open, dobj);
216: } catch (MalformedURLException mue) {
217: fail("MalformedURLException in " + url);
218: } catch (DataObjectNotFoundException donfo) {
219: fail("DataObject must exist for " + fo);
220: }
221: }
222:
223: }
224:
225: private void modifyDO(DataObject toModify)
226: throws BadLocationException, IOException {
227: System.err.println("toModify = " + toModify);
228: EditorCookie ec = toModify.getCookie(EditorCookie.class);
229:
230: ec.openDocument().insertString(0, "test", null);
231: }
232:
233: public void testSavingModifiedNotOpenedFiles67526()
234: throws BadLocationException, IOException {
235: AuxiliaryConfiguration aux = project1.getLookup().lookup(
236: AuxiliaryConfiguration.class);
237: assertNotNull(
238: "AuxiliaryConfiguration must be present if project's lookup",
239: aux);
240:
241: Element openFilesEl = aux.getConfigurationFragment(
242: ProjectUtilities.OPEN_FILES_ELEMENT,
243: ProjectUtilities.OPEN_FILES_NS, false);
244: if (openFilesEl != null) {
245: assertEquals("OpenFiles element is empty or null.", 0,
246: openFilesEl.getChildNodes().getLength());
247: }
248:
249: modifyDO(do1_4_close);
250:
251: Project[] projects = new Project[] { project1 };
252:
253: if (ProjectUtilities.closeAllDocuments(projects, true)) {
254: OpenProjectList.getDefault().close(projects, true);
255: }
256:
257: assertFalse("the do1_4_close not modified", do1_4_close
258: .isModified());
259:
260: openFilesEl = aux.getConfigurationFragment(
261: ProjectUtilities.OPEN_FILES_ELEMENT,
262: ProjectUtilities.OPEN_FILES_NS, false);
263: assertNotNull(
264: "OPEN_FILES_ELEMENT found in the private configuration.",
265: openFilesEl);
266:
267: NodeList list = openFilesEl
268: .getElementsByTagName(ProjectUtilities.FILE_ELEMENT);
269:
270: assertNotNull("FILE_ELEMENT must be present", list);
271: assertTrue(
272: "Same count of FILE_ELEMENTs and open files, elements count "
273: + list.getLength(), openFilesSet.size() == list
274: .getLength());
275:
276: for (int i = 0; i < list.getLength(); i++) {
277: String url = list.item(i).getChildNodes().item(0)
278: .getNodeValue();
279: FileObject fo = null;
280: try {
281: fo = URLMapper.findFileObject(new URL(url));
282: assertNotNull("Found file for URL " + url, fo);
283: DataObject dobj = DataObject.find(fo);
284: System.err.println("openFilesSet = " + openFilesSet);
285: assertTrue(dobj
286: + " is present in the set of open files.",
287: openFilesSet.contains(dobj));
288: assertNotSame("The closed file are not present.",
289: do1_3_close, dobj);
290: assertNotSame(
291: "The open file of other project is not present.",
292: do2_1_open, dobj);
293: } catch (MalformedURLException mue) {
294: fail("MalformedURLException in " + url);
295: } catch (DataObjectNotFoundException donfo) {
296: fail("DataObject must exist for " + fo);
297: }
298: }
299: }
300:
301: public void testCloseAndOpenProjectAndClosedWithoutOpenFiles() {
302: closeProjectWithOpenedFiles();
303:
304: OpenProjectList.getDefault().open(project1, false);
305:
306: Iterator/*<TopComponent>*/openTCs = WindowManager.getDefault()
307: .getRegistry().getOpened().iterator();
308: while (openTCs.hasNext()) {
309: assertTrue("TopComponent has been closed successfully.",
310: ((TopComponent) openTCs.next()).close());
311: }
312:
313: if (ProjectUtilities.closeAllDocuments(
314: new Project[] { project1 }, false)) {
315: OpenProjectList.getDefault().close(
316: new Project[] { project1 }, false);
317: }
318:
319: AuxiliaryConfiguration aux = project1.getLookup().lookup(
320: AuxiliaryConfiguration.class);
321: Element openFilesEl = aux.getConfigurationFragment(
322: ProjectUtilities.OPEN_FILES_ELEMENT,
323: ProjectUtilities.OPEN_FILES_NS, false);
324: assertNull(
325: "OPEN_FILES_ELEMENT not found in the private configuration.",
326: openFilesEl);
327:
328: assertFalse("Project1 must be closed.", OpenProjectList
329: .getDefault().isOpen(project1));
330: }
331:
332: public void testCanUseFileName() throws Exception {
333: FileObject d = FileUtil.toFileObject(getWorkDir());
334: FileObject p1 = d.getFileObject("project1");
335: assertNotNull(p1);
336: assertNull("normal file addition", ProjectUtilities
337: .canUseFileName(p1, null, "foo", "java", false));
338: assertNull("normal file addition with no extension is OK",
339: ProjectUtilities.canUseFileName(p1, null, "foo", null,
340: false));
341: assertNull("normal file addition in an existing subdir",
342: ProjectUtilities.canUseFileName(d, "project1", "foo",
343: "java", false));
344: assertNull("normal file addition in a new subdir",
345: ProjectUtilities.canUseFileName(d, "dir", "foo",
346: "java", false));
347: //assertNotNull("no target name", ProjectUtilities.canUseFileName(d, "dir", null, "java"));
348: assertNotNull("no target folder", ProjectUtilities
349: .canUseFileName(null, "dir", "foo", "java", false));
350: assertNotNull("file already exists", ProjectUtilities
351: .canUseFileName(p1, null, "f1_1", "java", false));
352: assertNotNull("file already exists in subdir", ProjectUtilities
353: .canUseFileName(d, "project1", "f1_1", "java", false));
354: assertNull("similar file already exists in subdir",
355: ProjectUtilities.canUseFileName(d, "project1", "f1_1",
356: "properties", false));
357: assertNull("similar file already exists in subdir",
358: ProjectUtilities.canUseFileName(d, "project1", "f1_1",
359: null, false));
360: d = new XMLFileSystem().getRoot();
361: assertNotNull("FS is r/o", ProjectUtilities.canUseFileName(d,
362: null, "foo", "java", false));
363: // #59876: deal with non-disk-based filesystems sensibly
364: d = FileUtil.createMemoryFileSystem().getRoot();
365: d.createData("bar.java");
366: FileUtil.createData(d, "sub/dir/foo.java");
367: assertNull("can create file in non-disk FS", ProjectUtilities
368: .canUseFileName(d, null, "foo", "java", false));
369: assertNotNull("file already exists", ProjectUtilities
370: .canUseFileName(d, null, "bar", "java", false));
371: assertNotNull("file already exists in subsubdir",
372: ProjectUtilities.canUseFileName(d, "sub/dir", "foo",
373: "java", false));
374: assertNull("can otherwise create file in subsubdir",
375: ProjectUtilities.canUseFileName(d, "sub/dir", "bar",
376: "java", false));
377: //#66792: allow to create whole directory tree at once using Folder Template:
378: assertNull("can create directory subtree", ProjectUtilities
379: .canUseFileName(d, null, "a/b/c", null, true));
380: //#59654: do not allow slash and backslash for common templates:
381: assertNotNull("cannot create file with slashes",
382: ProjectUtilities.canUseFileName(d, null, "a/b/c",
383: "txt", false));
384: assertNotNull("cannot create file with backslashes",
385: ProjectUtilities.canUseFileName(d, null, "a\\b\\c",
386: "txt", false));
387: }
388:
389: public void testNavigatorIsNotClosed() throws Exception {
390: closeProjectWithOpenedFiles();
391:
392: assertFalse(tc1_1.isOpened());
393: assertFalse(tc1_2.isOpened());
394: assertTrue(tc1_1_navigator.isOpened());
395: }
396:
397: private static class SimpleTopComponent extends
398: CloneableTopComponent {
399: private Object content;
400: private String modeToDockInto;
401:
402: public SimpleTopComponent(Object obj, String modeToDockInto) {
403: this .content = obj;
404: this .modeToDockInto = modeToDockInto;
405: setName(obj.toString());
406: }
407:
408: public Lookup getLookup() {
409: return Lookups.singleton(content);
410: }
411:
412: public void open() {
413: super .open();
414: WindowManager.getDefault().findMode(modeToDockInto)
415: .dockInto(this );
416: }
417: }
418:
419: private static class SimpleTopComponent2 extends TopComponent {
420: private Object content;
421: private String modeToDockInto;
422:
423: public SimpleTopComponent2(Object obj, String modeToDockInto) {
424: this .content = obj;
425: this .modeToDockInto = modeToDockInto;
426: setName(obj.toString());
427: }
428:
429: public Lookup getLookup() {
430: return Lookups.singleton(content);
431: }
432:
433: public void open() {
434: super.open();
435: WindowManager.getDefault().findMode(modeToDockInto)
436: .dockInto(this);
437: }
438: }
439:
440: }
|