All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jqwik.time.internal.properties.arbitraries.DefaultLocalTimeArbitrary Maven / Gradle / Ivy

package net.jqwik.time.internal.properties.arbitraries;

import java.time.*;
import java.time.temporal.*;

import org.apiguardian.api.*;

import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.time.api.arbitraries.*;
import net.jqwik.time.internal.properties.arbitraries.valueRanges.*;

import static java.time.temporal.ChronoUnit.*;
import static org.apiguardian.api.API.Status.*;

@API(status = INTERNAL)
public class DefaultLocalTimeArbitrary extends ArbitraryDecorator implements LocalTimeArbitrary {

	private final LocalTimeBetween timeBetween = new LocalTimeBetween();
	private final HourBetween hourBetween = (HourBetween) new HourBetween().set(0, 23);
	private final MinuteBetween minuteBetween = (MinuteBetween) new MinuteBetween().set(0, 59);
	private final SecondBetween secondBetween = (SecondBetween) new SecondBetween().set(0, 59);
	private final OfPrecision ofPrecision = new OfPrecision();

	@Override
	protected Arbitrary arbitrary() {

		LocalTime effectiveMin = effectiveMin(timeBetween, hourBetween, minuteBetween, secondBetween, ofPrecision);
		LocalTime effectiveMax = effectiveMax(timeBetween, hourBetween, minuteBetween, secondBetween, ofPrecision);

		long longEnd = ofPrecision.longsBetween(effectiveMin, effectiveMax);

		Arbitrary longs = Arbitraries.longs()
										   .withDistribution(RandomDistribution.uniform())
										   .between(0L, longEnd)
										   .edgeCases(config -> config.includeOnly(0L, longEnd));

		Arbitrary localTimes = longs.map(v -> ofPrecision.localTimeFromValue(v, effectiveMin));

		localTimes = localTimes.filter(
			20000,
			v -> v.getMinute() >= minuteBetween.getMin()
					 && v.getMinute() <= minuteBetween.getMax()
					 && v.getSecond() >= secondBetween.getMin()
					 && v.getSecond() <= secondBetween.getMax()
		);

		return localTimes;

	}

	public static LocalTime effectiveMin(
		LocalTimeBetween timeBetween,
		HourBetween hourBetween,
		MinuteBetween minuteBetween,
		SecondBetween secondBetween,
		OfPrecision ofPrecision
	) {
		checkMinValuesAndPrecision(minuteBetween, secondBetween, ofPrecision);
		LocalTime effective = timeBetween.getMin() != null ? timeBetween.getMin() : LocalTime.MIN;
		checkTimeValueAndPrecision(effective, ofPrecision, true);
		if (hourBetween.getMin() > effective.getHour()) {
			effective = effective.withHour(hourBetween.getMin());
			effective = effective.withMinute(0);
			effective = effective.withSecond(0);
			effective = effective.withNano(0);
		}
		if (minuteBetween.getMin() > effective.getMinute()) {
			effective = effective.withMinute(minuteBetween.getMin());
			effective = effective.withSecond(0);
			effective = effective.withNano(0);
		}
		if (secondBetween.getMin() > effective.getSecond()) {
			effective = effective.withSecond(secondBetween.getMin());
			effective = effective.withNano(0);
		}
		return effective;
	}

	public static void checkTimeValueAndPrecision(LocalTime time, OfPrecision ofPrecision, boolean minimum) {
		if (!ofPrecision.valueWithPrecisionIsAllowed(time.getMinute(), time.getSecond(), time.getNano())) {
			throwTimeAndPrecisionException(time.toString(), minimum, ofPrecision.get());
		}
	}

	private static void checkMinValuesAndPrecision(MinuteBetween minuteBetween, SecondBetween secondBetween, OfPrecision ofPrecision) {
		if (ofPrecision.isGreatherThan(SECONDS)) {
			if (secondBetween.getMin() > 0) {
				throwValueAndPrecisionException(secondBetween.getMin().toString(), true, "second", ofPrecision.get());
			}
			if (ofPrecision.isGreatherThan(MINUTES) && minuteBetween.getMin() > 0) {
				throwValueAndPrecisionException(minuteBetween.getMin().toString(), true, "minute", ofPrecision.get());
			}
		}
	}

