public void AbsoluteExpirationExpiresInBackground()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();
            var callbackInvoked = new ManualResetEvent(false);

            var result = cache.Set(key, context =>
            {
                context.SetAbsoluteExpiration(clock.UtcNow + TimeSpan.FromMinutes(1));
                context.RegisterPostEvictionCallback((subkey, value, reason, state) =>
                {
                    // TODO: Verify params
                    var localCallbackInvoked = (ManualResetEvent)state;
                    localCallbackInvoked.Set();
                }, state: callbackInvoked);
                return obj;
            });
            Assert.Same(obj, result);

            var found = cache.TryGetValue(key, out result);
            Assert.True(found);
            Assert.Same(obj, result);

            clock.Add(TimeSpan.FromMinutes(2));
            var ignored = cache.Get("otherKey"); // Background expiration checks are triggered by misc cache activity.

            Assert.True(callbackInvoked.WaitOne(100), "Callback");

            found = cache.TryGetValue(key, out result);
            Assert.False(found);
            Assert.Null(result);
        }
        public void AbsoluteExpirationExpires()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();

            var result = cache.Set(key, context =>
            {
                context.SetAbsoluteExpiration(clock.UtcNow + TimeSpan.FromMinutes(1));
                return obj;
            });
            Assert.Same(obj, result);

            var found = cache.TryGetValue(key, out result);
            Assert.True(found);
            Assert.Same(obj, result);

            clock.Add(TimeSpan.FromMinutes(2));

            found = cache.TryGetValue(key, out result);
            Assert.False(found);
            Assert.Null(result);
        }
        public void AbsoluteExpirationInThePastThrows()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();

            var expected = clock.UtcNow - TimeSpan.FromMinutes(1);
            ExceptionAssert.ThrowsArgumentOutOfRange(() =>
            {
                var result = cache.Set(key, context =>
                {
                    context.SetAbsoluteExpiration(expected);
                    return obj;
                });
            }, "absolute", "The absolute expiration value must be in the future.", expected.ToString(CultureInfo.CurrentCulture));
        }
        public void ZeroSlidingExpirationThrows()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();

            ExceptionAssert.ThrowsArgumentOutOfRange(() =>
            {
                var result = cache.Set(key, context =>
                {
                    context.SetSlidingExpiration(TimeSpan.Zero);
                    return obj;
                });
            }, "offset", "The sliding expiration value must be positive.", TimeSpan.Zero);
        }
        public void SlidingExpirationRenewedByAccessUntilAbsoluteExpiration()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();

            var result = cache.Set(key, context =>
            {
                context.SetSlidingExpiration(TimeSpan.FromMinutes(1));
                context.SetAbsoluteExpiration(TimeSpan.FromMinutes(2));
                return obj;
            });
            Assert.Same(obj, result);

            var found = cache.TryGetValue(key, out result);
            Assert.True(found);
            Assert.Same(obj, result);

            for (int i = 0; i < 7; i++)
            {
                clock.Add(TimeSpan.FromSeconds(15));

                found = cache.TryGetValue(key, out result);
                Assert.True(found);
                Assert.Same(obj, result);
            }

            clock.Add(TimeSpan.FromSeconds(15));

            found = cache.TryGetValue(key, out result);
            Assert.False(found);
            Assert.Null(result);
        }
        public void NegativeRelativeExpirationThrows()
        {
            var clock = new TestClock();
            var cache = CreateCache(clock);
            var key = "myKey";
            var obj = new object();

            ExceptionAssert.ThrowsArgumentOutOfRange(() =>
            {
                var result = cache.Set(key, context =>
                {
                    context.SetAbsoluteExpiration(TimeSpan.FromMinutes(-1));
                    return obj;
                });
            }, "relative", "The relative expiration value must be positive.", TimeSpan.FromMinutes(-1));
        }