public void GetUpcomingMovies_SpecificPage_InvokeServiceWithCorrectParameters()
        {
            int       expectedPage     = 2;
            var       expectedLanguage = "en-US";
            var       pagingInfo       = new MoviePagingInfo();
            GenreInfo genreInfo        = null;

            var apiClientMock = new Mock <ITmdbApiClient>();

            apiClientMock
            .Setup(x => x.FetchUpcomingMovies(
                       It.IsAny <int>(),
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(pagingInfo));
            apiClientMock
            .Setup(x => x.FetchMovieGenres(
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(genreInfo));

            var apiServiceMock = new Mock <ITmdbApiService>();

            apiServiceMock
            .Setup(x => x.GetClient())
            .Returns(apiClientMock.Object);

            var cacheMock = new Mock <ICache>();

            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <MoviePagingInfo> > >()))
            .Returns <string, Func <IObservable <MoviePagingInfo> > >((arg, targetMethod) => targetMethod());
            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <GenreInfo> > >()))
            .Returns <string, Func <IObservable <GenreInfo> > >((arg, targetMethod) => targetMethod());

            var target = new MovieService(
                apiServiceMock.Object,
                cacheMock.Object);

            target.GetUpcomingMovies(expectedPage).Subscribe();

            apiServiceMock.Verify(x => x.GetClient(), Times.Once);
            apiClientMock.Verify(
                x => x.FetchUpcomingMovies(
                    It.Is <int>(page => page == expectedPage),
                    It.Is <string>(language => language == expectedLanguage)),
                Times.Once);
            apiClientMock.Verify(
                x => x.FetchMovieGenres(
                    It.Is <string>(language => language == expectedLanguage)),
                Times.Once);
        }
        public void GetMovies_WhenInvoked_UsesSpecifiedCacheKey()
        {
            var expectedQuery = "another query";
            int expectedPage  = 2;
            var pagingInfo    = new MoviePagingInfo();

            GenreInfo genreInfo = null;

            var apiClientMock = new Mock <ITmdbApiClient>();

            apiClientMock
            .Setup(x => x.FetchMovies(
                       It.IsAny <string>(),
                       It.IsAny <int>(),
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(pagingInfo));
            apiClientMock
            .Setup(x => x.FetchMovieGenres(
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(genreInfo));

            var apiServiceMock = new Mock <ITmdbApiService>();

            apiServiceMock
            .Setup(x => x.GetClient())
            .Returns(apiClientMock.Object);

            var cacheMock = new Mock <ICache>();

            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <MoviePagingInfo> > >()))
            .Returns <string, Func <IObservable <MoviePagingInfo> > >((arg, targetMethod) => targetMethod());
            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <GenreInfo> > >()))
            .Returns <string, Func <IObservable <GenreInfo> > >((arg, targetMethod) => targetMethod());

            var target = new MovieService(
                apiServiceMock.Object,
                cacheMock.Object);

            target
            .GetMovies(expectedQuery, expectedPage)
            .Subscribe();

            cacheMock.Verify(
                x => x.GetAndFetchLatest(
                    It.Is <string>(cacheKey => cacheKey == $"movies_{expectedQuery}_{expectedPage}"),
                    It.IsAny <Func <IObservable <MoviePagingInfo> > >()),
                Times.Once);
        }
        public void GetMovies_PagingInfoIsNull_ReturnsEmpty()
        {
            string expectedQuery = "a query value";
            int    expectedPage  = 2;

            MoviePagingInfo pagingInfo = null;
            GenreInfo       genreInfo  = null;

            var apiClientMock = new Mock <ITmdbApiClient>();

            apiClientMock
            .Setup(x => x.FetchMovies(
                       It.IsAny <string>(),
                       It.IsAny <int>(),
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(pagingInfo));
            apiClientMock
            .Setup(x => x.FetchMovieGenres(
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(genreInfo));

            var apiServiceMock = new Mock <ITmdbApiService>();

            apiServiceMock
            .Setup(x => x.GetClient())
            .Returns(apiClientMock.Object);

            var cacheMock = new Mock <ICache>();

            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <MoviePagingInfo> > >()))
            .Returns <string, Func <IObservable <MoviePagingInfo> > >((arg, targetMethod) => targetMethod());
            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <GenreInfo> > >()))
            .Returns <string, Func <IObservable <GenreInfo> > >((arg, targetMethod) => targetMethod());

            var target = new MovieService(
                apiServiceMock.Object,
                cacheMock.Object);

            IEnumerable <Movie> resultData = null;

            Assert.DoesNotThrow(
                () => target
                .GetMovies(expectedQuery, expectedPage)
                .Subscribe(results => resultData = results));

            Assert.IsEmpty(resultData);
        }
        public void GetMovies_MovieHasGenres_MovieWithGenres()
        {
            string expectedQuery = "query";
            int    expectedPage  = 2;
            var    pagingInfo    = new MoviePagingInfo()
            {
                Results = new List <MovieResult>()
                {
                    new MovieResult()
                    {
                        Id = 1, Title = "Movie 1", GenreIds = new List <int>()
                        {
                            1, 2, 3
                        }, ReleaseDate = "2004-01-02"
                    },
                    new MovieResult()
                    {
                        Id = 2, Title = "Movie 2", GenreIds = new List <int>()
                        {
                            1, 3
                        }, ReleaseDate = "2003-10-10"
                    }
                }
            };
            var genreInfo = new GenreInfo()
            {
                Genres = new List <GenreResult>()
                {
                    new GenreResult()
                    {
                        Id = 1, Name = "Genre 1"
                    },
                    new GenreResult()
                    {
                        Id = 2, Name = "Genre 2"
                    },
                    new GenreResult()
                    {
                        Id = 3, Name = "Genre 3"
                    }
                }
            };

            var apiClientMock = new Mock <ITmdbApiClient>();

            apiClientMock
            .Setup(x => x.FetchMovies(
                       It.IsAny <string>(),
                       It.IsAny <int>(),
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(pagingInfo));
            apiClientMock
            .Setup(x => x.FetchMovieGenres(
                       It.IsAny <string>()))
            .Returns(() => Observable.Return(genreInfo));

            var apiServiceMock = new Mock <ITmdbApiService>();

            apiServiceMock
            .Setup(x => x.GetClient())
            .Returns(apiClientMock.Object);

            var cacheMock = new Mock <ICache>();

            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <MoviePagingInfo> > >()))
            .Returns <string, Func <IObservable <MoviePagingInfo> > >((arg, targetMethod) => targetMethod());
            cacheMock
            .Setup(x => x.GetAndFetchLatest(
                       It.IsAny <string>(),
                       It.IsAny <Func <IObservable <GenreInfo> > >()))
            .Returns <string, Func <IObservable <GenreInfo> > >((arg, targetMethod) => targetMethod());

            IList <Movie> results = null;

            var target = new MovieService(
                apiServiceMock.Object,
                cacheMock.Object);

            target
            .GetMovies(expectedQuery, expectedPage)
            .Subscribe(movies => results = movies.ToList());

            Assert.AreEqual(pagingInfo.Results.Count, results.Count());
            Assert.AreEqual(pagingInfo.Results[0].GenreIds.Count, results[0].Genres.Count());
            Assert.AreEqual(pagingInfo.Results[1].GenreIds.Count, results[1].Genres.Count());
        }