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 java.lang.Math.signum; 020 021import java.util.Calendar; 022import java.util.Date; 023import java.util.concurrent.TimeUnit; 024 025import de.cuioss.test.generator.internal.net.java.quickcheck.Generator; 026 027public class DateGenerator implements Generator<Date> { 028 029 private final VetoableGenerator<Long> generator; 030 031 public DateGenerator(TimeUnit precision, long low, long high, int tries) { 032 generator = new VetoableGenerator<>(new MillisGenerator(precision, low, high), tries) { 033 034 @Override 035 protected boolean tryValue(Long value) { 036 return value != null; 037 } 038 }; 039 } 040 041 @Override 042 public Date next() { 043 return new Date(generator.next()); 044 } 045 046 private static class MillisGenerator implements Generator<Long> { 047 048 private final TimeUnit precision; 049 private final LongGenerator times; 050 private final long low; 051 private final long high; 052 053 public MillisGenerator(TimeUnit precision, long low, long high) { 054 this.precision = precision; 055 this.times = new LongGenerator(low, high); 056 this.low = low; 057 this.high = high; 058 } 059 060 @Override 061 public Long next() { 062 Long millis = times.next(); 063 Calendar time = Calendar.getInstance(); 064 time.setTimeInMillis(millis); 065 switch (precision) { 066 case DAYS: 067 time.set(Calendar.HOUR, 0); //$FALL-THROUGH$ 068 case HOURS: 069 time.set(Calendar.MINUTE, 0); //$FALL-THROUGH$ 070 case MINUTES: 071 time.set(Calendar.SECOND, 0); //$FALL-THROUGH$ 072 case SECONDS: 073 time.set(Calendar.MILLISECOND, 0); //$FALL-THROUGH$ 074 default: 075 } 076 long correctedMillis = time.getTimeInMillis(); 077 return isOutOffBounds(correctedMillis) || isOverflow(millis, correctedMillis) ? null : correctedMillis; 078 } 079 080 private boolean isOutOffBounds(long correctedMillis) { 081 return correctedMillis < low || correctedMillis > high; 082 } 083 084 // TODO define this differently (signum changes near 0 without overflow) 085 private boolean isOverflow(long millis, long correctedMillis) { 086 return signum(correctedMillis) != signum(millis); 087 } 088 089 @Override 090 public String toString() { 091 return "%s[low=%s, high=%s, precision=%s".formatted(getClass().getSimpleName(), low, high, precision); 092 } 093 094 } 095}