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 Throws_ArgumentNullException_when_factory_function_is_null()
        {
            Func <object, CancellationToken, Task <object> > funcTT = null;
            Func <CancellationToken, Task <object> >         funcT  = null;

            Assert.Throws <ArgumentNullException>(() => new AsyncGenericBuffer <object>(
                                                      factory: funcTT,
                                                      initialValue: Task.FromResult(new object()),
                                                      bufferingPeriod: TimeSpan.Zero));

            Assert.Throws <ArgumentNullException>(() => new AsyncGenericBuffer <object>(
                                                      factory: funcTT,
                                                      initialValue: new object(),
                                                      bufferingPeriod: TimeSpan.Zero,
                                                      ClockFactory.FrozenClock()));

            Assert.Throws <ArgumentNullException>(() => new AsyncGenericBuffer <object>(
                                                      factory: funcT,
                                                      bufferingPeriod: TimeSpan.Zero));

            Assert.Throws <ArgumentNullException>(() => new AsyncGenericBuffer <object>(
                                                      factory: funcT,
                                                      bufferingPeriod: TimeSpan.Zero,
                                                      ClockFactory.FrozenClock()));
        }
        public void Throws_ArgumentNullException_when_factory_function_is_null()
        {
            Func <object, object> funcTT = null;
            Func <object>         funcT  = null;

            // ReSharper disable ExpressionIsAlwaysNull
            Assert.Throws <ArgumentNullException>(() => new GenericBuffer <object>(
                                                      factory: funcTT,
                                                      initialValue: new object(),
                                                      bufferingPeriod: TimeSpan.Zero));

            Assert.Throws <ArgumentNullException>(() => new GenericBuffer <object>(
                                                      factory: funcTT,
                                                      initialValue: new object(),
                                                      bufferingPeriod: TimeSpan.Zero,
                                                      ClockFactory.FrozenClock()));

            Assert.Throws <ArgumentNullException>(() => new GenericBuffer <object>(
                                                      factory: funcT,
                                                      bufferingPeriod: TimeSpan.Zero));

            Assert.Throws <ArgumentNullException>(() => new GenericBuffer <object>(
                                                      factory: funcT,
                                                      bufferingPeriod: TimeSpan.Zero,
                                                      ClockFactory.FrozenClock()));
            // ReSharper restore ExpressionIsAlwaysNull
        }
        public void Throws_the_same_exception_as_factory()
        {
            var expectedException = new Exception();
            var genericBuffer     = new GenericBuffer <object>(
                factory: () => throw expectedException,
                bufferingPeriod: TimeSpan.Zero, clock:
                ClockFactory.FrozenClock());

            Exception actualException = Record.Exception(() => genericBuffer.GetValue());

            Assert.Same(expectedException, actualException);
        }
        public async Task Throws_the_same_exception_as_factory()
        {
            CancellationToken ct   = CancellationToken.None;
            var expectedException  = new Exception();
            var asyncGenericBuffer = new AsyncGenericBuffer <object>(
                factory: _ => throw expectedException,
                bufferingPeriod: TimeSpan.Zero,
                clock: ClockFactory.FrozenClock());

            Exception recoredException = await Record.ExceptionAsync(async() => await asyncGenericBuffer.GetValueAsync(ct));

            Assert.Same(expectedException, recoredException);
        }
        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 async Task Reset_forces_creating_a_new_value()
        {
            CancellationToken ct = CancellationToken.None;

            var asyncGenericBuffer = new AsyncGenericBuffer <object>(
                factory: _ => Task.FromResult(new object()),
                bufferingPeriod: TimeSpan.FromTicks(1),
                clock: ClockFactory.FrozenClock());

            var firstObject = await asyncGenericBuffer.GetValueAsync(ct);

            Assert.Same(firstObject, await asyncGenericBuffer.GetValueAsync(ct));
            Assert.Same(firstObject, await asyncGenericBuffer.GetValueAsync(ct));

            await asyncGenericBuffer.ResetAsync(ct);

            Assert.NotSame(firstObject, await asyncGenericBuffer.GetValueAsync(ct));
        }
        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 async Task Force_fefresh_creates_new_value_even_if_the_old_one_is_still_valid()
        {
            CancellationToken ct = CancellationToken.None;

            var asyncGenericBuffer = new AsyncGenericBuffer <object>(
                factory: _ => Task.FromResult(new object()),
                bufferingPeriod: TimeSpan.FromTicks(1),
                clock: ClockFactory.FrozenClock());

            var val1 = await asyncGenericBuffer.GetValueAsync(ct);

            var val2 = await asyncGenericBuffer.GetValueAsync(ct);

            var forced = await asyncGenericBuffer.ForceRefreshAsync(ct);

            var val3 = await asyncGenericBuffer.GetValueAsync(ct);

            var val4 = await asyncGenericBuffer.GetValueAsync(ct);

            Assert.Same(val1, val2);
            Assert.NotSame(val1, forced);
            Assert.Same(forced, val3);
            Assert.Same(val3, val4);
        }