public void IfAnyMethodsNotConfigured_ThrowsException()
        {
            var originalImpl = new DummySingleKeyInterfaceImpl();

            var cache = new MockLocalCache <int, int>();

            Action action = () => CachedInterfaceFactory.For <IDummySingleKeyInterface>(originalImpl)
                            .Configure <int, int>(x => x.GetAsync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache))
                            .Configure <int, int>(x => x.GetAsyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache))
                            .Configure <int, int>(x => x.GetSync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache))
                            .Build();

            action.Should().Throw <Exception>().Where(ex => ex.Message.Contains(nameof(IDummySingleKeyInterface.GetSyncCanx)));
        }
        public void WorksWithUpTo8Parameters()
        {
            var originalImpl = new MultiParamImpl();

            var cachedInterface = CachedInterfaceFactory.For <IMultiParam>(originalImpl)
                                  .Configure <int, int, int, int>(
                x => x.GetAsync3,
                c => c.WithCacheKey((p1, p2, p3) => p1))
                                  .Configure <int, int, int, int, IEnumerable <int>, Dictionary <int, int> >(
                x => x.GetMultiSyncCanx5,
                c => c.WithEnumerableKeys <int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>())
                                  .Configure <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int> >(
                x => x.GetMultiValueTask8,
                c => c
                .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>()
                .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1))
                                  .Build();

            cachedInterface.GetAsync3(1, 2, 3).Result.Should().Be(6);
            cachedInterface.GetMultiSyncCanx5(1, 2, 3, 4, new[] { 5 }, CancellationToken.None).Single().Should().Be(new KeyValuePair <int, int>(5, 15));
            cachedInterface.GetMultiValueTask8(1, 2, 3, 4, 5, 6, 7, new[] { 8 }).Result.Single().Should().Be(new KeyValuePair <int, int>(8, 36));
        }
        public void OuterKeyAndInnerEnumerableKey_WorksForAllMethodTypes()
        {
            var originalImpl = new DummyOuterKeyAndInnerEnumerableKeyInterfaceImpl();

            var cache1 = new MockLocalCache <int, int, int>();
            var cache2 = new MockLocalCache <int, int, int>();
            var cache3 = new MockLocalCache <int, int, int>();
            var cache4 = new MockLocalCache <int, int, int>();
            var cache5 = new MockLocalCache <int, int, int>();
            var cache6 = new MockLocalCache <int, int, int>();

            var cachedInterface = CachedInterfaceFactory.For <IDummyOuterKeyAndInnerEnumerableKeyInterface>(originalImpl)
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsync, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1))
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsyncCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2))
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetSync, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3))
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetSyncCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4))
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTask, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5))
                                  .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTaskCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6))
                                  .Build();

            cachedInterface.GetAsync(0, new[] { 1 }).Result.Single().Should().Be(new KeyValuePair <int, int>(1, 1));
            cache1.GetMany(0, new[] { 1 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(1, 1));

            cachedInterface.GetAsyncCanx(0, new[] { 2 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(2, 2));
            cache2.GetMany(0, new[] { 2 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(2, 2));

            cachedInterface.GetSync(0, new[] { 3 }).Single().Should().Be(new KeyValuePair <int, int>(3, 3));
            cache3.GetMany(0, new[] { 3 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(3, 3));

            cachedInterface.GetSyncCanx(0, new[] { 4 }, CancellationToken.None).Single().Should().Be(new KeyValuePair <int, int>(4, 4));
            cache4.GetMany(0, new[] { 4 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(4, 4));

            cachedInterface.GetValueTask(0, new[] { 5 }).Result.Single().Should().Be(new KeyValuePair <int, int>(5, 5));
            cache5.GetMany(0, new[] { 5 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(5, 5));

            cachedInterface.GetValueTaskCanx(0, new[] { 6 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(6, 6));
            cache6.GetMany(0, new[] { 6 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(6, 6));
        }
        public void EnumerableKey_WorksForAllMethodTypes()
        {
            var originalImpl = new DummyEnumerableKeyInterfaceImpl();

            var cache1 = new MockLocalCache <int, int>();
            var cache2 = new MockLocalCache <int, int>();
            var cache3 = new MockLocalCache <int, int>();
            var cache4 = new MockLocalCache <int, int>();
            var cache5 = new MockLocalCache <int, int>();
            var cache6 = new MockLocalCache <int, int>();

            var cachedInterface = CachedInterfaceFactory.For <IDummyEnumerableKeyInterface>(originalImpl)
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsync, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1))
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsyncCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2))
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetSync, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3))
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetSyncCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4))
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTask, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5))
                                  .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTaskCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6))
                                  .Build();

            cachedInterface.GetAsync(new[] { 1 }).Result.Single().Should().Be(new KeyValuePair <int, int>(1, 1));
            cache1.TryGet(1, out _).Should().BeTrue();

            cachedInterface.GetAsyncCanx(new[] { 2 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(2, 2));
            cache2.TryGet(2, out _).Should().BeTrue();

            cachedInterface.GetSync(new[] { 3 }).Single().Should().Be(new KeyValuePair <int, int>(3, 3));
            cache3.TryGet(3, out _).Should().BeTrue();

            cachedInterface.GetSyncCanx(new[] { 4 }, CancellationToken.None).Single().Should().Be(new KeyValuePair <int, int>(4, 4));
            cache4.TryGet(4, out _).Should().BeTrue();

            cachedInterface.GetValueTask(new[] { 5 }).Result.Single().Should().Be(new KeyValuePair <int, int>(5, 5));
            cache5.TryGet(5, out _).Should().BeTrue();

            cachedInterface.GetValueTaskCanx(new[] { 6 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(6, 6));
            cache6.TryGet(6, out _).Should().BeTrue();
        }
        public void SingleKey_WorksForAllMethodTypes()
        {
            var originalImpl = new DummySingleKeyInterfaceImpl();

            var cache1 = new MockLocalCache <int, int>();
            var cache2 = new MockLocalCache <int, int>();
            var cache3 = new MockLocalCache <int, int>();
            var cache4 = new MockLocalCache <int, int>();
            var cache5 = new MockLocalCache <int, int>();
            var cache6 = new MockLocalCache <int, int>();

            var cachedInterface = CachedInterfaceFactory.For <IDummySingleKeyInterface>(originalImpl)
                                  .Configure <int, int>(x => x.GetAsync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1))
                                  .Configure <int, int>(x => x.GetAsyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2))
                                  .Configure <int, int>(x => x.GetSync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3))
                                  .Configure <int, int>(x => x.GetSyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4))
                                  .Configure <int, int>(x => x.GetValueTask, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5))
                                  .Configure <int, int>(x => x.GetValueTaskCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6))
                                  .Build();

            cachedInterface.GetAsync(1).Result.Should().Be(1);
            cache1.TryGet(1, out _).Should().BeTrue();

            cachedInterface.GetAsyncCanx(2, CancellationToken.None).Result.Should().Be(2);
            cache2.TryGet(2, out _).Should().BeTrue();

            cachedInterface.GetSync(3).Should().Be(3);
            cache3.TryGet(3, out _).Should().BeTrue();

            cachedInterface.GetSyncCanx(4, CancellationToken.None).Should().Be(4);
            cache4.TryGet(4, out _).Should().BeTrue();

            cachedInterface.GetValueTask(5).Result.Should().Be(5);
            cache5.TryGet(5, out _).Should().BeTrue();

            cachedInterface.GetValueTaskCanx(6, CancellationToken.None).Result.Should().Be(6);
            cache6.TryGet(6, out _).Should().BeTrue();
        }