Initialize CBDD solution and add a .NET-focused gitignore for generated artifacts.
This commit is contained in:
177
tests/CBDD.Tests/QueryPrimitivesTests.cs
Executable file
177
tests/CBDD.Tests/QueryPrimitivesTests.cs
Executable file
@@ -0,0 +1,177 @@
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equal_ShouldReturnEmpty_WhenNotFound()
|
||||
{
|
||||
var key = IndexKey.Create(25);
|
||||
var result = _index.Equal(key, 0).ToList();
|
||||
|
||||
result.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
[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"));
|
||||
}
|
||||
|
||||
[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.
|
||||
}
|
||||
|
||||
[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"));
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_storage.Dispose();
|
||||
File.Delete(_testFile);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user