mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 11:35:29 -04:00
Added test cases + fixed some hard to find bugs.
This commit is contained in:
parent
d36d828110
commit
b92caf121d
@ -28,17 +28,21 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.util;
|
package com.twelvemonkeys.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class with some useful collection-related functions.
|
* A utility class with some useful collection-related functions.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author <A href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</A>
|
* @author <A href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</A>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/CollectionUtil.java#3 $
|
* @version $Id: com/twelvemonkeys/util/CollectionUtil.java#3 $
|
||||||
* @todo move makeList and makeSet to StringUtil?
|
|
||||||
* @see Collections
|
* @see Collections
|
||||||
* @see Arrays
|
* @see Arrays
|
||||||
*/
|
*/
|
||||||
@ -51,8 +55,6 @@ public final class CollectionUtil {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"UnusedDeclaration", "UnusedAssignment", "unchecked"})
|
@SuppressWarnings({"UnusedDeclaration", "UnusedAssignment", "unchecked"})
|
||||||
public static void main(String[] pArgs) {
|
public static void main(String[] pArgs) {
|
||||||
test();
|
|
||||||
|
|
||||||
int howMany = 1000;
|
int howMany = 1000;
|
||||||
|
|
||||||
if (pArgs.length > 0) {
|
if (pArgs.length > 0) {
|
||||||
@ -257,7 +259,7 @@ public final class CollectionUtil {
|
|||||||
* If the sub array is same length as the original
|
* If the sub array is same length as the original
|
||||||
* ({@code pStart == 0}), the original array will be returned.
|
* ({@code pStart == 0}), the original array will be returned.
|
||||||
*
|
*
|
||||||
* @param pArray the origianl array
|
* @param pArray the original array
|
||||||
* @param pStart the start index of the original array
|
* @param pStart the start index of the original array
|
||||||
* @return a subset of the original array, or the original array itself,
|
* @return a subset of the original array, or the original array itself,
|
||||||
* if {@code pStart} is 0.
|
* if {@code pStart} is 0.
|
||||||
@ -270,16 +272,33 @@ public final class CollectionUtil {
|
|||||||
return subArray(pArray, pStart, -1);
|
return subArray(pArray, pStart, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array containing a subset of the original array.
|
||||||
|
* If the sub array is same length as the original
|
||||||
|
* ({@code pStart == 0}), the original array will be returned.
|
||||||
|
*
|
||||||
|
* @param pArray the original array
|
||||||
|
* @param pStart the start index of the original array
|
||||||
|
* @return a subset of the original array, or the original array itself,
|
||||||
|
* if {@code pStart} is 0.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code pArray} is {@code null}
|
||||||
|
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
|
||||||
|
*/
|
||||||
|
public static <T> T[] subArray(T[] pArray, int pStart) {
|
||||||
|
return subArray(pArray, pStart, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an array containing a subset of the original array.
|
* Creates an array containing a subset of the original array.
|
||||||
* If the {@code pLength} parameter is negative, it will be ignored.
|
* If the {@code pLength} parameter is negative, it will be ignored.
|
||||||
* If there are not {@code pLength} elements in the original array
|
* If there are not {@code pLength} elements in the original array
|
||||||
* after {@code pStart}, the {@code pLength} paramter will be
|
* after {@code pStart}, the {@code pLength} parameter will be
|
||||||
* ignored.
|
* ignored.
|
||||||
* If the sub array is same length as the original, the original array will
|
* If the sub array is same length as the original, the original array will
|
||||||
* be returned.
|
* be returned.
|
||||||
*
|
*
|
||||||
* @param pArray the origianl array
|
* @param pArray the original array
|
||||||
* @param pStart the start index of the original array
|
* @param pStart the start index of the original array
|
||||||
* @param pLength the length of the new array
|
* @param pLength the length of the new array
|
||||||
* @return a subset of the original array, or the original array itself,
|
* @return a subset of the original array, or the original array itself,
|
||||||
@ -292,9 +311,7 @@ public final class CollectionUtil {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"SuspiciousSystemArraycopy"})
|
@SuppressWarnings({"SuspiciousSystemArraycopy"})
|
||||||
public static Object subArray(Object pArray, int pStart, int pLength) {
|
public static Object subArray(Object pArray, int pStart, int pLength) {
|
||||||
if (pArray == null) {
|
Validate.notNull(pArray, "array");
|
||||||
throw new IllegalArgumentException("array == null");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get component type
|
// Get component type
|
||||||
Class type;
|
Class type;
|
||||||
@ -321,7 +338,7 @@ public final class CollectionUtil {
|
|||||||
Object result;
|
Object result;
|
||||||
|
|
||||||
if (newLength < originalLength) {
|
if (newLength < originalLength) {
|
||||||
// Create subarray & copy into
|
// Create sub array & copy into
|
||||||
result = Array.newInstance(type, newLength);
|
result = Array.newInstance(type, newLength);
|
||||||
System.arraycopy(pArray, pStart, result, 0, newLength);
|
System.arraycopy(pArray, pStart, result, 0, newLength);
|
||||||
}
|
}
|
||||||
@ -335,7 +352,33 @@ public final class CollectionUtil {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array containing a subset of the original array.
|
||||||
|
* If the {@code pLength} parameter is negative, it will be ignored.
|
||||||
|
* If there are not {@code pLength} elements in the original array
|
||||||
|
* after {@code pStart}, the {@code pLength} parameter will be
|
||||||
|
* ignored.
|
||||||
|
* If the sub array is same length as the original, the original array will
|
||||||
|
* be returned.
|
||||||
|
*
|
||||||
|
* @param pArray the original array
|
||||||
|
* @param pStart the start index of the original array
|
||||||
|
* @param pLength the length of the new array
|
||||||
|
* @return a subset of the original array, or the original array itself,
|
||||||
|
* if {@code pStart} is 0 and {@code pLength} is either
|
||||||
|
* negative, or greater or equal to {@code pArray.length}.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code pArray} is {@code null}
|
||||||
|
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T[] subArray(T[] pArray, int pStart, int pLength) {
|
||||||
|
return (T[]) subArray((Object) pArray, pStart, pLength);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> Iterator<T> iterator(final Enumeration<T> pEnum) {
|
public static <T> Iterator<T> iterator(final Enumeration<T> pEnum) {
|
||||||
|
notNull(pEnum, "enumeration");
|
||||||
|
|
||||||
return new Iterator<T>() {
|
return new Iterator<T>() {
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return pEnum.hasMoreElements();
|
return pEnum.hasMoreElements();
|
||||||
@ -361,8 +404,8 @@ public final class CollectionUtil {
|
|||||||
* the given collection.
|
* the given collection.
|
||||||
* @throws ClassCastException class of the specified element prevents it
|
* @throws ClassCastException class of the specified element prevents it
|
||||||
* from being added to this collection.
|
* from being added to this collection.
|
||||||
* @throws NullPointerException if the specified element is null and this
|
* @throws NullPointerException if the specified element is {@code null} and this
|
||||||
* collection does not support null elements.
|
* collection does not support {@code null} elements.
|
||||||
* @throws IllegalArgumentException some aspect of this element prevents
|
* @throws IllegalArgumentException some aspect of this element prevents
|
||||||
* it from being added to this collection.
|
* it from being added to this collection.
|
||||||
*/
|
*/
|
||||||
@ -372,7 +415,7 @@ public final class CollectionUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there a usecase where Arrays.asList(pArray).iterator() can't ne used?
|
// Is there a use case where Arrays.asList(pArray).iterator() can't ne used?
|
||||||
/**
|
/**
|
||||||
* Creates a thin {@link Iterator} wrapper around an array.
|
* Creates a thin {@link Iterator} wrapper around an array.
|
||||||
*
|
*
|
||||||
@ -383,7 +426,7 @@ public final class CollectionUtil {
|
|||||||
* {@code pLength > pArray.length - pStart}
|
* {@code pLength > pArray.length - pStart}
|
||||||
*/
|
*/
|
||||||
public static <E> ListIterator<E> iterator(final E[] pArray) {
|
public static <E> ListIterator<E> iterator(final E[] pArray) {
|
||||||
return iterator(pArray, 0, pArray.length);
|
return iterator(pArray, 0, notNull(pArray).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -408,7 +451,7 @@ public final class CollectionUtil {
|
|||||||
* @return a new {@code Map} of same type as {@code pSource}
|
* @return a new {@code Map} of same type as {@code pSource}
|
||||||
* @throws IllegalArgumentException if {@code pSource == null},
|
* @throws IllegalArgumentException if {@code pSource == null},
|
||||||
* or if a new map can't be instantiated,
|
* or if a new map can't be instantiated,
|
||||||
* or if source map contains duplaicates.
|
* or if source map contains duplicates.
|
||||||
*
|
*
|
||||||
* @see #invert(java.util.Map, java.util.Map, DuplicateHandler)
|
* @see #invert(java.util.Map, java.util.Map, DuplicateHandler)
|
||||||
*/
|
*/
|
||||||
@ -424,7 +467,7 @@ public final class CollectionUtil {
|
|||||||
* @param pResult the map used to contain the result, may be {@code null},
|
* @param pResult the map used to contain the result, may be {@code null},
|
||||||
* in that case a new {@code Map} of same type as {@code pSource} is created.
|
* in that case a new {@code Map} of same type as {@code pSource} is created.
|
||||||
* The result map <em>should</em> be empty, otherwise duplicate values will need to be resolved.
|
* The result map <em>should</em> be empty, otherwise duplicate values will need to be resolved.
|
||||||
* @param pHandler duplicate handler, may be {@code null} if source map don't contain dupliate values
|
* @param pHandler duplicate handler, may be {@code null} if source map don't contain duplicate values
|
||||||
* @return {@code pResult}, or a new {@code Map} if {@code pResult == null}
|
* @return {@code pResult}, or a new {@code Map} if {@code pResult == null}
|
||||||
* @throws IllegalArgumentException if {@code pSource == null},
|
* @throws IllegalArgumentException if {@code pSource == null},
|
||||||
* or if result map is {@code null} and a new map can't be instantiated,
|
* or if result map is {@code null} and a new map can't be instantiated,
|
||||||
@ -476,20 +519,20 @@ public final class CollectionUtil {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Comparator<T> reverseOrder(Comparator<T> pOriginal) {
|
public static <T> Comparator<T> reverseOrder(final Comparator<T> pOriginal) {
|
||||||
return new ReverseComparator<T>(pOriginal);
|
return new ReverseComparator<T>(pOriginal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReverseComparator<T> implements Comparator<T> {
|
private static class ReverseComparator<T> implements Comparator<T> {
|
||||||
private Comparator<T> mComparator;
|
private final Comparator<T> comparator;
|
||||||
|
|
||||||
public ReverseComparator(Comparator<T> pComparator) {
|
public ReverseComparator(final Comparator<T> pComparator) {
|
||||||
mComparator = pComparator;
|
comparator = notNull(pComparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int compare(T pLeft, T pRight) {
|
public int compare(T pLeft, T pRight) {
|
||||||
int result = mComparator.compare(pLeft, pRight);
|
int result = comparator.compare(pLeft, pRight);
|
||||||
|
|
||||||
// We can't simply return -result, as -Integer.MIN_VALUE == Integer.MIN_VALUE.
|
// We can't simply return -result, as -Integer.MIN_VALUE == Integer.MIN_VALUE.
|
||||||
return -(result | (result >>> 1));
|
return -(result | (result >>> 1));
|
||||||
@ -516,73 +559,21 @@ public final class CollectionUtil {
|
|||||||
return (T) pCollection;
|
return (T) pCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"UnusedDeclaration"})
|
|
||||||
static void test() {
|
|
||||||
List list = Collections.singletonList("foo");
|
|
||||||
@SuppressWarnings({"unchecked"})
|
|
||||||
Set set = new HashSet(list);
|
|
||||||
|
|
||||||
List<String> strs0 = CollectionUtil.generify(list, String.class);
|
|
||||||
List<Object> objs0 = CollectionUtil.generify(list, String.class);
|
|
||||||
// List<String> strs01 = CollectionUtil.generify(list, Object.class); // Not okay
|
|
||||||
try {
|
|
||||||
List<String> strs1 = CollectionUtil.generify(set, String.class); // Not ok, runtime CCE unless set is null
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ArrayList<String> strs01 = CollectionUtil.generify(list, String.class); // Not ok, runtime CCE unless list is null
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> setstr1 = CollectionUtil.generify(set, String.class);
|
|
||||||
Set<Object> setobj1 = CollectionUtil.generify(set, String.class);
|
|
||||||
try {
|
|
||||||
Set<Object> setobj44 = CollectionUtil.generify(list, String.class); // Not ok, runtime CCE unless list is null
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> strs2 = CollectionUtil.<List<String>, String>generify2(list);
|
|
||||||
List<Object> objs2 = CollectionUtil.<List<Object>, String>generify2(list);
|
|
||||||
// List<String> morestrs = CollectionUtil.<List<Object>, String>generify2(list); // Not ok
|
|
||||||
try {
|
|
||||||
List<String> strs3 = CollectionUtil.<List<String>, String>generify2(set); // Not ok, runtime CCE unless set is null
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ArrayIterator<E> implements ListIterator<E> {
|
private static class ArrayIterator<E> implements ListIterator<E> {
|
||||||
private int mIndex;
|
private int next;
|
||||||
private final int mStart;
|
private final int start;
|
||||||
private final int mLength;
|
private final int length;
|
||||||
private final E[] mArray;
|
private final E[] array;
|
||||||
|
|
||||||
public ArrayIterator(E[] pArray, int pStart, int pLength) {
|
public ArrayIterator(final E[] pArray, final int pStart, final int pLength) {
|
||||||
if (pArray == null) {
|
array = notNull(pArray, "array");
|
||||||
throw new IllegalArgumentException("array == null");
|
start = isTrue(pStart >= 0, pStart, "start < 0: %d");
|
||||||
}
|
length = isTrue(pLength <= pArray.length - pStart, pLength, "length > array.length - start: %d");
|
||||||
if (pStart < 0) {
|
next = start;
|
||||||
throw new IllegalArgumentException("start < 0");
|
|
||||||
}
|
|
||||||
if (pLength > pArray.length - pStart) {
|
|
||||||
throw new IllegalArgumentException("length > array.length - start");
|
|
||||||
}
|
|
||||||
mArray = pArray;
|
|
||||||
mStart = pStart;
|
|
||||||
mLength = pLength;
|
|
||||||
mIndex = mStart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return mIndex < mLength + mStart;
|
return next < length + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public E next() {
|
public E next() {
|
||||||
@ -591,7 +582,7 @@ public final class CollectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return mArray[mIndex++];
|
return array[next++];
|
||||||
}
|
}
|
||||||
catch (ArrayIndexOutOfBoundsException e) {
|
catch (ArrayIndexOutOfBoundsException e) {
|
||||||
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
|
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
|
||||||
@ -609,11 +600,11 @@ public final class CollectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPrevious() {
|
public boolean hasPrevious() {
|
||||||
return mIndex > mStart;
|
return next > start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int nextIndex() {
|
public int nextIndex() {
|
||||||
return mIndex + 1;
|
return next - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public E previous() {
|
public E previous() {
|
||||||
@ -622,7 +613,7 @@ public final class CollectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return mArray[mIndex--];
|
return array[--next];
|
||||||
}
|
}
|
||||||
catch (ArrayIndexOutOfBoundsException e) {
|
catch (ArrayIndexOutOfBoundsException e) {
|
||||||
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
|
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
|
||||||
@ -632,11 +623,11 @@ public final class CollectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int previousIndex() {
|
public int previousIndex() {
|
||||||
return mIndex - 1;
|
return nextIndex() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(E pElement) {
|
public void set(E pElement) {
|
||||||
mArray[mIndex] = pElement;
|
array[next - 1] = pElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,483 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.util;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CollectionUtilTest
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: CollectionUtilTest.java,v 1.0 24.01.12 17:39 haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class CollectionUtilTest {
|
||||||
|
|
||||||
|
private static final Object[] stringObjects = new Object[] {"foo", "bar", "baz"};
|
||||||
|
private static final Object[] integerObjects = new Object[] {1, 2, 3};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeArraysObject() {
|
||||||
|
Object[] merged = (Object[]) CollectionUtil.mergeArrays(stringObjects, integerObjects);
|
||||||
|
assertArrayEquals(new Object[] {"foo", "bar", "baz", 1, 2, 3}, merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeArraysObjectOffset() {
|
||||||
|
Object[] merged = (Object[]) CollectionUtil.mergeArrays(stringObjects, 1, 2, integerObjects, 2, 1);
|
||||||
|
assertArrayEquals(new Object[] {"bar", "baz", 3}, merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectBadOffset() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 4, 2, integerObjects, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectBadSecondOffset() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, 2, integerObjects, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectBadLength() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, 4, integerObjects, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectBadSecondLength() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, 2, integerObjects, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectNegativeOffset() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, -1, 2, integerObjects, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectNegativeSecondOffset() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, 2, integerObjects, -1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectNegativeLength() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, -1, integerObjects, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IndexOutOfBoundsException.class)
|
||||||
|
public void testMergeArraysObjectNegativeSecondLength() {
|
||||||
|
CollectionUtil.mergeArrays(stringObjects, 1, 2, integerObjects, 2, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeArraysObjectAssignable() {
|
||||||
|
Integer[] integers = {1, 2, 3}; // Integer assignable to Object
|
||||||
|
|
||||||
|
Object[] merged = (Object[]) CollectionUtil.mergeArrays(stringObjects, integers);
|
||||||
|
assertArrayEquals(new Object[] {"foo", "bar", "baz", 1, 2, 3}, merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ArrayStoreException.class)
|
||||||
|
public void testMergeArraysObjectIllegalType() {
|
||||||
|
String[] strings = {"foo", "bar", "baz"};
|
||||||
|
Integer[] integers = {1, 2, 3}; // Integer not assignable to String
|
||||||
|
|
||||||
|
CollectionUtil.mergeArrays(strings, integers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ArrayStoreException.class)
|
||||||
|
public void testMergeArraysNativeIllegalType() {
|
||||||
|
char[] chars = {'a', 'b', 'c'};
|
||||||
|
int[] integers = {1, 2, 3}; // Integer not assignable to String
|
||||||
|
|
||||||
|
CollectionUtil.mergeArrays(chars, integers);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeArraysNative() {
|
||||||
|
char[] chars = {'a', 'b', 'c'};
|
||||||
|
char[] more = {'x', 'y', 'z'};
|
||||||
|
|
||||||
|
char[] merged = (char[]) CollectionUtil.mergeArrays(chars, more);
|
||||||
|
assertArrayEquals(new char[] {'a', 'b', 'c', 'x', 'y', 'z'}, merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubArrayObject() {
|
||||||
|
String[] strings = CollectionUtil.subArray(new String[] {"foo", "bar", "baz", "xyzzy"}, 1, 2);
|
||||||
|
assertArrayEquals(new String[] {"bar", "baz"}, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubArrayNative() {
|
||||||
|
int[] numbers = (int[]) CollectionUtil.subArray(new int[] {1, 2, 3, 4, 5}, 1, 3);
|
||||||
|
assertArrayEquals(new int[] {2, 3, 4}, numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testEnumIteratorNull() {
|
||||||
|
CollectionUtil.iterator((Enumeration<Object>) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnumIterator() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterator<String> iterator = CollectionUtil.iterator((Enumeration) new StringTokenizer("foo, bar, baz", ", "));
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (Object stringObject : stringObjects) {
|
||||||
|
assertTrue(iterator.hasNext());
|
||||||
|
assertEquals(stringObject, iterator.next());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Enumeration has no remove method, iterator.remove() must throw exception");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(3, count);
|
||||||
|
assertFalse(iterator.hasNext());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Iterator has more elements than enumeration");
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testArrayIteratorNull() {
|
||||||
|
CollectionUtil.iterator((Object[]) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayIterator() {
|
||||||
|
Iterator<String> iterator = CollectionUtil.iterator(new String[] {"foo", "bar", "baz"});
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (Object stringObject : stringObjects) {
|
||||||
|
assertTrue(iterator.hasNext());
|
||||||
|
assertEquals(stringObject, iterator.next());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Array have fixed length, iterator.remove() must throw exception");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(3, count);
|
||||||
|
assertFalse(iterator.hasNext());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Iterator has more elements than array");
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIterator() {
|
||||||
|
assertCorrectListIterator(CollectionUtil.iterator(new String[] {"foo", "bar", "baz"}), stringObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIteratorRange() {
|
||||||
|
assertCorrectListIterator(CollectionUtil.iterator(new String[] {"foo", "bar", "baz", "boo"}, 1, 2), new String[] {"bar", "baz"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIteratorSanityCheckArraysAsList() {
|
||||||
|
assertCorrectListIterator(Arrays.asList(new String[] {"foo", "bar", "baz"}).listIterator(), stringObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIteratorSanityCheckArraysAsListRange() {
|
||||||
|
// NOTE: sublist(fromInc, toExcl) vs iterator(start, length)
|
||||||
|
assertCorrectListIterator(Arrays.asList(new String[] {"foo", "bar", "baz", "boo"}).subList(1, 3).listIterator(0), new String[] {"bar", "baz"}, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIteratorSanityCheckArraysList() {
|
||||||
|
assertCorrectListIterator(new ArrayList<String>(Arrays.asList(new String[] {"foo", "bar", "baz"})).listIterator(), stringObjects, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListIteratorSanityCheckArraysListRange() {
|
||||||
|
// NOTE: sublist(fromInc, toExcl) vs iterator(start, length)
|
||||||
|
assertCorrectListIterator(new ArrayList<String>(Arrays.asList(new String[] {"foo", "bar", "baz", "boo"})).subList(1, 3).listIterator(0), new String[] {"bar", "baz"}, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements) {
|
||||||
|
assertCorrectListIterator(iterator, elements, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The test is can only test list iterators with a starting index == 0
|
||||||
|
private void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements, boolean skipRemove, boolean skipAdd) {
|
||||||
|
// Index is now "before 0"
|
||||||
|
assertEquals(-1, iterator.previousIndex());
|
||||||
|
assertEquals(0, iterator.nextIndex());
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (Object element : elements) {
|
||||||
|
assertTrue("No next element for element '" + element + "' at index: " + count, iterator.hasNext());
|
||||||
|
assertEquals(count > 0, iterator.hasPrevious());
|
||||||
|
assertEquals(count, iterator.nextIndex());
|
||||||
|
assertEquals(count - 1, iterator.previousIndex());
|
||||||
|
assertEquals(element, iterator.next());
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (!skipRemove) {
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Array has fixed length, iterator.remove() must throw exception");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify cursor not moving
|
||||||
|
assertEquals(count, iterator.nextIndex());
|
||||||
|
assertEquals(count - 1, iterator.previousIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: AbstractlList.ListItr.add() moves cursor forward, even if backing list's add() throws Exception
|
||||||
|
// (coll) AbstractList.ListItr.add might corrupt iterator state if enclosing add throws
|
||||||
|
// See: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6533203, fixed in Java 7
|
||||||
|
if (!skipAdd && !("java.util.AbstractList$ListItr".equals(iterator.getClass().getName()) /* && isJava7OrLater() */)) {
|
||||||
|
try {
|
||||||
|
iterator.add("xyzzy");
|
||||||
|
fail("Array has fixed length, iterator.add() must throw exception");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify cursor not moving
|
||||||
|
assertEquals(count, iterator.nextIndex());
|
||||||
|
assertEquals(count - 1, iterator.previousIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set is supported
|
||||||
|
iterator.set(String.valueOf(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(elements.length, count);
|
||||||
|
assertFalse(iterator.hasNext());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Iterator has more elements than array");
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index should now be "before last"
|
||||||
|
assertEquals(elements.length - 1, iterator.previousIndex());
|
||||||
|
assertEquals(elements.length, iterator.nextIndex());
|
||||||
|
|
||||||
|
for (int i = count; i > 0; i--) {
|
||||||
|
assertTrue("No previous element for element '" + elements[i - 1] + "' at index: " + (i - 1), iterator.hasPrevious());
|
||||||
|
assertEquals(i < elements.length, iterator.hasNext());
|
||||||
|
assertEquals(i - 1, iterator.previousIndex());
|
||||||
|
assertEquals(i, iterator.nextIndex());
|
||||||
|
|
||||||
|
assertEquals(String.valueOf(i), iterator.previous());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index should now be back "before 0"
|
||||||
|
assertEquals(-1, iterator.previousIndex());
|
||||||
|
assertEquals(0, iterator.nextIndex());
|
||||||
|
assertFalse(iterator.hasPrevious());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.previous();
|
||||||
|
fail("Iterator has more elements than array");
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testArrayIteratorRangeNull() {
|
||||||
|
CollectionUtil.iterator(null, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testArrayIteratorRangeBadStart() {
|
||||||
|
CollectionUtil.iterator(stringObjects, stringObjects.length + 1, 2);
|
||||||
|
}
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testArrayIteratorRangeBadLength() {
|
||||||
|
CollectionUtil.iterator(stringObjects, 1, stringObjects.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayIteratorRange() {
|
||||||
|
Iterator<String> iterator = CollectionUtil.iterator(new String[] {"foo", "bar", "baz", "xyzzy"}, 1, 2);
|
||||||
|
|
||||||
|
for (int i = 1; i < 3; i++) {
|
||||||
|
assertTrue(iterator.hasNext());
|
||||||
|
assertEquals(stringObjects[i], iterator.next());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Array has no remove method, iterator.remove() must throw exception");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(iterator.hasNext());
|
||||||
|
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Iterator has more elements than array range");
|
||||||
|
}
|
||||||
|
catch (NoSuchElementException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testReverseOrderNull() {
|
||||||
|
CollectionUtil.reverseOrder(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReverseOrder() {
|
||||||
|
Comparator<String> naturalOrder = new NaturalOrder<String>();
|
||||||
|
Comparator<String> reverse = CollectionUtil.reverseOrder(naturalOrder);
|
||||||
|
|
||||||
|
assertNotNull(reverse);
|
||||||
|
|
||||||
|
assertEquals(0, naturalOrder.compare("foo", "foo"));
|
||||||
|
assertEquals(0, reverse.compare("foo", "foo"));
|
||||||
|
|
||||||
|
assertTrue(naturalOrder.compare("bar", "baz") < 0);
|
||||||
|
assertTrue(reverse.compare("bar", "baz") > 0);
|
||||||
|
|
||||||
|
assertTrue(naturalOrder.compare("baz", "bar") > 0);
|
||||||
|
assertTrue(reverse.compare("baz", "bar") < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReverseOrderRandomIntegers() {
|
||||||
|
Comparator<Integer> naturalOrder = new NaturalOrder<Integer>();
|
||||||
|
Comparator<Integer> reverse = CollectionUtil.reverseOrder(naturalOrder);
|
||||||
|
|
||||||
|
Random random = new Random(243249878l); // Stable "random" sequence
|
||||||
|
|
||||||
|
for (int i = 0; i < 65536; i++) {
|
||||||
|
// Verified to be ~ 50/50 lt/gt
|
||||||
|
int integer = random.nextInt();
|
||||||
|
int integerToo = random.nextInt();
|
||||||
|
|
||||||
|
assertEquals(0, reverse.compare(integer, integer));
|
||||||
|
assertEquals(0, reverse.compare(integerToo, integerToo));
|
||||||
|
|
||||||
|
int natural = naturalOrder.compare(integer, integerToo);
|
||||||
|
|
||||||
|
if (natural == 0) {
|
||||||
|
// Actually never hits, but eq case is tested above
|
||||||
|
assertEquals(0, reverse.compare(integer, integerToo));
|
||||||
|
}
|
||||||
|
else if (natural < 0) {
|
||||||
|
assertTrue(reverse.compare(integer, integerToo) > 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertTrue(reverse.compare(integer, integerToo) < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("For development only")
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
|
public void testGenerify() {
|
||||||
|
List list = Collections.singletonList("foo");
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
Set set = new HashSet(list);
|
||||||
|
|
||||||
|
List<String> strs0 = CollectionUtil.generify(list, String.class);
|
||||||
|
List<Object> objs0 = CollectionUtil.generify(list, String.class);
|
||||||
|
// List<String> strs01 = CollectionUtil.generify(list, Object.class); // Not okay
|
||||||
|
try {
|
||||||
|
List<String> strs1 = CollectionUtil.generify(set, String.class); // Not ok, runtime CCE unless set is null
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ArrayList<String> strs01 = CollectionUtil.generify(list, String.class); // Not ok, runtime CCE unless list is null
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> setstr1 = CollectionUtil.generify(set, String.class);
|
||||||
|
Set<Object> setobj1 = CollectionUtil.generify(set, String.class);
|
||||||
|
try {
|
||||||
|
Set<Object> setobj44 = CollectionUtil.generify(list, String.class); // Not ok, runtime CCE unless list is null
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> strs2 = CollectionUtil.<List<String>, String>generify2(list);
|
||||||
|
List<Object> objs2 = CollectionUtil.<List<Object>, String>generify2(list);
|
||||||
|
// List<String> morestrs = CollectionUtil.<List<Object>, String>generify2(list); // Not ok
|
||||||
|
try {
|
||||||
|
List<String> strs3 = CollectionUtil.<List<String>, String>generify2(set); // Not ok, runtime CCE unless set is null
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NaturalOrder<T extends Comparable<T>> implements Comparator<T> {
|
||||||
|
public int compare(T left, T right) {
|
||||||
|
return left.compareTo(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user