Index: /Users/edwin/workspace/groovy/src/test/groovy/lang/IntRangeTest.java =================================================================== --- /Users/edwin/workspace/groovy/src/test/groovy/lang/IntRangeTest.java (revision 4080) +++ /Users/edwin/workspace/groovy/src/test/groovy/lang/IntRangeTest.java (working copy) @@ -45,16 +45,552 @@ */ package groovy.lang; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import junit.framework.TestCase; /** + * Provides unit tests for the IntRange class. + * * @author James Strachan * @version $Revision$ */ public class IntRangeTest extends TestCase { + /** + * Records the values passed to a closure. + */ + private static class RecordingClosure extends Closure { + /** + * Holds the values passed in + */ + final List callLog; + + /** + * Creates a new RecordingClosure + * + * @param callLog is filled with the values passed to doCall + */ + RecordingClosure(final List callLog) { + super(null); + this.callLog = callLog; + } + + /** + * Stores params in the callLog. + * + * @param params the parameters. + * + * @return null + */ + public Object doCall(final Object params) { + callLog.add(params); + return null; + } + } + + /** + * Tests stepping through a range by two with a closure. + */ + public void testStepByTwoWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(0, 4); + range.step(2, closure); + + assertEquals("wrong number of calls to closure", 3, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 0; i <= 4; i += 2) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping through a reversed range by two with a closure. + */ + public void testReverseStepByTwoWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(4, 0); + range.step(2, closure); + + assertEquals("wrong number of calls to closure", 3, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 4; i >= 0; i -= 2) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping through a range with a closure. + */ + public void testStepByOneWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(1, 5); + range.step(1, closure); + + assertEquals("wrong number of calls to closure", 5, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 1; i <= 5; i++) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping through a reversed range by one with a closure. + */ + public void testReverseStepByOneWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(5, 1); + range.step(1, closure); + + assertEquals("wrong number of calls to closure", 5, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 5; i >= 1; i--) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping backwards through a range with a closure. + */ + public void testNegativeStepByOneWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(1, 5); + range.step(-1, closure); + + assertEquals("wrong number of calls to closure", 5, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 5; i >= 1; i--) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping backwards through a reversed range with a closure. + */ + public void testNegativeReverseStepByOneWithClosure() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(5, 1); + range.step(-1, closure); + + assertEquals("wrong number of calls to closure", 5, callLog.size()); + final Iterator iter = callLog.iterator(); + for (int i = 1; i <= 5; i++) { + assertEquals("wrong argument passed to closure", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping backwards through a range with a step size greater than the range size. + */ + public void testStepLargerThanRange() { + final List callLog = new ArrayList(); + final Closure closure = new RecordingClosure(callLog); + + final IntRange range = new IntRange(1, 5); + + range.step(6, closure); + assertEquals("wrong number of calls to closure", 1, callLog.size()); + assertEquals("wrong value", new Integer(1), callLog.get(0)); + + final List stepList = range.step(6); + assertEquals("wrong number of values in result", 1, stepList.size()); + assertEquals("wrong value", new Integer(1), callLog.get(0)); + } + + /** + * Tests stepping through a range by one. + */ + public void testStepByOne() { + final IntRange range = new IntRange(1, 5); + final List result = range.step(1); + + assertEquals("wrong number of calls", 5, result.size()); + final Iterator iter = result.iterator(); + for (int i = 1; i <= 5; i++) { + assertEquals("incorrect value in result", new Integer(i), iter.next()); + } + } + + /** + * Tests stepping through a range by two. + */ + public void testStepByTwo() { + final IntRange range = new IntRange(1, 5); + final List result = range.step(2); + + assertEquals("wrong number of calls", 3, result.size()); + final Iterator iter = result.iterator(); + for (int i = 1; i <= 5; i += 2) { + assertEquals("incorrect value in result", new Integer(i), iter.next()); + } + } + + /** + * Tests providing invalid arguments to the protected constructor. + */ + public void testInvalidArgumentsToConstructor() { + try { + new IntRange(2, 1, true); + fail("invalid range created"); + } + catch (IllegalArgumentException e) { + assertTrue("expected exception thrown", true); + } + } + + /** + * Tests creating a sub list with a negative "from" index. + */ + public void testSubListNegativeFrom() { + try { + final IntRange range = new IntRange(1, 5); + range.subList(-1, 3); + fail("accepted sub list with negative index"); + } + catch (IndexOutOfBoundsException e) { + assertTrue("expected exception thrown", true); + } + } + + /** + * Tests creating a sub list with an out of range "to" index. + */ + public void testSubListOutOfRangeTo() { + try { + final IntRange range = new IntRange(1, 5); + range.subList(0, 6); + fail("accepted sub list with invalid 'to'"); + } + catch (IndexOutOfBoundsException e) { + assertTrue("expected exception thrown", true); + } + } + + /** + * Tests creating a sub list with "from" grater than "to." + */ + public void testSubListFromGreaterThanTo() { + try { + final IntRange range = new IntRange(1, 5); + range.subList(3, 2); + fail("accepted sub list with 'from' greater than 'to'"); + } + catch (IllegalArgumentException e) { + assertTrue("expected exception thrown", true); + } + } + + /** + * Tests creating an empty sub list. + */ + public void testEmptySubList() { + final IntRange range = new IntRange(1, 5); + + List subList = range.subList(0, 0); + assertEquals("wrong number of elements in sub list", 0, subList.size()); + + subList = range.subList(2, 2); + assertEquals("wrong number of elements in sub list", 0, subList.size()); + } + + /** + * Tests iterating over a non-reversed range. + */ + public void testIterate() { + final IntRange range = new IntRange(1, 5); + int next = 1; + final Iterator iter = range.iterator(); + while (iter.hasNext()) { + final Integer number = (Integer) iter.next(); + assertEquals("wrong number", next++, number); + } + assertEquals("wrong number of elements in iteration", 6, next); + assertNull("got element after iterator finished", iter.next()); + } + + /** + * Tests iterating over a one-element range. + */ + public void testOneElementRange() { + final IntRange range = new IntRange(1, 1); + int next = 1; + for (Iterator iter = range.iterator(); iter.hasNext();) { + final Integer number = (Integer) iter.next(); + assertEquals("wrong number", next++, number); + } + assertEquals("wrong number of elements in iteration", 2, next); + } + + /** + * Tests removing an element from the range using an iterator (not supported). + */ + public void testRemove() { + final IntRange range = new IntRange(1, 5); + + try { + final Iterator iter = range.iterator(); + iter.remove(); + fail("successfully removed an element from an IntRange"); + } + catch (UnsupportedOperationException e) { + assertTrue("expected exception thrown", true); + } + } + + /** + * Tests iterating over a reversed range. + */ + public void testIterateReversed() { + final IntRange range = new IntRange(5, 1); + int next = 5; + for (Iterator iter = range.iterator(); iter.hasNext();) { + final Integer number = (Integer) iter.next(); + assertEquals("wrong number", next--, number); + } + assertEquals("wrong number of elements in iteration", 0, next); + } + + /** + * Tests creating an IntRange with from > to. + */ + public void testFromGreaterThanTo() { + final int from = 9; + final int to = 0; + final IntRange range = new IntRange(from, to); + + assertTrue("range not reversed", range.isReverse()); + + // make sure to/from are swapped + assertEquals("from incorrect", to, range.getFromInt()); + assertEquals("to incorrect", from, range.getToInt()); + + assertEquals("wrong size", 10, range.size()); + + assertEquals("wrong first element", 9, range.get(0)); + assertEquals("wrong last element", 0, range.get(9)); + } + + /** + * Tests creating an IntRange with from == to. + */ + public void testFromEqualsTo() { + final IntRange range = new IntRange(5, 5); + + assertFalse("range reversed", range.isReverse()); + assertEquals("wrong size", 1, range.size()); + } + + /** + * Tests creating an IntRange with from < to. + */ + public void testFromLessThanTo() { + final int from = 1; + final int to = 4; + final IntRange range = new IntRange(from, to); + + assertFalse("range reversed", range.isReverse()); + + assertEquals("to incorrect", from, range.getFromInt()); + assertEquals("from incorrect", to, range.getToInt()); + + assertEquals("wrong size", 4, range.size()); + } + + /** + * Making a range equal a list is not actually possible, since list.equals(range) will not evaluate to + * true and equals should be symmetric. + */ + public void testEqualsList() { + final List list = new ArrayList(); + list.add(new Integer(1)); + list.add(new Integer(2)); + + final IntRange range = new IntRange(1, 2); + + // cast to Object to test routing through IntRange.equals(Object) + assertTrue("range equals list", range.equals((Object) list)); + assertTrue("list equals range", list.equals(range)); + assertEquals("hash codes are equal", range.hashCode(), list.hashCode()); + + // compare lists that are the same size but contain different elements + list.set(0, new Integer(3)); + assertFalse("range does not equal list", range.equals(list)); + assertFalse("list doest not equal range", list.equals(range)); + assertFalse("hash codes are not equal", range.hashCode() == list.hashCode()); + + // compare a list longer than the range + list.set(0, new Integer(1)); + list.add(new Integer(3)); + assertFalse("range does not equal list", range.equals(list)); + assertFalse("list doest not equal range", list.equals(range)); + assertFalse("hash codes are not equal", range.hashCode() == list.hashCode()); + + // compare a list shorter than the range + list.remove(2); + list.remove(1); + assertFalse("range does not equal list", range.equals(list)); + assertFalse("list doest not equal range", list.equals(range)); + assertFalse("hash codes are not equal", range.hashCode() == list.hashCode()); + } + + /** + * Making a range equal a list is not actually possible, since list.equals(range) will not evaluate to + * true and equals should be symmetric. + */ + public void testEqualsNullList() { + final IntRange range = new IntRange(1, 2); + assertFalse("range not equal to null list", range.equals((List) null)); + } + + /** + * Tests comparing an IntRange to an object that is not an IntRange. + */ + public void testEqualsNonIntRange() { + final Integer number = new Integer(5); + final IntRange range = new IntRange(5, 5); + assertFalse("range equal to number", range.equals(number)); + } + + /** + * Tests comparing IntRanges cast to Object. + */ + public void testEqualsIntRangeAsObject() { + final IntRange range1 = new IntRange(1, 5); + final IntRange range2 = new IntRange(1, 5); + assertTrue("ranges not equal", range1.equals((Object) range2)); + assertTrue("ranges not equal", range2.equals((Object) range1)); + } + + /** + * Tests comparing IntRanges to each other. + */ + public void testEqualsIntRange() { + final IntRange range1 = new IntRange(1, 5); + IntRange range2 = new IntRange(1, 5); + assertTrue("ranges not equal", range1.equals((Object) range2)); + assertTrue("ranges not equal", range2.equals((Object) range1)); + assertEquals("hash codes not equal", range1.hashCode(), range2.hashCode()); + + range2 = new IntRange(0, 5); + assertFalse("ranges equal", range1.equals((Object) range2)); + assertFalse("ranges equal", range2.equals((Object) range1)); + assertFalse("hash codes equal", range1.hashCode() == range2.hashCode()); + + range2 = new IntRange(1, 6); + assertFalse("ranges equal", range1.equals((Object) range2)); + assertFalse("ranges equal", range2.equals((Object) range1)); + assertFalse("hash codes equal", range1.hashCode() == range2.hashCode()); + + range2 = new IntRange(0, 6); + assertFalse("ranges equal", range1.equals((Object) range2)); + assertFalse("ranges equal", range2.equals((Object) range1)); + assertFalse("hash codes equal", range1.hashCode() == range2.hashCode()); + + range2 = new IntRange(2, 4); + assertFalse("ranges equal", range1.equals((Object) range2)); + assertFalse("ranges equal", range2.equals((Object) range1)); + assertFalse("hash codes equal", range1.hashCode() == range2.hashCode()); + + range2 = new IntRange(5, 1); + assertFalse("ranges equal", range1.equals((Object) range2)); + assertFalse("ranges equal", range2.equals((Object) range1)); + assertFalse("hash codes equal", range1.hashCode() == range2.hashCode()); + } + + /** + * Tests toString and inspect + */ + public void testToStringAndInspect() { + IntRange range = new IntRange(1, 5); + assertEquals("wrong string representation", "1..5", range.toString()); + assertEquals("wrong string representation", "1..5", range.inspect()); + + range = new IntRange(5, 1); + assertEquals("wrong string representation", "5..1", range.toString()); + assertEquals("wrong string representation", "5..1", range.inspect()); + } + + /** + * Tests getFrom and getTo. + */ + public void testGetFromAndTo() { + final int from = 1, to = 5; + final IntRange range = new IntRange(from, to); + + assertEquals("wrong 'from' value", from, range.getFromInt()); + assertEquals("wrong 'from' value", new Integer(from), range.getFrom()); + + assertEquals("wrong 'to' value", to, range.getToInt()); + assertEquals("wrong 'to' value", new Integer(to), range.getTo()); + } + + /** + * Tests comparing an IntRange to null. + * + */ + public void testEqualsNullObject() { + final IntRange range = new IntRange(1, 5); + assertFalse("range equal to null", range.equals(null)); + assertFalse("range equal to null object", range.equals((Object) null)); + assertFalse("range equal to null IntRange", range.equals((IntRange) null)); + } + + /** + * Tests get from a reversed range. + */ + public void testGetFromReversedRange() { + final IntRange range = new IntRange(5, 1); + + for (int i = 0; i < 5; i++) { + assertEquals("wrong element at position " + i, 5 - i, range.get(i)); + } + } + + private void doTestContains(int from, int to, IntRange range) { + // test integers + assertTrue("missing 'from' value", range.contains(new Integer(from))); + assertTrue("missing 'to' value", range.contains(new Integer(to))); + assertTrue("missing mid point", range.contains(new Integer((from + to) / 2))); + assertFalse("contains out of range value", range.contains(new Integer(from - 1))); + assertFalse("contains out of range value", range.contains(new Integer(to + 1))); + + // test int range + assertTrue("missing same range", range.contains(new IntRange(from, to))); + assertTrue("missing same range", range.contains(new IntRange(to, from))); + assertTrue("missing strict subset", range.contains(new IntRange(from + 1, to - 1))); + assertTrue("missing subset", range.contains(new IntRange(from, to - 1))); + assertTrue("missing subset", range.contains(new IntRange(from + 1, to))); + assertFalse("contains non-subset", range.contains(new IntRange(from - 1, to))); + assertFalse("contains non-subset", range.contains(new IntRange(from, to + 1))); + assertFalse("contains non-subset", range.contains(new IntRange(from - 2, from - 1))); + + // test non-integer number + assertFalse("contains floating point number", range.contains(new Float(from))); + } + + /** + * Tests whether an IntRange contains another IntRange or a specific integer. + */ + public void testContains() { + final int from = 1, to = 5; + doTestContains(from, to, new IntRange(from, to)); + doTestContains(from, to, new IntRange(to, from)); + } + public void testSize() { IntRange r = createRange(0, 10); assertEquals("Size of " + r, 11, r.size()); @@ -98,19 +634,6 @@ } - public void testContains() { - IntRange r = createRange(10, 20); - - assertTrue("contains 11", r.contains(new Integer(11))); - assertTrue("contains 10", r.contains(new Integer(10))); - assertTrue("contains 19", r.contains(new Integer(19))); - assertTrue("contains 20", r.contains(new Integer(20))); - assertFalse("contains 9", r.contains(new Integer(9))); - assertFalse("contains 21", r.contains(new Integer(21))); - assertFalse("contains 100", r.contains(new Integer(100))); - assertFalse("contains -1", r.contains(new Integer(-1))); - } - public void testSubList() { IntRange r = createRange(10, 20);