// $HeadURL$ // $Id$ // // Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College. // // Screensaver is an open-source project developed by the ICCB-L and NSRB labs // at Harvard Medical School. This software is distributed under the terms of // the GNU General Public License. package edu.harvard.med.screensaver.ui.arch.datatable; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Observable; import java.util.Observer; import junit.framework.TestCase; import edu.harvard.med.screensaver.db.SortDirection; import edu.harvard.med.screensaver.ui.arch.datatable.SortChangedEvent; import edu.harvard.med.screensaver.ui.arch.datatable.column.CompoundColumnComparator; import edu.harvard.med.screensaver.ui.arch.datatable.column.EnumColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.IntegerColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.RealColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.SelectableColumnTreeNode; import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumnManager; import edu.harvard.med.screensaver.ui.arch.datatable.column.TextColumn; import org.apache.log4j.Logger; import org.apache.myfaces.custom.tree2.TreeModel; public class TableColumnManagerTest extends TestCase { // static members private static final String BASIC_COLUMNS_GROUP = "Basic Columns"; private static final String ADVANCED_COLUMNS_GROUP = "Advanced Columns"; private static final String ADVANCED_SPECIAL_COLUMNS_GROUP = "Advanced Columns::Special"; private static Logger log = Logger.getLogger(TableColumnManagerTest.class); // instance data members private TableColumnManager<RowItem> _columnManager; private List<TableColumn<RowItem,?>> _columns; private TableColumn<RowItem,?> _currentSortColumn; private SortDirection _currentSortDirection; private IntegerColumn<RowItem> _idCol; private TextColumn<RowItem> _nameCol; private EnumColumn<RowItem,Status> _statusCol; private RealColumn<RowItem> _valueCol; private TextColumn<RowItem> _urlCol; private List<RowItem> _unsortedData; private List<RowItem> _sortedData; // public constructors and methods @Override protected void setUp() throws Exception { _columns = makeColumns(); _idCol = (IntegerColumn<RowItem>) _columns.get(0); assertEquals("ID", _idCol.getName()); _nameCol = (TextColumn<RowItem>) _columns.get(1); assertEquals("Name", _nameCol.getName()); _statusCol = (EnumColumn<RowItem,Status>) _columns.get(2); assertEquals("Status", _statusCol.getName()); _valueCol = (RealColumn<RowItem>) _columns.get(3); assertEquals("Value", _valueCol.getName()); _urlCol = (TextColumn<RowItem>) _columns.get(4); assertEquals("URL", _urlCol.getName()); _columnManager = new TableColumnManager<RowItem>(_columns, null, false); _columnManager.addObserver(new Observer() { @SuppressWarnings("unchecked") public void update(Observable o, Object obj) { if (obj instanceof SortChangedEvent) { SortChangedEvent<RowItem> event = (SortChangedEvent<RowItem>) obj; if (event.getColumn() != null) { _currentSortColumn = event.getColumn(); } if (event.getDirection() != null) { _currentSortDirection = event.getDirection(); } _sortedData = new ArrayList<RowItem>(_unsortedData); Collections.sort(_sortedData, new CompoundColumnComparator<RowItem>( _columnManager.getSortColumns(), _columnManager.getSortDirection())); } } }); _currentSortColumn = _columnManager.getSortColumn(); _currentSortDirection = _columnManager.getSortDirection(); _unsortedData = new ArrayList<RowItem>(); // Note: test data rows must be initially unsorted by every column! _unsortedData.add(new RowItem(1, "A", Status.ACTIVE, 3.5, new URL("https://screensaver.med.harvard.edu/screensaver"))); _unsortedData.add(new RowItem(2, "D", Status.DEAD, 2.0, new URL("http://www.java.sun.com"))); _unsortedData.add(new RowItem(4, "B", Status.NEW, -3.0, new URL("http://www.hibernate.org"))); _unsortedData.add(new RowItem(3, "C", Status.ACTIVE, 0.0, new URL("http://www.springframework.org"))); } public static List<TableColumn<RowItem,?>> makeColumns() { List<TableColumn<RowItem,?>> columns = new ArrayList<TableColumn<RowItem,?>>(); TableColumn<RowItem,?> idCol = new IntegerColumn<RowItem>( "ID", "The row's ID", TableColumn.UNGROUPED) { @Override public Integer getCellValue(RowItem row) { return row.getId(); } }; TableColumn<RowItem,?> nameCol = new TextColumn<RowItem>( "Name", "The row's name", BASIC_COLUMNS_GROUP) { @Override public String getCellValue(RowItem row) { return row.getName(); } }; TableColumn<RowItem,?> statusCol = new EnumColumn<RowItem,Status>( "Status", "The row's status", ADVANCED_COLUMNS_GROUP, Status.values()) { @Override public Status getCellValue(RowItem row) { return row.getStatus(); } @Override protected Comparator<RowItem> getAscendingComparator() { return new Comparator<RowItem>() { public int compare(RowItem row1, RowItem row2) { Integer orderedStatus1 = row1.getStatus().equals(Status.NEW) ? 0 : row1.getStatus().equals(Status.ACTIVE) ? 1 : 2; Integer orderedStatus2 = row2.getStatus().equals(Status.NEW) ? 0 : row2.getStatus().equals(Status.ACTIVE) ? 1 : 2; return orderedStatus1.compareTo(orderedStatus2); } }; } }; TableColumn<RowItem,?> valueCol = new RealColumn<RowItem>( "Value", "The row's value", ADVANCED_COLUMNS_GROUP, 3) { @Override public Double getCellValue(RowItem row) { return row.getValue(); } }; TableColumn<RowItem,?> urlCol = new TextColumn<RowItem>( "URL", "The row's URL", ADVANCED_SPECIAL_COLUMNS_GROUP) { @Override public String getCellValue(RowItem row) { return row.getUrl().toString(); } @Override protected Comparator<RowItem> getAscendingComparator() { return new Comparator<RowItem>() { public int compare(RowItem row1, RowItem row2) { return row1.getUrl().toString().compareTo(row2.getUrl().toString()); } }; } }; columns.add(idCol); columns.add(nameCol); columns.add(statusCol); columns.add(valueCol); columns.add(urlCol); return columns; } /** * Tests resetting TableColumnManager with an entirely new set of columns */ public void testSetColumns() { assertTrue("initial columns", _columns.equals(_columnManager.getAllColumns())); assertTrue("initial visible columns", _columns.equals(_columnManager.getVisibleColumns())); List<TableColumn<RowItem,?>> subList = _columns.subList(1, _columns.size() - 1); _columnManager.setColumns(subList); assertTrue("new columns", subList.equals(_columnManager.getAllColumns())); assertTrue("new visible", subList.equals(_columnManager.getVisibleColumns())); } public void testColumnVisibility() { assertTrue("all columns initially visible", _columns.equals(_columnManager.getVisibleColumns())); _idCol.setVisible(false); assertTrue("column hidden, via column object update", !_columnManager.getVisibleColumns().contains(_idCol) && _columnManager.getVisibleColumns().size() == _columns.size() - 1); _idCol.setVisible(true); assertTrue("column unhidden, via column object update", _columnManager.getVisibleColumns().contains(_idCol) && _columns.size() == _columnManager.getVisibleColumns().size()); TreeModel model = _columnManager.getColumnsTreeModel(); SelectableColumnTreeNode node = (SelectableColumnTreeNode) model.getNodeById("0:0"); assertEquals("using idCol node", node.getColumn(), _idCol); node.setChecked(false); assertTrue("column hidden, via columns selector", !_columnManager.getVisibleColumns().contains(_idCol) && _columnManager.getVisibleColumns().size() == _columns.size() - 1); node.setChecked(true); assertTrue("column unhidden, via columns selector", _columnManager.getVisibleColumns().contains(_idCol) && _columns.size() == _columnManager.getVisibleColumns().size()); // TODO: test that hidden column does not remain the sort column } public void testColumnGroups() { TreeModel model = _columnManager.getColumnsTreeModel(); assertEquals("root node name", "Columns", model.getNodeById("0").getDescription()); assertEquals("id column", _idCol.getName(), model.getNodeById("0:0").getDescription()); assertEquals("basic group", BASIC_COLUMNS_GROUP, model.getNodeById("0:1").getDescription()); assertEquals("name column", _nameCol.getName(), model.getNodeById("0:1:0").getDescription()); assertEquals("advanced", ADVANCED_COLUMNS_GROUP, model.getNodeById("0:2").getDescription()); assertEquals("status column", _statusCol.getName(), model.getNodeById("0:2:0").getDescription()); assertEquals("value column", _valueCol.getName(), model.getNodeById("0:2:1").getDescription()); assertEquals("advanced:special", "Special", model.getNodeById("0:2:2").getDescription()); assertEquals("url column", _urlCol.getName(), model.getNodeById("0:2:2:0").getDescription()); } public void testSortColumnSelection() { assertEquals("initial sort column", _idCol, _columnManager.getSortColumn()); assertEquals("initial sort column via UISelectBean", _idCol, _columnManager.getSortColumnSelector().getSelection()); assertEquals("initial sort direction", SortDirection.ASCENDING, _columnManager.getSortDirection()); assertEquals("initial sort direction via UISelectBean", SortDirection.ASCENDING, _columnManager.getSortDirectionSelector().getSelection()); _columnManager.setSortColumn(_valueCol); assertEquals("new sort column", _valueCol, _columnManager.getSortColumn()); assertEquals("new sort column in UISelectBean", _valueCol, _columnManager.getSortColumnSelector().getSelection()); assertEquals("new sort column in callback", _valueCol, _currentSortColumn); assertEquals("unchanged sort direction", SortDirection.ASCENDING, _columnManager.getSortDirection()); assertEquals("unchanged sort direction in UISelectBean", SortDirection.ASCENDING, _columnManager.getSortDirectionSelector().getSelection()); assertEquals("unchanged sort direction in callback", SortDirection.ASCENDING, _currentSortDirection); _columnManager.setSortDirection(SortDirection.DESCENDING); assertEquals("unchanged sort column", _valueCol, _columnManager.getSortColumn()); assertEquals("unchanged sort column in UISelectBean", _valueCol, _columnManager.getSortColumnSelector().getSelection()); assertEquals("unchanged sort column in callback", _valueCol, _currentSortColumn); assertEquals("new sort direction", SortDirection.DESCENDING, _columnManager.getSortDirection()); assertEquals("new sort direction in UISelectBean", SortDirection.DESCENDING, _columnManager.getSortDirectionSelector().getSelection()); assertEquals("new sort direction in callback", SortDirection.DESCENDING, _currentSortDirection); _columnManager.getSortColumnSelector().setSelection(_nameCol); assertEquals("new sort column via selector update", _nameCol, _columnManager.getSortColumn()); assertEquals("new sort column in UISelectBean via selector update", _nameCol, _columnManager.getSortColumnSelector().getSelection()); assertEquals("new sort column in callback via selector update", _nameCol, _currentSortColumn); assertEquals("unchanged sort direction via selector update", SortDirection.DESCENDING, _columnManager.getSortDirection()); assertEquals("unchanged sort direction in UISelectBean via selector update", SortDirection.DESCENDING, _columnManager.getSortDirectionSelector().getSelection()); assertEquals("unchanged sort direction in callback via selector update", SortDirection.DESCENDING, _currentSortDirection); _columnManager.getSortDirectionSelector().setSelection(SortDirection.ASCENDING); assertEquals("unchanged sort column via selector update", _nameCol, _columnManager.getSortColumn()); assertEquals("unchanged sort column in UISelectBean via selector update", _nameCol, _columnManager.getSortColumnSelector().getSelection()); assertEquals("unchanged sort column in callback via selector update", _nameCol, _currentSortColumn); assertEquals("new sort direction via selector update", SortDirection.ASCENDING, _columnManager.getSortDirection()); assertEquals("new sort direction in UISelectBean via selector update", SortDirection.ASCENDING, _columnManager.getSortDirectionSelector().getSelection()); assertEquals("new sort direction in callback via selector update", SortDirection.ASCENDING, _currentSortDirection); } public void testSingleColumnSort() { // ensure that first update to sort order forces a change; TableSortManager // only invokes sortChanged() callback if sort column or direction changes List<TableColumn<RowItem,?>> columnsTestOrder = new ArrayList<TableColumn<RowItem,?>>(_columns); Collections.rotate(columnsTestOrder, 1); int i = 0; for (TableColumn<RowItem,?> col : columnsTestOrder) { // ensure sortDir always changes from previous sort SortDirection sortDir = i++ % 2 == 0 ? SortDirection.DESCENDING : SortDirection.ASCENDING; doTestSort(col, sortDir); } } public void testCompoundColumnSort() { List<TableColumn<RowItem,?>> compoundSort = new ArrayList<TableColumn<RowItem,?>>(); compoundSort.add(_statusCol); compoundSort.add(_nameCol); _columnManager.addCompoundSortColumns(compoundSort); _sortedData = null; TableColumn<RowItem,?> primarySortCol = _statusCol; _columnManager.setSortColumn(primarySortCol); _columnManager.setSortDirection(SortDirection.ASCENDING); assertNotNull("compound sort occurred on " + primarySortCol.getName() + " " + SortDirection.ASCENDING, _sortedData); assertEquals("compound sort row 0", 4, _sortedData.get(0).getId().intValue()); assertEquals("compound sort row 1", 1, _sortedData.get(1).getId().intValue()); assertEquals("compound sort row 2", 3, _sortedData.get(2).getId().intValue()); assertEquals("compound sort row 3", 2, _sortedData.get(3).getId().intValue()); _sortedData = null; _columnManager.setSortDirection(SortDirection.DESCENDING); assertNotNull("compound sort occurred on " + primarySortCol.getName() + " " + SortDirection.DESCENDING, _sortedData); assertEquals("compound sort row 0", 2, _sortedData.get(0).getId().intValue()); assertEquals("compound sort row 1", 1, _sortedData.get(1).getId().intValue()); assertEquals("compound sort row 2", 3, _sortedData.get(2).getId().intValue()); assertEquals("compound sort row 3", 4, _sortedData.get(3).getId().intValue()); } // private methods private void doTestSort(TableColumn<RowItem,?> sortCol, SortDirection sortDir) { _sortedData = null; _columnManager.setSortColumn(sortCol); assertSorted(sortCol, _currentSortDirection); _sortedData = null; _columnManager.setSortDirection(sortDir); assertSorted(sortCol, sortDir); } @SuppressWarnings("unchecked") private void assertSorted(TableColumn<RowItem,?> sortCol, SortDirection sortDir) { assertNotNull("sort occurred on " + sortCol.getName() + " " + sortDir, _sortedData); for (int i = 0; i < _sortedData.size(); ++i) { log.debug("row " + i +" : " + _sortedData.get(i)); } for (int i = 0; i < _sortedData.size() - 1; ++i) { assertRowPairSorted(i, sortCol, sortDir); } } private void assertRowPairSorted(int i, TableColumn<RowItem,?> sortCol, SortDirection sortDir) { RowItem prevRow = _sortedData.get(i); RowItem currRow = _sortedData.get(i + 1); int cmpResult = sortCol.getComparator(sortDir).compare(prevRow, currRow); assertTrue("row " + i + " sorted by " + sortCol.getName() + " " + sortDir, cmpResult <= 0); } }