fix: preserve search input and add choseong lookup
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
using System.Text;
|
||||
using MMoneyCoderSharp.Data;
|
||||
|
||||
namespace MBN_STOCK_WEBVIEW.Core.Tests;
|
||||
|
||||
public sealed class HangulSearchMatcherTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("삼성전자", "ㅅㅅㅈㅈ")]
|
||||
[InlineData("홍길동 위원", "ㅎㄱㄷ ㅇㅇ")]
|
||||
[InlineData("까치산", "ㄲㅊㅅ")]
|
||||
[InlineData("삼성전자(NXT)", "ㅅㅅㅈㅈ")]
|
||||
[InlineData("삼성전자", "ᄉᄉᄌᄌ")]
|
||||
public void IsMatch_MatchesCompatibilityOrLeadingInitialConsonants(
|
||||
string candidate,
|
||||
string query)
|
||||
{
|
||||
Assert.True(HangulSearchMatcher.IsMatch(candidate, query));
|
||||
Assert.True(HangulSearchMatcher.IsInitialConsonantQuery(query));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsMatch_NormalizesDecomposedHangulAndKeepsOrdinarySubstringSearch()
|
||||
{
|
||||
var decomposed = "삼성전자".Normalize(NormalizationForm.FormD);
|
||||
|
||||
Assert.True(HangulSearchMatcher.IsMatch(decomposed, "ㅅㅅㅈㅈ"));
|
||||
Assert.True(HangulSearchMatcher.IsMatch("김전문 연구원", "전문"));
|
||||
Assert.True(HangulSearchMatcher.IsMatch("Alpha Analyst", "analyst"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("삼성전자", "ㅅ성")]
|
||||
[InlineData("삼성전자", "ㅏ")]
|
||||
public void IsMatch_DoesNotTreatMixedOrNonInitialJamoAsFuzzyInput(
|
||||
string candidate,
|
||||
string query)
|
||||
{
|
||||
Assert.False(HangulSearchMatcher.IsMatch(candidate, query));
|
||||
Assert.False(HangulSearchMatcher.IsInitialConsonantQuery(query));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsMatch_RecognizesAValidDoubleInitialWithoutCreatingAFalseMatch()
|
||||
{
|
||||
Assert.True(HangulSearchMatcher.IsInitialConsonantQuery("ㄲㅅ"));
|
||||
Assert.False(HangulSearchMatcher.IsMatch("삼성전자", "ㄲㅅ"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsMatch_BlankQueryRetainsExistingInitialListBehavior()
|
||||
{
|
||||
Assert.True(HangulSearchMatcher.IsMatch("아무 이름", " "));
|
||||
Assert.False(HangulSearchMatcher.IsInitialConsonantQuery(" "));
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,46 @@ public sealed class LegacyExpertSelectionServiceTests
|
||||
Assert.Equal(2, executor.Calls[0].Spec.Parameters[1].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_MatchesHangulInitialConsonantsAfterBoundedCandidateRead()
|
||||
{
|
||||
var executor = new RecordingExecutor(_ => SearchTable(
|
||||
("박전문", "0003"),
|
||||
("김투자", "0002"),
|
||||
("김전문", "0001"),
|
||||
("강지민", "0004")));
|
||||
var service = new LegacyExpertSelectionService(executor);
|
||||
|
||||
var result = await service.SearchAsync(" ㄱㅈㅁ ", maximumResults: 10);
|
||||
|
||||
Assert.Equal("ㄱㅈㅁ", result.Query);
|
||||
Assert.False(result.IsTruncated);
|
||||
Assert.Equal(
|
||||
["강지민", "김전문"],
|
||||
result.Items.Select(item => item.Identity.ExpertName));
|
||||
var call = Assert.Single(executor.Calls);
|
||||
Assert.Equal(string.Empty, call.Spec.Parameters[0].Value);
|
||||
Assert.Equal(LegacyExpertSelectionService.MaximumResults + 1,
|
||||
call.Spec.Parameters[1].Value);
|
||||
Assert.DoesNotContain("ㄱㅈㅁ", call.Spec.Sql, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchAsync_AppliesRequestedLimitAfterInitialConsonantFiltering()
|
||||
{
|
||||
var executor = new RecordingExecutor(_ => SearchTable(
|
||||
("김전문", "0001"),
|
||||
("강지민", "0002"),
|
||||
("고정민", "0003")));
|
||||
|
||||
var result = await new LegacyExpertSelectionService(executor)
|
||||
.SearchAsync("ᄀᄌᄆ", maximumResults: 1);
|
||||
|
||||
Assert.Single(result.Items);
|
||||
Assert.Equal("강지민", result.Items[0].Identity.ExpertName);
|
||||
Assert.True(result.IsTruncated);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(-1)]
|
||||
|
||||
Reference in New Issue
Block a user