Added full-text search to voice works search provider. Added initial tests for voice works full-text search.

This commit is contained in:
2025-08-31 23:29:01 -04:00
parent 3d0b2ed31d
commit a73a2ea1c9
8 changed files with 214 additions and 43 deletions

View File

@@ -26,7 +26,7 @@ public class MariaDbFixture : IAsyncLifetime
await using AppDbContext context = CreateDbContext();
await context.Database.EnsureCreatedAsync();
//await context.Database.MigrateAsync(); // Testing
await OnInitializedAsync(context);
}

View File

@@ -52,6 +52,43 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
new() { EnglishTagId = 8, TagId = 8, Name = "Maid" }
);
context.VoiceWorkTags.AddRange(
new() { VoiceWorkId = 1, TagId = 1 }, // ASMR
new() { VoiceWorkId = 1, TagId = 2 }, // Office Lady
new() { VoiceWorkId = 2, TagId = 1 }, // ASMR
new() { VoiceWorkId = 2, TagId = 3 }, // Heartwarming
new() { VoiceWorkId = 2, TagId = 4 }, // Elf / Fairy
new() { VoiceWorkId = 2, TagId = 5 }, // Tsundere
new() { VoiceWorkId = 2, TagId = 6 }, // All Happy
new() { VoiceWorkId = 2, TagId = 7 }, // Gal
new() { VoiceWorkId = 2, TagId = 8 } // Maid
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 3, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 4, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 },
//new() { VoiceWorkId = 5, TagId = 1 }
);
context.Creators.AddRange(
new() { CreatorId = 1, Name = "陽向葵ゅか", Favorite = true },
new() { CreatorId = 2, Name = "秋野かえで" },
@@ -60,6 +97,15 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
new() { CreatorId = 5, Name = "山田じぇみ子", Blacklisted = true }
);
// <Product Id> <Maker Id> <Circle Name> <Product Name> <Product Description> <Tags> <Creators>
context.VoiceWorkSearches.AddRange(
new() { VoiceWorkId = 1, SearchText = "RJ0000001 RG00001 Good Dreams Today Sounds An average product. ASMR Office Lady" },
new() { VoiceWorkId = 2, SearchText = "RJ0000002 RG00002 Sweet Dreams Super Comfy ASMR An amazing product! ASMR Heartwarming Elf / Fairy Tsundere All Happy Gal Maid" },
new() { VoiceWorkId = 3, SearchText = "RJ0000003 RG00003 Nightmare Fuel Low Effort A bad product." },
new() { VoiceWorkId = 4, SearchText = "RJ0000004 RG00001 Good Dreams Tomorrow Sounds A average upcoming product." },
new() { VoiceWorkId = 5, SearchText = "RJ0000005 RG00002 Sweet Dreams Super Comfy ASMR+ All your favorite sounds, plus more!" }
);
await context.SaveChangesAsync();
}
}

View File

@@ -9,11 +9,19 @@ namespace JSMR.Tests.Integration;
public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture) : IClassFixture<VoiceWorkSearchProviderFixture>
{
private VoiceWorkSearchProvider InitializeVoiceWorkSearchProvider(AppDbContext context)
{
MySqlVoiceWorkFullTextSearch fullTextSearch = new();
VoiceWorkSearchProvider provider = new(context, fullTextSearch);
return provider;
}
[Fact]
public async Task Filter_Default()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = new(context);
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
@@ -21,11 +29,7 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
{
SaleStatus = SaleStatus.Available,
CircleStatus = CircleStatus.NotBlacklisted
},
SortOptions =
[
new(VoiceWorkSortField.ReleaseDate, Application.Common.Search.SortDirection.Descending)
]
}
};
var result = await provider.SearchAsync(options);
@@ -40,7 +44,7 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
public async Task Filter_Upcoming_Favorite()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = new(context);
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
@@ -48,11 +52,7 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
{
SaleStatus = SaleStatus.Upcoming,
CircleStatus = CircleStatus.Favorited
},
SortOptions =
[
new(VoiceWorkSortField.ReleaseDate, Application.Common.Search.SortDirection.Descending)
]
}
};
var result = await provider.SearchAsync(options);
@@ -67,7 +67,7 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
public async Task Filter_Availble_Blacklisted()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = new(context);
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
@@ -75,11 +75,7 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
{
SaleStatus = SaleStatus.Available,
CircleStatus = CircleStatus.Blacklisted
},
SortOptions =
[
new(VoiceWorkSortField.ReleaseDate, Application.Common.Search.SortDirection.Descending)
]
}
};
var result = await provider.SearchAsync(options);
@@ -89,4 +85,93 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
result.Items.ShouldAllBe(item => item.SalesDate != null);
result.Items.ShouldNotContain(item => item.ExpectedDate != null);
}
[Fact]
public async Task Filter_Keywords_Basic()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
Criteria = new()
{
Keywords = "ASMR"
}
};
var result = await provider.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()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
Criteria = new()
{
Keywords = "ASMR -Good"
}
};
var result = await provider.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()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
Criteria = new()
{
Keywords = "Dreams + (Amazing|Favorite)"
}
};
var result = await provider.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()
{
await using AppDbContext context = fixture.CreateDbContext();
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
{
Criteria = new()
{
Keywords = "\"All Your Favorite\""
}
};
var result = await provider.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));
}
}