1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.binding.form.support;
17
18 import org.springframework.beans.NotReadablePropertyException;
19 import org.springframework.binding.convert.ConversionException;
20 import org.springframework.binding.convert.ConversionExecutor;
21 import org.springframework.binding.convert.ConversionService;
22 import org.springframework.binding.form.CommitListener;
23 import org.springframework.binding.form.FormModel;
24 import org.springframework.binding.support.BeanPropertyAccessStrategy;
25 import org.springframework.binding.support.TestBean;
26 import org.springframework.binding.support.TestPropertyChangeListener;
27 import org.springframework.binding.value.ValueModel;
28 import org.springframework.binding.value.support.ValueHolder;
29 import org.springframework.richclient.test.SpringRichTestCase;
30
31 import java.beans.PropertyChangeEvent;
32 import java.beans.PropertyChangeListener;
33
34
35
36
37
38
39
40 public abstract class AbstractFormModelTests extends SpringRichTestCase {
41
42 protected AbstractFormModel getFormModel(Object formObject) {
43 return new TestAbstractFormModel(formObject);
44 }
45
46 protected AbstractFormModel getFormModel(BeanPropertyAccessStrategy pas, boolean buffering) {
47 return new TestAbstractFormModel(pas, buffering);
48 }
49
50 protected AbstractFormModel getFormModel(ValueModel valueModel, boolean buffering) {
51 return new TestAbstractFormModel(valueModel, buffering);
52 }
53
54 public void testGetValueModelFromPAS() {
55 TestBean p = new TestBean();
56 TestPropertyAccessStrategy tpas = new TestPropertyAccessStrategy(p);
57 AbstractFormModel fm = getFormModel(tpas, true);
58 ValueModel vm1 = fm.getValueModel("simpleProperty");
59 assertEquals(1, tpas.numValueModelRequests());
60 assertEquals("simpleProperty", tpas.lastRequestedValueModel());
61 ValueModel vm2 = fm.getValueModel("simpleProperty");
62 assertEquals(vm1, vm2);
63 assertEquals(1, tpas.numValueModelRequests());
64
65 try {
66 fm.getValueModel("iDontExist");
67 fail("should't be able to get value model for invalid property");
68 }
69 catch (NotReadablePropertyException e) {
70
71 }
72 }
73
74 public void testUnbufferedWritesThrough() {
75 TestBean p = new TestBean();
76 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
77 AbstractFormModel fm = getFormModel(pas, false);
78 ValueModel vm = fm.getValueModel("simpleProperty");
79
80 vm.setValue("1");
81 assertEquals("1", p.getSimpleProperty());
82
83 vm.setValue(null);
84 assertEquals(null, p.getSimpleProperty());
85 }
86
87 public void testBufferedDoesNotWriteThrough() {
88 TestBean p = new TestBean();
89 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
90 AbstractFormModel fm = getFormModel(pas, true);
91 ValueModel vm = fm.getValueModel("simpleProperty");
92
93 vm.setValue("1");
94 assertEquals(null, p.getSimpleProperty());
95
96 vm.setValue(null);
97 assertEquals(null, p.getSimpleProperty());
98 }
99
100 public void testDirtyTrackingWithBuffering() {
101 testDirtyTracking(true);
102 }
103
104 public void testDirtyTrackingWithoutBuffering() {
105 testDirtyTracking(false);
106 }
107
108 public void testDirtyTracking(boolean buffering) {
109 TestBean p = new TestBean();
110 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
111 TestPropertyChangeListener pcl = new TestPropertyChangeListener(FormModel.DIRTY_PROPERTY);
112 AbstractFormModel fm = getFormModel(pas, buffering);
113 fm.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, pcl);
114 ValueModel vm = fm.getValueModel("simpleProperty");
115 assertTrue(!fm.isDirty());
116
117 vm.setValue("2");
118 assertTrue(fm.isDirty());
119 assertEquals(1, pcl.eventCount());
120
121 fm.commit();
122 assertTrue(!fm.isDirty());
123 assertEquals(2, pcl.eventCount());
124
125 vm.setValue("1");
126 assertTrue(fm.isDirty());
127 assertEquals(3, pcl.eventCount());
128
129 fm.setFormObject(new TestBean());
130 assertTrue(!fm.isDirty());
131 assertEquals(4, pcl.eventCount());
132
133 vm.setValue("2");
134 assertTrue(fm.isDirty());
135 assertEquals(5, pcl.eventCount());
136
137 fm.revert();
138 assertTrue(!fm.isDirty());
139 assertEquals(6, pcl.eventCount());
140 }
141
142
143
144
145
146
147 public void testDirtyTracksKids() {
148 TestPropertyChangeListener pcl = new TestPropertyChangeListener(FormModel.DIRTY_PROPERTY);
149 AbstractFormModel pfm = getFormModel(new TestBean());
150 AbstractFormModel fm = getFormModel(new TestBean());
151 pfm.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, pcl);
152 pfm.addChild(fm);
153 ValueModel childSimpleProperty = fm.getValueModel("simpleProperty");
154 ValueModel parentSimpleProperty = pfm.getValueModel("simpleProperty");
155
156 childSimpleProperty.setValue("1");
157 assertTrue(pfm.isDirty());
158 assertEquals(1, pcl.eventCount());
159
160 fm.revert();
161 assertTrue(!pfm.isDirty());
162 assertEquals(2, pcl.eventCount());
163
164 childSimpleProperty.setValue("1");
165 assertTrue(pfm.isDirty());
166 assertEquals(3, pcl.eventCount());
167
168 pfm.revert();
169 assertTrue(!pfm.isDirty());
170 assertTrue(!fm.isDirty());
171 assertEquals(4, pcl.eventCount());
172
173
174 childSimpleProperty.setValue("1");
175 assertTrue(pfm.isDirty());
176 assertEquals(5, pcl.eventCount());
177
178 parentSimpleProperty.setValue("2");
179 assertTrue(pfm.isDirty());
180 assertEquals(5, pcl.eventCount());
181
182 fm.revert();
183 assertTrue(pfm.isDirty());
184 assertEquals(5, pcl.eventCount());
185
186 pfm.revert();
187 assertTrue(!pfm.isDirty());
188 assertEquals(6, pcl.eventCount());
189 }
190
191 public void testSetFormObjectDoesNotRevertChangesToPreviousFormObject() {
192 TestBean p1 = new TestBean();
193 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p1);
194 AbstractFormModel fm = getFormModel(pas, false);
195 fm.getValueModel("simpleProperty").setValue("1");
196 fm.setFormObject(new TestBean());
197 assertEquals("1", p1.getSimpleProperty());
198 }
199
200 public void testCommitEvents() {
201 TestBean p = new TestBean();
202 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
203 TestCommitListener cl = new TestCommitListener();
204 AbstractFormModel fm = getFormModel(pas, false);
205 fm.addCommitListener(cl);
206 ValueModel vm = fm.getValueModel("simpleProperty");
207
208 vm.setValue("1");
209 fm.commit();
210 assertEquals(1, cl.preEditCalls);
211 assertEquals(1, cl.postEditCalls);
212 }
213
214 public void testCommitWritesBufferingThrough() {
215 TestBean p = new TestBean();
216 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
217 TestCommitListener cl = new TestCommitListener();
218 AbstractFormModel fm = getFormModel(pas, true);
219 fm.addCommitListener(cl);
220 ValueModel vm = fm.getValueModel("simpleProperty");
221
222 vm.setValue("1");
223 fm.commit();
224 assertEquals("1", p.getSimpleProperty());
225 }
226
227 public void testRevertWithBuffering() {
228 testRevert(true);
229 }
230
231 public void testRevertWithoutBuffering() {
232 testRevert(false);
233 }
234
235 public void testRevert(boolean buffering) {
236 TestBean p = new TestBean();
237 BeanPropertyAccessStrategy pas = new BeanPropertyAccessStrategy(p);
238 TestPropertyChangeListener pcl = new TestPropertyChangeListener(FormModel.DIRTY_PROPERTY);
239 AbstractFormModel fm = getFormModel(pas, buffering);
240 fm.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, pcl);
241 ValueModel vm = fm.getValueModel("simpleProperty");
242
243 vm.setValue("1");
244 fm.revert();
245
246 assertEquals(null, vm.getValue());
247 assertEquals(null, p.getSimpleProperty());
248
249 TestBean tb2 = new TestBean();
250 tb2.setSimpleProperty("tb2");
251 fm.setFormObject(tb2);
252
253 vm.setValue("1");
254 fm.revert();
255
256 assertEquals("tb2", vm.getValue());
257 assertEquals("tb2", tb2.getSimpleProperty());
258 }
259
260 public void testEnabledEvents() {
261 TestPropertyChangeListener pcl = new TestPropertyChangeListener(FormModel.ENABLED_PROPERTY);
262 AbstractFormModel fm = getFormModel(new Object());
263 fm.addPropertyChangeListener(FormModel.ENABLED_PROPERTY, pcl);
264
265 assertTrue(fm.isEnabled());
266
267 fm.setEnabled(false);
268 assertTrue(!fm.isEnabled());
269 assertEquals(1, pcl.eventCount());
270
271 fm.setEnabled(false);
272 assertTrue(!fm.isEnabled());
273 assertEquals(1, pcl.eventCount());
274
275 fm.setEnabled(true);
276 assertTrue(fm.isEnabled());
277 assertEquals(2, pcl.eventCount());
278
279 fm.setEnabled(true);
280 assertTrue(fm.isEnabled());
281 assertEquals(2, pcl.eventCount());
282 }
283
284 public void testEnabledTracksParent() {
285 TestPropertyChangeListener pcl = new TestPropertyChangeListener(FormModel.ENABLED_PROPERTY);
286 AbstractFormModel pfm = getFormModel(new Object());
287 AbstractFormModel fm = getFormModel(new Object());
288 fm.addPropertyChangeListener(FormModel.ENABLED_PROPERTY, pcl);
289 pfm.addChild(fm);
290
291 pfm.setEnabled(false);
292 assertTrue(!fm.isEnabled());
293 assertEquals(1, pcl.eventCount());
294
295 pfm.setEnabled(true);
296 assertTrue(fm.isEnabled());
297 assertEquals(2, pcl.eventCount());
298
299 pfm.setEnabled(false);
300 assertTrue(!fm.isEnabled());
301 assertEquals(3, pcl.eventCount());
302
303 fm.setEnabled(false);
304 assertTrue(!fm.isEnabled());
305 assertEquals(3, pcl.eventCount());
306
307 pfm.setEnabled(true);
308 assertTrue(!fm.isEnabled());
309 assertEquals(3, pcl.eventCount());
310
311 fm.setEnabled(true);
312 assertTrue(fm.isEnabled());
313 assertEquals(4, pcl.eventCount());
314 }
315
316 public void testConvertingValueModels() {
317 AbstractFormModel fm = getFormModel(new TestBean());
318 TestConversionService cs = new TestConversionService();
319 fm.setConversionService(cs);
320
321 ValueModel vm = fm.getValueModel("simpleProperty", String.class);
322 assertEquals(fm.getValueModel("simpleProperty"), vm);
323 assertEquals(0, cs.calls);
324
325 try {
326 fm.getValueModel("simpleProperty", Integer.class);
327 fail("should have throw IllegalArgumentException");
328 }
329 catch (IllegalArgumentException e) {
330
331 }
332 assertEquals(1, cs.calls);
333 assertEquals(String.class, cs.lastSource);
334 assertEquals(Integer.class, cs.lastTarget);
335
336 cs.executer = new ConversionExecutor(String.class, Integer.class, new CopiedPublicNoOpConverter(String.class,
337 Integer.class));
338 ValueModel cvm = fm.getValueModel("simpleProperty", Integer.class);
339 assertEquals(3, cs.calls);
340 assertEquals(Integer.class, cs.lastSource);
341 assertEquals(String.class, cs.lastTarget);
342
343 assertEquals(fm.getValueModel("simpleProperty", Integer.class), cvm);
344 assertEquals(3, cs.calls);
345 }
346
347 public void testFieldMetadata() {
348 AbstractFormModel fm = getFormModel(new TestBean());
349
350 assertEquals(String.class, fm.getFieldMetadata("simpleProperty").getPropertyType());
351 assertTrue(!fm.getFieldMetadata("simpleProperty").isReadOnly());
352
353 assertEquals(Object.class, fm.getFieldMetadata("readOnly").getPropertyType());
354 assertTrue(fm.getFieldMetadata("readOnly").isReadOnly());
355 }
356
357 public void testSetFormObjectUpdatesDirtyState() {
358 final AbstractFormModel fm = getFormModel(new TestBean());
359 fm.add("simpleProperty");
360 fm.add("singleSelectListProperty");
361
362 assertTrue(!fm.isDirty());
363
364 fm.getValueModel("simpleProperty").addValueChangeListener(new PropertyChangeListener() {
365
366 public void propertyChange(PropertyChangeEvent evt) {
367 fm.getValueModel("singleSelectListProperty").setValue(null);
368 }
369 });
370
371 TestBean newBean = new TestBean();
372 newBean.setSimpleProperty("simpleProperty");
373 newBean.setSingleSelectListProperty("singleSelectListProperty");
374 fm.setFormObject(newBean);
375 assertEquals(null, fm.getValueModel("singleSelectListProperty").getValue());
376 assertTrue(fm.isDirty());
377 fm.getValueModel("singleSelectListProperty").setValue("singleSelectListProperty");
378 assertTrue(!fm.isDirty());
379 }
380
381 public void testFormPropertiesAreAccessableFromFormObjectChangeEvents() {
382 final AbstractFormModel fm = getFormModel(new TestBean());
383 assertEquals(null, fm.getValueModel("simpleProperty").getValue());
384 TestBean newTestBean = new TestBean();
385 newTestBean.setSimpleProperty("NewValue");
386 fm.getFormObjectHolder().addValueChangeListener(new PropertyChangeListener() {
387
388 public void propertyChange(PropertyChangeEvent evt) {
389 assertEquals("NewValue", fm.getValueModel("simpleProperty").getValue());
390 }
391 });
392 fm.setFormObject(newTestBean);
393 }
394
395 public void testFormObjectChangeEventComesBeforePropertyChangeEvent() {
396 final TestBean testBean = new TestBean();
397 final AbstractFormModel fm = getFormModel(testBean);
398 final TestBean newTestBean = new TestBean();
399 newTestBean.setSimpleProperty("NewValue");
400 final boolean[] formObjectChangeCalled = new boolean[1];
401 fm.getFormObjectHolder().addValueChangeListener(new PropertyChangeListener() {
402
403 public void propertyChange(PropertyChangeEvent evt) {
404 formObjectChangeCalled[0] = true;
405 }
406 });
407 fm.getValueModel("simpleProperty").addValueChangeListener(new PropertyChangeListener() {
408
409 public void propertyChange(PropertyChangeEvent evt) {
410 assertEquals("Form property change event was called before form object change event", true,
411 formObjectChangeCalled[0]);
412 }
413 });
414 fm.setFormObject(newTestBean);
415 }
416
417 public void testFormObjectChangeEvents() {
418 TestBean testBean = new TestBean();
419 final AbstractFormModel fm = getFormModel(testBean);
420 TestBean newTestBean = new TestBean();
421 newTestBean.setSimpleProperty("NewValue");
422 TestPropertyChangeListener testPCL = new TestPropertyChangeListener(ValueModel.VALUE_PROPERTY);
423 fm.getFormObjectHolder().addValueChangeListener(testPCL);
424 fm.setFormObject(newTestBean);
425 assertEquals(1, testPCL.eventCount());
426 assertEquals(testBean, testPCL.lastEvent().getOldValue());
427 assertEquals(newTestBean, testPCL.lastEvent().getNewValue());
428 }
429
430 public static class TestCommitListener implements CommitListener {
431 int preEditCalls;
432
433 int postEditCalls;
434
435 public void preCommit(FormModel formModel) {
436 preEditCalls++;
437 }
438
439 public void postCommit(FormModel formModel) {
440 postEditCalls++;
441 }
442 }
443
444 public class TestConversionService implements ConversionService {
445
446 public int calls;
447
448 public Class lastSource;
449
450 public Class lastTarget;
451
452 public ConversionExecutor executer;
453
454 public ConversionExecutor getConversionExecutor(Class source, Class target) {
455 calls++;
456 lastSource = source;
457 lastTarget = target;
458 if (executer != null) {
459 return executer;
460 }
461 throw new IllegalArgumentException("no converter found");
462 }
463
464 public ConversionExecutor getConversionExecutorByTargetAlias(Class arg0, String arg1)
465 throws IllegalArgumentException {
466 fail("this method should never be called");
467 return null;
468 }
469
470 public Class getClassByAlias(String arg0) {
471 fail("this method should never be called");
472 return null;
473 }
474
475 public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) throws ConversionException {
476 fail("this method should never be called");
477 return null;
478 }
479 }
480
481
482
483
484
485
486
487
488
489
490
491
492
493 public void testBufferedFormModelSetFormObjectNotDirty() {
494 String someString = "someString";
495 FormModel model = getFormModel(new TestBean());
496 ValueModel valueModel = model.getValueModel("simpleProperty");
497
498 assertEquals("Initial check, formmodel not dirty.", false, model.isDirty());
499
500 valueModel.setValue(someString);
501 assertEquals("Value changed, model should be dirty.", true, model.isDirty());
502
503 TestBean newFormObject = new TestBean();
504 newFormObject.setSimpleProperty(someString);
505 model.setFormObject(newFormObject);
506 assertEquals("New formObject is set, model should not be dirty.", false, model.isDirty());
507 }
508
509
510
511
512
513
514
515
516
517
518
519
520
521 public void testFormModelSetFormObjectNotDirty() {
522 String someString = "someString";
523 FormModel model = getFormModel(new ValueHolder(new TestBean()), false);
524 ValueModel valueModel = model.getValueModel("simpleProperty");
525
526 assertEquals("Initial check, formmodel not dirty.", false, model.isDirty());
527
528 valueModel.setValue(someString);
529 assertEquals("Value changed, model should be dirty.", true, model.isDirty());
530
531 TestBean newFormObject = new TestBean();
532 newFormObject.setSimpleProperty(someString);
533 model.setFormObject(newFormObject);
534 assertEquals("New formObject is set, model should not be dirty.", false, model.isDirty());
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 public void testParentChildEnabledState() {
551 TestBean formObject = new TestBean();
552 AbstractFormModel parent = getFormModel(formObject);
553 AbstractFormModel child = getFormModel(formObject);
554 BooleanStatelistener listener = new BooleanStatelistener(FormModel.ENABLED_PROPERTY);
555 listener.state = child.isEnabled();
556 child.addPropertyChangeListener(FormModel.ENABLED_PROPERTY, listener);
557
558 parent.addChild(child);
559
560
561 parent.setEnabled(true);
562 child.setEnabled(true);
563 assertTrue(listener.state);
564 child.setEnabled(false);
565 assertFalse(listener.state);
566
567
568 parent.setEnabled(false);
569 child.setEnabled(false);
570 assertFalse(listener.state);
571 child.setEnabled(true);
572 assertFalse(listener.state);
573
574 parent.removeChild(child);
575
576
577
578
579 parent.setEnabled(false);
580 child.setEnabled(true);
581 parent.addChild(child);
582 assertFalse(listener.state);
583 parent.removeChild(child);
584 assertTrue(listener.state);
585 parent.setEnabled(false);
586 child.setEnabled(false);
587 parent.addChild(child);
588 assertFalse(listener.state);
589 parent.removeChild(child);
590 assertFalse(listener.state);
591
592
593 parent.setEnabled(true);
594 child.setEnabled(false);
595 parent.addChild(child);
596 assertFalse(listener.state);
597 parent.removeChild(child);
598 assertFalse(listener.state);
599 parent.setEnabled(true);
600 child.setEnabled(true);
601 parent.addChild(child);
602 assertTrue(listener.state);
603 parent.removeChild(child);
604 assertTrue(listener.state);
605 }
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620 public void testParentChildReadOnlyState() {
621 TestBean formObject = new TestBean();
622 AbstractFormModel parent = getFormModel(formObject);
623 AbstractFormModel child = getFormModel(formObject);
624 BooleanStatelistener listener = new BooleanStatelistener(FormModel.READONLY_PROPERTY);
625 listener.state = child.isReadOnly();
626 child.addPropertyChangeListener(FormModel.READONLY_PROPERTY, listener);
627
628 parent.addChild(child);
629
630
631 parent.setReadOnly(true);
632 child.setReadOnly(false);
633 assertTrue(listener.state);
634 child.setReadOnly(true);
635 assertTrue(listener.state);
636
637
638 parent.setReadOnly(false);
639 child.setReadOnly(false);
640 assertFalse(listener.state);
641 child.setReadOnly(true);
642 assertTrue(listener.state);
643
644 parent.removeChild(child);
645
646
647
648
649 parent.setReadOnly(false);
650 child.setReadOnly(true);
651 parent.addChild(child);
652 assertTrue(listener.state);
653 parent.removeChild(child);
654 assertTrue(listener.state);
655 parent.setReadOnly(false);
656 child.setReadOnly(false);
657 parent.addChild(child);
658 assertFalse(listener.state);
659 parent.removeChild(child);
660 assertFalse(listener.state);
661
662
663 parent.setReadOnly(true);
664 child.setReadOnly(false);
665 parent.addChild(child);
666 assertTrue(listener.state);
667 parent.removeChild(child);
668 assertFalse(listener.state);
669 parent.setReadOnly(true);
670 child.setReadOnly(true);
671 parent.addChild(child);
672 assertTrue(listener.state);
673 parent.removeChild(child);
674 assertTrue(listener.state);
675 }
676
677
678
679
680 protected static class BooleanStatelistener implements PropertyChangeListener {
681
682 final String property;
683
684 boolean state = false;
685
686 public BooleanStatelistener(final String property) {
687 this.property = property;
688 }
689
690 public void propertyChange(PropertyChangeEvent evt) {
691 if (property.equals(evt.getPropertyName()))
692 state = Boolean.parseBoolean(evt.getNewValue().toString());
693 }
694 }
695
696
697
698
699
700
701
702
703
704
705
706
707
708 public void testParentChildDirtyState() {
709 TestBean formObject = new TestBean();
710 AbstractFormModel parent = getFormModel(formObject);
711 ValueModel parentValueModel = parent.getValueModel("simpleProperty");
712 AbstractFormModel child = getFormModel(formObject);
713 ValueModel childValueModel = child.getValueModel("booleanProperty");
714 BooleanStatelistener listener = new BooleanStatelistener(FormModel.DIRTY_PROPERTY);
715 listener.state = parent.isDirty();
716 parent.addPropertyChangeListener(FormModel.DIRTY_PROPERTY, listener);
717
718 parent.addChild(child);
719
720
721 assertFalse(listener.state);
722 childValueModel.setValue(Boolean.TRUE);
723 assertTrue(listener.state);
724 parentValueModel.setValue("x");
725 assertTrue(listener.state);
726 parentValueModel.setValue(null);
727 assertTrue(listener.state);
728 childValueModel.setValue(Boolean.FALSE);
729 assertFalse(listener.state);
730
731
732 parentValueModel.setValue("x");
733 assertTrue(listener.state);
734 parentValueModel.setValue(null);
735 assertFalse(listener.state);
736
737 parent.removeChild(child);
738
739
740
741
742 childValueModel.setValue(Boolean.TRUE);
743 assertFalse(listener.state);
744 parent.addChild(child);
745 assertTrue(listener.state);
746 parent.removeChild(child);
747 assertFalse(listener.state);
748 parentValueModel.setValue("x");
749 assertTrue(listener.state);
750 parent.addChild(child);
751 assertTrue(listener.state);
752 parent.removeChild(child);
753 assertTrue(listener.state);
754
755
756 child.revert();
757 parent.revert();
758 assertFalse(listener.state);
759 parent.addChild(child);
760 assertFalse(listener.state);
761 parent.removeChild(child);
762 parentValueModel.setValue("x");
763 assertTrue(listener.state);
764 parent.addChild(child);
765 assertTrue(listener.state);
766 parent.removeChild(child);
767 assertTrue(listener.state);
768 }
769 }