Repository: assertj/assertj (Java)

Issue:
`returns` and `doesNotReturn` should invoke `isNotNull` internally
**Describe the bug**
The `AbstractObjectAssert#returns(...)` method should assert that the initial `actual` value is not `null`. Instead, it directly applies the `from` function, which then almost always throws a NullPointerException.

Compatibility consideration: 
While one could contrive a scenario where the `from` function can handle `null` values (e.g., `assertThat((Object)null).returns(true, from(java.util.Objects::isNull))`), I cannot think of a real-world use case where any further checks on a `null` `actual` value would provide any benefit.

* assertj core version: 3.24.2
* java version: 11
* test framework version: -
* os (if relevant): -

**Test case reproducing the bug**

The following code should throw an AssertionError instead of a NullPointerException.

```java
assertThat((Object)null).returns(null, from(Object::toString));
```



Hints:
I agree we should guard `returns` and `doesNotReturn` with an `isNotNull` call.

Patch:
diff --git a/assertj-core/src/main/java/org/assertj/core/api/AbstractObjectAssert.java b/assertj-core/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
--- a/assertj-core/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
+++ b/assertj-core/src/main/java/org/assertj/core/api/AbstractObjectAssert.java
@@ -1102,6 +1102,7 @@ public SELF isEqualToComparingFieldByFieldRecursively(Object other) {
    */
   public <T> SELF returns(T expected, Function<ACTUAL, T> from) {
     requireNonNull(from, "The given getter method/Function must not be null");
+    isNotNull();
     Objects objects = getComparatorBasedObjectAssertions(expected);
     objects.assertEqual(info, from.apply(actual), expected);
     return myself;
@@ -1132,6 +1133,7 @@ public <T> SELF returns(T expected, Function<ACTUAL, T> from) {
    */
   public <T> SELF doesNotReturn(T expected, Function<ACTUAL, T> from) {
     requireNonNull(from, "The given getter method/Function must not be null");
+    isNotNull();
     Objects objects = getComparatorBasedObjectAssertions(expected);
     objects.assertNotEqual(info, from.apply(actual), expected);
     return myself;


Test patch:
diff --git a/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java b/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java
--- a/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java
+++ b/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java
@@ -19,63 +19,63 @@
 import static org.assertj.core.api.BDDAssertions.then;
 import static org.assertj.core.error.ShouldNotBeEqual.shouldNotBeEqual;
 import static org.assertj.core.util.AssertionsUtil.expectAssertionError;
-import static org.mockito.Mockito.verify;
+import static org.assertj.core.util.FailureMessages.actualIsNull;
 
-import org.assertj.core.api.ObjectAssert;
-import org.assertj.core.api.ObjectAssertBaseTest;
 import org.assertj.core.internal.ComparatorBasedComparisonStrategy;
 import org.assertj.core.test.Jedi;
 import org.junit.jupiter.api.Test;
 
-class ObjectAssert_doesNotReturn_Test extends ObjectAssertBaseTest {
+class ObjectAssert_doesNotReturn_Test {
 
-  @Override
-  protected ObjectAssert<Jedi> invoke_api_method() {
-    return assertions.doesNotReturn("Yoda", Jedi::getName);
-  }
-
-  @Override
-  protected void verify_internal_effects() {
-    verify(objects).assertNotEqual(getInfo(assertions), getActual(assertions).getName(), "Yoda");
+  @Test
+  void should_fail_if_actual_is_null() {
+    // GIVEN
+    Jedi actual = null;
+    // WHEN
+    AssertionError assertionError = expectAssertionError(() -> assertThat(actual).doesNotReturn("Yoda", from(Jedi::getName)));
+    // THEN
+    then(assertionError).hasMessage(actualIsNull());
   }
 
   @Test
-  void should_fail_with_throwing_NullPointerException_if_method_is_null() {
+  void should_fail_if_from_is_null() {
+    // GIVEN
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN
-    Throwable thrown = catchThrowable(() -> assertions.doesNotReturn("May the force be with you.", null));
+    Throwable thrown = catchThrowable(() -> assertThat(actual).doesNotReturn("Yoda", null));
     // THEN
     then(thrown).isInstanceOf(NullPointerException.class)
                 .hasMessage("The given getter method/Function must not be null");
   }
 
   @Test
-  void perform_assertion_like_users() {
+  void should_pass() {
     // GIVEN
-    Jedi yoda = new Jedi("Yoda", "Green");
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN/THEN
-    assertThat(yoda).doesNotReturn("Luke", from(Jedi::getName))
-                    .doesNotReturn("Luke", Jedi::getName);
+    assertThat(actual).doesNotReturn("Luke", from(Jedi::getName))
+                      .doesNotReturn("Luke", Jedi::getName);
+  }
+
+  @Test
+  void should_pass_if_expected_is_null() {
+    // GIVEN
+    Jedi actual = new Jedi("Yoda", "Green");
+    // WHEN/THEN
+    assertThat(actual).doesNotReturn(null, from(Jedi::getName));
   }
 
   @Test
   void should_honor_custom_type_comparator() {
     // GIVEN
-    Jedi yoda = new Jedi("Yoda", "Green");
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN
-    AssertionError assertionError = expectAssertionError(() -> assertThat(yoda).usingComparatorForType(CASE_INSENSITIVE_ORDER,
-                                                                                                       String.class)
-                                                                               .doesNotReturn("YODA", from(Jedi::getName)));
+    AssertionError assertionError = expectAssertionError(() -> assertThat(actual).usingComparatorForType(CASE_INSENSITIVE_ORDER,
+                                                                                                         String.class)
+                                                                                 .doesNotReturn("YODA", from(Jedi::getName)));
     // THEN
     then(assertionError).hasMessage(shouldNotBeEqual("Yoda", "YODA",
                                                      new ComparatorBasedComparisonStrategy(CASE_INSENSITIVE_ORDER)).create());
   }
 
-  @Test
-  void should_pass_with_null_expected_value() {
-    // GIVEN
-    Jedi yoda = new Jedi("Yoda", "Green");
-    // WHEN/THEN
-    assertThat(yoda).doesNotReturn(null, from(Jedi::getName));
-  }
-
 }
diff --git a/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java b/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java
--- a/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java
+++ b/assertj-core/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java
@@ -17,61 +17,62 @@
 import static org.assertj.core.api.Assertions.catchThrowable;
 import static org.assertj.core.api.Assertions.from;
 import static org.assertj.core.api.BDDAssertions.then;
-import static org.mockito.Mockito.verify;
+import static org.assertj.core.util.AssertionsUtil.expectAssertionError;
+import static org.assertj.core.util.FailureMessages.actualIsNull;
 
-import org.assertj.core.api.ObjectAssert;
-import org.assertj.core.api.ObjectAssertBaseTest;
 import org.assertj.core.test.Jedi;
 import org.junit.jupiter.api.Test;
 
 /**
  * @author Takuya "Mura-Mi" Murakami
  */
-class ObjectAssert_returns_Test extends ObjectAssertBaseTest {
+class ObjectAssert_returns_Test {
 
-  @Override
-  protected ObjectAssert<Jedi> invoke_api_method() {
-    return assertions.returns("Yoda", Jedi::getName);
-  }
-
-  @Override
-  protected void verify_internal_effects() {
-    verify(objects).assertEqual(getInfo(assertions), getActual(assertions).getName(), "Yoda");
+  @Test
+  void should_fail_if_actual_is_null() {
+    // GIVEN
+    Jedi actual = null;
+    // WHEN
+    AssertionError assertionError = expectAssertionError(() -> assertThat(actual).returns("Yoda", from(Jedi::getName)));
+    // THEN
+    then(assertionError).hasMessage(actualIsNull());
   }
 
   @Test
-  void should_fail_with_throwing_NullPointerException_if_method_is_null() {
+  void should_fail_if_from_is_null() {
+    // GIVEN
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN
-    Throwable thrown = catchThrowable(() -> assertions.returns("May the force be with you.", null));
+    Throwable thrown = catchThrowable(() -> assertThat(actual).returns("Yoda", null));
     // THEN
     then(thrown).isInstanceOf(NullPointerException.class)
                 .hasMessage("The given getter method/Function must not be null");
   }
 
   @Test
-  void perform_assertion_like_users() {
+  void should_pass() {
     // GIVEN
-    Jedi yoda = new Jedi("Yoda", "Green");
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN/THEN
-    assertThat(yoda).returns("Yoda", from(Jedi::getName))
-                    .returns("Yoda", Jedi::getName);
+    assertThat(actual).returns("Yoda", from(Jedi::getName))
+                      .returns("Yoda", Jedi::getName);
   }
 
   @Test
-  void should_honor_custom_type_comparator() {
+  void should_pass_if_expected_is_null() {
     // GIVEN
-    Jedi yoda = new Jedi("Yoda", "Green");
+    Jedi actual = new Jedi(null, "Green");
     // WHEN/THEN
-    assertThat(yoda).usingComparatorForType(CASE_INSENSITIVE_ORDER, String.class)
-                    .returns("YODA", from(Jedi::getName));
+    assertThat(actual).returns(null, from(Jedi::getName));
   }
 
   @Test
-  void should_pass_with_null_expected_value() {
+  void should_honor_custom_type_comparator() {
     // GIVEN
-    Jedi yoda = new Jedi(null, "Green");
+    Jedi actual = new Jedi("Yoda", "Green");
     // WHEN/THEN
-    assertThat(yoda).returns(null, from(Jedi::getName));
+    assertThat(actual).usingComparatorForType(CASE_INSENSITIVE_ORDER, String.class)
+                      .returns("YODA", from(Jedi::getName));
   }
 
 }