Skip to content

Skip assertEquals/assertNotEquals conversion when equals() argument is null - #1

Open
mattdepaula wants to merge 3 commits into
mainfrom
fix/assert-false-true-equals-null-contract
Open

Skip assertEquals/assertNotEquals conversion when equals() argument is null#1
mattdepaula wants to merge 3 commits into
mainfrom
fix/assert-false-true-equals-null-contract

Conversation

@mattdepaula

@mattdepaula mattdepaula commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

AssertFalseEqualsToAssertNotEquals and AssertTrueEqualsToAssertEquals both rewrite assertFalse(a.equals(b)) / assertTrue(a.equals(b)) to assertNotEquals(a, b) / assertEquals(a, b). When the argument to .equals() is a null literal this rewrite silently changes semantics:

  • Before: assertFalse(a.equals(null)) — calls a.equals(null), exercising the null-contract of equals()
  • After: assertNotEquals(a, null) — JUnit's internal objectsAreEqual(a, null) short-circuits to a == null via reference equality, never calling a.equals(null)

The fix adds an early-exit guard in isEquals() using the idiomatic J.Literal.isLiteralValue(arg, null) check (consistent with AssertFalseNullToAssertNotNull, AssertTrueNullToAssertNull, and others in the same package).

Upstream issue

openrewrite#1072

Changes

  • AssertFalseEqualsToAssertNotEquals: isEquals() returns false when the argument to .equals() is a null literal
  • AssertTrueEqualsToAssertEquals: same fix
  • Both test files: new doNotConvertWhenArgumentToEqualsIsNull test asserting no change for assertFalse(a.equals(null)) / assertTrue(a.equals(null))

Test plan

  • AssertFalseEqualToAssertNotEqualsTest#doNotConvertWhenArgumentToEqualsIsNull — new, asserts no rewrite
  • AssertTrueEqualsToAssertEqualsTest#doNotConvertWhenArgumentToEqualsIsNull — new, asserts no rewrite
  • All pre-existing tests in both test classes continue to pass

…s null

AssertFalseEqualsToAssertNotEquals and AssertTrueEqualsToAssertEquals were
converting assertFalse(a.equals(null)) and assertTrue(a.equals(null)) to
assertNotEquals(a, null) / assertEquals(a, null). AssertionsArgumentOrder then
hoisted null to the expected position, producing assertNotEquals(null, a).

Assertions.objectsAreEqual short-circuits on a null first argument, returning
a == null without ever invoking a.equals(null). This silently disabled the
null-contract test for custom equals() implementations.

Fix: return false from isEquals() when the argument to .equals() is a null
literal, leaving the original assertion unchanged.

Fixes openrewrite#1071
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant