From e25dd72efe36de7e59780cda0de472c1183be028 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 2 Feb 2016 11:23:58 +0200 Subject: Add simple support for generic reset for data to DataProvider Adds a simple test that sorts the data and verifies that the content does not actually change with just sorting. Change-Id: I0d8889694a98da1d55e0335714f63abaedb5684a --- .../connectors/data/typed/DataSourceConnector.java | 3 +- .../communication/data/typed/DataProvider.java | 24 ++++- .../tests/dataprovider/DummyDataProviderTest.java | 104 +++++++++++++++++++-- .../tests/dataprovider/DummyDataProviderUI.java | 40 +++++++- 4 files changed, 155 insertions(+), 16 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/data/typed/DataSourceConnector.java b/client/src/com/vaadin/client/connectors/data/typed/DataSourceConnector.java index 59d72baa67..1d4521c5b3 100644 --- a/client/src/com/vaadin/client/connectors/data/typed/DataSourceConnector.java +++ b/client/src/com/vaadin/client/connectors/data/typed/DataSourceConnector.java @@ -59,7 +59,8 @@ public class DataSourceConnector extends AbstractExtensionConnector { public void resetSize(long size) { ds.asList().clear(); // Inform the server-side that all keys are now dropped. - for (String key : keyToJson.keySet()) { + Set keySet = new HashSet(keyToJson.keySet()); + for (String key : keySet) { dropKey(key); } sendDroppedKeys(); diff --git a/server/src/com/vaadin/server/communication/data/typed/DataProvider.java b/server/src/com/vaadin/server/communication/data/typed/DataProvider.java index e975792713..9417d0a1f0 100644 --- a/server/src/com/vaadin/server/communication/data/typed/DataProvider.java +++ b/server/src/com/vaadin/server/communication/data/typed/DataProvider.java @@ -197,8 +197,10 @@ public class DataProvider extends AbstractExtension { } } - private Collection data; private Collection> generators = new LinkedHashSet>(); + private boolean reset = false; + + private Collection data; private DataProviderClientRpc rpc; // TODO: Allow customizing the used key mapper private DataKeyMapper keyMapper = new KeyMapper(); @@ -220,17 +222,17 @@ public class DataProvider extends AbstractExtension { } /** - * Initially we need to push all the data to the client. - * - * TODO: The same is true for unknown size changes. + * Initially and in the case of a reset all data should be pushed to the + * client. */ @Override public void beforeClientResponse(boolean initial) { super.beforeClientResponse(initial); - if (initial) { + if (initial || reset) { getRpcProxy(DataProviderClientRpc.class).resetSize(data.size()); pushData(0, data); + reset = false; } } @@ -355,4 +357,16 @@ public class DataProvider extends AbstractExtension { } } + /** + * Informs the DataProvider that the collection has changed. + */ + public void reset() { + if (reset) { + return; + } + + reset = true; + markAsDirty(); + } + } diff --git a/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderTest.java b/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderTest.java index 9771f7b0f6..e82f25ba04 100644 --- a/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderTest.java +++ b/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderTest.java @@ -17,7 +17,11 @@ package com.vaadin.tests.dataprovider; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; import org.junit.Test; @@ -25,6 +29,7 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import com.vaadin.shared.data.DataProviderConstants; +import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.tests.fieldgroup.ComplexPerson; import com.vaadin.tests.tb3.SingleBrowserTest; @@ -33,6 +38,32 @@ import elemental.json.JsonObject; public class DummyDataProviderTest extends SingleBrowserTest { + // Each test uses a set of person objects (generated json) that is supposed + // to match the data sent to the client-side. + private List personObjects = new ArrayList(); + // Persons are created exactly the same way as in the test, so we should + // have identical data. + private List persons = DummyDataProviderUI.createPersons( + DummyDataProviderUI.PERSON_COUNT, new Random( + DummyDataProviderUI.RANDOM_SEED)); + // For each person we generate a string key, that should match the one + // DataProvider gives to it. + private Map personToKeyMap = new HashMap(); + + { + int key = 0; + for (ComplexPerson p : persons) { + personToKeyMap.put(p, "" + (++key)); + } + } + + @Override + public void setup() throws Exception { + super.setup(); + + setDebug(true); + } + @Override protected Class getUIClass() { return DummyDataProviderUI.class; @@ -40,9 +71,7 @@ public class DummyDataProviderTest extends SingleBrowserTest { @Test public void testVerifyJsonContent() { - Random r = new Random(DummyDataProviderUI.RANDOM_SEED); - List persons = DummyDataProviderUI.createPersons( - DummyDataProviderUI.PERSON_COUNT, r); + createPersonObjects(); openTestURL(); @@ -54,13 +83,74 @@ public class DummyDataProviderTest extends SingleBrowserTest { List personData = labels.subList(1, size); - int key = 0; - for (WebElement e : personData) { + for (int i = 0; i < personData.size(); ++i) { + WebElement e = personData.get(i); + JsonObject j = personObjects.get(i); + assertEquals("Json did not match.", j.toJson(), e.getText()); + } + + assertNoErrorNotifications(); + } + + private void createPersonObjects() { + for (ComplexPerson p : persons) { JsonObject j = Json.createObject(); - ComplexPerson p = persons.get(key); - j.put(DataProviderConstants.KEY, "" + (++key)); + j.put(DataProviderConstants.KEY, personToKeyMap.get(p)); j.put("name", p.getLastName() + ", " + p.getFirstName()); + personObjects.add(j); + } + } + + @Test + public void testSortDoesNotChangeContent() { + // Sort our internal data to match the order after sort. + Collections.sort(persons, DummyDataProviderUI.nameComparator); + createPersonObjects(); + + openTestURL(); + + $(ButtonElement.class).id("sort").click(); + + // Second sort would show if any keys got destroyed/recreated. + $(ButtonElement.class).id("sort").click(); + + int size = DummyDataProviderUI.PERSON_COUNT + 1; + List labels = findElements(By.className("v-label")); + + assertEquals("Label count did not match person count", size, + labels.size()); + + List personData = labels.subList(1, size); + + for (int i = 0; i < personData.size(); ++i) { + WebElement e = personData.get(i); + JsonObject j = personObjects.get(i); assertEquals("Json did not match.", j.toJson(), e.getText()); } + + assertNoErrorNotifications(); + } + + @Test + public void testRemoveWorksAfterSort() { + // Sort our internal data to match the order after sort. + Collections.sort(persons, DummyDataProviderUI.nameComparator); + createPersonObjects(); + + openTestURL(); + + $(ButtonElement.class).id("sort").click(); + + String text = findElements(By.className("v-label")).get(3).getText(); + String json = personObjects.get(2).toJson(); + assertEquals("Data not sorted", json, text); + + $(ButtonElement.class).id("remove").click(); + + text = findElements(By.className("v-label")).get(3).getText(); + json = personObjects.get(3).toJson(); + assertEquals("Data not removed", json, text); + + assertNoErrorNotifications(); } } diff --git a/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderUI.java b/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderUI.java index 26a0277274..095f4d694c 100644 --- a/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderUI.java +++ b/uitest/src/com/vaadin/tests/dataprovider/DummyDataProviderUI.java @@ -17,6 +17,8 @@ package com.vaadin.tests.dataprovider; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Random; @@ -41,10 +43,14 @@ public class DummyDataProviderUI extends AbstractTestUI { public static class DummyDataComponent extends AbstractComponent { private DataProvider dataProvider; - private Collection data; + private List data; public DummyDataComponent(Collection data) { - this.data = data; + if (data instanceof List) { + this.data = (List) data; + } else { + this.data = new ArrayList(data); + } dataProvider = DataProvider.create(data, this); dataProvider .addDataGenerator(new TypedDataGenerator() { @@ -74,10 +80,25 @@ public class DummyDataProviderUI extends AbstractTestUI { dataProvider.remove(person); } } + + public void sort(Comparator comparator) { + Collections.sort(data, comparator); + dataProvider.reset(); + } } public static final int RANDOM_SEED = 1337; public static final int PERSON_COUNT = 20; + public static final Comparator nameComparator = new Comparator() { + + @Override + public int compare(ComplexPerson p1, ComplexPerson p2) { + int fn = p1.getFirstName().compareTo(p2.getFirstName()); + int ln = p1.getLastName().compareTo(p2.getLastName()); + return fn != 0 ? fn : ln; + } + }; + private Random r = new Random(RANDOM_SEED); private List persons = createPersons(PERSON_COUNT, r); private DummyDataComponent dummy; @@ -100,7 +121,20 @@ public class DummyDataProviderUI extends AbstractTestUI { dummy.addItem(ComplexPerson.create(r)); } }); - addComponent(new HorizontalLayout(add, remove)); + Button sort = new Button("Sort content", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + dummy.sort(nameComparator); + } + }); + + // Button Ids + remove.setId("remove"); + add.setId("add"); + sort.setId("sort"); + + addComponent(new HorizontalLayout(add, remove, sort)); addComponent(dummy); } -- cgit v1.2.3