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.generator.support; 018 019import static de.cuioss.test.generator.internal.net.java.quickcheck.generator.iterable.Iterables.sizeOf; 020import static de.cuioss.tools.base.Preconditions.checkArgument; 021 022import java.util.Iterator; 023import java.util.Objects; 024 025import de.cuioss.test.generator.internal.net.java.quickcheck.Generator; 026import de.cuioss.test.generator.internal.net.java.quickcheck.StatefulGenerator; 027 028public class EnsuredValuesGenerator<T> implements StatefulGenerator<T> { 029 030 private final Iterable<T> ensured; 031 private final Generator<T> otherValues; 032 private Iterator<T> iterator; 033 private final int size; 034 private final int window; 035 private int valuesLeft; 036 private int generatesLeft; 037 038 public EnsuredValuesGenerator(Iterable<T> values) { 039 this(values, new FixedValuesGenerator<>(values)); 040 } 041 042 public EnsuredValuesGenerator(Iterable<T> ensured, Generator<T> random) { 043 this(ensured, sizeOf(ensured), random); 044 } 045 046 public EnsuredValuesGenerator(Iterable<T> ensured, int window, Generator<T> random) { 047 this.size = sizeOf(ensured); 048 checkArgument(this.size <= window, "window"); 049 this.window = window; 050 Objects.requireNonNull(random, "random"); 051 this.ensured = ensured; 052 this.otherValues = random; 053 054 reset(); 055 } 056 057 @Override 058 public T next() { 059 return takeEnsured() ? iterator.next() : otherValues.next(); 060 } 061 062 private boolean takeEnsured() { 063 if (valuesLeft > 0 && spreadOverWindow()) { 064 valuesLeft--; 065 return true; 066 } 067 generatesLeft--; 068 return false; 069 } 070 071 /** 072 * @return true if an ensured values should be taken. The results should be such 073 * that the ensured values are uniformly distributed over the window. 074 */ 075 private boolean spreadOverWindow() { 076 assert valuesLeft > 0 && generatesLeft >= 0; 077 return new IntegerGenerator(0, valuesLeft + generatesLeft).next() <= valuesLeft; 078 } 079 080 @Override 081 public void reset() { 082 iterator = ensured.iterator(); 083 valuesLeft = size; 084 generatesLeft = window - size; 085 assert generatesLeft >= 0 : generatesLeft; 086 } 087}