public async Task GetItemAsync_OfCacheableStructRequestedMultipleTimesInSuccession_CallsRetrievalDelegateJustOnce()
        {
            // Arrange
            CacheableStruct cacheableStruct           = new CacheableStruct(100);
            InMemoryItemCache <CacheableStruct> cache = new InMemoryItemCache <CacheableStruct>(
                () => { return(Task.FromResult(cacheableStruct.GetSelf())); },
                null,
                TimeSpan.FromMinutes(2));
            int actualResult;
            int expectedResult = 1;

            // Act
            _ = await cache.GetItemAsync();

            _ = await cache.GetItemAsync();

            _ = await cache.GetItemAsync();

            _ = await cache.GetItemAsync();

            actualResult = cacheableStruct.NumberOfGetSelfCalls;

            // Assert
            Assert.AreEqual(expectedResult, actualResult);
        }
        public async Task GetItemAsync_OfCacheableClassWhenCalledTwice_DoesNotReturnSameInstance()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                () => { return(Task.FromResult(new CacheableClass(100))); },
                null,
                TimeSpan.FromMilliseconds(100));
            CacheableClass cacheItem1;
            CacheableClass cacheItem2;

            // Act
            cacheItem1 = await cache.GetItemAsync();

            cacheItem2 = await cache.GetItemAsync();

            // Assert that full, deep cloning is being performed
            Assert.AreNotEqual(cacheItem1, cacheItem2);
            Assert.AreNotEqual(cacheItem1.Child, cacheItem2.Child);
        }
        public async Task GetItemAsync_OfCacheableClassWhenCalledTwice_CreatesPerfectClone()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                () => { return(Task.FromResult(new CacheableClass(100))); },
                null,
                TimeSpan.FromMilliseconds(100));
            CacheableClass cacheItem1;
            CacheableClass cacheItem2;

            // Act
            cacheItem1 = await cache.GetItemAsync();

            cacheItem2 = await cache.GetItemAsync();

            // Assert that the clone worked correctly
            Assert.AreEqual(cacheItem1.GetValue(), cacheItem2.GetValue());
            Assert.AreEqual(cacheItem1.NumberOfCalls, cacheItem2.NumberOfCalls);
            Assert.AreEqual(cacheItem1.CreatedAt, cacheItem2.CreatedAt);
        }
        public async Task GetItemAsync_OfCacheableClassWhenCacheExpires_CallsRetrievalDelegateAgain()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                () => { return(Task.FromResult(new CacheableClass(100))); },
                null,
                TimeSpan.FromMilliseconds(100));
            DateTime       initialCreatedAt;
            DateTime       finalCreatedAt;
            CacheableClass cacheItem;

            // Act
            cacheItem = await cache.GetItemAsync();

            initialCreatedAt = cacheItem.CreatedAt;
            // Wait for the cache item to expire and then retry
            TimeDelay.WaitFor(150);
            cacheItem = await cache.GetItemAsync();

            finalCreatedAt = cacheItem.CreatedAt;

            // Assert that the creation values are different
            Assert.AreNotEqual(initialCreatedAt, finalCreatedAt);
        }
        public async Task GetItemAsync_OfCacheableClassRequestedMultipleTimesInSuccession_CallsRetrievalDelegateJustOnce()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                () => { return(Task.FromResult(new CacheableClass(100))); },
                null,
                TimeSpan.FromMilliseconds(100));
            DateTime       initialCreatedAt;
            DateTime       finalCreatedAt;
            CacheableClass cacheItem;

            // Act
            cacheItem = await cache.GetItemAsync();

            initialCreatedAt = cacheItem.CreatedAt;
            _         = cache.GetItemAsync();
            _         = cache.GetItemAsync();
            cacheItem = await cache.GetItemAsync();

            finalCreatedAt = cacheItem.CreatedAt;

            // Assert
            Assert.AreEqual(initialCreatedAt, finalCreatedAt);
        }
        public async Task GetItemAsync_OfCacheableStruct_ReturnsCorrectCachedValue()
        {
            // Arrange
            CacheableStruct cacheableStruct           = new CacheableStruct(100);
            InMemoryItemCache <CacheableStruct> cache = new InMemoryItemCache <CacheableStruct>(
                () => { return(Task.FromResult(cacheableStruct.GetSelf())); },
                null,
                TimeSpan.FromMinutes(2));
            int actualResult;
            int expectedResult = 100;

            // Act
            actualResult = (await cache.GetItemAsync()).GetValue();

            // Assert
            Assert.AreEqual(expectedResult, actualResult);
        }
        public async Task GetItemAsync_OfInt_ReturnsCorrectCachedValue()
        {
            // Arrange
            InMemoryItemCache <int> cache = new InMemoryItemCache <int>(
                new NonCloningClonerFactory <int>(),
                () => { return(Task.FromResult(100)); },
                null,
                TimeSpan.FromMinutes(2),
                100, 100);
            int actualResult;
            int expectedResult = 100;

            // Act
            actualResult = await cache.GetItemAsync();

            // Assert
            Assert.AreEqual(expectedResult, actualResult);
        }
        public async Task GetItemAsync_OfCacheableClass_ReturnsCorrectCachedValue()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                () => { return(Task.FromResult(new CacheableClass(100))); },
                null,
                TimeSpan.FromMinutes(2),
                100, 100);
            CacheableClass cacheItem;
            int            actualResult;
            int            expectedResult = 100;

            // Act
            cacheItem = await cache.GetItemAsync();

            actualResult = cacheItem.GetValue();

            // Assert
            Assert.AreEqual(expectedResult, actualResult);
        }
        public void GetItemAsync_OfCacheableClassWhenInitialRetrievalTimesOut_ReturnsDefaultValueOfNull()
        {
            // Arrange
            InMemoryItemCache <CacheableClass> cache = new InMemoryItemCache <CacheableClass>(
                async() => { await TimeDelay.WaitForAsync(200); return(new CacheableClass(100)); },
                null,
                TimeSpan.FromMinutes(2),
                50, 50);
            CacheableClass cacheItem;

            // Act
            Task <CacheableClass> task1 = cache.GetItemAsync();
            Task <CacheableClass> task2 = AwaitDelayAndGetItemFromCacheableClassCacheAsync(50, cache);

            // Start the 2 tasks, with task2 likely to have to wait on task1
            Task.WaitAll(task1, task2);
            cacheItem = task2.Result;

            // Assert
            Assert.IsNull(cacheItem);
        }
        public void GetItemAsync_OfIntWhenInitialRetrievalTimesOut_ReturnsDefaultValueOfZero()
        {
            // Arrange
            InMemoryItemCache <int> cache = new InMemoryItemCache <int>(
                new NonCloningClonerFactory <int>(),
                async() => { await TimeDelay.WaitForAsync(200); return(125); },
                null,
                TimeSpan.FromMinutes(2),
                50, 50);
            int actualResult;
            int expectedResult = 0;

            // Act
            Task <int> task1 = cache.GetItemAsync();
            Task <int> task2 = AwaitDelayAndGetItemFromIntCacheAsync(50, cache);

            // Start the 2 tasks, with task2 likely to have to wait on task1
            Task.WaitAll(task1, task2);
            actualResult = task2.Result;

            // Assert
            Assert.AreEqual(expectedResult, actualResult);
        }
        private async Task <CacheableClass> AwaitDelayAndGetItemFromCacheableClassCacheAsync(int delayPeriod, InMemoryItemCache <CacheableClass> cache)
        {
            await TimeDelay.WaitForAsync(delayPeriod);

            return(await cache.GetItemAsync());
        }