Skip to content

Commit a8bfcbe

Browse files
committed
feat(assert): array-delta assertNotEquals + collection/string fixes
- Add assertNotEquals(float[]/double[], delta) overloads (with and without a message), the missing counterparts of the existing assertEquals(...delta) array assertions. - Fix assertNotEquals(Collection, Collection) to be the exact inverse of assertEquals(Collection, Collection): compare by size and element order instead of relying on the collections' own equals(), so a List and a Set with the same ordered content are no longer reported as both equal and not-equal. - Delegate assertEquals(String, String, String) to AssertJ, producing a readable character-level diff on mismatch. The failure message format changes accordingly. - Add regression tests documenting that assertThrows/expectThrows already cover the requested exception assertion (#8) and that assertSame now yields an explicit identity-vs-equality message via AssertJ (#10). fix #11 fix #14 fix #18
1 parent 4cc39e5 commit a8bfcbe

4 files changed

Lines changed: 191 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- `Assert.assertNotEquals(float[], float[], delta)` and
13+
`Assert.assertNotEquals(double[], double[], delta)` overloads (with and without a message),
14+
the missing counterparts of the existing `assertEquals(...delta)` array assertions
15+
([#11](https://github.com/testng-team/testng-asserts/issues/11)).
16+
17+
### Changed
18+
19+
- `Assert.assertEquals(String, String, String)` now delegates to AssertJ, producing a readable
20+
character-level diff on mismatch. The failure message format changes accordingly
21+
([#18](https://github.com/testng-team/testng-asserts/issues/18)).
22+
23+
### Fixed
24+
25+
- `Assert.assertNotEquals(Collection, Collection)` is now the exact inverse of
26+
`assertEquals(Collection, Collection)`: it compares by size and element order instead of relying
27+
on the collections' `equals()`, so a `List` and a `Set` with the same ordered content are no
28+
longer reported as both equal and not-equal
29+
([#14](https://github.com/testng-team/testng-asserts/issues/14)).
30+
1031
## [1.0.0]
1132

1233
First standalone release of `org.testng:testng-asserts`.

src/main/java/org/testng/Assert.java

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,8 @@ public static void assertEquals(Object actual, Object expected) {
670670
* @param message the assertion error message
671671
*/
672672
public static void assertEquals(String actual, String expected, String message) {
673-
assertEquals((Object) actual, (Object) expected, message);
673+
// Delegated to AssertJ to produce a readable character-level diff on mismatch (GITHUB-18).
674+
assertThat(actual).as(message).isEqualTo(expected);
674675
}
675676

676677
/**
@@ -1972,8 +1973,10 @@ private static String getNotEqualReason(Collection<?> actual, Collection<?> expe
19721973
return "Collections not equal: expected: " + expected + " and actual: " + actual;
19731974
}
19741975

1975-
if (!Objects.equals(actual, expected)) {
1976-
return "Collections differ: expected " + expected + " but got " + actual;
1976+
// Mirror assertEquals(Collection): compare by size + element order so that assertNotEquals is
1977+
// the exact inverse of assertEquals, regardless of the collections' own equals() (GITHUB-14).
1978+
if (actual.size() != expected.size()) {
1979+
return "Collections differ in size: expected " + expected + " but got " + actual;
19771980
}
19781981

19791982
return getNotEqualReason(actual.iterator(), expected.iterator());
@@ -2304,6 +2307,92 @@ public static void assertNotEquals(double actual, double expected, double delta,
23042307
}
23052308
}
23062309

2310+
/**
2311+
* Asserts that two float arrays are not equal within the given delta. If they are equal, an
2312+
* AssertionError is thrown.
2313+
*
2314+
* @param actual the actual value
2315+
* @param expected the expected value
2316+
* @param delta the absolute tolerable difference between the actual and expected values
2317+
*/
2318+
public static void assertNotEquals(float[] actual, float[] expected, float delta) {
2319+
assertNotEquals(actual, expected, delta, null);
2320+
}
2321+
2322+
/**
2323+
* Asserts that two float arrays are not equal within the given delta. If they are equal, an
2324+
* AssertionError, with the given message, is thrown.
2325+
*
2326+
* @param actual the actual value
2327+
* @param expected the expected value
2328+
* @param delta the absolute tolerable difference between the actual and expected values
2329+
* @param message the assertion error message
2330+
*/
2331+
public static void assertNotEquals(
2332+
float[] actual, float[] expected, float delta, String message) {
2333+
if (areEqual(actual, expected, delta)) {
2334+
Assert.fail(format(actual, expected, message, false));
2335+
}
2336+
}
2337+
2338+
private static boolean areEqual(float[] actual, float[] expected, float delta) {
2339+
if (actual == expected) {
2340+
return true;
2341+
}
2342+
if (actual == null || expected == null || actual.length != expected.length) {
2343+
return false;
2344+
}
2345+
for (int i = 0; i < expected.length; i++) {
2346+
if (!areEqual(actual[i], expected[i], delta)) {
2347+
return false;
2348+
}
2349+
}
2350+
return true;
2351+
}
2352+
2353+
/**
2354+
* Asserts that two double arrays are not equal within the given delta. If they are equal, an
2355+
* AssertionError is thrown.
2356+
*
2357+
* @param actual the actual value
2358+
* @param expected the expected value
2359+
* @param delta the absolute tolerable difference between the actual and expected values
2360+
*/
2361+
public static void assertNotEquals(double[] actual, double[] expected, double delta) {
2362+
assertNotEquals(actual, expected, delta, null);
2363+
}
2364+
2365+
/**
2366+
* Asserts that two double arrays are not equal within the given delta. If they are equal, an
2367+
* AssertionError, with the given message, is thrown.
2368+
*
2369+
* @param actual the actual value
2370+
* @param expected the expected value
2371+
* @param delta the absolute tolerable difference between the actual and expected values
2372+
* @param message the assertion error message
2373+
*/
2374+
public static void assertNotEquals(
2375+
double[] actual, double[] expected, double delta, String message) {
2376+
if (areEqual(actual, expected, delta)) {
2377+
Assert.fail(format(actual, expected, message, false));
2378+
}
2379+
}
2380+
2381+
private static boolean areEqual(double[] actual, double[] expected, double delta) {
2382+
if (actual == expected) {
2383+
return true;
2384+
}
2385+
if (actual == null || expected == null || actual.length != expected.length) {
2386+
return false;
2387+
}
2388+
for (int i = 0; i < expected.length; i++) {
2389+
if (!areEqual(actual[i], expected[i], delta)) {
2390+
return false;
2391+
}
2392+
}
2393+
return true;
2394+
}
2395+
23072396
public static void assertNotEquals(Set<?> actual, Set<?> expected) {
23082397
assertNotEquals(actual, expected, null);
23092398
}

src/test/java/org/testng/AssertTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,10 @@ public void testAssertEqualsWithNull() {
349349
}
350350

351351
@Test(
352-
description = "GITHUB-1935",
352+
description = "GITHUB-1935, GITHUB-18",
353353
expectedExceptions = AssertionError.class,
354-
expectedExceptionsMessageRegExp = "expected \\[y\\] but found \\[x\\]")
354+
// String equality now delegates to AssertJ, which produces a readable diff (GITHUB-18).
355+
expectedExceptionsMessageRegExp = "[\\s\\S]*expected: \"y\"[\\s\\S]*but was: \"x\"[\\s\\S]*")
355356
public void testInequalityMessage() {
356357
Assert.assertEquals("x", "y");
357358
}

src/test/java/test/asserttests/AssertTest.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,79 @@ protected void assertMapsNotEqual(Map m1, Map m2) {
640640
assertNotEquals((Object) m1, (Object) m2);
641641
assertNotEquals(m1, m2);
642642
}
643+
644+
@Test(
645+
description = "GITHUB-11",
646+
expectedExceptions = AssertionError.class)
647+
public void assertNotEqualsFloatArrayWithinDeltaFails() {
648+
assertNotEquals(new float[] {1.0f, 2.0f}, new float[] {1.05f, 2.0f}, 0.1f);
649+
}
650+
651+
@Test(description = "GITHUB-11")
652+
public void assertNotEqualsFloatArrayOutsideDeltaPasses() {
653+
assertNotEquals(new float[] {1.0f, 2.0f}, new float[] {1.5f, 2.0f}, 0.1f);
654+
}
655+
656+
@Test(description = "GITHUB-11")
657+
public void assertNotEqualsFloatArrayDifferentLengthPasses() {
658+
assertNotEquals(new float[] {1.0f}, new float[] {1.0f, 2.0f}, 0.1f);
659+
}
660+
661+
@Test(
662+
description = "GITHUB-11",
663+
expectedExceptions = AssertionError.class)
664+
public void assertNotEqualsDoubleArrayWithinDeltaFails() {
665+
assertNotEquals(new double[] {1.0, 2.0}, new double[] {1.05, 2.0}, 0.1);
666+
}
667+
668+
@Test(description = "GITHUB-11")
669+
public void assertNotEqualsDoubleArrayOutsideDeltaPasses() {
670+
assertNotEquals(new double[] {1.0, 2.0}, new double[] {1.5, 2.0}, 0.1);
671+
}
672+
673+
@Test(description = "GITHUB-14")
674+
public void assertNotEqualsListVsSetSameContentFails() {
675+
Collection<String> list = List.of("a", "b", "c");
676+
Collection<String> set = new LinkedHashSet<>(list);
677+
// assertEquals passes for these (same size + order); a failure here is a real regression, not
678+
// swallowed by the expected AssertionError of the assertNotEquals under test.
679+
assertEquals(list, set);
680+
// assertNotEquals must be the exact inverse of assertEquals, so it must throw here.
681+
assertThrows(AssertionError.class, () -> assertNotEquals(list, set));
682+
}
683+
684+
@Test(description = "GITHUB-18")
685+
public void assertEqualsStringShowsDiff() {
686+
try {
687+
assertEquals("Root", "Not Root", "Transform JSON");
688+
fail("should have thrown");
689+
} catch (AssertionError e) {
690+
assertTrue(e.getMessage().contains("Transform JSON"), e.getMessage());
691+
assertTrue(e.getMessage().contains("Not Root"), e.getMessage());
692+
}
693+
}
694+
695+
@Test(description = "GITHUB-8")
696+
public void assertThrowsCoversAssertException() {
697+
assertThrows(NullPointerException.class, () -> {
698+
throw new NullPointerException();
699+
});
700+
IllegalStateException ex =
701+
expectThrows(
702+
IllegalStateException.class,
703+
() -> {
704+
throw new IllegalStateException("boom");
705+
});
706+
assertEquals(ex.getMessage(), "boom");
707+
}
708+
709+
@Test(description = "GITHUB-10")
710+
public void assertSameMessageIsExplicit() {
711+
try {
712+
assertSame(new String("foo"), "foo");
713+
fail("should have thrown");
714+
} catch (AssertionError e) {
715+
assertTrue(e.getMessage().contains("same"), e.getMessage());
716+
}
717+
}
643718
}

0 commit comments

Comments
 (0)