/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.jorphan.gui; import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import java.util.AbstractMap; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.swing.RowSorter.SortKey; import javax.swing.SortOrder; import org.apache.jorphan.reflect.Functor; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; import org.junit.rules.ExpectedException; public class ObjectTableSorterTest { ObjectTableModel model; ObjectTableSorter sorter; @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public ErrorCollector errorCollector = new ErrorCollector(); @Before public void createModelAndSorter() { String[] headers = { "key", "value", "object" }; Functor[] readFunctors = { new Functor("getKey"), new Functor("getValue"), new Functor("getValue") }; Functor[] writeFunctors = { null, null, null }; Class<?>[] editorClasses = { String.class, Integer.class, Object.class }; model = new ObjectTableModel(headers, readFunctors, writeFunctors, editorClasses); sorter = new ObjectTableSorter(model); List<Entry<String,Integer>> data = asList(b2(), a3(), d4(), c1()); data.forEach(model::addRow); } @Test public void noSorting() { List<SimpleImmutableEntry<String, Integer>> expected = asList(b2(), a3(), d4(), c1()); assertRowOrderAndIndexes(expected); } @Test public void sortKeyAscending() { sorter.setSortKey(new SortKey(0, SortOrder.ASCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(a3(), b2(), c1(), d4()); assertRowOrderAndIndexes(expected); } @Test public void sortKeyDescending() { sorter.setSortKey(new SortKey(0, SortOrder.DESCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(d4(), c1(), b2(), a3()); assertRowOrderAndIndexes(expected); } @Test public void sortValueAscending() { sorter.setSortKey(new SortKey(1, SortOrder.ASCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(c1(), b2(), a3(), d4()); assertRowOrderAndIndexes(expected); } @Test public void sortValueDescending() { sorter.setSortKey(new SortKey(1, SortOrder.DESCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(d4(), a3(), b2(), c1()); assertRowOrderAndIndexes(expected); } @Test public void fixLastRowWithAscendingKey() { sorter.fixLastRow().setSortKey(new SortKey(0, SortOrder.ASCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(a3(), b2(), d4(), c1()); assertRowOrderAndIndexes(expected); } @Test public void fixLastRowWithDescendingKey() { sorter.fixLastRow().setSortKey(new SortKey(0, SortOrder.DESCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(d4(), b2(), a3(), c1()); assertRowOrderAndIndexes(expected); } @Test public void fixLastRowWithAscendingValue() { sorter.fixLastRow().setSortKey(new SortKey(1, SortOrder.ASCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(b2(), a3(), d4(), c1()); assertRowOrderAndIndexes(expected); } @Test public void fixLastRowWithDescendingValue() { sorter.fixLastRow().setSortKey(new SortKey(1, SortOrder.DESCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(d4(), a3(), b2(), c1()); assertRowOrderAndIndexes(expected); } @Test public void customKeyOrder() { HashMap<String, Integer> customKeyOrder = asList("a", "c", "b", "d").stream().reduce(new HashMap<String,Integer>(), (map,key) -> { map.put(key, map.size()); return map; }, (a,b) -> a); Comparator<String> customKeyComparator = (a,b) -> customKeyOrder.get(a).compareTo(customKeyOrder.get(b)); sorter.setValueComparator(0, customKeyComparator).setSortKey(new SortKey(0, SortOrder.ASCENDING)); List<SimpleImmutableEntry<String, Integer>> expected = asList(a3(), c1(), b2(), d4()); assertRowOrderAndIndexes(expected); } @Test public void getDefaultComparatorForNullClass() { ObjectTableModel model = new ObjectTableModel(new String[] { "null" }, new Functor[] { null }, new Functor[] { null }, new Class<?>[] { null }); ObjectTableSorter sorter = new ObjectTableSorter(model); assertThat(sorter.getValueComparator(0), is(nullValue())); } @Test public void getDefaultComparatorForStringClass() { ObjectTableModel model = new ObjectTableModel(new String[] { "string" }, new Functor[] { null }, new Functor[] { null }, new Class<?>[] { String.class }); ObjectTableSorter sorter = new ObjectTableSorter(model); assertThat(sorter.getValueComparator(0), is(CoreMatchers.notNullValue())); } @Test public void getDefaultComparatorForIntegerClass() { ObjectTableModel model = new ObjectTableModel(new String[] { "integer" }, new Functor[] { null }, new Functor[] { null }, new Class<?>[] { Integer.class }); ObjectTableSorter sorter = new ObjectTableSorter(model); assertThat(sorter.getValueComparator(0), is(CoreMatchers.notNullValue())); } @Test public void getDefaultComparatorForObjectClass() { ObjectTableModel model = new ObjectTableModel(new String[] { "integer" }, new Functor[] { null }, new Functor[] { null }, new Class<?>[] { Object.class }); ObjectTableSorter sorter = new ObjectTableSorter(model); assertThat(sorter.getValueComparator(0), is(nullValue())); } @Test public void toggleSortOrder_none() { assertSame(emptyList(), sorter.getSortKeys()); } @Test public void toggleSortOrder_0() { sorter.toggleSortOrder(0); assertEquals(singletonList(new SortKey(0, SortOrder.ASCENDING)), sorter.getSortKeys()); } @Test public void toggleSortOrder_0_1() { sorter.toggleSortOrder(0); sorter.toggleSortOrder(1); assertEquals(singletonList(new SortKey(1, SortOrder.ASCENDING)), sorter.getSortKeys()); } @Test public void toggleSortOrder_0_0() { sorter.toggleSortOrder(0); sorter.toggleSortOrder(0); assertEquals(singletonList(new SortKey(0, SortOrder.DESCENDING)), sorter.getSortKeys()); } @Test public void toggleSortOrder_0_0_0() { sorter.toggleSortOrder(0); sorter.toggleSortOrder(0); sorter.toggleSortOrder(0); assertEquals(singletonList(new SortKey(0, SortOrder.ASCENDING)), sorter.getSortKeys()); } @Test public void toggleSortOrder_2() { sorter.toggleSortOrder(2); assertSame(emptyList(), sorter.getSortKeys()); } @Test public void toggleSortOrder_0_2() { sorter.toggleSortOrder(0); sorter.toggleSortOrder(2); assertSame(emptyList(), sorter.getSortKeys()); } @Test public void setSortKeys_none() { sorter.setSortKeys(new ArrayList<>()); assertSame(Collections.emptyList(), sorter.getSortKeys()); } @Test public void setSortKeys_withSortedThenUnsorted() { sorter.setSortKeys(singletonList(new SortKey(0, SortOrder.ASCENDING))); sorter.setSortKeys(new ArrayList<>()); assertSame(Collections.emptyList(), sorter.getSortKeys()); } @Test public void setSortKeys_single() { List<SortKey> keys = singletonList(new SortKey(0, SortOrder.ASCENDING)); sorter.setSortKeys(keys); assertThat(sorter.getSortKeys(), allOf( is(not(sameInstance(keys))), is(equalTo(keys)) )); } @Test public void setSortKeys_many() { expectedException.expect(IllegalArgumentException.class); sorter.setSortKeys(asList(new SortKey(0, SortOrder.ASCENDING), new SortKey(1, SortOrder.ASCENDING))); } @Test public void setSortKeys_invalidColumn() { expectedException.expect(IllegalArgumentException.class); sorter.setSortKeys(Collections.singletonList(new SortKey(2, SortOrder.ASCENDING))); } @SuppressWarnings("unchecked") protected List<Entry<String,Integer>> actual() { return IntStream .range(0, sorter.getViewRowCount()) .map(sorter::convertRowIndexToModel) .mapToObj(modelIndex -> (Entry<String,Integer>) sorter.getModel().getObjectListAsList().get(modelIndex)) .collect(Collectors.toList()) ; } protected SimpleImmutableEntry<String, Integer> d4() { return new AbstractMap.SimpleImmutableEntry<>("d", 4); } protected SimpleImmutableEntry<String, Integer> c1() { return new AbstractMap.SimpleImmutableEntry<>("c", 1); } protected SimpleImmutableEntry<String, Integer> b2() { return new AbstractMap.SimpleImmutableEntry<>("b", 2); } protected SimpleImmutableEntry<String, Integer> a3() { return new AbstractMap.SimpleImmutableEntry<>("a", 3); } protected void assertRowOrderAndIndexes(List<SimpleImmutableEntry<String, Integer>> expected) { assertEquals(expected, actual()); assertRowIndexes(); } protected void assertRowIndexes() { IntStream .range(0, sorter.getViewRowCount()) .forEach(viewIndex -> { int modelIndex = sorter.convertRowIndexToModel(viewIndex); errorCollector.checkThat(format("view(%d) model(%d)", viewIndex, modelIndex), sorter.convertRowIndexToView(modelIndex), CoreMatchers.equalTo(viewIndex)); }); } }