From 411284c30232dd2582e4a1bee963f9eb2d9a6fcf Mon Sep 17 00:00:00 2001 From: Jan Ouwens Date: Wed, 4 Dec 2024 19:14:49 +0100 Subject: [PATCH] Let ValueProvider return an Optional --- .../checkers/AbstractDelegationChecker.java | 2 +- .../MapEntryHashCodeRequirementChecker.java | 2 +- .../fieldchecks/JpaLazyGetterFieldCheck.java | 10 ++---- .../fieldchecks/ReflexivityFieldCheck.java | 2 +- .../fieldchecks/StringFieldCheck.java | 3 +- .../internal/exceptions/NoValueException.java | 20 +++++++++++ .../instantiation/SubjectCreator.java | 3 +- .../instantiation/ValueProvider.java | 21 ++++++++++-- .../instantiation/VintageValueProvider.java | 4 +-- .../exceptions/NoValueExceptionTest.java | 16 +++++++++ .../instantiation/SubjectCreatorTest.java | 34 +++++++++++++++---- .../VintageValueProviderTest.java | 11 +++--- 12 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/exceptions/NoValueException.java create mode 100644 equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/exceptions/NoValueExceptionTest.java diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/AbstractDelegationChecker.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/AbstractDelegationChecker.java index ca64fabb1..3b5820ab7 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/AbstractDelegationChecker.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/AbstractDelegationChecker.java @@ -74,7 +74,7 @@ private void checkAbstractDelegationInFields() { private Tuple safelyGetTuple(TypeTag tag) { try { - return valueProvider.provide(tag); + return valueProvider.provideOrThrow(tag); } catch (Exception ignored) { // If it fails for some reason, any reason, just return null so we can skip the test. return null; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/MapEntryHashCodeRequirementChecker.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/MapEntryHashCodeRequirementChecker.java index 3ae750f99..3caf7f991 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/MapEntryHashCodeRequirementChecker.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/MapEntryHashCodeRequirementChecker.java @@ -23,7 +23,7 @@ public MapEntryHashCodeRequirementChecker(Context context) { public void check() { if (Map.Entry.class.isAssignableFrom(config.getType())) { Map.Entry e = valueProvider - .>provide(config.getTypeTag()) + .>provideOrThrow(config.getTypeTag()) .getRed(); int expectedHashCode = Objects.hashCode(e.getKey()) ^ Objects.hashCode(e.getValue()); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/JpaLazyGetterFieldCheck.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/JpaLazyGetterFieldCheck.java index 9727744bf..2632bc342 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/JpaLazyGetterFieldCheck.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/JpaLazyGetterFieldCheck.java @@ -9,11 +9,7 @@ import java.util.function.Function; import nl.jqno.equalsverifier.Warning; import nl.jqno.equalsverifier.internal.exceptions.EqualsVerifierInternalBugException; -import nl.jqno.equalsverifier.internal.reflection.ClassProbe; -import nl.jqno.equalsverifier.internal.reflection.FieldProbe; -import nl.jqno.equalsverifier.internal.reflection.Instantiator; -import nl.jqno.equalsverifier.internal.reflection.Tuple; -import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.*; import nl.jqno.equalsverifier.internal.reflection.annotations.AnnotationCache; import nl.jqno.equalsverifier.internal.reflection.annotations.SupportedAnnotations; import nl.jqno.equalsverifier.internal.reflection.instantiation.SubjectCreator; @@ -67,8 +63,8 @@ public void execute(FieldProbe fieldProbe) { classProbe.hasMethod(getterName) ); - Class sub = throwingGetterCreator(getterName); - Tuple tuple = valueProvider.provide(new TypeTag(sub)); + TypeTag sub = new TypeTag(throwingGetterCreator(getterName)); + Tuple tuple = valueProvider.provideOrThrow(sub); T red1 = tuple.getRed(); T red2 = tuple.getRedCopy(); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/ReflexivityFieldCheck.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/ReflexivityFieldCheck.java index 3d775008a..c8705a78c 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/ReflexivityFieldCheck.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/ReflexivityFieldCheck.java @@ -82,7 +82,7 @@ private void checkValueReflexivity(FieldProbe probe) { TypeTag tag = TypeTag.of(field, typeTag); Tuple tuple = prefabbedFields.contains(fieldName) ? fieldCache.get(fieldName) - : valueProvider.provide(tag); + : valueProvider.provideOrThrow(tag); Object left = subjectCreator.withFieldSetTo(field, tuple.getRed()); Object right = subjectCreator.withFieldSetTo(field, tuple.getRedCopy()); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/StringFieldCheck.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/StringFieldCheck.java index e05e50ad5..9377394a0 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/StringFieldCheck.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/fieldchecks/StringFieldCheck.java @@ -40,7 +40,8 @@ public StringFieldCheck( ) public void execute(FieldProbe fieldProbe) { if (String.class.equals(fieldProbe.getType()) && !fieldProbe.isStatic()) { - String red = valueProvider.provide(new TypeTag(String.class)).getRed(); + TypeTag string = new TypeTag(String.class); + String red = valueProvider.provideOrThrow(string).getRed(); final T reference; final T copy; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/exceptions/NoValueException.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/exceptions/NoValueException.java new file mode 100644 index 000000000..182a71572 --- /dev/null +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/exceptions/NoValueException.java @@ -0,0 +1,20 @@ +package nl.jqno.equalsverifier.internal.exceptions; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; + +@SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "EqualsVerifier doesn't serialize.") +public class NoValueException extends MessagingException { + + private final TypeTag tag; + + public NoValueException(TypeTag tag) { + super(); + this.tag = tag; + } + + @Override + public String getDescription() { + return "Could not find a value for " + tag + ". Please add prefab values for this type."; + } +} diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreator.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreator.java index 86c3a7cb2..17fc59420 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreator.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreator.java @@ -244,7 +244,8 @@ private Tuple valuesFor(Field f) { return fieldCache.get(fieldName); } try { - Tuple tuple = valueProvider.provide(TypeTag.of(f, typeTag)); + TypeTag fieldTag = TypeTag.of(f, typeTag); + Tuple tuple = valueProvider.provideOrThrow(fieldTag); fieldCache.put(fieldName, tuple); return tuple; } catch (ModuleException e) { diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ValueProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ValueProvider.java index eef125f5c..268a43e24 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ValueProvider.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ValueProvider.java @@ -1,5 +1,7 @@ package nl.jqno.equalsverifier.internal.reflection.instantiation; +import java.util.Optional; +import nl.jqno.equalsverifier.internal.exceptions.NoValueException; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; @@ -18,7 +20,22 @@ public interface ValueProvider { * * @param The returned tuple will have this generic type. * @param tag A description of the desired type, including generic parameters. - * @return A tuple of two different values of the given type. + * @return A tuple of two different values of the given type, or an empty Optional if none + * could be found. */ - Tuple provide(TypeTag tag); + Optional> provide(TypeTag tag); + + /** + * Returns a tuple of prefabricated values of the specified type, or, if none exists, throws a + * NoValueException. + * + * @param The returned tuple will have this generic type. + * @param tag A description of the desired type, including generic parameters. + * @return A tuple of two different values of the given type, or an empty Optional if none + * could be found. + * @throws NoValueException if no value could be found for the given tag. + */ + default Tuple provideOrThrow(TypeTag tag) { + return this.provide(tag).orElseThrow(() -> new NoValueException(tag)); + } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProvider.java index 4af2fbd1b..c92154520 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProvider.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProvider.java @@ -42,8 +42,8 @@ public VintageValueProvider(FactoryCache factoryCache, Objenesis objenesis) { /** {@inheritDoc} */ @Override - public Tuple provide(TypeTag tag) { - return Rethrow.rethrow(() -> giveTuple(tag)); + public Optional> provide(TypeTag tag) { + return Rethrow.rethrow(() -> Optional.of(giveTuple(tag))); } /** diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/exceptions/NoValueExceptionTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/exceptions/NoValueExceptionTest.java new file mode 100644 index 000000000..58259cc49 --- /dev/null +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/exceptions/NoValueExceptionTest.java @@ -0,0 +1,16 @@ +package nl.jqno.equalsverifier.internal.exceptions; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import org.junit.jupiter.api.Test; + +public class NoValueExceptionTest { + + @Test + public void description() { + TypeTag tag = new TypeTag(String.class); + NoValueException e = new NoValueException(tag); + assertTrue(e.getDescription().contains("String")); + } +} diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreatorTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreatorTest.java index d9e9ba8cd..e62ebfd13 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreatorTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/SubjectCreatorTest.java @@ -5,9 +5,12 @@ import java.lang.reflect.Field; import java.util.Objects; +import java.util.Optional; +import nl.jqno.equalsverifier.internal.exceptions.NoValueException; import nl.jqno.equalsverifier.internal.reflection.FieldCache; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import nl.jqno.equalsverifier.internal.util.Configuration; import nl.jqno.equalsverifier.internal.util.ConfigurationHelper; import org.junit.jupiter.api.BeforeEach; @@ -49,9 +52,6 @@ public void setup() throws NoSuchFieldException { fieldS = SomeClass.class.getDeclaredField("s"); } - @Test - public void sanity() {} - @Test public void plain() { expected = new SomeClass(I_RED, I_RED, S_RED); @@ -194,16 +194,36 @@ public void copyIntoSubclass() { assertEquals(SomeSub.class, actual.getClass()); } + @Test + public void noValueFound() { + sut = new SubjectCreator<>(config, new NoValueProvider(), fieldCache, objenesis); + + ExpectedException + .when(() -> sut.plain()) + .assertThrows(NoValueException.class) + .assertDescriptionContains("int"); + + assertEquals(expected, actual); + } + static class SubjectCreatorTestValueProvider implements ValueProvider { - public Tuple provide(TypeTag tag) { + public Optional> provide(TypeTag tag) { if (int.class.equals(tag.getType())) { - return Tuple.of(I_RED, I_BLUE, I_RED); + return Optional.of(Tuple.of(I_RED, I_BLUE, I_RED)); } if (String.class.equals(tag.getType())) { - return Tuple.of(S_RED, S_BLUE, new String(S_RED)); + return Optional.of(Tuple.of(S_RED, S_BLUE, new String(S_RED))); } - throw new IllegalStateException(); + return Optional.empty(); + } + } + + static class NoValueProvider implements ValueProvider { + + @Override + public Optional> provide(TypeTag tag) { + return Optional.empty(); } } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderTest.java index 2fa15353e..03cde5c19 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderTest.java @@ -7,9 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.fail; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; +import java.util.*; import nl.jqno.equalsverifier.internal.reflection.FactoryCache; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; @@ -48,8 +46,11 @@ public void sanityTestFactoryIncreasesStringLength() { @Test public void provide() { - Tuple actual = vp.provide(POINT_TAG); - assertEquals(Tuple.of(new Point(42, 42), new Point(1337, 1337), new Point(42, 42)), actual); + Optional> actual = vp.provide(POINT_TAG); + assertEquals( + Tuple.of(new Point(42, 42), new Point(1337, 1337), new Point(42, 42)), + actual.get() + ); } @Test