/** * @author bret5 * Copyright(C) 2007 bret5 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ package jmemorize.core.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import jmemorize.util.EquivalenceClassSet; import junit.framework.TestCase; /** * @author bret5 * */ public class EquivalenceClassSetTest extends TestCase { private EquivalenceClassSet mod3EqvSet; protected void setUp() { Comparator mod3cmp = new Comparator() { public int compare(Object arg0, Object arg1) { if (!(arg0 instanceof Integer) && (arg1 instanceof Integer)) { throw new ClassCastException(); } int arg0mod3 = ((Integer)arg0).intValue() % 3; int arg1mod3 = ((Integer)arg1).intValue() % 3; if (arg0mod3 < arg1mod3) return -1; if (arg0mod3 == arg1mod3) return 0; return 1; } }; mod3EqvSet = new EquivalenceClassSet(mod3cmp); assert mod3EqvSet.getComparator().equals(mod3cmp); // now populate the set int expectedSize = 0; for (int i = 3; i <= 9; i++) { assertTrue(mod3EqvSet.add(new Integer(i))); expectedSize += 1; if (i > 3) { assertFalse(mod3EqvSet.add(new Integer(i - 1))); } assertEquals(expectedSize, mod3EqvSet.size()); } } public void testIterator() { Iterator iter = mod3EqvSet.iterator(); int lastModVal = 0; int nValues = 0; while (iter.hasNext()) { int value = ((Integer)(iter.next())).intValue(); nValues += 1; int modVal = value % 3; assertTrue(modVal >= lastModVal); lastModVal = modVal; } assertEquals(nValues, mod3EqvSet.size()); } public void testAddAll() { EquivalenceClassSet newSet = new EquivalenceClassSet(mod3EqvSet.getComparator()); List randomOrderList = new ArrayList(mod3EqvSet); Collections.shuffle(randomOrderList); newSet.addAll(randomOrderList); Set interSet = new HashSet(newSet); interSet.retainAll(mod3EqvSet); assertTrue(interSet.size() == mod3EqvSet.size()); } protected void internalSanityTestLoopIterator(int iters, boolean isShuffle) { if (!isShuffle) { mod3EqvSet.setShuffleEquivalenceClasses(isShuffle); } int hashCode = mod3EqvSet.hashCode(); Iterator loopIter = mod3EqvSet.loopIterator(); int items = mod3EqvSet.size(); for (int i = 0; i < iters; i++) { int lastModVal = 0; int lastVal = 0; for (int j = 0; j < items; j++) { assertTrue(loopIter.hasNext()); int value = ((Integer)(loopIter.next())).intValue(); int modVal = value % 3; assertTrue(modVal >= lastModVal); if (!isShuffle) { assertTrue(modVal != lastModVal || value >= lastVal); lastVal = value; } lastModVal = modVal; } assertTrue(mod3EqvSet.hashCode() == hashCode); } } public void testLoopIteratorNoChanges() { internalSanityTestLoopIterator(4, true); } public void testNoShuffle() { internalSanityTestLoopIterator(4, false); } public void internalTestLoopIteratorAddToClass(int addVal, boolean expired, boolean expectedInCycle) { // add something to a following class (increases the number of items // till back to 0) Iterator loopIter = mod3EqvSet.loopIterator(); int expectedCount = mod3EqvSet.size(); int expectedSize = mod3EqvSet.size() + 1; if (expectedInCycle) { expectedCount += 1; } int lastModVal = 0; boolean isAdded = false; boolean isFound = false; for (int j = 0; j < expectedCount + 1; j++) { // note extra item - we want to wrap around to verify the first item assertTrue(loopIter.hasNext()); int value = ((Integer)(loopIter.next())).intValue(); if (value == addVal && (j < expectedCount)) { isFound = true; } int modVal = value % 3; if (j < expectedCount) { assertTrue(modVal >= lastModVal); } else { assertTrue(modVal == 0); } lastModVal = modVal; if (modVal == 1 && !isAdded) { isAdded = true; if (!expired) { assertTrue(mod3EqvSet.add(new Integer(addVal))); } else { assertTrue(mod3EqvSet.addExpired(new Integer(addVal))); } } } if (expectedInCycle) { assertTrue(isFound); } else { assertFalse(isFound); } assertTrue(mod3EqvSet.contains(new Integer(addVal))); assertTrue(new ArrayList(mod3EqvSet).size() == expectedSize); mod3EqvSet.resetLoopIterator(); internalSanityTestLoopIterator(1, true); } public void testLoopIteratorAddToFollowingClass() { // add something to a following class (increases the number of items // till back to 0) internalTestLoopIteratorAddToClass(32, false, true); } public void testLoopIteratorAddToPrevClass() { // add something to a prior class (doesn't increase the number of items // till back to 0) internalTestLoopIteratorAddToClass(30, false, false); } public void testLoopIteratorAddToCurrentClass() { // add something to the current class - add internalTestLoopIteratorAddToClass(31, false, true); // add something to the current class - addExpired // test remove! } public void testLoopIteratorAddToCurrentClassExpired() { // add something to the current class - addExpired internalTestLoopIteratorAddToClass(31, true, false); } public void internalTestLoopIteratorRemoveFromClass(int remVal, boolean expectedToReduceCycle, boolean removeAlreadyFound) { // remove something from a class and test loop iterator behavior Iterator loopIter = mod3EqvSet.loopIterator(); int expectedSize = mod3EqvSet.size() - 1; int expectedCount = mod3EqvSet.size(); if (expectedToReduceCycle) { expectedCount -= 1; } int lastModVal = 0; boolean isRemoved = false; for (int j = 0; j < expectedCount + 1; j++) { // note extra item - we want to wrap around to verify the first item assertTrue(loopIter.hasNext()); int value = ((Integer)(loopIter.next())).intValue(); int modVal = value % 3; if (j < expectedCount) { assertTrue(modVal >= lastModVal); } else { assertTrue(modVal == 0); } lastModVal = modVal; if (modVal == 1 && !isRemoved) { if (remVal % 3 == 1) { if (value % 3 == modVal) { isRemoved = true; if (removeAlreadyFound) { remVal = value; } else { // this relies on knowing that the two values in the // set are 11 and 4 remVal = 11 - value; } assertTrue(mod3EqvSet.remove(new Integer(remVal))); } } else { isRemoved = true; assertTrue(mod3EqvSet.remove(new Integer(remVal))); } } } assertFalse(mod3EqvSet.contains(new Integer(remVal))); assertTrue(new ArrayList(mod3EqvSet).size() == expectedSize); mod3EqvSet.resetLoopIterator(); internalSanityTestLoopIterator(1, true); } public void testLoopIteratorRemoveFromPrevClass() { // remove something from a prior class (no effect on items till back to 0) internalTestLoopIteratorRemoveFromClass(6, false, false); } public void testLoopIteratorRemoveFromFollowingClass() { // remove something from a following class (reduces items till back to 0) internalTestLoopIteratorRemoveFromClass(8, true, false); } public void testLoopIteratorRemoveFromCurrentClass1() { // remove something not yet found from current class (reduces items till back to 0) internalTestLoopIteratorRemoveFromClass(7, true, false); } public void testLoopIteratorRemoveFromCurrentClass2() { // remove something found from current class (no effect on items till back to 0) internalTestLoopIteratorRemoveFromClass(7, false, true); } public void internalTestLoopIteratorRemoveList(List remValues, int expectedCycleReduction, int expectedFirstModVal) { // remove something from a class and test loop iterator behavior Iterator loopIter = mod3EqvSet.loopIterator(); int expectedCount = mod3EqvSet.size() - expectedCycleReduction; int expectedSize = mod3EqvSet.size() - remValues.size(); int lastModVal = 0; boolean isRemoved = false; for (int j = 0; j < expectedCount + 1; j++) { // note extra item - we want to wrap around to verify the first item assertTrue(loopIter.hasNext()); int value = ((Integer)(loopIter.next())).intValue(); int modVal = value % 3; if (j < expectedCount) { assertTrue(modVal >= lastModVal); } else { assertTrue(modVal == expectedFirstModVal); } lastModVal = modVal; if (modVal == 1 && !isRemoved) { isRemoved = true; Iterator iter = remValues.iterator(); while (iter.hasNext()) { Integer remVal = (Integer)iter.next(); assertTrue(mod3EqvSet.remove(remVal)); } } } Iterator iter = remValues.iterator(); while (iter.hasNext()) { Integer remVal = (Integer)iter.next(); assertFalse(mod3EqvSet.contains(remVal)); } assertTrue(new ArrayList(mod3EqvSet).size() == expectedSize); mod3EqvSet.resetLoopIterator(); internalSanityTestLoopIterator(1, true); } public void testLoopIteratorRemoveEntireFollowingClass() { Integer[] vals = { new Integer(8), new Integer(5) }; internalTestLoopIteratorRemoveList(Arrays.asList(vals), vals.length, 0); } public void testLoopIteratorRemoveEntirePrevClass() { Integer[] vals = { new Integer(6), new Integer(3), new Integer(9) }; internalTestLoopIteratorRemoveList(Arrays.asList(vals), 0, 1); } public void testLoopIteratorRemoveEntireCurrentClass() { Integer[] vals = { new Integer(7), new Integer(4) }; internalTestLoopIteratorRemoveList(Arrays.asList(vals), vals.length - 1, 0); } public void testPartition() { int originalSize = mod3EqvSet.size(); int NUM_TO_REMOVE = 4; EquivalenceClassSet newSet = mod3EqvSet.partition(NUM_TO_REMOVE); assertTrue(NUM_TO_REMOVE == newSet.size()); assertTrue(mod3EqvSet.size() + newSet.size() == originalSize); // now make sure the order is right Iterator iter = mod3EqvSet.iterator(); Iterator newSetIter = newSet.iterator(); int lastModVal = 0; int nValues = 0; while (newSetIter.hasNext()) { int value = ((Integer)(newSetIter.next())).intValue(); nValues += 1; int modVal = value % 3; assertTrue(modVal >= lastModVal); lastModVal = modVal; } assertEquals(nValues, NUM_TO_REMOVE); nValues = 0; while (iter.hasNext()) { int value = ((Integer)(iter.next())).intValue(); nValues += 1; int modVal = value % 3; assertTrue(modVal >= lastModVal); lastModVal = modVal; } assertEquals(nValues, originalSize - NUM_TO_REMOVE); Set interSet = new HashSet(newSet); interSet.retainAll(mod3EqvSet); assertTrue(interSet.size() == 0); } }