/// <summary>
        /// Creates the default <see cref="IMapImageRetriever"/>, which is a
        /// database cache that falls back to HERE services.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <returns>The default <see cref="IMapImageRetriever"/>.</returns>
        public static IMapImageRetriever CreateDefault(IServiceProvider serviceProvider)
        {
            var hereMapsRetriever = new HEREMapImageRetriever(
                serviceProvider.GetService <IGeocodeClient>(),
                serviceProvider.GetService <IMapImageClient>());

            var cacheRetriever = new CachedMapImageRetriever(
                serviceProvider.GetService <FvectContext>(),
                hereMapsRetriever,
                serviceProvider.GetService <IOptionsMonitor <BackendOptions> >(),
                serviceProvider.GetService <ILogger <CachedMapImageRetriever> >());

            return(cacheRetriever);
        }
        public async Task CachableImageWithinCacheRetrievesFromCache()
        {
            using var db = new TestDatabase(this.outputHelper);

            var zipCode           = "1234 AB";
            var zipCodeNormalized = "1234";
            var houseNumber       = 1;
            var zoomLevel         = ZoomLevel.CITY;
            var imageData         = new byte[] { 0, 1, 2, 3, };

            var optionsMock = OptionsTestHelper.CreateBackendOptionsMock(
                x => x.Geo.CacheTimesPerZoomLevel = ImmutableDictionary <ZoomLevel, TimeSpan> .Empty.Add(
                    zoomLevel,
                    TimeSpan.MaxValue));

            var innerMock = new Mock <IMapImageRetriever>();

            var logger = LoggingTestHelper.CreateLogger <CachedMapImageRetriever>(this.outputHelper);

            var imageInCache = new MapImage
            {
                PostalCode       = zipCodeNormalized,
                ImageData        = imageData,
                ZoomLevel        = zoomLevel,
                LastTimeAccessed = DateTimeOffset.UtcNow,
            };

            using (var ctx = await db.CreateContextAsync().ConfigureAwait(true))
            {
                ctx.MapImages.Add(imageInCache);
                await ctx.SaveChangesAsync().ConfigureAwait(true);
            }

            Stream?imageStream = default;

            using (var ctx = await db.CreateContextAsync().ConfigureAwait(true))
            {
                var retriever = new CachedMapImageRetriever(
                    ctx,
                    innerMock.Object,
                    optionsMock.Object,
                    logger);

                imageStream = await retriever.GetMapImageAsync(
                    zipCode,
                    houseNumber,
                    zoomLevel,
                    default)
                              .ConfigureAwait(true);
            }

            imageStream
            .Should()
            .NotBeNull(
                because: "the value should have been retrieved from the cache");

            using var ms           = new MemoryStream();
            imageStream !.Position = 0;
            await imageStream.CopyToAsync(ms).ConfigureAwait(true);

            ms.ToArray()
            .Should()
            .BeEquivalentTo(
                imageData,
                because: "the retrieved value should be equal to the data intially stored in the cache");

            innerMock.VerifyNoOtherCalls();
        }