using ErsatzTV.Application.Search; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Search; using NSubstitute; using NUnit.Framework; using Shouldly; namespace ErsatzTV.Tests.Application.Search; [TestFixture] public class QuerySearchIndexAllItemsHandlerTests { private ISearchIndex _searchIndex = null!; private QuerySearchIndexAllItemsHandler _handler = null!; [SetUp] public void SetUp() { _searchIndex = Substitute.For(); // Default every kind's search to an empty page so unconfigured kinds don't NRE. _searchIndex.Search( Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(new SearchResult([], 0)); _handler = new QuerySearchIndexAllItemsHandler(_searchIndex); } [Test] public async Task Handle_Should_Translate_Page_To_Skip_And_Limit() { await _handler.Handle(new QuerySearchIndexAllItems("star", 2, 50), CancellationToken.None); // Every one of the ten media kinds is queried with skip = pageNum * pageSize, limit = pageSize. await _searchIndex.Received(10).Search( Arg.Any(), string.Empty, 100, 50, Arg.Any()); await _searchIndex.Received(1).Search( Arg.Is(q => q.Contains("type:movie")), string.Empty, 100, 50, Arg.Any()); } [Test] public async Task Handle_Should_Return_Ids_And_Per_Kind_Totals() { _searchIndex.Search( Arg.Is(q => q.Contains("type:movie")), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(new SearchResult( [new SearchItem("movie", 1), new SearchItem("movie", 2)], 7)); SearchResultAllItemsViewModel result = await _handler.Handle(new QuerySearchIndexAllItems("star", 0, 500), CancellationToken.None); // The bucket holds this page's ids; the total reflects the full hit count (SearchResult.TotalCount), // which is what lets a client page to completeness. result.MovieIds.ShouldBe(new List { 1, 2 }); result.Totals.MovieCount.ShouldBe(7); // A kind with no hits returns an empty bucket and a zero total. result.ShowIds.ShouldBeEmpty(); result.Totals.ShowCount.ShouldBe(0); } }