package com.vaadin.data.provider; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import org.junit.Assert; import org.junit.Test; import com.vaadin.data.HierarchyData; import com.vaadin.server.SerializablePredicate; public class InMemoryHierarchicalDataProviderTest extends DataProviderTestBase<InMemoryHierarchicalDataProvider<StrBean>> { private HierarchyData<StrBean> data; private List<StrBean> flattenedData; private List<StrBean> rootData; @Override public void setUp() { List<StrBean> randomBeans = StrBean.generateRandomBeans(20); flattenedData = new ArrayList<>(); rootData = new ArrayList<>(); data = new HierarchyData<>(); data.addItems(null, randomBeans.subList(0, 5)); data.addItems(randomBeans.get(0), randomBeans.subList(5, 10)); data.addItems(randomBeans.get(5), randomBeans.subList(10, 15)); data.addItems(null, randomBeans.subList(15, 20)); flattenedData.add(randomBeans.get(0)); flattenedData.add(randomBeans.get(5)); flattenedData.addAll(randomBeans.subList(10, 15)); flattenedData.addAll(randomBeans.subList(6, 10)); flattenedData.addAll(randomBeans.subList(1, 5)); flattenedData.addAll(randomBeans.subList(15, 20)); rootData.addAll(randomBeans.subList(0, 5)); rootData.addAll(randomBeans.subList(15, 20)); super.setUp(); } @Test(expected = IllegalArgumentException.class) public void hierarchyData_add_item_parent_not_in_hierarchy_throws() { new HierarchyData<>().addItem(new StrBean("", 0, 0), new StrBean("", 0, 0)); } @Test(expected = NullPointerException.class) public void hierarchyData_add_null_item_throws() { new HierarchyData<>().addItem(null, null); } @Test(expected = IllegalArgumentException.class) public void hierarchyData_add_item_already_in_hierarchy_throws() { StrBean bean = new StrBean("", 0, 0); new HierarchyData<>().addItem(null, bean).addItem(null, bean); } @Test public void hierarchyData_remove_root_item() { data.removeItem(null); Assert.assertTrue(data.getChildren(null).isEmpty()); } @Test public void hierarchyData_clear() { data.clear(); Assert.assertTrue(data.getChildren(null).isEmpty()); } @Test public void hierarchyData_re_add_removed_item() { StrBean item = rootData.get(0); data.removeItem(item).addItem(null, item); Assert.assertTrue(data.getChildren(null).contains(item)); } @Test public void setFilter() { getDataProvider().setFilter(item -> item.getValue().equals("Xyz") || item.getValue().equals("Baz")); Assert.assertEquals(10, sizeWithUnfilteredQuery()); getDataProvider().setFilter(item -> !item.getValue().equals("Foo") && !item.getValue().equals("Xyz")); Assert.assertEquals( "Previous filter should be replaced when setting a new one", 6, sizeWithUnfilteredQuery()); getDataProvider().setFilter(null); Assert.assertEquals("Setting filter to null should remove all filters", 20, sizeWithUnfilteredQuery()); } @Test public void addFilter() { getDataProvider().addFilter(item -> item.getId() <= 10); getDataProvider().addFilter(item -> item.getId() >= 5); Assert.assertEquals(5, sizeWithUnfilteredQuery()); } @Override public void filteringListDataProvider_convertFilter() { DataProvider<StrBean, String> strFilterDataProvider = getDataProvider() .withConvertedFilter( text -> strBean -> strBean.getValue().contains(text)); Assert.assertEquals("Only one item should match 'Xyz'", 1, strFilterDataProvider .size(new HierarchicalQuery<>("Xyz", null))); Assert.assertEquals("No item should match 'Zyx'", 0, strFilterDataProvider .size(new HierarchicalQuery<>("Zyx", null))); Assert.assertEquals("Unexpected number of matches for 'Foo'", 3, strFilterDataProvider .size(new HierarchicalQuery<>("Foo", null))); Assert.assertEquals("No items should've been filtered out", rootData.size(), strFilterDataProvider .size(new HierarchicalQuery<>(null, null))); } @Override public void filteringListDataProvider_defaultFilterType() { Assert.assertEquals("Only one item should match 'Xyz'", 1, getDataProvider().size(new HierarchicalQuery<>( strBean -> strBean.getValue().contains("Xyz"), null))); Assert.assertEquals("No item should match 'Zyx'", 0, dataProvider.size(new HierarchicalQuery<>( strBean -> strBean.getValue().contains("Zyx"), null))); Assert.assertEquals("Unexpected number of matches for 'Foo'", 3, getDataProvider() .size(new HierarchicalQuery<>(fooFilter, null))); } @Override public void testDefaultSortWithSpecifiedPostSort() { Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue) .thenComparing(Comparator.comparing(StrBean::getId).reversed()); setSortOrder(QuerySortOrder.asc("value").thenDesc("id").build(), comp); List<StrBean> list = getDataProvider() .fetch(createQuery(QuerySortOrder.asc("randomNumber").build(), Comparator.comparing(StrBean::getRandomNumber), null, null)) .collect(Collectors.toList()); Assert.assertEquals("Sorted data and original data sizes don't match", getDataProvider().fetch(new HierarchicalQuery<>(null, null)) .count(), list.size()); for (int i = 1; i < list.size(); ++i) { StrBean prev = list.get(i - 1); StrBean cur = list.get(i); // Test specific sort Assert.assertTrue( "Failure: " + prev.getRandomNumber() + " > " + cur.getRandomNumber(), prev.getRandomNumber() <= cur.getRandomNumber()); if (prev.getRandomNumber() == cur.getRandomNumber()) { // Test default sort Assert.assertTrue( prev.getValue().compareTo(cur.getValue()) <= 0); if (prev.getValue().equals(cur.getValue())) { Assert.assertTrue(prev.getId() > cur.getId()); } } } } @Override public void testDefaultSortWithFunction() { setSortOrder(QuerySortOrder.asc("value").build(), Comparator.comparing(StrBean::getValue)); List<StrBean> list = getDataProvider() .fetch(new HierarchicalQuery<>(null, null)) .collect(Collectors.toList()); Assert.assertEquals("Sorted data and original data sizes don't match", rootData.size(), list.size()); for (int i = 1; i < list.size(); ++i) { StrBean prev = list.get(i - 1); StrBean cur = list.get(i); // Test default sort Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0); } } @Override public void testListContainsAllData() { assertHierarchyCorrect(); } @Override public void testSortByComparatorListsDiffer() { Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue) .thenComparing(StrBean::getRandomNumber) .thenComparing(StrBean::getId); List<StrBean> list = getDataProvider().fetch( createQuery(QuerySortOrder.asc("value").thenAsc("randomNumber") .thenAsc("id").build(), comp, null, null)) .collect(Collectors.toList()); Assert.assertNotEquals("First value should not match", rootData.get(0), list.get(0)); Assert.assertEquals("Sorted data and original data sizes don't match", rootData.size(), list.size()); rootData.sort(comp); for (int i = 0; i < rootData.size(); ++i) { Assert.assertEquals("Sorting result differed", rootData.get(i), list.get(i)); } } @Override protected InMemoryHierarchicalDataProvider<StrBean> createDataProvider() { return new InMemoryHierarchicalDataProvider<>(data); } @Override protected void setSortOrder(List<QuerySortOrder> sortOrder, Comparator<StrBean> comp) { getDataProvider().setSortComparator(comp::compare); } @Override protected long sizeWithUnfilteredQuery() { return getFlattenedDataFromProvider(new ArrayList<>(), null).size(); } private void assertHierarchyCorrect() { Assert.assertEquals(flattenedData, getFlattenedData(new ArrayList<>(), null)); Assert.assertEquals(flattenedData, getFlattenedDataFromProvider(new ArrayList<>(), null)); } private List<StrBean> getFlattenedData(List<StrBean> flattened, StrBean item) { if (item != null) { flattened.add(item); } data.getChildren(item) .forEach(child -> getFlattenedData(flattened, child)); return flattened; } private List<StrBean> getFlattenedDataFromProvider(List<StrBean> flattened, StrBean item) { if (item != null) { flattened.add(item); } getDataProvider().fetchChildren(new HierarchicalQuery<>(null, item)) .forEach(child -> getFlattenedDataFromProvider(flattened, child)); return flattened; } private HierarchicalQuery<StrBean, SerializablePredicate<StrBean>> createQuery( List<QuerySortOrder> sortOrder, Comparator<StrBean> comp, SerializablePredicate<StrBean> filter, StrBean parent) { return new HierarchicalQuery<>(0, Integer.MAX_VALUE, sortOrder, comp, filter, parent); } }