diff --git a/README.md b/README.md index a982868..21fbbf8 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ product.setBrand("Ocado"); com.ocadotechnology.gembus test-arranger - 1.6.2 + 1.6.3 ``` ### Gradle ```groovy -testImplementation 'com.ocadotechnology.gembus:test-arranger:1.6.2' +testImplementation 'com.ocadotechnology.gembus:test-arranger:1.6.3' ``` ## Features @@ -318,13 +318,11 @@ Eventually, we may end up with something like this: class ShopFixture { Repository repo; public void shopWithNineProductsAndFourCustomers() { - Stream.generate(() -> Arranger.some(Product.class)) - .limit(9) - .forEach(p -> repo.save(p)); + Arranger.someObjects(Product.class, 9) + .forEach(p -> repo.save(p)); - Stream.generate(() -> Arranger.some(Customer.class)) - .limit(4) - .forEach(p -> repo.save(p)); + Arranger.someObjects(Customer.class, 4) + .forEach(p -> repo.save(p)); } } ``` diff --git a/pom.xml b/pom.xml index 6bb0bff..15614f4 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 com.ocadotechnology.gembus test-arranger - 1.6.2.1 + 1.6.3 jar test-arranger A tool for arranging test data with pseudo-random values. @@ -59,8 +59,8 @@ UTF-8 UTF-8 17 - 1.9.22 - 7.0.0 + 1.9.25 + 7.1.0 @@ -95,17 +95,17 @@ org.apache.commons commons-lang3 - 3.12.0 + 3.17.0 org.yaml snakeyaml - 2.2 + 2.3 io.github.classgraph classgraph - 4.8.165 + 4.8.177 org.jetbrains.kotlin @@ -130,7 +130,7 @@ org.assertj assertj-core - 3.25.1 + 3.26.3 test @@ -140,7 +140,7 @@ org.junit junit-bom - 5.10.1 + 5.11.3 pom import @@ -195,7 +195,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 @@ -229,13 +229,13 @@ maven-surefire-plugin - 3.2.5 + 3.5.1 com.mycila license-maven-plugin - 4.3 + 4.6 @@ -284,7 +284,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.14 + 1.7.0 true ossrh @@ -296,7 +296,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 attach-sources @@ -310,7 +310,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.3 + 3.10.1 attach-javadocs diff --git a/src/main/java/com/ocadotechnology/gembus/test/ArrangersConfigurer.java b/src/main/java/com/ocadotechnology/gembus/test/ArrangersConfigurer.java index ba10274..c8f19e6 100644 --- a/src/main/java/com/ocadotechnology/gembus/test/ArrangersConfigurer.java +++ b/src/main/java/com/ocadotechnology/gembus/test/ArrangersConfigurer.java @@ -74,10 +74,11 @@ EnhancedRandom simplifiedRandom() { return randomWithArrangers(simplifiedArrangers, new EnhancedRandom.Builder(ArrangersConfigurer::getEasyRandomSimplifiedParameters)); } - EnhancedRandom randomForGivenConfiguration(Class type, boolean withoutGivenType, Map, CustomArranger> arrangers, Supplier parametersSupplier) { + EnhancedRandom randomForGivenConfiguration(Class type, Map, CustomArranger> arrangers, Supplier parametersSupplier) { EnhancedRandom.Builder randomBuilder = new EnhancedRandom.Builder(parametersSupplier); long seed = SeedHelper.calculateSeed(); - if (withoutGivenType && arrangers.get(type) != null) { + CustomArranger arrangerToUpdate = arrangers.get(type); + if (arrangerToUpdate != null) { seed = SeedHelper.customArrangerTypeSpecificSeedRespectingRandomSeedSetting(type); arrangers = withoutGivenType(arrangers, type); } diff --git a/src/main/java/com/ocadotechnology/gembus/test/CustomArranger.java b/src/main/java/com/ocadotechnology/gembus/test/CustomArranger.java index 32d1f86..4b90e3b 100644 --- a/src/main/java/com/ocadotechnology/gembus/test/CustomArranger.java +++ b/src/main/java/com/ocadotechnology/gembus/test/CustomArranger.java @@ -33,19 +33,9 @@ public abstract class CustomArranger { protected EnhancedRandom enhancedRandom = null; - protected final Class type; + protected final Class type = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; protected CustomArranger() { - this.type = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - initEnhancedRandom(); - } - - protected CustomArranger(Class type) { - this.type = type; - initEnhancedRandom(); - } - - private void initEnhancedRandom() { if (ArrangersConfigurer.defaultInitialized.get()) { enhancedRandom = ArrangersConfigurer.instance().defaultRandom(); } else { diff --git a/src/main/java/com/ocadotechnology/gembus/test/EnhancedRandom.java b/src/main/java/com/ocadotechnology/gembus/test/EnhancedRandom.java index fc05eed..bca376b 100644 --- a/src/main/java/com/ocadotechnology/gembus/test/EnhancedRandom.java +++ b/src/main/java/com/ocadotechnology/gembus/test/EnhancedRandom.java @@ -15,27 +15,15 @@ */ package com.ocadotechnology.gembus.test; -import com.ocadotechnology.gembus.test.experimental.SealedInterfaceArranger; import org.jeasy.random.EasyRandom; import org.jeasy.random.EasyRandomParameters; import org.jeasy.random.api.Randomizer; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.function.Function.identity; - /** * Class for random object generator. */ @@ -96,90 +84,26 @@ public Stream objects(final Class type, final int amount, final String } private EasyRandom selectEasyRandomWithRespectToExclusion(Class type, String[] excludedFields) { - if (newEasyRandomWithCustomRandomizersOrFieldExclusionConfigIsRequired(type, excludedFields)) { - return createEasyRandomWithCustomRandomizersAndExclusions(type, excludedFields); + if (newEasyRandomWithFieldExclusionConfigIsRequired(type, excludedFields)) { + return createEasyRandomWithExclusions(type, excludedFields); } return easyRandom; } - private boolean newEasyRandomWithCustomRandomizersOrFieldExclusionConfigIsRequired(Class type, String[] excludedFields) { + private boolean newEasyRandomWithFieldExclusionConfigIsRequired(Class type, String[] excludedFields) { /* There is a logical inconsistency in using a custom arranger and field exclusion for the same type - the * exclusion can be configured in the custom arranger. Technically, creating an arranger with exclusion disables * the custom arranger for the type that is being instantiated. */ - return !arrangers.containsKey(type) && (excludedFields.length != 0 || isSealedInterface(type) || !nestedSealedInterfaceFields(type).isEmpty()); + return !arrangers.containsKey(type) && excludedFields.length != 0; } - private EasyRandom createEasyRandomWithCustomRandomizersAndExclusions(Class type, String[] excludedFields) { + private EasyRandom createEasyRandomWithExclusions(Class type, String[] excludedFields) { Set fields = new HashSet<>(Arrays.asList(excludedFields)); - var forSealedInterfaces = createCustomArrangersForSealedInterfaces(type, fields); - Set cacheKey = getCacheKey(fields, forSealedInterfaces.keySet()); - cache.computeIfAbsent(cacheKey, key -> { - HashMap, CustomArranger> enhancedArrangers = new HashMap<>(arrangers); - enhancedArrangers.putAll(forSealedInterfaces); - EnhancedRandom er = ArrangersConfigurer.instance() - .randomForGivenConfiguration(type, !forSealedInterfaces.containsKey(type), enhancedArrangers, () -> addExclusionToParameters(fields)); + cache.computeIfAbsent(fields, key -> { + EnhancedRandom er = ArrangersConfigurer.instance().randomForGivenConfiguration(type, arrangers, () -> addExclusionToParameters(fields)); return er.easyRandom; }); - return cache.get(cacheKey); - } - - private Set getCacheKey(Set fields, Set> sealedInterfaces) { - Set cacheKey = new HashSet<>(fields); - cacheKey.addAll(sealedInterfaces.stream().map(Class::getName).toList()); - return cacheKey; - } - - private Map, CustomArranger> createCustomArrangersForSealedInterfaces(Class type, Set excludedFields) { - Map, CustomArranger> sealedInterfaceArrangers = new HashMap<>(); - if (isSealedInterface(type)) { - sealedInterfaceArrangers.put(type, new SealedInterfaceArranger(type)); - } - sealedInterfaceArrangers.putAll(nestedSealedInterfaceFields(type) - .entrySet() - .stream() - .filter(entry -> !excludedFields.contains(entry.getKey())) - .map(Map.Entry::getValue) - .collect(Collectors.toMap(identity(), SealedInterfaceArranger::new))); - return sealedInterfaceArrangers; - } - - private Map> nestedSealedInterfaceFields(Class type) { - return allNestedFields(new HashMap<>(), type) - .entrySet() - .stream() - .filter(entry -> isSealedInterface(entry.getValue())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - private Map> allNestedFields(Map> acc, Class clazz) { - if (clazz == null || clazz.isPrimitive()) { - return Map.of(); - } - if (isSealedInterface(clazz)) { - for (Class permittedSubclasses : clazz.getPermittedSubclasses()) { - acc.putAll(allNestedFields(acc, permittedSubclasses)); - } - } - for (Field field : clazz.getDeclaredFields()) { - if (!acc.containsKey(field.getName())) { - if (field.getGenericType() instanceof ParameterizedType parameterizedType) { - for (var genericType : parameterizedType.getActualTypeArguments()) { - if(genericType instanceof Class genericTypeClass) { - acc.put(field.getName(), genericTypeClass); - acc.putAll(allNestedFields(acc, genericTypeClass)); - } - } - } else { - acc.put(field.getName(), field.getType()); - acc.putAll(allNestedFields(acc, field.getType())); - } - } - } - return acc; - } - - private static boolean isSealedInterface(Class type) { - return type.isSealed() && type.isInterface(); + return cache.get(fields); } private EasyRandomParameters addExclusionToParameters(Set fields) { diff --git a/src/main/java/com/ocadotechnology/gembus/test/ReflectionHelper.java b/src/main/java/com/ocadotechnology/gembus/test/ReflectionHelper.java index 4b182f6..efea474 100644 --- a/src/main/java/com/ocadotechnology/gembus/test/ReflectionHelper.java +++ b/src/main/java/com/ocadotechnology/gembus/test/ReflectionHelper.java @@ -15,7 +15,6 @@ */ package com.ocadotechnology.gembus.test; -import com.ocadotechnology.gembus.test.experimental.SealedInterfaceArranger; import io.github.classgraph.ClassGraph; import java.lang.reflect.Constructor; @@ -40,7 +39,6 @@ class ReflectionHelper { .loadClasses(CustomArranger.class, true) .stream() .filter(clazz -> isNotAbstract(clazz)) - .filter(clazz -> !SealedInterfaceArranger.class.equals(clazz)) .map(clazz -> extractConstructor(clazz)) .filter(constructor -> constructor.isPresent()) .map(constructor -> constructor.get()) diff --git a/src/main/java/com/ocadotechnology/gembus/test/experimental/SealedInterfaceArranger.java b/src/main/java/com/ocadotechnology/gembus/test/experimental/SealedInterfaceArranger.java deleted file mode 100644 index 90bdf8c..0000000 --- a/src/main/java/com/ocadotechnology/gembus/test/experimental/SealedInterfaceArranger.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright © 2020 Ocado (marian.jureczko@ocado.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ocadotechnology.gembus.test.experimental; - -import com.ocadotechnology.gembus.test.CustomArranger; - -public class SealedInterfaceArranger extends CustomArranger { - - public SealedInterfaceArranger() { - } - - public SealedInterfaceArranger(Class clazz) { - super(clazz); - } - - @Override - protected T instance() { - Class[] subclasses = type.getPermittedSubclasses(); - return (T) enhancedRandom.nextObject(subclasses[enhancedRandom.nextInt(subclasses.length)]); - } -} diff --git a/src/test/java/com/ocadotechnology/gembus/test/ArrangerSealedInterfacesTest.java b/src/test/java/com/ocadotechnology/gembus/test/ArrangerSealedInterfacesTest.java index 41fabce..a8ade11 100644 --- a/src/test/java/com/ocadotechnology/gembus/test/ArrangerSealedInterfacesTest.java +++ b/src/test/java/com/ocadotechnology/gembus/test/ArrangerSealedInterfacesTest.java @@ -15,7 +15,6 @@ */ package com.ocadotechnology.gembus.test; -import com.ocadotechnology.gembus.test.experimental.SealedInterfaceArranger; import org.jeasy.random.ObjectCreationException; import org.junit.jupiter.api.Test; @@ -152,7 +151,7 @@ sealed interface SealedInterfaceWithCustomArranger permits ConcreteDataWithCusto record ConcreteDataWithCustomArranger(String test) implements SealedInterfaceWithCustomArranger { } -class CustomSealedInterfaceArranger extends SealedInterfaceArranger { +class CustomSealedInterfaceArranger extends CustomArranger { @Override protected SealedInterfaceWithCustomArranger instance() {