using ZB.MOM.WW.CBDD.Bson; using ZB.MOM.WW.CBDD.Bson.IO; using ZB.MOM.WW.CBDD.Shared; namespace ZB.MOM.WW.CBDD.Tests; public class ScanTests : IDisposable { private readonly TestDbContext _db; private readonly string _testFile; /// /// Initializes a new instance of the class. /// public ScanTests() { _testFile = Path.Combine(Path.GetTempPath(), $"scan_tests_{Guid.NewGuid()}.db"); if (File.Exists(_testFile)) File.Delete(_testFile); string wal = Path.ChangeExtension(_testFile, ".wal"); if (File.Exists(wal)) File.Delete(wal); _db = new TestDbContext(_testFile); } /// /// Executes Dispose. /// public void Dispose() { _db.Dispose(); if (File.Exists(_testFile)) File.Delete(_testFile); string wal = Path.ChangeExtension(_testFile, ".wal"); if (File.Exists(wal)) File.Delete(wal); } /// /// Executes Scan_FindsMatchingDocuments. /// [Fact] public void Scan_FindsMatchingDocuments() { // Arrange _db.Users.Insert(new User { Name = "Alice", Age = 30 }); _db.Users.Insert(new User { Name = "Bob", Age = 25 }); _db.Users.Insert(new User { Name = "Charlie", Age = 35 }); _db.SaveChanges(); // Act: Find users older than 28 var results = _db.Users.Scan(reader => ParseAge(reader) > 28).ToList(); // Assert results.Count.ShouldBe(2); results.ShouldContain(d => d.Name == "Alice"); results.ShouldContain(d => d.Name == "Charlie"); } /// /// Executes Repro_Insert_Loop_Hang. /// [Fact] public void Repro_Insert_Loop_Hang() { // Reproduce hang reported by user at 501 documents var count = 600; for (var i = 0; i < count; i++) _db.Users.Insert(new User { Name = $"User_{i}", Age = i }); _db.SaveChanges(); } /// /// Executes ParallelScan_FindsMatchingDocuments. /// [Fact] public void ParallelScan_FindsMatchingDocuments() { // Arrange var count = 1000; for (var i = 0; i < count; i++) _db.Users.Insert(new User { Name = $"User_{i}", Age = i }); _db.SaveChanges(); // Act: Find users with Age >= 500 // Parallelism 2 to force partitioning var results = _db.Users.ParallelScan(reader => ParseAge(reader) >= 500, 2).ToList(); // Assert results.Count.ShouldBe(500); } private int ParseAge(BsonSpanReader reader) { try { reader.ReadDocumentSize(); while (reader.Remaining > 0) { var type = reader.ReadBsonType(); if (type == 0) break; // End of doc string name = reader.ReadElementHeader(); if (name == "age") return reader.ReadInt32(); reader.SkipValue(type); } } catch { return -1; } return -1; } }