Warning RSPEC-5853 when using assertJ and extracting

Hello,

I think there may be a false positive with RSPEC-5853 when using assertJ extracting/flatExtracting method with this kind of code:

        assertThat(record)
                .flatExtracting(Record::getSubRecords1)
                .containsExactlyInAnyOrderElementsOf(s1);
        assertThat(record)
                .flatExtracting(Record::getSubRecords2)
                .containsExactlyInAnyOrderElementsOf(s2);

I’m not aware of a way to chain extracting/flatExtracting methods to go back to a parent bean (i.e once I’m in subRecords1, I cannot go back to …/record/subRecords2).

Edit: I have the same shortcoming when using filteredOn, i.e.

        assertThat(responses)
                .filteredOn(it -> it.getRequest() == accessAllowedRequest)
                .hasSize(1)
                .allSatisfy(it ->
                        assertThat(it.isAutorise()).isTrue()
                );
        assertThat(responses)
                .filteredOn(it -> it.getRequest() == accessForbiddenRequest)
                .hasSize(1)
                .first()
                .extracting(Response::isAutorise)
                .asInstanceOf(InstanceOfAssertFactories.BOOLEAN)
                .isFalse();

Version used SonarLint Intellij 4.12.1.22375

Minimal code to reproduce this issue:

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static org.assertj.core.api.Assertions.assertThat;

class RSPEC5853ExtractingTest {

    @Test
    void issueWithRSPEC5853WhenUsingExtracting() {
        List<SubRecord> s1 = Arrays.asList(new SubRecord("s1"));
        List<SubRecord> s2 = Arrays.asList(new SubRecord("s2"));
        List<Record> record = Arrays.asList(new Record(
                s1,
                s2
        ));

        assertThat(record)
                .flatExtracting(Record::getSubRecords1)
                .containsExactlyInAnyOrderElementsOf(s1);
        assertThat(record)
                .flatExtracting(Record::getSubRecords2)
                .containsExactlyInAnyOrderElementsOf(s2);
    }

    private static class Record {
        List<SubRecord> subRecords1;
        List<SubRecord> subRecords2;

        public Record(List<SubRecord> subRecords1, List<SubRecord> subRecords2) {
            this.subRecords1 = subRecords1;
            this.subRecords2 = subRecords2;
        }

        public List<SubRecord> getSubRecords1() {
            return subRecords1;
        }

        public List<SubRecord> getSubRecords2() {
            return subRecords2;
        }
    }
    private static class SubRecord {
        private String name;

        public SubRecord(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            SubRecord subRecord = (SubRecord) o;
            return Objects.equals(getName(), subRecord.getName());
        }

        @Override
        public int hashCode() {
            return Objects.hash(getName());
        }
    }

}

Hello @gonzalad and welcome to the community!

I agree with you, in such cases, it is not possible/cleaner to chain the assertions.
For flatExtracting, I confirm that we are not supporting it. Ticket created: SONARJAVA-3628.

Now concerning extracting and filteredOn, I’m surprised to see that we still report an issue, we are supposed to support methods subtype of org.assertj.core.api.AbstractAssert, starting with filtered and extracting.

Examples, taken from our units tests:

  String myString = "42";
  List<String> myList = new ArrayList<>();

  @Test
  void extracting() {
    assertThat((Object) myString).extracting("field1").isEqualTo("f1"); // Compliant
    assertThat((Object) myString).extracting("field2").isEqualTo("f2");
    assertThat((Object) myString).isEqualTo("42");
  }

  @Test
  void filtered() {
    assertThat(myList).filteredOn("", "").isEqualTo("");  // Compliant
    assertThat(myList).isEmpty();
  }

Is it possible that the methods you are using are actually not inheriting from org.assertj.core.api.AbstractAssert? Or that you have a misconfiguration of the analysis (dependencies/libraries missing during analysis, check your logs), preventing the analysis to correctly detect the different types?