001/* 002 * Licensed to the author under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package de.cuioss.test.generator.internal.net.java.quickcheck; 018 019import java.io.PrintWriter; 020 021import lombok.experimental.UtilityClass; 022 023/** 024 * QuickCheck is an implementation of the Haskell QuickCheck generator based 025 * test tool (<a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/">...</a>). 026 */ 027@UtilityClass 028@SuppressWarnings("java:S106") // owolff ok for testcode 029public class QuickCheck { 030 031 public static final int MAX_NUMBER_OF_RUNS = 200; 032 public static final int MIN_NUMBER_OF_RUNS = 1; 033 034 public static final String SYSTEM_PROPERTY_RUNS = propertyName("RUNS"); 035 036 /** 037 * Check the {@link Characteristic} for all values generated by the given 038 * {@link Generator}. The execution will fail fast if any of the calls of the 039 * {@link Characteristic#specify(Object)} method throws an exception. 040 * 041 * @param <T> type of the generated values 042 * @throws CharacteristicException if a characteristic is not {@code true} for a 043 * generated value 044 * @throws GeneratorException if generation of the next value failed. 045 */ 046 public static <T> void forAll(Generator<T> generator, Characteristic<T> characteristic) 047 throws GeneratorException, CharacteristicException { 048 runner(characteristic, MAX_NUMBER_OF_RUNS, generator, new PrintWriter(new NullWriter())).forAll(); 049 } 050 051 public static int getDefaultNumberOfRuns() { 052 var runs = Integer.getInteger(SYSTEM_PROPERTY_RUNS, MAX_NUMBER_OF_RUNS); 053 return Math.max(MIN_NUMBER_OF_RUNS, runs); 054 } 055 056 private static String propertyName(String name) { 057 return QuickCheck.class.getSimpleName() + "." + name; 058 } 059 060 /** 061 * Check the {@link Characteristic} for all values generated by the given 062 * {@link Generator}. The execution will fail fast if any of the calls of the 063 * {@link Characteristic#specify(Object)} method throws an exception. 064 * 065 * @param runs number of runs and generated values for this characteristic 066 * @param <T> type of the generated values 067 * @throws CharacteristicException if a characteristic is not {@code true} for a 068 * generated value 069 * @throws GeneratorException if generation of the next value failed. 070 */ 071 public static <T> void forAll(int runs, Generator<T> generator, Characteristic<T> characteristic) 072 throws GeneratorException, CharacteristicException { 073 runner(characteristic, runs, generator, new PrintWriter(new NullWriter())).forAll(); 074 } 075 076 /** 077 * Check the {@link Characteristic} for all values generated by the given 078 * {@link Generator}. The execution will fail fast if any of the calls of the 079 * {@link Characteristic#specify(Object)} method throws an exception. 080 * 081 * @param <T> type of the generated values 082 * @throws CharacteristicException if a characteristic is not {@code true} for a 083 * generated value 084 * @throws GeneratorException if generation of the next value failed. 085 */ 086 public static <T> void forAllVerbose(Generator<T> generator, Characteristic<T> characteristic) 087 throws GeneratorException, CharacteristicException { 088 runner(characteristic, MAX_NUMBER_OF_RUNS, generator, new PrintWriter(new PrintWriter(System.out))).forAll(); 089 } 090 091 /** 092 * Check the {@link Characteristic} for all values generated by the given 093 * {@link Generator}. The execution will fail fast if any of the calls of the 094 * {@link Characteristic#specify(Object)} method throws an exception. 095 * 096 * @param runs number of runs and generated values for this characteristic 097 * @param <T> type of the generated values 098 * @throws CharacteristicException if a characteristic is not {@code true} for a 099 * generated value 100 * @throws GeneratorException if generation of the next value failed. 101 */ 102 public static <T> void forAllVerbose(int runs, Generator<T> generator, Characteristic<T> characteristic) 103 throws GeneratorException, CharacteristicException { 104 runner(characteristic, runs, generator, new PrintWriter(new PrintWriter(System.out))).forAll(); 105 } 106 107 /** 108 * All executions of {@link Characteristic#specify(Object)} which execute this 109 * method will be skipped and a new test case will be generated. Execution will 110 * be stopped if it is not possible to create a new test cases after a 111 * reasonable amount of tries. 112 * 113 * @param predicate Skip the current test case if the predicate is true. 114 */ 115 public static void guard(boolean predicate) { 116 if (!predicate) { 117 throw new GuardException(); 118 } 119 } 120 121 private static <T> Runner<T> runner(Characteristic<T> characteristic, int runs, Generator<T> generator, 122 PrintWriter writer) { 123 return new RunnerImpl<>(characteristic, runs, generator, writer); 124 } 125}