package org.fxmisc.flowless;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class CellCreationAndLayoutEfficiencyTest extends FlowlessTestBase {

    private StackPane stackPane;

    @Override
    public void start(Stage stage) throws Exception {
        super.start(stage);
        stackPane = new StackPane();
        // 25 cells (each 16px high) fit into the viewport
        stage.setScene(new Scene(stackPane, 200, 400));
        stage.show();
    }

    @Test
    public void test() {
        Counter cellCreations = new Counter();
        Counter cellLayouts = new Counter();
        ObservableList<String> items = FXCollections.observableArrayList();
        for(int i = 0; i < 20; ++i) {
            items.addAll("red", "green", "blue", "purple");
        }
        VirtualFlow<String, ?> flow = VirtualFlow.createVertical(
                items,
                color -> {
                    cellCreations.inc();
                    Region reg = new Region() {
                        @Override
                        protected void layoutChildren() {
                            cellLayouts.inc();
                            super.layoutChildren();
                        }
                    };
                    reg.setPrefHeight(16.0);
                    reg.setStyle("-fx-background-color: " + color);
                    return Cell.wrapNode(reg);
                });

        interact(() -> stackPane.getChildren().add(flow));
        cellCreations.reset();
        cellLayouts.reset();

        // update an item in the viewport
        interact(() -> items.set(10, "yellow"));
        assertEquals(1, cellCreations.getAndReset());
        assertEquals(1, cellLayouts.getAndReset());

        // update an item outside the viewport
        interact(() -> items.set(30, "yellow"));
        assertEquals(0, cellCreations.getAndReset());
        assertEquals(0, cellLayouts.getAndReset());

        // delete an item in the middle of the viewport
        interact(() -> items.remove(12));
        assertEquals(1, cellCreations.getAndReset());
        assertEquals(1, cellLayouts.getAndReset());

        // add an item in the middle of the viewport
        interact(() -> items.add(12, "yellow"));
        assertEquals(1, cellCreations.getAndReset());
        assertEquals(1, cellLayouts.getAndReset());

        // scroll 5 items down
        interact(() -> flow.showAsFirst(5));
        assertEquals(5, cellCreations.getAndReset());
        assertEquals(5, cellLayouts.getAndReset());

        // scroll 50 items down (only 25 fit into the viewport)
        interact(() -> flow.showAsFirst(55));
        assertEquals(25, cellCreations.getAndReset());
        assertEquals(25, cellLayouts.getAndReset());
    }
}
@@ -233,16 +233,41 @@
 .Stage;%0A
+import org.junit.Before;%0A
 import o
@@ -421,464 +421,262 @@
 ate 
-StackPane stackPane;%0A%0A    @Override%0A    public void start(Stage stage) throws Exception %7B%0A        super.start(stage);%0A        stackPane = new StackPane();%0A        // 25 cells (each 16px high) fit into the viewport%0A        stage.setScene(new Scene(stackPane, 200, 400));%0A        stage.show();%0A    %7D%0A%0A    @Test%0A    public void test() %7B%0A        Counter cellCreations = new Counter();%0A        Counter cellLayouts = new Counter();%0A        ObservableList%3CString%3E
+ObservableList%3CString%3E items;%0A    private Counter cellCreations = new Counter();%0A    private Counter cellLayouts = new Counter();%0A    private VirtualFlow%3CString, ?%3E flow;%0A%0A    @Override%0A    public void start(Stage stage) %7B%0A        // set up items%0A       
  ite
@@ -825,24 +825,25 @@
       %7D%0A
+%0A
         
 VirtualF
@@ -834,38 +834,46 @@
         
-V
+// set up v
 irtual
-Flow%3CString, ?%3E
+ flow%0A       
  flow = 
@@ -1472,119 +1472,433 @@
     
-interact(() -%3E stackPane.getChildren().add(flow));%0A        cellCreations.reset();%0A        cellLayouts.reset();%0A
+StackPane stackPane = new StackPane();%0A        // 25 cells (each 16px high) fit into the viewport%0A        stackPane.getChildren().add(flow);%0A        stage.setScene(new Scene(stackPane, 200, 400));%0A        stage.show();%0A    %7D%0A%0A    @Before%0A    public void setup() %7B%0A        cellCreations.reset();%0A        cellLayouts.reset();%0A    %7D%0A%0A    @Test%0A    public void updating_an_item_in_viewport_only_creates_and_lays_out_cell_once() %7B
 %0A   
@@ -2083,32 +2083,133 @@
 getAndReset());%0A
+    %7D%0A    @Test%0A    public void updating_an_item_outside_viewport_does_not_create_or_lay_out_cell() %7B
 %0A        // upda
@@ -2387,32 +2387,133 @@
 getAndReset());%0A
+    %7D%0A%0A    @Test%0A    public void deleting_an_item_in_viewport_only_creates_and_lays_out_cell_once() %7B
 %0A        // dele
@@ -2693,32 +2693,131 @@
 getAndReset());%0A
+    %7D%0A%0A    @Test%0A    public void adding_an_item_in_viewport_only_creates_and_lays_out_cell_once() %7B
 %0A        // add 
@@ -3001,32 +3001,157 @@
 getAndReset());%0A
+    %7D%0A%0A    @Test%0A    public void scrolling_so_partial_viewport_update_creates_and_lays_out_equal_number_of_cells_scrolled() %7B
 %0A        // scro
@@ -3317,16 +3317,147 @@
 set());%0A
+    %7D%0A%0A    @Test%0A    public void scrolling_so_full_viewport_update_creates_and_lays_out_max_cells_renderable_in_viewport_bounds() %7B
 %0A       

Split up single test into multiple tests