	private static void throwValueAndPrecisionException(String val, boolean minimum, String unit, ChronoUnit precision) {
		String minMax = minimum ? "minimum" : "maximum";
		throw new IllegalArgumentException(String.format("Can't use %s as %s %s with precision %s.", val, minMax, unit, precision));
	}

	private static void throwTimeAndPrecisionException(String val, boolean minimum, ChronoUnit precision) {
		String minMax = minimum ? "minimum" : "maximum";
		throw new IllegalArgumentException(
			String
				.format("Can't use %s as %s time with precision %s.%nYou may want to round the time to %s or change the precision.", val, minMax, precision, precision)
		);
	}

	public static LocalTime effectiveMax(
		LocalTimeBetween timeBetween,
		HourBetween hourBetween,
		MinuteBetween minuteBetween,
		SecondBetween secondBetween,
		OfPrecision ofPrecision
	) {
		LocalTime effective = timeBetween.getMax() != null ? timeBetween.getMax() : ofPrecision.maxPossibleLocalTime();
		checkTimeValueAndPrecision(effective, ofPrecision, false);
		if (hourBetween.getMax() < effective.getHour()) {
			effective = effective.withHour(hourBetween.getMax());
			effective = effectiveMaxValues(effective, ofPrecision, MINUTES);
		}
		if (minuteBetween.getMax() < effective.getMinute()) {
			effective = effective.withMinute(minuteBetween.getMax());
			effective = effectiveMaxValues(effective, ofPrecision, SECONDS);
		}
		if (secondBetween.getMax() < effective.getSecond()) {
			effective = effective.withSecond(secondBetween.getMax());
			effective = effectiveMaxValues(effective, ofPrecision, NANOS);
		}
		return effective;
	}

	private static LocalTime effectiveMaxValues(LocalTime effective, OfPrecision ofPrecision, ChronoUnit precision) {
		switch (precision) {
			case MINUTES:
				effective = ofPrecision.isLessOrEqualTo(MINUTES) ? effective.withMinute(59) : effective.withMinute(0);
			case SECONDS:
				effective = ofPrecision.isLessOrEqualTo(SECONDS) ? effective.withSecond(59) : effective.withSecond(0);
			default:
				effective = ofPrecision.effectiveMaxNanos(effective);
		}
		return effective;
	}

	public static ChronoUnit ofPrecisionFromNanos(int nanos) {
		ChronoUnit ofPrecision = OfPrecision.DEFAULT;
		if (nanos % 1_000 != 0) {
			ofPrecision = NANOS;
		} else if ((nanos / 1_000) % 1_000 != 0) {
			ofPrecision = MICROS;
		} else if (nanos / 1_000_000 != 0) {
			ofPrecision = MILLIS;
		}
		return ofPrecision;
	}

	public static ChronoUnit ofPrecisionFromTime(LocalTime time) {
		int nanos = time.getNano();
		return ofPrecisionFromNanos(nanos);
	}

	private void setOfPrecisionImplicitly(DefaultLocalTimeArbitrary clone, LocalTime time) {
		if (clone.ofPrecision.isSet()) {
			return;
		}
		ChronoUnit ofPrecision = ofPrecisionFromTime(time);
		if (clone.ofPrecision.isGreatherThan(ofPrecision)) {
			clone.ofPrecision.setProgrammatically(ofPrecision);
		}
	}

	@Override
	public LocalTimeArbitrary atTheEarliest(LocalTime min) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.timeBetween.set(min, null);
		setOfPrecisionImplicitly(clone, min);
		return clone;
	}

	@Override
	public LocalTimeArbitrary atTheLatest(LocalTime max) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.timeBetween.set(null, max);
		setOfPrecisionImplicitly(clone, max);
		return clone;
	}

	@Override
	public LocalTimeArbitrary hourBetween(int min, int max) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.hourBetween.set(min, max);
		return clone;
	}

	@Override
	public LocalTimeArbitrary minuteBetween(int min, int max) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.minuteBetween.set(min, max);
		return clone;
	}

	@Override
	public LocalTimeArbitrary secondBetween(int min, int max) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.secondBetween.set(min, max);
		return clone;
	}

	@Override
	public LocalTimeArbitrary ofPrecision(ChronoUnit ofPrecision) {
		DefaultLocalTimeArbitrary clone = typedClone();
		clone.ofPrecision.set(ofPrecision);
		return clone;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy