Files
CBDD/tests/CBDD.Tests/QueryPrimitivesTests.cs
Joseph Doherty 3ffd468c79
All checks were successful
NuGet Publish / build-and-pack (push) Successful in 45s
NuGet Publish / publish-to-gitea (push) Successful in 52s
Fix audit findings for coverage, architecture checks, and XML docs
2026-02-20 15:43:25 -05:00

214 lines
6.1 KiB
C#
Executable File

using ZB.MOM.WW.CBDD.Core.Storage;
using ZB.MOM.WW.CBDD.Core.Indexing;
using ZB.MOM.WW.CBDD.Bson;
using Xunit;
namespace ZB.MOM.WW.CBDD.Tests;
public class QueryPrimitivesTests : IDisposable
{
private readonly string _testFile;
private readonly StorageEngine _storage;
private readonly BTreeIndex _index;
/// <summary>
/// Initializes a new instance of the <see cref="QueryPrimitivesTests"/> class.
/// </summary>
public QueryPrimitivesTests()
{
_testFile = Path.Combine(Path.GetTempPath(), $"docdb_test_{Guid.NewGuid()}.db");
_storage = new StorageEngine(_testFile, PageFileConfig.Default);
// Initialize simple index
var options = IndexOptions.CreateBTree("test");
_index = new BTreeIndex(_storage, options);
SeedData();
}
private void SeedData()
{
// Insert keys: 10, 20, 30, 40, 50
// And strings: "A", "AB", "ABC", "B", "C"
var txnId = _storage.BeginTransaction().TransactionId;
Insert(10, txnId);
Insert(20, txnId);
Insert(30, txnId);
Insert(40, txnId);
Insert(50, txnId);
Insert("A", txnId);
Insert("AB", txnId);
Insert("ABC", txnId);
Insert("B", txnId);
Insert("C", txnId);
_storage.CommitTransaction(txnId);
}
private void Insert(dynamic value, ulong txnId)
{
IndexKey key;
if (value is int i) key = IndexKey.Create(i);
else if (value is string s) key = IndexKey.Create(s);
else throw new ArgumentException();
_index.Insert(key, new DocumentLocation(1, 1), txnId);
}
/// <summary>
/// Executes Equal_ShouldFindExactMatch.
/// </summary>
[Fact]
public void Equal_ShouldFindExactMatch()
{
var key = IndexKey.Create(30);
var result = _index.Equal(key, 0).ToList();
result.Count().ShouldBe(1);
result[0].Key.ShouldBe(key);
}
/// <summary>
/// Executes Equal_ShouldReturnEmpty_WhenNotFound.
/// </summary>
[Fact]
public void Equal_ShouldReturnEmpty_WhenNotFound()
{
var key = IndexKey.Create(25);
var result = _index.Equal(key, 0).ToList();
result.ShouldBeEmpty();
}
/// <summary>
/// Executes GreaterThan_ShouldReturnMatches.
/// </summary>
[Fact]
public void GreaterThan_ShouldReturnMatches()
{
var key = IndexKey.Create(30);
var result = _index.GreaterThan(key, orEqual: false, 0).ToList();
(result.Count >= 2).ShouldBeTrue();
result[0].Key.ShouldBe(IndexKey.Create(40));
result[1].Key.ShouldBe(IndexKey.Create(50));
}
/// <summary>
/// Executes GreaterThanOrEqual_ShouldReturnMatches.
/// </summary>
[Fact]
public void GreaterThanOrEqual_ShouldReturnMatches()
{
var key = IndexKey.Create(30);
var result = _index.GreaterThan(key, orEqual: true, 0).ToList();
(result.Count >= 3).ShouldBeTrue();
result[0].Key.ShouldBe(IndexKey.Create(30));
result[1].Key.ShouldBe(IndexKey.Create(40));
result[2].Key.ShouldBe(IndexKey.Create(50));
}
/// <summary>
/// Executes LessThan_ShouldReturnMatches.
/// </summary>
[Fact]
public void LessThan_ShouldReturnMatches()
{
var key = IndexKey.Create(30);
var result = _index.LessThan(key, orEqual: false, 0).ToList();
result.Count.ShouldBe(2); // 20, 10 (Order is backward?)
// LessThan yields backward?
// Implementation: MovePrev(). So yes, 20 then 10.
result[0].Key.ShouldBe(IndexKey.Create(20));
result[1].Key.ShouldBe(IndexKey.Create(10));
}
/// <summary>
/// Executes Between_ShouldReturnRange.
/// </summary>
[Fact]
public void Between_ShouldReturnRange()
{
var start = IndexKey.Create(20);
var end = IndexKey.Create(40);
var result = _index.Between(start, end, startInclusive: true, endInclusive: true, 0).ToList();
result.Count.ShouldBe(3); // 20, 30, 40
result[0].Key.ShouldBe(IndexKey.Create(20));
result[1].Key.ShouldBe(IndexKey.Create(30));
result[2].Key.ShouldBe(IndexKey.Create(40));
}
/// <summary>
/// Executes StartsWith_ShouldReturnPrefixMatches.
/// </summary>
[Fact]
public void StartsWith_ShouldReturnPrefixMatches()
{
var result = _index.StartsWith("AB", 0).ToList();
result.Count.ShouldBe(2); // AB, ABC
result[0].Key.ShouldBe(IndexKey.Create("AB"));
result[1].Key.ShouldBe(IndexKey.Create("ABC"));
}
/// <summary>
/// Executes Like_ShouldSupportWildcards.
/// </summary>
[Fact]
public void Like_ShouldSupportWildcards()
{
// "A%" -> A, AB, ABC
var result = _index.Like("A%", 0).ToList();
result.Count.ShouldBe(3);
// "%B%" -> AB, ABC, B
var result2 = _index.Like("%B%", 0).ToList();
// A (no), AB (yes), ABC (yes), B (yes), C (no)
result2.Count.ShouldBe(3); // AB, ABC, B. Wait, order?
// Index order: A, AB, ABC, B, C.
// AB ok. ABC ok. B ok.
}
/// <summary>
/// Executes Like_Underscore_ShouldMatchSingleChar.
/// </summary>
[Fact]
public void Like_Underscore_ShouldMatchSingleChar()
{
// "_B" -> AB (yes), B (no: len 1), ABC (no)
var result = _index.Like("_B", 0).ToList();
result.Count().ShouldBe(1);
result[0].Key.ShouldBe(IndexKey.Create("AB"));
}
/// <summary>
/// Executes In_ShouldReturnSpecificKeys.
/// </summary>
[Fact]
public void In_ShouldReturnSpecificKeys()
{
var keys = new[] { IndexKey.Create(10), IndexKey.Create(30), IndexKey.Create(50), IndexKey.Create(99) };
var result = _index.In(keys, 0).ToList();
result.Count.ShouldBe(3); // 10, 30, 50. (99 missing)
result[0].Key.ShouldBe(IndexKey.Create(10));
result[1].Key.ShouldBe(IndexKey.Create(30));
result[2].Key.ShouldBe(IndexKey.Create(50));
}
/// <summary>
/// Executes Dispose.
/// </summary>
public void Dispose()
{
_storage.Dispose();
File.Delete(_testFile);
}
}