public async Task GetOrAdd_ExtentionMethod_protected_from_running_twice_in_multi_threaded_code()
        {
            var cache               = new MultiThreadProtectedDecorator(new SimpleInmemoryCache());
            int ctorCallCount       = 0;
            Func <string, int> ctor = _ => {
                Interlocked.Increment(ref ctorCallCount);
                return(ctorCallCount);
            };
            Task <int> t1 = Task.Run(() => cache.GetOrAdd("Key", ctor));
            Task <int> t2 = Task.Run(() => cache.GetOrAdd("Key", ctor));
            await Task.WhenAll(t1, t2);

            Assert.That(ctorCallCount, Is.EqualTo(1));
        }
        public async Task GetOrAdd_protected_from_running_twice_in_multi_threaded_code()
        {
            var cache                   = new MultiThreadProtectedDecorator(new SimpleInmemoryCache());
            int ctorCallCount           = 0;
            Func <string, int> slowCtor = _ => {
                // slow down the first ctor call to ensure second thread always see the cache
                // as empty even though this ctor has been called to add the item
                Thread.Sleep(TimeSpan.FromMilliseconds(100));
                Interlocked.Increment(ref ctorCallCount);
                return(ctorCallCount);
            };
            Func <string, int> ctor = _ => {
                Interlocked.Increment(ref ctorCallCount);
                return(ctorCallCount);
            };
            Task <int> t1 = Task.Run(() => cache.GetOrAdd("Key", slowCtor));
            Task <int> t2 = Task.Run(() => cache.GetOrAdd("Key", ctor));
            await Task.WhenAll(t1, t2);

            Assert.That(ctorCallCount, Is.EqualTo(1));
        }