The assertEquals(Set, Set) doesn't behave as Set.equals(set).
Is this intentional?
Calling assertEqual(...) with two Sets as arguments "hits" the
assertEqual(Collection, Collection), which seems to be made for arrays
and/or lists, in that all text there refer to "Arrays not equal" but
at the same time "Lists differ at ..", and that the implementation
takes the iterator for both collections, and steps them
simultaneously, failing on any mismatch, which IMO isn't quite
set-correct.
I find this suboptimal, as I specifically want to use Set logic in
some tests (unordered equals), and List logic in others (ordered
equals).
There's a method assertEqualsNoOrder(Object[], Object[]). This seems
along the lines of what I want (although I still see the above as a
bug), but there is no corresponding assertEqualsNoOrder(Collection,
Collection). The method could possibly be used as a workaround, but
upon inspection, I can't seem to understand how that method should
work either: The method seems to make use of the idea that Set-equals
is unordered (it makes two HashSets and sticks the array elements in
them, then calls assertEquals), which we just showed isn't the case.
Upon testing with a couple String[] {"a", "b", "c"} and String[] {"c",
"a", "b"}, I find that these actually does assert with
assertEqualsNoOrder. However, upon inspection, the HashSet "magically"
keeps these in the same iteration order, but this is obviously just
because of a spurious combination of small size, and the inner
workings of HashSet. Thus, the system should fail on a test where the
hashCode is bad, and on two much larger arrays which are
unordered-equal, but have different permutations.
Bad hash code, fails:
----------------
import org.testng.Assert;
import org.testng.annotations.Test;
public class XTestNGequalsNoOrder_BadHashCode {
@Test
public void test() {
BadHashCode a = new BadHashCode();
BadHashCode b = new BadHashCode();
BadHashCode c = new BadHashCode();
BadHashCode[] array1 = new BadHashCode[] { a, b, c };
BadHashCode[] array2 = new BadHashCode[] { a, b, c };
Assert.assertEqualsNoOrder(array1, array2);
// Fails:
array2 = new BadHashCode[] { c, b, a };
Assert.assertEqualsNoOrder(array1, array2);
}
private static class BadHashCode {
static int count;
int _count = count++;
@Override
public int hashCode() {
return 1;
}
@Override
public String toString() {
return "" + _count;
}
}
}
Random permutation of larger number of elements, fails:
----------------
import java.util.ArrayList;
import java.util.Collections;
import org.testng.Assert;
import org.testng.annotations.Test;
public class XTestnGequalsNoOrder_ManyRandom {
static int NUM = 2000;
@Test
public void test() {
ArrayList<String> source = new ArrayList<String>();
for (int i = 0; i < NUM; i++) {
source.add(i + ":" + Math.random());
}
String[] array1_sorted = source.toArray(new String[NUM]);
String[] array2_sorted = source.toArray(new String[NUM]);
Collections.shuffle(source);
String[] array1_random = source.toArray(new String[NUM]);
Collections.shuffle(source);
String[] array2_random = source.toArray(new String[NUM]);
Assert.assertEquals(array1_sorted, array2_sorted);
Assert.assertEqualsNoOrder(array1_sorted, array2_sorted);
// Fails:
Assert.assertEqualsNoOrder(array1_random, array2_random);
}
}
Quick suggestion for assertEquals(Set, Set, msg) (which thus should
fix both problems at once), or possibly instead for
assertEqualsNoOrder(Collection, Collection, msg) (in which case the
assertEqualsNoOrder(Object[], Object[], msg) must use this). If my
analysis is deemed correct, then please feel free to use it:
----------------
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.testng.Assert;
import org.testng.annotations.Test;
public class XTestNGequalsSetSet {
static int NUM = 2000;
@Test
public void test() {
ArrayList<String> source = new ArrayList<String>();
for (int i = 0; i < NUM; i++) {
source.add(i + ":" + Math.random());
}
List<String> list1 = new ArrayList<String>(source);
List<String> list2 = new ArrayList<String>(source);
Assert.assertEquals(list1, list2);
Collections.shuffle(list1);
Collections.shuffle(list2);
Set<String> set1 = new HashSet<String>(list1);
Set<String> set2 = new HashSet<String>(list2);
assertEquals(set1, set2, null);
// ========== The following shall fail: ============
list1.remove(500);
// list2.remove(500);
set1 = new HashSet<String>(list1);
set2 = new HashSet<String>(list2);
assertEquals(set1, set2, null);
}
/**
* Asserts that two Sets contain the same elements, but
potentially in different order. If they do not, an
* AssertionError, with the given message, is thrown.
*
* @param actual the actual Set of elements
* @param expected the expected Set of elements
* @param message the assertion error message
*/
static public void assertEquals(Set actual, Set expected, String message) {
if (actual == expected) return;
if ((actual == null && expected != null) || (actual != null &&
expected == null)) {
if (actual == null) {
Assert.fail((message != null ? message + ": " : "") +
"Actual is null, while expected is '" + expected
+ "'.");
}
Assert.fail((message != null ? message + ": " : "") +
"Expected is null, while actual is '" + expected
+ "'.");
}
Iterator actIt = actual.iterator();
int i = 0;
// To avoid dependency on the elements' hashCode()
List expectedArray = new ArrayList(expected);
while (actIt.hasNext()) {
Object a = actIt.next();
if (!expectedArray.contains(a)) {
Assert.fail((message != null ? message + ": " : "") +
"Sets differ at iterator position #" + i
+ ": Actual (size:" + actual.size() + ")
contains element '" + a
+ "' which doesn't exist in expected (size:" +
expected.size() + ").");
}
i++;
}
if (actual.size() != expected.size()) {
Iterator expIt = expected.iterator();
i = 0;
List actualArray = new ArrayList(actual);
while (expIt.hasNext()) {
Object e = expIt.next();
if (!actualArray.contains(e)) {
Assert.fail((message != null ? message + ": " :
"") + "Sets differ at iterator position #" + i
+ ": Expected (size:" + expected.size() +
") contains element '" + e
+ "' which doesn't exist in actual (size:"
+ actual.size() + ").");
}
i++;
}
}
}
}
Kind regards,
Endre.
I imagine the project owners are as hesitant as I would be to add a
bunch of overloaded collections methods to Assert.
I imagine the project owners are as hesitant as I would be to add a
bunch of overloaded collections methods to Assert.
I filed a related issue the other day as http://code.google.com/p/testng/issues/detail?id=48
but, I see now that I should have filed it on the JIRA site.
A failing testcase for assertEqualsNoOrder is:
String[] rto1 = { "boolean", "BigInteger", "List",};
String[] rto2 = { "List", "BigInteger", "boolean",};
assertEqualsNoOrder(rto1, rto2);
There's also an open bug that mentions that
String[] rto1 = { "a", "a", "b",};
String[] rto2 = { "a", "b", "b",};
assertEqualsNoOrder(rto1, rto2);
will yield a false positive.
PS: What is the point of requiring people that want to view the
archives of these google groups to be subscribers? When they are
already indexed by both nabble and markmail?