Dan Alexandru Hintea/ February 29, 2020/ Testing/ 0 comments

My current date time abstraction.

public static class Rolex
{
    static ImATimekeeper timekeeper = new Timekeeper();

    public static ImATimekeeper TimeKeepingMechanism => timekeeper;

    public static DateTime Time => timekeeper.Time;
    public static DateTime Date => timekeeper.Date;

    public static void UseMechanism(ImATimekeeper timeKeepingMechanism)
    {
        timekeeper = timeKeepingMechanism;
    }
}

Customizable for testing since this is the main reason we abstract it.

public class RolexCustomizer : IDisposable
{
    readonly ImATimekeeper originalMechanism;

    public RolexCustomizer(ImATimekeeper timeKeepingMechanism)
    {
        this.originalMechanism = Rolex.TimeKeepingMechanism;
        Rolex.UseMechanism(timeKeepingMechanism);
    }

    public void Dispose()
    {
        Rolex.UseMechanism(originalMechanism);
    }
}

And the controllable mechanism, to be used in tests.

Chronos is the personification of time in pre-Socratic philosophy and later literature.

public class ChronosTimekeeper : ImATimekeeper
{
    static readonly SemaphoreSlim timeTravellingSemaphore = new SemaphoreSlim(1, 1);

    private readonly Timekeeper timekeeper = new Timekeeper();

    private TimeSpan timeSpanDifferenceFromReality = TimeSpan.Zero;

    public DateTime Time => timekeeper.Time.Add(timeSpanDifferenceFromReality);

    public DateTime Date => timekeeper.Date.Add(timeSpanDifferenceFromReality);

    public ChronosTimekeeper TimeTravel(TimeSpan by)
    {
        timeTravellingSemaphore.Wait(TimeSpan.FromSeconds(15));

        timeSpanDifferenceFromReality = by;

        return this;
    }

    public ChronosTimekeeper ReturnToPresent()
    {
        if (timeTravellingSemaphore.CurrentCount == 1)
            return this;

        timeSpanDifferenceFromReality = TimeSpan.Zero;

        timeTravellingSemaphore.Release();

        return this;
    }
}

public class ChronosTimeTraveler : IDisposable
{
    readonly ChronosTimekeeper chronosTimekeeper;
    readonly RolexCustomizer rolexCustomizer;

    public ChronosTimeTraveler(ChronosTimekeeper chronosTimekeeper, TimeSpan by)
    {
        this.chronosTimekeeper = chronosTimekeeper;
        chronosTimekeeper.TimeTravel(by);
        rolexCustomizer = new RolexCustomizer(chronosTimekeeper);
    }

    public void Dispose()
    {
        chronosTimekeeper.ReturnToPresent();
        rolexCustomizer.Dispose();
    }
}

public static class ChronosTimeTravelerExtensions
{
    public static IDisposable TimeHeistBy(this ChronosTimekeeper chronosTimekeeper, TimeSpan by) => new ChronosTimeTraveler(chronosTimekeeper, by);
}

And here is the usage syntax in unit tests.

[...]
using (Chronos.TimeHeistBy(TimeSpan.FromHours(24.5)))
{
    [...]
}
[...]
Share this Post

Leave a Comment

Your email address will not be published. Required fields are marked *

*
*