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

Allow ComparingNormalizedFields instances to be reused across different assertions #3493

Closed

Conversation

genuss
Copy link
Contributor

@genuss genuss commented May 28, 2024

Hi, team!

After upgrading to 3.25.3 I see that ComparingNormalizedFields RecursiveComparisonIntrospectionStrategy can't be between different assertions (see my example). I digged into the code and found that the change was introduced in commit 0d5b789, related to some performance improvements. The root cause is that originalFieldNamesByNormalizedFieldNameByNode is an identity hash map, although fieldNamesPerClass is keyed by class values. So, I found a fix for that, which I present here. I'm not sure that it's 100% correct, but I didn't find any failing tests. Hope you may find this helpful.

package test;

import org.assertj.core.api.Assertions;
import org.assertj.core.api.recursive.comparison.ComparingNormalizedFields;
import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;
import org.junit.jupiter.api.Test;

class AssertjBugTest {

  @Test
  void test() {
    Assertions.assertThat(new Actual(0))
        .usingRecursiveComparison(
            RecursiveComparisonConfiguration.builder()
                .withIntrospectionStrategy(SomeIntrospectionStrategy.INSTANCE)
                .build())
        .isEqualTo(new Expected(0));
    Assertions.assertThat(new Actual(0))
        .usingRecursiveComparison(
            RecursiveComparisonConfiguration.builder()
                .withIntrospectionStrategy(SomeIntrospectionStrategy.INSTANCE)
                .build())
        .isEqualTo(new Expected(0));
  }

  record Actual(int a) {}

  record Expected(int A) {}
}

class SomeIntrospectionStrategy extends ComparingNormalizedFields {

  static final SomeIntrospectionStrategy INSTANCE = new SomeIntrospectionStrategy();

  @Override
  protected String normalizeFieldName(String fieldName) {
    return fieldName.toLowerCase();
  }
}

Check List:

  • Unit tests : YES
  • Javadoc with a code example (on API only) : NA

@genuss genuss force-pushed the fix/reuse-comparing-normalized-fields branch from b087207 to 309c62c Compare May 28, 2024 09:46
@scordio scordio added the type: regression A regression from a previous release label May 28, 2024
@scordio scordio added this to the 3.26.1 milestone May 28, 2024
@scordio
Copy link
Member

scordio commented May 28, 2024

Thanks for reporting it and providing a fix, @genuss! We'll check it and get back to you.

@joel-costigliola
Copy link
Member

thanks @genuss, I'll look at it next week

@joel-costigliola
Copy link
Member

I had a quick look and there was indeed a bug in getChildrenNodeNamesOf which tried to be clever and not renormalize fields for the same class twice, but it turns out that the fields normalization also populates originalFieldNamesByNormalizedFieldNameByNode and this needs to be done for each nodes.

The code is a bit crap because getChildrenNodeNamesOf has some side effects and is not performant as it calls Objects.getFieldsNames(node.getClass()); which is expensive whereas normalizing fields names is not.

I have a fix but it needs a bit more love and I'll see if I want to cache Objects.getFieldsNames(node.getClass()) operation as it is expensive.

@joel-costigliola
Copy link
Member

Integrated thanks @genuss !

@genuss
Copy link
Contributor Author

genuss commented Jun 6, 2024

Very good, thank you too!

@scordio scordio changed the title Allow ComparingNormalizedFields instances to be reused across different assertions Allow ComparingNormalizedFields instances to be reused across different assertions Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants