home *** CD-ROM | disk | FTP | other *** search
- /*
- File: CheckedCollection.java
-
- Originally written by Doug Lea and released into the public domain.
- Thanks for the assistance and support of Sun Microsystems Labs, Agorics
- Inc, Loral, and everyone contributing, testing, and using this code.
-
- History:
- Date Who What
- 24Sep95 dl@cs.oswego.edu Create from collections.java working file
- 13Oct95 dl Misc clean-up.
- 19Oct95 dl more misc clean-up.
-
- */
-
- package collections;
-
- import java.util.Enumeration;
- import java.util.NoSuchElementException;
-
- /**
- *
- * Base class for Collection testing.
- * CheckCollections are simple harnesses around other Collections.
- * They include constructors that accept any other kind of collection, c.
- * They mirror each operation in the corresponding interface.
- * For each operation, they invoke c.checkImplementation(),
- * then operate upon c,
- * then check for as many testable effects of the operation
- * as is feasible, and then recheck c.
- * <P>
- * This is not usually very fast. Among other reasons,
- * checks often require that copies of state be made to compare against later.
- * <P>
- * @author Doug Lea
- * @version 0.94
- *
- * <P> For an introduction to this package see <A HREF="index.html"> Overview </A>.
- **/
-
- public class CheckedCollection implements UpdatableCollection {
-
- /**
- * The collection performing the actual work.
- * (All instance variables are public so can be inspected easily in tests)
- **/
-
- public UpdatableCollection thys;
-
- /**
- * A clone of the thys made before an operation
- **/
-
- public UpdatableCollection prev;
-
-
- /**
- * The version number of thys before an operation
- **/
-
- public int prevVersion;
-
- /**
- * Wrap collection c in inside a Checker
- **/
-
- public CheckedCollection(UpdatableCollection c) {
- thys = c;
- thys.checkImplementation();
- }
-
- /**
- * Make a Checked clone of underlying collection
- **/
- protected Object clone() throws CloneNotSupportedException {
- return new CheckedCollection((UpdatableCollection)(thys.duplicate()));
- }
-
-
- /**
- * Wrapper for clone()
- * @see clone
- **/
-
- public synchronized Collection duplicate() {
- Collection c = null;
- try {
- c = (Collection)(this.clone());
- } catch (CloneNotSupportedException ex) {}
- return c;
- }
-
-
- /**
- * Call at the end of any checked method
- **/
-
- protected void postCheck() {
- thys.checkImplementation();
- prev = null; // side effect -- detach prev so GC can claim it
- }
-
- /**
- * Call at the beginnning of any checked method requiring
- * use of prev clone
- **/
-
- protected void preCheck() {
- prev = (UpdatableCollection)(thys.duplicate());
- prevVersion = thys.version();
- }
-
- /**
- * Checks collections.Collection.canInclude according to its specification
- * @see collections.Collection#canInclude
- **/
- public synchronized boolean canInclude(Object element) {
- preCheck();
- boolean result = thys.canInclude(element);
- // not allowed to report true for null
- assert(!(result == true && element == null));
- // must be side-effect free
- assert(thys.sameStructure(prev));
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.Collection.isEmpty according to its specification
- * @see collections.Collection#isEmpty
- **/
- public synchronized boolean isEmpty() {
- preCheck();
- boolean result = thys.isEmpty();
- // must be behaviorally equivalent to asking if size() == 0
- assert(result == (thys.size() == 0));
- assert(thys.sameStructure(prev));
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.Collection.size according to its specification
- * @see collections.Collection#size
- **/
- public synchronized int size() {
- preCheck();
- int result = thys.size();
- // sizes are non-negative
- assert(result >= 0);
- // cross-check of isEmpty assertion
- assert( (result == 0) == thys.isEmpty());
- assert(thys.sameStructure(prev));
- postCheck();
- return result;
- }
-
-
-
- /**
- * Checks collections.Collection.occurrencesOf according to its specification
- * @see collections.Collection#occurrencesOf
- **/
- public synchronized int occurrencesOf(Object element) {
- preCheck();
- int result = thys.occurrencesOf(element);
- // occurrences are non-negative
- assert((result >= 0));
- // cannot be greater than size()
- assert(result <= thys.size());
- // occurrences of things you canot include must be 0
- assert(thys.canInclude(element) || result == 0);
- // cross-check of include condition
- assert( !((result == 0) && thys.includes(element)));
- assert(thys.sameStructure(prev));
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.Collection.includes according to its specification
- * @see collections.Collection#includes
- **/
- public synchronized boolean includes(Object element) {
- preCheck();
- boolean result = thys.includes(element);
- // must be equiv to asking if occurrences >= 1
- assert(result == (thys.occurrencesOf(element) >= 1));
- assert(thys.sameStructure(prev));
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.Collection.elements according to its specification
- * @see collections.Collection#elements
- **/
- public synchronized CollectionEnumeration elements() {
- // get one and make sure it is OK
- int c = thys.size();
- CollectionEnumeration e = thys.elements();
- while (e.hasMoreElements()) {
- // reports correct number of elements
- assert(e.numberOfRemainingElements() == c);
- --c;
- Object v = e.nextElement();
- // each element reported actually occurs
- assert(thys.includes(v));
- }
- // We've exhausted e; return another one
- postCheck();
- return thys.elements();
- }
-
-
- /**
- * Checks collections.Collection.sameStructure according to its specification
- * @see collections.Collection#sameStructure
- **/
- public synchronized boolean sameStructure(Collection c) {
- // cannot check since we rely on it to check other assertions
- boolean result = thys.sameStructure(c);
- postCheck();
- return result;
- }
-
- /**
- * Implements Object.toString
- **/
- public String toString() {
- // cannot check
- String result = thys.toString();
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.UpdatableCollection.version according to its specification
- * @see collections.UpdatableCollection#version
- **/
- public synchronized int version() {
- // nothing to check
- int result = thys.version();
- postCheck();
- return result;
- }
-
- /**
- * Checks collections.UpdatableCollection.clear according to its specification
- * @see collections.UpdatableCollection#clear
- **/
- public synchronized void clear() {
- preCheck();
- thys.clear();
- // mst now be empty
- assert(thys.isEmpty());
- // version change only if not previously empty
- assert((thys.version() == prevVersion) == prev.isEmpty());
- postCheck();
- }
-
-
- /**
- * Checks collections.UpdatableCollection.exclude according to its specification
- * @see collections.UpdatableCollection#exclude
- **/
- public synchronized void exclude(Object element) {
- preCheck();
- thys.exclude(element);
- checkRemove(thys, prev, element, true, true);
- postCheck();
- }
-
-
- /**
- * Checks collections.Collection.excluding.
- * @see collections.Collection#excluding
- **/
- public synchronized Collection excluding(Object element) {
- preCheck();
- Collection nc = thys.excluding(element);
- checkRemove(nc, thys, element, true, false);
- assert(thys.sameStructure(prev));
- postCheck();
- return nc;
- }
-
-
- /**
- * Checks collections.UpdatableCollection.removeOneOf according to its specification
- * @see collections.UpdatableCollection#removeOneOf
- **/
- public synchronized void removeOneOf(Object element) {
- preCheck();
- thys.removeOneOf(element);
- checkRemove(thys, prev, element, false, true);
- postCheck();
- }
-
- /**
- * Checks collections.Collection.removingOneOf
- * @see collections.Collection#removingOneOf
- **/
- public synchronized Collection removingOneOf(Object element) {
- preCheck();
- Collection nc = thys.removingOneOf(element);
- checkRemove(nc, thys, element, false, false);
- assert(thys.sameStructure(prev));
- postCheck();
- return nc;
- }
-
-
-
- /**
- * Checks collections.UpdatableCollection.replaceOneOf according to its specification
- * @see collections.UpdatableCollection#replaceOneOf
- **/
- public synchronized void replaceOneOf(Object oldElement, Object newElement)
- throws IllegalElementException {
- preCheck();
- try {
- thys.replaceOneOf(oldElement, newElement);
- checkReplace(thys, prev, oldElement, newElement, false, true);
- postCheck();
- }
- catch(IllegalElementException ex) {
- assert(thys.includes(oldElement) && !thys.canInclude(newElement));
- assert(thys.sameStructure(prev));
- postCheck();
- throw ex;
- }
- }
-
- /**
- * Checks collections.Collection.replacingOneOf
- * @see collections.Collection#replacingOneOf
- **/
- public synchronized Collection replacingOneOf(Object oldElement,
- Object newElement)
- throws IllegalElementException {
- preCheck();
- try {
- Collection nc = thys.replacingOneOf(oldElement, newElement);
- checkReplace(nc, thys, oldElement, newElement, false, false);
- assert(thys.sameStructure(prev));
- postCheck();
- return nc;
- }
- catch(IllegalElementException ex) {
- assert(thys.includes(oldElement) && !thys.canInclude(newElement));
- assert(thys.sameStructure(prev));
- postCheck();
- throw ex;
- }
-
- }
-
- /**
- * Checks collections.UpdatableCollection.replaceAllOf according to its specification
- * @see collections.UpdatableCollection#replaceAllOf
- **/
- public synchronized void replaceAllOf(Object oldElement, Object newElement)
- throws IllegalElementException {
- preCheck();
- try {
- thys.replaceAllOf(oldElement, newElement);
- checkReplace(thys, prev, oldElement, newElement, true, true);
- postCheck();
- }
- catch(IllegalElementException ex) {
- assert(thys.includes(oldElement) && !thys.canInclude(newElement));
- assert(thys.sameStructure(prev));
- postCheck();
- throw ex;
- }
- }
-
- /**
- * Checks collections.Collection.replacingAllOf
- * @see collections.Collection#replacingAllOf
- **/
- public synchronized Collection replacingAllOf(Object oldElement,
- Object newElement)
- throws IllegalElementException {
- preCheck();
- try {
- Collection nc = thys.replacingAllOf(oldElement, newElement);
- checkReplace(nc, thys, oldElement, newElement, true, false);
- assert(thys.sameStructure(prev));
- postCheck();
- return nc;
- }
- catch(IllegalElementException ex) {
- assert(thys.includes(oldElement) && !thys.canInclude(newElement));
- assert(thys.sameStructure(prev));
- postCheck();
- throw ex;
- }
-
- }
-
- /**
- * Checks collections.UpdatableCollection.take according to its specification
- * @see collections.UpdatableCollection#take
- **/
- public Object take() throws NoSuchElementException {
- preCheck();
- try {
- Object result = thys.take();
- assert(result != null);
- checkRemove(thys, prev, result, false, true);
- postCheck();
- return result;
- }
- catch (NoSuchElementException ex) {
- assert(prev.isEmpty());
- assert(thys.sameStructure(prev));
- postCheck();
- throw ex;
- }
- }
-
-
- /**
- * Checks collections.UpdatableCollection.excludeElements
- * @see collections.UpdatableCollection#excludeElements
- **/
- public synchronized void excludeElements(Enumeration e)
- throws CorruptedEnumerationException {
- preCheck();
- thys.excludeElements(e);
- // can't check elements since e has been exhausted --
- // we have no handle to them.
- postCheck();
- }
-
-
- /**
- * Checks collections.UpdatableCollection.removeElements
- * @see collections.UpdatableCollection#removeElements
- **/
- public synchronized void removeElements(Enumeration e)
- throws CorruptedEnumerationException {
- preCheck();
- thys.removeElements(e);
- // Same problem as above
- postCheck();
- }
-
- /**
- * Implements collections.ImplementationCheckable.assert.
- * @see collections.ImplementationCheckable#assert
- **/
- public void assert(boolean pred)
- throws ImplementationError {
- ImplementationError.assert(thys, pred);
- }
-
-
- /**
- * Implements collections.ImplementationCheckable.checkImplementation
- * @see collections.ImplementationCheckable#checkImplementation
- **/
- public synchronized void checkImplementation()
- throws ImplementationError {
- // we cannot check ourselves!
- }
-
- /**
- * Helper for checking remov*, exclud*, take
- **/
-
- protected void checkRemove(Collection nc, Collection oc,
- Object element,
- boolean allOccurrences, boolean verchk) {
- int prevOcc = oc.occurrencesOf(element);
- int reqOcc = 0;
- if (!allOccurrences && prevOcc > 1)
- reqOcc = prevOcc - 1;
- int newOcc = nc.occurrencesOf(element);
-
- assert(newOcc == reqOcc);
-
- // size reflects removals
- assert(nc.size() == oc.size() - (prevOcc - newOcc));
-
- if (verchk) {
- // version change only if occurrences change
- int nv = ((UpdatableCollection)nc).version();
- assert((nv == prevVersion) == (prevOcc == newOcc));
- }
-
- // all other elements the same
- CollectionEnumeration os = oc.elements();
- while (os.hasMoreElements()) {
- Object v = os.nextElement();
- assert(!v.equals(element) ==
- (nc.occurrencesOf(v) == oc.occurrencesOf(v)));
- }
-
- nc.checkImplementation();
-
- }
-
- /**
- * Helper for checking replac*
- **/
- protected void checkReplace(Collection nc, Collection oc,
- Object oldElement, Object newElement,
- boolean allOccurrences, boolean verchk) {
- int delta = prev.occurrencesOf(oldElement);
- // for OneOf, occurrences of old element == max(0, old occurrences - 1)
- if (!allOccurrences && delta > 1) delta = 1;
- // ... unless they are equal, in which case unchanged
- if (oldElement.equals(newElement)) delta = 0;
-
- assert(nc.occurrencesOf(oldElement) ==
- oc.occurrencesOf(oldElement) - delta);
-
- if (delta != 0)
- assert(nc.canInclude(newElement));
-
- // new occurrences added by one
- int reqNewOcc = prev.occurrencesOf(newElement) + delta;
- // .. unless it obeys Set semantics, in which case max of 1
- if (reqNewOcc > 1 && (nc instanceof Set)) reqNewOcc = 1;
-
- assert(nc.occurrencesOf(newElement) == reqNewOcc);
-
- if (verchk) {
- // version change only if occurrences change
- int nv = ((UpdatableCollection)nc).version();
- assert(!((nv == prevVersion) && (delta != 0)));;
- }
-
- // all other elements the same
-
- CollectionEnumeration os = oc.elements();
- while (os.hasMoreElements()) {
- Object v = os.nextElement();
- if (!v.equals(oldElement) && !v.equals(newElement))
- assert(nc.occurrencesOf(v) == oc.occurrencesOf(v));
- }
-
- nc.checkImplementation();
- }
-
- }
-
-