public async Task When_NoSeasonsAreReturnedForANewShow_HtmlChangedExceptionThrows()
        {
            // Arrange
            var newTvShow = "The Blacklist";

            IEnumerable <TvShow> suggestions = new TvShow[]
            {
                new ("", newTvShow, TVCategory.TVSeries, 2020, "2020-")
            };

            var imdbClient = new Mock <IImdbClient>();

            imdbClient.Setup(m => m.GetSuggestionsAsync(It.IsAny <string>()))
            .Returns(Task.FromResult(suggestions));

            var htmlParserStrategyFactory = new Mock <IHtmlParserStrategyFactory>();

            htmlParserStrategyFactory.Setup(h => h.ResolveParsingStrategy(It.IsAny <string>()))
            .Returns(new Mock <IHtmlParser>().Object);

            var latestAiredTvShowCache = new FakePersistantCache <int>();

            var sut = new SeasonCheckerBuilder()
                      .WithImdbClient(imdbClient.Object)
                      .WithCacheLatestAiredSeasons(latestAiredTvShowCache)
                      .WithHtmlParserStrategy(htmlParserStrategyFactory.Object)
                      .Build();

            // Act & Assert
            await Assert.ThrowsAsync <ImdbHtmlChangedException>(() => sut.TryCheckForNewSeasonAsync(newTvShow));
        }
        public async Task When_TvShowIsCancelled_ShowIsSetAsIgnored()
        {
            // Arrange
            var tvShow = "The Blacklist";

            var tvShowIdCache = new FakePersistantCache <string>(
                new Dictionary <string, string> {
                [tvShow] = "some id"
            });

            var latestAiredSeasonCache = new FakePersistantCache <int>(
                new Dictionary <string, int> {
                [tvShow] = 3
            });

            var ignoredTvShowCache = new FakePersistantCache <string>();

            var htmlParser = new Mock <IHtmlParser>();

            // Setup with no new season.
            htmlParser.Setup(p => p.Seasons(It.IsAny <string>()))
            .Returns(new[]
            {
                3
            });

            htmlParser.Setup(p => p.ShowIsCancelled(It.IsAny <string>()))
            .Returns(true);

            var htmlParserStrategyFactory = new Mock <IHtmlParserStrategyFactory>();

            htmlParserStrategyFactory.Setup(h => h.ResolveParsingStrategy(It.IsAny <string>()))
            .Returns(htmlParser.Object);

            var sut = new SeasonCheckerBuilder()
                      .WithCacheTvShowIds(tvShowIdCache)
                      .WithCacheLatestAiredSeasons(latestAiredSeasonCache)
                      .WithCacheIgnoredTvShows(ignoredTvShowCache)
                      .WithHtmlParserStrategy(htmlParserStrategyFactory.Object)
                      .Build();

            // Act & Assert
            var(newSeasonAired, seasonInfo) = await sut.TryCheckForNewSeasonAsync(tvShow);

            Assert.False(newSeasonAired);

            Assert.True(ignoredTvShowCache.CacheItems.ContainsKey(tvShow));
            Assert.False(latestAiredSeasonCache.CacheItems.ContainsKey(tvShow));
            Assert.False(tvShowIdCache.CacheItems.ContainsKey(tvShow));
        }
        public async Task When_TvShowIsToBeAired_ItIsAddedToSubscriptionList()
        {
            // Arrange
            var newTvShow = "New Tv Show";

            IEnumerable <TvShow> suggestions = new TvShow[]
            {
                new ("", newTvShow, TVCategory.TVSeries, 2023, "2023-")
            };

            var imdbClient = new Mock <IImdbClient>();

            imdbClient.Setup(m => m.GetSuggestionsAsync(It.IsAny <string>()))
            .Returns(Task.FromResult(suggestions));

            var dateTimeProvider = new Mock <IDateTimeProvider>();

            dateTimeProvider.Setup(m => m.Now).Returns(new DateTime(2022, 1, 1)); // Stubbed suggestion is now "to be aired"

            var htmlParser = new Mock <IHtmlParser>();

            htmlParser.Setup(h => h.Seasons(It.IsAny <string>()))
            .Returns(new[]
            {
                1
            });

            var htmlParserStrategyFactory = new Mock <IHtmlParserStrategyFactory>();

            htmlParserStrategyFactory.Setup(h => h.ResolveParsingStrategy(It.IsAny <string>()))
            .Returns(htmlParser.Object);

            var latestAiredSeason = new FakePersistantCache <int>();

            var sut = new SeasonCheckerBuilder()
                      .WithCacheLatestAiredSeasons(latestAiredSeason)
                      .WithImdbClient(imdbClient.Object)
                      .WithHtmlParserStrategy(htmlParserStrategyFactory.Object)
                      .WithDateTimeProvider(dateTimeProvider.Object)
                      .Build();

            // Act
            var(success, newSeason) = await sut.TryCheckForNewSeasonAsync(newTvShow);

            // Assert
            Assert.False(success); // upcoming tv show is treated as a new ongoing tv show. Meaning we now have "latest" aired season
            Assert.True(latestAiredSeason.CacheItems.ContainsKey(newTvShow));
        }
        public async Task When_AnOngoingTvShowIsFirstChecked_LatestAiredSeasonIsSet()
        {
            // Arrange
            var newTvShow = "The Blacklist";

            IEnumerable <TvShow> suggestions = new TvShow[]
            {
                new ("", newTvShow, TVCategory.TVSeries, 2020, "2020-")
            };

            var imdbClient = new Mock <IImdbClient>();

            imdbClient.Setup(m => m.GetSuggestionsAsync(It.IsAny <string>()))
            .Returns(Task.FromResult(suggestions));

            var htmlParser = new Mock <IHtmlParser>();

            htmlParser.Setup(p => p.Seasons(It.IsAny <string>()))
            .Returns(new[]
            {
                1,
                2
            });

            var htmlParserStrategyFactory = new Mock <IHtmlParserStrategyFactory>();

            htmlParserStrategyFactory.Setup(h => h.ResolveParsingStrategy(It.IsAny <string>()))
            .Returns(htmlParser.Object);

            htmlParser.Setup(p => p.AnyEpisodeHasAired(It.IsAny <string>()))
            .Returns(true);

            var latestAiredTvShowCache = new FakePersistantCache <int>();

            var sut = new SeasonCheckerBuilder()
                      .WithImdbClient(imdbClient.Object)
                      .WithHtmlParserStrategy(htmlParserStrategyFactory.Object)
                      .WithCacheLatestAiredSeasons(latestAiredTvShowCache)
                      .Build();

            // Act
            var(success, newSeason) = await sut.TryCheckForNewSeasonAsync(newTvShow);

            // Assert
            Assert.True(latestAiredTvShowCache.Exists(newTvShow));
        }
        public async Task When_TvShowHasANewAiredSeason_ShowCacheIsUpdatedWithTheValue()
        {
            // Arrange
            var tvShow = "The Blacklist";

            var tvShowIdCache = new FakePersistantCache <string>(
                new Dictionary <string, string> {
                [tvShow] = "some id"
            });

            var latestAiredSeasonCache = new FakePersistantCache <int>(
                new Dictionary <string, int> {
                [tvShow] = 3
            });

            var htmlParser = new Mock <IHtmlParser>();

            // Setup with new season.
            htmlParser.Setup(p => p.Seasons(It.IsAny <string>()))
            .Returns(new[]
            {
                4
            });

            htmlParser.Setup(p => p.AnyEpisodeHasAired(It.IsAny <string>()))
            .Returns(true);

            var htmlParserStrategyFactory = new Mock <IHtmlParserStrategyFactory>();

            htmlParserStrategyFactory.Setup(h => h.ResolveParsingStrategy(It.IsAny <string>()))
            .Returns(htmlParser.Object);

            var sut = new SeasonCheckerBuilder()
                      .WithCacheTvShowIds(tvShowIdCache)
                      .WithCacheLatestAiredSeasons(latestAiredSeasonCache)
                      .WithHtmlParserStrategy(htmlParserStrategyFactory.Object)
                      .Build();

            // Act & Assert
            var(newSeasonAired, seasonInfo) = await sut.TryCheckForNewSeasonAsync(tvShow);

            Assert.True(newSeasonAired);
            Assert.Equal(4, latestAiredSeasonCache.CacheItems[tvShow]);
        }
        public async Task When_TvShowSuggestionsIsNotFound_TvShowIsAddedToIgnoredList()
        {
            // Arrange
            var imdbClient = new Mock <IImdbClient>();

            imdbClient.Setup(m => m.GetSuggestionsAsync(It.IsAny <string>()))
            .Returns(Task.FromResult(Enumerable.Empty <TvShow>()));

            var ignoredTvShowsCache = new FakePersistantCache <string>();

            var sut = new SeasonCheckerBuilder()
                      .WithCacheIgnoredTvShows(ignoredTvShowsCache)
                      .WithImdbClient(imdbClient.Object)
                      .Build();

            // Act
            var(success, newSeason) = await sut.TryCheckForNewSeasonAsync("The Blacklist");

            // Assert
            Assert.False(success);
            Assert.NotEmpty(ignoredTvShowsCache.CacheItems);
        }