"""Tests for Java assertion removal transformer.

This test suite covers the transformation of Java test assertions into
regression test code that captures function return values.

All tests assert for full string equality, no substring matching.
"""

from pathlib import Path

from codeflash.discovery.functions_to_optimize import FunctionToOptimize
from codeflash.languages.java.remove_asserts import JavaAssertTransformer, transform_java_assertions


class TestBasicJUnit5Assertions:
    """Tests for basic JUnit 5 assertion transformations."""

    def test_assert_equals_basic(self):
        source = """\
@Test
void testFibonacci() {
    assertEquals(55, calculator.fibonacci(10));
}"""
        expected = """\
@Test
void testFibonacci() {
    int _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_equals_with_message(self):
        source = """\
@Test
void testFibonacci() {
    assertEquals(55, calculator.fibonacci(10), "Fibonacci of 10 should be 55");
}"""
        expected = """\
@Test
void testFibonacci() {
    int _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_true(self):
        source = """\
@Test
void testIsValid() {
    assertTrue(validator.isValid("test"));
}"""
        expected = """\
@Test
void testIsValid() {
    boolean _cf_result1 = validator.isValid("test");
}"""
        result = transform_java_assertions(source, "isValid")
        assert result == expected

    def test_assert_false(self):
        source = """\
@Test
void testIsInvalid() {
    assertFalse(validator.isValid(""));
}"""
        expected = """\
@Test
void testIsInvalid() {
    boolean _cf_result1 = validator.isValid("");
}"""
        result = transform_java_assertions(source, "isValid")
        assert result == expected

    def test_assert_null(self):
        source = """\
@Test
void testGetNull() {
    assertNull(processor.getValue(null));
}"""
        expected = """\
@Test
void testGetNull() {
    Object _cf_result1 = processor.getValue(null);
}"""
        result = transform_java_assertions(source, "getValue")
        assert result == expected

    def test_assert_not_null(self):
        source = """\
@Test
void testGetValue() {
    assertNotNull(processor.getValue("key"));
}"""
        expected = """\
@Test
void testGetValue() {
    Object _cf_result1 = processor.getValue("key");
}"""
        result = transform_java_assertions(source, "getValue")
        assert result == expected

    def test_assert_not_equals(self):
        source = """\
@Test
void testDifferent() {
    assertNotEquals(0, calculator.add(1, 2));
}"""
        expected = """\
@Test
void testDifferent() {
    int _cf_result1 = calculator.add(1, 2);
}"""
        result = transform_java_assertions(source, "add")
        assert result == expected

    def test_assert_same(self):
        source = """\
@Test
void testSame() {
    assertSame(expected, factory.getInstance());
}"""
        expected = """\
@Test
void testSame() {
    Object _cf_result1 = factory.getInstance();
}"""
        result = transform_java_assertions(source, "getInstance")
        assert result == expected

    def test_assert_array_equals(self):
        source = """\
@Test
void testSort() {
    assertArrayEquals(expected, sorter.sort(input));
}"""
        expected = """\
@Test
void testSort() {
    Object _cf_result1 = sorter.sort(input);
}"""
        result = transform_java_assertions(source, "sort")
        assert result == expected


class TestJUnit5PrefixedAssertions:
    """Tests for JUnit 5 assertions with Assertions. prefix."""

    def test_assertions_prefix(self):
        source = """\
@Test
void testFibonacci() {
    Assertions.assertEquals(55, calculator.fibonacci(10));
}"""
        expected = """\
@Test
void testFibonacci() {
    int _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_prefix(self):
        source = """\
@Test
void testAdd() {
    Assert.assertEquals(5, calculator.add(2, 3));
}"""
        expected = """\
@Test
void testAdd() {
    int _cf_result1 = calculator.add(2, 3);
}"""
        result = transform_java_assertions(source, "add")
        assert result == expected


class TestJUnit5ExceptionAssertions:
    """Tests for JUnit 5 exception assertions."""

    def test_assert_throws_lambda(self):
        source = """\
@Test
void testDivideByZero() {
    assertThrows(IllegalArgumentException.class, () -> calculator.divide(1, 0));
}"""
        expected = """\
@Test
void testDivideByZero() {
    try { calculator.divide(1, 0); } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected

    def test_assert_throws_block_lambda(self):
        source = """\
@Test
void testDivideByZero() {
    assertThrows(ArithmeticException.class, () -> {
        calculator.divide(1, 0);
    });
}"""
        expected = """\
@Test
void testDivideByZero() {
    try { calculator.divide(1, 0); } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected

    def test_assert_does_not_throw(self):
        source = """\
@Test
void testValidDivision() {
    assertDoesNotThrow(() -> calculator.divide(10, 2));
}"""
        expected = """\
@Test
void testValidDivision() {
    try { calculator.divide(10, 2); } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected


class TestStaticMethodCalls:
    """Tests for static method call handling."""

    def test_static_method_call(self):
        source = """\
@Test
void testQuickAdd() {
    assertEquals(15.0, Calculator.quickAdd(10.0, 5.0));
}"""
        expected = """\
@Test
void testQuickAdd() {
    double _cf_result1 = Calculator.quickAdd(10.0, 5.0);
}"""
        result = transform_java_assertions(source, "quickAdd")
        assert result == expected

    def test_static_method_fully_qualified(self):
        source = """\
@Test
void testReverse() {
    assertEquals("olleh", com.example.StringUtils.reverse("hello"));
}"""
        expected = """\
@Test
void testReverse() {
    String _cf_result1 = com.example.StringUtils.reverse("hello");
}"""
        result = transform_java_assertions(source, "reverse")
        assert result == expected


class TestMultipleAssertions:
    """Tests for multiple assertions in a single test method."""

    def test_multiple_assertions_same_function(self):
        source = """\
@Test
void testFibonacciSequence() {
    assertEquals(0, calculator.fibonacci(0));
    assertEquals(1, calculator.fibonacci(1));
    assertEquals(55, calculator.fibonacci(10));
}"""
        expected = """\
@Test
void testFibonacciSequence() {
    int _cf_result1 = calculator.fibonacci(0);
    int _cf_result2 = calculator.fibonacci(1);
    int _cf_result3 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_multiple_assertions_different_functions(self):
        source = """\
@Test
void testCalculator() {
    assertEquals(5, calculator.add(2, 3));
    assertEquals(6, calculator.multiply(2, 3));
}"""
        expected = """\
@Test
void testCalculator() {
    int _cf_result1 = calculator.add(2, 3);
}"""
        result = transform_java_assertions(source, "add")
        assert result == expected


class TestAssertJFluentAssertions:
    """Tests for AssertJ fluent assertion transformations."""

    def test_assertj_basic(self):
        source = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testFibonacci() {
    assertThat(calculator.fibonacci(10)).isEqualTo(55);
}"""
        expected = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testFibonacci() {
    Object _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assertj_chained(self):
        source = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetList() {
    assertThat(processor.getList()).hasSize(5).contains("a", "b");
}"""
        expected = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetList() {
    Object _cf_result1 = processor.getList();
}"""
        result = transform_java_assertions(source, "getList")
        assert result == expected

    def test_assertj_is_null(self):
        source = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetNull() {
    assertThat(processor.getValue(null)).isNull();
}"""
        expected = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetNull() {
    Object _cf_result1 = processor.getValue(null);
}"""
        result = transform_java_assertions(source, "getValue")
        assert result == expected

    def test_assertj_is_not_empty(self):
        source = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetList() {
    assertThat(processor.getList()).isNotEmpty();
}"""
        expected = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testGetList() {
    Object _cf_result1 = processor.getList();
}"""
        result = transform_java_assertions(source, "getList")
        assert result == expected


class TestNestedMethodCalls:
    """Tests for nested method calls in assertions."""

    def test_nested_call_in_expected(self):
        source = """\
@Test
void testCompare() {
    assertEquals(helper.getExpected(), calculator.compute(5));
}"""
        expected = """\
@Test
void testCompare() {
    Object _cf_result1 = calculator.compute(5);
}"""
        result = transform_java_assertions(source, "compute")
        assert result == expected

    def test_nested_call_as_argument(self):
        source = """\
@Test
void testProcess() {
    assertEquals(expected, processor.process(helper.getData()));
}"""
        expected = """\
@Test
void testProcess() {
    Object _cf_result1 = processor.process(helper.getData());
}"""
        result = transform_java_assertions(source, "process")
        assert result == expected

    def test_deeply_nested(self):
        source = """\
@Test
void testDeep() {
    assertEquals(expected, outer.process(inner.compute(calculator.fibonacci(5))));
}"""
        expected = """\
@Test
void testDeep() {
    Object _cf_result1 = outer.process(inner.compute(calculator.fibonacci(5)));
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_target_nested_in_non_target_call(self):
        source = """\
@Test
void testSubtract() {
    assertEquals(0, add(2, subtract(2, 2)));
}"""
        expected = """\
@Test
void testSubtract() {
    int _cf_result1 = add(2, subtract(2, 2));
}"""
        result = transform_java_assertions(source, "subtract")
        assert result == expected

    def test_non_target_nested_in_target_call(self):
        source = """\
@Test
void testAdd() {
    assertEquals(0, subtract(2, add(2, 3)));
}"""
        expected = """\
@Test
void testAdd() {
    int _cf_result1 = subtract(2, add(2, 3));
}"""
        result = transform_java_assertions(source, "add")
        assert result == expected

    def test_multiple_targets_nested_in_same_outer_call(self):
        source = """\
@Test
void testOuter() {
    assertEquals(0, outer(subtract(1, 1), subtract(2, 2)));
}"""
        expected = """\
@Test
void testOuter() {
    int _cf_result1 = outer(subtract(1, 1), subtract(2, 2));
}"""
        result = transform_java_assertions(source, "subtract")
        assert result == expected


class TestWhitespacePreservation:
    """Tests for whitespace and indentation preservation."""

    def test_preserves_indentation(self):
        source = """\
    @Test
    void testFibonacci() {
        assertEquals(55, calculator.fibonacci(10));
    }"""
        expected = """\
    @Test
    void testFibonacci() {
        int _cf_result1 = calculator.fibonacci(10);
    }"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_multiline_assertion(self):
        source = """\
@Test
void testLongAssertion() {
    assertEquals(
        expectedValue,
        calculator.computeComplexResult(
            arg1,
            arg2,
            arg3
        )
    );
}"""
        expected = """\
@Test
void testLongAssertion() {
    Object _cf_result1 = calculator.computeComplexResult(
            arg1,
            arg2,
            arg3
        );
}"""
        result = transform_java_assertions(source, "computeComplexResult")
        assert result == expected


class TestStringsWithSpecialCharacters:
    """Tests for strings containing special characters."""

    def test_string_with_parentheses(self):
        source = """\
@Test
void testFormat() {
    assertEquals("hello (world)", formatter.format("hello", "world"));
}"""
        expected = """\
@Test
void testFormat() {
    String _cf_result1 = formatter.format("hello", "world");
}"""
        result = transform_java_assertions(source, "format")
        assert result == expected

    def test_string_with_quotes(self):
        source = """\
@Test
void testEscape() {
    assertEquals("hello \\"world\\"", formatter.escape("hello \\"world\\""));
}"""
        expected = """\
@Test
void testEscape() {
    String _cf_result1 = formatter.escape("hello \\"world\\"");
}"""
        result = transform_java_assertions(source, "escape")
        assert result == expected

    def test_string_with_newlines(self):
        source = """\
@Test
void testMultiline() {
    assertEquals("line1\\nline2", processor.join("line1", "line2"));
}"""
        expected = """\
@Test
void testMultiline() {
    String _cf_result1 = processor.join("line1", "line2");
}"""
        result = transform_java_assertions(source, "join")
        assert result == expected


class TestNonAssertionCodePreservation:
    """Tests that non-assertion code is preserved unchanged."""

    def test_setup_code_preserved(self):
        source = """\
@Test
void testWithSetup() {
    Calculator calc = new Calculator(2);
    int input = 10;
    assertEquals(55, calc.fibonacci(input));
}"""
        expected = """\
@Test
void testWithSetup() {
    Calculator calc = new Calculator(2);
    int input = 10;
    int _cf_result1 = calc.fibonacci(input);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_other_method_calls_preserved(self):
        source = """\
@Test
void testWithHelper() {
    helper.setup();
    assertEquals(55, calculator.fibonacci(10));
    helper.cleanup();
}"""
        expected = """\
@Test
void testWithHelper() {
    helper.setup();
    int _cf_result1 = calculator.fibonacci(10);
    helper.cleanup();
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_variable_declarations_preserved(self):
        source = """\
@Test
void testWithVariables() {
    int expected = 55;
    int actual = calculator.fibonacci(10);
    assertEquals(expected, actual);
}"""
        # Variable declarations are preserved, but assertEquals is removed (all assertions removed)
        expected = """\
@Test
void testWithVariables() {
    int expected = 55;
    int actual = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected


class TestParameterizedTests:
    """Tests for parameterized test handling."""

    def test_parameterized_test(self):
        source = """\
@ParameterizedTest
@CsvSource({
    "0, 0",
    "1, 1",
    "10, 55"
})
void testFibonacciSequence(int n, long expected) {
    assertEquals(expected, calculator.fibonacci(n));
}"""
        expected = """\
@ParameterizedTest
@CsvSource({
    "0, 0",
    "1, 1",
    "10, 55"
})
void testFibonacciSequence(int n, long expected) {
    Object _cf_result1 = calculator.fibonacci(n);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected


class TestNestedTestClasses:
    """Tests for nested test class handling."""

    def test_nested_class(self):
        source = """\
@Nested
@DisplayName("Fibonacci Tests")
class FibonacciTests {
    @Test
    void testBasic() {
        assertEquals(55, calculator.fibonacci(10));
    }
}"""
        expected = """\
@Nested
@DisplayName("Fibonacci Tests")
class FibonacciTests {
    @Test
    void testBasic() {
        int _cf_result1 = calculator.fibonacci(10);
    }
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected


class TestMockitoPreservation:
    """Tests that Mockito code is not modified."""

    def test_mockito_when_preserved(self):
        source = """\
@Test
void testWithMock() {
    when(mockService.getData()).thenReturn("test");
    assertEquals("test", processor.process(mockService));
}"""
        expected = """\
@Test
void testWithMock() {
    when(mockService.getData()).thenReturn("test");
    String _cf_result1 = processor.process(mockService);
}"""
        result = transform_java_assertions(source, "process")
        assert result == expected

    def test_mockito_verify_preserved(self):
        source = """\
@Test
void testWithVerify() {
    processor.process(mockService);
    verify(mockService).getData();
}"""
        # No assertions to transform, source unchanged
        expected = source
        result = transform_java_assertions(source, "process")
        assert result == expected


class TestEdgeCases:
    """Tests for edge cases and boundary conditions."""

    def test_empty_source(self):
        result = transform_java_assertions("", "fibonacci")
        assert result == ""

    def test_whitespace_only(self):
        source = "   \n\t  "
        result = transform_java_assertions(source, "fibonacci")
        assert result == source

    def test_no_assertions(self):
        source = """\
@Test
void testNoAssertions() {
    calculator.fibonacci(10);
}"""
        expected = source
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assertion_without_target_function(self):
        source = """\
@Test
void testOther() {
    assertEquals(5, helper.compute(3));
}"""
        # All assertions are removed regardless of target function
        expected = """\
@Test
void testOther() {
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_function_name_in_string(self):
        source = """\
@Test
void testWithStringContainingFunctionName() {
    assertEquals("fibonacci(10) = 55", formatter.format("fibonacci", 10, 55));
}"""
        expected = """\
@Test
void testWithStringContainingFunctionName() {
    String _cf_result1 = formatter.format("fibonacci", 10, 55);
}"""
        result = transform_java_assertions(source, "format")
        assert result == expected


class TestJUnit4Compatibility:
    """Tests for JUnit 4 style assertions."""

    def test_junit4_assert_equals(self):
        source = """\
import static org.junit.Assert.*;

@Test
public void testFibonacci() {
    assertEquals(55, calculator.fibonacci(10));
}"""
        expected = """\
import static org.junit.Assert.*;

@Test
public void testFibonacci() {
    int _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_junit4_with_message_first(self):
        source = """\
@Test
public void testFibonacci() {
    assertEquals("Should be 55", 55, calculator.fibonacci(10));
}"""
        expected = """\
@Test
public void testFibonacci() {
    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."""

    def test_assert_all_basic(self):
        source = """\
@Test
void testMultiple() {
    assertAll(
        () -> assertEquals(0, calculator.fibonacci(0)),
        () -> assertEquals(1, calculator.fibonacci(1)),
        () -> assertEquals(55, calculator.fibonacci(10))
    );
}"""
        expected = """\
@Test
void testMultiple() {
    Object _cf_result1 = calculator.fibonacci(0);
    Object _cf_result2 = calculator.fibonacci(1);
    Object _cf_result3 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected


class TestTransformerClass:
    """Tests for the JavaAssertTransformer class directly."""

    def test_invocation_counter_increments(self):
        transformer = JavaAssertTransformer("fibonacci")
        source = """\
@Test
void test() {
    assertEquals(0, calc.fibonacci(0));
    assertEquals(1, calc.fibonacci(1));
}"""
        expected = """\
@Test
void test() {
    int _cf_result1 = calc.fibonacci(0);
    int _cf_result2 = calc.fibonacci(1);
}"""
        result = transformer.transform(source)
        assert result == expected
        assert transformer.invocation_counter == 2

    def test_qualified_name_support(self):
        transformer = JavaAssertTransformer(
            function_name="fibonacci", qualified_name="com.example.Calculator.fibonacci"
        )
        assert transformer.qualified_name == "com.example.Calculator.fibonacci"

    def test_custom_analyzer(self):
        from codeflash.languages.java.parser import get_java_analyzer

        analyzer = get_java_analyzer()
        transformer = JavaAssertTransformer("fibonacci", analyzer=analyzer)
        assert transformer.analyzer is analyzer


class TestImportDetection:
    """Tests for framework detection from imports."""

    def test_detect_junit5(self):
        source = """\
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;"""
        transformer = JavaAssertTransformer("test")
        transformer._detected_framework = transformer._detect_framework(source)
        assert transformer._detected_framework == "junit5"

    def test_detect_assertj(self):
        source = """\
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;"""
        transformer = JavaAssertTransformer("test")
        transformer._detected_framework = transformer._detect_framework(source)
        assert transformer._detected_framework == "assertj"

    def test_detect_testng(self):
        source = """\
import org.testng.Assert;
import org.testng.annotations.Test;"""
        transformer = JavaAssertTransformer("test")
        transformer._detected_framework = transformer._detect_framework(source)
        assert transformer._detected_framework == "testng"

    def test_detect_hamcrest(self):
        source = """\
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;"""
        transformer = JavaAssertTransformer("test")
        transformer._detected_framework = transformer._detect_framework(source)
        assert transformer._detected_framework == "hamcrest"


class TestInstrumentGeneratedJavaTest:
    """Tests for the instrument_generated_java_test integration."""

    def test_behavior_mode_removes_assertions(self):
        from codeflash.languages.java.instrumentation import instrument_generated_java_test

        test_code = """\
package com.example;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class FibonacciTest {
    @Test
    void testFibonacci() {
        Calculator calc = new Calculator();
        assertEquals(55, calc.fibonacci(10));
    }
}"""
        func = FunctionToOptimize(
            function_name="fibonacci",
            file_path=Path("Calculator.java"),
            starting_line=1,
            ending_line=5,
            parents=[],
            is_method=True,
            language="java",
        )
        result = instrument_generated_java_test(
            test_code=test_code,
            function_name="fibonacci",
            qualified_name="com.example.Calculator.fibonacci",
            mode="behavior",
            function_to_optimize=func,
        )
        # Behavior mode now adds full instrumentation
        assert "FibonacciTest__perfinstrumented" in result
        assert "_cf_result" in result
        assert "com.codeflash.Serializer.serialize" in result

    def test_behavior_mode_with_assertj(self):
        from codeflash.languages.java.instrumentation import instrument_generated_java_test

        test_code = """\
package com.example;

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class StringUtilsTest {
    @Test
    void testReverse() {
        assertThat(StringUtils.reverse("hello")).isEqualTo("olleh");
    }
}"""
        func = FunctionToOptimize(
            function_name="reverse",
            file_path=Path("StringUtils.java"),
            starting_line=1,
            ending_line=5,
            parents=[],
            is_method=True,
            language="java",
        )
        result = instrument_generated_java_test(
            test_code=test_code,
            function_name="reverse",
            qualified_name="com.example.StringUtils.reverse",
            mode="behavior",
            function_to_optimize=func,
        )
        # Behavior mode now adds full instrumentation
        assert "StringUtilsTest__perfinstrumented" in result
        assert "_cf_result" in result
        assert "com.codeflash.Serializer.serialize" in result


class TestComplexRealWorldExamples:
    """Tests based on real-world test patterns."""

    def test_calculator_test_pattern(self):
        source = """\
@Test
@DisplayName("should calculate compound interest for basic case")
void testBasicCompoundInterest() {
    String result = calculator.calculateCompoundInterest(1000.0, 0.05, 1, 12);
    assertNotNull(result);
    assertTrue(result.contains("."));
}"""
        # All assertions are removed; variable assignment is preserved
        expected = """\
@Test
@DisplayName("should calculate compound interest for basic case")
void testBasicCompoundInterest() {
    String result = calculator.calculateCompoundInterest(1000.0, 0.05, 1, 12);
}"""
        result = transform_java_assertions(source, "calculateCompoundInterest")
        assert result == expected

    def test_string_utils_pattern(self):
        source = """\
@Test
@DisplayName("should reverse a simple string")
void testReverseSimple() {
    assertEquals("olleh", StringUtils.reverse("hello"));
    assertEquals("dlrow", StringUtils.reverse("world"));
}"""
        expected = """\
@Test
@DisplayName("should reverse a simple string")
void testReverseSimple() {
    String _cf_result1 = StringUtils.reverse("hello");
    String _cf_result2 = StringUtils.reverse("world");
}"""
        result = transform_java_assertions(source, "reverse")
        assert result == expected

    def test_with_before_each_setup(self):
        source = """\
private Calculator calculator;

@BeforeEach
void setUp() {
    calculator = new Calculator(2);
}

@Test
void testFibonacci() {
    assertEquals(55, calculator.fibonacci(10));
}"""
        expected = """\
private Calculator calculator;

@BeforeEach
void setUp() {
    calculator = new Calculator(2);
}

@Test
void testFibonacci() {
    int _cf_result1 = calculator.fibonacci(10);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected


class TestConcurrencyPatterns:
    """Tests that assertion removal correctly handles Java concurrency constructs.

    Validates that synchronized blocks, volatile field access, atomic operations,
    concurrent collections, Thread.sleep, wait/notify, and synchronized method
    modifiers are all preserved verbatim after assertion transformation.
    """

    def test_synchronized_method_assertion_removal(self):
        """Assertion inside synchronized block is transformed; synchronized wrapper preserved."""
        source = """\
@Test
void testSynchronizedAccess() {
    synchronized (lock) {
        assertEquals(42, counter.incrementAndGet());
    }
}"""
        expected = """\
@Test
void testSynchronizedAccess() {
    synchronized (lock) {
        int _cf_result1 = counter.incrementAndGet();
    }
}"""
        result = transform_java_assertions(source, "incrementAndGet")
        assert result == expected

    def test_volatile_field_read_preserved(self):
        """Assertion wrapping a volatile field reader is transformed; method call preserved."""
        source = """\
@Test
void testVolatileRead() {
    assertTrue(buffer.isReady());
}"""
        expected = """\
@Test
void testVolatileRead() {
    boolean _cf_result1 = buffer.isReady();
}"""
        result = transform_java_assertions(source, "isReady")
        assert result == expected

    def test_synchronized_block_with_multiple_assertions(self):
        """Multiple assertions inside a synchronized block are all transformed."""
        source = """\
@Test
void testSynchronizedBlock() {
    synchronized (cache) {
        assertEquals(1, cache.size());
        assertNotNull(cache.get("key"));
        assertTrue(cache.containsKey("key"));
    }
}"""
        # All assertions are removed; target-containing ones get Object capture
        expected = """\
@Test
void testSynchronizedBlock() {
    synchronized (cache) {
        int _cf_result1 = cache.size();
    }
}"""
        result = transform_java_assertions(source, "size")
        assert result == expected

    def test_synchronized_block_multiple_assertions_same_target(self):
        """Multiple assertions in synchronized block targeting the same function."""
        source = """\
@Test
void testSynchronizedBlock() {
    synchronized (cache) {
        assertNotNull(cache.get("key1"));
        assertNotNull(cache.get("key2"));
    }
}"""
        expected = """\
@Test
void testSynchronizedBlock() {
    synchronized (cache) {
        Object _cf_result1 = cache.get("key1");
        Object _cf_result2 = cache.get("key2");
    }
}"""
        result = transform_java_assertions(source, "get")
        assert result == expected

    def test_atomic_operations_preserved(self):
        """Atomic operations (incrementAndGet) are preserved as Object capture calls."""
        source = """\
@Test
void testAtomicCounter() {
    assertEquals(1, counter.incrementAndGet());
    assertEquals(2, counter.incrementAndGet());
}"""
        expected = """\
@Test
void testAtomicCounter() {
    int _cf_result1 = counter.incrementAndGet();
    int _cf_result2 = counter.incrementAndGet();
}"""
        result = transform_java_assertions(source, "incrementAndGet")
        assert result == expected

    def test_concurrent_collection_assertion(self):
        """ConcurrentHashMap putIfAbsent call is preserved in assertion transformation."""
        source = """\
@Test
void testConcurrentMap() {
    assertEquals("value", concurrentMap.putIfAbsent("key", "value"));
}"""
        expected = """\
@Test
void testConcurrentMap() {
    String _cf_result1 = concurrentMap.putIfAbsent("key", "value");
}"""
        result = transform_java_assertions(source, "putIfAbsent")
        assert result == expected

    def test_thread_sleep_with_assertion(self):
        """Thread.sleep() before assertion is preserved verbatim."""
        source = """\
@Test
void testWithThreadSleep() throws InterruptedException {
    Thread.sleep(100);
    assertEquals(42, processor.getResult());
}"""
        expected = """\
@Test
void testWithThreadSleep() throws InterruptedException {
    Thread.sleep(100);
    int _cf_result1 = processor.getResult();
}"""
        result = transform_java_assertions(source, "getResult")
        assert result == expected

    def test_synchronized_method_signature_preserved(self):
        """Synchronized modifier on a test method is preserved after transformation."""
        source = """\
@Test
synchronized void testSyncMethod() {
    assertEquals(10, calculator.compute(5));
}"""
        expected = """\
@Test
synchronized void testSyncMethod() {
    int _cf_result1 = calculator.compute(5);
}"""
        result = transform_java_assertions(source, "compute")
        assert result == expected

    def test_wait_notify_pattern_preserved(self):
        """wait/notify pattern around an assertion is preserved."""
        source = """\
@Test
void testWaitNotify() {
    synchronized (monitor) {
        monitor.notify();
    }
    assertTrue(listener.wasNotified());
}"""
        expected = """\
@Test
void testWaitNotify() {
    synchronized (monitor) {
        monitor.notify();
    }
    boolean _cf_result1 = listener.wasNotified();
}"""
        result = transform_java_assertions(source, "wasNotified")
        assert result == expected

    def test_reentrant_lock_pattern_preserved(self):
        """ReentrantLock acquire/release around assertion is preserved."""
        source = """\
@Test
void testReentrantLock() {
    lock.lock();
    try {
        assertEquals(99, sharedResource.getValue());
    } finally {
        lock.unlock();
    }
}"""
        expected = """\
@Test
void testReentrantLock() {
    lock.lock();
    try {
        int _cf_result1 = sharedResource.getValue();
    } finally {
        lock.unlock();
    }
}"""
        result = transform_java_assertions(source, "getValue")
        assert result == expected

    def test_count_down_latch_pattern_preserved(self):
        """CountDownLatch await/countDown around assertion is preserved."""
        source = """\
@Test
void testCountDownLatch() throws InterruptedException {
    latch.countDown();
    latch.await();
    assertEquals(42, collector.getTotal());
}"""
        expected = """\
@Test
void testCountDownLatch() throws InterruptedException {
    latch.countDown();
    latch.await();
    int _cf_result1 = collector.getTotal();
}"""
        result = transform_java_assertions(source, "getTotal")
        assert result == expected

    def test_token_bucket_synchronized_method(self):
        """Real pattern: synchronized method call (like TokenBucket.allowRequest) inside assertion."""
        source = """\
@Test
void testTokenBucketAllowRequest() {
    TokenBucket bucket = new TokenBucket(10, 1);
    assertTrue(bucket.allowRequest());
    assertTrue(bucket.allowRequest());
}"""
        expected = """\
@Test
void testTokenBucketAllowRequest() {
    TokenBucket bucket = new TokenBucket(10, 1);
    boolean _cf_result1 = bucket.allowRequest();
    boolean _cf_result2 = bucket.allowRequest();
}"""
        result = transform_java_assertions(source, "allowRequest")
        assert result == expected

    def test_circular_buffer_atomic_integer_pattern(self):
        """Real pattern: CircularBuffer with AtomicInteger-backed isEmpty/isFull assertions."""
        source = """\
@Test
void testCircularBufferOperations() {
    CircularBuffer<Integer> buffer = new CircularBuffer<>(3);
    assertTrue(buffer.isEmpty());
    buffer.put(1);
    assertFalse(buffer.isEmpty());
    assertTrue(buffer.put(2));
}"""
        # All assertions are removed; target-containing ones get Object capture,
        # non-target assertions (assertTrue(buffer.put(2))) are deleted entirely
        expected = """\
@Test
void testCircularBufferOperations() {
    CircularBuffer<Integer> buffer = new CircularBuffer<>(3);
    boolean _cf_result1 = buffer.isEmpty();
    buffer.put(1);
    boolean _cf_result2 = buffer.isEmpty();
}"""
        result = transform_java_assertions(source, "isEmpty")
        assert result == expected

    def test_concurrent_assertion_with_assertj(self):
        """AssertJ assertion on a synchronized method call is correctly transformed."""
        source = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testSynchronizedMethodWithAssertJ() {
    synchronized (lock) {
        assertThat(counter.incrementAndGet()).isEqualTo(1);
    }
}"""
        expected = """\
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testSynchronizedMethodWithAssertJ() {
    synchronized (lock) {
        Object _cf_result1 = counter.incrementAndGet();
    }
}"""
        result = transform_java_assertions(source, "incrementAndGet")
        assert result == expected


class TestFullyQualifiedAssertions:
    """Tests for fully qualified assertion calls like org.junit.jupiter.api.Assertions.assertXxx."""

    def test_assert_timeout_fully_qualified_with_variable_assignment(self):
        source = """\
@Test
void testLargeInput() {
    Long result = org.junit.jupiter.api.Assertions.assertTimeout(
            Duration.ofSeconds(1),
            () -> Fibonacci.fibonacci(100_000)
    );
}"""
        expected = """\
@Test
void testLargeInput() {
    Object _cf_result1 = Fibonacci.fibonacci(100_000);
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_equals_fully_qualified(self):
        source = """\
@Test
void testAdd() {
    org.junit.jupiter.api.Assertions.assertEquals(5, calc.add(2, 3));
}"""
        expected = """\
@Test
void testAdd() {
    int _cf_result1 = calc.add(2, 3);
}"""
        result = transform_java_assertions(source, "add")
        assert result == expected


class TestAssertThrowsVariableAssignment:
    """Tests for assertThrows with variable assignment (Issue: exception handling instrumentation bug)."""

    def test_assert_throws_with_variable_assignment_expression_lambda(self):
        """Test assertThrows assigned to variable with expression lambda."""
        source = """\
@Test
void testNegativeInput() {
    IllegalArgumentException exception = assertThrows(
        IllegalArgumentException.class,
        () -> calculator.fibonacci(-1)
    );
    assertEquals("Negative input not allowed", exception.getMessage());
}"""
        # assertThrows becomes try/catch, and assertEquals after it is also removed
        expected = """\
@Test
void testNegativeInput() {
    IllegalArgumentException exception = null;
    try { calculator.fibonacci(-1); } catch (IllegalArgumentException _cf_caught1) { exception = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_throws_with_variable_assignment_block_lambda(self):
        """Test assertThrows assigned to variable with block lambda."""
        source = """\
@Test
void testInvalidOperation() {
    ArithmeticException ex = assertThrows(ArithmeticException.class, () -> {
        calculator.divide(10, 0);
    });
    assertEquals("Division by zero", ex.getMessage());
}"""
        # assertThrows becomes try/catch, and assertEquals after it is also removed
        expected = """\
@Test
void testInvalidOperation() {
    ArithmeticException ex = null;
    try { calculator.divide(10, 0); } catch (ArithmeticException _cf_caught1) { ex = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected

    def test_assert_throws_with_variable_assignment_generic_exception(self):
        """Test assertThrows with generic Exception type."""
        source = """\
@Test
void testGenericException() {
    Exception e = assertThrows(Exception.class, () -> processor.process(null));
    assertNotNull(e.getMessage());
}"""
        # assertThrows becomes try/catch, and assertNotNull after it is also removed
        expected = """\
@Test
void testGenericException() {
    Exception e = null;
    try { processor.process(null); } catch (Exception _cf_caught1) { e = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "process")
        assert result == expected

    def test_assert_throws_without_variable_assignment(self):
        """Test assertThrows without variable assignment still works (no regression)."""
        source = """\
@Test
void testThrowsException() {
    assertThrows(IllegalArgumentException.class, () -> calculator.fibonacci(-1));
}"""
        expected = """\
@Test
void testThrowsException() {
    try { calculator.fibonacci(-1); } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "fibonacci")
        assert result == expected

    def test_assert_throws_with_variable_and_multi_line_lambda(self):
        """Test assertThrows with variable assignment and multi-line lambda."""
        source = """\
@Test
void testComplexException() {
    IllegalStateException exception = assertThrows(
        IllegalStateException.class,
        () -> {
            processor.initialize();
            processor.execute();
        }
    );
    assertTrue(exception.getMessage().contains("not initialized"));
}"""
        # assertThrows becomes try/catch, and assertTrue after it is also removed
        expected = """\
@Test
void testComplexException() {
    IllegalStateException exception = null;
    try { processor.initialize();
            processor.execute(); } catch (IllegalStateException _cf_caught1) { exception = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "execute")
        assert result == expected

    def test_assert_throws_assigned_with_final_modifier(self):
        """Test assertThrows with final modifier on variable."""
        source = """\
@Test
void testDivideByZero() {
    final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> calc.divide(1, 0));
}"""
        expected = """\
@Test
void testDivideByZero() {
    IllegalArgumentException ex = null;
    try { calc.divide(1, 0); } catch (IllegalArgumentException _cf_caught1) { ex = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected

    def test_assert_throws_assigned_with_qualified_assertions(self):
        """Test assertThrows with qualified assertion (Assertions.assertThrows)."""
        source = """\
@Test
void testDivideByZero() {
    IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> calc.divide(1, 0));
}"""
        expected = """\
@Test
void testDivideByZero() {
    IllegalArgumentException ex = null;
    try { calc.divide(1, 0); } catch (IllegalArgumentException _cf_caught1) { ex = _cf_caught1; } catch (Exception _cf_ignored1) {}
}"""
        result = transform_java_assertions(source, "divide")
        assert result == expected
