public async Task Creates_item_only_once_when_get_value_is_called_in_parallel()
        {
            var blockFactoryMethod = true;

            var genericBuffer = new GenericBuffer <object>(
                factory: () =>
            {
                while (blockFactoryMethod)
                {
                }
                return(new object());
            },
                bufferingPeriod: TimeSpan.FromTicks(1),
                clock: ClockFactory.FrozenClock());

            var tasks = Enumerable.Range(0, 100)
                        .Select(_ => Task.Run(() => genericBuffer.GetValue()));

            blockFactoryMethod = false;
            await Task.Delay(200);

            object[] results = await Task.WhenAll(tasks);

            foreach (var result in results)
            {
                Assert.Same(results.First(), result);
            }
        }
        public void Reset_forces_creating_a_new_value()
        {
            var genericBuffer = new GenericBuffer <object>(
                factory: () => new object(),
                bufferingPeriod: TimeSpan.FromTicks(1),
                clock: ClockFactory.FrozenClock());

            var firstObject = genericBuffer.GetValue();

            Assert.Same(firstObject, genericBuffer.GetValue());
            Assert.Same(firstObject, genericBuffer.GetValue());

            genericBuffer.Reset();

            Assert.NotSame(firstObject, genericBuffer.GetValue());
        }
        public void Returns_new_value_after_buffering_period_passes()
        {
            DateTime dateTime         = DateTime.MinValue;
            var      bufferingPeriod  = TimeSpan.FromTicks(1);
            var      incrementalClock = new IncrementalClock();
            int      executions       = 0;
            var      genericBuffer    = new GenericBuffer <int>(factory: () => executions++, bufferingPeriod: bufferingPeriod, clock: () => dateTime);


            Assert.Equal(0, genericBuffer.GetValue()); // Before buffering period is past

            dateTime += bufferingPeriod;
            Assert.Equal(1, genericBuffer.GetValue()); // After first buffering period is past

            dateTime += bufferingPeriod;
            Assert.Equal(2, genericBuffer.GetValue()); // After second buffering period is past
        }
        public void Force_refresh_creates_new_value_even_if_the_old_one_is_still_valid()
        {
            var genericBuffer = new GenericBuffer <object>(
                factory: () => new object(),
                bufferingPeriod: TimeSpan.FromTicks(1),
                clock: ClockFactory.FrozenClock());


            var val1   = genericBuffer.GetValue();
            var val2   = genericBuffer.GetValue();
            var forced = genericBuffer.ForceRefresh();
            var val3   = genericBuffer.GetValue();
            var val4   = genericBuffer.GetValue();

            Assert.Same(val1, val2);
            Assert.NotSame(val1, forced);
            Assert.Same(forced, val3);
            Assert.Same(val3, val4);
        }
        public void Returns_the_same_object_while_in_the_same_buffering_period()
        {
            DateTime dateTime        = DateTime.MinValue;
            var      bufferingPeriod = TimeSpan.FromTicks(1);
            var      genericBuffer   = new GenericBuffer <object>(factory: () => new object(), bufferingPeriod: bufferingPeriod, clock: () => dateTime);

            object firstValue = genericBuffer.GetValue();

            Assert.Same(firstValue, genericBuffer.GetValue());
            Assert.Same(firstValue, genericBuffer.GetValue());

            dateTime += bufferingPeriod;
            Assert.NotSame(firstValue, genericBuffer.GetValue());
            Assert.Same(genericBuffer.GetValue(), genericBuffer.GetValue());
        }
        public static async Task Main(string[] args)
        {
            int i             = 0;
            var genericBuffer = new GenericBuffer <int>(
                factory: () =>
            {
                Console.WriteLine("Generating new value...");
                return(i++);
            },
                bufferingPeriod: TimeSpan.FromMilliseconds(200));

            while (true)
            {
                Console.WriteLine($"Value: {genericBuffer.GetValue()}");
                await Task.Delay(TimeSpan.FromMilliseconds(50));
            }

            // OUTPUT:
            //Generating new value...
            //Value: 0
            //Value: 0
            //Value: 0
            //Value: 0
            //Generating new value...
            //Value: 1
            //Value: 1
            //Value: 1
            //Value: 1
            //Generating new value...
            //Value: 2
            //Value: 2
            //Value: 2
            //Value: 2
            //Generating new value...
            //Value: 3
            //Value: 3
            //Value: 3
            //Value: 3
        }