4

How do i test for the equality of two iterators using JUnit?

Is there any built in method or is it just by comparing each and every element in that?

Thanks, Sriram

sriram
  • 378
  • 1
  • 7
  • 21
  • I don't think I have ever considered this question. – Tony Ennis Mar 17 '12 at 19:34
  • 1
    Remember that an `Iterator` can be arbitrarily long (even infinite). If there was a built in method for testing equality of two iterators and it worked in a reasonable amount of time, I could use it to generate interesting and publishable mathematical proofs. – emory Mar 17 '12 at 19:54
  • Also, testing the contents is a destructive operation. – OrangeDog Jul 14 '17 at 15:18

3 Answers3

5

You can't (and needn't) test the equality of iterators, only that of the underlying collections. To do that, you can iterate through both and compare each pair of elements in turn, as you guessed. Note that this effectively consumes at least one of the iterators. And the result is dependent on the state of the iterators at the start of the test, so this method is brittle. Therefore it is best to get hold of the underlying collections and test them directly for equality (using their equals method), whenever you can.

Why would you ever want to test the equality of two iterators? If you explain your concrete problem, we may be able to offer a better alternative.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 1
    There may not necessarily be an underlying collection. If there is an underlying collection, it may be infinite. – emory Mar 17 '12 at 19:56
  • 1
    I have a function which returns a type of Iterator. http://stackoverflow.com/questions/9747291/does-a-getter-with-a-different-return-type-qualify-as-a-getter . I am trying to test that. – sriram Mar 17 '12 at 20:20
  • 1
    @emory, good point, although these sound more like cases for a functional language rather than Java. – Péter Török Mar 17 '12 at 21:20
  • 1
    @sriram, and why do you need the method to return an iterator instead of the `List` you actually have? – Péter Török Mar 17 '12 at 21:24
1

There is no "classical" notion of equality for Iterators except for object identity, because they are mutable in the "worst" kind of way.

In a JUnit scenario, it would probably be preferable to collect the values next() returns into a list, e.g. using Guava's ImmutableList.copyOf(Iterator<T>), and then proceed with assertThat(a, is(b)) as described in this SO answer

Bernhard Stadler
  • 1,725
  • 14
  • 24
1

There is no sane way to test equality of Iterators.

If going insane in this is an option, you may want to delve into the implementation of the specific iterator type you are testing, and use reflection to access private stuff and compare that (I'm sure, with enough analysis of source code, that you would find what needs to hold for two ListIterators to be equal, for example).

Or if it's your own iterator type, then export some variables that help you out and use them instead of reflection.

Iterating through and comparing elements is only a weak guarantee, as you could be iterating over a clone of your collection, meaning the iterators look the same, but aren't.

Just don't do this.

Irfy
  • 9,323
  • 1
  • 45
  • 67
  • >"..., as you could be iterating over a clone of your collection, meaning the iterators look the same, but aren't."< What did you mean by "clone"? I see the problem that a developer might have an "underlying collection" in mind when dealing with iterators, but iterators can exist without ``Collection``s and ``Iterable``s. In a test scenario, it may make sense to check the behaviour of an iterator, because sometimes you just have no choice but to deal with the given API, no matter how good it is designed. – Bernhard Stadler Nov 16 '16 at 09:38
  • You could have an exact copy of your original collection and two iterators pointing into each one at the same position. If you just compare the container values through those iterators, you would think the iterators are *equal*, but in fact they point to distinct collections. – Irfy Nov 17 '16 at 09:23
  • Ok, so your idea was that when comparing iterators, you only want them to be equal if their underlying collections are identical, which of course implies that such an underlying collections exists in the first place. I don't think this is necessary because, even if the official Javadoc defines an ``Iterator`` as "an iterator over a collection" (with lower-case 'c'), the ``Iterator`` interface offers no means of accessing the collection, but only one element after another. So given only an ``Iterator``, we can't really even talk about the underlying collection when defining equality. – Bernhard Stadler Nov 29 '16 at 10:36
  • In practice, there is (almost) always an underlying collection and you can access it with reflection if you really must. What I wrote is doable but highly implementation-specific and non-portable, and thus the warning at the beginning of my 2nd paragraph. – Irfy Dec 04 '16 at 09:49
  • 1
    Ok so we agree that using reflection to access an iterator's underlying collection never should be done under ordinary circumstances. – Bernhard Stadler Dec 05 '16 at 10:24