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.openide.nodes;
043:
044: import com.sun.org.apache.bcel.internal.generic.ARRAYLENGTH;
045: import junit.framework.*;
046: import junit.textui.TestRunner;
047: import java.util.*;
048: import org.openide.cookies.EditCookie;
049: import org.openide.cookies.OpenCookie;
050: import org.openide.cookies.SaveCookie;
051: import org.openide.nodes.*;
052:
053: import org.netbeans.junit.*;
054: import javax.swing.event.ChangeListener;
055: import org.openide.util.Lookup;
056: import org.openide.util.LookupEvent;
057: import org.openide.util.LookupListener;
058: import org.openide.util.lookup.InstanceContent;
059:
060: /** Tests behaviour of CookieSet.
061: *
062: * @author Jaroslav Tulach
063: */
064: public class CookieSetTest extends NbTestCase {
065: public CookieSetTest(String name) {
066: super (name);
067: }
068:
069: public void testAddRemove() throws Exception {
070: CookieSet set = new CookieSet();
071: L l = new L();
072: set.addChangeListener(l);
073:
074: C1 a1 = new C1();
075: C1 c1 = new C1();
076: C2 c2 = new C2();
077:
078: set.add(c1);
079:
080: assertEquals("One change expected", l.cnt(), 1);
081: assertEquals("Node.Cookie", c1, set
082: .getCookie(Node.Cookie.class));
083:
084: // replacing the c1 with a1
085: set.add(a1);
086:
087: assertEquals("One change expected", l.cnt(), 1);
088: assertEquals("Node.Cookie", a1, set
089: .getCookie(Node.Cookie.class));
090:
091: // removing the cookie a1 leaves the set empty
092: set.remove(a1);
093: assertEquals("One change expected", l.cnt(), 1);
094: assertNull("Node.Cookie", set.getCookie(Node.Cookie.class));
095:
096: // adding c1 again
097: set.add(c1);
098: assertEquals("One change expected", l.cnt(), 1);
099: assertEquals("Node.Cookie", c1, set
100: .getCookie(Node.Cookie.class));
101:
102: // and c2
103: set.add(c2);
104: assertEquals("One change expected", l.cnt(), 1);
105: assertEquals("C1 cookie", c1, set.getCookie(Node.Cookie.class));
106: assertEquals("C2 index", c2, set.getCookie(Index.class));
107:
108: // removing c2 leaves to null on Index cookie
109: set.remove(c2);
110: assertEquals("One change expected", l.cnt(), 1);
111: assertEquals("C1 cookie", c1, set.getCookie(Node.Cookie.class));
112: assertNull("Null index", set.getCookie(Index.class));
113:
114: assertCookieSet(set);
115: }
116:
117: /** Adding smaller and bigger and removing smaller.
118: */
119: public void testAddSBremoveS() {
120: CookieSet set = new CookieSet();
121: C1 c1 = new C1();
122: C2 c2 = new C2();
123:
124: // after adding c1
125: set.add(c1);
126:
127: // adding c2 and removing c1
128: set.add(c2);
129: set.remove(c1);
130:
131: assertEquals("C2 index", c2, set.getCookie(Index.class));
132: assertEquals("C2 cookie", c2, set.getCookie(Node.Cookie.class));
133: assertCookieSet(set);
134: }
135:
136: /** Adding bigger and smaller and removing bigger.
137: */
138: public void testAddBSremoveB() {
139: CookieSet set = new CookieSet();
140: C1 c1 = new C1();
141: C2 c2 = new C2();
142:
143: // after adding c1
144: set.add(c2);
145: assertEquals("Bigger registered", c2, set
146: .getCookie(Node.Cookie.class));
147:
148: // adding c2 and removing c1
149: set.add(c1);
150:
151: assertEquals("Smaller takes preceedence", c1, set
152: .getCookie(Node.Cookie.class));
153:
154: set.remove(c2);
155:
156: assertEquals("C1 cookie", c1, set.getCookie(Node.Cookie.class));
157: assertEquals("Null index", null, set.getCookie(Index.class));
158:
159: assertCookieSet(set);
160: }
161:
162: /** Tests behaviour of modifications via factory.
163: */
164: public void testFactoryAddRemove() {
165: L l = new L();
166: CookieSet set = new CookieSet();
167: set.addChangeListener(l);
168:
169: set.add(C1.class, l);
170:
171: assertEquals("One change", l.cnt(), 1);
172: Node.Cookie obj = set.getCookie(C1.class);
173: if (!(obj instanceof C1)) {
174: fail("Instance created by factory is wrong");
175: }
176:
177: if (obj != set.getCookie(C1.class)) {
178: fail("New cookie created even it should not");
179: }
180:
181: if (obj != set.getCookie(Node.Cookie.class)) {
182: fail("C1 is not registered as cookie");
183: }
184:
185: // replace
186: set.add(C1.class, l);
187: assertEquals("One change", l.cnt(), 1);
188:
189: if (obj == set.getCookie(C1.class)) {
190: fail("Factory changed, but cookie remains");
191: }
192:
193: obj = set.getCookie(C1.class);
194:
195: // remove
196: set.remove(obj);
197: assertNotNull("Factory cookies cannot directly be removed", set
198: .getCookie(C1.class));
199:
200: // remove of a factory
201: set.remove(C1.class, l);
202: assertNull("Removed factory still returns a cookie", set
203: .getCookie(C1.class));
204:
205: assertCookieSet(set);
206: }
207:
208: /** Tests behaviour of modifications via factory.
209: */
210: public void testFactoryAddRemoveInherit() {
211: L l = new L();
212: CookieSet set = new CookieSet();
213: set.addChangeListener(l);
214:
215: set.add(C1.class, l);
216: set.add(Node.Cookie.class, l);
217:
218: assertNull("Nobody registered as C2", set.getCookie(C2.class));
219:
220: {
221: Node.Cookie cookie = set.getCookie(Node.Cookie.class);
222: if (!(cookie instanceof C2)) {
223: fail("factory provides cookie C2 for Node.Cookie");
224: }
225: }
226:
227: {
228: Node.Cookie c1 = set.getCookie(C1.class);
229: assertNotNull(c1);
230: assertEquals("Factory provides C1 for C1 class", c1
231: .getClass(), C1.class);
232: }
233:
234: assertNull("Still nobody registered as C2", set
235: .getCookie(C2.class));
236:
237: assertCookieSet(set);
238: }
239:
240: public void testCookieSetThruLookupReturnsTheSame()
241: throws Exception {
242: doCookieSetTestsToSimulateIssue47411(Node.Cookie.class, false);
243: }
244:
245: public void testCookieSetThruLookupReturnsTheSameEvenWhenQueriedForLarger()
246: throws Exception {
247: doCookieSetTestsToSimulateIssue47411(Index.class, false);
248: }
249:
250: public void testCookieSetThruLookupReturnsTheSameWithFilter()
251: throws Exception {
252: doCookieSetTestsToSimulateIssue47411(Node.Cookie.class, true);
253: }
254:
255: public void testCookieSetThruLookupReturnsTheSameEvenWhenQueriedForLargerWithFilter()
256: throws Exception {
257: doCookieSetTestsToSimulateIssue47411(Index.class, true);
258: }
259:
260: private void doCookieSetTestsToSimulateIssue47411(Class firstQuery,
261: boolean filter) throws Exception {
262: AbstractNode an = new AbstractNode(Children.LEAF);
263: CookieSet set = new CookieSet();
264: an.setCookieSet(set);
265:
266: Node n = filter ? new FilterNode(an) : an;
267:
268: C1 c1 = new C1();
269: C2 c2 = new C2();
270:
271: // after adding c1
272: set.add(c2);
273: assertEquals("Bigger registered", c2, set.getCookie(firstQuery));
274: assertEquals("Bigger in lookup", c2, n.getLookup().lookup(
275: firstQuery));
276:
277: // adding c2 and removing c1
278: set.add(c1);
279: assertEquals("Smaller takes preceedence", c1, set
280: .getCookie(Node.Cookie.class));
281: assertEquals("Smaller even in lookup", c1, n.getLookup()
282: .lookup(Node.Cookie.class));
283: assertCookieSet(set);
284: }
285:
286: public void testCookieSetThruLookupImprovedVersionIssue47411()
287: throws Exception {
288: doCookieSetThruLookupImprovedVersionIssue47411(false);
289: }
290:
291: public void testCookieSetThruLookupImprovedVersionWithFitlerIssue47411()
292: throws Exception {
293: doCookieSetThruLookupImprovedVersionIssue47411(true);
294: }
295:
296: private void doCookieSetThruLookupImprovedVersionIssue47411(
297: boolean filter) throws Exception {
298: AbstractNode node = new AbstractNode(Children.LEAF);
299: CookieSet set = new CookieSet();
300: node.setCookieSet(set);
301:
302: Node an = filter ? new FilterNode(node) : node;
303:
304: class X implements org.openide.cookies.OpenCookie,
305: org.openide.cookies.EditCookie {
306: public void open() {
307: }
308:
309: public void edit() {
310: }
311: }
312: X x = new X();
313:
314: class A implements org.openide.cookies.OpenCookie {
315: public void open() {
316: }
317: }
318: A a = new A();
319:
320: set.add(a);
321: set.add(x);
322:
323: Object edit = an.getLookup().lookup(
324: org.openide.cookies.EditCookie.class);
325: assertEquals("X has edit", x, edit);
326:
327: Object open = an.getLookup().lookup(
328: org.openide.cookies.OpenCookie.class);
329:
330: assertEquals("Just verify that CookieSet returns A", a, set
331: .getCookie(org.openide.cookies.OpenCookie.class));
332: assertEquals("A has open", a, open);
333:
334: assertEquals(null, an.getLookup().lookup(SaveCookie.class));
335: assertEquals(a, an.getLookup().lookup(OpenCookie.class));
336: assertEquals(x, an.getLookup().lookup(EditCookie.class));
337: assertCookieSet(set);
338: }
339:
340: private static void assertCookieSet(CookieSet en) {
341: if (en.getCookie(Node.Cookie.class) == null) {
342: assertEquals("Should be empty", 0, en.getLookup()
343: .lookupAll(Node.Cookie.class).size());
344: return;
345: }
346:
347: Lookup.Result<Node.Cookie> all = en.getLookup().lookupResult(
348: Node.Cookie.class);
349: int cnt = 0;
350: for (Class<? extends Node.Cookie> c : all.allClasses()) {
351: Object o = en.getLookup().lookup(c);
352: assertEquals("Query for " + c, o, en.getCookie(c));
353: cnt++;
354: }
355:
356: if (cnt == 0) {
357: fail("There shall be at least one object in lookup: " + cnt);
358: }
359: }
360:
361: public void testOneChangeInLookupWhenAddingMultipleElements()
362: throws Exception {
363: CookieSet general = CookieSet.createGeneric(null);
364:
365: L listener = new L();
366: Lookup.Result<String> res = general.getLookup().lookupResult(
367: String.class);
368: res.addLookupListener(listener);
369: res.allItems();
370:
371: assertEquals("No change", 0, listener.cnt());
372:
373: general.assign(String.class, "Ahoj", "Jardo");
374:
375: assertEquals("One change", 1, listener.cnt());
376: assertEquals("Two items", 2, res.allItems().size());
377:
378: general.assign(String.class, "Ahoj", "Jardo");
379: assertEquals("No change", 0, listener.cnt());
380: assertEquals("Still two items", 2, res.allItems().size());
381:
382: general.assign(String.class, "Ahoj");
383: assertEquals("Yet one change", 1, listener.cnt());
384: assertEquals("One item", 1, res.allItems().size());
385: }
386:
387: public void testOneChangeInLookupWhenAddingMultipleElementsWithBefore()
388: throws Exception {
389: class B implements CookieSet.Before {
390: CookieSet general;
391: private String[] asg;
392:
393: public void assign(String... arr) {
394: asg = arr;
395: }
396:
397: public void beforeLookup(Class<?> c) {
398: if (asg != null) {
399: general.assign(String.class, asg);
400: asg = null;
401: }
402: }
403: }
404: B b = new B();
405:
406: b.general = CookieSet.createGeneric(b);
407:
408: L listener = new L();
409: Lookup.Result<String> res = b.general.getLookup().lookupResult(
410: String.class);
411: res.addLookupListener(listener);
412: res.allItems();
413:
414: assertEquals("No change", 0, listener.cnt());
415:
416: b.assign("Ahoj", "Jardo");
417:
418: assertEquals("Two items", 2, res.allItems().size());
419: assertEquals("One change", 1, listener.cnt());
420:
421: b.assign("Ahoj", "Jardo");
422: assertEquals("Still two items", 2, res.allItems().size());
423: assertEquals("No change", 0, listener.cnt());
424:
425: b.assign("Ahoj");
426: assertEquals("One item", 1, res.allItems().size());
427: assertEquals("Yet one change", 1, listener.cnt());
428: }
429:
430: public void testStackOverFlowOnAssign() throws Exception {
431: class B implements CookieSet.Before {
432: CookieSet g = CookieSet.createGeneric(this );
433:
434: public void beforeLookup(Class<?> clazz) {
435: Class<? extends Node.Cookie> c = clazz
436: .asSubclass(Node.Cookie.class);
437: g.getCookie(c);
438: }
439: }
440: B b = new B();
441:
442: class C implements Node.Cookie {
443: }
444:
445: b.g.assign(C.class, new C());
446: }
447:
448: /** Change listener.
449: */
450: private static final class L extends Object implements
451: LookupListener, ChangeListener, CookieSet.Factory {
452: private int count;
453:
454: public void stateChanged(
455: javax.swing.event.ChangeEvent changeEvent) {
456: count++;
457: }
458:
459: /** Gets and clears the count.
460: */
461: public int cnt() {
462: int c = count;
463: count = 0;
464: return c;
465: }
466:
467: /** Creates a Node.Cookie of given class. The method
468: * may be called more than once.
469: */
470: public Node.Cookie createCookie(Class klass) {
471: if (klass == C1.class) {
472: return new C1();
473: }
474: return new C2();
475: }
476:
477: public void resultChanged(LookupEvent ev) {
478: count++;
479: }
480:
481: }
482:
483: /** A simple cookie.
484: */
485: private static class C1 implements Node.Cookie {
486: }
487:
488: /** A complicated cookie.
489: */
490: private static final class C2 extends C1 implements Index {
491:
492: /** Get the index of a given node.
493: * @param node node to find index of
494: * @return index of the node, or <code>-1</code> if no such node was found
495: */
496: public int indexOf(Node node) {
497: return 0;
498: }
499:
500: /** Move an element up.
501: * @param x index of element to move up
502: * @exception IndexOutOfBoundsException if an index is out of bounds
503: */
504: public void moveUp(int x) {
505: }
506:
507: /** Get the child nodes.
508: * @return array of nodes that can be sorted by this index
509: */
510: public Node[] getNodes() {
511: return null;
512: }
513:
514: /** Move an element down.
515: * @param x index of element to move down
516: * @exception IndexOutOfBoundsException if an index is out of bounds
517: */
518: public void moveDown(int x) {
519: }
520:
521: /** Invoke a dialog for reordering the children.
522: */
523: public void reorder() {
524: }
525:
526: /** Exchange two elements.
527: * @param x position of the first element
528: * @param y position of the second element
529: * @exception IndexOutOfBoundsException if an index is out of bounds
530: */
531: public void exchange(int x, int y) {
532: }
533:
534: /** Remove a listener from the listener list.
535: *
536: * @param chl listener to remove
537: */
538: public void removeChangeListener(ChangeListener chl) {
539: }
540:
541: /** Get the number of nodes.
542: * @return the count
543: */
544: public int getNodesCount() {
545: return 0;
546: }
547:
548: /** Add a new listener to the listener list. The listener will be notified of
549: * any change in the order of the nodes.
550: *
551: * @param chl new listener
552: */
553: public void addChangeListener(ChangeListener chl) {
554: }
555:
556: /** Reorder all children with a given permutation.
557: * @param perm permutation with the length of current nodes
558: * @exception IllegalArgumentException if the permutation is not valid
559: */
560: public void reorder(int[] perm) {
561: }
562:
563: /** Move the element at the <code>x</code>-th position to the <code>y</code>-th position. All
564: * elements after the <code>y</code>-th position are moved down.
565: *
566: * @param x the position to remove the element from
567: * @param y the position to insert the element to
568: * @exception IndexOutOfBoundsException if an index is out of bounds
569: */
570: public void move(int x, int y) {
571: }
572: };
573: }
|