Add new FixedOrderComparator that allows the order to be easily specified
from David Leppik, bug ref 16823 git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131005 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
37b4ba1135
commit
54a2013989
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/comparators/FixedOrderComparator.java,v 1.1 2003/04/13 17:37:26 scolebourne Exp $
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution, if
|
||||||
|
* any, must include the following acknowlegement:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowlegement may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowlegements normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||||
|
* Foundation" must not be used to endorse or promote products derived
|
||||||
|
* from this software without prior written permission. For written
|
||||||
|
* permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache"
|
||||||
|
* nor may "Apache" appear in their names without prior written
|
||||||
|
* permission of the Apache Group.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.apache.commons.collections.comparators;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Comparator which imposes a specific order on a specific set of Objects.
|
||||||
|
* Objects are presented to the FixedOrderComparator in a specified order and
|
||||||
|
* subsequent calls to {@link #compare} yield that order.
|
||||||
|
* For example:
|
||||||
|
* <pre>
|
||||||
|
* String[] planets = {"Mercury", "Venus", "Earth", "Mars"};
|
||||||
|
* FixedOrderComparator distanceFromSun = new FixedOrderComparator(planets);
|
||||||
|
* Arrays.sort(planets); // Sort to alphabetical order
|
||||||
|
* Arrays.sort(planets, distanceFromSun); // Back to original order
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Once {@link #compare} has been called, the FixedOrderComparator is locked and
|
||||||
|
* attempts to modify it yield an UnsupportedOperationException.
|
||||||
|
* <p>
|
||||||
|
* Instances of FixedOrderComparator are not synchronized. The class is not
|
||||||
|
* thread-safe at construction time, but it is thread-safe to perform
|
||||||
|
* multiple comparisons after all the setup operations are complete.
|
||||||
|
*
|
||||||
|
* @since Commons Collections 2.2
|
||||||
|
* @version $Revision: 1.1 $ $Date: 2003/04/13 17:37:26 $
|
||||||
|
*
|
||||||
|
* @author David Leppik
|
||||||
|
* @author Stephen Colebourne
|
||||||
|
*/
|
||||||
|
public class FixedOrderComparator implements Comparator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior when comparing unknown Objects:
|
||||||
|
* unknown objects compare as before known Objects.
|
||||||
|
*/
|
||||||
|
public static final int UNKNOWN_BEFORE = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior when comparing unknown Objects:
|
||||||
|
* unknown objects compare as before known Objects.
|
||||||
|
*/
|
||||||
|
public static final int UNKNOWN_AFTER = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior when comparing unknown Objects:
|
||||||
|
* unknown objects cause a IllegalArgumentException to be thrown.
|
||||||
|
* This is the default behavior.
|
||||||
|
*/
|
||||||
|
public static final int UNKNOWN_THROW_EXCEPTION = 2;
|
||||||
|
|
||||||
|
/** Internal map of object to position */
|
||||||
|
private final Map map = new HashMap();
|
||||||
|
/** Counter used in determining the position in the map */
|
||||||
|
private int counter = 0;
|
||||||
|
/** Is the comparator locked against further change */
|
||||||
|
private boolean isLocked = false;
|
||||||
|
/** The behaviour in the case of an unknown object */
|
||||||
|
private int unknownObjectBehavior = UNKNOWN_THROW_EXCEPTION;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Constructs an empty FixedOrderComparator.
|
||||||
|
*/
|
||||||
|
public FixedOrderComparator() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a FixedOrderComparator which uses the order of the given array
|
||||||
|
* to compare the objects.
|
||||||
|
* <p>
|
||||||
|
* The array is copied, so later changes will not affect the comparator.
|
||||||
|
*
|
||||||
|
* @param items the items that the comparator can compare in order
|
||||||
|
* @throws IllegalArgumentException if the array is null
|
||||||
|
*/
|
||||||
|
public FixedOrderComparator(Object[] items) {
|
||||||
|
super();
|
||||||
|
if (items == null) {
|
||||||
|
throw new IllegalArgumentException("The list of items must not be null");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < items.length; i++) {
|
||||||
|
add(items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a FixedOrderComparator which uses the order of the given list
|
||||||
|
* to compare the objects.
|
||||||
|
* <p>
|
||||||
|
* The list is copied, so later changes will not affect the comparator.
|
||||||
|
*
|
||||||
|
* @param items the items that the comparator can compare in order
|
||||||
|
* @throws IllegalArgumentException if the list is null
|
||||||
|
*/
|
||||||
|
public FixedOrderComparator(List items) {
|
||||||
|
super();
|
||||||
|
if (items == null) {
|
||||||
|
throw new IllegalArgumentException("The list of items must not be null");
|
||||||
|
}
|
||||||
|
for (Iterator it = items.iterator(); it.hasNext();) {
|
||||||
|
add(it.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bean methods / state querying methods
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Returns true if modifications cannot be made to the FixedOrderComparator.
|
||||||
|
* FixedOrderComparators cannot be modified once they have performed a comparison.
|
||||||
|
*
|
||||||
|
* @return true if attempts to change the FixedOrderComparator yield an
|
||||||
|
* UnsupportedOperationException, false if it can be changed.
|
||||||
|
*/
|
||||||
|
public boolean isLocked() {
|
||||||
|
return isLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see whether the comparator is now locked against further changes.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if the comparator is locked
|
||||||
|
*/
|
||||||
|
protected void checkLocked() {
|
||||||
|
if (isLocked()) {
|
||||||
|
throw new UnsupportedOperationException("Cannot modify a FixedOrderComparator after a comparison");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the behavior for comparing unknown objects.
|
||||||
|
*/
|
||||||
|
public int getUnkownObjectBehavior() {
|
||||||
|
return unknownObjectBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the behavior for comparing unknown objects.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if a comparison has been performed
|
||||||
|
* @throws IllegalArgumentException if the unknown flag is not valid
|
||||||
|
*/
|
||||||
|
public void setUnknownObjectBehavior(int unknownObjectBehavior) {
|
||||||
|
checkLocked();
|
||||||
|
if (unknownObjectBehavior != UNKNOWN_AFTER
|
||||||
|
&& unknownObjectBehavior != UNKNOWN_BEFORE
|
||||||
|
&& unknownObjectBehavior != UNKNOWN_THROW_EXCEPTION) {
|
||||||
|
throw new IllegalArgumentException("Unrecognised value for unkown behaviour flag");
|
||||||
|
}
|
||||||
|
this.unknownObjectBehavior = unknownObjectBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods for adding items
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Adds an item, which compares as after all items known to the Comparator.
|
||||||
|
* If the item is already known to the Comparator, its old position is
|
||||||
|
* replaced with the new position.
|
||||||
|
*
|
||||||
|
* @param obj the item to be added to the Comparator.
|
||||||
|
* @return true if obj has been added for the first time, false if
|
||||||
|
* it was already known to the Comparator.
|
||||||
|
* @throws UnsupportedOperationException if a comparison has already been made
|
||||||
|
*/
|
||||||
|
public boolean add(Object obj) {
|
||||||
|
checkLocked();
|
||||||
|
Object position = map.put(obj, new Integer(counter++));
|
||||||
|
return (position == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new item, which compares as equal to the given existing item.
|
||||||
|
*
|
||||||
|
* @param existingObj an item already in the Comparator's set of
|
||||||
|
* known objects
|
||||||
|
* @param newObj an item to be added to the Comparator's set of
|
||||||
|
* known objects
|
||||||
|
* @return true if newObj has been added for the first time, false if
|
||||||
|
* it was already known to the Comparator.
|
||||||
|
* @throws IllegalArgumentException if existingObject is not in the
|
||||||
|
* Comparator's set of known objects.
|
||||||
|
* @throws UnsupportedOperationException if a comparison has already been made
|
||||||
|
*/
|
||||||
|
public boolean addAsEqual(Object existingObj, Object newObj) {
|
||||||
|
checkLocked();
|
||||||
|
Integer position = (Integer) map.get(existingObj);
|
||||||
|
if (position == null) {
|
||||||
|
throw new IllegalArgumentException(existingObj + " not known to " + this);
|
||||||
|
}
|
||||||
|
Object result = map.put(newObj, position);
|
||||||
|
return (result == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparator methods
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Compares two objects according to the order of this Comparator.
|
||||||
|
* <p>
|
||||||
|
* It is important to note that this class will throw an IllegalArgumentException
|
||||||
|
* in the case of an unrecognised object. This is not specified in the
|
||||||
|
* Comparator interface, but is the most appropriate exception.
|
||||||
|
*
|
||||||
|
* @param obj1 the first object to compare
|
||||||
|
* @param obj2 the second object to compare
|
||||||
|
* @throws IllegalArgumentException if o1 or o2 are not known
|
||||||
|
* to this Comparator and an alternative behavior has not been set
|
||||||
|
* via {@link #setUnknownObjectBehavior(int)}.
|
||||||
|
*/
|
||||||
|
public int compare(Object obj1, Object obj2) {
|
||||||
|
isLocked = true;
|
||||||
|
Integer position1 = (Integer) map.get(obj1);
|
||||||
|
Integer position2 = (Integer) map.get(obj2);
|
||||||
|
if (position1 == null || position2 == null) {
|
||||||
|
switch (unknownObjectBehavior) {
|
||||||
|
case UNKNOWN_BEFORE :
|
||||||
|
if (position1 == null) {
|
||||||
|
return (position2 == null) ? 0 : -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case UNKNOWN_AFTER :
|
||||||
|
if (position1 == null) {
|
||||||
|
return (position2 == null) ? 0 : 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
case UNKNOWN_THROW_EXCEPTION :
|
||||||
|
Object unknownObj = (position1 == null) ? obj1 : obj2;
|
||||||
|
throw new IllegalArgumentException("Attempting to compare unknown object " + unknownObj);
|
||||||
|
default :
|
||||||
|
throw new UnsupportedOperationException("Unknown unknownObjectBehavior: " + unknownObjectBehavior);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return position1.compareTo(position2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/comparators/TestAll.java,v 1.2 2003/01/10 00:21:08 rwaldhoff Exp $
|
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/comparators/TestAll.java,v 1.3 2003/04/13 17:37:26 scolebourne Exp $
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
*
|
*
|
||||||
* The Apache Software License, Version 1.1
|
* The Apache Software License, Version 1.1
|
||||||
|
@ -55,16 +55,17 @@
|
||||||
* <http://www.apache.org/>.
|
* <http://www.apache.org/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.commons.collections.comparators;
|
package org.apache.commons.collections.comparators;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for all Comparator Collections tests.
|
* Entry point for all Comparator Collections tests.
|
||||||
|
*
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @version $Revision: 1.2 $ $Date: 2003/01/10 00:21:08 $
|
* @version $Revision: 1.3 $ $Date: 2003/04/13 17:37:26 $
|
||||||
*/
|
*/
|
||||||
public class TestAll extends TestCase {
|
public class TestAll extends TestCase {
|
||||||
public TestAll(String testName) {
|
public TestAll(String testName) {
|
||||||
|
@ -76,6 +77,7 @@ public class TestAll extends TestCase {
|
||||||
suite.addTest(TestBooleanComparator.suite());
|
suite.addTest(TestBooleanComparator.suite());
|
||||||
suite.addTest(TestComparableComparator.suite());
|
suite.addTest(TestComparableComparator.suite());
|
||||||
suite.addTest(TestComparatorChain.suite());
|
suite.addTest(TestComparatorChain.suite());
|
||||||
|
suite.addTest(TestFixedOrderComparator.suite());
|
||||||
suite.addTest(TestNullComparator.suite());
|
suite.addTest(TestNullComparator.suite());
|
||||||
suite.addTest(TestReverseComparator.suite());
|
suite.addTest(TestReverseComparator.suite());
|
||||||
return suite;
|
return suite;
|
||||||
|
@ -85,4 +87,5 @@ public class TestAll extends TestCase {
|
||||||
String[] testCaseName = { TestAll.class.getName() };
|
String[] testCaseName = { TestAll.class.getName() };
|
||||||
junit.textui.TestRunner.main(testCaseName);
|
junit.textui.TestRunner.main(testCaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/comparators/TestFixedOrderComparator.java,v 1.1 2003/04/13 17:37:26 scolebourne Exp $
|
||||||
|
* $Revision: 1.1 $
|
||||||
|
* $Date: 2003/04/13 17:37:26 $
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 1999-2001 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution, if
|
||||||
|
* any, must include the following acknowlegement:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowlegement may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowlegements normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||||
|
* Foundation" must not be used to endorse or promote products derived
|
||||||
|
* from this software without prior written permission. For written
|
||||||
|
* permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache"
|
||||||
|
* nor may "Apache" appear in their names without prior written
|
||||||
|
* permission of the Apache Group.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.apache.commons.collections.comparators;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for FixedOrderComparator.
|
||||||
|
*
|
||||||
|
* @author David Leppik
|
||||||
|
* @author Stephen Colebourne
|
||||||
|
*/
|
||||||
|
public class TestFixedOrderComparator extends TestCase {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top cities of the world, by population including metro areas.
|
||||||
|
*/
|
||||||
|
public static final String topCities[] = new String[] {
|
||||||
|
"Tokyo",
|
||||||
|
"Mexico City",
|
||||||
|
"Mumbai",
|
||||||
|
"Sao Paulo",
|
||||||
|
"New York",
|
||||||
|
"Shanghai",
|
||||||
|
"Lagos",
|
||||||
|
"Los Angeles",
|
||||||
|
"Calcutta",
|
||||||
|
"Buenos Aires"
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialization and busywork
|
||||||
|
//
|
||||||
|
|
||||||
|
public TestFixedOrderComparator(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return new TestSuite(TestFixedOrderComparator.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
junit.textui.TestRunner.run(suite());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up and tear down
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// The tests
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the constructor plus add method compares items properly.
|
||||||
|
*/
|
||||||
|
public void testConstructorPlusAdd() {
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator();
|
||||||
|
for (int i = 0; i < topCities.length; i++) {
|
||||||
|
comparator.add(topCities[i]);
|
||||||
|
}
|
||||||
|
String[] keys = (String[]) topCities.clone();
|
||||||
|
assertComparatorYieldsOrder(keys, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the array constructor compares items properly.
|
||||||
|
*/
|
||||||
|
public void testArrayConstructor() {
|
||||||
|
String[] keys = (String[]) topCities.clone();
|
||||||
|
String[] topCitiesForTest = (String[]) topCities.clone();
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator(topCitiesForTest);
|
||||||
|
assertComparatorYieldsOrder(keys, comparator);
|
||||||
|
// test that changing input after constructor has no effect
|
||||||
|
topCitiesForTest[0] = "Brighton";
|
||||||
|
assertComparatorYieldsOrder(keys, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the list constructor.
|
||||||
|
*/
|
||||||
|
public void testListConstructor() {
|
||||||
|
String[] keys = (String[]) topCities.clone();
|
||||||
|
List topCitiesForTest = new LinkedList(Arrays.asList(topCities));
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator(topCitiesForTest);
|
||||||
|
assertComparatorYieldsOrder(keys, comparator);
|
||||||
|
// test that changing input after constructor has no effect
|
||||||
|
topCitiesForTest.set(0, "Brighton");
|
||||||
|
assertComparatorYieldsOrder(keys, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests addAsEqual method.
|
||||||
|
*/
|
||||||
|
public void testAddAsEqual() {
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator(topCities);
|
||||||
|
comparator.addAsEqual("New York", "Minneapolis");
|
||||||
|
assertEquals(0, comparator.compare("New York", "Minneapolis"));
|
||||||
|
assertEquals(-1, comparator.compare("Tokyo", "Minneapolis"));
|
||||||
|
assertEquals(1, comparator.compare("Shanghai", "Minneapolis"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether or not updates are disabled after a comparison is made.
|
||||||
|
*/
|
||||||
|
public void testLock() {
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator(topCities);
|
||||||
|
assertEquals(false, comparator.isLocked());
|
||||||
|
comparator.compare("New York", "Tokyo");
|
||||||
|
assertEquals(true, comparator.isLocked());
|
||||||
|
try {
|
||||||
|
comparator.add("Minneapolis");
|
||||||
|
fail("Should have thrown an UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// success -- ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
comparator.addAsEqual("New York", "Minneapolis");
|
||||||
|
fail("Should have thrown an UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// success -- ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUnknownObjectBehavior() {
|
||||||
|
FixedOrderComparator comparator = new FixedOrderComparator(topCities);
|
||||||
|
try {
|
||||||
|
comparator.compare("New York", "Minneapolis");
|
||||||
|
fail("Should have thrown a IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// success-- ignore
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
comparator.compare("Minneapolis", "New York");
|
||||||
|
fail("Should have thrown a IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// success-- ignore
|
||||||
|
}
|
||||||
|
assertEquals(FixedOrderComparator.UNKNOWN_THROW_EXCEPTION, comparator.getUnkownObjectBehavior());
|
||||||
|
|
||||||
|
comparator = new FixedOrderComparator(topCities);
|
||||||
|
comparator.setUnknownObjectBehavior(FixedOrderComparator.UNKNOWN_BEFORE);
|
||||||
|
assertEquals(FixedOrderComparator.UNKNOWN_BEFORE, comparator.getUnkownObjectBehavior());
|
||||||
|
LinkedList keys = new LinkedList(Arrays.asList(topCities));
|
||||||
|
keys.addFirst("Minneapolis");
|
||||||
|
assertComparatorYieldsOrder(keys.toArray(new String[0]), comparator);
|
||||||
|
|
||||||
|
assertEquals(-1, comparator.compare("Minneapolis", "New York"));
|
||||||
|
assertEquals( 1, comparator.compare("New York", "Minneapolis"));
|
||||||
|
assertEquals( 0, comparator.compare("Minneapolis", "St Paul"));
|
||||||
|
|
||||||
|
comparator = new FixedOrderComparator(topCities);
|
||||||
|
comparator.setUnknownObjectBehavior(FixedOrderComparator.UNKNOWN_AFTER);
|
||||||
|
keys = new LinkedList(Arrays.asList(topCities));
|
||||||
|
keys.add("Minneapolis");
|
||||||
|
assertComparatorYieldsOrder(keys.toArray(new String[0]), comparator);
|
||||||
|
|
||||||
|
assertEquals( 1, comparator.compare("Minneapolis", "New York"));
|
||||||
|
assertEquals(-1, comparator.compare("New York", "Minneapolis"));
|
||||||
|
assertEquals( 0, comparator.compare("Minneapolis", "St Paul"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helper methods
|
||||||
|
//
|
||||||
|
|
||||||
|
/** Shuffles the keys and asserts that the comparator sorts them back to
|
||||||
|
* their original order.
|
||||||
|
*/
|
||||||
|
private void assertComparatorYieldsOrder(Object[] orderedObjects,
|
||||||
|
Comparator comparator) {
|
||||||
|
Object[] keys = (Object[]) orderedObjects.clone();
|
||||||
|
|
||||||
|
// shuffle until the order changes. It's extremely rare that
|
||||||
|
// this requires more than one shuffle.
|
||||||
|
|
||||||
|
boolean isInNewOrder = false;
|
||||||
|
while (keys.length > 1 && isInNewOrder == false) {
|
||||||
|
shuffle: {
|
||||||
|
Random rand = new Random();
|
||||||
|
for (int i = keys.length-1; i > 0; i--) {
|
||||||
|
Object swap = keys[i];
|
||||||
|
int j = rand.nextInt(i+1);
|
||||||
|
keys[i] = keys[j];
|
||||||
|
keys[j] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testShuffle: {
|
||||||
|
for (int i = 0; i < keys.length && !isInNewOrder; i++) {
|
||||||
|
if( !orderedObjects[i].equals(keys[i])) {
|
||||||
|
isInNewOrder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The real test: sort and make sure they come out right.
|
||||||
|
|
||||||
|
Arrays.sort(keys, comparator);
|
||||||
|
|
||||||
|
for (int i = 0; i < orderedObjects.length; i++) {
|
||||||
|
assertEquals(orderedObjects[i], keys[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue