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

tech.sirwellington.alchemy.arguments.assertions.TimeAssertions Maven / Gradle / Ivy

Go to download

Part of the Alchemy Collection. Easy, Simple, and Robust argument checking logic for your Services, Libraries, and Scripts.

There is a newer version: 2.3
Show newest version
/*
 * Copyright 2015 SirWellington Tech.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package tech.sirwellington.alchemy.arguments.assertions;

import java.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.sirwellington.alchemy.annotations.access.NonInstantiable;
import tech.sirwellington.alchemy.annotations.arguments.NonNull;
import tech.sirwellington.alchemy.arguments.AlchemyAssertion;
import tech.sirwellington.alchemy.arguments.FailedAssertionException;

import static java.lang.String.format;
import static tech.sirwellington.alchemy.arguments.Checks.Internal.checkNotNull;
import static tech.sirwellington.alchemy.arguments.Checks.Internal.checkThat;
import static tech.sirwellington.alchemy.arguments.assertions.Assertions.notNull;
import static tech.sirwellington.alchemy.arguments.assertions.NumberAssertions.greaterThan;

/**
 *
 * @author SirWellington
 */
@NonInstantiable
public final class TimeAssertions
{

    private final static Logger LOG = LoggerFactory.getLogger(TimeAssertions.class);

    TimeAssertions() throws IllegalAccessException
    {
        throw new IllegalAccessException("cannot instantiate");
    }

    /**
     * Asserts that the {@link Instant} is in the past. Note that the present is constantly recalculated in order to
     * stay current.
     *
     * @return
     */
    public static AlchemyAssertion inThePast()
    {
        return argument ->
        {
            //Recalculate the present on each call to stay current
            Instant present = Instant.now();
            if (!argument.isBefore(present))
            {
                throw new FailedAssertionException(format("Expected Timestamp %s to be in the past. Now: %s", argument, present));
            }
        };
    }

    public static AlchemyAssertion before(@NonNull Instant expected)
    {
        checkNotNull(expected, "time cannot be null");

        return argument ->
        {
            Assertions.notNull().check(argument);

            if (!argument.isBefore(expected))
            {
                throw new FailedAssertionException(format("Expected Timestamp to be before %s", expected.toString()));
            }
        };
    }

    public static AlchemyAssertion inTheFuture()
    {
        return argument ->
        {
            //Recalculate the present on each call to stay current
            Instant present = Instant.now();
            if (!argument.isAfter(present))
            {
                throw new FailedAssertionException(format("Expected Timestamp %s to be in the future. Now: %s", argument, present));
            }
        };
    }

    public static AlchemyAssertion after(@NonNull Instant expected)
    {
        checkNotNull(expected, "time cannot be null");

        return argument ->
        {
            Assertions.notNull().check(argument);

            if (!argument.isAfter(expected))
            {
                throw new FailedAssertionException(format("Expected Timestamp to be after %s", expected.toString()));
            }
        };
    }
    
    /**
     * Ensures that the {@link Instant} represents exactly Right now, at the time of checking. It does so
     * within a margin-of-error of 5 milliseconds. This should be acceptable for most modern processors.
     * Use {@link #nowWithinDelta(long) } for more fine-grained deltas.
     * 
     * @return 
     * @see #nowWithinDelta(long) 
     */
    public static AlchemyAssertion rightNow() 
    {
        return nowWithinDelta(5L);
    }
    
    /**
     * Ensures that an {@link Instant} is {@link Instant#now() }, within the specified margin of error.
     * 
     * @param marginOfErrorInMillis The Acceptable Margin-Of-Error, in Milliseconds. The instant must be within this delta.
     * 
     * @return
     * @throws IllegalArgumentException If the marginOfError is {@code < 0}.
     * 
     * @see #rightNow() 
     */
    public static AlchemyAssertion nowWithinDelta(long marginOfErrorInMillis) throws IllegalArgumentException
    {
        checkThat(marginOfErrorInMillis >= 0, "millis must be non-negative.");
        
        return instant ->
        {
            long now = Instant.now().toEpochMilli();
            notNull().check(instant);
            
            long epoch = instant.toEpochMilli();
            long difference = Math.abs(epoch - now);
            
            if (difference > marginOfErrorInMillis)
            {
                throw new FailedAssertionException(
                    "Time difference of " + difference + " exceeded margin-of-error of " + marginOfErrorInMillis + "ms");
            }
            
        };
    }
    
    /**
     * Epoch version of {@link #rightNow() }.
     * 
     * @return 
     */
    public static AlchemyAssertion epochRightNow()
    {
        return epochNowWithinDelta(5L);
    }
    
    /**
     * Epoch version of {@link #nowWithinDelta(long) }.
     * 
     * @param marginOfErrorInMillis The Acceptable Margin-Of-Error, in Milliseconds. The instant must be within this delta.
     * 
     * @return
     * @throws IllegalArgumentException If the marginOfError is {@code < 0}.
     */
    public static AlchemyAssertion epochNowWithinDelta(long marginOfErrorInMillis) throws IllegalArgumentException
    {
        checkThat(marginOfErrorInMillis >= 0, "millis must be non-negative.");
        
        return epoch ->
        {
            long now = Instant.now().toEpochMilli();
            greaterThan(0L).check(epoch);
            
            long difference = Math.abs(epoch - now);
            
            if (difference > marginOfErrorInMillis)
            {
                throw new FailedAssertionException(
                    "Time difference of " + difference + " exceeded margin-of-error of " + marginOfErrorInMillis + "ms");
            }
            
        };
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy