280 lines
8.4 KiB
C#
Executable File
280 lines
8.4 KiB
C#
Executable File
using ZB.MOM.WW.CBDD.Bson;
|
|
using Xunit;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace ZB.MOM.WW.CBDD.Tests;
|
|
|
|
public class BsonSpanReaderWriterTests
|
|
{
|
|
private readonly ConcurrentDictionary<string, ushort> _keyMap = new(StringComparer.OrdinalIgnoreCase);
|
|
private readonly ConcurrentDictionary<ushort, string> _keys = new();
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BsonSpanReaderWriterTests"/> class.
|
|
/// </summary>
|
|
public BsonSpanReaderWriterTests()
|
|
{
|
|
ushort id = 1;
|
|
string[] initialKeys = ["name", "age", "active", "_id", "val", "dec", "timestamp", "int32", "int64", "double", "data", "child", "value", "0", "1"];
|
|
foreach (var key in initialKeys)
|
|
{
|
|
_keyMap[key] = id;
|
|
_keys[id] = key;
|
|
id++;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read simple document.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_SimpleDocument()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
var sizePos = writer.BeginDocument();
|
|
writer.WriteString("name", "John");
|
|
writer.WriteInt32("age", 30);
|
|
writer.WriteBoolean("active", true);
|
|
writer.EndDocument(sizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
var size = reader.ReadDocumentSize();
|
|
|
|
size.ShouldBe(writer.Position);
|
|
|
|
var type1 = reader.ReadBsonType();
|
|
var name1 = reader.ReadElementHeader();
|
|
var value1 = reader.ReadString();
|
|
|
|
type1.ShouldBe(BsonType.String);
|
|
name1.ShouldBe("name");
|
|
value1.ShouldBe("John");
|
|
|
|
var type2 = reader.ReadBsonType();
|
|
var name2 = reader.ReadElementHeader();
|
|
var value2 = reader.ReadInt32();
|
|
|
|
type2.ShouldBe(BsonType.Int32);
|
|
name2.ShouldBe("age");
|
|
value2.ShouldBe(30);
|
|
|
|
var type3 = reader.ReadBsonType();
|
|
var name3 = reader.ReadElementHeader();
|
|
var value3 = reader.ReadBoolean();
|
|
|
|
type3.ShouldBe(BsonType.Boolean);
|
|
name3.ShouldBe("active");
|
|
value3.ShouldBeTrue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read object id.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_ObjectId()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
var oid = ObjectId.NewObjectId();
|
|
|
|
var sizePos = writer.BeginDocument();
|
|
writer.WriteObjectId("_id", oid);
|
|
writer.EndDocument(sizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
|
|
reader.ReadDocumentSize();
|
|
var type = reader.ReadBsonType();
|
|
var name = reader.ReadElementHeader();
|
|
var readOid = reader.ReadObjectId();
|
|
|
|
type.ShouldBe(BsonType.ObjectId);
|
|
name.ShouldBe("_id");
|
|
readOid.ShouldBe(oid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests read write double.
|
|
/// </summary>
|
|
[Fact]
|
|
public void ReadWrite_Double()
|
|
{
|
|
var buffer = new byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
writer.WriteDouble("val", 123.456);
|
|
|
|
var reader = new BsonSpanReader(buffer, _keys);
|
|
var type = reader.ReadBsonType();
|
|
var name = reader.ReadElementHeader();
|
|
var val = reader.ReadDouble();
|
|
|
|
type.ShouldBe(BsonType.Double);
|
|
name.ShouldBe("val");
|
|
val.ShouldBe(123.456);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests read write decimal128 round trip.
|
|
/// </summary>
|
|
[Fact]
|
|
public void ReadWrite_Decimal128_RoundTrip()
|
|
{
|
|
var buffer = new byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
decimal original = 123456.789m;
|
|
writer.WriteDecimal128("dec", original);
|
|
|
|
var reader = new BsonSpanReader(buffer, _keys);
|
|
var type = reader.ReadBsonType();
|
|
var name = reader.ReadElementHeader();
|
|
var val = reader.ReadDecimal128();
|
|
|
|
type.ShouldBe(BsonType.Decimal128);
|
|
name.ShouldBe("dec");
|
|
val.ShouldBe(original);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read date time.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_DateTime()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
var now = DateTime.UtcNow;
|
|
// Round to milliseconds as BSON only stores millisecond precision
|
|
var expectedTime = new DateTime(now.Year, now.Month, now.Day,
|
|
now.Hour, now.Minute, now.Second, now.Millisecond, DateTimeKind.Utc);
|
|
|
|
var sizePos = writer.BeginDocument();
|
|
writer.WriteDateTime("timestamp", expectedTime);
|
|
writer.EndDocument(sizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
|
|
reader.ReadDocumentSize();
|
|
var type = reader.ReadBsonType();
|
|
var name = reader.ReadElementHeader();
|
|
var readTime = reader.ReadDateTime();
|
|
|
|
type.ShouldBe(BsonType.DateTime);
|
|
name.ShouldBe("timestamp");
|
|
readTime.ShouldBe(expectedTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read numeric types.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_NumericTypes()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
var sizePos = writer.BeginDocument();
|
|
writer.WriteInt32("int32", int.MaxValue);
|
|
writer.WriteInt64("int64", long.MaxValue);
|
|
writer.WriteDouble("double", 3.14159);
|
|
writer.EndDocument(sizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
|
|
reader.ReadDocumentSize();
|
|
|
|
reader.ReadBsonType();
|
|
reader.ReadElementHeader();
|
|
reader.ReadInt32().ShouldBe(int.MaxValue);
|
|
|
|
reader.ReadBsonType();
|
|
reader.ReadElementHeader();
|
|
reader.ReadInt64().ShouldBe(long.MaxValue);
|
|
|
|
reader.ReadBsonType();
|
|
reader.ReadElementHeader();
|
|
Math.Round(reader.ReadDouble(), 5).ShouldBe(Math.Round(3.14159, 5));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read binary.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_Binary()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[256];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
byte[] testData = [1, 2, 3, 4, 5];
|
|
|
|
var sizePos = writer.BeginDocument();
|
|
writer.WriteBinary("data", testData);
|
|
writer.EndDocument(sizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
|
|
reader.ReadDocumentSize();
|
|
var type = reader.ReadBsonType();
|
|
var name = reader.ReadElementHeader();
|
|
var readData = reader.ReadBinary(out var subtype);
|
|
|
|
type.ShouldBe(BsonType.Binary);
|
|
name.ShouldBe("data");
|
|
subtype.ShouldBe((byte)0);
|
|
testData.AsSpan().SequenceEqual(readData).ShouldBeTrue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests write and read nested document.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteAndRead_NestedDocument()
|
|
{
|
|
Span<byte> buffer = stackalloc byte[512];
|
|
var writer = new BsonSpanWriter(buffer, _keyMap);
|
|
|
|
var rootSizePos = writer.BeginDocument();
|
|
writer.WriteString("name", "Parent");
|
|
|
|
var childSizePos = writer.BeginDocument("child");
|
|
writer.WriteString("name", "Child");
|
|
writer.WriteInt32("value", 42);
|
|
writer.EndDocument(childSizePos);
|
|
|
|
writer.EndDocument(rootSizePos);
|
|
|
|
var documentBytes = buffer[..writer.Position];
|
|
var reader = new BsonSpanReader(documentBytes, _keys);
|
|
var rootSize = reader.ReadDocumentSize();
|
|
|
|
rootSize.ShouldBe(writer.Position);
|
|
|
|
reader.ReadBsonType(); // String
|
|
reader.ReadElementHeader().ShouldBe("name");
|
|
reader.ReadString().ShouldBe("Parent");
|
|
|
|
reader.ReadBsonType(); // Document
|
|
reader.ReadElementHeader().ShouldBe("child");
|
|
|
|
reader.ReadDocumentSize();
|
|
reader.ReadBsonType(); // String
|
|
reader.ReadElementHeader().ShouldBe("name");
|
|
reader.ReadString().ShouldBe("Child");
|
|
|
|
reader.ReadBsonType(); // Int32
|
|
reader.ReadElementHeader().ShouldBe("value");
|
|
reader.ReadInt32().ShouldBe(42);
|
|
}
|
|
}
|