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: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * Portions Copyrighted 2007 Sun Microsystems, Inc.
038: */
039:
040: package org.netbeans.modules.project.ui;
041:
042: import java.awt.EventQueue;
043: import java.beans.PropertyChangeEvent;
044: import java.lang.ref.WeakReference;
045: import java.net.URL;
046: import java.util.ArrayList;
047: import java.util.EventObject;
048: import java.util.List;
049: import java.util.concurrent.CountDownLatch;
050: import junit.framework.AssertionFailedError;
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.ui.LogicalViewProvider;
057: import org.netbeans.spi.project.ui.ProjectOpenedHook;
058: import org.openide.filesystems.FileObject;
059: import org.openide.filesystems.FileUtil;
060: import org.openide.filesystems.URLMapper;
061: import org.openide.nodes.AbstractNode;
062: import org.openide.nodes.Children;
063: import org.openide.nodes.Node;
064: import org.openide.nodes.NodeEvent;
065: import org.openide.nodes.NodeListener;
066: import org.openide.nodes.NodeMemberEvent;
067: import org.openide.nodes.NodeReorderEvent;
068: import org.openide.util.Lookup;
069: import org.openide.util.lookup.Lookups;
070: import org.openidex.search.SearchInfo;
071:
072: /**
073: *
074: * @author Jaroslav Tulach <jtulach@netbeans.org>
075: */
076: public class ProjectsRootNodePhysicalViewTest extends NbTestCase {
077: CountDownLatch down;
078:
079: public ProjectsRootNodePhysicalViewTest(String testName) {
080: super (testName);
081: }
082:
083: Lookup createLookup(TestSupport.TestProject project, Object instance) {
084: return Lookups.fixed(instance, new LVP());
085: }
086:
087: @Override
088: protected void setUp() throws Exception {
089: clearWorkDir();
090:
091: MockServices.setServices(TestSupport.TestProjectFactory.class);
092:
093: FileObject workDir = FileUtil.toFileObject(getWorkDir());
094: assertNotNull(workDir);
095:
096: down = new CountDownLatch(1);
097:
098: List<URL> list = new ArrayList<URL>();
099: List<ExtIcon> icons = new ArrayList<ExtIcon>();
100: List<String> names = new ArrayList<String>();
101: for (int i = 0; i < 30; i++) {
102: FileObject prj = TestSupport.createTestProject(workDir,
103: "prj" + i);
104: URL url = URLMapper.findURL(prj, URLMapper.EXTERNAL);
105: list.add(url);
106: names.add(url.toExternalForm());
107: icons.add(new ExtIcon());
108: TestSupport.TestProject tmp = (TestSupport.TestProject) ProjectManager
109: .getDefault().findProject(prj);
110: assertNotNull("Project found", tmp);
111: tmp.setLookup(createLookup(tmp,
112: new TestProjectOpenedHookImpl(down)));
113: }
114:
115: OpenProjectListSettings.getInstance().setOpenProjectsURLs(list);
116: OpenProjectListSettings.getInstance()
117: .setOpenProjectsDisplayNames(names);
118: OpenProjectListSettings.getInstance().setOpenProjectsIcons(
119: icons);
120: }
121:
122: @Override
123: protected void tearDown() throws Exception {
124: super .tearDown();
125: }
126:
127: public void testBehaviourOfProjectsLogicNode()
128: throws InterruptedException {
129: Node n = doBehaviourOfProjectsNode();
130:
131: Project p = n.getLookup().lookup(Project.class);
132: assertNotNull("Project is in the node", p);
133:
134: WeakReference<Project> ref = new WeakReference<Project>(p);
135: p = null;
136:
137: // keep just parent
138: n = n.getParentNode();
139:
140: try {
141: assertGC("Cannot be garbage collected while open", ref);
142: throw new IllegalStateException("Cannot be GCed");
143: } catch (AssertionFailedError ok) {
144: // ok
145: }
146:
147: OpenProjectList.getDefault().close(new Project[] { ref.get() },
148: true);
149:
150: assertGC("Can be garbage collected when closed", ref);
151: }
152:
153: private Node doBehaviourOfProjectsNode()
154: throws InterruptedException {
155: Node view = new ProjectsRootNode(ProjectsRootNode.PHYSICAL_VIEW);
156: L listener = new L();
157: view.addNodeListener(listener);
158:
159: assertEquals("30 children", 30, view.getChildren()
160: .getNodesCount());
161: listener.assertEvents("None", 0);
162: assertEquals("No project opened yet", 0,
163: TestProjectOpenedHookImpl.opened);
164:
165: for (Node n : view.getChildren().getNodes()) {
166: TestSupport.TestProject p = n.getLookup().lookup(
167: TestSupport.TestProject.class);
168: assertNull("No project of this type, yet", p);
169: SearchInfo info = n.getLookup().lookup(SearchInfo.class);
170: assertNoRealSearchInfo(n, info);
171: }
172:
173: // let project open code run
174: down.countDown();
175: TestProjectOpenedHookImpl.toOpen.await();
176:
177: assertEquals("All projects opened", 30,
178: TestProjectOpenedHookImpl.opened);
179:
180: OpenProjectList.waitProjectsFullyOpen();
181:
182: for (Node n : view.getChildren().getNodes()) {
183: SearchInfo info = n.getLookup().lookup(SearchInfo.class);
184: assertNoRealSearchInfo(n, info);
185: LogicalView v = n.getLookup().lookup(LogicalView.class);
186: assertEquals("View is not present in physical view", null,
187: v);
188: }
189:
190: listener.assertEvents("Goal is to receive no events at all", 0);
191:
192: return view.getChildren().getNodes()[0];
193: }
194:
195: private static class L implements NodeListener {
196: public List<EventObject> events = new ArrayList<EventObject>();
197:
198: public void childrenAdded(NodeMemberEvent ev) {
199: assertFalse("No event in AWT thread", EventQueue
200: .isDispatchThread());
201: events.add(ev);
202: }
203:
204: public void childrenRemoved(NodeMemberEvent ev) {
205: assertFalse("No event in AWT thread", EventQueue
206: .isDispatchThread());
207: events.add(ev);
208: }
209:
210: public void childrenReordered(NodeReorderEvent ev) {
211: assertFalse("No event in AWT thread", EventQueue
212: .isDispatchThread());
213: events.add(ev);
214: }
215:
216: public void nodeDestroyed(NodeEvent ev) {
217: assertFalse("No event in AWT thread", EventQueue
218: .isDispatchThread());
219: events.add(ev);
220: }
221:
222: public void propertyChange(PropertyChangeEvent evt) {
223: assertFalse("No event in AWT thread", EventQueue
224: .isDispatchThread());
225: events.add(evt);
226: }
227:
228: final void assertEvents(String string, int i) {
229: assertEquals(string + events, i, events.size());
230: events.clear();
231: }
232:
233: }
234:
235: private static class TestProjectOpenedHookImpl extends
236: ProjectOpenedHook {
237:
238: public static CountDownLatch toOpen = new CountDownLatch(30);
239: public static int opened = 0;
240: public static int closed = 0;
241:
242: private CountDownLatch toWaitOn;
243:
244: public TestProjectOpenedHookImpl(CountDownLatch toWaitOn) {
245: this .toWaitOn = toWaitOn;
246: }
247:
248: protected void projectClosed() {
249: closed++;
250: }
251:
252: protected void projectOpened() {
253: if (toWaitOn != null) {
254: try {
255: toWaitOn.await();
256: } catch (InterruptedException ex) {
257: throw new IllegalStateException(ex);
258: }
259: }
260: opened++;
261: toOpen.countDown();
262: }
263:
264: }
265:
266: private static class LVP implements LogicalViewProvider {
267: public Node createLogicalView() {
268: return new LogicalView();
269: }
270:
271: public Node findPath(Node root, Object target) {
272: return null;
273: }
274: }
275:
276: private static class LogicalView extends AbstractNode {
277: public LogicalView() {
278: super (Children.LEAF);
279: }
280: }
281:
282: static void assertNoRealSearchInfo(Node n, SearchInfo info) {
283: if (info != null) {
284: if (info instanceof LazyProject) {
285: // OK
286: } else {
287: fail("No search info at " + n + "\nwas: " + info);
288: }
289: }
290: }
291: }
|