using JSMR.Application.Common.Search; using JSMR.Application.VoiceWorks.Queries.Search; using JSMR.Infrastructure.Data; using JSMR.Infrastructure.Data.Repositories.VoiceWorks; using Shouldly; using SortDirection = JSMR.Application.Common.Search.SortDirection; namespace JSMR.Tests.Search.VoiceWork; public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture) : IClassFixture { private async Task> SearchAsync(SearchOptions options) { AppDbContext context = fixture.DbContext!; MySqlVoiceWorkFullTextSearch fullTextSearch = new(); VoiceWorkSearchProvider provider = new(context, fullTextSearch); return await provider.SearchAsync(options, TestContext.Current.CancellationToken); } [Fact] public async Task Filter_Default() { var options = new SearchOptions() { Criteria = new() { SaleStatus = SaleStatus.Available, CircleStatus = CircleStatus.NotBlacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items.ShouldAllBe(item => item.SalesDate != null); result.Items.ShouldNotContain(item => item.ExpectedDate != null); } [Fact] public async Task Filter_Upcoming_Favorite() { var options = new SearchOptions() { Criteria = new() { SaleStatus = SaleStatus.Upcoming, CircleStatus = CircleStatus.Favorited } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items.ShouldAllBe(item => item.ExpectedDate != null); result.Items.ShouldNotContain(item => item.SalesDate != null); } [Fact] public async Task Filter_Availble_Blacklisted() { var options = new SearchOptions() { Criteria = new() { SaleStatus = SaleStatus.Available, CircleStatus = CircleStatus.Blacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items.ShouldAllBe(item => item.SalesDate != null); result.Items.ShouldNotContain(item => item.ExpectedDate != null); } [Fact] public async Task Filter_Keywords_Basic() { var options = new SearchOptions() { Criteria = new() { Keywords = "ASMR" } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(3); result.TotalItems.ShouldBe(3); result.Items.ShouldAllBe(item => item.Tags.Any(tag => tag.Name == "ASMR") || item.ProductName.Contains("ASMR") || (item.Description ?? string.Empty).Contains("ASMR")); } [Fact] public async Task Filter_Keywords_Not_Good() { var options = new SearchOptions() { Criteria = new() { Keywords = "ASMR -Good" } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items.ShouldAllBe(item => item.Tags.Any(tag => tag.Name == "ASMR") || item.ProductName.Contains("ASMR") || (item.Description ?? string.Empty).Contains("ASMR")); result.Items.ShouldAllBe(item => !item.Tags.Any(tag => tag.Name == "Good") || !item.ProductName.Contains("Good") || !(item.Description ?? string.Empty).Contains("Good")); } [Fact] public async Task Filter_Keywords_Dreams_And_Amazing_Or_Favorite() { var options = new SearchOptions() { Criteria = new() { Keywords = "Dreams + (Amazing|Favorite)" } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000005"]); } [Fact] public async Task Filter_Keywords_Phrase_Search() { var options = new SearchOptions() { Criteria = new() { Keywords = "\"All Your Favorite\"" } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items.ShouldAllBe(item => (item.Description ?? string.Empty).Contains("All Your Favorite", StringComparison.OrdinalIgnoreCase)); } [Fact] public async Task Filter_Tags_Favorite_Exclude_Blacklisted() { var options = new SearchOptions() { Criteria = new() { TagStatus = TagStatus.FavoriteExcludeBlacklist } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002"]); } [Fact] public async Task Filter_Tags_Favorite_Include_Blacklisted() { var options = new SearchOptions() { Criteria = new() { TagStatus = TagStatus.FavoriteIncludeBlacklist } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000003"]); } [Fact] public async Task Filter_Tags_Not_Blacklisted() { var options = new SearchOptions() { Criteria = new() { TagStatus = TagStatus.NotBlacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(4); result.TotalItems.ShouldBe(4); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000002", "RJ0000004", "RJ0000005"]); } [Fact] public async Task Filter_Tags_Blacklisted() { var options = new SearchOptions() { Criteria = new() { TagStatus = TagStatus.Blacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000003"]); } [Fact] public async Task Filter_TagIds_Or() { var options = new SearchOptions() { Criteria = new() { TagIds = [1,2], IncludeAllTags = false } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000002"]); } [Fact] public async Task Filter_TagIds_And() { var options = new SearchOptions() { Criteria = new() { TagIds = [1, 2], IncludeAllTags = true } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001"]); } [Fact] public async Task Filter_Creators_Favorite_Exclude_Blacklisted() { var options = new SearchOptions() { Criteria = new() { CreatorStatus = CreatorStatus.FavoriteExcludeBlacklist } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(2); result.TotalItems.ShouldBe(2); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000005"]); } [Fact] public async Task Filter_Creators_Favorite_Include_Blacklisted() { var options = new SearchOptions() { Criteria = new() { CreatorStatus = CreatorStatus.FavoriteIncludeBlacklist } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(3); result.TotalItems.ShouldBe(3); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000003", "RJ0000005"]); } [Fact] public async Task Filter_Creators_Not_Blacklisted() { var options = new SearchOptions() { Criteria = new() { CreatorStatus = CreatorStatus.NotBlacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(4); result.TotalItems.ShouldBe(4); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000002", "RJ0000004", "RJ0000005"]); } [Fact] public async Task Filter_Creators_Blacklisted() { var options = new SearchOptions() { Criteria = new() { CreatorStatus = CreatorStatus.Blacklisted } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000003"]); } [Fact] public async Task Filter_CreatorIds_Or() { var options = new SearchOptions() { Criteria = new() { CreatorIds = [1, 4], IncludeAllCreators = false } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(3); result.TotalItems.ShouldBe(3); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000003", "RJ0000005"]); } [Fact] public async Task Filter_CreatorIds_And() { var options = new SearchOptions() { Criteria = new() { CreatorIds = [1, 4], IncludeAllCreators = true } }; var result = await SearchAsync(options); result.Items.Length.ShouldBe(1); result.TotalItems.ShouldBe(1); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000005"]); } [Fact] public async Task Sort_By_Release_Date_Ascending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.ReleaseDate, SortDirection.Ascending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000004", "RJ0000003", "RJ0000002", "RJ0000005"]); } [Fact] public async Task Sort_By_Release_Date_Descending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.ReleaseDate, SortDirection.Descending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000005", "RJ0000002", "RJ0000003", "RJ0000001", "RJ0000004"]); } [Fact] public async Task Sort_By_Downloads_Ascending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.Downloads, SortDirection.Ascending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000004", "RJ0000005", "RJ0000003", "RJ0000001", "RJ0000002"]); } [Fact] public async Task Sort_By_Downloads_Descending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.Downloads, SortDirection.Descending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000001", "RJ0000003", "RJ0000004", "RJ0000005"]); } [Fact] public async Task Sort_By_WishlistCount_Ascending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.WishlistCount, SortDirection.Ascending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000003", "RJ0000004", "RJ0000001", "RJ0000005", "RJ0000002"]); } [Fact] public async Task Sort_By_WishlistCount_Descending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.WishlistCount, SortDirection.Descending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000005", "RJ0000001", "RJ0000004", "RJ0000003"]); } [Fact] public async Task Sort_By_StarRating_Ascending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.StarRating, SortDirection.Ascending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000004", "RJ0000005", "RJ0000003", "RJ0000001", "RJ0000002"]); } [Fact] public async Task Sort_By_StarRating_Descending() { var options = new SearchOptions() { SortOptions = [ new(VoiceWorkSortField.StarRating, SortDirection.Descending) ] }; var result = await SearchAsync(options); result.Items .Select(item => item.ProductId) .ShouldBe(["RJ0000002", "RJ0000001", "RJ0000003", "RJ0000004", "RJ0000005"]); } [Fact] public async Task Filter_Scheduled_Release_Date_Range() { var options = new SearchOptions() { Criteria = new() { ScheduledReleaseDateStart = new DateOnly(2025, 1, 1), ScheduledReleaseDateEnd = new DateOnly(2025, 1, 13) } }; var result = await SearchAsync(options); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000005"]); } [Fact] public async Task Filter_Release_Date_Range() { var options = new SearchOptions() { Criteria = new() { ReleaseDateStart = new DateOnly(2025, 1, 1), ReleaseDateEnd = new DateOnly(2025, 1, 2) } }; var result = await SearchAsync(options); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000003"]); } [Fact] public async Task Filter_Downloads_Range() { var options = new SearchOptions() { Criteria = new() { MinDownloads = 100, MaxDownloads = 10000 } }; var result = await SearchAsync(options); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000001", "RJ0000002"]); } [Fact] public async Task Filter_Favorite() { var options = new SearchOptions() { Criteria = new() { ShowFavoriteVoiceWorks = true } }; var result = await SearchAsync(options); result.Items .OrderBy(item => item.ProductId) .Select(item => item.ProductId) .ShouldBe(["RJ0000002"]); } }