diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-02-02 11:23:58 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-02-03 12:22:07 +0200 |
commit | e25dd72efe36de7e59780cda0de472c1183be028 (patch) | |
tree | 66b8a6902be8093582205062c99aff34dddbc875 | |
parent | 38396def32f9c58ce8b4c4d2df42310ef9b0605e (diff) | |
download | vaadin-framework-e25dd72efe36de7e59780cda0de472c1183be028.tar.gz vaadin-framework-e25dd72efe36de7e59780cda0de472c1183be028.zip |
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
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<String> keySet = new HashSet<String>(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<T> extends AbstractExtension { } } - private Collection<T> data; private Collection<TypedDataGenerator<T>> generators = new LinkedHashSet<TypedDataGenerator<T>>(); + private boolean reset = false; + + private Collection<T> data; private DataProviderClientRpc rpc; // TODO: Allow customizing the used key mapper private DataKeyMapper<T> keyMapper = new KeyMapper<T>(); @@ -220,17 +222,17 @@ public class DataProvider<T> 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<T> 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<JsonObject> personObjects = new ArrayList<JsonObject>(); + // Persons are created exactly the same way as in the test, so we should + // have identical data. + private List<ComplexPerson> 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<ComplexPerson, String> personToKeyMap = new HashMap<ComplexPerson, String>(); + + { + 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<ComplexPerson> persons = DummyDataProviderUI.createPersons( - DummyDataProviderUI.PERSON_COUNT, r); + createPersonObjects(); openTestURL(); @@ -54,13 +83,74 @@ public class DummyDataProviderTest extends SingleBrowserTest { List<WebElement> 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<WebElement> labels = findElements(By.className("v-label")); + + assertEquals("Label count did not match person count", size, + labels.size()); + + List<WebElement> 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<ComplexPerson> dataProvider; - private Collection<ComplexPerson> data; + private List<ComplexPerson> data; public DummyDataComponent(Collection<ComplexPerson> data) { - this.data = data; + if (data instanceof List) { + this.data = (List<ComplexPerson>) data; + } else { + this.data = new ArrayList<ComplexPerson>(data); + } dataProvider = DataProvider.create(data, this); dataProvider .addDataGenerator(new TypedDataGenerator<ComplexPerson>() { @@ -74,10 +80,25 @@ public class DummyDataProviderUI extends AbstractTestUI { dataProvider.remove(person); } } + + public void sort(Comparator<ComplexPerson> 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<ComplexPerson> nameComparator = new Comparator<ComplexPerson>() { + + @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<ComplexPerson> 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); } |