fix: handle JUnit 4 message-first assertEquals type inference

The type inference for assertEquals always used the first argument, but
JUnit 4's 3-arg overload is assertEquals(message, expected, actual).
When the first arg was a string message, the type was incorrectly inferred
as String instead of the actual expected value's type. Now detects the
message-first pattern and uses the second argument for type inference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mohamed Ashraf 2026-03-03 19:29:39 +00:00
parent 77b545c802
commit cda56d1389
2 changed files with 56 additions and 4 deletions

View file

@ -954,11 +954,16 @@ class JavaAssertTransformer:
if not first_arg:
return "Object"
# assertEquals has (expected, actual) or (expected, actual, message/delta)
# Some overloads have (message, expected, actual) in JUnit 4 but JUnit 5 uses (expected, actual[, message])
# Try the first argument as the expected value
expected = first_arg.strip()
# JUnit 4 has assertEquals(String message, expected, actual) where the first arg is a message.
# If the first arg is a string literal, check if there are 3+ args — if so, the real expected
# value is the second argument, not the message string.
if expected.startswith('"') and method in ("assertEquals", "assertNotEquals"):
all_args = self._split_top_level_args(args_str)
if len(all_args) >= 3:
expected = all_args[1].strip()
return self._type_from_literal(expected)
def _type_from_literal(self, value: str) -> str:

View file

@ -769,11 +769,58 @@ public void testFibonacci() {
expected = """\
@Test
public void testFibonacci() {
String _cf_result1 = calculator.fibonacci(10);
int _cf_result1 = calculator.fibonacci(10);
}"""
result = transform_java_assertions(source, "fibonacci")
assert result == expected
def test_junit4_message_first_with_string_expected(self):
"""When assertEquals has 3 args and the first is a message but the second is also a string,
the type should be inferred from the second arg (the real expected value), not the message."""
source = """\
@Test
public void testGetName() {
assertEquals("Name should match", "Alice", user.getName());
}"""
expected = """\
@Test
public void testGetName() {
String _cf_result1 = user.getName();
}"""
result = transform_java_assertions(source, "getName")
assert result == expected
def test_junit4_message_first_with_boolean_expected(self):
"""JUnit 4 assertEquals with message, boolean expected, and actual."""
source = """\
@Test
public void testIsValid() {
assertEquals("Should be true", true, validator.isValid(input));
}"""
expected = """\
@Test
public void testIsValid() {
boolean _cf_result1 = validator.isValid(input);
}"""
result = transform_java_assertions(source, "isValid")
assert result == expected
def test_two_arg_string_expected_not_treated_as_message(self):
"""When assertEquals has only 2 args and the first is a string, it IS the expected value,
not a message. This tests that we don't incorrectly skip the first arg."""
source = """\
@Test
public void testGetGreeting() {
assertEquals("hello", greeter.getGreeting());
}"""
expected = """\
@Test
public void testGetGreeting() {
String _cf_result1 = greeter.getGreeting();
}"""
result = transform_java_assertions(source, "getGreeting")
assert result == expected
class TestAssertAll:
"""Tests for assertAll grouped assertions."""