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<String> generator = Generators.strings("X", 2, 2); 075 * String value = generator.next(); 076 * 077 * // Fixed values 078 * TypedGenerator<String> generator = Generators.fixedValues("A", "B", "C"); 079 * String value = generator.next(); 080 * 081 * // Enum values 082 * Optional<TypedGenerator<TimeUnit>> generator = Generators.enumValuesIfAvailable(TimeUnit.class); 083 * TypedGenerator<TimeUnit> generator = Generators.enumValues(TimeUnit.class); 084 * 085 * // Unique values 086 * TypedGenerator<Integer> baseGen = Generators.integers(1, 10); 087 * TypedGenerator<Integer> uniqueGen = Generators.uniqueValues(baseGen); 088 * Set<Integer> seen = new HashSet<>(); 089 * for (int i = 0; i < 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<TypedGenerator<TimeUnit>> 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<TimeUnit> 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<String> 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<String> 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<Integer> baseGen = Generators.integers(1, 10); 299 * TypedGenerator<Integer> uniqueGen = Generators.uniqueValues(baseGen); 300 * Set<Integer> seen = new HashSet<>(); 301 * for (int i = 0; i < 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}