Added
Link Here
|
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-2007 Sun |
17 |
* Microsystems, Inc. All Rights Reserved. |
18 |
*/ |
19 |
package org.openide.nodes; |
20 |
|
21 |
import java.awt.EventQueue; |
22 |
import java.beans.*; |
23 |
import java.util.*; |
24 |
import junit.framework.TestCase; |
25 |
import org.openide.nodes.*; |
26 |
import org.openide.nodes.NodeAdapter; |
27 |
import org.openide.util.NbBundle; |
28 |
|
29 |
/** Test for AsynchChildren |
30 |
* |
31 |
* @author Tim Boudreau |
32 |
*/ |
33 |
public class ChildFactoryTest extends TestCase { |
34 |
|
35 |
public ChildFactoryTest(String name) { |
36 |
super(name); |
37 |
} |
38 |
|
39 |
private ProviderImpl factory; |
40 |
private BatchProviderImpl factory2; |
41 |
private AsynchChildren kids2; |
42 |
private Node node2; |
43 |
private AsynchChildren kids; |
44 |
private Node node; |
45 |
public void setUp() throws Exception { |
46 |
factory = new ProviderImpl(); |
47 |
kids = new AsynchChildren (factory); |
48 |
node = new AbstractNode (kids); |
49 |
|
50 |
factory2 = new BatchProviderImpl(); |
51 |
kids2 = new AsynchChildren (factory2); |
52 |
node2 = new AbstractNode (kids2); |
53 |
} |
54 |
|
55 |
public void testChildrenCreate() { |
56 |
System.out.println("testChildrenCreate"); |
57 |
ChildFactory f = new ProviderImpl(); |
58 |
Children kids = Children.create (f, true); |
59 |
assertTrue (kids instanceof AsynchChildren); |
60 |
|
61 |
ChildFactory ff = new ProviderImpl(); |
62 |
Children kids2 = Children.create (ff, false); |
63 |
assertFalse (kids2 instanceof AsynchChildren); |
64 |
assertTrue (kids2 instanceof SynchChildren); |
65 |
|
66 |
RuntimeException e = null; |
67 |
Children kids3 = null; |
68 |
try { |
69 |
kids3 = Children.create (ff, true); |
70 |
} catch (RuntimeException ex) { |
71 |
e = ex; |
72 |
} |
73 |
assertNull (kids3); |
74 |
assertNotNull ("Exception should have been thrown creating two " + |
75 |
"Children objects over the same ChildFactory", e); |
76 |
} |
77 |
|
78 |
//A word of caution re adding tests: |
79 |
//Almost anything (getNodes(), justCreateNodes(), etc. can trigger a |
80 |
//fresh call to Children.addNotify(). Any test that expects a synchronous |
81 |
//change in the child nodes as a result of having triggered a call |
82 |
//to setKeys() is probably testing a race condition, not the behavior |
83 |
//of the children implementation |
84 |
|
85 |
public void testGetNodesWaits() throws Exception { |
86 |
System.out.println("testGetNodesWaits"); |
87 |
factory.wait = false; |
88 |
kids.getNodes (false); |
89 |
synchronized (factory.lock) { |
90 |
factory.lock.wait (300); |
91 |
} |
92 |
Thread.currentThread().yield(); |
93 |
new NL (node); |
94 |
Node[] n = kids.getNodes(true); |
95 |
assertEquals (4, n.length); |
96 |
} |
97 |
|
98 |
public void testInitialNodeIsWaitNode() throws Exception { |
99 |
System.out.println("testInitialNodeIsWaitNode"); |
100 |
factory.wait = true; |
101 |
kids.addNotify(); |
102 |
Node[] n = kids.getNodes(false); |
103 |
factory.wait = false; |
104 |
assertEquals (1, n.length); |
105 |
assertEquals (NbBundle.getMessage(AsynchChildren.class, "LBL_WAIT"), |
106 |
n[0].getDisplayName()); |
107 |
factory.wait = false; |
108 |
synchronized (factory) { |
109 |
factory.wait (2000); |
110 |
} |
111 |
for (int i = 0; i < 5 && n.length != 4; i++) { |
112 |
n = kids.getNodes(true); |
113 |
java.lang.Thread.currentThread().yield(); |
114 |
} |
115 |
assertEquals (4, n.length); |
116 |
} |
117 |
|
118 |
public void testBatch() throws Exception { |
119 |
System.out.println("testBatch"); |
120 |
kids2.addNotify(); |
121 |
Thread.currentThread().yield(); |
122 |
synchronized (factory2.lock) { |
123 |
factory2.lock.notifyAll(); |
124 |
} |
125 |
new NL (node2); |
126 |
Node[] n = n = kids2.getNodes(true); |
127 |
assertEquals (4, n.length); |
128 |
assertEquals (2, factory2.callCount); |
129 |
} |
130 |
|
131 |
public void testSynchChildren() throws Exception { |
132 |
System.out.println("testSynchChildren"); |
133 |
final SynchProviderImpl factory = new SynchProviderImpl(); |
134 |
final Children ch = Children.create (factory, false); |
135 |
assertTrue (ch instanceof SynchChildren); |
136 |
factory.assertCreateKeysNotCalled(); |
137 |
factory.assertCreateNodesForKeyNotCalled(); |
138 |
final Node nd = new AbstractNode (ch); |
139 |
NodeAdapter adap = new NodeAdapter() {}; |
140 |
nd.addNodeListener (adap); |
141 |
|
142 |
EventQueue.invokeAndWait (new Runnable() { |
143 |
public void run() { |
144 |
ch.getNodes(true); |
145 |
} |
146 |
}); |
147 |
((SynchChildren) ch).active = true; |
148 |
synchronized (factory) { |
149 |
factory.wait (1000); |
150 |
} |
151 |
factory.assertCreateKeysCalled(); |
152 |
factory.assertCreateNodesForKeyCalled(); |
153 |
Node[] nodes = nd.getChildren().getNodes(true); |
154 |
assertEquals (factory.CONTENTS1.size(), nodes.length); |
155 |
int ix = 0; |
156 |
for (String s : factory.CONTENTS1) { |
157 |
assertEquals (s, nodes[ix].getName()); |
158 |
ix++; |
159 |
} |
160 |
factory.switchChildren(); |
161 |
nodes = nd.getChildren().getNodes(true); |
162 |
assertEquals (factory.CONTENTS2.size(), nodes.length); |
163 |
ix = 0; |
164 |
for (String s : factory.CONTENTS2) { |
165 |
assertEquals (s, nodes[ix].getName()); |
166 |
ix++; |
167 |
} |
168 |
} |
169 |
|
170 |
public void testCancel() throws Exception { |
171 |
System.out.println("testCancel"); |
172 |
Thread.interrupted(); |
173 |
factory.wait = true; |
174 |
kids.addNotify(); |
175 |
Thread.currentThread().yield(); |
176 |
synchronized (factory.lock) { |
177 |
factory.lock.wait (500); |
178 |
} |
179 |
kids.removeNotify(); |
180 |
factory.wait = false; |
181 |
synchronized (factory) { |
182 |
factory.wait (2000); |
183 |
} |
184 |
assertTrue (kids.cancelled); |
185 |
assertTrue (factory.cancelled); |
186 |
} |
187 |
|
188 |
static final class ProviderImpl extends ChildFactory <String> { |
189 |
Object lock = new Object(); |
190 |
volatile boolean wait = false; |
191 |
|
192 |
public Node[] createNodesForKey(String key) { |
193 |
AbstractNode nd = new AbstractNode (Children.LEAF); |
194 |
nd.setDisplayName (key); |
195 |
return new Node[] { nd }; |
196 |
} |
197 |
|
198 |
boolean cancelled = false; |
199 |
public boolean createKeys(List <String> result) { |
200 |
try { |
201 |
while (wait) { |
202 |
Thread.currentThread().yield(); |
203 |
} |
204 |
synchronized (lock) { |
205 |
lock.notifyAll(); |
206 |
} |
207 |
if (Thread.interrupted()) { |
208 |
cancelled = true; |
209 |
return true; |
210 |
} |
211 |
result.add ("A"); |
212 |
result.add ("B"); |
213 |
result.add ("C"); |
214 |
result.add ("D"); |
215 |
if (Thread.interrupted()) { |
216 |
cancelled = true; |
217 |
} |
218 |
return true; |
219 |
} finally { |
220 |
synchronized (this) { |
221 |
notifyAll(); |
222 |
} |
223 |
} |
224 |
} |
225 |
} |
226 |
|
227 |
static final class BatchProviderImpl extends ChildFactory <String> { |
228 |
boolean firstCycle = true; |
229 |
|
230 |
public Node[] createNodesForKey(String key) { |
231 |
AbstractNode nd = new AbstractNode (Children.LEAF); |
232 |
nd.setDisplayName (key); |
233 |
return new Node[] { nd }; |
234 |
} |
235 |
|
236 |
Object lock = new Object(); |
237 |
int callCount = 0; |
238 |
public boolean createKeys(List <String> result) { |
239 |
callCount++; |
240 |
synchronized (lock) { |
241 |
try { |
242 |
lock.wait(500); |
243 |
} catch (InterruptedException ex) { |
244 |
//re-interrupt |
245 |
Thread.currentThread().interrupt(); |
246 |
} |
247 |
} |
248 |
if (Thread.interrupted()) { |
249 |
return true; |
250 |
} |
251 |
boolean wasFirstCycle = firstCycle; |
252 |
if (wasFirstCycle) { |
253 |
result.add ("A"); |
254 |
result.add ("B"); |
255 |
firstCycle = false; |
256 |
return false; |
257 |
} else { |
258 |
result.add ("C"); |
259 |
result.add ("D"); |
260 |
} |
261 |
if (Thread.interrupted()) { |
262 |
return true; |
263 |
} |
264 |
synchronized (this) { |
265 |
notifyAll(); |
266 |
} |
267 |
return true; |
268 |
} |
269 |
} |
270 |
|
271 |
private static final class NL implements NodeListener { |
272 |
NL (Node n) { |
273 |
n.addNodeListener (this); |
274 |
try { |
275 |
waitFor(); |
276 |
} catch (InterruptedException ex) { |
277 |
Thread.currentThread().interrupt(); |
278 |
} catch (Exception e) { |
279 |
throw new Error (e); |
280 |
} |
281 |
} |
282 |
|
283 |
NL () { |
284 |
|
285 |
} |
286 |
|
287 |
public void childrenAdded(NodeMemberEvent ev) { |
288 |
go(); |
289 |
} |
290 |
|
291 |
public void childrenRemoved(NodeMemberEvent ev) { |
292 |
go(); |
293 |
} |
294 |
|
295 |
public void childrenReordered(NodeReorderEvent ev) { |
296 |
go(); |
297 |
} |
298 |
|
299 |
public void nodeDestroyed(NodeEvent ev) { |
300 |
} |
301 |
|
302 |
public void propertyChange(PropertyChangeEvent arg0) { |
303 |
} |
304 |
|
305 |
private void go() { |
306 |
synchronized (this) { |
307 |
notifyAll(); |
308 |
} |
309 |
} |
310 |
|
311 |
void waitFor() throws Exception { |
312 |
System.err.println("Enter waitfor"); |
313 |
synchronized (this) { |
314 |
wait (1000); |
315 |
} |
316 |
} |
317 |
} |
318 |
|
319 |
private static final class SynchProviderImpl extends ChildFactory <String> { |
320 |
static List <String> CONTENTS1 = Arrays.<String>asList (new String[] { |
321 |
"One", "Two", "Three", "Four" |
322 |
}); |
323 |
static List <String> CONTENTS2 = Arrays.<String>asList (new String[] { |
324 |
"Five", "Six", "Seven", "Eight", "Nine" |
325 |
}); |
326 |
|
327 |
boolean createNodesForKeyCalled = false; |
328 |
public Node[] createNodesForKey(String key) { |
329 |
createNodesForKeyCalled = true; |
330 |
Node result = new AbstractNode(Children.LEAF); |
331 |
result.setDisplayName (key); |
332 |
result.setName (key); |
333 |
return new Node[] { result }; |
334 |
} |
335 |
|
336 |
boolean createKeysCalled = false; |
337 |
public boolean createKeys(List <String> toPopulate) { |
338 |
createKeysCalled = true; |
339 |
List <String> l = switched ? CONTENTS2 : CONTENTS1; |
340 |
toPopulate.addAll (l); |
341 |
return true; |
342 |
} |
343 |
|
344 |
void assertCreateNodesForKeyNotCalled() { |
345 |
assertFalse (createNodesForKeyCalled); |
346 |
} |
347 |
|
348 |
void assertCreateKeysNotCalled() { |
349 |
assertFalse (createKeysCalled); |
350 |
} |
351 |
|
352 |
boolean assertCreateNodesForKeyCalled() { |
353 |
boolean result = createNodesForKeyCalled; |
354 |
createNodesForKeyCalled = false; |
355 |
assertTrue (result); |
356 |
return result; |
357 |
} |
358 |
|
359 |
boolean assertCreateKeysCalled() { |
360 |
boolean result = createKeysCalled; |
361 |
createKeysCalled = false; |
362 |
assertTrue (result); |
363 |
return result; |
364 |
} |
365 |
|
366 |
volatile boolean switched = false; |
367 |
void switchChildren() { |
368 |
switched = !switched; |
369 |
refresh(true); |
370 |
} |
371 |
} |
372 |
} |