001package de.cuioss.test.generator.impl; 002 003import static de.cuioss.tools.collect.CollectionLiterals.mutableSet; 004import static java.util.Objects.requireNonNull; 005 006import java.util.ArrayList; 007import java.util.Collection; 008import java.util.List; 009import java.util.Set; 010import java.util.SortedSet; 011import java.util.TreeSet; 012 013import de.cuioss.test.generator.Generators; 014import de.cuioss.test.generator.TypedGenerator; 015import de.cuioss.tools.logging.CuiLogger; 016 017/** 018 * Wraps a given {@link TypedGenerator} and provides additional methods for creating {@link List}s 019 * and {@link Set}s 020 * 021 * @param <T> identifying the type of the object being generated 022 * @author Oliver Wolff 023 */ 024public class CollectionGenerator<T> implements TypedGenerator<T> { 025 026 private static final CuiLogger log = new CuiLogger(CollectionGenerator.class); 027 private static final String JAVA_UTIL_SORTED_SET = "java.util.SortedSet"; 028 029 private static final String JAVA_UTIL_COLLECTION = "java.util.Collection"; 030 031 private static final String JAVA_UTIL_SET = "java.util.Set"; 032 033 private static final String JAVA_UTIL_LIST = "java.util.List"; 034 035 private final TypedGenerator<T> wrapped; 036 037 private final TypedGenerator<Integer> sizeGenerator; 038 039 /** 040 * @param wrapped must not be null 041 * @param sizeGenerator must not be null 042 */ 043 public CollectionGenerator(final TypedGenerator<T> wrapped, final TypedGenerator<Integer> sizeGenerator) { 044 super(); 045 this.wrapped = requireNonNull(wrapped, "wrapped must not be null"); 046 this.sizeGenerator = requireNonNull(sizeGenerator, "sizeGenerator must not be null"); 047 } 048 049 /** 050 * Constructor. 051 * 052 * @param wrapped generator, must not be null 053 * @param lowerBound defines the lower bound of the integer generator that determines the 054 * of {@link Collection} size 055 * @param upperBound defines the upper bound of the integer generator that determines the 056 * of {@link Collection} size 057 */ 058 public CollectionGenerator(final TypedGenerator<T> wrapped, final int lowerBound, 059 final int upperBound) { 060 this(wrapped, 061 Generators.integers(lowerBound, upperBound)); 062 } 063 064 /** 065 * Constructor. 066 * using 2 and 12 as bounds of the {@link Collection} size to be created. 067 * 068 * @param wrapped generator, must not be null 069 */ 070 public CollectionGenerator(final TypedGenerator<T> wrapped) { 071 this(wrapped, 2, 12); 072 } 073 074 /** 075 * @return the next object from the contained {@link TypedGenerator} 076 */ 077 @Override 078 public T next() { 079 return this.wrapped.next(); 080 } 081 082 /** 083 * Returns a {@link List} of the elements provided by the generator 084 * 085 * @param count the number of elements within the list 086 * @return a list with a given number of elements. 087 */ 088 public List<T> list(final int count) { 089 final List<T> result = new ArrayList<>(); 090 for (var i = 0; i < count; i++) { 091 result.add(next()); 092 } 093 return result; 094 } 095 096 /** 097 * Returns a {@link Set} of the elements provided by the generator 098 * 099 * @param count the number of elements within the {@link Set}. It defines an upper bound of 100 * elements, but depending on the elements / the entropy of the generator there may 101 * be a lower number of elements. 102 * @return a {@link Set} with a given number of elements as maximum. 103 */ 104 public Set<T> set(final int count) { 105 final Set<T> result = mutableSet(); 106 for (var i = 0; i < count; i++) { 107 result.add(next()); 108 } 109 return result; 110 } 111 112 /** 113 * Returns a {@link SortedSet} of the elements provided by the generator 114 * 115 * @param count the number of elements within the {@link Set}. It defines an upper bound of 116 * elements, but depending on the elements / the entropy of the generator there may 117 * be a lower number of elements. 118 * @return a {@link Set} with a given number of elements as maximum. 119 */ 120 public SortedSet<T> sortedSet(final int count) { 121 return new TreeSet<>(set(count)); 122 } 123 124 /** 125 * @return a {@link Set} with a random number of elements as maximum. 126 */ 127 public Set<T> set() { 128 return set(this.sizeGenerator.next()); 129 } 130 131 /** 132 * @return a {@link List} with a random number of elements as maximum. 133 */ 134 public List<T> list() { 135 return list(this.sizeGenerator.next()); 136 } 137 138 /** 139 * @return a {@link SortedSet} with a random number of elements as maximum. 140 */ 141 public SortedSet<T> sortedSet() { 142 return sortedSet(this.sizeGenerator.next()); 143 } 144 145 /** 146 * Generates a concrete {@link Iterable}. 147 * It is smart enough to determine whether the elements are to be wrapped in a {@link List}, 148 * {@link Set}, {@link Collection} or {@link SortedSet}. 149 * 150 * @param expectedType type of the expected {@link Iterable} 151 * @return depending on the given expectedType a corresponding {@link Iterable}, 152 * {@link Collection}, {@link List}, {@link SortedSet} or {@link Set} 153 */ 154 public Iterable<T> nextCollection(final Class<? extends Iterable<?>> expectedType) { 155 requireNonNull(expectedType, "expectedType must not be null"); 156 switch (expectedType.getName()) { 157 case JAVA_UTIL_LIST: 158 return list(); 159 case JAVA_UTIL_SET: 160 return set(); 161 case JAVA_UTIL_COLLECTION: 162 return list(); 163 case JAVA_UTIL_SORTED_SET: 164 return sortedSet(); 165 default: 166 log.info("No specific case defined for {}. Returning list-implementation.", 167 expectedType.getName()); 168 return list(); 169 } 170 } 171}