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