diff --git a/easy-random-bean-validation/src/main/java/org/jeasy/random/validation/SizeAnnotationHandler.java b/easy-random-bean-validation/src/main/java/org/jeasy/random/validation/SizeAnnotationHandler.java index 930f81d69..a58e67412 100644 --- a/easy-random-bean-validation/src/main/java/org/jeasy/random/validation/SizeAnnotationHandler.java +++ b/easy-random-bean-validation/src/main/java/org/jeasy/random/validation/SizeAnnotationHandler.java @@ -23,27 +23,39 @@ */ package org.jeasy.random.validation; +import org.jeasy.random.EasyRandom; +import org.jeasy.random.EasyRandomParameters; import org.jeasy.random.api.Randomizer; +import org.jeasy.random.randomizers.range.IntegerRangeRandomizer; import org.jeasy.random.randomizers.text.StringRandomizer; import org.jeasy.random.util.ReflectionUtils; +import org.objenesis.ObjenesisStd; import javax.validation.constraints.Size; +import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.charset.Charset; -import java.util.Random; +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; -class SizeAnnotationHandler implements BeanValidationAnnotationHandler { +import static org.jeasy.random.util.ReflectionUtils.*; - private final Random random; +class SizeAnnotationHandler implements BeanValidationAnnotationHandler { + private long seed; private Charset charset; + private EasyRandom easyRandom; - public SizeAnnotationHandler(long seed, Charset charset) { - random = new Random(seed); + SizeAnnotationHandler(long seed, Charset charset) { + this.seed = seed; this.charset = charset; } @Override + @SuppressWarnings({"unchecked"}) public Randomizer getRandomizer(Field field) { Class fieldType = field.getType(); Size sizeAnnotation = ReflectionUtils @@ -51,8 +63,96 @@ public Randomizer getRandomizer(Field field) { final int min = sizeAnnotation.min(); final int max = sizeAnnotation.max(); + if (easyRandom == null) { + EasyRandomParameters parameters = new EasyRandomParameters() + .seed(this.seed) + .charset(this.charset) + .collectionSizeRange(min, max) + .stringLengthRange(min, max); + easyRandom = new EasyRandom(parameters); + } + if (fieldType.equals(String.class)) { - return new StringRandomizer(charset, min, max, random.nextLong()); + return new StringRandomizer(charset, min, max, easyRandom.nextLong()); + } + + if (isArrayType(fieldType)) { + return (Randomizer) () -> { + int randomSize = new IntegerRangeRandomizer(min, max, seed).getRandomValue(); + Object[] itemsList = (Object[]) Array.newInstance(field.getType().getComponentType(), randomSize); + for (int i = 0; i < randomSize; i++) { + itemsList[i] = (Object) easyRandom.nextObject(fieldType.getComponentType()); + } + return itemsList; + }; + } + + if (isCollectionType(fieldType)) { + return (Randomizer) () -> { + int randomSize = new IntegerRangeRandomizer(min, max, seed).getRandomValue(); + Type fieldGenericType = field.getGenericType(); + Collection collection; + + if (isInterface(fieldType)) { + collection = getEmptyImplementationForCollectionInterface(fieldType); + } else { + collection = createEmptyCollectionForType(fieldType, randomSize); + } + if (isParameterizedType(fieldGenericType)) { + ParameterizedType parameterizedType = (ParameterizedType) fieldGenericType; + Type type = parameterizedType.getActualTypeArguments()[0]; + if (isPopulatable(type)) { + for (int i = 0; i < randomSize; i++) { + Object item = easyRandom.nextObject((Class) type); + collection.add(item); + } + + } + } + return collection; + }; + } + if (isMapType(fieldType)) { + return (Randomizer) () -> { + int randomSize = new IntegerRangeRandomizer(min, max, seed).getRandomValue(); + Type fieldGenericType = field.getGenericType(); + Map map; + + if (isInterface(fieldType)) { + map = (Map) getEmptyImplementationForMapInterface(fieldType); + } else { + try { + map = (Map) fieldType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + if (fieldType.isAssignableFrom(EnumMap.class)) { + if (isParameterizedType(fieldGenericType)) { + Type type = ((ParameterizedType) fieldGenericType).getActualTypeArguments()[0]; + map = new EnumMap((Class)type); + } else { + return null; + } + } else { + map = (Map) new ObjenesisStd().newInstance(fieldType); + } + } + } + + if (isParameterizedType(fieldGenericType)) { // populate only parameterized types, raw types will be empty + ParameterizedType parameterizedType = (ParameterizedType) fieldGenericType; + Type keyType = parameterizedType.getActualTypeArguments()[0]; + Type valueType = parameterizedType.getActualTypeArguments()[1]; + if (isPopulatable(keyType) && isPopulatable(valueType)) { + for (int index = 0; index < randomSize; index++) { + Object randomKey = easyRandom.nextObject((Class) keyType); + Object randomValue = easyRandom.nextObject((Class) valueType); + if(randomKey != null) { + map.put(randomKey, randomValue); + } + } + } + } + return map; + }; } return null; } diff --git a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationAnnotatedBean.java b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationAnnotatedBean.java index 5e30afa1b..f0f898f7b 100644 --- a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationAnnotatedBean.java +++ b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationAnnotatedBean.java @@ -23,11 +23,14 @@ */ package org.jeasy.random.validation; +import lombok.Data; + import javax.validation.constraints.*; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Date; +import java.util.*; +@Data class BeanValidationAnnotatedBean { @AssertFalse @@ -96,224 +99,23 @@ class BeanValidationAnnotatedBean { @Size(min=2, max=10) private String briefMessage; - - @Pattern(regexp="[a-z]{4}") - private String regexString; - - public BeanValidationAnnotatedBean() { - } - - public boolean isUnsupported() { - return unsupported; - } - - public void setUnsupported(boolean unsupported) { - this.unsupported = unsupported; - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } - - public BigDecimal getMaxDiscount() { - return maxDiscount; - } - - public void setMaxDiscount(BigDecimal maxDiscount) { - this.maxDiscount = maxDiscount; - } - - public BigDecimal getMinDiscount() { - return minDiscount; - } - - public void setMinDiscount(BigDecimal minDiscount) { - this.minDiscount = minDiscount; - } - - public Date getEventDate() { - return eventDate; - } - - public void setEventDate(Date eventDate) { - this.eventDate = eventDate; - } - public LocalDateTime getEventLocalDateTime() { - return eventLocalDateTime; - } - - public Date getFutureOrPresent() { - return futureOrPresent; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - public LocalDateTime getBirthdayLocalDateTime() { - return birthdayLocalDateTime; - } - - public Date getPastOrPresent() { - return pastOrPresent; - } - - public int getMaxQuantity() { - return maxQuantity; - } - - public void setMaxQuantity(int maxQuantity) { - this.maxQuantity = maxQuantity; - } + @Size(min=2, max=10) + private Collection sizedCollection; - public int getMinQuantity() { - return minQuantity; - } + @Size(min=2, max=10) + private List sizedList; - public void setMinQuantity(int minQuantity) { - this.minQuantity = minQuantity; - } + @Size(min=2, max=10) + private Set sizedSet; - public String getUsername() { - return username; - } + @Size(min=2, max=10) + private Map sizedMap; - public void setUsername(String username) { - this.username = username; - } + @Size(min=2, max=10) + private String[] sizedArray; - public String getUnusedString() { - return unusedString; - } + @Pattern(regexp="[a-z]{4}") + private String regexString; - public void setUnusedString(String unusedString) { - this.unusedString = unusedString; - } - - public String getBriefMessage() { - return briefMessage; - } - - public void setBriefMessage(String briefMessage) { - this.briefMessage = briefMessage; - } - - - public String getRegexString() { - return regexString; - } - - public void setRegexString(String regexString) { - this.regexString = regexString; - } - - public int getPositive() { - return positive; - } - - public void setPositive(int positive) { - this.positive = positive; - } - - public int getPositiveOrZero() { - return positiveOrZero; - } - - public void setPositiveOrZero(int positiveOrZero) { - this.positiveOrZero = positiveOrZero; - } - - public int getNegative() { - return negative; - } - - public void setNegative(int negative) { - this.negative = negative; - } - - public int getNegativeOrZero() { - return negativeOrZero; - } - - public void setNegativeOrZero(int negativeOrZero) { - this.negativeOrZero = negativeOrZero; - } - - public String getNotBlank() { - return notBlank; - } - - public void setNotBlank(String notBlank) { - this.notBlank = notBlank; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public BigDecimal getDiscount() { - return discount; - } - - public void setDiscount(BigDecimal discount) { - this.discount = discount; - } - - public void setEventLocalDateTime(LocalDateTime eventLocalDateTime) { - this.eventLocalDateTime = eventLocalDateTime; - } - - public void setFutureOrPresent(Date futureOrPresent) { - this.futureOrPresent = futureOrPresent; - } - - public void setBirthdayLocalDateTime(LocalDateTime birthdayLocalDateTime) { - this.birthdayLocalDateTime = birthdayLocalDateTime; - } - - public void setPastOrPresent(Date pastOrPresent) { - this.pastOrPresent = pastOrPresent; - } - - @Override - public String toString() { - return "BeanValidationAnnotatedBean{" + - "unsupported=" + unsupported + - ", active=" + active + - ", maxDiscount=" + maxDiscount + - ", minDiscount=" + minDiscount + - ", discount=" + discount + - ", eventDate=" + eventDate + - ", eventLocalDateTime=" + eventLocalDateTime + - ", birthday=" + birthday + - ", birthdayLocalDateTime=" + birthdayLocalDateTime + - ", pastOrPresent=" + pastOrPresent + - ", futureOrPresent=" + futureOrPresent + - ", maxQuantity=" + maxQuantity + - ", minQuantity=" + minQuantity + - ", positive=" + positive + - ", positiveOrZero=" + positiveOrZero + - ", negative=" + negative + - ", negativeOrZero=" + negativeOrZero + - ", notBlank='" + notBlank + '\'' + - ", email='" + email + '\'' + - ", username='" + username + '\'' + - ", unusedString='" + unusedString + '\'' + - ", briefMessage='" + briefMessage + '\'' + - ", regexString='" + regexString + '\'' + - '}'; - } } diff --git a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationMethodAnnotatedBean.java b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationMethodAnnotatedBean.java index e7a51ddb6..4d3c42044 100644 --- a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationMethodAnnotatedBean.java +++ b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationMethodAnnotatedBean.java @@ -26,7 +26,7 @@ import javax.validation.constraints.*; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Date; +import java.util.*; class BeanValidationMethodAnnotatedBean { @@ -71,6 +71,16 @@ class BeanValidationMethodAnnotatedBean { private String briefMessage; + private Collection sizedCollection; + + private List sizedList; + + private Set sizedSet; + + private Map sizedMap; + + private String[] sizedArray; + private String regexString; @AssertFalse @@ -282,6 +292,51 @@ public void setEmail(String email) { this.email = email; } + @Size(min=2, max=10) + public Collection getSizedCollection() { + return sizedCollection; + } + + public void setSizedCollection(Collection sizedCollection) { + this.sizedCollection = sizedCollection; + } + + @Size(min=2, max=10) + public List getSizedList() { + return sizedList; + } + + public void setSizedList(List sizedList) { + this.sizedList = sizedList; + } + + @Size(min=2, max=10) + public Set getSizedSet() { + return sizedSet; + } + + public void setSizedSet(Set sizedSet) { + this.sizedSet = sizedSet; + } + + @Size(min=2, max=10) + public Map getSizedMap() { + return sizedMap; + } + + public void setSizedMap(Map sizedMap) { + this.sizedMap = sizedMap; + } + + @Size(min=2, max=10) + public String[] getSizedArray() { + return sizedArray; + } + + public void setSizedArray(String[] sizedArray) { + this.sizedArray = sizedArray; + } + @Override public String toString() { return "BeanValidationMethodAnnotatedBean{" + @@ -307,6 +362,11 @@ public String toString() { ", username='" + username + '\'' + ", unusedString='" + unusedString + '\'' + ", briefMessage='" + briefMessage + '\'' + + ", sizedCollection=" + sizedCollection + + ", sizedList=" + sizedList + + ", sizedSet=" + sizedSet + + ", sizedMap=" + sizedMap + + ", sizedArray=" + Arrays.toString(sizedArray) + ", regexString='" + regexString + '\'' + '}'; } diff --git a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationTest.java b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationTest.java index 02168796d..656a243b2 100644 --- a/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationTest.java +++ b/easy-random-bean-validation/src/test/java/org/jeasy/random/validation/BeanValidationTest.java @@ -101,6 +101,11 @@ public void generatedValuesShouldBeValidAccordingToValidationConstraints() { assertThat(bean.getMinQuantity()).isGreaterThanOrEqualTo(5);// @Min(5) int minQuantity; assertThat(bean.getBriefMessage().length()).isBetween(2, 10);// @Size(min=2, max=10) String briefMessage; + assertThat(bean.getSizedCollection().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedCollection; + assertThat(bean.getSizedList().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedList; + assertThat(bean.getSizedSet().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedSet; + assertThat(bean.getSizedMap().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedMap; + assertThat(bean.getSizedArray().length).isBetween(2, 10);// @Size(min=2, max=10) String sizedArray; assertThat(bean.getRegexString()).matches("[a-z]{4}"); } @@ -157,6 +162,11 @@ public void generatedValuesShouldBeValidAccordingToValidationConstraintsOnMethod assertThat(bean.getMinQuantity()).isGreaterThanOrEqualTo(5);// @Min(5) int minQuantity; assertThat(bean.getBriefMessage().length()).isBetween(2, 10);// @Size(min=2, max=10) String briefMessage; + assertThat(bean.getSizedCollection().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedCollection; + assertThat(bean.getSizedList().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedList; + assertThat(bean.getSizedSet().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedSet; + assertThat(bean.getSizedMap().size()).isBetween(2, 10);// @Size(min=2, max=10) String sizedMap; + assertThat(bean.getSizedArray().length).isBetween(2, 10);// @Size(min=2, max=10) String sizedArray; assertThat(bean.getRegexString()).matches("[a-z]{4}"); } diff --git a/easy-random-core/src/main/java/org/jeasy/random/CollectionPopulator.java b/easy-random-core/src/main/java/org/jeasy/random/CollectionPopulator.java index dd5a755b5..1c38d4aca 100644 --- a/easy-random-core/src/main/java/org/jeasy/random/CollectionPopulator.java +++ b/easy-random-core/src/main/java/org/jeasy/random/CollectionPopulator.java @@ -23,13 +23,10 @@ */ package org.jeasy.random; -import org.objenesis.ObjenesisStd; - import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.*; +import java.util.Collection; import static org.jeasy.random.util.ReflectionUtils.*; @@ -73,55 +70,4 @@ Collection getRandomCollection(final Field field, final RandomizationContext return collection; } - - Collection createEmptyCollectionForType(Class fieldType, int initialSize) { - rejectUnsupportedTypes(fieldType); - Collection collection; - try { - collection = (Collection) fieldType.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - if (fieldType.equals(ArrayBlockingQueue.class)) { - collection = new ArrayBlockingQueue<>(initialSize); - } else { - // FIXME objenesis should be a field to be created only once + can we avoid objenesis at all in this class? - collection = (Collection) new ObjenesisStd().newInstance(fieldType); - } - } - return collection; - } - - private void rejectUnsupportedTypes(Class type) { - if (type.equals(SynchronousQueue.class)) { - // SynchronousQueue is not supported since it requires a consuming thread at insertion time - throw new UnsupportedOperationException(SynchronousQueue.class.getName() + " type is not supported"); - } - if (type.equals(DelayQueue.class)) { - // DelayQueue is not supported since it requires creating dummy delayed objects - throw new UnsupportedOperationException(DelayQueue.class.getName() + " type is not supported"); - } - } - - Collection getEmptyImplementationForCollectionInterface(final Class collectionInterface) { - Collection collection = new ArrayList<>(); - if (List.class.isAssignableFrom(collectionInterface)) { - collection = new ArrayList<>(); - } else if (NavigableSet.class.isAssignableFrom(collectionInterface)) { - collection = new TreeSet<>(); - } else if (SortedSet.class.isAssignableFrom(collectionInterface)) { - collection = new TreeSet<>(); - } else if (Set.class.isAssignableFrom(collectionInterface)) { - collection = new HashSet<>(); - } else if (BlockingDeque.class.isAssignableFrom(collectionInterface)) { - collection = new LinkedBlockingDeque<>(); - } else if (Deque.class.isAssignableFrom(collectionInterface)) { - collection = new ArrayDeque<>(); - } else if (TransferQueue.class.isAssignableFrom(collectionInterface)) { - collection = new LinkedTransferQueue<>(); - } else if (BlockingQueue.class.isAssignableFrom(collectionInterface)) { - collection = new LinkedBlockingQueue<>(); - } else if (Queue.class.isAssignableFrom(collectionInterface)) { - collection = new LinkedList<>(); - } - return collection; - } } diff --git a/easy-random-core/src/main/java/org/jeasy/random/EasyRandom.java b/easy-random-core/src/main/java/org/jeasy/random/EasyRandom.java index 8f3bb58a3..b939849b5 100644 --- a/easy-random-core/src/main/java/org/jeasy/random/EasyRandom.java +++ b/easy-random-core/src/main/java/org/jeasy/random/EasyRandom.java @@ -25,6 +25,7 @@ import org.jeasy.random.api.*; import org.jeasy.random.randomizers.misc.EnumRandomizer; +import org.jeasy.random.util.ReflectionUtils; import java.lang.reflect.Field; import java.util.*; @@ -177,10 +178,10 @@ private T randomize(final Class type, final RandomizationContext context) return (T) arrayPopulator.getRandomArray(type, context); } if (isCollectionType(type)) { - return (T) collectionPopulator.getEmptyImplementationForCollectionInterface(type); + return (T) ReflectionUtils.getEmptyImplementationForCollectionInterface(type); } if (isMapType(type)) { - return (T) mapPopulator.getEmptyImplementationForMapInterface(type); + return (T) ReflectionUtils.getEmptyImplementationForMapInterface(type); } return null; } diff --git a/easy-random-core/src/main/java/org/jeasy/random/MapPopulator.java b/easy-random-core/src/main/java/org/jeasy/random/MapPopulator.java index 98879ef07..2188579ec 100644 --- a/easy-random-core/src/main/java/org/jeasy/random/MapPopulator.java +++ b/easy-random-core/src/main/java/org/jeasy/random/MapPopulator.java @@ -28,11 +28,8 @@ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; +import java.util.EnumMap; +import java.util.Map; import static org.jeasy.random.util.ReflectionUtils.*; @@ -96,18 +93,4 @@ class MapPopulator { return map; } - Map getEmptyImplementationForMapInterface(final Class mapInterface) { - Map map = new HashMap<>(); - if (ConcurrentNavigableMap.class.isAssignableFrom(mapInterface)) { - map = new ConcurrentSkipListMap<>(); - } else if (ConcurrentMap.class.isAssignableFrom(mapInterface)) { - map = new ConcurrentHashMap<>(); - } else if (NavigableMap.class.isAssignableFrom(mapInterface)) { - map = new TreeMap<>(); - } else if (SortedMap.class.isAssignableFrom(mapInterface)) { - map = new TreeMap<>(); - } - return map; - } - } diff --git a/easy-random-core/src/main/java/org/jeasy/random/util/ReflectionUtils.java b/easy-random-core/src/main/java/org/jeasy/random/util/ReflectionUtils.java index 5240e06fd..466b3a293 100644 --- a/easy-random-core/src/main/java/org/jeasy/random/util/ReflectionUtils.java +++ b/easy-random-core/src/main/java/org/jeasy/random/util/ReflectionUtils.java @@ -28,11 +28,13 @@ import org.jeasy.random.ObjectCreationException; import org.jeasy.random.api.Randomizer; import lombok.experimental.UtilityClass; +import org.objenesis.ObjenesisStd; import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.text.SimpleDateFormat; import java.util.*; +import java.util.concurrent.*; import java.util.function.Supplier; import java.util.stream.Stream; @@ -419,6 +421,70 @@ public static boolean isAnnotationPresent(Field field, Class getEmptyImplementationForCollectionInterface(final Class collectionInterface) { + Collection collection = new ArrayList<>(); + if (List.class.isAssignableFrom(collectionInterface)) { + collection = new ArrayList<>(); + } else if (NavigableSet.class.isAssignableFrom(collectionInterface)) { + collection = new TreeSet<>(); + } else if (SortedSet.class.isAssignableFrom(collectionInterface)) { + collection = new TreeSet<>(); + } else if (Set.class.isAssignableFrom(collectionInterface)) { + collection = new HashSet<>(); + } else if (BlockingDeque.class.isAssignableFrom(collectionInterface)) { + collection = new LinkedBlockingDeque<>(); + } else if (Deque.class.isAssignableFrom(collectionInterface)) { + collection = new ArrayDeque<>(); + } else if (TransferQueue.class.isAssignableFrom(collectionInterface)) { + collection = new LinkedTransferQueue<>(); + } else if (BlockingQueue.class.isAssignableFrom(collectionInterface)) { + collection = new LinkedBlockingQueue<>(); + } else if (Queue.class.isAssignableFrom(collectionInterface)) { + collection = new LinkedList<>(); + } + return collection; + } + + public static Collection createEmptyCollectionForType(Class fieldType, int initialSize) { + rejectUnsupportedTypes(fieldType); + Collection collection; + try { + collection = (Collection) fieldType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + if (fieldType.equals(ArrayBlockingQueue.class)) { + collection = new ArrayBlockingQueue<>(initialSize); + } else { + collection = (Collection) new ObjenesisStd().newInstance(fieldType); + } + } + return collection; + } + + public static Map getEmptyImplementationForMapInterface(final Class mapInterface) { + Map map = new HashMap<>(); + if (ConcurrentNavigableMap.class.isAssignableFrom(mapInterface)) { + map = new ConcurrentSkipListMap<>(); + } else if (ConcurrentMap.class.isAssignableFrom(mapInterface)) { + map = new ConcurrentHashMap<>(); + } else if (NavigableMap.class.isAssignableFrom(mapInterface)) { + map = new TreeMap<>(); + } else if (SortedMap.class.isAssignableFrom(mapInterface)) { + map = new TreeMap<>(); + } + return map; + } + + private void rejectUnsupportedTypes(Class type) { + if (type.equals(SynchronousQueue.class)) { + // SynchronousQueue is not supported since it requires a consuming thread at insertion time + throw new UnsupportedOperationException(SynchronousQueue.class.getName() + " type is not supported"); + } + if (type.equals(DelayQueue.class)) { + // DelayQueue is not supported since it requires creating dummy delayed objects + throw new UnsupportedOperationException(DelayQueue.class.getName() + " type is not supported"); + } + } + /** * Get the read method for given field. * @param field field to get the read method for. diff --git a/easy-random-core/src/test/java/org/jeasy/random/CollectionPopulatorTest.java b/easy-random-core/src/test/java/org/jeasy/random/CollectionPopulatorTest.java index b0a939275..b4ea9dca0 100644 --- a/easy-random-core/src/test/java/org/jeasy/random/CollectionPopulatorTest.java +++ b/easy-random-core/src/test/java/org/jeasy/random/CollectionPopulatorTest.java @@ -57,7 +57,6 @@ @SuppressWarnings({"unchecked", "rawtypes"}) public class CollectionPopulatorTest { - private static final int INITIAL_CAPACITY = 10; private static final int SIZE = 2; private static final String STRING = "foo"; @@ -130,13 +129,6 @@ public void typedConcreteCollectionTypesMightBePopulated() throws Exception { assertThat(collection).containsExactly(STRING, STRING); } - @Test - public void getEmptyImplementationForCollectionInterface() { - Collection collection = collectionPopulator.getEmptyImplementationForCollectionInterface(List.class); - - assertThat(collection).isInstanceOf(ArrayList.class).isEmpty(); - } - @Data @SuppressWarnings("rawtypes") class Foo { @@ -418,25 +410,6 @@ public void typeVariableCollectionTypesMustBeGeneratedEmpty() { assertThat(bean.getMap()).isEmpty(); } - - @Test - public void createEmptyCollectionForArrayBlockingQueue() { - Collection collection = collectionPopulator.createEmptyCollectionForType(ArrayBlockingQueue.class, INITIAL_CAPACITY); - - assertThat(collection).isInstanceOf(ArrayBlockingQueue.class).isEmpty(); - assertThat(((ArrayBlockingQueue) collection).remainingCapacity()).isEqualTo(INITIAL_CAPACITY); - } - - @Test - public void synchronousQueueShouldBeRejected() { - assertThatThrownBy(() -> collectionPopulator.createEmptyCollectionForType(SynchronousQueue.class, INITIAL_CAPACITY)).isInstanceOf(UnsupportedOperationException.class); - } - - @Test - public void delayQueueShouldBeRejected() { - assertThatThrownBy(() -> collectionPopulator.createEmptyCollectionForType(DelayQueue.class, INITIAL_CAPACITY)).isInstanceOf(UnsupportedOperationException.class); - } - private void assertContainsOnlyNonEmptyPersons(Collection persons) { for (Person Person : persons) { assertThat(Person).isNotNull(); diff --git a/easy-random-core/src/test/java/org/jeasy/random/MapPopulatorTest.java b/easy-random-core/src/test/java/org/jeasy/random/MapPopulatorTest.java index c5d6e76c3..258483249 100644 --- a/easy-random-core/src/test/java/org/jeasy/random/MapPopulatorTest.java +++ b/easy-random-core/src/test/java/org/jeasy/random/MapPopulatorTest.java @@ -126,13 +126,6 @@ public void typedConcreteMapTypesMightBePopulated() throws Exception { assertThat(randomMap).containsExactly(entry(FOO, BAR)); } - @Test - public void getEmptyImplementationForMapInterface() { - Map map = mapPopulator.getEmptyImplementationForMapInterface(SortedMap.class); - - assertThat(map).isInstanceOf(TreeMap.class).isEmpty(); - } - @Test public void notAddNullKeysToMap() throws NoSuchFieldException { // Given diff --git a/easy-random-core/src/test/java/org/jeasy/random/util/ReflectionUtilsTest.java b/easy-random-core/src/test/java/org/jeasy/random/util/ReflectionUtilsTest.java index 2a413b513..806059b07 100644 --- a/easy-random-core/src/test/java/org/jeasy/random/util/ReflectionUtilsTest.java +++ b/easy-random-core/src/test/java/org/jeasy/random/util/ReflectionUtilsTest.java @@ -32,16 +32,20 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.SynchronousQueue; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ReflectionUtilsTest { + private static final int INITIAL_CAPACITY = 10; + @Test public void testGetDeclaredFields() throws Exception { BigDecimal javaVersion = new BigDecimal(System.getProperty("java.specification.version")); @@ -187,6 +191,38 @@ public void testIsAnnotationPresent() throws NoSuchMethodException, NoSuchFieldE assertThat(ReflectionUtils.isAnnotationPresent(field, NotNull.class)).isFalse(); } + @Test + public void testGetEmptyImplementationForCollectionInterface() { + Collection collection = ReflectionUtils.getEmptyImplementationForCollectionInterface(List.class); + + assertThat(collection).isInstanceOf(ArrayList.class).isEmpty(); + } + + @Test + public void createEmptyCollectionForArrayBlockingQueue() { + Collection collection = ReflectionUtils.createEmptyCollectionForType(ArrayBlockingQueue.class, INITIAL_CAPACITY); + + assertThat(collection).isInstanceOf(ArrayBlockingQueue.class).isEmpty(); + assertThat(((ArrayBlockingQueue) collection).remainingCapacity()).isEqualTo(INITIAL_CAPACITY); + } + + @Test + public void synchronousQueueShouldBeRejected() { + assertThatThrownBy(() -> ReflectionUtils.createEmptyCollectionForType(SynchronousQueue.class, INITIAL_CAPACITY)).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + public void delayQueueShouldBeRejected() { + assertThatThrownBy(() -> ReflectionUtils.createEmptyCollectionForType(DelayQueue.class, INITIAL_CAPACITY)).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + public void getEmptyImplementationForMapInterface() { + Map map = ReflectionUtils.getEmptyImplementationForMapInterface(SortedMap.class); + + assertThat(map).isInstanceOf(TreeMap.class).isEmpty(); + } + @SuppressWarnings("unused") private class PrimitiveFieldsWithDefaultValuesBean { public boolean bool;