Files
CBDD/tests/CBDD.Tests/DictionaryPersistenceTests.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

169 lines
5.9 KiB
C#
Executable File

using ZB.MOM.WW.CBDD.Bson;
using ZB.MOM.WW.CBDD.Core.Collections;
using ZB.MOM.WW.CBDD.Core.Storage;
using Xunit;
using System.Collections.Generic;
using System.Linq;
using ZB.MOM.WW.CBDD.Bson.Schema;
namespace ZB.MOM.WW.CBDD.Tests;
public class DictionaryPersistenceTests : IDisposable
{
private readonly string _dbPath;
private readonly StorageEngine _storage;
/// <summary>
/// Initializes a new instance of the <see cref="DictionaryPersistenceTests"/> class.
/// </summary>
public DictionaryPersistenceTests()
{
_dbPath = Path.Combine(Path.GetTempPath(), $"cbdd_dict_{Guid.NewGuid():N}.db");
_storage = new StorageEngine(_dbPath, PageFileConfig.Default);
}
/// <summary>
/// Disposes test resources and removes temporary files.
/// </summary>
public void Dispose()
{
_storage.Dispose();
if (File.Exists(_dbPath)) File.Delete(_dbPath);
var walPath = Path.ChangeExtension(_dbPath, ".wal");
if (File.Exists(walPath)) File.Delete(walPath);
}
private class MockMapper : DocumentMapperBase<ObjectId, Dictionary<string, object>>
{
private readonly string _collectionName;
private readonly List<string> _keys;
/// <summary>
/// Initializes a new instance of the <see cref="MockMapper"/> class.
/// </summary>
/// <param name="name">The collection name.</param>
/// <param name="keys">The mapper keys.</param>
public MockMapper(string name, params string[] keys)
{
_collectionName = name;
_keys = keys.ToList();
}
/// <inheritdoc />
public override string CollectionName => _collectionName;
/// <inheritdoc />
public override IEnumerable<string> UsedKeys => _keys;
/// <inheritdoc />
public override BsonSchema GetSchema() => new BsonSchema { Title = _collectionName };
/// <inheritdoc />
public override ObjectId GetId(Dictionary<string, object> entity) => throw new NotImplementedException();
/// <inheritdoc />
public override void SetId(Dictionary<string, object> entity, ObjectId id) => throw new NotImplementedException();
/// <inheritdoc />
public override int Serialize(Dictionary<string, object> entity, BsonSpanWriter writer) => throw new NotImplementedException();
/// <inheritdoc />
public override Dictionary<string, object> Deserialize(BsonSpanReader reader) => throw new NotImplementedException();
}
/// <summary>
/// Verifies mapper registration adds all unique dictionary keys.
/// </summary>
[Fact]
public void RegisterMappers_Registers_All_Unique_Keys()
{
var mapper1 = new MockMapper("Coll1", "Name", "Age");
var mapper2 = new MockMapper("Coll2", "Name", "Address", "City");
_storage.RegisterMappers(new IDocumentMapper[] { mapper1, mapper2 });
// Verify keys in cache
_storage.GetOrAddDictionaryEntry("Name").ShouldNotBe((ushort)0);
_storage.GetOrAddDictionaryEntry("Age").ShouldNotBe((ushort)0);
_storage.GetOrAddDictionaryEntry("Address").ShouldNotBe((ushort)0);
_storage.GetOrAddDictionaryEntry("City").ShouldNotBe((ushort)0);
// Verify they have unique IDs (at least 4 unique IDs for 4 unique keys + internal ones)
var ids = new HashSet<ushort>
{
_storage.GetOrAddDictionaryEntry("Name"),
_storage.GetOrAddDictionaryEntry("Age"),
_storage.GetOrAddDictionaryEntry("Address"),
_storage.GetOrAddDictionaryEntry("City")
};
ids.Count.ShouldBe(4);
}
/// <summary>
/// Verifies dictionary keys persist across storage restarts.
/// </summary>
[Fact]
public void Dictionary_Keys_Persist_Across_Restarts()
{
var mapper = new MockMapper("Coll1", "PersistedKey");
_storage.RegisterMappers(new IDocumentMapper[] { mapper });
var originalId = _storage.GetOrAddDictionaryEntry("PersistedKey");
originalId.ShouldNotBe((ushort)0);
_storage.Dispose();
// Re-open
using var storage2 = new StorageEngine(_dbPath, PageFileConfig.Default);
var recoveredId = storage2.GetOrAddDictionaryEntry("PersistedKey");
recoveredId.ShouldBe(originalId);
}
private class NestedMockMapper : DocumentMapperBase<ObjectId, object>
{
/// <inheritdoc />
public override string CollectionName => "Nested";
/// <inheritdoc />
public override BsonSchema GetSchema()
{
var schema = new BsonSchema { Title = "Nested" };
schema.Fields.Add(new BsonField
{
Name = "Top",
Type = BsonType.Document,
NestedSchema = new BsonSchema
{
Fields = { new BsonField { Name = "Child", Type = BsonType.String } }
}
});
return schema;
}
/// <inheritdoc />
public override ObjectId GetId(object entity) => throw new NotImplementedException();
/// <inheritdoc />
public override void SetId(object entity, ObjectId id) => throw new NotImplementedException();
/// <inheritdoc />
public override int Serialize(object entity, BsonSpanWriter writer) => throw new NotImplementedException();
/// <inheritdoc />
public override object Deserialize(BsonSpanReader reader) => throw new NotImplementedException();
}
/// <summary>
/// Verifies nested schema fields are registered as dictionary keys.
/// </summary>
[Fact]
public void RegisterMappers_Handles_Nested_Keys()
{
var mapper = new NestedMockMapper();
_storage.RegisterMappers(new IDocumentMapper[] { mapper });
_storage.GetOrAddDictionaryEntry("Top").ShouldNotBe((ushort)0);
_storage.GetOrAddDictionaryEntry("Child").ShouldNotBe((ushort)0);
}
}