using ZB.MOM.WW.CBDD.Core; using ZB.MOM.WW.CBDD.Core.Storage; using ZB.MOM.WW.CBDD.Core.Collections; using ZB.MOM.WW.CBDD.Core.Indexing; using ZB.MOM.WW.CBDD.Bson; using Xunit; using System; using System.IO; using System.Linq; using System.Collections.Generic; using ZB.MOM.WW.CBDD.Shared; namespace ZB.MOM.WW.CBDD.Tests { public class ScanTests : IDisposable { private readonly string _testFile; private readonly Shared.TestDbContext _db; public ScanTests() { _testFile = Path.Combine(Path.GetTempPath(), $"scan_tests_{Guid.NewGuid()}.db"); if (File.Exists(_testFile)) File.Delete(_testFile); var wal = Path.ChangeExtension(_testFile, ".wal"); if (File.Exists(wal)) File.Delete(wal); _db = new Shared.TestDbContext(_testFile); } public void Dispose() { _db.Dispose(); if (File.Exists(_testFile)) File.Delete(_testFile); var wal = Path.ChangeExtension(_testFile, ".wal"); if (File.Exists(wal)) File.Delete(wal); } [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"); } [Fact] public void Repro_Insert_Loop_Hang() { // Reproduce hang reported by user at 501 documents int count = 600; for (int i = 0; i < count; i++) { _db.Users.Insert(new User { Name = $"User_{i}", Age = i }); } _db.SaveChanges(); } [Fact] public void ParallelScan_FindsMatchingDocuments() { // Arrange int count = 1000; for (int 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, degreeOfParallelism: 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 var name = reader.ReadElementHeader(); if (name == "age") { return reader.ReadInt32(); } else { reader.SkipValue(type); } } } catch { return -1; } return -1; } } }