/* * JBoss, Home of Professional Open Source * Copyright 2010-2016, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.richfaces.tests.metamer.ftest.richCollapsibleSubTable; import static java.text.MessageFormat.format; import static org.testng.Assert.assertEquals; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import org.jboss.arquillian.graphene.Graphene; import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.richfaces.model.SortMode; import org.richfaces.tests.metamer.ftest.annotations.IssueTracking; import org.richfaces.tests.metamer.ftest.extension.attributes.coverage.annotations.CoversAttributes; import org.richfaces.tests.metamer.ftest.extension.configurator.skip.On; import org.richfaces.tests.metamer.ftest.extension.configurator.skip.annotation.AndExpression; import org.richfaces.tests.metamer.ftest.extension.configurator.skip.annotation.Skip; import org.richfaces.tests.metamer.ftest.extension.configurator.templates.annotation.Templates; import org.richfaces.tests.metamer.ftest.extension.configurator.use.annotation.UseForAllTests; import org.richfaces.tests.metamer.ftest.extension.configurator.use.annotation.ValuesFrom; import org.richfaces.tests.metamer.model.Employee; import org.testng.annotations.Test; import com.google.common.collect.Lists; /** * @author <a href="mailto:lfryc@redhat.com">Lukas Fryc</a> * @author <a href="mailto:jstefek@redhat.com">Jiri Stefek</a> */ public class TestCollapsibleSubTableSorting extends AbstractCollapsibleSubTableTest { @FindBy(css = ".rf-dt[id$=richDataTable]") private DataTableWithCSTWithBuiltInSortingHeader dataTableWithCSTWithBuiltInSortingHeader; @FindBy(css = ".rf-dt[id$=richDataTable]") private DataTableWithCSTWithSortingHeader dataTableWithCSTWithSortingHeader; private final int rows = 15; @UseForAllTests(valuesFrom = ValuesFrom.FROM_FIELD, value = "samples") private String sample; private final String[] samples = { "builtInFilteringAndSorting", "sorting-using-column" }; private SortMode sortMode = SortMode.multi; private SortingState sortingStateMen; private SortingState sortingStateWomen; @Override public String getComponentTestPagePath() { return format("richCollapsibleSubTable/{0}.xhtml", sample); } public DataTableWithCSTWithBuiltInSortingHeader getDataTable() { return sample.equals("builtInFilteringAndSorting") ? dataTableWithCSTWithBuiltInSortingHeader : dataTableWithCSTWithSortingHeader; } private void testSorting(boolean isSingle) { if (isSingle) { sortMode = SortMode.single; } else { sortMode = SortMode.multi; } attsSetter() .setAttribute(CollapsibleSubTableAttributes.rows).toValue(rows) .setAttribute(CollapsibleSubTableAttributes.sortMode).toValue(sortMode) .asSingleAction().perform(); sortingStateMen = new SortingState(getEmployees(Boolean.TRUE)); sortingStateWomen = new SortingState(getEmployees(Boolean.FALSE)); verifySortingInBothSubTables(SortBy.NAME); verifySortingInBothSubTables(SortBy.TITLE); verifySortingInBothSubTables(SortBy.NAME); verifySortingInBothSubTables(SortBy.TITLE); } @Test @Templates(exclude = "uiRepeat") @CoversAttributes("sortMode") @IssueTracking("https://issues.jboss.org/browse/RF-11302") public void testSortingMulti() { testSorting(false); } @Test @Templates("uiRepeat")// RFPL-4156 @Skip(expressions = { @AndExpression({ On.Container.Tomcat7.class, On.JSF.Mojarra.class }), @AndExpression({ On.Container.Tomcat8.class, On.JSF.Mojarra.class }) }) @CoversAttributes("sortMode") @IssueTracking("https://issues.jboss.org/browse/RF-11302") public void testSortingMultiInUiRepeat() { testSortingMulti(); } @Test @CoversAttributes("sortMode") @IssueTracking("https://issues.jboss.org/browse/RF-11302") public void testSortingSingle() { testSorting(true); } private void verifySortingInBothSubTables(final SortBy by) { getDataTable().sortBy(by); sortingStateMen.sortEmployees(sortMode, by); sortingStateWomen.sortEmployees(sortMode, by); verifySortingInSubTable(sortingStateMen, Boolean.TRUE); verifySortingInSubTable(sortingStateWomen, Boolean.FALSE); } private void verifySortingInSubTable(final SortingState state, boolean isMaleTable) { List<Employee> expectedSortedEmployees = state.getSortedEmployees().subList(0, rows); CollapsibleSubTableWithEmployees table = getSubTable(isMaleTable); int rowCount = table.advanced().getNumberOfVisibleRows(); assertEquals(rowCount, expectedSortedEmployees.size()); EmployeeRecord entry; for (int i = 0; i < rowCount; i++) { entry = table.getRow(i); assertEquals(entry.getName(), expectedSortedEmployees.get(i).getName()); assertEquals(entry.getTitle(), expectedSortedEmployees.get(i).getTitle()); } } public static enum SortBy { NAME, TITLE, BIRTHDAY; } public static class DataTableWithCSTWithBuiltInSortingHeader extends DataTableWithCST { @FindByJQuery(".rf-cst-shdr .rf-dt-srt-btn:eq(2)") private WebElement sortByDate; @FindByJQuery(value = ".rf-cst-shdr:eq(1) .rf-dt-srt-btn:eq(2)") private WebElement sortByDate2; @FindByJQuery(value = ".rf-cst-shdr .rf-dt-srt-btn:eq(0)") private WebElement sortByName; @FindByJQuery(".rf-cst-shdr:eq(1) .rf-dt-srt-btn:eq(0)") private WebElement sortByName2; @FindByJQuery(value = ".rf-cst-shdr .rf-dt-srt-btn:eq(1)") private WebElement sortByTitle; @FindByJQuery(".rf-cst-shdr:eq(1) .rf-dt-srt-btn:eq(1)") private WebElement sortByTitle2; public void sortBy(SortBy by) { switch (by) { case NAME: Graphene.guardAjax(sortByName).click(); Graphene.guardAjax(sortByName2).click(); break; case TITLE: Graphene.guardAjax(sortByTitle).click(); Graphene.guardAjax(sortByTitle2).click(); break; case BIRTHDAY: Graphene.guardAjax(sortByDate).click(); Graphene.guardAjax(sortByDate2).click(); break; default: throw new UnsupportedOperationException("unknown sortBy " + by); } } } public static class DataTableWithCSTWithSortingHeader extends DataTableWithCSTWithBuiltInSortingHeader { @FindByJQuery(".rf-dt-hdr a:eq(0)") private WebElement sortByName; @FindByJQuery(".rf-dt-hdr a:eq(1)") private WebElement sortByTitle; @FindByJQuery(".rf-dt-hdr a:eq(2)") private WebElement sortByDate; @Override public void sortBy(SortBy by) { switch (by) { case NAME: Graphene.guardAjax(sortByName).click(); break; case TITLE: Graphene.guardAjax(sortByTitle).click(); break; case BIRTHDAY: Graphene.guardAjax(sortByDate).click(); break; default: throw new UnsupportedOperationException("unknown sortBy " + by); } } } public static class SortingState { private final List<Employee> initialEmployees; private List<Employee> sortedEmployees; private final LinkedHashMap<SortBy, Boolean> sortPriority = new LinkedHashMap<SortBy, Boolean>(); public SortingState(List<Employee> initialEmployees) { this.initialEmployees = initialEmployees; } public List<Employee> sortEmployees(final SortMode sortMode, final SortBy by) { sortedEmployees = Lists.newArrayList(initialEmployees); if (sortMode.equals(SortMode.single) && !sortPriority.containsKey(by)) { sortPriority.clear(); } if (sortPriority.containsKey(by)) { Boolean val = sortPriority.get(by); if (sortPriority.size() > 1) {// need to add it to the end of the collection if the value is there already sortPriority.remove(by); sortPriority.put(by, !val); } } else { sortPriority.put(by, !sortPriority.containsKey(by)); } sort(sortedEmployees, sortMode); return sortedEmployees; } public List<Employee> getSortedEmployees() { return sortedEmployees; } private void sort(List<Employee> list, final SortMode sortMode) { Collections.sort(list, new Comparator<Employee>() { @Override public int compare(Employee e1, Employee e2) { if (sortMode == SortMode.single) { SortBy sortBy = (SortBy) sortPriority.keySet().toArray()[0]; return _compare(sortPriority.get(sortBy), sortBy, e1, e2); } else { int result; for (SortBy sortBy : sortPriority.keySet()) { result = _compare(sortPriority.get(sortBy), sortBy, e1, e2); if (result != 0) { return result; } } return 0; } } }); } private int _compare(boolean isAscending, final SortBy by, Employee e1, Employee e2) { int result; switch (by) { case BIRTHDAY: Date d1 = e1.getBirthdate(); Date d2 = e2.getBirthdate(); d1 = (d1 == null ? new Date(0) : d1); d2 = (d2 == null ? new Date(0) : d2); result = d1.compareTo(d2); break; case NAME: result = e1.getName().compareToIgnoreCase(e2.getName()); break; case TITLE: result = e1.getTitle().compareToIgnoreCase(e2.getTitle()); break; default: throw new UnsupportedOperationException("unknown sortBy " + by); } return isAscending ? result : -result; } } }