public void RetrieveItems_algorithmTest()
 {
     m_recentItems = new RecentItemsCache <string, int>(5);
     AddNewItem("1", 6);
     AddNewItem("2", 5);
     AddNewItem("3", 4);
     AddNewItem("4", 3);
     AddNewItem("5", 2);
     // At this point the cache is fully loaded. When we add another, it will have to discard
     // at least the least frequently requested item.
     AddNewItem("6", 1);
     // So, when we add "5" again, it will have to be recomputed.
     AddNewItem("5", 2);
     // The question is, which one should it have discarded in order to add "5" again?
     // "6" is plausible, since it has only been asked for once, while all the other
     // values have been requested more. However, we want some bias towards things
     // recently asked for. We'd like to see "4" as the next one chosen to remove.
     AddNewItem("4", 2);
     // Don't want to constrain the algorithm too closely, but after several cycles even "1" should be discarded.
     AddNewItem("7", 2);
     AddNewItem("8", 2);
     AddNewItem("9", 2);
     AddNewItem("10", 2);
     AddNewItem("11", 2);
     AddNewItem("1", 1);
     AddItem("11", false);             // most recent one should still be around.
 }
        public void NullInput_key()
        {
            // Attempt to cache a key,value pair with null key
            var cache = new RecentItemsCache <string, string>(7);

            cache.GetItem(null, key => { return("value"); });
        }
        public void NullInput_value()
        {
            // Cache a key,value pair with null value.
            var cache = new RecentItemsCache <int, string>(7);

            Assert.DoesNotThrow(() => {
                cache.GetItem(0, key => { return(null); });
            }, "Null value should not throw exception");
        }
        public void Cache_addItem()
        {
            Func <int, string> creator = (int key) => {
                return(key.ToString());
            };

            var cache = new RecentItemsCache <int, string>(7);

            AddNewItem <int, string>(cache, 0, creator);
        }
        public void Cache_reportsIfItemWasRetrievedFromCache()
        {
            Func <int, string> creator = key => {
                return(key.ToString());
            };

            bool wasRetrievedFromCache;
            var  cache = new RecentItemsCache <int, string>(7);

            cache.GetItem(0, creator, out wasRetrievedFromCache);
            Assert.AreEqual(false, wasRetrievedFromCache, "Adding a new item to cache should not report it as retrieved from cache.");
            cache.GetItem(0, creator, out wasRetrievedFromCache);
            Assert.AreEqual(true, wasRetrievedFromCache, "Retrieving a cached item should report that it was retrieved from cache.");
        }
        public void Cache_matchesEqualKeyOfDifferentReference()
        {
            Func <MyKey, string> creator = (MyKey inputKey) => {
                return(inputKey.Data + "value");
            };

            int capacity = 7;
            var cache    = new RecentItemsCache <MyKey, string>(capacity);

            // Two keys: equal in data/value but of different references
            var key1 = new MyKey(0);
            var key2 = new MyKey(0);

            AddNewItem <MyKey, string>(cache, key1, creator);
            GetExistingItem <MyKey, string>(cache, key2, creator);
        }
        public void Cache_matchesKeyOfSameReference()
        {
            Func <MyKey, string> creator = (MyKey inputKey) => {
                return(inputKey.Data + "value");
            };

            int capacity = 7;
            var cache    = new RecentItemsCache <MyKey, string>(capacity);

            // Keys have the same Reference
            var key1 = new MyKey(0);
            var key2 = key1;

            AddNewItem <MyKey, string>(cache, key1, creator);
            GetExistingItem <MyKey, string>(cache, key2, creator);
        }
        public void Cache_retainsManyItems()
        {
            Func <int, string> creator = (int key) => {
                return(key.ToString());
            };

            int capacity = 7;
            var cache    = new RecentItemsCache <int, string>(capacity);

            for (int i = 0; i < capacity; i++)
            {
                AddNewItem <int, string>(cache, i, creator);
            }
            for (int i = 0; i < capacity; i++)
            {
                GetExistingItem <int, string>(cache, i, creator);
            }
        }
        /// <summary>
        /// Add key,value pair to cache, checking if it was newly added.
        /// Will assert if computed if not expected, or did not compute if expected to.
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key"></param>
        /// <param name="creator">Delegate to create the value from key</param>
        /// <param name="expectToCompute">
        /// Whether should expect to need to compute the value from key using creator
        /// </param>
        private void AddItem <K, V>(RecentItemsCache <K, V> cache, K key, Func <K, V> creator,
                                    bool expectToCompute)
        {
            bool didCompute = false;

            Assert.AreEqual(creator(key), cache.GetItem(key, key1 =>
            {
                didCompute = true;
                return(creator(key1));
            }), String.Format("wrong value for {0} cached key given", didCompute?"newly":"previously"));

            string errorMessage;

            if (expectToCompute)
            {
                errorMessage = "Expected to compute value from key since it was not expected to be in the cache, but it was in the cache.";
            }
            else
            {
                errorMessage = "Did not expect to compute value from key since expected it to be in the cache, but it was not in the cache.";
            }
            Assert.AreEqual(expectToCompute, didCompute, errorMessage);
        }
        public void Caching_itemsFallOutOfCache()
        {
            Func <int, string> creator = (int key) => {
                return(key.ToString());
            };

            var cacheCapacity = 7;
            var cache         = new RecentItemsCache <int, string>(cacheCapacity);
            int valueLargerThanCacheCapacity = cacheCapacity * 3;

            // Add some items, all of which should be new to the cache
            for (int i = 0; i < valueLargerThanCacheCapacity; i++)
            {
                AddNewItem <int, string>(cache, i, creator);
            }

            // Adding the first few items again should not be able to retrieve them from the cache.
            // They should have fallen out of the cache by now.
            for (int i = 0; i < cacheCapacity; i++)
            {
                AddNewItem <int, string>(cache, i, creator);
            }
        }
 private void AddNewItem <K, V>(RecentItemsCache <K, V> cache, K key, Func <K, V> creator)
 {
     AddItem <K, V>(cache, key, creator, true);
 }
 private void GetExistingItem <K, V>(RecentItemsCache <K, V> cache, K key, Func <K, V> creator)
 {
     AddItem <K, V>(cache, key, creator, false);
 }