Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Truth Subject#check #1092

Open
ben-manes opened this issue Dec 14, 2024 · 2 comments
Open

Support Truth Subject#check #1092

ben-manes opened this issue Dec 14, 2024 · 2 comments

Comments

@ben-manes
Copy link

ben-manes commented Dec 14, 2024

The test assertion library support will infer from an assertThat statement for use in a test method. A more advanced user may want to write custom assertions, known as a Subject, in order to create their own reusable ones. This internally uses the check method to use the nicely formatted error messaging subsystem. Currently NullAway does not understand this for reasoning about the possibility of null dereferences.

In this example the check("value").that(value).isNotNull() precedes the check...containsValue(value) and emits a warning that containsValue requires a non-null parameter.

  private void checkValue(BoundedLocalCache<Object, Object> bounded,
      Node<Object, Object> node, @Nullable Object key, @Nullable Object value) {
    if (!bounded.collectValues()) {
      check("value").that(value).isNotNull();
      if ((key != null) && !bounded.hasExpired(node, bounded.expirationTicker().read())) {
        check("containsValue(value) for key %s", key)
            .about(map()).that(bounded).containsValue(value);
      }
    }
    checkIfAsyncValue(value);
  }
/Users/ben/projects/caffeine/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LocalCacheSubject.java:381: error: [NullAway] passing @Nullable parameter 'value' where @NonNull is required
            .about(map()).that(bounded).containsValue(value);
                                                      ^
    (see http://t.uber.com/nullaway )
  Did you mean '@SuppressWarnings("NullAway") private void checkValue(BoundedLocalCache<Object, Object> bounded,'?

The benefit is that test methods can continue to stay focused on the behavioral aspects instead of having repeated logic that inspects implementation details. For example inspecting the listener configured on the cache so ensure the correct events were emited.

assertThat(context).removalNotifications().withCause(REPLACED)
    .contains(context.original()).exclusively();

Another scenario to support is assertWithMessage(msg).that(subject).isNotNull(). This is an assertThat where the message can be supplied for a better description.

I've also had cases where the null assertion was not taken into account and it warns about the following statement. I believe this is because I have my own FutureSubject and MethodNameUtil looks for concrete classes rather than at the polymorphic type.

assertThat(future).isNotNull();
future.complete(Int.MAX_VALUE);
@msridhar
Copy link
Collaborator

Thanks for the report. On this part:

The benefit is that test methods can continue to stay focused on the behavioral aspects instead of having repeated logic that inspects implementation details. For example inspecting the listener configured on the cache so ensure the correct events were emited.

assertThat(context).removalNotifications().withCause(REPLACED)
    .contains(context.original()).exclusively();

I didn't quite get the connection to nullability for this example?

Conceptually, adding the requested support is not difficult. It's just a bit of a pain to implement. We can look into it, though I think we have higher-priority issues to deal with at the moment.

@ben-manes
Copy link
Author

Thanks, it’s not much of an issue. I think only once or twice, but maybe in a larger code base it will be desirable. I’d backlog until others ask for it, or close as informational.

The last was merely an example for why custom assertions is nice and unrelated. Most developers don’t realize they can do this or that it’s the intended usage of the assertion library. I wanted to show that in case it came across as an obscure use-case.

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

No branches or pull requests

2 participants