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