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