📄 abstracttestcollection.java
字号:
/*
* Copyright 2001-2004 The Apache Software Foundation
*
* Licensed 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.commons.collections.collection;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.commons.collections.AbstractTestObject;
/**
* Abstract test class for {@link java.util.Collection} methods and contracts.
* <p>
* You should create a concrete subclass of this class to test any custom
* {@link Collection} implementation. At minimum, you'll have to
* implement the {@link #makeCollection()} method. You might want to
* override some of the additional public methods as well:
* <p>
* <b>Element Population Methods</b>
* <p>
* Override these if your collection restricts what kind of elements are
* allowed (for instance, if <code>null</code> is not permitted):
* <ul>
* <li>{@link #getFullElements()}
* <li>{@link #getOtherElements()}
* </ul>
* <p>
* <b>Supported Operation Methods</b>
* <p>
* Override these if your collection doesn't support certain operations:
* <ul>
* <li>{@link #isAddSupported()}
* <li>{@link #isRemoveSupported()}
* <li>{@link #areEqualElementsDistinguishable()}
* <li>{@link #isNullSupported()}
* <li>{@link #isFailFastSupported()}
* </ul>
* <p>
* <b>Fixture Methods</b>
* <p>
* Fixtures are used to verify that the the operation results in correct state
* for the collection. Basically, the operation is performed against your
* collection implementation, and an identical operation is performed against a
* <i>confirmed</i> collection implementation. A confirmed collection
* implementation is something like <code>java.util.ArrayList</code>, which is
* known to conform exactly to its collection interface's contract. After the
* operation takes place on both your collection implementation and the
* confirmed collection implementation, the two collections are compared to see
* if their state is identical. The comparison is usually much more involved
* than a simple <code>equals</code> test. This verification is used to ensure
* proper modifications are made along with ensuring that the collection does
* not change when read-only modifications are made.
* <p>
* The {@link #collection} field holds an instance of your collection
* implementation; the {@link #confirmed} field holds an instance of the
* confirmed collection implementation. The {@link #resetEmpty()} and
* {@link #resetFull()} methods set these fields to empty or full collections,
* so that tests can proceed from a known state.
* <p>
* After a modification operation to both {@link #collection} and
* {@link #confirmed}, the {@link #verify()} method is invoked to compare
* the results. You may want to override {@link #verify()} to perform
* additional verifications. For instance, when testing the collection
* views of a map, {@link AbstractTestMap} would override {@link #verify()} to make
* sure the map is changed after the collection view is changed.
* <p>
* If you're extending this class directly, you will have to provide
* implementations for the following:
* <ul>
* <li>{@link #makeConfirmedCollection()}
* <li>{@link #makeConfirmedFullCollection()}
* </ul>
* <p>
* Those methods should provide a confirmed collection implementation
* that's compatible with your collection implementation.
* <p>
* If you're extending {@link AbstractTestList}, {@link AbstractTestSet},
* or {@link AbstractTestBag}, you probably don't have to worry about the
* above methods, because those three classes already override the methods
* to provide standard JDK confirmed collections.<P>
* <p>
* <b>Other notes</b>
* <p>
* If your {@link Collection} fails one of these tests by design,
* you may still use this base set of cases. Simply override the
* test case (method) your {@link Collection} fails.
*
* @version $Revision: 155406 $ $Date: 2005-02-26 12:55:26 +0000 (Sat, 26 Feb 2005) $
*
* @author Rodney Waldhoff
* @author Paul Jack
* @author Michael A. Smith
* @author Neil O'Toole
* @author Stephen Colebourne
*/
public abstract class AbstractTestCollection extends AbstractTestObject {
//
// NOTE:
//
// Collection doesn't define any semantics for equals, and recommends you
// use reference-based default behavior of Object.equals. (And a test for
// that already exists in AbstractTestObject). Tests for equality of lists, sets
// and bags will have to be written in test subclasses. Thus, there is no
// tests on Collection.equals nor any for Collection.hashCode.
//
// These fields are used by reset() and verify(), and any test
// method that tests a modification.
/**
* A collection instance that will be used for testing.
*/
public Collection collection;
/**
* Confirmed collection. This is an instance of a collection that is
* confirmed to conform exactly to the java.util.Collection contract.
* Modification operations are tested by performing a mod on your
* collection, performing the exact same mod on an equivalent confirmed
* collection, and then calling verify() to make sure your collection
* still matches the confirmed collection.
*/
public Collection confirmed;
/**
* JUnit constructor.
*
* @param testName the test class name
*/
public AbstractTestCollection(String testName) {
super(testName);
}
//-----------------------------------------------------------------------
/**
* Specifies whether equal elements in the collection are, in fact,
* distinguishable with information not readily available. That is, if a
* particular value is to be removed from the collection, then there is
* one and only one value that can be removed, even if there are other
* elements which are equal to it.
*
* <P>In most collection cases, elements are not distinguishable (equal is
* equal), thus this method defaults to return false. In some cases,
* however, they are. For example, the collection returned from the map's
* values() collection view are backed by the map, so while there may be
* two values that are equal, their associated keys are not. Since the
* keys are distinguishable, the values are.
*
* <P>This flag is used to skip some verifications for iterator.remove()
* where it is impossible to perform an equivalent modification on the
* confirmed collection because it is not possible to determine which
* value in the confirmed collection to actually remove. Tests that
* override the default (i.e. where equal elements are distinguishable),
* should provide additional tests on iterator.remove() to make sure the
* proper elements are removed when remove() is called on the iterator.
**/
public boolean areEqualElementsDistinguishable() {
return false;
}
/**
* Returns true if the collections produced by
* {@link #makeCollection()} and {@link #makeFullCollection()}
* support the <code>add</code> and <code>addAll</code>
* operations.<P>
* Default implementation returns true. Override if your collection
* class does not support add or addAll.
*/
public boolean isAddSupported() {
return true;
}
/**
* Returns true if the collections produced by
* {@link #makeCollection()} and {@link #makeFullCollection()}
* support the <code>remove</code>, <code>removeAll</code>,
* <code>retainAll</code>, <code>clear</code> and
* <code>iterator().remove()</code> methods.
* Default implementation returns true. Override if your collection
* class does not support removal operations.
*/
public boolean isRemoveSupported() {
return true;
}
/**
* Returns true to indicate that the collection supports holding null.
* The default implementation returns true;
*/
public boolean isNullSupported() {
return true;
}
/**
* Returns true to indicate that the collection supports fail fast iterators.
* The default implementation returns true;
*/
public boolean isFailFastSupported() {
return false;
}
/**
* Returns true to indicate that the collection supports equals() comparisons.
* This implementation returns false;
*/
public boolean isEqualsCheckable() {
return false;
}
//-----------------------------------------------------------------------
/**
* Verifies that {@link #collection} and {@link #confirmed} have
* identical state.
*/
public void verify() {
int confirmedSize = confirmed.size();
assertEquals("Collection size should match confirmed collection's",
confirmedSize, collection.size());
assertEquals("Collection isEmpty() result should match confirmed " +
" collection's",
confirmed.isEmpty(), collection.isEmpty());
// verify the collections are the same by attempting to match each
// object in the collection and confirmed collection. To account for
// duplicates and differing orders, each confirmed element is copied
// into an array and a flag is maintained for each element to determine
// whether it has been matched once and only once. If all elements in
// the confirmed collection are matched once and only once and there
// aren't any elements left to be matched in the collection,
// verification is a success.
// copy each collection value into an array
Object[] confirmedValues = new Object[confirmedSize];
Iterator iter;
iter = confirmed.iterator();
int pos = 0;
while(iter.hasNext()) {
confirmedValues[pos++] = iter.next();
}
// allocate an array of boolean flags for tracking values that have
// been matched once and only once.
boolean[] matched = new boolean[confirmedSize];
// now iterate through the values of the collection and try to match
// the value with one in the confirmed array.
iter = collection.iterator();
while(iter.hasNext()) {
Object o = iter.next();
boolean match = false;
for(int i = 0; i < confirmedSize; i++) {
if(matched[i]) {
// skip values already matched
continue;
}
if(o == confirmedValues[i] ||
(o != null && o.equals(confirmedValues[i]))) {
// values matched
matched[i] = true;
match = true;
break;
}
}
// no match found!
if(!match) {
fail("Collection should not contain a value that the " +
"confirmed collection does not have: " + o +
"\nTest: " + collection + "\nReal: " + confirmed);
}
}
// make sure there aren't any unmatched values
for(int i = 0; i < confirmedSize; i++) {
if(!matched[i]) {
// the collection didn't match all the confirmed values
fail("Collection should contain all values that are in the confirmed collection" +
"\nTest: " + collection + "\nReal: " + confirmed);
}
}
}
//-----------------------------------------------------------------------
/**
* Resets the {@link #collection} and {@link #confirmed} fields to empty
* collections. Invoke this method before performing a modification
* test.
*/
public void resetEmpty() {
this.collection = makeCollection();
this.confirmed = makeConfirmedCollection();
}
/**
* Resets the {@link #collection} and {@link #confirmed} fields to full
* collections. Invoke this method before performing a modification
* test.
*/
public void resetFull() {
this.collection = makeFullCollection();
this.confirmed = makeConfirmedFullCollection();
}
//-----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -