diff --git a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/RecordsTest.java b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/RecordsTest.java index 076a44c41..fd6aa50ae 100644 --- a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/RecordsTest.java +++ b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/RecordsTest.java @@ -134,7 +134,7 @@ public void succeed_whenRecordValidatesInput_givenValidPrefabValues() { } @Test - public void succeed_whenRecord() { + public void succeed_whenRecordHasBoundedWildcardGeneric() { EqualsVerifier.forClass(WildcardGenericRecordContainer.class).verify(); } diff --git a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordFallbackFactoryTest.java b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordFallbackFactoryTest.java new file mode 100644 index 000000000..5c2a62dea --- /dev/null +++ b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordFallbackFactoryTest.java @@ -0,0 +1,51 @@ +package nl.jqno.equalsverifier.internal.reflection.vintage; + +import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import nl.jqno.equalsverifier.internal.reflection.Tuple; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.FallbackFactory; +import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.objenesis.Objenesis; +import org.objenesis.ObjenesisStd; + +public class RecordFallbackFactoryTest { + + private FallbackFactory factory; + private VintageValueProvider valueProvider; + private Attributes attributes; + + @BeforeEach + public void setUp() { + Objenesis objenesis = new ObjenesisStd(); + factory = new FallbackFactory<>(objenesis); + CachedValueProvider cache = new CachedValueProvider(); + FactoryCache factoryCache = new FactoryCache(); + factoryCache.put(int.class, values(42, 1337, 42)); + valueProvider = + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); + attributes = Attributes.unlabeled(); + } + + @Test + public void redCopyHasTheSameValuesAsRed_whenSutContainsGenericValueThatNeedsToBeIdenticalInRedAndRedCopy() { + Tuple tuple = factory.createValues( + new TypeTag(GenericRecordContainer.class), + valueProvider, + attributes + ); + + assertEquals(tuple.getRed(), tuple.getRedCopy()); + assertNotSame(tuple.getRed(), tuple.getRedCopy()); + } + + record GenericRecord(T t) {} + + record GenericRecordContainer(GenericRecord bgr) {} +} diff --git a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorCopyingTest.java b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorCopyingTest.java similarity index 96% rename from equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorCopyingTest.java rename to equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorCopyingTest.java index 25c904414..cbcc3c17a 100644 --- a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorCopyingTest.java +++ b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorCopyingTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; diff --git a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorScramblingTest.java b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorScramblingTest.java similarity index 77% rename from equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorScramblingTest.java rename to equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorScramblingTest.java index 5f689a58c..7c9a42732 100644 --- a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorScramblingTest.java +++ b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorScramblingTest.java @@ -1,14 +1,16 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotSame; import java.lang.reflect.Constructor; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,15 +18,22 @@ public class RecordObjectAccessorScramblingTest { - private static final LinkedHashSet EMPTY_TYPE_STACK = new LinkedHashSet<>(); + private static final Attributes EMPTY_ATTRIBUTES = Attributes.unlabeled(); + private CachedValueProvider cache; private FactoryCache factoryCache; private VintageValueProvider valueProvider; @BeforeEach public void setup() throws Exception { + cache = new CachedValueProvider(); factoryCache = JavaApiPrefabValues.build(); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, new ObjenesisStd()); + new VintageValueProvider( + TestValueProviders.empty(), + cache, + factoryCache, + new ObjenesisStd() + ); } @Test @@ -58,7 +67,7 @@ private RecordObjectAccessor create(T object) { } private ObjectAccessor doScramble(Object object) { - return create(object).scramble(valueProvider, TypeTag.NULL, EMPTY_TYPE_STACK); + return create(object).scramble(valueProvider, TypeTag.NULL, EMPTY_ATTRIBUTES); } record Point(int x, int y) {} diff --git a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorTest.java b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorTest.java similarity index 90% rename from equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorTest.java rename to equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorTest.java index cc19512d5..83a5d6333 100644 --- a/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessorTest.java +++ b/equalsverifier-16/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessorTest.java @@ -1,16 +1,17 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Constructor; -import java.util.LinkedHashSet; import java.util.Objects; import nl.jqno.equalsverifier.internal.exceptions.ReflectionException; import nl.jqno.equalsverifier.internal.reflection.Instantiator; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import org.junit.jupiter.api.BeforeEach; @@ -20,7 +21,7 @@ public class RecordObjectAccessorTest { - private static final LinkedHashSet EMPTY_TYPE_STACK = new LinkedHashSet<>(); + private static final Attributes EMPTY_ATTRIBUTES = Attributes.unlabeled(); private Objenesis objenesis; private Object recordInstance; @@ -77,11 +78,12 @@ public void fail_whenConstructorThrowsOnSomethingElse() { VintageValueProvider vp = new VintageValueProvider( TestValueProviders.empty(), + new CachedValueProvider(), JavaApiPrefabValues.build(), objenesis ); ExpectedException - .when(() -> accessorFor(instance).scramble(vp, TypeTag.NULL, EMPTY_TYPE_STACK)) + .when(() -> accessorFor(instance).scramble(vp, TypeTag.NULL, EMPTY_ATTRIBUTES)) .assertThrows(ReflectionException.class) .assertMessageContains("Record:", "failed to run constructor", "prefab values"); } diff --git a/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassAccessorSealedTest.java b/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassProbeSealedTest.java similarity index 94% rename from equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassAccessorSealedTest.java rename to equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassProbeSealedTest.java index 2b7ad0633..f9539c7a5 100644 --- a/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassAccessorSealedTest.java +++ b/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/ClassProbeSealedTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; -public class ClassAccessorSealedTest { +public class ClassProbeSealedTest { @Test public void isNotSealed() { diff --git a/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/SealedTypesFallbackFactoryTest.java b/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/SealedTypesFallbackFactoryTest.java new file mode 100644 index 000000000..afc7eb192 --- /dev/null +++ b/equalsverifier-17/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/SealedTypesFallbackFactoryTest.java @@ -0,0 +1,87 @@ +package nl.jqno.equalsverifier.internal.reflection.vintage; + +import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import java.util.Objects; +import nl.jqno.equalsverifier.internal.reflection.Tuple; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.FallbackFactory; +import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.objenesis.Objenesis; +import org.objenesis.ObjenesisStd; + +public class SealedTypesFallbackFactoryTest { + + private FallbackFactory factory; + private VintageValueProvider valueProvider; + private Attributes attributes; + + @BeforeEach + public void setUp() { + Objenesis objenesis = new ObjenesisStd(); + factory = new FallbackFactory<>(objenesis); + CachedValueProvider cache = new CachedValueProvider(); + FactoryCache factoryCache = new FactoryCache(); + factoryCache.put(int.class, values(42, 1337, 42)); + valueProvider = + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); + attributes = Attributes.unlabeled(); + } + + @Test + public void redCopyHasTheSameValuesAsRed_whenSutIsAbstractSealedAndPermittedTypeAddsField() { + Tuple tuple = factory.createValues( + new TypeTag(SealedParentWithFinalChild.class), + valueProvider, + attributes + ); + + assertEquals(tuple.getRed(), tuple.getRedCopy()); + assertNotSame(tuple.getRed(), tuple.getRedCopy()); + } + + public abstract static sealed class SealedParentWithFinalChild permits FinalSealedChild { + + private final int i; + + public SealedParentWithFinalChild(int i) { + this.i = i; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof SealedParentWithFinalChild other && i == other.i; + } + + @Override + public int hashCode() { + return Objects.hash(i); + } + } + + public static final class FinalSealedChild extends SealedParentWithFinalChild { + + private final int j; + + public FinalSealedChild(int i, int j) { + super(i); + this.j = j; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FinalSealedChild other && super.equals(obj) && j == other.j; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), j); + } + } +} diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/ConfiguredEqualsVerifier.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/ConfiguredEqualsVerifier.java index 687f6c78a..8e9aa2e57 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/ConfiguredEqualsVerifier.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/ConfiguredEqualsVerifier.java @@ -11,8 +11,8 @@ import nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi; import nl.jqno.equalsverifier.internal.reflection.PackageScanner; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.PrefabValuesApi; import nl.jqno.equalsverifier.internal.util.ListBuilders; -import nl.jqno.equalsverifier.internal.util.PrefabValuesApi; import nl.jqno.equalsverifier.internal.util.Validations; import org.objenesis.Objenesis; import org.objenesis.ObjenesisStd; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/api/SingleTypeEqualsVerifierApi.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/api/SingleTypeEqualsVerifierApi.java index 9d99721be..a401fc832 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/api/SingleTypeEqualsVerifierApi.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/api/SingleTypeEqualsVerifierApi.java @@ -11,6 +11,7 @@ import nl.jqno.equalsverifier.internal.checkers.*; import nl.jqno.equalsverifier.internal.exceptions.MessagingException; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.PrefabValuesApi; import nl.jqno.equalsverifier.internal.util.*; import nl.jqno.equalsverifier.internal.util.Formatter; import org.objenesis.Objenesis; 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 9cd851599..4ae690cc6 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 @@ -10,6 +10,7 @@ import nl.jqno.equalsverifier.internal.reflection.TypeTag; import nl.jqno.equalsverifier.internal.reflection.instantiation.SubjectCreator; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.*; public class AbstractDelegationChecker implements Checker { @@ -74,7 +75,7 @@ private void checkAbstractDelegationInFields() { private Tuple safelyGetTuple(TypeTag tag, String fieldName) { try { - return valueProvider.provideOrThrow(tag, fieldName); + return valueProvider.provideOrThrow(tag, Attributes.labeled(fieldName)); } 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 7438783b4..f9abe6f8c 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 @@ -5,6 +5,7 @@ import java.util.Map; import java.util.Objects; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.Configuration; import nl.jqno.equalsverifier.internal.util.Context; import nl.jqno.equalsverifier.internal.util.Formatter; @@ -23,7 +24,7 @@ public MapEntryHashCodeRequirementChecker(Context context) { public void check() { if (Map.Entry.class.isAssignableFrom(config.getType())) { Map.Entry e = valueProvider - .>provideOrThrow(config.getTypeTag(), null) + .>provideOrThrow(config.getTypeTag(), Attributes.unlabeled()) .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 c2119280c..0ef963e88 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 @@ -14,6 +14,7 @@ import nl.jqno.equalsverifier.internal.reflection.annotations.SupportedAnnotations; import nl.jqno.equalsverifier.internal.reflection.instantiation.SubjectCreator; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.Configuration; import nl.jqno.equalsverifier.internal.util.Context; import nl.jqno.equalsverifier.internal.util.Formatter; @@ -64,7 +65,7 @@ public void execute(FieldProbe fieldProbe) { ); TypeTag sub = new TypeTag(throwingGetterCreator(getterName)); - Tuple tuple = valueProvider.provideOrThrow(sub, fieldName); + Tuple tuple = valueProvider.provideOrThrow(sub, Attributes.labeled(fieldName)); 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 fd2d98f06..e3d3b25b1 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 @@ -13,6 +13,7 @@ import nl.jqno.equalsverifier.internal.reflection.annotations.SupportedAnnotations; import nl.jqno.equalsverifier.internal.reflection.instantiation.SubjectCreator; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.Configuration; import nl.jqno.equalsverifier.internal.util.Context; import nl.jqno.equalsverifier.internal.util.Formatter; @@ -80,7 +81,7 @@ private void checkValueReflexivity(FieldProbe probe) { String fieldName = field.getName(); TypeTag tag = TypeTag.of(field, typeTag); Tuple tuple = valueProvider - .provide(tag, fieldName) + .provide(tag, Attributes.labeled(fieldName)) .orElseThrow(() -> new NoValueException(tag, fieldName)); Object left = subjectCreator.withFieldSetTo(field, tuple.getRed()); 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 6c67acc42..a90be9261 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 @@ -8,6 +8,7 @@ import nl.jqno.equalsverifier.internal.reflection.TypeTag; import nl.jqno.equalsverifier.internal.reflection.instantiation.SubjectCreator; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.CachedHashCodeInitializer; import nl.jqno.equalsverifier.internal.util.Formatter; @@ -42,7 +43,7 @@ public void execute(FieldProbe fieldProbe) { if (String.class.equals(fieldProbe.getType()) && !fieldProbe.isStatic()) { TypeTag string = new TypeTag(String.class); String red = valueProvider - .provideOrThrow(string, fieldProbe.getName()) + .provideOrThrow(string, Attributes.labeled(fieldProbe.getName())) .getRed(); final T reference; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/JavaApiPrefabValues.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/JavaApiPrefabValues.java index cadf7fcd3..1fe54c94d 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/JavaApiPrefabValues.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/JavaApiPrefabValues.java @@ -9,17 +9,18 @@ import java.beans.PropertyChangeSupport; import java.io.File; import java.io.PrintStream; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; -import java.net.*; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URL; import java.nio.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; +import java.text.*; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; @@ -28,12 +29,9 @@ import java.util.concurrent.locks.StampedLock; import java.util.function.Supplier; import java.util.regex.Pattern; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.EnumMapFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.EnumSetFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.ExternalFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.*; /** * Creates instances of classes for use in a {@link VintageValueProvider} object. diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProvider.java new file mode 100644 index 000000000..e564ecb99 --- /dev/null +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProvider.java @@ -0,0 +1,75 @@ +package nl.jqno.equalsverifier.internal.reflection.instantiation; + +import java.util.*; +import nl.jqno.equalsverifier.internal.reflection.Tuple; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; + +/** + * Provider of instances that have been created before, e.g. by other ValueProviders. + */ +public class CachedValueProvider implements ValueProvider { + + private final Map> cache = new HashMap<>(); + + /** + * Adds a value to the cache. + * + * @param tag The type to assign the value to. + * @param label The label that the value should be linked to. + * @param tuple The value to add to the cache. + */ + public void put(TypeTag tag, String label, Tuple tuple) { + cache.put(Key.of(tag, label), tuple); + } + + /** + * {@inheritDoc}} + */ + @SuppressWarnings("unchecked") + @Override + public Optional> provide(TypeTag tag, Attributes attributes) { + Key first = Key.of(tag, attributes.label); + if (cache.containsKey(first)) { + return Optional.of((Tuple) cache.get(first)); + } + Key second = Key.of(tag, null); + if (cache.containsKey(second)) { + return Optional.of((Tuple) cache.get(second)); + } + return Optional.empty(); + } + + static final class Key { + + final TypeTag tag; + final String label; + + private Key(TypeTag tag, String label) { + this.tag = tag; + this.label = label; + } + + public static Key of(TypeTag tag, String label) { + return new Key(tag, label); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Key)) { + return false; + } + Key other = (Key) obj; + return Objects.equals(tag, other.tag) && Objects.equals(label, other.label); + } + + @Override + public int hashCode() { + return Objects.hash(tag, label); + } + + @Override + public String toString() { + return "Key: [" + tag + "/" + label + "]"; + } + } +} diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProvider.java index f2c32e770..599444795 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProvider.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProvider.java @@ -1,5 +1,6 @@ package nl.jqno.equalsverifier.internal.reflection.instantiation; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -8,12 +9,19 @@ import nl.jqno.equalsverifier.internal.reflection.TypeTag; /** - * Provider of prefabricated instances of classes, delegating to other ValueProviders in sequence. + * Provider of instances of classes, delegating to other ValueProviders in sequence. */ public class ChainedValueProvider implements ValueProvider { private boolean locked = false; private final List providers = new ArrayList<>(); + private final CachedValueProvider cache; + + @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "A cache is inherently mutable") + public ChainedValueProvider(CachedValueProvider cache) { + this.cache = cache; + providers.add(cache); + } /** * Adds providers to the chain, so they can be delegated to when providing a value. @@ -34,12 +42,15 @@ public void register(ValueProvider... valueProviders) { /** {@inheritDoc} */ @Override - public Optional> provide(TypeTag tag, String label) { - return providers + public Optional> provide(TypeTag tag, Attributes attributes) { + Optional> result = providers .stream() - .map(vp -> vp.provide(tag, label)) + .map(vp -> vp.provide(tag, attributes)) .filter(Optional::isPresent) .findFirst() .orElse(Optional.empty()); + + result.ifPresent(r -> cache.put(tag, attributes.label, r)); + return result; } } 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 0e4a8f70a..56fd956fb 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 @@ -6,6 +6,7 @@ import java.util.Map; import nl.jqno.equalsverifier.internal.exceptions.ModuleException; import nl.jqno.equalsverifier.internal.reflection.*; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.util.Configuration; import nl.jqno.equalsverifier.internal.util.Rethrow; import org.objenesis.Objenesis; @@ -237,7 +238,10 @@ private FieldIterable nonSuperFields() { private Tuple valuesFor(Field f) { try { TypeTag fieldTag = TypeTag.of(f, typeTag); - Tuple tuple = valueProvider.provideOrThrow(fieldTag, f.getName()); + Tuple tuple = valueProvider.provideOrThrow( + fieldTag, + Attributes.labeled(f.getName()) + ); return tuple; } catch (ModuleException e) { throw new ModuleException( 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 cc37b9873..366f6963a 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,6 @@ package nl.jqno.equalsverifier.internal.reflection.instantiation; +import java.util.LinkedHashSet; import java.util.Optional; import nl.jqno.equalsverifier.internal.exceptions.NoValueException; import nl.jqno.equalsverifier.internal.reflection.Tuple; @@ -21,12 +22,11 @@ public interface ValueProvider { * * @param The returned tuple will have this generic type. * @param tag A description of the desired type, including generic parameters. - * @param label Returns only the value assigned to the given label, or if label is null, - * returns the value that's not assigned to any label. + * @param attributes Provides metadata needed to provide a value. * @return A tuple of two different values of the given type, or an empty Optional if none * could be found. */ - Optional> provide(TypeTag tag, String label); + Optional> provide(TypeTag tag, Attributes attributes); /** * Returns a tuple of prefabricated values of the specified type, or, if none exists, throws a @@ -34,13 +34,66 @@ public interface ValueProvider { * * @param The returned tuple will have this generic type. * @param tag A description of the desired type, including generic parameters. - * @param label Returns only the value assigned to the given label, or if label is null, - * returns the value that's not assigned to any label. + * @param attributes Provides metadata needed to provide a value. * @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, String label) { - return this.provide(tag, label).orElseThrow(() -> new NoValueException(tag)); + default Tuple provideOrThrow(TypeTag tag, Attributes attributes) { + return this.provide(tag, attributes).orElseThrow(() -> new NoValueException(tag)); + } + + /** + * Container for metadata needed to provide values. + */ + public static final class Attributes { + + /** + * Values can be assigned to a label; if one is specified, ValueProvider returns the value + * assigned to it (or falls back to the value assigned to a null label). If label is null, + * it immediately returns the value assigned to the null label. + */ + public final String label; + /** + * Keeps track of recursion. + */ + public final LinkedHashSet typeStack; + + /** Private constructor. Use the factories instead. */ + private Attributes(String label, LinkedHashSet typeStack) { + this.label = label; + this.typeStack = typeStack; + } + + /** + * Don't use a label when providing a value. + * + * @return An Attributes object with no label. + */ + public static Attributes unlabeled() { + return new Attributes(null, new LinkedHashSet<>()); + } + + /** + * Use a label when providing a value. + * + * @param label The label to use. + * @return An Attributes object with the given label. + */ + public static Attributes labeled(String label) { + return new Attributes(label, new LinkedHashSet<>()); + } + + /** + * Clones the internal typeStack and adds a type to it. + * + * @param tag A type to add to the recursion checker. + * @return A new Attributes object with a type added to its typeStack. + */ + public Attributes cloneAndAdd(TypeTag tag) { + LinkedHashSet clone = new LinkedHashSet<>(typeStack); + clone.add(tag); + return new Attributes(label, clone); + } } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessor.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessor.java deleted file mode 100644 index e19fde95d..000000000 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessor.java +++ /dev/null @@ -1,108 +0,0 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; - -import java.util.LinkedHashSet; -import nl.jqno.equalsverifier.internal.reflection.Instantiator; -import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; -import org.objenesis.Objenesis; - -/** - * Instantiates and populates objects of a given class. {@link ClassAccessor} can create two - * different instances of T, which are guaranteed not to be equal to each other, and which contain - * no null values. - * - * @param A class. - */ -public class ClassAccessor { - - private final Class type; - private final VintageValueProvider valueProvider; - private final Objenesis objenesis; - - /** Private constructor. Call {@link #of(Class, PrefabValues)} instead. */ - ClassAccessor(Class type, VintageValueProvider valueProvider, Objenesis objenesis) { - this.type = type; - this.valueProvider = valueProvider; - this.objenesis = objenesis; - } - - /** - * Factory method. - * - * @param The class on which {@link ClassAccessor} operates. - * @param type The class on which {@link ClassAccessor} operates. Should be the same as T. - * @param valueProvider Prefabricated values with which to fill instantiated objects. - * @param objenesis To instantiate non-record classes. - * @return A {@link ClassAccessor} for T. - */ - public static ClassAccessor of( - Class type, - VintageValueProvider valueProvider, - Objenesis objenesis - ) { - return new ClassAccessor<>(type, valueProvider, objenesis); - } - - /** - * Returns an instance of T that is not equal to the instance of T returned by {@link - * #getBlueObject(TypeTag, LinkedHashSet)}. - * - * @param enclosingType Describes the type that contains this object as a field, to determine - * any generic parameters it may contain. - * @param typeStack Keeps track of recursion in the type. - * @return An instance of T. - */ - public T getRedObject(TypeTag enclosingType, LinkedHashSet typeStack) { - return getRedAccessor(enclosingType, typeStack).get(); - } - - /** - * Returns an {@link ObjectAccessor} for {@link #getRedObject(TypeTag, LinkedHashSet)}. - * - * @param enclosingType Describes the type that contains this object as a field, to determine - * any generic parameters it may contain. - * @param typeStack Keeps track of recursion in the type. - * @return An {@link ObjectAccessor} for {@link #getRedObject}. - */ - public ObjectAccessor getRedAccessor( - TypeTag enclosingType, - LinkedHashSet typeStack - ) { - return buildObjectAccessor().scramble(valueProvider, enclosingType, typeStack); - } - - /** - * Returns an instance of T that is not equal to the instance of T returned by {@link - * #getRedObject(TypeTag, LinkedHashSet)}. - * - * @param enclosingType Describes the type that contains this object as a field, to determine - * any generic parameters it may contain. - * @param typeStack Keeps track of recursion in the type. - * @return An instance of T. - */ - public T getBlueObject(TypeTag enclosingType, LinkedHashSet typeStack) { - return getBlueAccessor(enclosingType, typeStack).get(); - } - - /** - * Returns an {@link ObjectAccessor} for {@link #getBlueObject(TypeTag, LinkedHashSet)}. - * - * @param enclosingType Describes the type that contains this object as a field, to determine - * any generic parameters it may contain. - * @param typeStack Keeps track of recursion in the type. - * @return An {@link ObjectAccessor} for {@link #getBlueObject(TypeTag, LinkedHashSet)}. - */ - public ObjectAccessor getBlueAccessor( - TypeTag enclosingType, - LinkedHashSet typeStack - ) { - return buildObjectAccessor() - .scramble(valueProvider, enclosingType, typeStack) - .scramble(valueProvider, enclosingType, typeStack); - } - - private ObjectAccessor buildObjectAccessor() { - T object = Instantiator.of(type, objenesis).instantiate(); - return ObjectAccessor.of(object); - } -} diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCache.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCache.java index 528867fef..61ea3e55b 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCache.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCache.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; /** Contains a cache of factories, for {@link VintageValueProvider}. */ @@ -141,7 +140,7 @@ private void addAll(FactoryCache to, FactoryCache from) { } } - private static final class Key { + static final class Key { final String typeName; final String label; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApi.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApi.java similarity index 95% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApi.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApi.java index 529ec513c..0b1a86954 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApi.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApi.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.util; +package nl.jqno.equalsverifier.internal.reflection.vintage; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.simple; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; @@ -7,9 +7,9 @@ import nl.jqno.equalsverifier.Func.Func1; import nl.jqno.equalsverifier.Func.Func2; import nl.jqno.equalsverifier.internal.reflection.SuperclassIterable; -import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; -import nl.jqno.equalsverifier.internal.reflection.vintage.ObjectAccessor; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.ObjectAccessor; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; +import nl.jqno.equalsverifier.internal.util.Validations; import org.objenesis.Objenesis; public final class PrefabValuesApi { 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/vintage/VintageValueProvider.java similarity index 60% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProvider.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/VintageValueProvider.java index aab525544..c3e6ef616 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/vintage/VintageValueProvider.java @@ -1,12 +1,14 @@ -package nl.jqno.equalsverifier.internal.reflection.instantiation; +package nl.jqno.equalsverifier.internal.reflection.vintage; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.*; +import java.util.Arrays; +import java.util.Optional; import nl.jqno.equalsverifier.internal.exceptions.RecursionException; import nl.jqno.equalsverifier.internal.exceptions.ReflectionException; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.FallbackFactory; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; import nl.jqno.equalsverifier.internal.util.PrimitiveMappers; @@ -22,8 +24,6 @@ */ public class VintageValueProvider implements ValueProvider { - private final Map> valueCache = new HashMap<>(); - private final ValueProvider valueProvider; private final FactoryCache factoryCache; private final PrefabValueFactory fallbackFactory; @@ -32,12 +32,14 @@ public class VintageValueProvider implements ValueProvider { * Constructor. * * @param valueProvider Will be used to look up values before they are created. + * @param cache The values that have already been constructed. * @param factoryCache The factories that can be used to create values. * @param objenesis To instantiate non-record classes. */ @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "A cache is inherently mutable.") public VintageValueProvider( ValueProvider valueProvider, + CachedValueProvider cache, FactoryCache factoryCache, Objenesis objenesis ) { @@ -48,8 +50,8 @@ public VintageValueProvider( /** {@inheritDoc} */ @Override - public Optional> provide(TypeTag tag, String label) { - return Rethrow.rethrow(() -> Optional.of(giveTuple(tag, label))); + public Optional> provide(TypeTag tag, Attributes attributes) { + return Rethrow.rethrow(() -> Optional.of(giveTuple(tag, attributes))); } /** @@ -62,7 +64,11 @@ public Optional> provide(TypeTag tag, String label) { * @return The "red" prefabricated value. */ public T giveRed(TypeTag tag) { - return this.giveTuple(tag, null).getRed(); + return giveRed(tag, Attributes.unlabeled()); + } + + public T giveRed(TypeTag tag, Attributes attributes) { + return this.giveTuple(tag, attributes).getRed(); } /** @@ -75,7 +81,11 @@ public T giveRed(TypeTag tag) { * @return The "blue" prefabricated value. */ public T giveBlue(TypeTag tag) { - return this.giveTuple(tag, null).getBlue(); + return giveBlue(tag, Attributes.unlabeled()); + } + + public T giveBlue(TypeTag tag, Attributes attributes) { + return this.giveTuple(tag, attributes).getBlue(); } /** @@ -88,7 +98,11 @@ public T giveBlue(TypeTag tag) { * @return A shallow copy of the "red" prefabricated value. */ public T giveRedCopy(TypeTag tag) { - return this.giveTuple(tag, null).getRedCopy(); + return giveRedCopy(tag, Attributes.unlabeled()); + } + + public T giveRedCopy(TypeTag tag, Attributes attributes) { + return this.giveTuple(tag, attributes).getRedCopy(); } /** @@ -98,11 +112,11 @@ public T giveRedCopy(TypeTag tag) { * @param The type of the value. * @param tag A description of the desired type, including generic parameters. * @param value A value that is different from the value that will be returned. - * @param typeStack Keeps track of recursion in the type. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. * @return A value that is different from {@code value}. */ // CHECKSTYLE OFF: CyclomaticComplexity - public T giveOther(TypeTag tag, T value, LinkedHashSet typeStack) { + public T giveOther(TypeTag tag, T value, Attributes attributes) { Class type = tag.getType(); if ( value != null && @@ -112,7 +126,7 @@ public T giveOther(TypeTag tag, T value, LinkedHashSet typeStack) { throw new ReflectionException("TypeTag does not match value."); } - Tuple tuple = giveTuple(tag, null, typeStack); + Tuple tuple = giveTuple(tag, attributes); if (tuple.getRed() == null) { return null; } @@ -143,101 +157,27 @@ private boolean arraysAreDeeplyEqual(Object x, Object y) { return Arrays.deepEquals(new Object[] { x }, new Object[] { y }); } - /** - * Makes sure that values for the specified type are present in the cache, but doesn't return - * them. - * - * @param The desired type. - * @param tag A description of the desired type, including generic parameters. - * @param typeStack Keeps track of recursion in the type. - */ - public void realizeCacheFor(TypeTag tag, LinkedHashSet typeStack) { - realizeCacheFor(tag, null, typeStack); - } - - /** - * Makes sure that values for the specified type are present in the cache, but doesn't return - * them. - * - * @param The desired type. - * @param tag A description of the desired type, including generic parameters. - * @param label Adds the value assigned to the given label, if a label is given. - * @param typeStack Keeps track of recursion in the type. - */ - public void realizeCacheFor(TypeTag tag, String label, LinkedHashSet typeStack) { - Key key = Key.of(tag, label); - if (!valueCache.containsKey(key)) { - Tuple tuple = createTuple(tag, label, typeStack); - valueCache.put(key, tuple); - } - } - - private Tuple giveTuple(TypeTag tag, String label) { - return giveTuple(tag, label, new LinkedHashSet<>()); - } - @SuppressWarnings("unchecked") - private Tuple giveTuple(TypeTag tag, String label, LinkedHashSet typeStack) { - realizeCacheFor(tag, label, typeStack); - return (Tuple) valueCache.get(Key.of(tag, label)); - } - - private Tuple createTuple(TypeTag tag, String label, LinkedHashSet typeStack) { - if (typeStack.contains(tag)) { - throw new RecursionException(typeStack); + private Tuple giveTuple(TypeTag tag, Attributes attributes) { + if (attributes.typeStack.contains(tag)) { + throw new RecursionException(attributes.typeStack); } - Optional> provided = valueProvider.provide(tag, null); + Optional> provided = valueProvider.provide(tag, attributes); if (provided.isPresent()) { return provided.get(); } Class type = tag.getType(); - if (label != null && factoryCache.contains(type, label)) { - PrefabValueFactory factory = factoryCache.get(type, label); - return factory.createValues(tag, this, typeStack); + if (attributes.label != null && factoryCache.contains(type, attributes.label)) { + PrefabValueFactory factory = factoryCache.get(type, attributes.label); + return factory.createValues(tag, this, attributes); } if (factoryCache.contains(type)) { PrefabValueFactory factory = factoryCache.get(type); - return factory.createValues(tag, this, typeStack); + return factory.createValues(tag, this, attributes); } - @SuppressWarnings("unchecked") - Tuple result = (Tuple) fallbackFactory.createValues(tag, this, typeStack); - return result; - } - - private static final class Key { - - final TypeTag tag; - final String label; - - private Key(TypeTag tag, String label) { - this.tag = tag; - this.label = label; - } - - public static Key of(TypeTag tag, String label) { - return new Key(tag, label); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Key)) { - return false; - } - Key other = (Key) obj; - return Objects.equals(tag, other.tag) && Objects.equals(label, other.label); - } - - @Override - public int hashCode() { - return Objects.hash(tag, label); - } - - @Override - public String toString() { - return "Key: [" + tag + "/" + label + "]"; - } + return (Tuple) fallbackFactory.createValues(tag, this, attributes); } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessor.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessor.java new file mode 100644 index 000000000..bc4757e96 --- /dev/null +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessor.java @@ -0,0 +1,68 @@ +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; + +import nl.jqno.equalsverifier.internal.reflection.Instantiator; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; +import org.objenesis.Objenesis; + +/** + * Instantiates and populates objects of a given class. {@link ClassAccessor} can create two + * different instances of T, which are guaranteed not to be equal to each other, and which contain + * no null values. + * + * @param A class. + */ +public class ClassAccessor { + + private final Class type; + private final VintageValueProvider valueProvider; + private final Objenesis objenesis; + + /** + * Constructor. + * + * @param type The class on which {@link ClassAccessor} operates. Should be the same as T. + * @param valueProvider Prefabricated values with which to fill instantiated objects. + * @param objenesis To instantiate non-record classes. + */ + public ClassAccessor(Class type, VintageValueProvider valueProvider, Objenesis objenesis) { + this.type = type; + this.valueProvider = valueProvider; + this.objenesis = objenesis; + } + + /** + * Returns an instance of T that is not equal to the instance of T returned by {@link + * #getBlueObject(TypeTag, Attributes)}. + * + * @param enclosingType Describes the type that contains this object as a field, to determine + * any generic parameters it may contain. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. + * @return An instance of T. + */ + public T getRedObject(TypeTag enclosingType, Attributes attributes) { + return buildObjectAccessor().scramble(valueProvider, enclosingType, attributes).get(); + } + + /** + * Returns an instance of T that is not equal to the instance of T returned by {@link + * #getRedObject(TypeTag, Attributes)}. + * + * @param enclosingType Describes the type that contains this object as a field, to determine + * any generic parameters it may contain. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. + * @return An instance of T. + */ + public T getBlueObject(TypeTag enclosingType, Attributes attributes) { + return buildObjectAccessor() + .scramble(valueProvider, enclosingType, attributes) + .scramble(valueProvider, enclosingType, attributes) + .get(); + } + + private ObjectAccessor buildObjectAccessor() { + T object = Instantiator.of(type, objenesis).instantiate(); + return ObjectAccessor.of(object); + } +} diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifier.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifier.java similarity index 91% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifier.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifier.java index 0b91e5f87..fd5725b16 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifier.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifier.java @@ -1,13 +1,13 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static nl.jqno.equalsverifier.internal.util.Rethrow.rethrow; import java.lang.reflect.Field; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.exceptions.ReflectionException; import nl.jqno.equalsverifier.internal.reflection.FieldProbe; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; public final class FieldModifier { @@ -53,17 +53,17 @@ public void copyTo(Object to) { * will be taken from it. * @param enclosingType A tag for the type that contains the field. Needed to determine a * generic type, if it has one.. - * @param typeStack Keeps track of recursion in the type. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. * @throws ReflectionException If the operation fails. */ public void changeField( VintageValueProvider valueProvider, TypeTag enclosingType, - LinkedHashSet typeStack + Attributes attributes ) { FieldChanger fm = () -> { TypeTag tag = TypeTag.of(field, enclosingType); - Object newValue = valueProvider.giveOther(tag, field.get(object), typeStack); + Object newValue = valueProvider.giveOther(tag, field.get(object), attributes); field.set(object, newValue); }; change(fm, false); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessor.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessor.java similarity index 86% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessor.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessor.java index c9cf1c573..89943838f 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessor.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessor.java @@ -1,11 +1,11 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import java.lang.reflect.Field; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.FieldIterable; import nl.jqno.equalsverifier.internal.reflection.Instantiator; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import org.objenesis.Objenesis; /** @@ -35,10 +35,10 @@ public T copy(Objenesis objenesis) { public ObjectAccessor scramble( VintageValueProvider valueProvider, TypeTag enclosingType, - LinkedHashSet typeStack + Attributes attributes ) { for (Field field : FieldIterable.of(type())) { - fieldModifierFor(field).changeField(valueProvider, enclosingType, typeStack); + fieldModifierFor(field).changeField(valueProvider, enclosingType, attributes); } return this; } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ObjectAccessor.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ObjectAccessor.java similarity index 91% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ObjectAccessor.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ObjectAccessor.java index 480e30224..7cdd484cb 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/ObjectAccessor.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ObjectAccessor.java @@ -1,9 +1,9 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.RecordsHelper; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import org.objenesis.Objenesis; /** @@ -95,12 +95,12 @@ public Class type() { * @param valueProvider Prefabricated values to take values from. * @param enclosingType Describes the type that contains this object as a field, to determine * any generic parameters it may contain. - * @param typeStack Keeps track of recursion in the type. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. * @return An accessor to the scrambled object. */ public abstract ObjectAccessor scramble( VintageValueProvider valueProvider, TypeTag enclosingType, - LinkedHashSet typeStack + Attributes attributes ); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessor.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessor.java similarity index 88% rename from equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessor.java rename to equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessor.java index c1f63ea44..98a80dd49 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/RecordObjectAccessor.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/RecordObjectAccessor.java @@ -1,14 +1,14 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import java.lang.reflect.Field; -import java.util.LinkedHashSet; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import nl.jqno.equalsverifier.internal.reflection.FieldProbe; import nl.jqno.equalsverifier.internal.reflection.RecordProbe; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import org.objenesis.Objenesis; /** @@ -40,12 +40,12 @@ public T copy(Objenesis objenesis) { public ObjectAccessor scramble( VintageValueProvider valueProvider, TypeTag enclosingType, - LinkedHashSet typeStack + Attributes attributes ) { return makeAccessor(f -> { Object value = getField(f); TypeTag tag = TypeTag.of(f, enclosingType); - return valueProvider.giveOther(tag, value, typeStack); + return valueProvider.giveOther(tag, value, attributes); }); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactory.java index 0058867ad..7587ac03d 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactory.java @@ -4,11 +4,11 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import nl.jqno.equalsverifier.internal.exceptions.ReflectionException; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; /** * Abstract implementation of {@link PrefabValueFactory} that provides helper functions for dealing @@ -18,13 +18,6 @@ public abstract class AbstractGenericFactory implements PrefabValueFactory public static final TypeTag OBJECT_TYPE_TAG = new TypeTag(Object.class); - protected LinkedHashSet cloneWith(LinkedHashSet typeStack, TypeTag tag) { - @SuppressWarnings("unchecked") - LinkedHashSet clone = (LinkedHashSet) typeStack.clone(); - clone.add(tag); - return clone; - } - protected TypeTag copyGenericTypesInto(Class type, TypeTag source) { List genericTypes = new ArrayList<>(); for (TypeTag tag : source.getGenericTypes()) { @@ -37,23 +30,22 @@ protected TypeTag determineAndCacheActualTypeTag( int n, TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - return determineAndCacheActualTypeTag(n, tag, valueProvider, typeStack, null); + return determineAndCacheActualTypeTag(n, tag, valueProvider, attributes, null); } protected TypeTag determineAndCacheActualTypeTag( int n, TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack, + Attributes attributes, Class bottomType ) { TypeTag result = determineActualTypeTagFor(n, tag); if (bottomType != null && result.getType().equals(Object.class)) { result = new TypeTag(bottomType); } - valueProvider.realizeCacheFor(result, typeStack); return result; } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/CopyFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/CopyFactory.java index 1b1222861..5b8f782c1 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/CopyFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/CopyFactory.java @@ -1,10 +1,10 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; -import java.util.LinkedHashSet; import java.util.function.Function; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; public class CopyFactory extends AbstractGenericFactory { @@ -20,15 +20,14 @@ public CopyFactory(Class source, Function copy) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag sourceTag = copyGenericTypesInto(source, tag); - valueProvider.realizeCacheFor(sourceTag, clone); - S redSource = valueProvider.giveRed(sourceTag); - S blueSource = valueProvider.giveBlue(sourceTag); - S redCopySource = valueProvider.giveRedCopy(sourceTag); + S redSource = valueProvider.giveRed(sourceTag, clone); + S blueSource = valueProvider.giveBlue(sourceTag, clone); + S redCopySource = valueProvider.giveRedCopy(sourceTag, clone); return Tuple.of(copy.apply(redSource), copy.apply(blueSource), copy.apply(redCopySource)); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumMapFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumMapFactory.java index 5b1424694..abbf32cac 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumMapFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumMapFactory.java @@ -1,12 +1,12 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.Map; import java.util.function.Function; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; @SuppressWarnings({ "unchecked", "rawtypes" }) public final class EnumMapFactory extends AbstractGenericFactory { @@ -21,18 +21,18 @@ public EnumMapFactory(Function factory) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag keyTag = determineAndCacheActualTypeTag(0, tag, valueProvider, clone, Enum.class); TypeTag valueTag = determineAndCacheActualTypeTag(1, tag, valueProvider, clone, Enum.class); Map red = new HashMap<>(); Map blue = new HashMap<>(); Map redCopy = new HashMap<>(); - red.put(valueProvider.giveRed(keyTag), valueProvider.giveBlue(valueTag)); - blue.put(valueProvider.giveBlue(keyTag), valueProvider.giveBlue(valueTag)); - redCopy.put(valueProvider.giveRed(keyTag), valueProvider.giveBlue(valueTag)); + red.put(valueProvider.giveRed(keyTag, clone), valueProvider.giveBlue(valueTag, clone)); + blue.put(valueProvider.giveBlue(keyTag, clone), valueProvider.giveBlue(valueTag, clone)); + redCopy.put(valueProvider.giveRed(keyTag, clone), valueProvider.giveBlue(valueTag, clone)); return Tuple.of(factory.apply(red), factory.apply(blue), factory.apply(redCopy)); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumSetFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumSetFactory.java index 61a59e447..f6dae8634 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumSetFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/EnumSetFactory.java @@ -2,11 +2,11 @@ import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.function.Function; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; /** * Implementation of {@link PrefabValueFactory} that instantiates EnumSets using reflection, while @@ -25,17 +25,17 @@ public EnumSetFactory(Function factory) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag entryTag = determineAndCacheActualTypeTag(0, tag, valueProvider, clone, Enum.class); Collection red = new HashSet<>(); Collection blue = new HashSet<>(); Collection redCopy = new HashSet<>(); - red.add(valueProvider.giveRed(entryTag)); - blue.add(valueProvider.giveBlue(entryTag)); - redCopy.add(valueProvider.giveRed(entryTag)); + red.add(valueProvider.giveRed(entryTag, clone)); + blue.add(valueProvider.giveBlue(entryTag, clone)); + redCopy.add(valueProvider.giveRed(entryTag, clone)); return new Tuple<>(factory.apply(red), factory.apply(blue), factory.apply(redCopy)); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/ExternalFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/ExternalFactory.java index d458ee0a7..d777d7a64 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/ExternalFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/ExternalFactory.java @@ -3,12 +3,12 @@ import static nl.jqno.equalsverifier.internal.reflection.Util.classes; import static nl.jqno.equalsverifier.internal.reflection.Util.objects; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.ConditionalInstantiator; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factoryproviders.FactoryProvider; public class ExternalFactory implements PrefabValueFactory { @@ -27,7 +27,7 @@ public ExternalFactory(String factoryName) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { if (factoryCache == null) { ConditionalInstantiator ci = new ConditionalInstantiator(factoryName); @@ -36,6 +36,6 @@ public Tuple createValues( } PrefabValueFactory factory = factoryCache.get(tag.getType()); - return factory.createValues(tag, valueProvider, typeStack); + return factory.createValues(tag, valueProvider, attributes); } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactory.java index eb69ea6b3..917f7eb88 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactory.java @@ -1,14 +1,13 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.util.LinkedHashSet; -import nl.jqno.equalsverifier.internal.reflection.FieldIterable; -import nl.jqno.equalsverifier.internal.reflection.FieldProbe; +import nl.jqno.equalsverifier.internal.reflection.ClassProbe; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; -import nl.jqno.equalsverifier.internal.reflection.vintage.ClassAccessor; +import nl.jqno.equalsverifier.internal.reflection.instantiation.InstanceCreator; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.ClassAccessor; import org.objenesis.Objenesis; /** @@ -29,11 +28,9 @@ public FallbackFactory(Objenesis objenesis) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - @SuppressWarnings("unchecked") - LinkedHashSet clone = (LinkedHashSet) typeStack.clone(); - clone.add(tag); + Attributes clone = attributes.cloneAndAdd(tag); Class type = tag.getType(); if (type.isEnum()) { @@ -43,7 +40,6 @@ public Tuple createValues( return giveArrayInstances(tag, valueProvider, clone); } - traverseFields(tag, valueProvider, clone); return giveInstances(tag, valueProvider, clone); } @@ -65,47 +61,35 @@ private Tuple giveEnumInstances(TypeTag tag) { private Tuple giveArrayInstances( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { Class type = tag.getType(); Class componentType = type.getComponentType(); TypeTag componentTag = new TypeTag(componentType); - valueProvider.realizeCacheFor(componentTag, typeStack); T red = (T) Array.newInstance(componentType, 1); - Array.set(red, 0, valueProvider.giveRed(componentTag)); + Array.set(red, 0, valueProvider.giveRed(componentTag, attributes)); T blue = (T) Array.newInstance(componentType, 1); - Array.set(blue, 0, valueProvider.giveBlue(componentTag)); + Array.set(blue, 0, valueProvider.giveBlue(componentTag, attributes)); T redCopy = (T) Array.newInstance(componentType, 1); - Array.set(redCopy, 0, valueProvider.giveRed(componentTag)); + Array.set(redCopy, 0, valueProvider.giveRed(componentTag, attributes)); return new Tuple<>(red, blue, redCopy); } - private void traverseFields( - TypeTag tag, - VintageValueProvider valueProvider, - LinkedHashSet typeStack - ) { - Class type = tag.getType(); - for (Field field : FieldIterable.of(type)) { - FieldProbe probe = FieldProbe.of(field); - boolean isStaticAndFinal = probe.isStatic() && probe.isFinal(); - if (!isStaticAndFinal) { - valueProvider.realizeCacheFor(TypeTag.of(field, tag), typeStack); - } - } - } - private Tuple giveInstances( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - ClassAccessor accessor = ClassAccessor.of(tag.getType(), valueProvider, objenesis); - T red = accessor.getRedObject(tag, typeStack); - T blue = accessor.getBlueObject(tag, typeStack); - T redCopy = accessor.getRedObject(tag, typeStack); + ClassAccessor accessor = new ClassAccessor<>(tag.getType(), valueProvider, objenesis); + T red = accessor.getRedObject(tag, attributes); + T blue = accessor.getBlueObject(tag, attributes); + + @SuppressWarnings("unchecked") + Class actualType = (Class) red.getClass(); + T redCopy = new InstanceCreator<>(new ClassProbe(actualType), objenesis).copy(red); + return new Tuple<>(red, blue, redCopy); } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactory.java index f835cfe90..40030f4de 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactory.java @@ -1,11 +1,11 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; -import java.util.LinkedHashSet; import java.util.Map; import java.util.function.Supplier; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; /** * Implementation of {@link PrefabValueFactory} that specializes in creating implementations of @@ -24,9 +24,9 @@ public MapFactory(Supplier createEmpty) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag keyTag = determineAndCacheActualTypeTag(0, tag, valueProvider, clone); TypeTag valueTag = determineAndCacheActualTypeTag(1, tag, valueProvider, clone); @@ -34,16 +34,16 @@ public Tuple createValues( // values. // But don't do it in the Blue map, or they may cancel each other out again. - Object redKey = valueProvider.giveRed(keyTag); - Object blueKey = valueProvider.giveBlue(keyTag); - Object blueValue = valueProvider.giveBlue(valueTag); + Object redKey = valueProvider.giveRed(keyTag, clone); + Object blueKey = valueProvider.giveBlue(keyTag, clone); + Object blueValue = valueProvider.giveBlue(valueTag, clone); T red = createEmpty.get(); red.put(redKey, blueValue); T blue = createEmpty.get(); if (!redKey.equals(blueKey)) { // This happens with single-element enums - blue.put(valueProvider.giveBlue(keyTag), blueValue); + blue.put(valueProvider.giveBlue(keyTag, clone), blueValue); } T redCopy = createEmpty.get(); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/PrefabValueFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/PrefabValueFactory.java index 4616c2660..e7c2c3c13 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/PrefabValueFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/PrefabValueFactory.java @@ -1,9 +1,9 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; /** * Creates instances of generic types for use as prefab value. @@ -17,13 +17,8 @@ public interface PrefabValueFactory { * * @param tag The typetag of the type for which to create values. * @param valueProvider Repository for querying instances of generic types of the type tag. - * @param typeStack A stack of {@link TypeTag}s that require tag in order to be created. Used - * for recursion detection. + * @param attributes Provides metadata needed to provide a value and to keep track of recursion. * @return A "red" instance of {@code T}. */ - Tuple createValues( - TypeTag tag, - VintageValueProvider valueProvider, - LinkedHashSet typeStack - ); + Tuple createValues(TypeTag tag, VintageValueProvider valueProvider, Attributes attributes); } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleFactory.java index 44a7ae041..3012b2cf5 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleFactory.java @@ -1,9 +1,9 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; /** * Implementation of {@link PrefabValueFactory} that holds on to two instances that have already @@ -21,7 +21,7 @@ public SimpleFactory(T red, T blue, T redCopy) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { return tuple; } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactory.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactory.java index 748f64f7f..558a8465b 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactory.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactory.java @@ -1,13 +1,13 @@ package nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import java.util.function.Supplier; import nl.jqno.equalsverifier.Func; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; public class SimpleGenericFactory extends AbstractGenericFactory { @@ -23,9 +23,9 @@ public SimpleGenericFactory(Func factory, Supplier emptyFactory) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); List redValues = new ArrayList<>(); List blueValues = new ArrayList<>(); @@ -35,8 +35,8 @@ public Tuple createValues( for (int i = 0; i < n; i++) { TypeTag paramTag = determineAndCacheActualTypeTag(i, tag, valueProvider, clone); - Object redValue = valueProvider.giveRed(paramTag); - Object blueValue = valueProvider.giveBlue(paramTag); + Object redValue = valueProvider.giveRed(paramTag, clone); + Object blueValue = valueProvider.giveBlue(paramTag, clone); if (redValue.equals(blueValue)) { // This happens with single-element enums useEmpty = true; } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/GuavaFactoryProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/GuavaFactoryProvider.java index cf571ca2f..e9860bd40 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/GuavaFactoryProvider.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/GuavaFactoryProvider.java @@ -8,12 +8,10 @@ import java.util.function.Supplier; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.AbstractGenericFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.EnumMapFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.EnumSetFactory; -import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.*; public final class GuavaFactoryProvider implements FactoryProvider { @@ -160,18 +158,24 @@ private MultimapFactory(Supplier factory) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag keyTag = determineAndCacheActualTypeTag(0, tag, valueProvider, clone); TypeTag valueTag = determineAndCacheActualTypeTag(1, tag, valueProvider, clone); T red = factory.get(); T blue = factory.get(); T redCopy = factory.get(); - red.put(valueProvider.giveRed(keyTag), valueProvider.giveBlue(valueTag)); - blue.put(valueProvider.giveBlue(keyTag), valueProvider.giveBlue(valueTag)); - redCopy.put(valueProvider.giveRed(keyTag), valueProvider.giveBlue(valueTag)); + red.put(valueProvider.giveRed(keyTag, clone), valueProvider.giveBlue(valueTag, clone)); + blue.put( + valueProvider.giveBlue(keyTag, clone), + valueProvider.giveBlue(valueTag, clone) + ); + redCopy.put( + valueProvider.giveRed(keyTag, clone), + valueProvider.giveBlue(valueTag, clone) + ); return Tuple.of(red, blue, redCopy); } @@ -190,9 +194,9 @@ private TableFactory(Supplier factory) { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { - LinkedHashSet clone = cloneWith(typeStack, tag); + Attributes clone = attributes.cloneAndAdd(tag); TypeTag columnTag = determineAndCacheActualTypeTag(0, tag, valueProvider, clone); TypeTag rowTag = determineAndCacheActualTypeTag(1, tag, valueProvider, clone); TypeTag valueTag = determineAndCacheActualTypeTag(2, tag, valueProvider, clone); @@ -201,19 +205,19 @@ public Tuple createValues( T blue = factory.get(); T redCopy = factory.get(); red.put( - valueProvider.giveRed(columnTag), - valueProvider.giveRed(rowTag), - valueProvider.giveBlue(valueTag) + valueProvider.giveRed(columnTag, clone), + valueProvider.giveRed(rowTag, clone), + valueProvider.giveBlue(valueTag, clone) ); blue.put( - valueProvider.giveBlue(columnTag), - valueProvider.giveBlue(rowTag), - valueProvider.giveBlue(valueTag) + valueProvider.giveBlue(columnTag, clone), + valueProvider.giveBlue(rowTag, clone), + valueProvider.giveBlue(valueTag, clone) ); redCopy.put( - valueProvider.giveRed(columnTag), - valueProvider.giveRed(rowTag), - valueProvider.giveBlue(valueTag) + valueProvider.giveRed(columnTag, clone), + valueProvider.giveRed(rowTag, clone), + valueProvider.giveBlue(valueTag, clone) ); return Tuple.of(red, blue, redCopy); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProvider.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProvider.java index 9d6496d4c..f601fa8cb 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProvider.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProvider.java @@ -5,11 +5,16 @@ import static nl.jqno.equalsverifier.internal.reflection.Util.objects; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.copy; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Function; -import nl.jqno.equalsverifier.internal.reflection.*; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.ConditionalInstantiator; +import nl.jqno.equalsverifier.internal.reflection.Tuple; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.AbstractGenericFactory; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; @@ -109,22 +114,22 @@ static final class PropertyFactory extends AbstractGenericFactory { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { ConditionalInstantiator ci = new ConditionalInstantiator(fullyQualifiedTypeName); TypeTag singleParameterTag = copyGenericTypesInto(parameterRawType, tag); T red = ci.instantiate( classes(parameterRawType), - objects(valueProvider.giveRed(singleParameterTag)) + objects(valueProvider.giveRed(singleParameterTag, attributes)) ); T blue = ci.instantiate( classes(parameterRawType), - objects(valueProvider.giveBlue(singleParameterTag)) + objects(valueProvider.giveBlue(singleParameterTag, attributes)) ); T redCopy = ci.instantiate( classes(parameterRawType), - objects(valueProvider.giveRed(singleParameterTag)) + objects(valueProvider.giveRed(singleParameterTag, attributes)) ); return Tuple.of(red, blue, redCopy); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/testhelpers/TestValueProviders.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/testhelpers/TestValueProviders.java index 7c0a56187..3e971ef63 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/testhelpers/TestValueProviders.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/testhelpers/TestValueProviders.java @@ -1,45 +1,18 @@ package nl.jqno.equalsverifier.internal.testhelpers; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Optional; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; -@SuppressFBWarnings( - value = "DM_STRING_CTOR", - justification = "We really do need a separate instances with the same value" -) public final class TestValueProviders { - public static final Tuple INTS = Tuple.of(42, 1337, 42); - public static final Tuple STRINGS = Tuple.of("abc", "xyz", new String("abc")); - private TestValueProviders() {} public static ValueProvider empty() { return new ValueProvider() { @Override - public Optional> provide(TypeTag tag, String label) { - return Optional.empty(); - } - }; - } - - public static ValueProvider simple() { - return new ValueProvider() { - @SuppressWarnings("unchecked") - @Override - public Optional> provide(TypeTag tag, String label) { - if (tag.getType().equals(int.class)) { - return Optional.of((Tuple) INTS); - } - if (tag.getType().equals(Integer.class)) { - return Optional.of((Tuple) INTS); - } - if (tag.getType().equals(String.class)) { - return Optional.of((Tuple) STRINGS); - } + public Optional> provide(TypeTag tag, Attributes attributes) { return Optional.empty(); } }; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/DefaultValueProviders.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/DefaultValueProviders.java index 867ccf5ee..664cd03b6 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/DefaultValueProviders.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/DefaultValueProviders.java @@ -1,9 +1,10 @@ package nl.jqno.equalsverifier.internal.util; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; import nl.jqno.equalsverifier.internal.reflection.instantiation.ChainedValueProvider; import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import org.objenesis.Objenesis; public final class DefaultValueProviders { @@ -11,12 +12,20 @@ public final class DefaultValueProviders { private DefaultValueProviders() {} public static ValueProvider create(FactoryCache factoryCache, Objenesis objenesis) { - ChainedValueProvider mainChain = new ChainedValueProvider(); - ChainedValueProvider vintageChain = new ChainedValueProvider(); + CachedValueProvider cache = new CachedValueProvider(); - ValueProvider vintage = new VintageValueProvider(vintageChain, factoryCache, objenesis); + ChainedValueProvider mainChain = new ChainedValueProvider(cache); + ChainedValueProvider vintageChain = new ChainedValueProvider(cache); - mainChain.register(vintage); + ValueProvider vintage = new VintageValueProvider( + vintageChain, + cache, + factoryCache, + objenesis + ); + + mainChain.register(cache, vintage); + vintageChain.register(cache); return mainChain; } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/GenericTypesTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/GenericTypesTest.java index 822567528..43bddc2f6 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/GenericTypesTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/integration/extended_contract/GenericTypesTest.java @@ -15,6 +15,11 @@ public class GenericTypesTest { + @Test + public void succeed_whenClassHasGenericFieldThatsSpecifiedToABuiltinGeneric() { + EqualsVerifier.forClass(GenericContainerWithBuiltin.class).verify(); + } + @Test public void succeed_whenEqualsLooksAtJava8TypesGenericContent() { EqualsVerifier.forClass(JavaGenericTypeContainer.class).verify(); @@ -85,6 +90,11 @@ public void succeed_whenToStringLooksAtNonCollectionGenericContent() { EqualsVerifier.forClass(SparseArrayToStringContainer.class).verify(); } + @Test + public void succeed_whenEqualsLooksAtGenericContent_givenTwoGenericFields() { + EqualsVerifier.forClass(TwoGenericsContainerWithIntrospection.class).verify(); + } + @Test public void succeed_whenClassHasTypeVariableThatExtendsSomething() { EqualsVerifier.forClass(TypeVariableExtendsContainer.class).verify(); @@ -121,6 +131,29 @@ public void succeed_whenClassHasASelfReferenceGenericParameter_givenPrefabValues .verify(); } + static final class GenericContainerWithBuiltin { + + private final Generic> b; + + public GenericContainerWithBuiltin(Generic> b) { + this.b = b; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GenericContainerWithBuiltin)) { + return false; + } + GenericContainerWithBuiltin other = (GenericContainerWithBuiltin) obj; + return Objects.equals(b, other.b); + } + + @Override + public int hashCode() { + return Objects.hash(b); + } + } + static final class JavaGenericTypeContainer { private final Optional optional; @@ -172,6 +205,30 @@ public String toString() { } } + static final class Generic { + + private final T t; + + public Generic(T t) { + this.t = t; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Generic)) { + return false; + } + @SuppressWarnings("unchecked") + Generic other = (Generic) obj; + return Objects.equals(t, other.t); + } + + @Override + public int hashCode() { + return Objects.hash(t); + } + } + static final class ListContainer { private final List list; @@ -693,6 +750,38 @@ public String toString() { } } + public static final class TwoGenericsContainerWithIntrospection { + + private final List stringList = new ArrayList<>(); + private final List intList = new ArrayList<>(); + + @SuppressWarnings("unused") + @Override + public boolean equals(Object obj) { + if (stringList != null && stringList.size() > 0) { + String key = stringList.get(0); // force a cast + } + if (intList != null && intList.size() > 0) { + Integer key = intList.get(0); // force a cast + } + + if (!(obj instanceof TwoGenericsContainerWithIntrospection)) { + return false; + } + TwoGenericsContainerWithIntrospection other = + (TwoGenericsContainerWithIntrospection) obj; + return ( + Objects.equals(stringList, other.stringList) && + Objects.equals(intList, other.intList) + ); + } + + @Override + public int hashCode() { + return Objects.hash(stringList, intList); + } + } + @SuppressWarnings("unused") static final class TypeVariableExtendsContainer> { diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/architecture/ArchitectureTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/architecture/ArchitectureTest.java index f8f889290..8614a5eb5 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/architecture/ArchitectureTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/architecture/ArchitectureTest.java @@ -5,15 +5,9 @@ import com.tngtech.archunit.junit.AnalyzeClasses; import com.tngtech.archunit.junit.ArchTest; import com.tngtech.archunit.lang.ArchRule; -import nl.jqno.equalsverifier.ConfiguredEqualsVerifier; -import nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi; -import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProviderCreatorTest; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProviderTest; -import nl.jqno.equalsverifier.internal.reflection.vintage.*; -import nl.jqno.equalsverifier.internal.util.Context; -import nl.jqno.equalsverifier.internal.util.PrefabValuesApi; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.ClassAccessor; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.FieldModifier; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.ObjectAccessor; @AnalyzeClasses(packages = "nl.jqno.equalsverifier") public final class ArchitectureTest { @@ -21,22 +15,15 @@ public final class ArchitectureTest { @ArchTest public static final ArchRule ONLY_VINTAGE_INSTANTIATORS_CAN_USE_VINTAGE_REFLECTION = noClasses() .that() - .doNotBelongToAnyOf( - VintageValueProvider.class, - Context.class, - PrefabValuesApi.class, - JavaApiPrefabValues.class, - ConfiguredEqualsVerifier.class, - SingleTypeEqualsVerifierApi.class, - // 👇 Test classes - VintageValueProviderTest.class, - VintageValueProviderCreatorTest.class - ) - .and() .resideOutsideOfPackage("nl.jqno.equalsverifier.internal.reflection.vintage..") .should() .accessClassesThat() - .resideInAPackage("nl.jqno.equalsverifier.internal.reflection.vintage.."); + .resideInAPackage("nl.jqno.equalsverifier.internal.reflection.vintage.mutation..") + .orShould() + .accessClassesThat() + .resideInAPackage( + "nl.jqno.equalsverifier.internal.reflection.vintage.mutation.prefabvalues.." + ); @ArchTest public static final ArchRule DONT_USE_VINTAGE_REFLECTION_DIRECTLY = noClasses() diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProviderTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProviderTest.java new file mode 100644 index 000000000..db4c5d5c9 --- /dev/null +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/CachedValueProviderTest.java @@ -0,0 +1,62 @@ +package nl.jqno.equalsverifier.internal.reflection.instantiation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Optional; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.internal.reflection.Tuple; +import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider.Key; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import org.junit.jupiter.api.Test; + +public class CachedValueProviderTest { + + private static final TypeTag INT = new TypeTag(int.class); + + private CachedValueProvider sut = new CachedValueProvider(); + + @Test + public void aRegisteredValueCanBeFound() { + sut.put(INT, null, Tuple.of(3, 2, 3)); + assertEquals(Tuple.of(3, 2, 3), sut.provide(INT, Attributes.unlabeled()).get()); + } + + @Test + public void aValueRegisteredWithALabelCanBeFoundUnderThatLabel() { + sut.put(INT, "label", Tuple.of(3, 2, 3)); + assertEquals(Tuple.of(3, 2, 3), sut.provide(INT, Attributes.labeled("label")).get()); + } + + @Test + public void aValueRegisteredWithALabelCanNotBeFoundWithoutThatLabel() { + sut.put(INT, "label", Tuple.of(3, 2, 3)); + assertEquals(Optional.empty(), sut.provide(INT, Attributes.unlabeled())); + } + + @Test + public void aQueryWithLabelFallsBackToRegisteredValueWithoutLabel() { + sut.put(INT, null, Tuple.of(3, 2, 3)); + assertEquals(Tuple.of(3, 2, 3), sut.provide(INT, Attributes.labeled("label")).get()); + } + + @Test + public void aQueryWithLabelPrefersRegisteredValueWithThatLabel() { + sut.put(INT, null, Tuple.of(3, 2, 3)); + sut.put(INT, "label", Tuple.of(4, 3, 4)); + assertEquals(Tuple.of(4, 3, 4), sut.provide(INT, Attributes.labeled("label")).get()); + } + + @Test + public void anUnregisteredValueCanNotBeFound() { + assertEquals(Optional.empty(), sut.provide(INT, Attributes.unlabeled())); + } + + @Test + public void key() { + EqualsVerifier + .forClass(Key.class) + .withPrefabValues(TypeTag.class, new TypeTag(String.class), new TypeTag(Integer.class)) + .verify(); + } +} diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProviderTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProviderTest.java index f416cea54..9f092f438 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProviderTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/ChainedValueProviderTest.java @@ -2,16 +2,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.*; +import java.util.Optional; import nl.jqno.equalsverifier.internal.exceptions.EqualsVerifierInternalBugException; import nl.jqno.equalsverifier.internal.exceptions.NoValueException; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import org.junit.jupiter.api.Test; public class ChainedValueProviderTest { + private static final Attributes EMPTY_ATTRIBUTES = Attributes.unlabeled(); private static final TypeTag INT = new TypeTag(int.class); private final SingleTypeValueProvider intProvider = new SingleTypeValueProvider<>( @@ -27,25 +29,26 @@ public class ChainedValueProviderTest { "a" ); - private final ChainedValueProvider sut = new ChainedValueProvider(); + private final CachedValueProvider cache = new CachedValueProvider(); + private final ChainedValueProvider sut = new ChainedValueProvider(cache); @Test public void returnsValueIfMatch() { sut.register(intProvider); - assertEquals(1, sut.provideOrThrow(INT, null).getRed()); + assertEquals(1, sut.provideOrThrow(INT, EMPTY_ATTRIBUTES).getRed()); } @Test public void returnsEmptyIfNoMatch() { sut.register(stringProvider); - assertEquals(Optional.empty(), sut.provide(INT, null)); + assertEquals(Optional.empty(), sut.provide(INT, EMPTY_ATTRIBUTES)); } @Test public void throwsExceptionIfNoMatch() { sut.register(stringProvider); ExpectedException - .when(() -> sut.provideOrThrow(INT, null)) + .when(() -> sut.provideOrThrow(INT, EMPTY_ATTRIBUTES)) .assertThrows(NoValueException.class) .assertDescriptionContains("Could not find a value for int"); } @@ -53,7 +56,7 @@ public void throwsExceptionIfNoMatch() { @Test public void skipsNonMatchingValue() { sut.register(stringProvider, intProvider); - assertEquals(1, sut.provideOrThrow(INT, null).getRed()); + assertEquals(1, sut.provideOrThrow(INT, EMPTY_ATTRIBUTES).getRed()); assertEquals(1, stringProvider.called); assertEquals(1, intProvider.called); } @@ -67,17 +70,25 @@ public void returnsValueFromFirstMatch() { 1 ); sut.register(intProvider, anotherIntProvider); - assertEquals(1, sut.provideOrThrow(INT, null).getRed()); + assertEquals(1, sut.provideOrThrow(INT, EMPTY_ATTRIBUTES).getRed()); assertEquals(1, intProvider.called); assertEquals(0, anotherIntProvider.called); } + @Test + public void updatesTheCache() { + sut.register(intProvider); + sut.provideOrThrow(INT, EMPTY_ATTRIBUTES); + + assertEquals(1, cache.provideOrThrow(INT, EMPTY_ATTRIBUTES).getRed()); + } + @Test public void makesDefensiveCopy() { ValueProvider[] providers = { stringProvider }; sut.register(providers); providers[0] = intProvider; - assertEquals(Optional.empty(), sut.provide(INT, null)); + assertEquals(Optional.empty(), sut.provide(INT, EMPTY_ATTRIBUTES)); } @Test @@ -102,7 +113,7 @@ public SingleTypeValueProvider(Class type, X red, X blue, X redCopy) { @Override @SuppressWarnings("unchecked") - public Optional> provide(TypeTag tag, String label) { + public Optional> provide(TypeTag tag, Attributes attributes) { called++; if (tag.getType().equals(type)) { return Optional.of((Tuple) values); 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 ee51ae639..e99595234 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 @@ -201,7 +201,7 @@ public void noValueFound() { static class SubjectCreatorTestValueProvider implements ValueProvider { - public Optional> provide(TypeTag tag, String label) { + public Optional> provide(TypeTag tag, Attributes attributes) { if (int.class.equals(tag.getType())) { return Optional.of(Tuple.of(I_RED, I_BLUE, I_RED)); } @@ -215,7 +215,7 @@ public Optional> provide(TypeTag tag, String label) { static class NoValueProvider implements ValueProvider { @Override - public Optional> provide(TypeTag tag, String label) { + public Optional> provide(TypeTag tag, Attributes attributes) { return Optional.empty(); } } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheTest.java index 66a17eff3..614d06fdd 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheTest.java @@ -2,6 +2,8 @@ import static org.junit.jupiter.api.Assertions.*; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache.Key; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.SimpleFactory; import org.junit.jupiter.api.Test; @@ -122,4 +124,9 @@ public void merge() { assertFalse(a.contains(INT_CLASS)); assertFalse(b.contains(STRING_CLASS)); } + + @Test + public void key() { + EqualsVerifier.forClass(Key.class).verify(); + } } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApiTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApiTest.java similarity index 82% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApiTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApiTest.java index cae0f474d..b8c43352c 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/util/PrefabValuesApiTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/PrefabValuesApiTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.util; +package nl.jqno.equalsverifier.internal.reflection.vintage; import static nl.jqno.equalsverifier.internal.testhelpers.Util.coverThePrivateConstructor; diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderCreatorTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/VintageValueProviderCreatorTest.java similarity index 90% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderCreatorTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/VintageValueProviderCreatorTest.java index ffcf6a4ef..2a6808a9a 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderCreatorTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/VintageValueProviderCreatorTest.java @@ -1,12 +1,12 @@ -package nl.jqno.equalsverifier.internal.reflection.instantiation; +package nl.jqno.equalsverifier.internal.reflection.vintage; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; import static org.junit.jupiter.api.Assertions.*; import nl.jqno.equalsverifier.internal.exceptions.RecursionException; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; -import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCacheFactory; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.vintage.mutation.FactoryCacheFactory; import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.Point; @@ -31,15 +31,17 @@ public class VintageValueProviderCreatorTest { private static final TypeTag TWOSTEP_NODE_ARRAY_A_TAG = new TypeTag(TwoStepNodeArrayA.class); private Objenesis objenesis; + private CachedValueProvider cache; private FactoryCache factoryCache; private VintageValueProvider valueProvider; @BeforeEach public void setup() { objenesis = new ObjenesisStd(); + cache = new CachedValueProvider(); factoryCache = FactoryCacheFactory.withPrimitiveFactories(); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); } @Test @@ -49,15 +51,6 @@ public void simple() { assertFalse(red.equals(blue)); } - @Test - public void createSecondTimeIsNoOp() { - Point red = valueProvider.giveRed(POINT_TAG); - Point blue = valueProvider.giveBlue(POINT_TAG); - - assertSame(red, valueProvider.giveRed(POINT_TAG)); - assertSame(blue, valueProvider.giveBlue(POINT_TAG)); - } - @Test public void createEnum() { assertNotNull(valueProvider.giveRed(ENUM_TAG)); @@ -80,7 +73,7 @@ public void createEmptyEnum() { public void oneStepRecursiveType() { factoryCache.put(Node.class, values(new Node(), new Node(), new Node())); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); valueProvider.giveRed(NODE_TAG); } @@ -98,7 +91,7 @@ public void oneStepRecursiveArrayType() { values(new NodeArray(), new NodeArray(), new NodeArray()) ); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); valueProvider.giveRed(NODE_ARRAY_TAG); } @@ -116,7 +109,7 @@ public void addTwoStepRecursiveType() { values(new TwoStepNodeB(), new TwoStepNodeB(), new TwoStepNodeB()) ); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); valueProvider.giveRed(TWOSTEP_NODE_A_TAG); } @@ -134,7 +127,7 @@ public void twoStepRecursiveArrayType() { values(new TwoStepNodeArrayB(), new TwoStepNodeArrayB(), new TwoStepNodeArrayB()) ); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); valueProvider.giveRed(TWOSTEP_NODE_ARRAY_A_TAG); } 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/vintage/VintageValueProviderTest.java similarity index 78% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/instantiation/VintageValueProviderTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/VintageValueProviderTest.java index 54db33c3d..dab6fa67e 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/vintage/VintageValueProviderTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.reflection.instantiation; +package nl.jqno.equalsverifier.internal.reflection.vintage; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; import static nl.jqno.equalsverifier.internal.testhelpers.Util.defaultEquals; @@ -8,11 +8,11 @@ import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.Point; @@ -29,27 +29,20 @@ public class VintageValueProviderTest { private static final TypeTag INT_TAG = new TypeTag(int.class); private Objenesis objenesis = new ObjenesisStd(); + private CachedValueProvider cache = new CachedValueProvider(); private FactoryCache factoryCache = new FactoryCache(); private VintageValueProvider vp; @BeforeEach public void setUp() { - factoryCache.put(String.class, new AppendingStringTestFactory()); + factoryCache.put(String.class, values("r", "b", new String("r"))); factoryCache.put(int.class, values(42, 1337, 42)); - vp = new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); - } - - @Test - public void sanityTestFactoryIncreasesStringLength() { - AppendingStringTestFactory f = new AppendingStringTestFactory(); - assertEquals("r", f.createValues(null, null, null).getRed()); - assertEquals("rr", f.createValues(null, null, null).getRed()); - assertEquals("rrr", f.createValues(null, null, null).getRed()); + vp = new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); } @Test public void provide() { - Tuple actual = vp.provideOrThrow(POINT_TAG, null); + Tuple actual = vp.provideOrThrow(POINT_TAG, Attributes.unlabeled()); assertEquals(Tuple.of(new Point(42, 42), new Point(1337, 1337), new Point(42, 42)), actual); } @@ -58,36 +51,17 @@ public void giveRedFromFactory() { assertEquals("r", vp.giveRed(STRING_TAG)); } - @Test - public void giveRedFromCache() { - vp.giveRed(STRING_TAG); - assertEquals("r", vp.giveRed(STRING_TAG)); - } - @Test public void giveBlueFromFactory() { assertEquals("b", vp.giveBlue(STRING_TAG)); } - @Test - public void giveBlueFromCache() { - vp.giveBlue(STRING_TAG); - assertEquals("b", vp.giveBlue(STRING_TAG)); - } - @Test public void giveRedCopyFromFactory() { assertEquals("r", vp.giveRedCopy(STRING_TAG)); assertNotSame(vp.giveRed(STRING_TAG), vp.giveRedCopy(STRING_TAG)); } - @Test - public void giveRedCopyFromCache() { - vp.giveRedCopy(STRING_TAG); - assertEquals("r", vp.giveRedCopy(STRING_TAG)); - assertNotSame(vp.giveRed(STRING_TAG), vp.giveRedCopy(STRING_TAG)); - } - @Test public void giveRedFromFallbackFactory() { Point actual = vp.giveRed(POINT_TAG); @@ -117,7 +91,7 @@ public void fallbackDoesNotAffectStaticFields() { @Test public void stringListIsSeparateFromIntegerList() { factoryCache.put(List.class, new ListTestFactory()); - vp = new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + vp = new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); List strings = vp.giveRed(new TypeTag(List.class, STRING_TAG)); List ints = vp.giveRed(new TypeTag(List.class, INT_TAG)); @@ -134,7 +108,7 @@ public void addingNullDoesntBreakAnything() { @Test public void addingATypeTwiceOverrulesTheExistingOne() { factoryCache.put(int.class, values(-1, -2, -1)); - vp = new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + vp = new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); assertEquals(-1, (int) vp.giveRed(INT_TAG)); assertEquals(-2, (int) vp.giveBlue(INT_TAG)); } @@ -143,7 +117,7 @@ public void addingATypeTwiceOverrulesTheExistingOne() { public void addLazyFactoryWorks() { TypeTag lazyTag = new TypeTag(Lazy.class); factoryCache.put(Lazy.class.getName(), values(Lazy.X, Lazy.Y, Lazy.X)); - vp = new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + vp = new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); assertEquals(Lazy.X, vp.giveRed(lazyTag)); assertEquals(Lazy.Y, vp.giveBlue(lazyTag)); assertEquals(Lazy.X, vp.giveRedCopy(lazyTag)); @@ -159,7 +133,7 @@ public void addLazyFactoryIsLazy() { (t, p, ts) -> Tuple.of(ThrowingInitializer.X, ThrowingInitializer.Y, ThrowingInitializer.X) ); - vp = new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + vp = new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); // Should throw, because `giveRed` does instantiate objects: try { @@ -193,28 +167,6 @@ public int hashCode() { } } - private static class AppendingStringTestFactory implements PrefabValueFactory { - - private String red; - private String blue; - - public AppendingStringTestFactory() { - red = ""; - blue = ""; - } - - @Override - public Tuple createValues( - TypeTag tag, - VintageValueProvider valueProvider, - LinkedHashSet typeStack - ) { - red += "r"; - blue += "b"; - return new Tuple<>(red, blue, new String(red)); - } - } - @SuppressWarnings("rawtypes") private static final class ListTestFactory implements PrefabValueFactory { @@ -223,7 +175,7 @@ private static final class ListTestFactory implements PrefabValueFactory { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { TypeTag subtag = tag.getGenericTypes().get(0); diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessorTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessorTest.java similarity index 72% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessorTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessorTest.java index ed6f1155f..17cb4b1e0 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/ClassAccessorTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/ClassAccessorTest.java @@ -1,14 +1,16 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.PointContainer; import nl.jqno.equalsverifier.testhelpers.types.RecursiveTypeHelper.TwoStepNodeA; @@ -21,20 +23,23 @@ public class ClassAccessorTest { - private LinkedHashSet empty; + private Attributes empty; private Objenesis objenesis; + private CachedValueProvider cache; private FactoryCache factoryCache; private VintageValueProvider valueProvider; private ClassAccessor pointContainerAccessor; @BeforeEach public void setup() { - empty = new LinkedHashSet<>(); + empty = Attributes.unlabeled(); objenesis = new ObjenesisStd(); + cache = new CachedValueProvider(); factoryCache = JavaApiPrefabValues.build(); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); - pointContainerAccessor = ClassAccessor.of(PointContainer.class, valueProvider, objenesis); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); + pointContainerAccessor = + new ClassAccessor<>(PointContainer.class, valueProvider, objenesis); } @Test @@ -45,7 +50,7 @@ public void getRedObject() { @Test @SuppressWarnings("rawtypes") public void getRedObjectGeneric() { - ClassAccessor accessor = ClassAccessor.of( + ClassAccessor accessor = new ClassAccessor<>( GenericTypeVariableListContainer.class, valueProvider, objenesis @@ -57,16 +62,6 @@ public void getRedObjectGeneric() { assertEquals(String.class, foo.tList.get(0).getClass()); } - @Test - public void getRedAccessor() { - PointContainer foo = pointContainerAccessor.getRedObject(TypeTag.NULL, empty); - ObjectAccessor objectAccessor = pointContainerAccessor.getRedAccessor( - TypeTag.NULL, - empty - ); - assertEquals(foo, objectAccessor.get()); - } - @Test public void getBlueObject() { assertObjectHasNoNullFields(pointContainerAccessor.getBlueObject(TypeTag.NULL, empty)); @@ -75,7 +70,7 @@ public void getBlueObject() { @Test @SuppressWarnings("rawtypes") public void getBlueObjectGeneric() { - ClassAccessor accessor = ClassAccessor.of( + ClassAccessor accessor = new ClassAccessor<>( GenericTypeVariableListContainer.class, valueProvider, objenesis @@ -87,16 +82,6 @@ public void getBlueObjectGeneric() { assertEquals(String.class, foo.tList.get(0).getClass()); } - @Test - public void getBlueAccessor() { - PointContainer foo = pointContainerAccessor.getBlueObject(TypeTag.NULL, empty); - ObjectAccessor objectAccessor = pointContainerAccessor.getBlueAccessor( - TypeTag.NULL, - empty - ); - assertEquals(foo, objectAccessor.get()); - } - @Test public void redAndBlueNotEqual() { PointContainer red = pointContainerAccessor.getRedObject(TypeTag.NULL, empty); @@ -106,15 +91,13 @@ public void redAndBlueNotEqual() { @Test public void instantiateAllTypes() { - ClassAccessor - .of(AllTypesContainer.class, valueProvider, objenesis) + new ClassAccessor<>(AllTypesContainer.class, valueProvider, objenesis) .getRedObject(TypeTag.NULL, empty); } @Test public void instantiateArrayTypes() { - ClassAccessor - .of(AllArrayTypesContainer.class, valueProvider, objenesis) + new ClassAccessor<>(AllArrayTypesContainer.class, valueProvider, objenesis) .getRedObject(TypeTag.NULL, empty); } @@ -125,29 +108,26 @@ public void instantiateRecursiveTypeUsingPrefabValue() { values(new TwoStepNodeB(), new TwoStepNodeB(), new TwoStepNodeB()) ); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); - ClassAccessor - .of(TwoStepNodeA.class, valueProvider, objenesis) + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); + new ClassAccessor<>(TwoStepNodeA.class, valueProvider, objenesis) .getRedObject(TypeTag.NULL, empty); } @Test public void instantiateInterfaceField() { - ClassAccessor - .of(InterfaceContainer.class, valueProvider, objenesis) + new ClassAccessor<>(InterfaceContainer.class, valueProvider, objenesis) .getRedObject(TypeTag.NULL, empty); } @Test public void instantiateAbstractClassField() { - ClassAccessor - .of(AbstractClassContainer.class, valueProvider, objenesis) + new ClassAccessor<>(AbstractClassContainer.class, valueProvider, objenesis) .getRedObject(TypeTag.NULL, empty); } @Test public void anInvalidTypeShouldNotThrowAnExceptionUponCreation() { - ClassAccessor.of(null, valueProvider, objenesis); + new ClassAccessor<>(null, valueProvider, objenesis); } private void assertObjectHasNoNullFields(PointContainer foo) { diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheFactory.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FactoryCacheFactory.java similarity index 85% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheFactory.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FactoryCacheFactory.java index be7c8020f..9a07e1245 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FactoryCacheFactory.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FactoryCacheFactory.java @@ -1,7 +1,9 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; +import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; + public final class FactoryCacheFactory { private FactoryCacheFactory() {} diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifierTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifierTest.java similarity index 95% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifierTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifierTest.java index e0b2562b2..060709d09 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/FieldModifierTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/FieldModifierTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorCopyingTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorCopyingTest.java similarity index 97% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorCopyingTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorCopyingTest.java index a224280df..71fa1f1aa 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorCopyingTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorCopyingTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorScramblingTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorScramblingTest.java similarity index 90% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorScramblingTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorScramblingTest.java index 638c4d55c..f6e6aca62 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorScramblingTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorScramblingTest.java @@ -1,16 +1,18 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.Factories.values; import static org.junit.jupiter.api.Assertions.*; import java.text.AttributedString; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import nl.jqno.equalsverifier.internal.exceptions.ModuleException; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.Point; @@ -25,7 +27,7 @@ public class InPlaceObjectAccessorScramblingTest { - private static final LinkedHashSet EMPTY_TYPE_STACK = new LinkedHashSet<>(); + private static final Attributes EMPTY_ATTRIBUTES = Attributes.unlabeled(); private Objenesis objenesis; private VintageValueProvider valueProviderTest; @@ -35,7 +37,12 @@ public void setup() { factoryCache.put(Point.class, values(new Point(1, 2), new Point(2, 3), new Point(1, 2))); objenesis = new ObjenesisStd(); valueProviderTest = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); + new VintageValueProvider( + TestValueProviders.empty(), + new CachedValueProvider(), + factoryCache, + objenesis + ); } @Test @@ -155,7 +162,7 @@ private T copy(T object) { } private ObjectAccessor doScramble(Object object) { - return create(object).scramble(valueProviderTest, TypeTag.NULL, EMPTY_TYPE_STACK); + return create(object).scramble(valueProviderTest, TypeTag.NULL, EMPTY_ATTRIBUTES); } static final class StringContainer { diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorTest.java similarity index 92% rename from equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorTest.java rename to equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorTest.java index 85152215a..b44d77d52 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/InPlaceObjectAccessorTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/mutation/InPlaceObjectAccessorTest.java @@ -1,4 +1,4 @@ -package nl.jqno.equalsverifier.internal.reflection.vintage; +package nl.jqno.equalsverifier.internal.reflection.vintage.mutation; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactoryTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactoryTest.java index e0a2263fd..b35ebc104 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactoryTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/AbstractGenericFactoryTest.java @@ -4,11 +4,11 @@ import static nl.jqno.equalsverifier.internal.reflection.Util.objects; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.exceptions.ReflectionException; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ public void setUp() { public Tuple createValues( TypeTag tag, VintageValueProvider valueProvider, - LinkedHashSet typeStack + Attributes attributes ) { return Tuple.of("red", "blue", new String("red")); } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactoryTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactoryTest.java index 3725424f8..074f279ee 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactoryTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/FallbackFactoryTest.java @@ -5,13 +5,15 @@ import static nl.jqno.equalsverifier.internal.testhelpers.Util.defaultHashCode; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; -import java.util.LinkedHashSet; import nl.jqno.equalsverifier.internal.exceptions.RecursionException; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; import nl.jqno.equalsverifier.internal.reflection.vintage.FactoryCache; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.ExpectedException; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.RecursiveTypeHelper.Node; @@ -29,17 +31,18 @@ public class FallbackFactoryTest { private FallbackFactory factory; private VintageValueProvider valueProvider; - private LinkedHashSet typeStack; + private Attributes attributes; @BeforeEach public void setUp() { Objenesis objenesis = new ObjenesisStd(); factory = new FallbackFactory<>(objenesis); + CachedValueProvider cache = new CachedValueProvider(); FactoryCache factoryCache = new FactoryCache(); factoryCache.put(int.class, values(42, 1337, 42)); valueProvider = - new VintageValueProvider(TestValueProviders.empty(), factoryCache, objenesis); - typeStack = new LinkedHashSet<>(); + new VintageValueProvider(TestValueProviders.empty(), cache, factoryCache, objenesis); + attributes = Attributes.unlabeled(); } @Test @@ -59,7 +62,7 @@ public void giveMultiElementEnum() { @Test public void giveArray() { - Tuple tuple = factory.createValues(new TypeTag(int[].class), valueProvider, typeStack); + Tuple tuple = factory.createValues(new TypeTag(int[].class), valueProvider, attributes); assertArrayEquals(new int[] { 42 }, (int[]) tuple.getRed()); assertArrayEquals(new int[] { 1337 }, (int[]) tuple.getBlue()); } @@ -76,10 +79,22 @@ public void giveClassWithFields() { assertEquals(-10, IntContainer.STATIC_FINAL_I); } + @Test + public void redCopyIsNotSameAsRed() { + Tuple tuple = factory.createValues( + new TypeTag(IntContainer.class), + valueProvider, + attributes + ); + + assertEquals(tuple.getRed(), tuple.getRedCopy()); + assertNotSame(tuple.getRed(), tuple.getRedCopy()); + } + @Test public void dontGiveRecursiveClass() { ExpectedException - .when(() -> factory.createValues(new TypeTag(Node.class), valueProvider, typeStack)) + .when(() -> factory.createValues(new TypeTag(Node.class), valueProvider, attributes)) .assertThrows(RecursionException.class); } @@ -87,7 +102,7 @@ public void dontGiveRecursiveClass() { public void dontGiveTwoStepRecursiveClass() { ExpectedException .when(() -> - factory.createValues(new TypeTag(TwoStepNodeA.class), valueProvider, typeStack) + factory.createValues(new TypeTag(TwoStepNodeA.class), valueProvider, attributes) ) .assertThrows(RecursionException.class) .assertDescriptionContains("TwoStepNodeA", "TwoStepNodeB"); @@ -96,15 +111,17 @@ public void dontGiveTwoStepRecursiveClass() { @Test public void dontGiveRecursiveArray() { ExpectedException - .when(() -> factory.createValues(new TypeTag(NodeArray.class), valueProvider, typeStack) + .when(() -> + factory.createValues(new TypeTag(NodeArray.class), valueProvider, attributes) ) .assertThrows(RecursionException.class); } private void assertCorrectTuple(Class type, T expectedRed, T expectedBlue) { - Tuple tuple = factory.createValues(new TypeTag(type), valueProvider, typeStack); + Tuple tuple = factory.createValues(new TypeTag(type), valueProvider, attributes); assertEquals(expectedRed, tuple.getRed()); assertEquals(expectedBlue, tuple.getBlue()); + assertEquals(expectedRed, tuple.getRedCopy()); } private static final class IntContainer { diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactoryTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactoryTest.java index e08d755fc..664462bcf 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactoryTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/MapFactoryTest.java @@ -3,12 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.Map; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.TypeHelper.OneElementEnum; import org.junit.jupiter.api.BeforeEach; @@ -40,7 +41,7 @@ public class MapFactoryTest { private static final MapFactory MAP_FACTORY = new MapFactory<>(HashMap::new); - private final LinkedHashSet typeStack = new LinkedHashSet<>(); + private final Attributes attributes = Attributes.unlabeled(); private VintageValueProvider valueProvider; private String red; private String blue; @@ -53,6 +54,7 @@ public void setUp() { valueProvider = new VintageValueProvider( TestValueProviders.empty(), + new CachedValueProvider(), JavaApiPrefabValues.build(), new ObjenesisStd() ); @@ -68,7 +70,7 @@ public void createMapsOfStringToString() { Tuple tuple = MAP_FACTORY.createValues( STRINGSTRINGMAP_TYPETAG, valueProvider, - typeStack + attributes ); assertEquals(mapOf(red, blue), tuple.getRed()); assertEquals(mapOf(blue, blue), tuple.getBlue()); @@ -76,14 +78,14 @@ public void createMapsOfStringToString() { @Test public void createMapsOfWildcard() { - Tuple tuple = MAP_FACTORY.createValues(WILDCARDMAP_TYPETAG, valueProvider, typeStack); + Tuple tuple = MAP_FACTORY.createValues(WILDCARDMAP_TYPETAG, valueProvider, attributes); assertEquals(mapOf(redObject, blueObject), tuple.getRed()); assertEquals(mapOf(blueObject, blueObject), tuple.getBlue()); } @Test public void createRawMaps() { - Tuple tuple = MAP_FACTORY.createValues(RAWMAP_TYPETAG, valueProvider, typeStack); + Tuple tuple = MAP_FACTORY.createValues(RAWMAP_TYPETAG, valueProvider, attributes); assertEquals(mapOf(redObject, blueObject), tuple.getRed()); assertEquals(mapOf(blueObject, blueObject), tuple.getBlue()); } @@ -93,7 +95,7 @@ public void createMapOfOneElementEnumKey() { Tuple tuple = MAP_FACTORY.createValues( ONEELEMENTENUMKEYMAP_TYPETAG, valueProvider, - typeStack + attributes ); assertEquals(mapOf(redEnum, blueObject), tuple.getRed()); assertEquals(new HashMap<>(), tuple.getBlue()); diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactoryTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactoryTest.java index c54b0b816..1065d71e2 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactoryTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factories/SimpleGenericFactoryTest.java @@ -2,12 +2,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.LinkedHashSet; import java.util.Optional; import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; import nl.jqno.equalsverifier.testhelpers.types.Pair; import org.junit.jupiter.api.BeforeEach; @@ -41,7 +42,7 @@ public class SimpleGenericFactoryTest { ); private static final PrefabValueFactory PAIR_FACTORY = Factories.simple(Pair::new, null); - private final LinkedHashSet typeStack = new LinkedHashSet<>(); + private final Attributes attributes = Attributes.unlabeled(); private VintageValueProvider valueProvider; private String redString; private String blueString; @@ -55,6 +56,7 @@ public void setUp() { valueProvider = new VintageValueProvider( TestValueProviders.empty(), + new CachedValueProvider(), JavaApiPrefabValues.build(), new ObjenesisStd() ); @@ -71,7 +73,7 @@ public void createOptionalsOfMapOfString() { Tuple tuple = OPTIONAL_FACTORY.createValues( STRINGOPTIONAL_TYPETAG, valueProvider, - typeStack + attributes ); assertEquals(Optional.of(redString), tuple.getRed()); assertEquals(Optional.of(blueString), tuple.getBlue()); @@ -82,7 +84,7 @@ public void createOptionalsOfWildcard() { Tuple tuple = OPTIONAL_FACTORY.createValues( WILDCARDOPTIONAL_TYPETAG, valueProvider, - typeStack + attributes ); assertEquals(Optional.of(redObject), tuple.getRed()); assertEquals(Optional.of(blueObject), tuple.getBlue()); @@ -93,7 +95,7 @@ public void createRawOptionals() { Tuple tuple = OPTIONAL_FACTORY.createValues( RAWOPTIONAL_TYPETAG, valueProvider, - typeStack + attributes ); assertEquals(Optional.of(redObject), tuple.getRed()); assertEquals(Optional.of(blueObject), tuple.getBlue()); @@ -101,7 +103,7 @@ public void createRawOptionals() { @Test public void createSomethingWithMoreThanOneTypeParameter() { - Tuple tuple = PAIR_FACTORY.createValues(PAIR_TYPETAG, valueProvider, typeStack); + Tuple tuple = PAIR_FACTORY.createValues(PAIR_TYPETAG, valueProvider, attributes); assertEquals(new Pair<>(redString, redInt), tuple.getRed()); assertEquals(new Pair<>(blueString, blueInt), tuple.getBlue()); } diff --git a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProviderTest.java b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProviderTest.java index adf0e4948..f782fae61 100644 --- a/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProviderTest.java +++ b/equalsverifier-core/src/test/java/nl/jqno/equalsverifier/internal/reflection/vintage/prefabvalues/factoryproviders/JavaFxFactoryProviderTest.java @@ -8,7 +8,9 @@ import nl.jqno.equalsverifier.internal.reflection.JavaApiPrefabValues; import nl.jqno.equalsverifier.internal.reflection.Tuple; import nl.jqno.equalsverifier.internal.reflection.TypeTag; -import nl.jqno.equalsverifier.internal.reflection.instantiation.VintageValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.CachedValueProvider; +import nl.jqno.equalsverifier.internal.reflection.instantiation.ValueProvider.Attributes; +import nl.jqno.equalsverifier.internal.reflection.vintage.VintageValueProvider; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factories.PrefabValueFactory; import nl.jqno.equalsverifier.internal.reflection.vintage.prefabvalues.factoryproviders.JavaFxFactoryProvider.PropertyFactory; import nl.jqno.equalsverifier.internal.testhelpers.TestValueProviders; @@ -27,6 +29,7 @@ public void setUp() { valueProvider = new VintageValueProvider( TestValueProviders.empty(), + new CachedValueProvider(), JavaApiPrefabValues.build(), new ObjenesisStd() ); @@ -46,7 +49,11 @@ public void createInstancesWithCorrectSingleGenericParameter() { GenericContainer.class.getName(), List.class ); - Tuple tuple = factory.createValues(tag, valueProvider, null); + Tuple tuple = factory.createValues( + tag, + valueProvider, + Attributes.unlabeled() + ); assertEquals(valueProvider.giveRed(listTag), tuple.getRed().t); assertEquals(valueProvider.giveBlue(listTag), tuple.getBlue().t); @@ -70,7 +77,11 @@ public void createInstancesWithCorrectMultipleGenericParameter() { GenericMultiContainer.class.getName(), Map.class ); - Tuple tuple = factory.createValues(tag, valueProvider, null); + Tuple tuple = factory.createValues( + tag, + valueProvider, + Attributes.unlabeled() + ); assertEquals(valueProvider.giveRed(mapTag), tuple.getRed().t); assertEquals(valueProvider.giveBlue(mapTag), tuple.getBlue().t); diff --git a/equalsverifier-release-verify/src/test/java/nl/jqno/equalsverifier/verify_release/jar/helper/JarAsserter.java b/equalsverifier-release-verify/src/test/java/nl/jqno/equalsverifier/verify_release/jar/helper/JarAsserter.java index 2da2a26f3..be86ac31b 100644 --- a/equalsverifier-release-verify/src/test/java/nl/jqno/equalsverifier/verify_release/jar/helper/JarAsserter.java +++ b/equalsverifier-release-verify/src/test/java/nl/jqno/equalsverifier/verify_release/jar/helper/JarAsserter.java @@ -23,7 +23,7 @@ public JarAsserter(JarReader reader) { public void assertPresenceOfCoreClasses() { assertPresenceOf( EV + "/EqualsVerifier.class", - EV + "/internal/reflection/vintage/ClassAccessor.class", + EV + "/internal/reflection/vintage/mutation/ClassAccessor.class", EV + "/internal/checkers/HierarchyChecker.class" ); }