/* * Copyright 2000-2016 Vaadin Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.vaadin.tests.server.component.combobox; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.vaadin.data.provider.DataCommunicator; import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.ListDataProvider; import com.vaadin.server.ClientMethodInvocation; import com.vaadin.server.ServerRpcManager; import com.vaadin.shared.ui.combobox.ComboBoxServerRpc; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.ComboBox; /** * Test for ComboBox data providers and filtering. * * @author Vaadin Ltd */ public class ComboBoxFilteringTest { private static final String[] PERSON_NAMES = new String[] { "Enrique Iglesias", "Henry Dunant", "Erwin Engelbrecht" }; private ComboBox<Person> comboBox; @Before public void setup() { comboBox = new ComboBox<>(); comboBox.setLocale(Locale.US); } @Test public void setItems_array_defaultFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "en" into the search field finds "Enrique Iglesias" // and "Henry Dunant", but not "Erwin Engelbrecht" comboBox.setItems(getPersonArray()); checkFiltering("en", "ennen", 3, 2); } @Test public void setItems_array_setItemCaptionAfterItems() { // Result: typing "en" into the search field finds "Enrique Iglesias" // and "Henry Dunant", but not "Erwin Engelbrecht" comboBox.setItems(getPersonArray()); // It shouldn't matter if this is done before or after setItems comboBox.setItemCaptionGenerator(Person::getFirstName); checkFiltering("en", "ennen", 3, 2); } @Test public void setItems_collection_defaultFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "en" into the search field finds "Enrique Iglesias" // and "Henry Dunant", but not "Erwin Engelbrecht" comboBox.setItems(getPersonCollection()); checkFiltering("en", "ennen", 3, 2); } @Test public void setItems_collection_setItemCaptionAfterItems() { // Result: typing "en" into the search field finds "Enrique Iglesias" // and "Henry Dunant", but not "Erwin Engelbrecht" comboBox.setItems(getPersonCollection()); // It shouldn't matter if this is done before or after setItems comboBox.setItemCaptionGenerator(Person::getFirstName); checkFiltering("en", "ennen", 3, 2); } @Test public void setItems_array_customFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "En" into the search field finds "Enrique Iglesias" // but not "Henry Dunant" or "Erwin Engelbrecht" comboBox.setItems(String::startsWith, getPersonArray()); checkFiltering("En", "en", 3, 1); } @Test public void setItems_collection_customFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "En" into the search field finds "Enrique Iglesias" // but not "Henry Dunant" or "Erwin Engelbrecht" comboBox.setItems(String::startsWith, getPersonCollection()); checkFiltering("En", "en", 3, 1); } @Test public void setListDataProvider_defaultFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "en" into the search field finds "Enrique Iglesias" // and "Henry Dunant", but not "Erwin Engelbrecht" comboBox.setDataProvider( DataProvider.ofCollection(getPersonCollection())); checkFiltering("en", "ennen", 3, 2); } @Test public void setListDataProvider_customFiltering() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Result: typing "En" into the search field finds "Enrique Iglesias" // but not "Henry Dunant" or "Erwin Engelbrecht" comboBox.setDataProvider(String::startsWith, DataProvider.ofCollection(getPersonCollection())); checkFiltering("En", "en", 3, 1); } public void invalid_dataProvider_compile_error() { DataProvider<Person, Address> dp = DataProvider .ofItems(getPersonArray()) .filteringByEquals(Person::getAddress); // uncommenting this causes a compile time error because of invalid data // provider filter type // comboBox.setDataProvider(dp); } @Test public void customDataProvider_filterByLastName() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Filters by last name, regardless of the item caption generator ListDataProvider<Person> ldp = DataProvider.ofItems(getPersonArray()); comboBox.setDataProvider(ldp.withConvertedFilter( text -> person -> person.getLastName().contains(text))); checkFiltering("u", "ab", 3, 1); } @Test public void customDataProvider_filterByLastNameWithAccessRestriction() { comboBox.setItemCaptionGenerator(Person::getFirstName); // Filters by last name, regardless of the item caption generator ListDataProvider<Person> ldp = DataProvider.ofItems(getPersonArray()); ldp.setFilter(person -> person.getFirstName().contains("nr")); // Same as above, but only showing a subset of the persons comboBox.setDataProvider(ldp.withConvertedFilter( text -> person -> person.getLastName().contains(text))); checkFiltering("t", "Engel", 2, 1); } @Test public void filterEmptyComboBox() { // Testing that filtering doesn't cause problems in the edge case where // neither setDataProvider nor setItems has been called checkFiltering("foo", "bar", 0, 0); } @Test public void setListDataProvider_notWrapped() { ListDataProvider<Person> provider = new ListDataProvider<>( Collections.emptyList()); comboBox.setDataProvider(provider); Assert.assertSame(provider, comboBox.getDataProvider()); } @Test public void setItems_hasListDataProvider() { comboBox.setItems(); Assert.assertEquals(ListDataProvider.class, comboBox.getDataProvider().getClass()); } private void checkFiltering(String filterText, String nonMatchingFilterText, int totalMatches, int matchingResults) { Assert.assertEquals( "ComboBox filtered out results with no filter applied", totalMatches, comboBoxSizeWithFilter(null)); Assert.assertEquals( "ComboBox filtered out results with empty filter string", totalMatches, comboBoxSizeWithFilter("")); Assert.assertEquals("ComboBox filtered out wrong number of results", matchingResults, comboBoxSizeWithFilter(filterText)); Assert.assertEquals( "ComboBox should have no results with a non-matching filter", 0, comboBoxSizeWithFilter(nonMatchingFilterText)); } private int comboBoxSizeWithFilter(String filter) { DataCommunicator<Person> dataCommunicator = comboBox .getDataCommunicator(); // Discard any currently pending RPC calls dataCommunicator.retrievePendingRpcCalls(); ServerRpcManager.getRpcProxy(comboBox, ComboBoxServerRpc.class) .setFilter(filter); dataCommunicator.beforeClientResponse(true); ClientMethodInvocation resetInvocation = dataCommunicator .retrievePendingRpcCalls().get(0); assert resetInvocation.getMethodName().equals("reset"); return ((Integer) resetInvocation.getParameters()[0]).intValue(); } private List<Person> getPersonCollection() { return Stream .of(PERSON_NAMES).map(name -> new Person(name.split(" ")[0], name.split(" ")[1], null, 0, Sex.MALE, null)) .collect(Collectors.toList()); } private Person[] getPersonArray() { return getPersonCollection().toArray(new Person[PERSON_NAMES.length]); } }