modules/graphics/src/test/java/test/javafx/scene/ParentTest.java

Print this page
rev 9250 : 8134762: Refactor Javafx graphics module tests for clear separation of tests
Reviewed-by:


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene;
  27 
  28 import com.sun.javafx.pgstub.StubToolkit;
  29 import com.sun.javafx.sg.prism.NGGroup;
  30 import com.sun.javafx.tk.Toolkit;
  31 import java.util.concurrent.atomic.AtomicBoolean;






  32 import javafx.scene.shape.Rectangle;
  33 import javafx.stage.Stage;
  34 import org.junit.After;
  35 import org.junit.Before;
  36 import org.junit.Test;
  37 
  38 import static org.junit.Assert.*;
  39 
  40 public class ParentTest {
  41     private StubToolkit toolkit;
  42     private Stage stage;
  43 
  44     @Before
  45     public void setUp() {
  46         toolkit = (StubToolkit) Toolkit.getToolkit();
  47         stage = new Stage();
  48     }
  49 
  50     @After
  51     public void tearDown() {


 127         groupD.setId("d");
 128         Group group = new Group(rectA, rectB, rectC, groupD, rectE, rectF);
 129 
 130         assertNull(group.lookup("#4444"));
 131     }
 132 
 133     @Test
 134     public void testRemoveChild() {
 135         Rectangle rect1 = new Rectangle();
 136         Rectangle rect2 = new Rectangle();
 137         Rectangle rect3 = new Rectangle();
 138         Rectangle rect4 = new Rectangle();
 139         Rectangle rect5 = new Rectangle();
 140         Rectangle rect6 = new Rectangle();
 141 
 142         Group g = new Group();
 143         Scene s = new Scene(g);
 144         stage.setScene(s);
 145         stage.show();
 146 
 147         g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5, rect6);
 148         toolkit.fireTestPulse();
 149 
 150         // try removing node from the end of the observableArrayList
 151         g.getChildren().remove(rect6);
 152         toolkit.fireTestPulse();
 153         final NGGroup peer = g.impl_getPeer();
 154         assertEquals(5, g.getChildren().size());
 155         assertEquals(5, peer.getChildren().size());
 156 
 157         // try removing node from the beginning of the observableArrayList
 158         g.getChildren().remove(rect1);
 159         toolkit.fireTestPulse();
 160         assertEquals(4, g.getChildren().size());
 161         assertEquals(4, peer.getChildren().size());
 162 
 163         // try removing node from the middle of the observableArrayList
 164         g.getChildren().remove(rect3);
 165         toolkit.fireTestPulse();
 166         assertEquals(3, g.getChildren().size());
 167         assertEquals(3, peer.getChildren().size());
 168     }
 169 
 170     @Test
 171     public void testSetChild() {
 172         Rectangle rect1 = new Rectangle();
 173         Rectangle rect2 = new Rectangle();
 174         Rectangle rect3 = new Rectangle();
 175 
 176         Group g = new Group();
 177         Scene s = new Scene(g);
 178         stage.setScene(s);
 179         stage.show();
 180 
 181         g.getChildren().addAll(rect1, rect2);
 182         toolkit.fireTestPulse();
 183 
 184         // try setting node at given index
 185         g.getChildren().set(1, rect3);
 186         toolkit.fireTestPulse();
 187         assertEquals(2, g.getChildren().size());
 188         assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size());
 189     }
 190 
 191     @Test
 192     public void testSetSameChild() {
 193         Rectangle rect1 = new Rectangle();
 194         Rectangle rect2 = new Rectangle();
 195 
 196         Group g = new Group();
 197         Scene s = new Scene(g);
 198         stage.setScene(s);
 199         stage.show();
 200 
 201         g.getChildren().addAll(rect1, rect2);
 202         toolkit.fireTestPulse();
 203 
 204         // try setting the same node at given index
 205         g.getChildren().set(1, rect2);
 206 
 207         toolkit.fireTestPulse();
 208         assertEquals(2, g.getChildren().size());
 209         assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size());
 210     }
 211 
 212     @Test
 213     public void testRemoveAddSameChild() {
 214         Rectangle rect1 = new Rectangle();
 215         Rectangle rect2 = new Rectangle();
 216         Rectangle rect3 = new Rectangle();
 217         Rectangle rect4 = new Rectangle();
 218         Rectangle rect5 = new Rectangle();
 219         Rectangle rect6 = new Rectangle();
 220 
 221         Group g = new Group();
 222         Scene s = new Scene(g);
 223         stage.setScene(s);
 224         stage.show();
 225 
 226         g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5, rect6);
 227         toolkit.fireTestPulse();
 228 
 229         // try removing node from the end of the observableArrayList
 230         // and add it afterwords
 231         g.getChildren().remove(rect6);
 232         g.getChildren().add(rect6);
 233         toolkit.fireTestPulse();
 234         assertEquals(6, g.getChildren().size());
 235         assertEquals(6, ((NGGroup)g.impl_getPeer()).getChildren().size());
 236     }
 237 
 238     @Test
 239     public void testRemoveAddDiferentChild() {
 240         Rectangle rect1 = new Rectangle();
 241         Rectangle rect2 = new Rectangle();
 242         Rectangle rect3 = new Rectangle();
 243         Rectangle rect4 = new Rectangle();
 244         Rectangle rect5 = new Rectangle();
 245         Rectangle rect6 = new Rectangle();
 246 
 247         Group g = new Group();
 248         Scene s = new Scene(g);
 249         stage.setScene(s);
 250         stage.show();
 251 
 252         g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5);
 253         toolkit.fireTestPulse();
 254 
 255         // try removing node from the end of the observableArrayList
 256         // and add a different one
 257         g.getChildren().remove(rect5);
 258         g.getChildren().add(rect6);
 259         toolkit.fireTestPulse();
 260         assertEquals(5, g.getChildren().size());
 261         assertEquals(5, ((NGGroup)g.impl_getPeer()).getChildren().size());
 262     }
 263 
 264     @Test
 265     public void testGetChildrenUnmodifiable() {
 266         Rectangle rect1 = new Rectangle();
 267         Rectangle rect2 = new Rectangle();
 268         Rectangle rect3 = new Rectangle();
 269 
 270         Group g = new Group();
 271         g.getChildren().addAll(rect1,rect2,rect3);
 272 
 273         assertEquals(3, g.getChildrenUnmodifiable().size());
 274         assertSame(rect1, g.getChildrenUnmodifiable().get(0));
 275         assertSame(rect2, g.getChildrenUnmodifiable().get(1));
 276         assertSame(rect3, g.getChildrenUnmodifiable().get(2));
 277     }
 278 
 279     @Test
 280     public void testGetChildrenUnmodifiableCantBeModified() {
 281         Rectangle rect1 = new Rectangle();
 282         Rectangle rect2 = new Rectangle();
 283         Rectangle rect3 = new Rectangle();
 284 
 285         Group g = new Group();
 286         g.getChildren().addAll(rect1,rect2,rect3);
 287 
 288         try {
 289             g.getChildrenUnmodifiable().add(new Rectangle());
 290             fail("UnsupportedOperationException should have been thrown.");
 291         } catch (UnsupportedOperationException uoe) {
 292             // expected
 293         }
 294     }
 295 
 296     @Test
 297     public void testRequestLayoutWithoutParent() {
 298         Group g = new Group();
 299         g.layout();
 300         // this shouldn't fail even when the group doesn't have a parent
 301         g.requestLayout();
 302     }
 303 
 304     @Test
 305     public void testRequestLayoutWithoutScene() {
 306         Group g = new Group();
 307         g.setManaged(false);
 308         g.layout();
 309         // this shouldn't fail even when the scene is not set
 310         g.requestLayout();
 311     }
 312 
 313     @Test
 314     public void testRequestLayoutClearsCache() {
 315         Group g = new Group();
 316         Rectangle r = new Rectangle(100,200);
 317         g.getChildren().add(r);
 318 
 319         g.requestLayout();
 320         assertEquals(100, g.prefWidth(-1), 1e-100);
 321         assertEquals(200, g.prefHeight(-1), 1e-100);
 322 
 323         r.setWidth(150);
 324         r.setHeight(250);
 325         g.requestLayout();
 326 
 327         assertEquals(150, g.prefWidth(-1), 1e-100);
 328         assertEquals(250, g.prefHeight(-1), 1e-100);
 329     }
 330 
 331     @Test
 332     public void testPrefWidthIncludesChildLayoutX() {
 333         Rectangle r = new Rectangle(10,10,100,100);
 334         r.setLayoutX(10);
 335         MockParent p = new MockParent(r);
 336 
 337         assertEquals(120, p.prefWidth(-1), 0);


 339 
 340     @Test
 341     public void testPrefHeightIncludesChildLayoutY() {
 342         Rectangle r = new Rectangle(10,10,100,100);
 343         r.setLayoutY(10);
 344         MockParent p = new MockParent(r);
 345 
 346         assertEquals(120, p.prefHeight(-1), 0);
 347     }
 348 
 349     @Test
 350     public void testDuplicates() {
 351         Group g = new Group();
 352 
 353         Rectangle r1 = new Rectangle();
 354         Rectangle r2 = new Rectangle();
 355         Rectangle r3 = new Rectangle();
 356         Rectangle r4 = new Rectangle();
 357 
 358         try {
 359         g.getChildren().addAll(r1, r2, r3, r4);
 360         g.getChildren().add(r2);
 361         fail();
 362         } catch (IllegalArgumentException e) {
 363 
 364         }
 365     }
 366 
 367     @Test(expected=NullPointerException.class)
 368     public void testAddingNullChild() {
 369         Group g = new Group();
 370         g.getChildren().add(null);
 371     }
 372 
 373     @Test(expected=NullPointerException.class)
 374     public void testNullCheckIsDoneBeforeTestForDuplicates() {
 375         Group g = new Group();
 376         g.getChildren().addAll(null, new Rectangle(), null);
 377     }
 378 
 379     @Test(expected=IllegalArgumentException.class)
 380     public void testAddingClipNodeTwice() {
 381         Group g = new Group();
 382 
 383         Node clipParent = new Rectangle();
 384         Node clipNode = new Rectangle();
 385 
 386         clipParent.setClip(clipNode);
 387         try {
 388             // try to add node which is already set as a clip
 389             g.getChildren().add(clipNode);
 390             fail();
 391         } catch (IllegalArgumentException e) {
 392         }
 393 
 394         // try again
 395         g.getChildren().add(clipNode);
 396     }
 397 
 398     @Test
 399     public void testAddingFixedClipNode() {
 400         Group g = new Group();
 401 
 402         Node clipParent = new Rectangle();
 403         Node clipNode = new Rectangle();
 404 
 405         clipParent.setClip(clipNode);
 406         try {
 407             // try to add node which is already set as a clip
 408             g.getChildren().add(clipNode);
 409             fail();
 410         } catch (IllegalArgumentException e) {
 411         }
 412 
 413         // fix the problem and add again
 414         clipParent.setClip(null);
 415         g.getChildren().add(clipNode);
 416     }
 417 
 418     @Test(expected=IllegalArgumentException.class)
 419     public void testFalsePermutation() {
 420         Group g = new Group();
 421 
 422         Rectangle r1 = new Rectangle();
 423         Rectangle r2 = new Rectangle();
 424         Rectangle r3 = new Rectangle();
 425         Rectangle r4 = new Rectangle();
 426 
 427         g.getChildren().addAll(r1, r2, r3, r4);
 428         g.getChildren().setAll(r1, r2, r2, r4);
 429     }
 430 
 431     @Test
 432     public void testFalseDuplicates() {
 433         Group g = new Group();
 434 
 435         Rectangle r1 = new Rectangle();
 436         Rectangle r2 = new Rectangle();
 437         Rectangle r3 = new Rectangle();
 438         Rectangle r4 = new Rectangle();
 439 
 440         g.getChildren().addAll(r1, r2);
 441         try {
 442             g.getChildren().addAll(r3, r4, r2);
 443             fail();
 444         } catch (IllegalArgumentException e) {
 445         }
 446         try {
 447             g.getChildren().add(r3);
 448         } catch (IllegalArgumentException e) {
 449             fail();
 450         }
 451 
 452     }
 453 
 454     @Test
 455     public void nodeCanBeAddedDuringLayout() {
 456         final Rectangle rect = new Rectangle(100, 100);
 457         final Group g = new Group(rect);
 458 
 459         Group root = new Group() {
 460             @Override protected void layoutChildren() {
 461                 getChildren().setAll(g);
 462             }
 463         };
 464 
 465         Scene scene = new Scene(root);
 466 
 467         stage.setScene(scene);
 468         stage.show();
 469 
 470         // there are assertions tested down the stack (see RT-21746)
 471     }
 472 
 473     private static class LGroup extends Group {
 474 
 475         private boolean layoutCalled;
 476 
 477         @Override
 478         public void requestLayout() {
 479             super.requestLayout();
 480             layoutCalled = true;
 481         }
 482 
 483         public void assertAndClear(boolean b) {
 484             assertEquals(b, layoutCalled);
 485             layoutCalled = false;
 486         }
 487 
 488         public void clear() {
 489             layoutCalled = false;
 490         }
 491 
 492     }
 493 
 494     @Test
 495     public void requestLayoutAlwaysCalledUpToTheLayoutRoot() {
 496         final Group root = new Group();
 497         final LGroup lroot = new LGroup();
 498         lroot.setManaged(false);
 499         root.getChildren().add(lroot);
 500         final LGroup sub = new LGroup();
 501         lroot.getChildren().add(sub);
 502 
 503         lroot.clear();
 504         sub.clear();
 505         root.layout();
 506 
 507         lroot.assertAndClear(false);
 508         sub.assertAndClear(false);
 509 
 510         sub.requestLayout();
 511 
 512         lroot.assertAndClear(true);
 513         sub.assertAndClear(true);
 514 
 515         sub.requestLayout();
 516         lroot.assertAndClear(true);
 517         sub.assertAndClear(true);
 518     }
 519     
 520     @Test
 521     public void unmanagedParentTest() {


 547         outerGroup.getChildren().add(intermediate);
 548 
 549         innerGroup.assertAndClear(false);
 550         intermediate.assertAndClear(true);
 551         outerGroup.assertAndClear(true);
 552 
 553         innerGroup.requestLayout();
 554         intermediate.getChildren().add(innerGroup);
 555 
 556         innerGroup.assertAndClear(true);
 557         intermediate.assertAndClear(true);
 558         outerGroup.assertAndClear(false);
 559 
 560     }
 561 
 562     @Test
 563     public void requestLayoutTriggersPulse() {
 564         final Group root = new Group();
 565         final LGroup lroot = new LGroup();
 566         lroot.setManaged(false);
 567         root.getChildren().add(lroot);
 568         final LGroup sub = new LGroup();
 569         lroot.getChildren().add(sub);
 570 
 571         toolkit.clearPulseRequested();
 572         sub.requestLayout();
 573         Scene scene = new Scene(root);
 574         assertTrue(toolkit.isPulseRequested());
 575         toolkit.clearPulseRequested();
 576         root.layout();
 577 
 578         sub.requestLayout();
 579 
 580         assertTrue(toolkit.isPulseRequested());
 581     }
 582 
 583     @Test
 584     public void requestLayoutNotPropagatingDuringLayout() {
 585         final LGroup lroot = new LGroup();
 586         lroot.setManaged(false);
 587         final LGroup sub = new LGroup() {
 588 
 589             @Override
 590             protected void layoutChildren() {
 591                 super.layoutChildren();
 592                 requestLayout();
 593             }
 594 
 595         };
 596         lroot.getChildren().add(sub);
 597         lroot.clear();
 598         sub.clear();
 599 
 600         sub.requestLayout();
 601         lroot.assertAndClear(true);
 602         sub.assertAndClear(true);
 603 
 604         lroot.layout();
 605 
 606         lroot.assertAndClear(false);
 607         sub.assertAndClear(true);
 608     }
 609 
 610     @Test
 611     public void testChildrenPermutationInvalidatesManagedChildrenAndLayout() {
 612         LGroup root = new LGroup();
 613         Rectangle r1 = new Rectangle();
 614         Rectangle r2 = new Rectangle();
 615 
 616         root.getChildren().addAll(r1, r2);
 617 
 618         root.clear();
 619 
 620         root.getManagedChildren().equals(root.getChildren());
 621 
 622         root.getChildren().setAll(r2, r1);
 623 
 624         root.getManagedChildren().equals(root.getChildren());
 625         root.assertAndClear(true);
 626 
 627         r2.toFront();
 628 
 629         root.getManagedChildren().equals(root.getChildren());
 630         root.assertAndClear(true);
 631     }
 632 
 633     @Test
 634     public void newChildInvalidatesLayoutWhenLayoutBoundsAreValidatedImmediately() {
 635         Group root = new Group();
 636         final AtomicBoolean layoutCalled = new AtomicBoolean();
 637         final AtomicBoolean testReady = new AtomicBoolean();
 638         LGroup sub = new LGroup() {
 639 
 640             @Override
 641             protected void layoutChildren() {
 642                 if (testReady.get()) {
 643                     assertAndClear(true);
 644                     layoutCalled.set(true);
 645                 }
 646             }
 647 
 648         };
 649         root.getChildren().add(sub);
 650         root.getLayoutBounds(); // validate
 651         sub.getBoundsInParent(); // validate
 652 
 653         root.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
 654             // ChangeListener will immediately validate the bounds
 655         });
 656         sub.clear();
 657 
 658         testReady.set(true);
 659         sub.getChildren().add(new Rectangle());
 660         assertTrue(layoutCalled.get());
 661     }
 662 
 663     @Test
 664     public void sceneListenerCanAddChild() {
 665         final Group root = new Group();
 666         final Scene scene = new Scene(root, 600, 450);
 667 
 668         final Group child = new Group(new Group(), new Group(), new Group());
 669 
 670         child.getChildren().get(1).sceneProperty().addListener(o -> child.getChildren().add(2, new Group()));
 671 
 672         root.getChildren().add(child);
 673 
 674         assertSame(scene, child.getChildren().get(3).getScene());
 675     }
 676 
 677     public static class MockParent extends Parent {
 678         public MockParent(Node... children) {
 679             getChildren().addAll(children);
 680         }
 681     }
 682 }


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.javafx.scene;
  27 
  28 import test.com.sun.javafx.pgstub.StubToolkit;
  29 import com.sun.javafx.sg.prism.NGGroup;
  30 import com.sun.javafx.tk.Toolkit;
  31 import java.util.concurrent.atomic.AtomicBoolean;
  32 import javafx.scene.Group;
  33 import javafx.scene.GroupShim;
  34 import javafx.scene.Node;
  35 import javafx.scene.Parent;
  36 import javafx.scene.ParentShim;
  37 import javafx.scene.Scene;
  38 import javafx.scene.shape.Rectangle;
  39 import javafx.stage.Stage;
  40 import org.junit.After;
  41 import org.junit.Before;
  42 import org.junit.Test;
  43 
  44 import static org.junit.Assert.*;
  45 
  46 public class ParentTest {
  47     private StubToolkit toolkit;
  48     private Stage stage;
  49 
  50     @Before
  51     public void setUp() {
  52         toolkit = (StubToolkit) Toolkit.getToolkit();
  53         stage = new Stage();
  54     }
  55 
  56     @After
  57     public void tearDown() {


 133         groupD.setId("d");
 134         Group group = new Group(rectA, rectB, rectC, groupD, rectE, rectF);
 135 
 136         assertNull(group.lookup("#4444"));
 137     }
 138 
 139     @Test
 140     public void testRemoveChild() {
 141         Rectangle rect1 = new Rectangle();
 142         Rectangle rect2 = new Rectangle();
 143         Rectangle rect3 = new Rectangle();
 144         Rectangle rect4 = new Rectangle();
 145         Rectangle rect5 = new Rectangle();
 146         Rectangle rect6 = new Rectangle();
 147 
 148         Group g = new Group();
 149         Scene s = new Scene(g);
 150         stage.setScene(s);
 151         stage.show();
 152 
 153         ParentShim.getChildren(g).addAll(rect1, rect2, rect3, rect4, rect5, rect6);
 154         toolkit.fireTestPulse();
 155 
 156         // try removing node from the end of the observableArrayList
 157         ParentShim.getChildren(g).remove(rect6);
 158         toolkit.fireTestPulse();
 159         final NGGroup peer = g.impl_getPeer();
 160         assertEquals(5, ParentShim.getChildren(g).size());
 161         assertEquals(5, peer.getChildren().size());
 162 
 163         // try removing node from the beginning of the observableArrayList
 164         ParentShim.getChildren(g).remove(rect1);
 165         toolkit.fireTestPulse();
 166         assertEquals(4, ParentShim.getChildren(g).size());
 167         assertEquals(4, peer.getChildren().size());
 168 
 169         // try removing node from the middle of the observableArrayList
 170         ParentShim.getChildren(g).remove(rect3);
 171         toolkit.fireTestPulse();
 172         assertEquals(3, ParentShim.getChildren(g).size());
 173         assertEquals(3, peer.getChildren().size());
 174     }
 175 
 176     @Test
 177     public void testSetChild() {
 178         Rectangle rect1 = new Rectangle();
 179         Rectangle rect2 = new Rectangle();
 180         Rectangle rect3 = new Rectangle();
 181 
 182         Group g = new Group();
 183         Scene s = new Scene(g);
 184         stage.setScene(s);
 185         stage.show();
 186 
 187         ParentShim.getChildren(g).addAll(rect1, rect2);
 188         toolkit.fireTestPulse();
 189 
 190         // try setting node at given index
 191         ParentShim.getChildren(g).set(1, rect3);
 192         toolkit.fireTestPulse();
 193         assertEquals(2, ParentShim.getChildren(g).size());
 194         assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size());
 195     }
 196 
 197     @Test
 198     public void testSetSameChild() {
 199         Rectangle rect1 = new Rectangle();
 200         Rectangle rect2 = new Rectangle();
 201 
 202         Group g = new Group();
 203         Scene s = new Scene(g);
 204         stage.setScene(s);
 205         stage.show();
 206 
 207         ParentShim.getChildren(g).addAll(rect1, rect2);
 208         toolkit.fireTestPulse();
 209 
 210         // try setting the same node at given index
 211         ParentShim.getChildren(g).set(1, rect2);
 212 
 213         toolkit.fireTestPulse();
 214         assertEquals(2, ParentShim.getChildren(g).size());
 215         assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size());
 216     }
 217 
 218     @Test
 219     public void testRemoveAddSameChild() {
 220         Rectangle rect1 = new Rectangle();
 221         Rectangle rect2 = new Rectangle();
 222         Rectangle rect3 = new Rectangle();
 223         Rectangle rect4 = new Rectangle();
 224         Rectangle rect5 = new Rectangle();
 225         Rectangle rect6 = new Rectangle();
 226 
 227         Group g = new Group();
 228         Scene s = new Scene(g);
 229         stage.setScene(s);
 230         stage.show();
 231 
 232         ParentShim.getChildren(g).addAll(rect1, rect2, rect3, rect4, rect5, rect6);
 233         toolkit.fireTestPulse();
 234 
 235         // try removing node from the end of the observableArrayList
 236         // and add it afterwords
 237         ParentShim.getChildren(g).remove(rect6);
 238         ParentShim.getChildren(g).add(rect6);
 239         toolkit.fireTestPulse();
 240         assertEquals(6, ParentShim.getChildren(g).size());
 241         assertEquals(6, ((NGGroup)g.impl_getPeer()).getChildren().size());
 242     }
 243 
 244     @Test
 245     public void testRemoveAddDiferentChild() {
 246         Rectangle rect1 = new Rectangle();
 247         Rectangle rect2 = new Rectangle();
 248         Rectangle rect3 = new Rectangle();
 249         Rectangle rect4 = new Rectangle();
 250         Rectangle rect5 = new Rectangle();
 251         Rectangle rect6 = new Rectangle();
 252 
 253         Group g = new Group();
 254         Scene s = new Scene(g);
 255         stage.setScene(s);
 256         stage.show();
 257 
 258         ParentShim.getChildren(g).addAll(rect1, rect2, rect3, rect4, rect5);
 259         toolkit.fireTestPulse();
 260 
 261         // try removing node from the end of the observableArrayList
 262         // and add a different one
 263         ParentShim.getChildren(g).remove(rect5);
 264         ParentShim.getChildren(g).add(rect6);
 265         toolkit.fireTestPulse();
 266         assertEquals(5, ParentShim.getChildren(g).size());
 267         assertEquals(5, ((NGGroup)g.impl_getPeer()).getChildren().size());
 268     }
 269 
 270     @Test
 271     public void testGetChildrenUnmodifiable() {
 272         Rectangle rect1 = new Rectangle();
 273         Rectangle rect2 = new Rectangle();
 274         Rectangle rect3 = new Rectangle();
 275 
 276         Group g = new Group();
 277         ParentShim.getChildren(g).addAll(rect1,rect2,rect3);
 278 
 279         assertEquals(3, g.getChildrenUnmodifiable().size());
 280         assertSame(rect1, g.getChildrenUnmodifiable().get(0));
 281         assertSame(rect2, g.getChildrenUnmodifiable().get(1));
 282         assertSame(rect3, g.getChildrenUnmodifiable().get(2));
 283     }
 284 
 285     @Test
 286     public void testGetChildrenUnmodifiableCantBeModified() {
 287         Rectangle rect1 = new Rectangle();
 288         Rectangle rect2 = new Rectangle();
 289         Rectangle rect3 = new Rectangle();
 290 
 291         Group g = new Group();
 292         ParentShim.getChildren(g).addAll(rect1,rect2,rect3);
 293 
 294         try {
 295             g.getChildrenUnmodifiable().add(new Rectangle());
 296             fail("UnsupportedOperationException should have been thrown.");
 297         } catch (UnsupportedOperationException uoe) {
 298             // expected
 299         }
 300     }
 301 
 302     @Test
 303     public void testRequestLayoutWithoutParent() {
 304         Group g = new Group();
 305         g.layout();
 306         // this shouldn't fail even when the group doesn't have a parent
 307         g.requestLayout();
 308     }
 309 
 310     @Test
 311     public void testRequestLayoutWithoutScene() {
 312         Group g = new Group();
 313         g.setManaged(false);
 314         g.layout();
 315         // this shouldn't fail even when the scene is not set
 316         g.requestLayout();
 317     }
 318 
 319     @Test
 320     public void testRequestLayoutClearsCache() {
 321         Group g = new Group();
 322         Rectangle r = new Rectangle(100,200);
 323         ParentShim.getChildren(g).add(r);
 324 
 325         g.requestLayout();
 326         assertEquals(100, g.prefWidth(-1), 1e-100);
 327         assertEquals(200, g.prefHeight(-1), 1e-100);
 328 
 329         r.setWidth(150);
 330         r.setHeight(250);
 331         g.requestLayout();
 332 
 333         assertEquals(150, g.prefWidth(-1), 1e-100);
 334         assertEquals(250, g.prefHeight(-1), 1e-100);
 335     }
 336 
 337     @Test
 338     public void testPrefWidthIncludesChildLayoutX() {
 339         Rectangle r = new Rectangle(10,10,100,100);
 340         r.setLayoutX(10);
 341         MockParent p = new MockParent(r);
 342 
 343         assertEquals(120, p.prefWidth(-1), 0);


 345 
 346     @Test
 347     public void testPrefHeightIncludesChildLayoutY() {
 348         Rectangle r = new Rectangle(10,10,100,100);
 349         r.setLayoutY(10);
 350         MockParent p = new MockParent(r);
 351 
 352         assertEquals(120, p.prefHeight(-1), 0);
 353     }
 354 
 355     @Test
 356     public void testDuplicates() {
 357         Group g = new Group();
 358 
 359         Rectangle r1 = new Rectangle();
 360         Rectangle r2 = new Rectangle();
 361         Rectangle r3 = new Rectangle();
 362         Rectangle r4 = new Rectangle();
 363 
 364         try {
 365         ParentShim.getChildren(g).addAll(r1, r2, r3, r4);
 366         ParentShim.getChildren(g).add(r2);
 367         fail();
 368         } catch (IllegalArgumentException e) {
 369 
 370         }
 371     }
 372 
 373     @Test(expected=NullPointerException.class)
 374     public void testAddingNullChild() {
 375         Group g = new Group();
 376         ParentShim.getChildren(g).add(null);
 377     }
 378 
 379     @Test(expected=NullPointerException.class)
 380     public void testNullCheckIsDoneBeforeTestForDuplicates() {
 381         Group g = new Group();
 382         ParentShim.getChildren(g).addAll(null, new Rectangle(), null);
 383     }
 384 
 385     @Test(expected=IllegalArgumentException.class)
 386     public void testAddingClipNodeTwice() {
 387         Group g = new Group();
 388 
 389         Node clipParent = new Rectangle();
 390         Node clipNode = new Rectangle();
 391 
 392         clipParent.setClip(clipNode);
 393         try {
 394             // try to add node which is already set as a clip
 395             ParentShim.getChildren(g).add(clipNode);
 396             fail();
 397         } catch (IllegalArgumentException e) {
 398         }
 399 
 400         // try again
 401         ParentShim.getChildren(g).add(clipNode);
 402     }
 403 
 404     @Test
 405     public void testAddingFixedClipNode() {
 406         Group g = new Group();
 407 
 408         Node clipParent = new Rectangle();
 409         Node clipNode = new Rectangle();
 410 
 411         clipParent.setClip(clipNode);
 412         try {
 413             // try to add node which is already set as a clip
 414             ParentShim.getChildren(g).add(clipNode);
 415             fail();
 416         } catch (IllegalArgumentException e) {
 417         }
 418 
 419         // fix the problem and add again
 420         clipParent.setClip(null);
 421         ParentShim.getChildren(g).add(clipNode);
 422     }
 423 
 424     @Test(expected=IllegalArgumentException.class)
 425     public void testFalsePermutation() {
 426         Group g = new Group();
 427 
 428         Rectangle r1 = new Rectangle();
 429         Rectangle r2 = new Rectangle();
 430         Rectangle r3 = new Rectangle();
 431         Rectangle r4 = new Rectangle();
 432 
 433         ParentShim.getChildren(g).addAll(r1, r2, r3, r4);
 434         ParentShim.getChildren(g).setAll(r1, r2, r2, r4);
 435     }
 436 
 437     @Test
 438     public void testFalseDuplicates() {
 439         Group g = new Group();
 440 
 441         Rectangle r1 = new Rectangle();
 442         Rectangle r2 = new Rectangle();
 443         Rectangle r3 = new Rectangle();
 444         Rectangle r4 = new Rectangle();
 445 
 446         ParentShim.getChildren(g).addAll(r1, r2);
 447         try {
 448             ParentShim.getChildren(g).addAll(r3, r4, r2);
 449             fail();
 450         } catch (IllegalArgumentException e) {
 451         }
 452         try {
 453             ParentShim.getChildren(g).add(r3);
 454         } catch (IllegalArgumentException e) {
 455             fail();
 456         }
 457 
 458     }
 459 
 460     @Test
 461     public void nodeCanBeAddedDuringLayout() {
 462         final Rectangle rect = new Rectangle(100, 100);
 463         final Group g = new Group(rect);
 464 
 465         Group root = new Group() {
 466             @Override protected void layoutChildren() {
 467                 ParentShim.getChildren(this).setAll(g);
 468             }
 469         };
 470 
 471         Scene scene = new Scene(root);
 472 
 473         stage.setScene(scene);
 474         stage.show();
 475 
 476         // there are assertions tested down the stack (see RT-21746)
 477     }
 478 
 479     private static class LGroup extends Group {
 480 
 481         private boolean layoutCalled;
 482 
 483         @Override
 484         public void requestLayout() {
 485             super.requestLayout();
 486             layoutCalled = true;
 487         }
 488 
 489         public void assertAndClear(boolean b) {
 490             assertEquals(b, layoutCalled);
 491             layoutCalled = false;
 492         }
 493 
 494         public void clear() {
 495             layoutCalled = false;
 496         }
 497 
 498     }
 499 
 500     @Test
 501     public void requestLayoutAlwaysCalledUpToTheLayoutRoot() {
 502         final Group root = new Group();
 503         final LGroup lroot = new LGroup();
 504         lroot.setManaged(false);
 505         ParentShim.getChildren(root).add(lroot);
 506         final LGroup sub = new LGroup();
 507         ParentShim.getChildren(lroot).add(sub);
 508 
 509         lroot.clear();
 510         sub.clear();
 511         root.layout();
 512 
 513         lroot.assertAndClear(false);
 514         sub.assertAndClear(false);
 515 
 516         sub.requestLayout();
 517 
 518         lroot.assertAndClear(true);
 519         sub.assertAndClear(true);
 520 
 521         sub.requestLayout();
 522         lroot.assertAndClear(true);
 523         sub.assertAndClear(true);
 524     }
 525     
 526     @Test
 527     public void unmanagedParentTest() {


 553         outerGroup.getChildren().add(intermediate);
 554 
 555         innerGroup.assertAndClear(false);
 556         intermediate.assertAndClear(true);
 557         outerGroup.assertAndClear(true);
 558 
 559         innerGroup.requestLayout();
 560         intermediate.getChildren().add(innerGroup);
 561 
 562         innerGroup.assertAndClear(true);
 563         intermediate.assertAndClear(true);
 564         outerGroup.assertAndClear(false);
 565 
 566     }
 567 
 568     @Test
 569     public void requestLayoutTriggersPulse() {
 570         final Group root = new Group();
 571         final LGroup lroot = new LGroup();
 572         lroot.setManaged(false);
 573         ParentShim.getChildren(root).add(lroot);
 574         final LGroup sub = new LGroup();
 575         ParentShim.getChildren(lroot).add(sub);
 576 
 577         toolkit.clearPulseRequested();
 578         sub.requestLayout();
 579         Scene scene = new Scene(root);
 580         assertTrue(toolkit.isPulseRequested());
 581         toolkit.clearPulseRequested();
 582         root.layout();
 583 
 584         sub.requestLayout();
 585 
 586         assertTrue(toolkit.isPulseRequested());
 587     }
 588 
 589     @Test
 590     public void requestLayoutNotPropagatingDuringLayout() {
 591         final LGroup lroot = new LGroup();
 592         lroot.setManaged(false);
 593         final LGroup sub = new LGroup() {
 594 
 595             @Override
 596             protected void layoutChildren() {
 597                 GroupShim.layoutChildren((Group)getParent());
 598                 requestLayout();
 599             }
 600 
 601         };
 602         ParentShim.getChildren(lroot).add(sub);
 603         lroot.clear();
 604         sub.clear();
 605 
 606         sub.requestLayout();
 607         lroot.assertAndClear(true);
 608         sub.assertAndClear(true);
 609 
 610         lroot.layout();
 611 
 612         lroot.assertAndClear(false);
 613         sub.assertAndClear(true);
 614     }
 615 
 616     @Test
 617     public void testChildrenPermutationInvalidatesManagedChildrenAndLayout() {
 618         LGroup root = new LGroup();
 619         Rectangle r1 = new Rectangle();
 620         Rectangle r2 = new Rectangle();
 621 
 622         ParentShim.getChildren(root).addAll(r1, r2);
 623 
 624         root.clear();
 625 
 626         ParentShim.getManagedChildren(root).equals(ParentShim.getChildren(root));
 627 
 628         ParentShim.getChildren(root).setAll(r2, r1);
 629 
 630         ParentShim.getManagedChildren(root).equals(ParentShim.getChildren(root));
 631         root.assertAndClear(true);
 632 
 633         r2.toFront();
 634 
 635         ParentShim.getManagedChildren(root).equals(ParentShim.getChildren(root));
 636         root.assertAndClear(true);
 637     }
 638 
 639     @Test
 640     public void newChildInvalidatesLayoutWhenLayoutBoundsAreValidatedImmediately() {
 641         Group root = new Group();
 642         final AtomicBoolean layoutCalled = new AtomicBoolean();
 643         final AtomicBoolean testReady = new AtomicBoolean();
 644         LGroup sub = new LGroup() {
 645 
 646             @Override
 647             protected void layoutChildren() {
 648                 if (testReady.get()) {
 649                     assertAndClear(true);
 650                     layoutCalled.set(true);
 651                 }
 652             }
 653 
 654         };
 655         ParentShim.getChildren(root).add(sub);
 656         root.getLayoutBounds(); // validate
 657         sub.getBoundsInParent(); // validate
 658 
 659         root.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
 660             // ChangeListener will immediately validate the bounds
 661         });
 662         sub.clear();
 663 
 664         testReady.set(true);
 665         ParentShim.getChildren(sub).add(new Rectangle());
 666         assertTrue(layoutCalled.get());
 667     }
 668 
 669     @Test
 670     public void sceneListenerCanAddChild() {
 671         final Group root = new Group();
 672         final Scene scene = new Scene(root, 600, 450);
 673 
 674         final Group child = new Group(new Group(), new Group(), new Group());
 675 
 676         ParentShim.getChildren(child).get(1).sceneProperty().addListener(o -> ParentShim.getChildren(child).add(2, new Group()));
 677 
 678         ParentShim.getChildren(root).add(child);
 679 
 680         assertSame(scene, ParentShim.getChildren(child).get(3).getScene());
 681     }
 682 
 683     public static class MockParent extends Parent {
 684         public MockParent(Node... children) {
 685             ParentShim.getChildren(this).addAll(children);
 686         }
 687     }
 688 }