public void GetOrCreateAsync_CallsFaultyFactoryOnce()
        {
            // Arrange

            var key     = Guid.NewGuid().ToString();
            var options = new CacheEntryOptions(TimeSpan.FromMilliseconds(1));

            var factoryCallCount = 0;
            Func <string, Task <AClass> > factory = _ =>
            {
                factoryCallCount++;
                throw new Exception();
            };

            var cache = Substitute.For <ICache>();

            cache.GetAsync <AClass>(key).Returns((AClass)null);
            cache.When(c => c.GetOrCreateAsync(key, options, Arg.Any <Func <string, Task <AClass> > >()))
            .Do(c => c.Arg <Func <string, AClass> >()(key));

            var logger    = Substitute.For <ILogger <ExceptionHandlingCacheDecorator> >();
            var decorator = new ExceptionHandlingCacheDecorator(cache, logger);


            // Act / Assert
            Assert.ThrowsAsync <Exception>(() => decorator.GetOrCreateAsync(key, options, factory));
            Assert.AreEqual(1, factoryCallCount);
        }
        public async Task GetOrCreateAsync_ReturnsCachedValue()
        {
            // Arrange

            var key         = Guid.NewGuid().ToString();
            var cachedValue = new AClass();
            Func <string, Task <AClass> > factory = _ => Task.FromResult(new AClass());
            var options = new CacheEntryOptions(TimeSpan.FromMilliseconds(1));

            var cache = Substitute.For <ICache>();

            cache.GetIfCachedAsync <AClass>(key).Returns((true, cachedValue));
            cache.GetAsync <AClass>(key).Returns(cachedValue);
            cache.GetOrCreateAsync(key, options, Arg.Any <Func <string, Task <AClass> > >()).Returns(cachedValue);

            var logger    = Substitute.For <ILogger <ExceptionHandlingCacheDecorator> >();
            var decorator = new ExceptionHandlingCacheDecorator(cache, logger);


            // Act
            var result = await decorator.GetOrCreateAsync(key, options, factory);

            // Assert
            Assert.AreEqual(cachedValue, result);
        }
        public async Task GetOrCreateAsync_CreatesValueType()
        {
            // Arrange
            var key          = Guid.NewGuid().ToString();
            var factoryValue = 1234;
            Func <string, Task <int> > factory = _ => Task.FromResult(factoryValue);
            var options = new CacheEntryOptions(TimeSpan.FromMilliseconds(1));
            var cache   = Substitute.For <IDistributedCache>();

            cache.GetAsync(key).Returns((byte[])null);
            var logger    = Substitute.For <ILogger <ExceptionHandlingCacheDecorator> >();
            var decorator =
                new ExceptionHandlingCacheDecorator(new DistributedCache(cache, Substitute.For <ILogger <DistributedCache> >()),
                                                    logger);

            // Act
            var result = await decorator.GetOrCreateAsync(key, options, factory);

            // Assert
            Assert.AreEqual(factoryValue, result);
        }
        public async Task GetOrCreateAsync_HandlesSetException()
        {
            // Arrange
            var key          = Guid.NewGuid().ToString();
            var factoryValue = new AClass();
            Func <string, Task <AClass> > factory = _ => Task.FromResult(factoryValue);
            var options = new CacheEntryOptions(TimeSpan.FromMilliseconds(1));
            var cache   = Substitute.For <ICache>();

            cache.GetAsync <AClass>(key).Returns((AClass)null);
            cache.When(c => c.Set(key, factoryValue, options)).Do(_ => throw new Exception());
            cache.GetOrCreateAsync(key, options, Arg.Any <Func <string, Task <AClass> > >()).Throws(new Exception());
            var logger    = Substitute.For <ILogger <ExceptionHandlingCacheDecorator> >();
            var decorator = new ExceptionHandlingCacheDecorator(cache, logger);

            // Act
            var result = await decorator.GetOrCreateAsync(key,
                                                          options,
                                                          factory);

            // Assert
            Assert.AreEqual(factoryValue, result);
        }