193 lines
6.3 KiB
C#
193 lines
6.3 KiB
C#
using MaigoLabs.NeedLe.Indexer;
|
|
using MaigoLabs.NeedLe.Searcher;
|
|
|
|
namespace MaigoLabs.NeedLe.Tests.E2E;
|
|
|
|
public sealed class Search_MatchesWithMixedSearchQueryTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(TestDocuments, TokenizerOptions);
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed);
|
|
|
|
var results = InvertedIndexSearcher.Search(invertedIndex, "bokunoh风じょう");
|
|
|
|
// Should have at least one result
|
|
Assert.NotEmpty(results);
|
|
|
|
// The first result should be "僕の和風本当上手"
|
|
Assert.Equal("僕の和風本当上手", results[0].DocumentText);
|
|
}
|
|
}
|
|
|
|
public sealed class Search_HighlightsSearchResultCorrectlyTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(TestDocuments, TokenizerOptions);
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed);
|
|
|
|
var results = InvertedIndexSearcher.Search(invertedIndex, "bokunoh风じょう");
|
|
Assert.NotEmpty(results);
|
|
|
|
var highlighted = SearchResultHighlighter.Highlight(results[0]);
|
|
|
|
// Should be a list of parts
|
|
Assert.NotEmpty(highlighted);
|
|
|
|
// Collect highlighted text
|
|
var highlightedTexts = highlighted.Where(p => p.IsHighlighted).Select(p => p.Text).ToList();
|
|
var highlightedJoined = string.Join("", highlightedTexts);
|
|
|
|
Assert.Contains("僕", highlightedJoined);
|
|
Assert.Contains("の", highlightedJoined);
|
|
Assert.Contains("和", highlightedJoined);
|
|
Assert.Contains("風", highlightedJoined);
|
|
Assert.Contains("上", highlightedJoined);
|
|
}
|
|
}
|
|
|
|
public sealed class Search_MatchesRomajiInputToKanaDocumentsTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(TestDocuments, TokenizerOptions);
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed);
|
|
|
|
// Search for "yoi" should match "宵の鳥"
|
|
var results = InvertedIndexSearcher.Search(invertedIndex, "yoi");
|
|
var matchedTexts = results.Select(r => r.DocumentText).ToList();
|
|
|
|
Assert.Contains("宵の鳥", matchedTexts);
|
|
}
|
|
}
|
|
|
|
public sealed class Search_BundleDocumentsOption_WorksWhenNotBundledTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(
|
|
TestDocuments,
|
|
TokenizerOptions,
|
|
new InvertedIndexBuilderOptions { BundleDocuments = false });
|
|
|
|
// Documents should not be in the compressed index
|
|
Assert.Null(compressed.documents);
|
|
|
|
// Load with documents provided explicitly
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed, TestDocuments);
|
|
|
|
var results = InvertedIndexSearcher.Search(invertedIndex, "yoi");
|
|
Assert.Contains("宵の鳥", results.Select(r => r.DocumentText));
|
|
}
|
|
}
|
|
|
|
public sealed class Search_BundleDocumentsOption_ThrowsWhenNoneProvidedTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(
|
|
TestDocuments,
|
|
TokenizerOptions,
|
|
new InvertedIndexBuilderOptions { BundleDocuments = false });
|
|
|
|
Assert.Throws<ArgumentException>(() => InvertedIndexLoader.Load(compressed));
|
|
}
|
|
}
|
|
|
|
public sealed class Search_FilterDocumentOption_ExcludesFilteredDocumentsTest : NeedleTestBase
|
|
{
|
|
private static readonly string[] TestDocuments =
|
|
[
|
|
"ミーティア",
|
|
"エンドマークに希望と涙を添えて",
|
|
"宵の鳥",
|
|
"僕の和風本当上手",
|
|
];
|
|
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(TestDocuments, TokenizerOptions);
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed);
|
|
|
|
// Search without filter - should find "宵の鳥" (documentId 2)
|
|
var resultsWithoutFilter = InvertedIndexSearcher.Search(invertedIndex, "yoi");
|
|
Assert.Contains("宵の鳥", resultsWithoutFilter.Select(r => r.DocumentText));
|
|
|
|
// Search with filter excluding documentId 2
|
|
var resultsWithFilter = InvertedIndexSearcher.Search(invertedIndex, "yoi", new InvertedIndexSearcherOptions
|
|
{
|
|
FilterDocument = id => id != 2
|
|
});
|
|
Assert.DoesNotContain("宵の鳥", resultsWithFilter.Select(r => r.DocumentText));
|
|
}
|
|
}
|
|
|
|
public sealed class Search_NextComparerOption_UsesCustomComparerTest : NeedleTestBase
|
|
{
|
|
[Fact]
|
|
public void Execute()
|
|
{
|
|
// Create documents that would have similar match scores
|
|
var similarDocs = new[] { "テストA", "テストB", "テストC" };
|
|
var compressed = InvertedIndexBuilder.BuildInvertedIndex(similarDocs, TokenizerOptions);
|
|
var invertedIndex = InvertedIndexLoader.Load(compressed);
|
|
|
|
// Search with reverse order comparer
|
|
var results = InvertedIndexSearcher.Search(invertedIndex, "テスト", new InvertedIndexSearcherOptions
|
|
{
|
|
NextComparer = (a, b) => b - a // Reverse by documentId
|
|
});
|
|
|
|
// Should be in reverse documentId order (2, 1, 0) when other criteria equal
|
|
Assert.Equal([2, 1, 0], results.Select(r => r.DocumentId).ToArray());
|
|
}
|
|
}
|
|
|