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

[Bug] withPrefabValuesForField() throws for fields declaring interfaces and super-types #1012

Closed
Vankog opened this issue Nov 5, 2024 · 3 comments

Comments

@Vankog
Copy link
Contributor

Vankog commented Nov 5, 2024

Describe the bug

withPrefabValuesForField() throws precondition exception for interface fields (e.g. java.util.List) if prefab values are interface-implementations or sub-implementations of the defined field type.
e.g. for List it fails for:

  • java.util.ArrayList
  • java.util.Arrays.ArrayList via java.util.Arrays.asList(T...)
  • java.util.Collections.SingletonList, created via java.util.Collections.singletonList(T)

Steps to reproduce

  1. Create a POJO with an interface, e.g. java.util.List field.
  2. Test POJO with
    .withPrefabValues(List.class, Collections.singletonList(red), Collections.singletonList(blue))
    • works☑️
  3. Test POJO with
    .withPrefabValuesForField("myListField", Collections.singletonList(red), Collections.singletonList(blue))
    • fails❌
  4. Test POJO with
    .withPrefabValuesForField("myListField", Arrays.asList(red), Arrays.asList(blue))
    • fails❌
  5. Test POJO with
    .withPrefabValuesForField("myListField", Collections.unmodifiableList(Arrays.asList(red)), Collections.unmodifiableList(Arrays.asList(blue)))
    • fails❌

Error message and version number

EqualsVerifier v. 3.17.1
JDK 8 Temurin

java.lang.IllegalStateException: Precondition: Prefab values for field subItems should be of type List but are SingletonList.
	at nl.jqno.equalsverifier.internal.util.Validations.validate(Validations.java:270)
	at nl.jqno.equalsverifier.internal.util.Validations.validateFieldTypeMatches(Validations.java:103)
	at nl.jqno.equalsverifier.internal.util.PrefabValuesApi.addPrefabValuesForField(PrefabValuesApi.java:51)
	at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.withPrefabValuesForField(SingleTypeEqualsVerifierApi.java:146)
	at my.test.DummyClassTest.testEqualsContract(ItemDataTest.java:27)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at java.util.ArrayList.forEach(ArrayList.java:1259)

Code: EqualsVerifier invocation

        EqualsVerifier.forClass(DummyClass.class)
                      .suppress(Warning.NONFINAL_FIELDS, Warning.STRICT_INHERITANCE)
                      .withPrefabValuesForField("myListField", Collections.singletonList(red), Collections.singletonList(blue))
                      .verify();

Code: class under test

public class DummyClass {
    String id;
    List<String> myListField;
    /* ...equals / hashcode... */
}

Additional context

Using the old
.withPrefabValues(List.class, Collections.singletonList(red), Collections.singletonList(blue))
works.
Thus, the expectation is that it works for withPrefabValuesForField() as well.

EDIT:
Looking at nl.jqno.equalsverifier.internal.util.Validations.validateFieldTypeMatches(Class, String, Class<?>) indicates that this happens with all type hierarchies, as the code uses
boolean sameFields = f.getType().equals(fieldType);
enforcing an exact type match, doesn't it?

EDIT 2: Yes, testing implies that also type hierarchies are affected.
I tested it against a field of type java.lang.Object with any sub-type as prefab values.

@Vankog Vankog changed the title [Bug] withPrefabValuesForField() throws for type List if Prefab values are created via Collections.singletonList() [Bug] withPrefabValuesForField() throws for interfaces and super-types Nov 5, 2024
@Vankog Vankog changed the title [Bug] withPrefabValuesForField() throws for interfaces and super-types [Bug] withPrefabValuesForField() throws for fields declaring interfaces and super-types Nov 5, 2024
@Vankog
Copy link
Contributor Author

Vankog commented Nov 5, 2024

The solution might probably, to use java.lang.Class.isAssignableFrom(Class<?>)

@jqno
Copy link
Owner

jqno commented Nov 5, 2024

You're completely right. Thanks for the elaborate report, this made it very easy for me to make the fix.

Version 3.17.2 is now syncing with Maven Central!

@jqno jqno closed this as completed Nov 5, 2024
Vankog added a commit to Vankog/equalsverifier that referenced this issue Nov 5, 2024
See jqno#1012 [Bug] withPrefabValuesForField() throws for fields declaring interfaces and super-types
@Vankog
Copy link
Contributor Author

Vankog commented Nov 5, 2024

Oh, I was too slow ^^
Well, maybe the test helps nonetheless.

Vankog added a commit to Vankog/equalsverifier that referenced this issue Nov 5, 2024
See jqno#1012 [Bug] withPrefabValuesForField() throws for fields declaring interfaces and super-types
Vankog added a commit to Vankog/equalsverifier that referenced this issue Nov 6, 2024
See jqno#1012 [Bug] withPrefabValuesForField() throws for fields declaring interfaces and super-types
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