001/*
002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de)
003 *
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 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
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;
017
018import de.cuioss.test.generator.impl.CollectionGenerator;
019import de.cuioss.test.generator.impl.DecoratorGenerator;
020import de.cuioss.test.generator.impl.FloatObjectGenerator;
021import de.cuioss.test.generator.impl.LocalDateGenerator;
022import de.cuioss.test.generator.impl.LocalDateTimeGenerator;
023import de.cuioss.test.generator.impl.LocalTimeGenerator;
024import de.cuioss.test.generator.impl.NonBlankStringGenerator;
025import de.cuioss.test.generator.impl.NumberGenerator;
026import de.cuioss.test.generator.impl.ShortObjectGenerator;
027import de.cuioss.test.generator.impl.URLGenerator;
028import de.cuioss.test.generator.impl.ZoneOffsetGenerator;
029import de.cuioss.test.generator.impl.ZonedDateTimeGenerator;
030import de.cuioss.test.generator.internal.net.QuickCheckGeneratorAdapter;
031import de.cuioss.test.generator.internal.net.java.quickcheck.Generator;
032import de.cuioss.test.generator.internal.net.java.quickcheck.generator.CombinedGenerators;
033import de.cuioss.test.generator.internal.net.java.quickcheck.generator.PrimitiveGenerators;
034import de.cuioss.test.generator.internal.net.java.quickcheck.generator.support.FixedValuesGenerator;
035import lombok.experimental.UtilityClass;
036
037import java.io.Serializable;
038import java.net.URL;
039import java.time.LocalDate;
040import java.time.LocalDateTime;
041import java.time.LocalTime;
042import java.time.ZoneId;
043import java.time.ZoneOffset;
044import java.time.ZonedDateTime;
045import java.time.temporal.Temporal;
046import java.util.ArrayList;
047import java.util.Arrays;
048import java.util.Collection;
049import java.util.Date;
050import java.util.List;
051import java.util.Locale;
052import java.util.Optional;
053import java.util.TimeZone;
054
055import static java.util.Objects.requireNonNull;
056
057/**
058 * Provides factory methods for creating {@link TypedGenerator}s for various Java types.
059 * All generators are thread-safe and suitable for concurrent use in tests.
060 * 
061 * <p>The generators are organized into the following categories:</p>
062 * <ul>
063 *   <li>Primitive Types and their Wrappers (boolean, int, long, etc.)</li>
064 *   <li>String Generators (empty, non-empty, letters only)</li>
065 *   <li>Date and Time Types (Date, LocalDate, ZonedDateTime, etc.)</li>
066 *   <li>Collection Types (List, Set, SortedSet)</li>
067 *   <li>Common Java Types (URL, Locale, Class)</li>
068 * </ul>
069 * 
070 * <p><em>Usage examples from tests:</em></p>
071 * <pre>
072 * {@code
073 * // Basic generators
074 * TypedGenerator&lt;String&gt; generator = Generators.strings("X", 2, 2);
075 * String value = generator.next();
076 * 
077 * // Fixed values
078 * TypedGenerator&lt;String&gt; generator = Generators.fixedValues("A", "B", "C");
079 * String value = generator.next();
080 * 
081 * // Enum values
082 * Optional&lt;TypedGenerator&lt;TimeUnit&gt;&gt; generator = Generators.enumValuesIfAvailable(TimeUnit.class);
083 * TypedGenerator&lt;TimeUnit&gt; generator = Generators.enumValues(TimeUnit.class);
084 * 
085 * // Unique values
086 * TypedGenerator&lt;Integer&gt; baseGen = Generators.integers(1, 10);
087 * TypedGenerator&lt;Integer&gt; uniqueGen = Generators.uniqueValues(baseGen);
088 * Set&lt;Integer&gt; seen = new HashSet&lt;&gt;();
089 * for (int i = 0; i &lt; 10; i++) {
090 *     seen.add(uniqueGen.next());
091 * }
092 * }
093 * </pre>
094 *
095 * @author Oliver Wolff
096 * @since 1.0
097 */
098@UtilityClass
099public class Generators {
100
101    /**
102     * Factory method for creating a generator for a possible given enum.
103     * 
104     * <p><em>Example from tests:</em></p>
105     * <pre>
106     * Optional&lt;TypedGenerator&lt;TimeUnit&gt;&gt; generator = Generators.enumValuesIfAvailable(TimeUnit.class);
107     * assertTrue(generator.isPresent());
108     * assertNotNull(generator.get().next());
109     * </pre>
110     *
111     * @param <T> The enum type
112     * @param type to be checked, must represent an enum
113     * @return an {@link Optional} containing the corresponding {@link TypedGenerator} if
114     *         the given type is an enum, {@link Optional#empty()} otherwise
115     * @throws NullPointerException if type is null
116     */
117    @SuppressWarnings({"rawtypes", "unchecked"})
118    public static <T> Optional<TypedGenerator<T>> enumValuesIfAvailable(final Class<T> type) {
119        if (null == type || !type.isEnum()) {
120            return Optional.empty();
121        }
122        return Optional.of(new QuickCheckGeneratorAdapter(type, PrimitiveGenerators.enumValues((Class<Enum>) type)));
123    }
124
125    /**
126     * Factory method for creating a generator for a given enum.
127     * 
128     * <p><em>Example from tests:</em></p>
129     * <pre>
130     * TypedGenerator&lt;TimeUnit&gt; generator = Generators.enumValues(TimeUnit.class);
131     * TimeUnit value = generator.next();
132     * assertNotNull(value);
133     * </pre>
134     *
135     * @param <T> The enum type
136     * @param type to be checked, must represent an enum
137     * @return A {@link TypedGenerator} for the given enum
138     * @throws IllegalArgumentException if type is not an enum
139     * @throws NullPointerException if type is null
140     */
141    public static <T extends Enum<T>> TypedGenerator<T> enumValues(final Class<T> type) {
142        requireNonNull(type);
143        return new QuickCheckGeneratorAdapter<>(type, PrimitiveGenerators.enumValues(type));
144    }
145
146    /**
147     * Factory method for creating a {@link TypedGenerator} for non-empty Strings.
148     *
149     * @return a {@link TypedGenerator} for non-empty Strings
150     */
151    public static TypedGenerator<String> nonEmptyStrings() {
152        return new QuickCheckGeneratorAdapter<>(String.class, PrimitiveGenerators.nonEmptyStrings());
153    }
154
155    /**
156     * Factory method for creating a {@link TypedGenerator} for non-blank Strings.
157     *
158     * @return a {@link TypedGenerator} for non-blank Strings.
159     */
160    public static TypedGenerator<String> nonBlankStrings() {
161        return new NonBlankStringGenerator();
162    }
163
164    /**
165     * Factory method for creating a {@link TypedGenerator} for Strings.
166     *
167     * @param minSize lower bound of size
168     * @param maxSize upper bound of size
169     * @return a {@link TypedGenerator} for Strings
170     */
171    public static TypedGenerator<String> strings(final int minSize, final int maxSize) {
172        return new QuickCheckGeneratorAdapter<>(String.class, PrimitiveGenerators.strings(minSize, maxSize));
173    }
174
175    /**
176     * Factory method for creating strings with given characters and size.
177     *
178     * <p><em>Example from tests:</em></p>
179     * <pre>
180     * TypedGenerator&lt;String&gt; generator = Generators.strings("X", 2, 2);
181     * String result = generator.next();
182     * assertEquals(2, result.length());
183     * assertTrue(result.matches("^X+$"));
184     * </pre>
185     *
186     * @param chars   to be generated
187     * @param minSize lower bound of size
188     * @param maxSize upper bound of size
189     * @return a {@link TypedGenerator} for Strings
190     * @throws IllegalArgumentException if minSize > maxSize or either is negative
191     * @throws NullPointerException if chars is null
192     */
193    public static TypedGenerator<String> strings(final String chars, final int minSize, final int maxSize) {
194        return new QuickCheckGeneratorAdapter<>(String.class, PrimitiveGenerators.strings(chars, minSize, maxSize));
195    }
196
197    /**
198     * Factory method for creating a {@link TypedGenerator} for any Strings, may be
199     * null or empty.
200     *
201     * @return a {@link TypedGenerator} for Strings
202     */
203    public static TypedGenerator<String> strings() {
204        return new QuickCheckGeneratorAdapter<>(String.class, PrimitiveGenerators.strings());
205    }
206
207    /**
208     * Factory method for creating a {@link TypedGenerator} for letter Strings.
209     *
210     * @param minSize lower bound of size
211     * @param maxSize upper bound of size
212     * @return a {@link TypedGenerator} for Strings
213     */
214    public static TypedGenerator<String> letterStrings(final int minSize, final int maxSize) {
215        return new QuickCheckGeneratorAdapter<>(String.class, PrimitiveGenerators.letterStrings(minSize, maxSize));
216    }
217
218    /**
219     * Factory method for creating a {@link TypedGenerator} for sensible / simple
220     * non empty letter Strings. The mininmal size is 3, the maximal size between 3
221     * and 256 characters
222     *
223     * @return a {@link TypedGenerator} for Strings
224     */
225    public static TypedGenerator<String> letterStrings() {
226        return letterStrings(3, integers(3, 256).next());
227    }
228
229    /**
230     * Factory method for creating a {@link TypedGenerator} for a number of fixed
231     * values.
232     *
233     * <p><em>Example from tests:</em></p>
234     * <pre>
235     * TypedGenerator&lt;String&gt; generator = Generators.fixedValues("A", "B", "C");
236     * assertEquals("A", generator.next());
237     * assertEquals("B", generator.next());
238     * assertEquals("C", generator.next());
239     * assertEquals("A", generator.next()); // Cycles back to start
240     * </pre>
241     *
242     * @param <T> The type of values
243     * @param values to be generated from.
244     * @return a {@link TypedGenerator} for the given values
245     * @throws IllegalArgumentException if values is empty
246     * @throws NullPointerException if values is null
247     */
248    @SafeVarargs
249    public static <T> TypedGenerator<T> fixedValues(final Class<T> type, final T... values) {
250        return fixedValues(type, Arrays.asList(values));
251    }
252
253    /**
254     * Factory method for creating a {@link TypedGenerator} for a number of fixed
255     * values.
256     *
257     * @param values to be generated from.
258     * @return a {@link TypedGenerator} for the given values
259     */
260    @SafeVarargs
261    public static <T> TypedGenerator<T> fixedValues(final T... values) {
262        return fixedValues(Arrays.asList(values));
263    }
264
265    /**
266     * Factory method for creating a {@link TypedGenerator} for a number of fixed
267     * values.
268     *
269     * @param type   of the value
270     * @param values to be generated from.
271     * @return a {@link TypedGenerator} for the given values
272     */
273    public static <T> TypedGenerator<T> fixedValues(final Class<T> type, final Iterable<T> values) {
274        var list = new ArrayList<T>();
275        values.forEach(list::add);
276        return new QuickCheckGeneratorAdapter<>(type, new FixedValuesGenerator<>(list));
277    }
278
279    /**
280     * Factory method for creating a {@link TypedGenerator} for a number of fixed
281     * values.
282     *
283     * @param values to be generated from.
284     * @return a {@link TypedGenerator} for the given values
285     */
286    public static <T> TypedGenerator<T> fixedValues(final Iterable<T> values) {
287        return fixedValues(determineSupertypeFromIterable(values), values);
288    }
289
290    /* Combined generators */
291
292    /**
293     * Factory method for creating a {@link TypedGenerator} generating unique
294     * values. In case this does not work it will throw an {@link RuntimeException}
295     *
296     * <p><em>Example from tests:</em></p>
297     * <pre>
298     * TypedGenerator&lt;Integer&gt; baseGen = Generators.integers(1, 10);
299     * TypedGenerator&lt;Integer&gt; uniqueGen = Generators.uniqueValues(baseGen);
300     * Set&lt;Integer&gt; seen = new HashSet&lt;&gt;();
301     * for (int i = 0; i &lt; 10; i++) {
302     *     assertTrue(seen.add(uniqueGen.next())); // Each value is unique
303     * }
304     * </pre>
305     *
306     * @param <T> The type of values
307     * @param source to be generated from.
308     * @return a {@link TypedGenerator} that ensures unique values
309     * @throws RuntimeException if unique value generation is not possible
310     *         (e.g., when source has limited unique values)
311     * @throws NullPointerException if source is null
312     */
313    @SuppressWarnings("unchecked") // Check not needed, because given TypedGenerator provides
314    // correct type
315    public static <T> TypedGenerator<T> uniqueValues(final TypedGenerator<T> source) {
316        return new QuickCheckGeneratorAdapter<>((Class<T>) source.getClass(),
317                CombinedGenerators.uniqueValues(unwrap(source)));
318    }
319
320    /**
321     * Factory method for creating a {@link CollectionGenerator} generating
322     * {@link Collection}s from the given {@link TypedGenerator} .
323     *
324     * @param <T> The type of values
325     * @param source to be generated from.
326     * @return a {@link TypedGenerator} for the given values
327     */
328    public static <T> CollectionGenerator<T> asCollectionGenerator(final TypedGenerator<T> source) {
329        return new CollectionGenerator<>(source);
330    }
331
332    // Basic Java Types
333
334    /**
335     * Factory method for creating a {@link TypedGenerator} for boolean primitives.
336     *
337     * @return a {@link TypedGenerator} for boolean primitives
338     */
339    public static TypedGenerator<Boolean> booleans() {
340        return new QuickCheckGeneratorAdapter<>(boolean.class, PrimitiveGenerators.booleans());
341    }
342
343    /**
344     * Factory method for creating a {@link TypedGenerator} for {@link Boolean}.
345     *
346     * @return a {@link TypedGenerator} for {@link Boolean}
347     */
348    public static TypedGenerator<Boolean> booleanObjects() {
349        return new QuickCheckGeneratorAdapter<>(Boolean.class, PrimitiveGenerators.booleans());
350    }
351
352    /**
353     * Factory method for creating a {@link TypedGenerator} for byte primitives.
354     *
355     * @return a {@link TypedGenerator} for byte primitives
356     */
357    public static TypedGenerator<Byte> bytes() {
358        return new QuickCheckGeneratorAdapter<>(byte.class, PrimitiveGenerators.bytes());
359    }
360
361    /**
362     * Factory method for creating a {@link TypedGenerator} for {@link Byte}.
363     *
364     * @return a {@link TypedGenerator} for {@link Byte}
365     */
366    public static TypedGenerator<Byte> byteObjects() {
367        return new QuickCheckGeneratorAdapter<>(Byte.class, PrimitiveGenerators.bytes());
368    }
369
370    /**
371     * Factory method for creating a {@link TypedGenerator} for char primitives.
372     *
373     * @return a {@link TypedGenerator} for char primitives
374     */
375    public static TypedGenerator<Character> characters() {
376        return new QuickCheckGeneratorAdapter<>(char.class, PrimitiveGenerators.characters());
377    }
378
379    /**
380     * Factory method for creating a {@link TypedGenerator} for {@link Character}.
381     *
382     * @return a {@link TypedGenerator} for {@link Character}
383     */
384    public static TypedGenerator<Character> characterObjects() {
385        return new QuickCheckGeneratorAdapter<>(Character.class, PrimitiveGenerators.characters());
386    }
387
388    /**
389     * Factory method for creating a {@link TypedGenerator} for double primitives.
390     *
391     * @return a {@link TypedGenerator} for double primitives
392     */
393    public static TypedGenerator<Double> doubles() {
394        return new QuickCheckGeneratorAdapter<>(double.class, PrimitiveGenerators.doubles());
395    }
396
397    /**
398     * Factory method for creating a {@link TypedGenerator} for {@link Double}.
399     *
400     * @param low  lower bound of range
401     * @param high upper bound of range
402     * @return a {@link TypedGenerator} for {@link Double}
403     */
404    public static TypedGenerator<Double> doubles(final double low, final double high) {
405        return new QuickCheckGeneratorAdapter<>(Double.class, PrimitiveGenerators.doubles(low, high));
406    }
407
408    /**
409     * Factory method for creating a {@link TypedGenerator} for {@link Double}.
410     *
411     * @return a {@link TypedGenerator} for {@link Double}
412     */
413    public static TypedGenerator<Double> doubleObjects() {
414        return new QuickCheckGeneratorAdapter<>(Double.class, PrimitiveGenerators.doubles());
415    }
416
417    /**
418     * Factory method for creating a {@link TypedGenerator} for float primitives.
419     *
420     * @return a {@link TypedGenerator} for float primitives
421     */
422    public static TypedGenerator<Float> floats() {
423        return new DecoratorGenerator<>(float.class, floatObjects());
424    }
425
426    /**
427     * Factory method for creating a {@link TypedGenerator} for {@link Float}.
428     *
429     * @param low  lower bound of range
430     * @param high upper bound of range
431     * @return a {@link TypedGenerator} for {@link Float}
432     */
433    public static TypedGenerator<Float> floats(final float low, final float high) {
434        return new FloatObjectGenerator(low, high);
435    }
436
437    /**
438     * Factory method for creating a {@link TypedGenerator} for {@link Float}.
439     *
440     * @return a {@link TypedGenerator} for {@link Float}
441     */
442    public static TypedGenerator<Float> floatObjects() {
443        return new FloatObjectGenerator();
444    }
445
446    /**
447     * Factory method for creating a {@link TypedGenerator} for integer primitives.
448     *
449     * @return a {@link TypedGenerator} for integer primitives
450     */
451    public static TypedGenerator<Integer> integers() {
452        return new QuickCheckGeneratorAdapter<>(int.class, PrimitiveGenerators.integers());
453    }
454
455    /**
456     * Factory method for creating a {@link TypedGenerator} for {@link Integer}.
457     *
458     * @param low  lower bound of range
459     * @param high upper bound of range
460     * @return a {@link TypedGenerator} for {@link Integer}
461     */
462    public static TypedGenerator<Integer> integers(final int low, final int high) {
463        return new QuickCheckGeneratorAdapter<>(Integer.class, PrimitiveGenerators.integers(low, high));
464    }
465
466    /**
467     * Factory method for creating a {@link TypedGenerator} for {@link Integer}.
468     *
469     * @return a {@link TypedGenerator} for {@link Integer}
470     */
471    public static TypedGenerator<Integer> integerObjects() {
472        return new QuickCheckGeneratorAdapter<>(Integer.class, PrimitiveGenerators.integers());
473    }
474
475    /**
476     * Factory method for creating a {@link TypedGenerator} for {@link Number}.
477     *
478     * @return a {@link TypedGenerator} for {@link Number}
479     */
480    public static TypedGenerator<Number> numbers() {
481        return new NumberGenerator();
482    }
483
484    /**
485     * Factory method for creating a {@link TypedGenerator} for short primitives.
486     *
487     * @return a {@link TypedGenerator} for short primitives
488     */
489    public static TypedGenerator<Short> shorts() {
490        return new DecoratorGenerator<>(short.class, shortObjects());
491    }
492
493    /**
494     * Factory method for creating a {@link TypedGenerator} for {@link Short}.
495     *
496     * @return a {@link TypedGenerator} for {@link Short}
497     */
498    public static TypedGenerator<Short> shortObjects() {
499        return new ShortObjectGenerator();
500    }
501
502    /**
503     * Factory method for creating a {@link TypedGenerator} for long primitives.
504     *
505     * @return a {@link TypedGenerator} for long primitives
506     */
507    public static TypedGenerator<Long> longs() {
508        return new QuickCheckGeneratorAdapter<>(long.class, PrimitiveGenerators.longs());
509    }
510
511    /**
512     * Factory method for creating a {@link TypedGenerator} for Long primitives.
513     *
514     * @param low  lower bound of range
515     * @param high upper bound of range
516     * @return a {@link TypedGenerator} for long primitives
517     */
518    public static TypedGenerator<Long> longs(final long low, final long high) {
519        return new QuickCheckGeneratorAdapter<>(long.class, PrimitiveGenerators.longs(low, high));
520    }
521
522    /**
523     * Factory method for creating a {@link TypedGenerator} for {@link Long}.
524     *
525     * @return a {@link TypedGenerator} for {@link Long}
526     */
527    public static TypedGenerator<Long> longObjects() {
528        return new QuickCheckGeneratorAdapter<>(Long.class, PrimitiveGenerators.longs());
529    }
530
531    /**
532     * Factory method for creating a {@link TypedGenerator} for {@link Date}.
533     *
534     * @return a {@link TypedGenerator} for {@link Date}
535     */
536    public static TypedGenerator<Date> dates() {
537        return new QuickCheckGeneratorAdapter<>(Date.class, PrimitiveGenerators.dates());
538    }
539
540    /**
541     * Factory method for creating a {@link TypedGenerator} for {@link LocalDate}.
542     *
543     * @return a {@link TypedGenerator} for {@link LocalDate}
544     */
545    public static TypedGenerator<LocalDate> localDates() {
546        return new LocalDateGenerator();
547    }
548
549    /**
550     * Factory method for creating a {@link TypedGenerator} for {@link LocalTime}.
551     *
552     * @return a {@link TypedGenerator} for {@link LocalTime}
553     */
554    public static TypedGenerator<LocalTime> localTimes() {
555        return new LocalTimeGenerator();
556    }
557
558    /**
559     * Factory method for creating a {@link TypedGenerator} for
560     * {@link LocalDateTime}.
561     *
562     * @return a {@link TypedGenerator} for {@link LocalDateTime}
563     */
564    public static TypedGenerator<LocalDateTime> localDateTimes() {
565        return new LocalDateTimeGenerator();
566    }
567
568    /**
569     * Factory method for creating a {@link TypedGenerator} for
570     * {@link ZonedDateTime}.
571     *
572     * @return a {@link TypedGenerator} for {@link ZonedDateTime}
573     */
574    public static TypedGenerator<ZonedDateTime> zonedDateTimes() {
575        return new ZonedDateTimeGenerator();
576    }
577
578    /**
579     * Factory method for creating a {@link TypedGenerator} for {@link TimeZone}.
580     *
581     * @return a {@link TypedGenerator} for {@link TimeZone}
582     */
583    public static TypedGenerator<TimeZone> timeZones() {
584        final List<TimeZone> timezones = new ArrayList<>();
585        for (final String id : TimeZone.getAvailableIDs()) {
586            timezones.add(TimeZone.getTimeZone(id));
587        }
588        return fixedValues(TimeZone.class, timezones);
589    }
590
591    /**
592     * Factory method for creating a {@link TypedGenerator} for {@link ZoneId}.
593     *
594     * @return a {@link TypedGenerator} for {@link ZoneId}
595     */
596    public static TypedGenerator<ZoneId> zoneIds() {
597        return fixedValues(ZoneId.class, ZoneId.getAvailableZoneIds().stream().map(ZoneId::of).toList());
598    }
599
600    /**
601     * Factory method for creating a {@link TypedGenerator} for {@link ZoneOffset}.
602     *
603     * @return a {@link TypedGenerator} for {@link ZoneOffset}
604     */
605    public static TypedGenerator<ZoneOffset> zoneOffsets() {
606        return new ZoneOffsetGenerator();
607    }
608
609    /**
610     * Factory method for creating a {@link TypedGenerator} for {@link Temporal}s.
611     *
612     * @return a {@link TypedGenerator} for {@link Temporal}s
613     */
614    public static TypedGenerator<Temporal> temporals() {
615        return new TypedGenerator<>() {
616
617            @Override
618            public Class<Temporal> getType() {
619                return Temporal.class;
620            }
621
622            @Override
623            public Temporal next() {
624                return zonedDateTimes().next().toInstant();
625            }
626        };
627    }
628
629    // Advanced Java Types
630
631    /**
632     * Factory method for creating a {@link TypedGenerator} arbitrary {@link Class}
633     * Objects
634     *
635     * @return a {@link TypedGenerator} for the given values
636     */
637    @SuppressWarnings("rawtypes")
638    public static TypedGenerator<Class> classTypes() {
639        return fixedValues(Class.class, Integer.class, String.class, Boolean.class, Float.class);
640    }
641
642    /**
643     * Factory method for creating a {@link TypedGenerator} arbitrary {@link Locale}
644     * Objects
645     *
646     * @return a {@link TypedGenerator} for all {@link Locale}s
647     */
648    public static TypedGenerator<Locale> locales() {
649        return fixedValues(Locale.class, Locale.getAvailableLocales());
650    }
651
652    /**
653     * Factory method for creating a {@link TypedGenerator} arbitrary
654     * {@link Serializable} Objects
655     *
656     * @return a {@link TypedGenerator} for all {@link Serializable}s
657     */
658    @SuppressWarnings({"unchecked", "rawtypes"})
659    public static TypedGenerator<Serializable> serializables() {
660        return new QuickCheckGeneratorAdapter(Serializable.class, PrimitiveGenerators.nonEmptyStrings());
661    }
662
663    /**
664     * Factory method for creating a {@link TypedGenerator} arbitrary
665     * {@link RuntimeException} Objects
666     *
667     * @return a {@link TypedGenerator} for all {@link RuntimeException}s
668     */
669    public static TypedGenerator<RuntimeException> runtimeExceptions() {
670        return fixedValues(RuntimeException.class, new RuntimeException(), new IllegalArgumentException(),
671                new IllegalStateException(), new NullPointerException());
672    }
673
674    /**
675     * Factory method for creating a {@link TypedGenerator} arbitrary
676     * {@link Throwable} Objects
677     *
678     * @return a {@link TypedGenerator} for all {@link Throwable}s
679     */
680    public static TypedGenerator<Throwable> throwables() {
681        return fixedValues(Throwable.class, new RuntimeException(), new IllegalArgumentException(),
682                new IllegalStateException(), new NullPointerException());
683    }
684
685    /**
686     * Factory method for creating a {@link TypedGenerator} arbitrary {@link URL}s
687     * Objects
688     *
689     * @return a {@link TypedGenerator} for all {@link URL}s
690     */
691    public static TypedGenerator<URL> urls() {
692        return new URLGenerator();
693    }
694
695    /**
696     * Factory method for creating a QuickCheck {@link Generator} from an existing
697     * {@link TypedGenerator}. Note: This method is for internal use only and will
698     * be removed soon!!!
699     *
700     * @param <T> The type of values
701     * @param generator to be un-wrapped
702     * @return a {@link TypedGenerator} for the given {@link Generator}
703     */
704    static <T> Generator<T> unwrap(final TypedGenerator<T> generator) {
705        return generator::next;
706    }
707
708    /**
709     * Helper method that determines the actual type of a given {@link Iterable} by
710     * peeking into it. <em>For testing only, should never be used in productive
711     * code</em>
712     *
713     * @param iterable must not be null nor empty, the iterator must be reentrant.
714     * @return The Class of the given {@link Iterable}.
715     */
716    @SuppressWarnings("unchecked")
717    private static <T> Class<T> determineSupertypeFromIterable(final Iterable<T> iterable) {
718        requireNonNull(iterable, "iterable must not be null");
719        final var iterator = iterable.iterator();
720        if (iterator.hasNext()) {
721            return (Class<T>) iterator.next().getClass();
722        }
723        throw new IllegalArgumentException("Must contain at least a single element");
724    }
725}