1662 lines
70 KiB
C#
1662 lines
70 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using EpicGames.Core;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
|
|
namespace EpicGames.Serialization.Tests
|
|
{
|
|
[TestClass]
|
|
public class EngineTests
|
|
{
|
|
class CbFieldAccessors(object defaultValue, Func<CbField, bool> isType, Func<CbField, object> asType, Func<CbField, object, object> asTypeWithDefault)
|
|
{
|
|
public object _defaultValue = defaultValue;
|
|
public Func<CbField, bool> _isType = isType;
|
|
public Func<CbField, object> _asType = asType;
|
|
public Func<CbField, object, object> _asTypeWithDefault = asTypeWithDefault;
|
|
public Func<object, object, bool> _comparer = (x, y) => x.Equals(y);
|
|
|
|
public static CbFieldAccessors FromStruct<T>(Func<CbField, bool> isType, Func<CbField, T, object> asTypeWithDefault) where T : struct
|
|
{
|
|
return new CbFieldAccessors(new T(), isType, x => asTypeWithDefault(x, new T()), (x, y) => asTypeWithDefault(x, (T)y));
|
|
}
|
|
|
|
public static CbFieldAccessors FromStruct<T>(T @default, Func<CbField, bool> isType, Func<CbField, T, object> asTypeWithDefault) where T : struct
|
|
{
|
|
return new CbFieldAccessors(@default, isType, x => asTypeWithDefault(x, new T()), (x, y) => asTypeWithDefault(x, (T)y));
|
|
}
|
|
|
|
public static CbFieldAccessors FromStruct<T>(Func<CbField, bool> isType, Func<CbField, T, object> asTypeWithDefault, Func<T, T, bool> comparer) where T : struct
|
|
{
|
|
return new CbFieldAccessors(new T(), isType, x => asTypeWithDefault(x, new T()), (x, y) => asTypeWithDefault(x, (T)y)) { _comparer = (x, y) => comparer((T)x, (T)y) };
|
|
}
|
|
}
|
|
|
|
readonly Dictionary<CbFieldType, CbFieldAccessors> _typeAccessors = new Dictionary<CbFieldType, CbFieldAccessors>
|
|
{
|
|
[CbFieldType.Object] = new CbFieldAccessors(CbObject.Empty, x => x.IsObject(), x => x.AsObject(), (x, y) => x.AsObject()),
|
|
[CbFieldType.UniformObject] = new CbFieldAccessors(CbObject.Empty, x => x.IsObject(), x => x.AsObject(), (x, y) => x.AsObject()),
|
|
[CbFieldType.Array] = new CbFieldAccessors(CbArray.Empty, x => x.IsArray(), x => x.AsArray(), (x, y) => x.AsArray()),
|
|
[CbFieldType.UniformArray] = new CbFieldAccessors(CbArray.Empty, x => x.IsArray(), x => x.AsArray(), (x, y) => x.AsArray()),
|
|
[CbFieldType.Binary] = CbFieldAccessors.FromStruct<ReadOnlyMemory<byte>>(x => x.IsBinary(), (x, y) => x.AsBinary(y), (x, y) => x.Span.SequenceEqual(y.Span)),
|
|
[CbFieldType.String] = new CbFieldAccessors(Utf8String.Empty, x => x.IsString(), x => x.AsUtf8String(), (x, @default) => x.AsUtf8String((Utf8String)@default)),
|
|
[CbFieldType.IntegerPositive] = CbFieldAccessors.FromStruct<ulong>(x => x.IsInteger(), (x, y) => x.AsUInt64(y)),
|
|
[CbFieldType.IntegerNegative] = CbFieldAccessors.FromStruct<long>(x => x.IsInteger(), (x, y) => x.AsInt64(y)),
|
|
[CbFieldType.Float32] = CbFieldAccessors.FromStruct<float>(x => x.IsFloat(), (x, y) => x.AsFloat(y)),
|
|
[CbFieldType.Float64] = CbFieldAccessors.FromStruct<double>(x => x.IsFloat(), (x, y) => x.AsDouble(y)),
|
|
[CbFieldType.BoolTrue] = CbFieldAccessors.FromStruct<bool>(x => x.IsBool(), (x, y) => x.AsBool(y)),
|
|
[CbFieldType.BoolFalse] = CbFieldAccessors.FromStruct<bool>(x => x.IsBool(), (x, y) => x.AsBool(y)),
|
|
[CbFieldType.ObjectAttachment] = new CbFieldAccessors(new CbObjectAttachment(IoHash.Zero), x => x.IsObjectAttachment(), x => x.AsObjectAttachment(), (x, @default) => x.AsObjectAttachment((CbObjectAttachment)@default)),
|
|
[CbFieldType.BinaryAttachment] = new CbFieldAccessors(new CbBinaryAttachment(IoHash.Zero), x => x.IsBinaryAttachment(), x => x.AsBinaryAttachment(), (x, @default) => x.AsBinaryAttachment((CbBinaryAttachment)@default)),
|
|
[CbFieldType.Hash] = new CbFieldAccessors(IoHash.Zero, x => x.IsHash(), x => x.AsHash(), (x, @default) => x.AsHash((IoHash)@default)),
|
|
[CbFieldType.Uuid] = CbFieldAccessors.FromStruct<Guid>(x => x.IsUuid(), (x, y) => x.AsUuid(y)),
|
|
[CbFieldType.DateTime] = CbFieldAccessors.FromStruct<DateTime>(new DateTime(0, DateTimeKind.Utc), x => x.IsDateTime(), (x, y) => x.AsDateTime(y)),
|
|
[CbFieldType.TimeSpan] = CbFieldAccessors.FromStruct<TimeSpan>(x => x.IsTimeSpan(), (x, y) => x.AsTimeSpan(y)),
|
|
};
|
|
|
|
void TestField(CbFieldType fieldType, CbField field, object? expectedValue = null, object? defaultValue = null, CbFieldError expectedError = CbFieldError.None, CbFieldAccessors? accessors = null)
|
|
{
|
|
accessors ??= _typeAccessors[fieldType];
|
|
expectedValue ??= accessors._defaultValue;
|
|
defaultValue ??= accessors._defaultValue;
|
|
|
|
Assert.AreEqual(accessors._isType(field), expectedError != CbFieldError.TypeError);
|
|
if (expectedError == CbFieldError.None && !field.IsBool())
|
|
{
|
|
Assert.IsFalse(field.AsBool());
|
|
Assert.IsTrue(field.HasError());
|
|
Assert.AreEqual(field.GetError(), CbFieldError.TypeError);
|
|
}
|
|
|
|
object value = accessors._asTypeWithDefault(field, defaultValue);
|
|
Assert.IsTrue(accessors._comparer(accessors._asTypeWithDefault(field, defaultValue), expectedValue));
|
|
Assert.AreEqual(field.HasError(), expectedError != CbFieldError.None);
|
|
Assert.AreEqual(field.GetError(), expectedError);
|
|
}
|
|
|
|
void TestField(CbFieldType fieldType, byte[] payload, object? expectedValue = null, object? defaultValue = null, CbFieldError expectedError = CbFieldError.None, CbFieldAccessors? accessors = null)
|
|
{
|
|
CbField field = new CbField(payload, fieldType);
|
|
Assert.AreEqual(field.GetSize(), payload.Length + (CbFieldUtils.HasFieldType(fieldType) ? 0 : 1));
|
|
Assert.IsTrue(field.HasValue());
|
|
Assert.IsFalse(field.HasError());
|
|
Assert.AreEqual(field.GetError(), CbFieldError.None);
|
|
TestField(fieldType, field, expectedValue, defaultValue, expectedError, accessors);
|
|
}
|
|
|
|
void TestFieldError(CbFieldType fieldType, CbField field, CbFieldError expectedError, object? expectedValue = null, CbFieldAccessors? accessors = null)
|
|
{
|
|
TestField(fieldType, field, expectedValue, expectedValue, expectedError, accessors);
|
|
}
|
|
|
|
void TestFieldError(CbFieldType fieldType, ReadOnlyMemory<byte> payload, CbFieldError expectedError, object? expectedValue = null, CbFieldAccessors? accessors = null)
|
|
{
|
|
CbField field = new CbField(payload, fieldType);
|
|
TestFieldError(fieldType, field, expectedError, expectedValue, accessors);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldNoneTest()
|
|
{
|
|
// Test CbField()
|
|
{
|
|
CbField defaultField = new CbField();
|
|
Assert.IsFalse(defaultField.HasName());
|
|
Assert.IsFalse(defaultField.HasValue());
|
|
Assert.IsFalse(defaultField.HasError());
|
|
Assert.IsTrue(defaultField.GetError() == CbFieldError.None);
|
|
Assert.AreEqual(defaultField.GetSize(), 1);
|
|
Assert.AreEqual(defaultField.GetName().Length, 0);
|
|
Assert.IsFalse(defaultField.HasName());
|
|
Assert.IsFalse(defaultField.HasValue());
|
|
Assert.IsFalse(defaultField.HasError());
|
|
Assert.AreEqual(defaultField.GetError(), CbFieldError.None);
|
|
Assert.AreEqual(defaultField.GetHash(), Blake3Hash.Compute([(byte)CbFieldType.None]));
|
|
Assert.IsFalse(defaultField.TryGetView(out _));
|
|
}
|
|
|
|
// Test CbField(None)
|
|
{
|
|
CbField noneField = new CbField(ReadOnlyMemory<byte>.Empty, CbFieldType.None);
|
|
Assert.AreEqual(noneField.GetSize(), 1);
|
|
Assert.AreEqual(noneField.GetName().Length, 0);
|
|
Assert.IsFalse(noneField.HasName());
|
|
Assert.IsFalse(noneField.HasValue());
|
|
Assert.IsFalse(noneField.HasError());
|
|
Assert.AreEqual(noneField.GetError(), CbFieldError.None);
|
|
Assert.AreEqual(noneField.GetHash(), new CbField().GetHash());
|
|
Assert.IsFalse(noneField.TryGetView(out _));
|
|
}
|
|
|
|
// Test CbField(None|Type|Name)
|
|
{
|
|
CbFieldType fieldType = CbFieldType.None | CbFieldType.HasFieldName;
|
|
byte[] noneBytes = [(byte)fieldType, 4, (byte)'N', (byte)'a', (byte)'m', (byte)'e'];
|
|
CbField noneField = new CbField(noneBytes);
|
|
Assert.AreEqual(noneField.GetSize(), noneBytes.Length);
|
|
Assert.AreEqual(noneField.GetName(), new Utf8String("Name"));
|
|
Assert.IsTrue(noneField.HasName());
|
|
Assert.IsFalse(noneField.HasValue());
|
|
Assert.AreEqual(noneField.GetHash(), Blake3Hash.Compute(noneBytes));
|
|
ReadOnlyMemory<byte> view;
|
|
Assert.IsTrue(noneField.TryGetView(out view) && view.Span.SequenceEqual(noneBytes));
|
|
|
|
byte[] copyBytes = new byte[noneBytes.Length];
|
|
noneField.CopyTo(copyBytes);
|
|
Assert.IsTrue(noneBytes.AsSpan().SequenceEqual(copyBytes));
|
|
}
|
|
|
|
// Test CbField(None|Type)
|
|
{
|
|
CbFieldType fieldType = CbFieldType.None;
|
|
byte[] noneBytes = [(byte)fieldType];
|
|
CbField noneField = new CbField(noneBytes);
|
|
Assert.AreEqual(noneField.GetSize(), noneBytes.Length);
|
|
Assert.AreEqual(noneField.GetName().Length, 0);
|
|
Assert.IsFalse(noneField.HasName());
|
|
Assert.IsFalse(noneField.HasValue());
|
|
Assert.AreEqual(noneField.GetHash(), new CbField().GetHash());
|
|
ReadOnlyMemory<byte> view;
|
|
Assert.IsTrue(noneField.TryGetView(out view) && view.Span.SequenceEqual(noneBytes));
|
|
}
|
|
|
|
// Test CbField(None|Name)
|
|
{
|
|
CbFieldType fieldType = CbFieldType.None | CbFieldType.HasFieldName;
|
|
byte[] noneBytes = [(byte)fieldType, 4, (byte)'N', (byte)'a', (byte)'m', (byte)'e'];
|
|
CbField noneField = new CbField(noneBytes.AsMemory(1), fieldType);
|
|
Assert.AreEqual(noneField.GetSize(), noneBytes.Length);
|
|
Assert.AreEqual(noneField.GetName(), new Utf8String("Name"));
|
|
Assert.IsTrue(noneField.HasName());
|
|
Assert.IsFalse(noneField.HasValue());
|
|
Assert.AreEqual(noneField.GetHash(), Blake3Hash.Compute(noneBytes));
|
|
Assert.IsFalse(noneField.TryGetView(out _));
|
|
|
|
byte[] copyBytes = new byte[noneBytes.Length];
|
|
noneField.CopyTo(copyBytes);
|
|
Assert.IsTrue(noneBytes.AsSpan().SequenceEqual(copyBytes));
|
|
}
|
|
|
|
// Test CbField(None|EmptyName)
|
|
{
|
|
CbFieldType fieldType = CbFieldType.None | CbFieldType.HasFieldName;
|
|
byte[] noneBytes = [(byte)fieldType, 0];
|
|
CbField noneField = new CbField(noneBytes.AsMemory(1), fieldType);
|
|
Assert.AreEqual(noneBytes.Length, noneField.GetSize());
|
|
Assert.AreEqual(Utf8String.Empty, noneField.GetName());
|
|
Assert.IsTrue(noneField.HasName());
|
|
Assert.IsFalse(noneField.HasValue());
|
|
Assert.AreEqual(noneField.GetHash(), Blake3Hash.Compute(noneBytes));
|
|
Assert.IsFalse(noneField.TryGetView(out _));
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldNullTest()
|
|
{
|
|
// Test CbField(Null)
|
|
{
|
|
CbField nullField = new CbField(ReadOnlyMemory<byte>.Empty, CbFieldType.Null);
|
|
Assert.AreEqual(nullField.GetSize(), 1);
|
|
Assert.IsTrue(nullField.IsNull());
|
|
Assert.IsTrue(nullField.HasValue());
|
|
Assert.IsFalse(nullField.HasError());
|
|
Assert.AreEqual(nullField.GetError(), CbFieldError.None);
|
|
Assert.AreEqual(nullField.GetHash(), Blake3Hash.Compute([(byte)CbFieldType.Null]));
|
|
}
|
|
|
|
// Test CbField(None) as Null
|
|
{
|
|
CbField field = new CbField();
|
|
Assert.IsFalse(field.IsNull());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldObjectTest()
|
|
{
|
|
static void TestIntObject(CbObject obj, int expectedNum, int expectedPayloadSize)
|
|
{
|
|
Assert.AreEqual(obj.GetSize(), expectedPayloadSize + sizeof(CbFieldType));
|
|
|
|
int actualNum = 0;
|
|
foreach (CbField field in obj)
|
|
{
|
|
++actualNum;
|
|
Assert.AreNotEqual(field.GetName().Length, 0);
|
|
Assert.AreEqual(field.AsInt32(), actualNum);
|
|
}
|
|
Assert.AreEqual(actualNum, expectedNum);
|
|
}
|
|
|
|
// Test CbField(Object, Empty)
|
|
TestField(CbFieldType.Object, new byte[1]);
|
|
|
|
// Test CbField(Object, Empty)
|
|
{
|
|
CbObject obj = CbObject.Empty;
|
|
TestIntObject(obj, 0, 1);
|
|
|
|
// Find fields that do not exist.
|
|
Assert.IsFalse(obj.Find("Field").HasValue());
|
|
Assert.IsFalse(obj.FindIgnoreCase("Field").HasValue());
|
|
Assert.IsFalse(obj["Field"].HasValue());
|
|
|
|
// Advance an iterator past the last field.
|
|
CbFieldIterator it = obj.CreateIterator();
|
|
Assert.IsFalse((bool)it);
|
|
Assert.IsTrue(!it);
|
|
for (int count = 16; count > 0; --count)
|
|
{
|
|
++it;
|
|
it.Current.AsInt32();
|
|
}
|
|
Assert.IsFalse((bool)it);
|
|
Assert.IsTrue(!it);
|
|
}
|
|
|
|
// Test CbField(Object, NotEmpty)
|
|
{
|
|
byte intType = (byte)(CbFieldType.HasFieldName | CbFieldType.IntegerPositive);
|
|
byte[] payload = [12, intType, 1, (byte)'A', 1, intType, 1, (byte)'B', 2, intType, 1, (byte)'C', 3];
|
|
CbField field = new CbField(payload, CbFieldType.Object);
|
|
TestField(CbFieldType.Object, field, new CbObject(payload, CbFieldType.Object));
|
|
CbObject @object = CbObject.Clone(field.AsObject());
|
|
TestIntObject(@object, 3, payload.Length);
|
|
TestIntObject(field.AsObject(), 3, payload.Length);
|
|
Assert.IsTrue(@object.Equals(field.AsObject()));
|
|
Assert.AreEqual(@object.Find("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.Find("b").AsInt32(4), 4);
|
|
Assert.AreEqual(@object.FindIgnoreCase("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.FindIgnoreCase("b").AsInt32(), 2);
|
|
Assert.AreEqual(@object["B"].AsInt32(), 2);
|
|
Assert.AreEqual(@object["b"].AsInt32(4), 4);
|
|
}
|
|
|
|
// Test CbField(UniformObject, NotEmpty)
|
|
{
|
|
byte intType = (byte)(CbFieldType.HasFieldName | CbFieldType.IntegerPositive);
|
|
byte[] payload = [10, intType, 1, (byte)'A', 1, 1, (byte)'B', 2, 1, (byte)'C', 3];
|
|
CbField field = new CbField(payload, CbFieldType.UniformObject);
|
|
TestField(CbFieldType.UniformObject, field, new CbObject(payload, CbFieldType.UniformObject));
|
|
CbObject @object = CbObject.Clone(field.AsObject());
|
|
TestIntObject(@object, 3, payload.Length);
|
|
TestIntObject(field.AsObject(), 3, payload.Length);
|
|
Assert.IsTrue(@object.Equals(field.AsObject()));
|
|
Assert.AreEqual(@object.Find("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.Find("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.Find("b").AsInt32(4), 4);
|
|
Assert.AreEqual(@object.Find("b").AsInt32(4), 4);
|
|
Assert.AreEqual(@object.FindIgnoreCase("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.FindIgnoreCase("B").AsInt32(), 2);
|
|
Assert.AreEqual(@object.FindIgnoreCase("b").AsInt32(), 2);
|
|
Assert.AreEqual(@object.FindIgnoreCase("b").AsInt32(), 2);
|
|
Assert.AreEqual(@object["B"].AsInt32(), 2);
|
|
Assert.AreEqual(@object["b"].AsInt32(4), 4);
|
|
|
|
// Equals
|
|
byte[] namedPayload = [1, (byte)'O', 10, intType, 1, (byte)'A', 1, 1, (byte)'B', 2, 1, (byte)'C', 3];
|
|
CbField namedField = new CbField(namedPayload, CbFieldType.UniformObject | CbFieldType.HasFieldName);
|
|
Assert.IsTrue(field.AsObject().Equals(namedField.AsObject()));
|
|
|
|
// CopyTo
|
|
byte[] copyBytes = new byte[payload.Length + 1];
|
|
field.AsObject().CopyTo(copyBytes);
|
|
Assert.IsTrue(payload.AsSpan().SequenceEqual(copyBytes.AsSpan(1)));
|
|
namedField.AsObject().CopyTo(copyBytes);
|
|
Assert.IsTrue(payload.AsSpan().SequenceEqual(copyBytes.AsSpan(1)));
|
|
|
|
// TryGetView
|
|
Assert.IsFalse(field.AsObject().TryGetView(out _));
|
|
Assert.IsFalse(namedField.AsObject().TryGetView(out _));
|
|
}
|
|
|
|
// Test CbField(None) as Object
|
|
{
|
|
CbField field = CbField.Empty;
|
|
TestFieldError(CbFieldType.Object, field, CbFieldError.TypeError);
|
|
field.AsObject();
|
|
}
|
|
|
|
// Test FCbObjectView(ObjectWithName) and CreateIterator
|
|
{
|
|
byte objectType = (byte)(CbFieldType.Object | CbFieldType.HasFieldName);
|
|
byte[] buffer = [objectType, 3, (byte)'K', (byte)'e', (byte)'y', 4, (byte)(CbFieldType.HasFieldName | CbFieldType.IntegerPositive), 1, (byte)'F', 8];
|
|
CbObject @object = new CbObject(buffer);
|
|
Assert.AreEqual(@object.GetSize(), 6);
|
|
CbObject objectClone = CbObject.Clone(@object);
|
|
Assert.AreEqual(objectClone.GetSize(), 6);
|
|
Assert.IsTrue(@object.Equals(objectClone));
|
|
Assert.AreEqual(objectClone.GetHash(), @object.GetHash());
|
|
for (CbFieldIterator it = objectClone.CreateIterator(); it; ++it)
|
|
{
|
|
CbField field = it.Current;
|
|
Assert.AreEqual(field.GetName(), new Utf8String("F"));
|
|
Assert.AreEqual(field.AsInt32(), 8);
|
|
}
|
|
for (CbFieldIterator it = objectClone.CreateIterator(), end = new CbFieldIterator(); it != end; ++it)
|
|
{
|
|
}
|
|
foreach (CbField _ in objectClone)
|
|
{
|
|
}
|
|
}
|
|
|
|
// Test FCbObjectView as CbFieldIterator
|
|
{
|
|
int count = 0;
|
|
CbObject @object = CbObject.Empty;
|
|
for (CbFieldIterator it = CbFieldIterator.MakeSingle(@object.AsField()); it; ++it)
|
|
{
|
|
CbField field = it.Current;
|
|
Assert.IsTrue(field.IsObject());
|
|
++count;
|
|
}
|
|
Assert.AreEqual(count, 1);
|
|
}
|
|
}
|
|
|
|
public void CbFieldArrayTest()
|
|
{
|
|
static void TestIntArray(CbArray array, int expectedNum, int expectedPayloadSize)
|
|
{
|
|
Assert.AreEqual(array.GetSize(), expectedPayloadSize + sizeof(CbFieldType));
|
|
Assert.AreEqual(array.Count, expectedNum);
|
|
|
|
int actualNum = 0;
|
|
for (CbFieldIterator it = array.CreateIterator(); it; ++it)
|
|
{
|
|
++actualNum;
|
|
Assert.AreEqual(it.Current.AsInt32(), actualNum);
|
|
}
|
|
Assert.AreEqual(actualNum, expectedNum);
|
|
|
|
actualNum = 0;
|
|
foreach (CbField field in array)
|
|
{
|
|
++actualNum;
|
|
Assert.AreEqual(field.AsInt32(), actualNum);
|
|
}
|
|
Assert.AreEqual(actualNum, expectedNum);
|
|
|
|
actualNum = 0;
|
|
foreach (CbField field in array.AsField())
|
|
{
|
|
++actualNum;
|
|
Assert.AreEqual(field.AsInt32(), actualNum);
|
|
}
|
|
Assert.AreEqual(actualNum, expectedNum);
|
|
}
|
|
|
|
// Test CbField(Array, Empty)
|
|
TestField(CbFieldType.Array, new byte[] { 1, 0 });
|
|
|
|
// Test CbField(Array, Empty)
|
|
{
|
|
CbArray array = new CbArray();
|
|
TestIntArray(array, 0, 2);
|
|
|
|
// Advance an iterator past the last field.
|
|
CbFieldIterator it = array.CreateIterator();
|
|
Assert.IsFalse((bool)it);
|
|
Assert.IsTrue(!it);
|
|
for (int count = 16; count > 0; --count)
|
|
{
|
|
++it;
|
|
it.Current.AsInt32();
|
|
}
|
|
Assert.IsFalse((bool)it);
|
|
Assert.IsTrue(!it);
|
|
}
|
|
|
|
// Test CbField(Array, NotEmpty)
|
|
{
|
|
byte intType = (byte)CbFieldType.IntegerPositive;
|
|
byte[] payload = [7, 3, intType, 1, intType, 2, intType, 3];
|
|
CbField field = new CbField(payload, CbFieldType.Array);
|
|
TestField(CbFieldType.Array, field, new CbArray(payload, CbFieldType.Array));
|
|
CbArray array = field.AsArray();
|
|
TestIntArray(array, 3, payload.Length);
|
|
TestIntArray(field.AsArray(), 3, payload.Length);
|
|
Assert.IsTrue(array.Equals(field.AsArray()));
|
|
}
|
|
|
|
// Test CbField(UniformArray)
|
|
{
|
|
byte intType = (byte)(CbFieldType.IntegerPositive);
|
|
byte[] payload = [5, 3, intType, 1, 2, 3];
|
|
CbField field = new CbField(payload, CbFieldType.UniformArray);
|
|
TestField(CbFieldType.UniformArray, field, new CbArray(payload, CbFieldType.UniformArray));
|
|
CbArray array = field.AsArray();
|
|
TestIntArray(array, 3, payload.Length);
|
|
TestIntArray(field.AsArray(), 3, payload.Length);
|
|
Assert.IsTrue(array.Equals(field.AsArray()));
|
|
|
|
// Assert.IsTrue(Array.GetOuterBuffer() == Array.AsField().AsArray().GetOuterBuffer());
|
|
|
|
// Equals
|
|
byte[] namedPayload = [1, (byte)'A', 5, 3, intType, 1, 2, 3];
|
|
CbField namedField = new CbField(namedPayload, CbFieldType.UniformArray | CbFieldType.HasFieldName);
|
|
Assert.IsTrue(field.AsArray().Equals(namedField.AsArray()));
|
|
Assert.IsTrue(field.Equals(field.AsArray().AsField()));
|
|
Assert.IsTrue(namedField.Equals(namedField.AsArray().AsField()));
|
|
|
|
// CopyTo
|
|
byte[] copyBytes = new byte[payload.Length + 1];
|
|
field.AsArray().CopyTo(copyBytes);
|
|
Assert.IsTrue(payload.AsSpan().SequenceEqual(copyBytes.AsSpan(1)));
|
|
namedField.AsArray().CopyTo(copyBytes);
|
|
Assert.IsTrue(payload.AsSpan().SequenceEqual(copyBytes.AsSpan(1)));
|
|
|
|
// TryGetView
|
|
// Assert.IsTrue(Array.TryGetView(out View) && View == Array.GetOuterBuffer().GetView());
|
|
Assert.IsFalse(field.AsArray().TryGetView(out _));
|
|
Assert.IsFalse(namedField.AsArray().TryGetView(out _));
|
|
|
|
// // GetBuffer
|
|
// Assert.IsTrue(Array.GetBuffer().Flatten().GetView() == Array.GetOuterBuffer().GetView());
|
|
// Assert.IsTrue(CbField.MakeView(Field).AsArray().GetBuffer().Flatten().GetView().Span.SequenceEqual(Array.GetOuterBuffer().GetView()));
|
|
// Assert.IsTrue(CbField.MakeView(NamedField).AsArray().GetBuffer().Flatten().GetView().Span.SequenceEqual(Array.GetOuterBuffer().GetView()));
|
|
}
|
|
|
|
// Test CbField(None) as Array
|
|
{
|
|
CbField field = new CbField();
|
|
// TestFieldError(CbFieldType.Array, Field, CbFieldError.TypeError);
|
|
field.AsArray();
|
|
}
|
|
|
|
// Test CbArray(ArrayWithName) and CreateIterator
|
|
{
|
|
byte arrayType = (byte)(CbFieldType.Array | CbFieldType.HasFieldName);
|
|
byte[] buffer = [arrayType, 3, (byte)'K', (byte)'e', (byte)'y', 3, 1, (byte)(CbFieldType.IntegerPositive), 8];
|
|
CbArray array = new CbArray(buffer);
|
|
Assert.AreEqual(array.GetSize(), 5);
|
|
CbArray arrayClone = array;
|
|
Assert.AreEqual(arrayClone.GetSize(), 5);
|
|
Assert.IsTrue(array.Equals(arrayClone));
|
|
Assert.AreEqual(arrayClone.GetHash(), array.GetHash());
|
|
for (CbFieldIterator it = arrayClone.CreateIterator(); it; ++it)
|
|
{
|
|
CbField field = it.Current;
|
|
Assert.AreEqual(field.AsInt32(), 8);
|
|
// Assert.IsTrue(Field.IsOwned());
|
|
}
|
|
for (CbFieldIterator it = arrayClone.CreateIterator(), end = new CbFieldIterator(); it != end; ++it)
|
|
{
|
|
}
|
|
foreach (CbField _ in arrayClone)
|
|
{
|
|
}
|
|
|
|
// CopyTo
|
|
byte[] copyBytes = new byte[5];
|
|
array.CopyTo(copyBytes);
|
|
// Assert.IsTrue(ArrayClone.GetOuterBuffer().GetView().Span.SequenceEqual(CopyBytes));
|
|
arrayClone.CopyTo(copyBytes);
|
|
// Assert.IsTrue(ArrayClone.GetOuterBuffer().GetView().Span.SequenceEqual(CopyBytes));
|
|
|
|
// // GetBuffer
|
|
// Assert.IsTrue(CbField(FSharedBuffer.MakeView(Buffer)).GetBuffer().Flatten().GetView().Span.SequenceEqual(Buffer));
|
|
// Assert.IsTrue(TEXT("CbField(ArrayWithNameNoType).GetBuffer()"),
|
|
// CbField(CbField(Buffer + 1, CbFieldType(ArrayType)), FSharedBuffer.MakeView(Buffer)).GetBuffer().Flatten().GetView().Span.SequenceEqual(Buffer));
|
|
}
|
|
|
|
// Test CbArray as CbFieldIterator
|
|
{
|
|
uint count = 0;
|
|
CbArray array = new CbArray();
|
|
for (CbFieldIterator iter = CbFieldIterator.MakeSingle(array.AsField()); iter; ++iter)
|
|
{
|
|
CbField field = iter.Current;
|
|
Assert.IsTrue(field.IsArray());
|
|
++count;
|
|
}
|
|
Assert.AreEqual(count, 1u);
|
|
}
|
|
|
|
// Test CbArray as CbFieldIterator
|
|
{
|
|
uint count = 0;
|
|
CbArray array = new CbArray();
|
|
// Array.MakeOwned();
|
|
for (CbFieldIterator iter = CbFieldIterator.MakeSingle(array.AsField()); iter; ++iter)
|
|
{
|
|
CbField field = iter.Current;
|
|
Assert.IsTrue(field.IsArray());
|
|
++count;
|
|
}
|
|
Assert.AreEqual(count, 1u);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldBinaryTest()
|
|
{
|
|
// Test CbField(Binary, Empty)
|
|
TestField(CbFieldType.Binary, new byte[] { 0 });
|
|
|
|
// Test CbField(Binary, Value)
|
|
{
|
|
byte[] payload = [3, 4, 5, 6]; // Size: 3, Data: 4/5/6
|
|
CbField fieldView = new CbField(payload, CbFieldType.Binary);
|
|
TestField(CbFieldType.Binary, fieldView, (ReadOnlyMemory<byte>)payload.AsMemory(1, 3));
|
|
|
|
CbField field = fieldView;
|
|
field.AsBinary();
|
|
// Assert.IsFalse(Field.GetOuterBuffer().IsNull());
|
|
// MoveTemp(Field).AsBinary();
|
|
// Assert.IsTrue(Field.GetOuterBuffer().IsNull());
|
|
}
|
|
|
|
// Test CbField(None) as Binary
|
|
{
|
|
CbField fieldView = new CbField();
|
|
byte[] @default = [1, 2, 3];
|
|
TestFieldError(CbFieldType.Binary, fieldView, CbFieldError.TypeError, (ReadOnlyMemory<byte>)@default);
|
|
|
|
// CbField Field = CbField.Clone(FieldView);
|
|
// TestFieldError(CbFieldType.Binary, FSharedBuffer, Field, CbFieldError.TypeError, FSharedBuffer.MakeView(Default), FCbBinaryAccessors());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldStringTest()
|
|
{
|
|
// Test CbField(String, Empty)
|
|
TestField(CbFieldType.String, new byte[] { 0 });
|
|
|
|
// Test CbField(String, Value)
|
|
{
|
|
byte[] payload = [3, (byte)'A', (byte)'B', (byte)'C']; // Size: 3, Data: ABC
|
|
TestField(CbFieldType.String, payload, new Utf8String(payload.AsMemory(1, 3)));
|
|
}
|
|
|
|
// Test CbField(String, OutOfRangeSize)
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, (ulong)(1) << 31);
|
|
TestFieldError(CbFieldType.String, payload, CbFieldError.RangeError, new Utf8String("ABC"));
|
|
}
|
|
|
|
// Test CbField(None) as String
|
|
{
|
|
CbField field = new CbField();
|
|
TestFieldError(CbFieldType.String, field, CbFieldError.TypeError, new Utf8String("ABC"));
|
|
}
|
|
}
|
|
|
|
[Flags]
|
|
enum EIntType : byte
|
|
{
|
|
None = 0x00,
|
|
Int8 = 0x01,
|
|
Int16 = 0x02,
|
|
Int32 = 0x04,
|
|
Int64 = 0x08,
|
|
UInt8 = 0x10,
|
|
UInt16 = 0x20,
|
|
UInt32 = 0x40,
|
|
UInt64 = 0x80,
|
|
// Masks for positive values requiring the specified number of bits.
|
|
Pos64 = UInt64,
|
|
Pos63 = Pos64 | Int64,
|
|
Pos32 = Pos63 | UInt32,
|
|
Pos31 = Pos32 | Int32,
|
|
Pos16 = Pos31 | UInt16,
|
|
Pos15 = Pos16 | Int16,
|
|
Pos8 = Pos15 | UInt8,
|
|
Pos7 = Pos8 | Int8,
|
|
// Masks for negative values requiring the specified number of bits.
|
|
Neg63 = Int64,
|
|
Neg31 = Neg63 | Int32,
|
|
Neg15 = Neg31 | Int16,
|
|
Neg7 = Neg15 | Int8,
|
|
};
|
|
|
|
void TestIntegerField(CbFieldType fieldType, EIntType expectedMask, ulong magnitude)
|
|
{
|
|
byte[] payload = new byte[9];
|
|
ulong negative = (ulong)((byte)fieldType & 1);
|
|
VarInt.WriteUnsigned(payload, magnitude - negative);
|
|
ulong defaultValue = 8;
|
|
ulong expectedValue = (negative != 0) ? (ulong)(-(long)(magnitude)) : magnitude;
|
|
CbField field = new CbField(payload, fieldType);
|
|
|
|
TestField(CbFieldType.IntegerNegative, field, (sbyte)(((expectedMask & EIntType.Int8) != 0) ? expectedValue : defaultValue),
|
|
(sbyte)(defaultValue), ((expectedMask & EIntType.Int8) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<sbyte>(x => x.IsInteger(), (x, y) => x.AsInt8(y)));
|
|
|
|
TestField(CbFieldType.IntegerNegative, field, (short)(((expectedMask & EIntType.Int16) != 0) ? expectedValue : defaultValue),
|
|
(short)(defaultValue), ((expectedMask & EIntType.Int16) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<short>(x => x.IsInteger(), (x, y) => x.AsInt16(y)));
|
|
|
|
TestField(CbFieldType.IntegerNegative, field, (int)(((expectedMask & EIntType.Int32) != 0) ? expectedValue : defaultValue),
|
|
(int)(defaultValue), ((expectedMask & EIntType.Int32) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<int>(x => x.IsInteger(), (x, y) => x.AsInt32(y)));
|
|
|
|
TestField(CbFieldType.IntegerNegative, field, (long)(((expectedMask & EIntType.Int64) != 0) ? expectedValue : defaultValue),
|
|
(long)(defaultValue), ((expectedMask & EIntType.Int64) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<long>(x => x.IsInteger(), (x, y) => x.AsInt64(y)));
|
|
|
|
TestField(CbFieldType.IntegerPositive, field, (byte)(((expectedMask & EIntType.UInt8) != 0) ? expectedValue : defaultValue),
|
|
(byte)(defaultValue), ((expectedMask & EIntType.UInt8) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<byte>(x => x.IsInteger(), (x, y) => x.AsUInt8(y)));
|
|
|
|
TestField(CbFieldType.IntegerPositive, field, (ushort)(((expectedMask & EIntType.UInt16) != 0) ? expectedValue : defaultValue),
|
|
(ushort)(defaultValue), ((expectedMask & EIntType.UInt16) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<ushort>(x => x.IsInteger(), (x, y) => x.AsUInt16(y)));
|
|
|
|
TestField(CbFieldType.IntegerPositive, field, (uint)(((expectedMask & EIntType.UInt32) != 0) ? expectedValue : defaultValue),
|
|
(uint)(defaultValue), ((expectedMask & EIntType.UInt32) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<uint>(x => x.IsInteger(), (x, y) => x.AsUInt32(y)));
|
|
TestField(CbFieldType.IntegerPositive, field, (ulong)(((expectedMask & EIntType.UInt64) != 0) ? expectedValue : defaultValue),
|
|
(ulong)(defaultValue), ((expectedMask & EIntType.UInt64) != 0) ? CbFieldError.None : CbFieldError.RangeError, CbFieldAccessors.FromStruct<ulong>(x => x.IsInteger(), (x, y) => x.AsUInt64(y)));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldIntegerTest()
|
|
{
|
|
// Test CbField(IntegerPositive)
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos7, 0x00);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos7, 0x7f);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos8, 0x80);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos8, 0xff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos15, 0x0100);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos15, 0x7fff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos16, 0x8000);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos16, 0xffff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos31, 0x0001_0000);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos31, 0x7fff_ffff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos32, 0x8000_0000);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos32, 0xffff_ffff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos63, 0x0000_0001_0000_0000);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos63, 0x7fff_ffff_ffff_ffff);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos64, 0x8000_0000_0000_0000);
|
|
TestIntegerField(CbFieldType.IntegerPositive, EIntType.Pos64, 0xffff_ffff_ffff_ffff);
|
|
|
|
// Test CbField(IntegerNegative)
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg7, 0x01);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg7, 0x80);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg15, 0x81);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg15, 0x8000);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg31, 0x8001);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg31, 0x8000_0000);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg63, 0x8000_0001);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.Neg63, 0x8000_0000_0000_0000);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.None, 0x8000_0000_0000_0001);
|
|
TestIntegerField(CbFieldType.IntegerNegative, EIntType.None, 0xffff_ffff_ffff_ffff);
|
|
|
|
// Test CbField(None) as Integer
|
|
{
|
|
CbField field = new CbField();
|
|
TestFieldError(CbFieldType.IntegerPositive, field, CbFieldError.TypeError, (ulong)(8));
|
|
TestFieldError(CbFieldType.IntegerNegative, field, CbFieldError.TypeError, (long)(8));
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldFloatTest()
|
|
{
|
|
// Test CbField(Float, 32-bit)
|
|
{
|
|
byte[] payload = [0xc0, 0x12, 0x34, 0x56]; // -2.28444433f
|
|
TestField(CbFieldType.Float32, payload, -2.28444433f);
|
|
|
|
CbField field = new CbField(payload, CbFieldType.Float32);
|
|
TestField(CbFieldType.Float64, field, (double)-2.28444433f);
|
|
}
|
|
|
|
// Test CbField(Float, 64-bit)
|
|
{
|
|
byte[] payload = [0xc1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; // -631475.76888888876
|
|
TestField(CbFieldType.Float64, payload, -631475.76888888876);
|
|
|
|
CbField field = new CbField(payload, CbFieldType.Float64);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
}
|
|
|
|
// Test CbField(Integer+, MaxBinary32) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 24) - 1); // 16,777,215
|
|
CbField field = new CbField(payload, CbFieldType.IntegerPositive);
|
|
TestField(CbFieldType.Float32, field, 16_777_215.0f);
|
|
TestField(CbFieldType.Float64, field, 16_777_215.0);
|
|
}
|
|
|
|
// Test CbField(Integer+, MaxBinary32+1) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, (ulong)(1) << 24); // 16,777,216
|
|
CbField field = new CbField(payload, CbFieldType.IntegerPositive);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestField(CbFieldType.Float64, field, 16_777_216.0);
|
|
}
|
|
|
|
// Test CbField(Integer+, MaxBinary64) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 53) - 1); // 9,007,199,254,740,991
|
|
CbField field = new CbField(payload, CbFieldType.IntegerPositive);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestField(CbFieldType.Float64, field, 9_007_199_254_740_991.0);
|
|
}
|
|
|
|
// Test CbField(Integer+, MaxBinary64+1) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, (ulong)(1) << 53); // 9,007,199,254,740,992
|
|
CbField field = new CbField(payload, CbFieldType.IntegerPositive);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestFieldError(CbFieldType.Float64, field, CbFieldError.RangeError, 8.0);
|
|
}
|
|
|
|
// Test CbField(Integer+, MaxUInt64) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ~(ulong)0); // Max uint64
|
|
CbField field = new CbField(payload, CbFieldType.IntegerPositive);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestFieldError(CbFieldType.Float64, field, CbFieldError.RangeError, 8.0);
|
|
}
|
|
|
|
// Test CbField(Integer-, MaxBinary32) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 24) - 2); // -16,777,215
|
|
CbField field = new CbField(payload, CbFieldType.IntegerNegative);
|
|
TestField(CbFieldType.Float32, field, -16_777_215.0f);
|
|
TestField(CbFieldType.Float64, field, -16_777_215.0);
|
|
}
|
|
|
|
// Test CbField(Integer-, MaxBinary32+1) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 24) - 1); // -16,777,216
|
|
CbField field = new CbField(payload, CbFieldType.IntegerNegative);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestField(CbFieldType.Float64, field, -16_777_216.0);
|
|
}
|
|
|
|
// Test CbField(Integer-, MaxBinary64) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 53) - 2); // -9,007,199,254,740,991
|
|
CbField field = new CbField(payload, CbFieldType.IntegerNegative);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestField(CbFieldType.Float64, field, -9_007_199_254_740_991.0);
|
|
}
|
|
|
|
// Test CbField(Integer-, MaxBinary64+1) as Float
|
|
{
|
|
byte[] payload = new byte[9];
|
|
VarInt.WriteUnsigned(payload, ((ulong)(1) << 53) - 1); // -9,007,199,254,740,992
|
|
CbField field = new CbField(payload, CbFieldType.IntegerNegative);
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.RangeError, 8.0f);
|
|
TestFieldError(CbFieldType.Float64, field, CbFieldError.RangeError, 8.0);
|
|
}
|
|
|
|
// Test CbField(None) as Float
|
|
{
|
|
CbField field = new CbField();
|
|
TestFieldError(CbFieldType.Float32, field, CbFieldError.TypeError, 8.0f);
|
|
TestFieldError(CbFieldType.Float64, field, CbFieldError.TypeError, 8.0);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldBoolTest()
|
|
{
|
|
// Test CbField(Bool, False)
|
|
TestField(CbFieldType.BoolFalse, Array.Empty<byte>(), false, true);
|
|
|
|
// Test CbField(Bool, True)
|
|
TestField(CbFieldType.BoolTrue, Array.Empty<byte>(), true, false);
|
|
|
|
// Test CbField(None) as Bool
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.BoolFalse, defaultField, CbFieldError.TypeError, false);
|
|
TestFieldError(CbFieldType.BoolTrue, defaultField, CbFieldError.TypeError, true);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldObjectAttachmentTest()
|
|
{
|
|
byte[] zeroBytes = new byte[20];
|
|
byte[] sequentialBytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
|
|
|
// Test CbField(ObjectAttachment, Zero)
|
|
TestField(CbFieldType.ObjectAttachment, zeroBytes);
|
|
|
|
// Test CbField(ObjectAttachment, NonZero)
|
|
TestField(CbFieldType.ObjectAttachment, sequentialBytes, (CbObjectAttachment)new IoHash(sequentialBytes));
|
|
|
|
// Test CbField(ObjectAttachment, NonZero) AsAttachment
|
|
{
|
|
CbField field = new CbField(sequentialBytes, CbFieldType.ObjectAttachment);
|
|
TestField(CbFieldType.ObjectAttachment, field, (CbObjectAttachment)new IoHash(sequentialBytes), (CbObjectAttachment)new IoHash(), CbFieldError.None);
|
|
}
|
|
|
|
// Test CbField(None) as ObjectAttachment
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.ObjectAttachment, defaultField, CbFieldError.TypeError, (CbObjectAttachment)new IoHash(sequentialBytes));
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldBinaryAttachmentTest()
|
|
{
|
|
byte[] zeroBytes = new byte[20];
|
|
byte[] sequentialBytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
|
|
|
// Test CbField(BinaryAttachment, Zero)
|
|
TestField(CbFieldType.BinaryAttachment, zeroBytes);
|
|
|
|
// Test CbField(BinaryAttachment, NonZero)
|
|
TestField(CbFieldType.BinaryAttachment, sequentialBytes, (CbBinaryAttachment)new IoHash(sequentialBytes));
|
|
|
|
// Test CbField(BinaryAttachment, NonZero) AsAttachment
|
|
{
|
|
CbField field = new CbField(sequentialBytes, CbFieldType.BinaryAttachment);
|
|
TestField(CbFieldType.BinaryAttachment, field, (CbBinaryAttachment)new IoHash(sequentialBytes), (CbBinaryAttachment)new IoHash(), CbFieldError.None);
|
|
}
|
|
|
|
// Test CbField(None) as BinaryAttachment
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.BinaryAttachment, defaultField, CbFieldError.TypeError, (CbBinaryAttachment)new IoHash(sequentialBytes));
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldHashTest()
|
|
{
|
|
byte[] zeroBytes = new byte[20];
|
|
byte[] sequentialBytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
|
|
|
// Test CbField(Hash, Zero)
|
|
TestField(CbFieldType.Hash, zeroBytes);
|
|
|
|
// Test CbField(Hash, NonZero)
|
|
TestField(CbFieldType.Hash, sequentialBytes, new IoHash(sequentialBytes));
|
|
|
|
// Test CbField(None) as Hash
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.Hash, defaultField, CbFieldError.TypeError, new IoHash(sequentialBytes));
|
|
}
|
|
|
|
// Test CbField(ObjectAttachment) as Hash
|
|
{
|
|
CbField field = new CbField(sequentialBytes, CbFieldType.ObjectAttachment);
|
|
TestField(CbFieldType.Hash, field, new IoHash(sequentialBytes));
|
|
}
|
|
|
|
// Test CbField(BinaryAttachment) as Hash
|
|
{
|
|
CbField field = new CbField(sequentialBytes, CbFieldType.BinaryAttachment);
|
|
TestField(CbFieldType.Hash, field, new IoHash(sequentialBytes));
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldUuidTest()
|
|
{
|
|
byte[] zeroBytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
byte[] sequentialBytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
Guid sequentialGuid = Guid.Parse("00010203-0405-0607-0809-0a0b0c0d0e0f");
|
|
|
|
// Test CbField(Uuid, Zero)
|
|
TestField(CbFieldType.Uuid, zeroBytes, new Guid(), sequentialGuid);
|
|
|
|
// Test CbField(Uuid, NonZero)
|
|
TestField(CbFieldType.Uuid, sequentialBytes, sequentialGuid, new Guid());
|
|
|
|
// Test CbField(None) as Uuid
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.Uuid, defaultField, CbFieldError.TypeError, Guid.NewGuid());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldDateTimeTest()
|
|
{
|
|
// Test CbField(DateTime, Zero)
|
|
TestField(CbFieldType.DateTime, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
|
|
|
|
// Test CbField(DateTime, 0x1020_3040_5060_7080)
|
|
TestField(CbFieldType.DateTime, new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 }, new DateTime(0x1020_3040_5060_7080L, DateTimeKind.Utc));
|
|
|
|
// Test CbField(DateTime, Zero) as FDateTime
|
|
{
|
|
byte[] payload = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
CbField field = new CbField(payload, CbFieldType.DateTime);
|
|
Assert.AreEqual(field.AsDateTime(), new DateTime(0));
|
|
}
|
|
|
|
// Test CbField(None) as DateTime
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.DateTime, defaultField, CbFieldError.TypeError);
|
|
DateTime defaultValue = new DateTime(0x1020_3040_5060_7080L, DateTimeKind.Utc);
|
|
Assert.AreEqual(defaultField.AsDateTime(defaultValue), defaultValue);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldTimeSpanTest()
|
|
{
|
|
// Test CbField(TimeSpan, Zero)
|
|
TestField(CbFieldType.TimeSpan, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
|
|
|
|
// Test CbField(TimeSpan, 0x1020_3040_5060_7080)
|
|
TestField(CbFieldType.TimeSpan, new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 }, new TimeSpan(0x1020_3040_5060_7080L));
|
|
|
|
// Test CbField(TimeSpan, Zero) as FTimeSpan
|
|
{
|
|
byte[] payload = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
CbField field = new CbField(payload, CbFieldType.TimeSpan);
|
|
Assert.AreEqual(field.AsTimeSpan(), new TimeSpan(0));
|
|
}
|
|
|
|
// Test CbField(None) as TimeSpan
|
|
{
|
|
CbField defaultField = new CbField();
|
|
TestFieldError(CbFieldType.TimeSpan, defaultField, CbFieldError.TypeError);
|
|
TimeSpan defaultValue = new TimeSpan(0x1020_3040_5060_7080L);
|
|
Assert.AreEqual(defaultField.AsTimeSpan(defaultValue), defaultValue);
|
|
}
|
|
}
|
|
|
|
#if false
|
|
[TestMethod]
|
|
public void CbFieldObjectIdTest()
|
|
{
|
|
// Test CbField(ObjectId, Zero)
|
|
TestField(CbFieldType.ObjectId, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
|
|
|
|
// Test CbField(ObjectId, 0x102030405060708090A0B0C0)
|
|
TestField(CbFieldType.ObjectId, {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0},
|
|
FCbObjectId(MakeMemoryView<byte>({0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0})));
|
|
|
|
// Test CbField(ObjectId, Zero) as FCbObjectId
|
|
{
|
|
byte[] Payload = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
CbField Field = new CbField(Payload, CbFieldType.ObjectId);
|
|
Assert.AreEqual(Field.AsObjectId(), FCbObjectId());
|
|
}
|
|
|
|
// Test CbField(None) as ObjectId
|
|
{
|
|
CbField DefaultField;
|
|
TestFieldError(CbFieldType.ObjectId, DefaultField, CbFieldError.TypeError);
|
|
FCbObjectId DefaultValue(MakeMemoryView<byte>({0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0}));
|
|
Assert.AreEqual(DefaultField.AsObjectId(DefaultValue), DefaultValue);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldCustomByIdTest()
|
|
{
|
|
struct FCustomByIdAccessor
|
|
{
|
|
explicit FCustomByIdAccessor(uint64 Id)
|
|
: AsType([Id](CbField& Field, FMemoryView Default) { return Field.AsCustom(Id, Default); })
|
|
{
|
|
}
|
|
|
|
bool (CbField.*IsType)() = &CbField.IsCustomById;
|
|
TUniqueFunction<FMemoryView (CbField& Field, FMemoryView Default)> AsType;
|
|
};
|
|
|
|
// Test CbField(CustomById, MinId, Empty)
|
|
{
|
|
byte[] Payload = new byte[]{1, 0};
|
|
TestField(CbFieldType.CustomById, Payload, FCbCustomById{0});
|
|
TestField(CbFieldType.CustomById, Payload, FMemoryView(), MakeMemoryView<byte>({1, 2, 3}), CbFieldError.None, FCustomByIdAccessor(0));
|
|
TestFieldError(CbFieldType.CustomById, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByIdAccessor(MAX_uint64));
|
|
}
|
|
|
|
// Test CbField(CustomById, MinId, Value)
|
|
{
|
|
byte[] Payload = new byte[]{5, 0, 1, 2, 3, 4};
|
|
TestFieldNoClone(CbFieldType.CustomById, Payload, FCbCustomById{0, Payload.Right(4)});
|
|
TestFieldNoClone(CbFieldType.CustomById, Payload, Payload.Right(4), FMemoryView(), CbFieldError.None, FCustomByIdAccessor(0));
|
|
TestFieldError(CbFieldType.CustomById, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByIdAccessor(MAX_uint64));
|
|
}
|
|
|
|
// Test CbField(CustomById, MaxId, Empty)
|
|
{
|
|
byte[] Payload = new byte[]{9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
TestField(CbFieldType.CustomById, Payload, FCbCustomById{MAX_uint64});
|
|
TestField(CbFieldType.CustomById, Payload, FMemoryView(), MakeMemoryView<byte>({1, 2, 3}), CbFieldError.None, FCustomByIdAccessor(MAX_uint64));
|
|
TestFieldError(CbFieldType.CustomById, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByIdAccessor(0));
|
|
}
|
|
|
|
// Test CbField(CustomById, MaxId, Value)
|
|
{
|
|
byte[] Payload = new byte[]{13, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 4};
|
|
TestFieldNoClone(CbFieldType.CustomById, Payload, FCbCustomById{MAX_uint64, Payload.Right(4)});
|
|
TestFieldNoClone(CbFieldType.CustomById, Payload, Payload.Right(4), FMemoryView(), CbFieldError.None, FCustomByIdAccessor(MAX_uint64));
|
|
TestFieldError(CbFieldType.CustomById, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByIdAccessor(0));
|
|
}
|
|
|
|
// Test CbField(None) as CustomById
|
|
{
|
|
CbField DefaultField;
|
|
TestFieldError(CbFieldType.CustomById, DefaultField, CbFieldError.TypeError, FCbCustomById{4, MakeMemoryView<byte>({1, 2, 3})});
|
|
TestFieldError(CbFieldType.CustomById, DefaultField, CbFieldError.TypeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByIdAccessor(0));
|
|
byte[] DefaultValue = new byte[]{1, 2, 3};
|
|
Assert.AreEqual(DefaultField.AsCustom(0, DefaultValue), DefaultValue);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[TestMethod]
|
|
void CbFieldCustomByNameTest()
|
|
{
|
|
struct FCustomByNameAccessor
|
|
{
|
|
explicit FCustomByNameAccessor(FAnsiStringView Name)
|
|
: AsType([Name = FString(Name)](CbField& Field, FMemoryView Default) { return Field.AsCustom(TCHAR_TO_ANSI(*Name), Default); })
|
|
{
|
|
}
|
|
|
|
bool (CbField.*IsType)() = &CbField.IsCustomByName;
|
|
TUniqueFunction<FMemoryView (CbField& Field, FMemoryView Default)> AsType;
|
|
};
|
|
|
|
// Test CbField(CustomByName, ABC, Empty)
|
|
{
|
|
byte[] Payload = new byte[]{4, 3, 'A', 'B', 'C'};
|
|
TestField(CbFieldType.CustomByName, Payload, FCbCustomByName{"ABC"});
|
|
TestField(CbFieldType.CustomByName, Payload, FMemoryView(), MakeMemoryView<byte>({1, 2, 3}), CbFieldError.None, FCustomByNameAccessor("ABC"));
|
|
TestFieldError(CbFieldType.CustomByName, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByNameAccessor("abc"));
|
|
}
|
|
|
|
// Test CbField(CustomByName, ABC, Value)
|
|
{
|
|
byte[] Payload = new byte[]{8, 3, 'A', 'B', 'C', 1, 2, 3, 4};
|
|
TestFieldNoClone(CbFieldType.CustomByName, Payload, FCbCustomByName{"ABC", Payload.Right(4)});
|
|
TestFieldNoClone(CbFieldType.CustomByName, Payload, Payload.Right(4), FMemoryView(), CbFieldError.None, FCustomByNameAccessor("ABC"));
|
|
TestFieldError(CbFieldType.CustomByName, Payload, CbFieldError.RangeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByNameAccessor("abc"));
|
|
}
|
|
|
|
// Test CbField(None) as CustomByName
|
|
{
|
|
CbField DefaultField;
|
|
TestFieldError(CbFieldType.CustomByName, DefaultField, CbFieldError.TypeError, FCbCustomByName{"ABC", MakeMemoryView<byte>({1, 2, 3})});
|
|
TestFieldError(CbFieldType.CustomByName, DefaultField, CbFieldError.TypeError, MakeMemoryView<byte>({1, 2, 3}), FCustomByNameAccessor("ABC"));
|
|
byte[] DefaultValue = new byte[]{1, 2, 3};
|
|
Assert.AreEqual(DefaultField.AsCustom("ABC", DefaultValue), DefaultValue);
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldIterateAttachmentsTest()
|
|
{
|
|
Func<uint, IoHash> MakeTestHash = (uint Index) =>
|
|
{
|
|
byte[] Data = new byte[4];
|
|
BinaryPrimitives.WriteUInt32LittleEndian(Data, Index);
|
|
return IoHash.Compute(Data);
|
|
};
|
|
|
|
CbFieldIterator Fields;
|
|
{
|
|
CbWriter Writer = new CbWriter();
|
|
|
|
Writer.SetName("IgnoredTypeInRoot").AddHash(MakeTestHash(100));
|
|
Writer.AddObjectAttachment(MakeTestHash(0));
|
|
Writer.AddBinaryAttachment(MakeTestHash(1));
|
|
Writer.SetName("ObjAttachmentInRoot").AddObjectAttachment(MakeTestHash(2));
|
|
Writer.SetName("BinAttachmentInRoot").AddBinaryAttachment(MakeTestHash(3));
|
|
|
|
// Uniform array of type to ignore.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer << 1;
|
|
Writer << 2;
|
|
}
|
|
Writer.EndArray();
|
|
// Uniform array of binary attachments.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer.AddBinaryAttachment(MakeTestHash(4));
|
|
Writer.AddBinaryAttachment(MakeTestHash(5));
|
|
}
|
|
Writer.EndArray();
|
|
// Uniform array of uniform arrays.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer.BeginArray();
|
|
Writer.AddBinaryAttachment(MakeTestHash(6));
|
|
Writer.AddBinaryAttachment(MakeTestHash(7));
|
|
Writer.EndArray();
|
|
Writer.BeginArray();
|
|
Writer.AddBinaryAttachment(MakeTestHash(8));
|
|
Writer.AddBinaryAttachment(MakeTestHash(9));
|
|
Writer.EndArray();
|
|
}
|
|
Writer.EndArray();
|
|
// Uniform array of non-uniform arrays.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer.BeginArray();
|
|
Writer << 0;
|
|
Writer << false;
|
|
Writer.EndArray();
|
|
Writer.BeginArray();
|
|
Writer.AddObjectAttachment(MakeTestHash(10));
|
|
Writer << false;
|
|
Writer.EndArray();
|
|
}
|
|
Writer.EndArray();
|
|
// Uniform array of uniform objects.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj1").AddObjectAttachment(MakeTestHash(11));
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj2").AddObjectAttachment(MakeTestHash(12));
|
|
Writer.EndObject();
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj3").AddObjectAttachment(MakeTestHash(13));
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj4").AddObjectAttachment(MakeTestHash(14));
|
|
Writer.EndObject();
|
|
}
|
|
Writer.EndArray();
|
|
// Uniform array of non-uniform objects.
|
|
Writer.BeginArray();
|
|
{
|
|
Writer.BeginObject();
|
|
Writer << "Int" << 0;
|
|
Writer << "Bool" << false;
|
|
Writer.EndObject();
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInNonUniObjInUniObj").AddObjectAttachment(MakeTestHash(15));
|
|
Writer << "Bool" << false;
|
|
Writer.EndObject();
|
|
}
|
|
Writer.EndArray();
|
|
|
|
// Uniform object of type to ignore.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer << "Int1" << 1;
|
|
Writer << "Int2" << 2;
|
|
}
|
|
Writer.EndObject();
|
|
// Uniform object of binary attachments.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer.SetName("BinAttachmentInUniObj1").AddBinaryAttachment(MakeTestHash(16));
|
|
Writer.SetName("BinAttachmentInUniObj2").AddBinaryAttachment(MakeTestHash(17));
|
|
}
|
|
Writer.EndObject();
|
|
// Uniform object of uniform arrays.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer.SetName("Array1");
|
|
Writer.BeginArray();
|
|
Writer.AddBinaryAttachment(MakeTestHash(18));
|
|
Writer.AddBinaryAttachment(MakeTestHash(19));
|
|
Writer.EndArray();
|
|
Writer.SetName("Array2");
|
|
Writer.BeginArray();
|
|
Writer.AddBinaryAttachment(MakeTestHash(20));
|
|
Writer.AddBinaryAttachment(MakeTestHash(21));
|
|
Writer.EndArray();
|
|
}
|
|
Writer.EndObject();
|
|
// Uniform object of non-uniform arrays.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer.SetName("Array1");
|
|
Writer.BeginArray();
|
|
Writer << 0;
|
|
Writer << false;
|
|
Writer.EndArray();
|
|
Writer.SetName("Array2");
|
|
Writer.BeginArray();
|
|
Writer.AddObjectAttachment(MakeTestHash(22));
|
|
Writer << false;
|
|
Writer.EndArray();
|
|
}
|
|
Writer.EndObject();
|
|
// Uniform object of uniform objects.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer.SetName("Object1");
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj1").AddObjectAttachment(MakeTestHash(23));
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj2").AddObjectAttachment(MakeTestHash(24));
|
|
Writer.EndObject();
|
|
Writer.SetName("Object2");
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj3").AddObjectAttachment(MakeTestHash(25));
|
|
Writer.SetName("ObjAttachmentInUniObjInUniObj4").AddObjectAttachment(MakeTestHash(26));
|
|
Writer.EndObject();
|
|
}
|
|
Writer.EndObject();
|
|
// Uniform object of non-uniform objects.
|
|
Writer.BeginObject();
|
|
{
|
|
Writer.SetName("Object1");
|
|
Writer.BeginObject();
|
|
Writer << "Int" << 0;
|
|
Writer << "Bool" << false;
|
|
Writer.EndObject();
|
|
Writer.SetName("Object2");
|
|
Writer.BeginObject();
|
|
Writer.SetName("ObjAttachmentInNonUniObjInUniObj").AddObjectAttachment(MakeTestHash(27));
|
|
Writer << "Bool" << false;
|
|
Writer.EndObject();
|
|
}
|
|
Writer.EndObject();
|
|
|
|
Fields = Writer.Save();
|
|
}
|
|
|
|
Assert.AreEqual(ValidateCompactBinaryRange(Fields.GetOuterBuffer(), ECbValidateMode.All), ECbValidateError.None);
|
|
|
|
uint AttachmentIndex = 0;
|
|
Fields.IterateRangeAttachments([this, &AttachmentIndex, &MakeTestHash](CbField Field)
|
|
{
|
|
Assert.IsTrue(FString.Printf(AttachmentIndex), Field.IsAttachment());
|
|
Assert.AreEqual(FString.Printf(AttachmentIndex), Field.AsAttachment(), MakeTestHash(AttachmentIndex));
|
|
++AttachmentIndex;
|
|
});
|
|
Assert.AreEqual(AttachmentIndex, 28);
|
|
}
|
|
|
|
[TestMethod]
|
|
void CbFieldBufferTest()
|
|
{
|
|
static_assert(std.is_constructible<CbField>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&&>.value, "Missing constructor for CbField");
|
|
|
|
static_assert(std.is_constructible<CbField, FSharedBuffer&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, FSharedBuffer&&>.value, "Missing constructor for CbField");
|
|
|
|
static_assert(std.is_constructible<CbField, CbField&, FSharedBuffer&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbFieldIterator&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbField&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbArray&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, FCbObject&>.value, "Missing constructor for CbField");
|
|
|
|
static_assert(std.is_constructible<CbField, CbField&, FSharedBuffer&&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbFieldIterator&&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbField&&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, CbArray&&>.value, "Missing constructor for CbField");
|
|
static_assert(std.is_constructible<CbField, CbField&, FCbObject&&>.value, "Missing constructor for CbField");
|
|
|
|
// Test CbField()
|
|
{
|
|
CbField DefaultField;
|
|
Assert.IsFalse(DefaultField.HasValue());
|
|
Assert.IsFalse(DefaultField.IsOwned());
|
|
DefaultField.MakeOwned();
|
|
Assert.IsTrue(DefaultField.IsOwned());
|
|
}
|
|
|
|
// Test Field w/ Type from Shared Buffer
|
|
{
|
|
byte[] Payload = new byte[]{ (byte)(CbFieldType.Binary), 3, 4, 5, 6 }; // Size: 3, Data: 4/5/6
|
|
FSharedBuffer ViewBuffer = FSharedBuffer.MakeView(Payload);
|
|
FSharedBuffer OwnedBuffer = FSharedBuffer.Clone(ViewBuffer);
|
|
|
|
CbField View(ViewBuffer);
|
|
CbField ViewMove{FSharedBuffer(ViewBuffer)};
|
|
CbField ViewOuterField(ImplicitConv<CbField>(View), ViewBuffer);
|
|
CbField ViewOuterBuffer(ImplicitConv<CbField>(View), View);
|
|
CbField Owned(OwnedBuffer);
|
|
CbField OwnedMove{FSharedBuffer(OwnedBuffer)};
|
|
CbField OwnedOuterField(ImplicitConv<CbField>(Owned), OwnedBuffer);
|
|
CbField OwnedOuterBuffer(ImplicitConv<CbField>(Owned), Owned);
|
|
|
|
// These lines are expected to assert when uncommented.
|
|
//CbField InvalidOuterBuffer(ImplicitConv<CbField>(Owned), ViewBuffer);
|
|
//CbField InvalidOuterBufferMove(ImplicitConv<CbField>(Owned), FSharedBuffer(ViewBuffer));
|
|
|
|
Assert.AreEqual(View.AsBinaryView(), ViewBuffer.GetView().Right(3));
|
|
Assert.AreEqual(ViewMove.AsBinaryView(), View.AsBinaryView());
|
|
Assert.AreEqual(ViewOuterField.AsBinaryView(), View.AsBinaryView());
|
|
Assert.AreEqual(ViewOuterBuffer.AsBinaryView(), View.AsBinaryView());
|
|
Assert.AreEqual(Owned.AsBinaryView(), OwnedBuffer.GetView().Right(3));
|
|
Assert.AreEqual(OwnedMove.AsBinaryView(), Owned.AsBinaryView());
|
|
Assert.AreEqual(OwnedOuterField.AsBinaryView(), Owned.AsBinaryView());
|
|
Assert.AreEqual(OwnedOuterBuffer.AsBinaryView(), Owned.AsBinaryView());
|
|
|
|
Assert.IsFalse(View.IsOwned());
|
|
Assert.IsFalse(ViewMove.IsOwned());
|
|
Assert.IsFalse(ViewOuterField.IsOwned());
|
|
Assert.IsFalse(ViewOuterBuffer.IsOwned());
|
|
Assert.IsTrue(Owned.IsOwned());
|
|
Assert.IsTrue(OwnedMove.IsOwned());
|
|
Assert.IsTrue(OwnedOuterField.IsOwned());
|
|
Assert.IsTrue(OwnedOuterBuffer.IsOwned());
|
|
|
|
View.MakeOwned();
|
|
Owned.MakeOwned();
|
|
Assert.AreNotEqual(View.AsBinaryView(), ViewBuffer.GetView().Right(3));
|
|
Assert.IsTrue(View.IsOwned());
|
|
Assert.AreEqual(Owned.AsBinaryView(), OwnedBuffer.GetView().Right(3));
|
|
Assert.IsTrue(Owned.IsOwned());
|
|
}
|
|
|
|
// Test Field w/ Type
|
|
{
|
|
byte[] Payload = new byte[]{ (byte)(CbFieldType.Binary), 3, 4, 5, 6 }; // Size: 3, Data: 4/5/6
|
|
CbField Field = new CbField(Payload);
|
|
|
|
CbField VoidView = CbField.MakeView(Payload);
|
|
CbField VoidClone = CbField.Clone(Payload);
|
|
CbField FieldView = CbField.MakeView(Field);
|
|
CbField FieldClone = CbField.Clone(Field);
|
|
CbField FieldViewClone = CbField.Clone(FieldView);
|
|
|
|
Assert.AreEqual(VoidView.AsBinaryView(), Payload.Right(3));
|
|
Assert.AreNotEqual(VoidClone.AsBinaryView(), Payload.Right(3));
|
|
Assert.IsTrue(VoidClone.AsBinaryView().Span.SequenceEqual(VoidView.AsBinaryView()));
|
|
Assert.AreEqual(FieldView.AsBinaryView(), Payload.Right(3));
|
|
Assert.AreNotEqual(FieldClone.AsBinaryView(), Payload.Right(3));
|
|
Assert.IsTrue(FieldClone.AsBinaryView().Span.SequenceEqual(VoidView.AsBinaryView()));
|
|
Assert.AreNotEqual(FieldViewClone.AsBinaryView(), FieldView.AsBinaryView());
|
|
Assert.IsTrue(FieldViewClone.AsBinaryView().Span.SequenceEqual(VoidView.AsBinaryView()));
|
|
|
|
Assert.IsFalse(VoidView.IsOwned());
|
|
Assert.IsTrue(VoidClone.IsOwned());
|
|
Assert.IsFalse(FieldView.IsOwned());
|
|
Assert.IsTrue(FieldClone.IsOwned());
|
|
Assert.IsTrue(FieldViewClone.IsOwned());
|
|
}
|
|
|
|
// Test Field w/o Type
|
|
{
|
|
byte[] Payload = new byte[]{ 3, 4, 5, 6 }; // Size: 3, Data: 4/5/6
|
|
CbField Field = new CbField(Payload, CbFieldType.Binary);
|
|
|
|
CbField FieldView = CbField.MakeView(Field);
|
|
CbField FieldClone = CbField.Clone(Field);
|
|
CbField FieldViewClone = CbField.Clone(FieldView);
|
|
|
|
Assert.AreEqual(FieldView.AsBinaryView(), Payload.Right(3));
|
|
Assert.IsTrue(FieldClone.AsBinaryView().Span.SequenceEqual(FieldView.AsBinaryView()));
|
|
Assert.IsTrue(FieldViewClone.AsBinaryView().Span.SequenceEqual(FieldView.AsBinaryView()));
|
|
|
|
Assert.IsFalse(FieldView.IsOwned());
|
|
Assert.IsTrue(FieldClone.IsOwned());
|
|
Assert.IsTrue(FieldViewClone.IsOwned());
|
|
|
|
FieldView.MakeOwned();
|
|
Assert.IsTrue(FieldView.AsBinaryView().Span.SequenceEqual(Payload.Right(3)));
|
|
Assert.IsTrue(FieldView.IsOwned());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[TestMethod]
|
|
void CbArrayBufferTest()
|
|
{
|
|
static_assert(std.is_constructible<CbArray>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&&>.value, "Missing constructor for CbArray");
|
|
|
|
static_assert(std.is_constructible<CbArray, CbArray&, FSharedBuffer&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbFieldIterator&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbField&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbArray&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, FCbObject&>.value, "Missing constructor for CbArray");
|
|
|
|
static_assert(std.is_constructible<CbArray, CbArray&, FSharedBuffer&&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbFieldIterator&&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbField&&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, CbArray&&>.value, "Missing constructor for CbArray");
|
|
static_assert(std.is_constructible<CbArray, CbArray&, FCbObject&&>.value, "Missing constructor for CbArray");
|
|
|
|
// Test CbArray()
|
|
{
|
|
CbArray DefaultArray;
|
|
Assert.IsFalse(DefaultArray.IsOwned());
|
|
DefaultArray.MakeOwned();
|
|
Assert.IsTrue(DefaultArray.IsOwned());
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbObjectBufferTest()
|
|
{
|
|
static_assert(std.is_constructible<FCbObject>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObject&&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObject&&>.value, "Missing constructor for FCbObject");
|
|
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, FSharedBuffer&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbFieldIterator&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbField&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbArray&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, FCbObject&>.value, "Missing constructor for FCbObject");
|
|
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, FSharedBuffer&&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbFieldIterator&&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbField&&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, CbArray&&>.value, "Missing constructor for FCbObject");
|
|
static_assert(std.is_constructible<FCbObject, FCbObjectView&, FCbObject&&>.value, "Missing constructor for FCbObject");
|
|
|
|
// Test FCbObject()
|
|
{
|
|
FCbObject DefaultObject;
|
|
Assert.IsFalse(DefaultObject.IsOwned());
|
|
DefaultObject.MakeOwned();
|
|
Assert.IsTrue(DefaultObject.IsOwned());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CbFieldBufferIterator()
|
|
{
|
|
static_assert(std.is_constructible<CbFieldIterator, CbFieldIterator&>.value, "Missing constructor for CbFieldIterator");
|
|
static_assert(std.is_constructible<CbFieldIterator, CbFieldIterator&&>.value, "Missing constructor for CbFieldIterator");
|
|
|
|
static_assert(std.is_constructible<CbFieldIterator, CbFieldIterator&>.value, "Missing constructor for CbFieldIterator");
|
|
static_assert(std.is_constructible<CbFieldIterator, CbFieldIterator&&>.value, "Missing constructor for CbFieldIterator");
|
|
|
|
auto GetCount = [](auto It) -> uint
|
|
{
|
|
uint Count = 0;
|
|
for (; It; ++It)
|
|
{
|
|
++Count;
|
|
}
|
|
return Count;
|
|
};
|
|
|
|
// Test CbField[View]Iterator()
|
|
{
|
|
Assert.AreEqual(GetCount(CbFieldIterator()), 0);
|
|
Assert.AreEqual(GetCount(CbFieldIterator()), 0);
|
|
}
|
|
|
|
// Test CbField[View]Iterator(Range)
|
|
{
|
|
byte T = (byte)(CbFieldType.IntegerPositive);
|
|
byte[] Payload = new byte[]{ T, 0, T, 1, T, 2, T, 3 };
|
|
|
|
FSharedBuffer View = FSharedBuffer.MakeView(Payload);
|
|
FSharedBuffer Clone = FSharedBuffer.Clone(View);
|
|
|
|
FMemoryView EmptyView;
|
|
FSharedBuffer NullBuffer;
|
|
|
|
CbFieldIterator FieldViewIt = CbFieldIterator.MakeRange(View);
|
|
CbFieldIterator FieldIt = CbFieldIterator.MakeRange(View);
|
|
|
|
Assert.AreEqual(FieldViewIt.GetRangeHash(), FBlake3.HashBuffer(View));
|
|
Assert.AreEqual(FieldIt.GetRangeHash(), FBlake3.HashBuffer(View));
|
|
|
|
FMemoryView RangeView;
|
|
Assert.IsTrue(FieldViewIt.TryGetRangeView(RangeView) && RangeView == Payload);
|
|
Assert.IsTrue(FieldIt.TryGetRangeView(RangeView) && RangeView == Payload);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator.CloneRange(CbFieldIterator())), 0);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.CloneRange(CbFieldIterator())), 0);
|
|
CbFieldIterator FieldViewItClone = CbFieldIterator.CloneRange(FieldViewIt);
|
|
CbFieldIterator FieldItClone = CbFieldIterator.CloneRange(FieldIt);
|
|
Assert.AreEqual(GetCount(FieldViewItClone), 4);
|
|
Assert.AreEqual(GetCount(FieldItClone), 4);
|
|
Assert.AreNotEqual(FieldViewItClone, FieldIt);
|
|
Assert.AreNotEqual(FieldItClone, FieldIt);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(EmptyView)), 0);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(NullBuffer)), 0);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(FSharedBuffer(NullBuffer))), 0);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(Payload)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(Clone)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRange(FSharedBuffer(Clone))), 4);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(View), NullBuffer)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(View), FSharedBuffer(NullBuffer))), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(View), View)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(View), FSharedBuffer(View))), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(Clone), Clone)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(Clone), FSharedBuffer(Clone))), 4);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator(FieldIt)), 4);
|
|
Assert.AreEqual(GetCount(CbFieldIterator(CbFieldIterator(FieldIt))), 4);
|
|
|
|
// Uniform
|
|
byte[] UniformPayload = new byte[]{ 0, 1, 2, 3 };
|
|
CbFieldIterator UniformFieldViewIt = CbFieldIterator.MakeRange(UniformPayload, CbFieldType.IntegerPositive);
|
|
Assert.AreEqual(UniformFieldViewIt.GetRangeHash(), FieldViewIt.GetRangeHash());
|
|
Assert.IsFalse(UniformFieldViewIt.TryGetRangeView(RangeView));
|
|
FSharedBuffer UniformView = FSharedBuffer.MakeView(UniformPayload);
|
|
CbFieldIterator UniformFieldIt = CbFieldIterator.MakeRange(UniformView, CbFieldType.IntegerPositive);
|
|
Assert.AreEqual(UniformFieldIt.GetRangeHash(), FieldViewIt.GetRangeHash());
|
|
Assert.IsFalse(UniformFieldIt.TryGetRangeView(RangeView));
|
|
|
|
// Equals
|
|
Assert.IsTrue(FieldViewIt.Equals(FieldViewIt));
|
|
Assert.IsTrue(FieldViewIt.Equals(FieldIt));
|
|
Assert.IsTrue(FieldIt.Equals(FieldIt));
|
|
Assert.IsTrue(FieldIt.Equals(FieldViewIt));
|
|
Assert.IsFalse(FieldViewIt.Equals(FieldViewItClone));
|
|
Assert.IsFalse(FieldIt.Equals(FieldItClone));
|
|
Assert.IsTrue(UniformFieldViewIt.Equals(UniformFieldViewIt));
|
|
Assert.IsTrue(UniformFieldViewIt.Equals(UniformFieldIt));
|
|
Assert.IsTrue(UniformFieldIt.Equals(UniformFieldIt));
|
|
Assert.IsTrue(UniformFieldIt.Equals(UniformFieldViewIt));
|
|
Assert.IsFalse(TEXT("CbFieldIterator.Equals(SamePayload, DifferentEnd)"),
|
|
CbFieldIterator.MakeRange(UniformPayload, CbFieldType.IntegerPositive)
|
|
.Equals(CbFieldIterator.MakeRange(UniformPayload.LeftChop(1), CbFieldType.IntegerPositive)));
|
|
Assert.IsFalse(TEXT("CbFieldIterator.Equals(DifferentPayload, SameEnd)"),
|
|
CbFieldIterator.MakeRange(UniformPayload, CbFieldType.IntegerPositive)
|
|
.Equals(CbFieldIterator.MakeRange(UniformPayload.RightChop(1), CbFieldType.IntegerPositive)));
|
|
|
|
// CopyRangeTo
|
|
byte[] CopyBytes = new byte[Payload.Length];
|
|
FieldViewIt.CopyRangeTo(CopyBytes);
|
|
Assert.IsTrue(CopyBytes.Span.SequenceEqual(Payload));
|
|
FieldIt.CopyRangeTo(CopyBytes);
|
|
Assert.IsTrue(CopyBytes.Span.SequenceEqual(Payload));
|
|
UniformFieldViewIt.CopyRangeTo(CopyBytes);
|
|
Assert.IsTrue(CopyBytes.Span.SequenceEqual(Payload));
|
|
|
|
// MakeRangeOwned
|
|
CbFieldIterator OwnedFromView = UniformFieldIt;
|
|
OwnedFromView.MakeRangeOwned();
|
|
Assert.IsTrue(OwnedFromView.TryGetRangeView(RangeView) && RangeView.Span.SequenceEqual(Payload));
|
|
CbFieldIterator OwnedFromOwned = OwnedFromView;
|
|
OwnedFromOwned.MakeRangeOwned();
|
|
Assert.AreEqual(OwnedFromOwned, OwnedFromView);
|
|
|
|
// These lines are expected to assert when uncommented.
|
|
//FSharedBuffer ShortView = FSharedBuffer.MakeView(Payload.LeftChop(2));
|
|
//Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(*View), ShortView)), 4);
|
|
//Assert.AreEqual(GetCount(CbFieldIterator.MakeRangeView(CbFieldIterator.MakeRange(*View), FSharedBuffer(ShortView))), 4);
|
|
}
|
|
|
|
// Test CbField[View]Iterator(Scalar)
|
|
{
|
|
byte T = (byte)(CbFieldType.IntegerPositive);
|
|
byte[] Payload = new byte[]{ T, 0 };
|
|
|
|
FSharedBuffer View = FSharedBuffer.MakeView(Payload);
|
|
FSharedBuffer Clone = FSharedBuffer.Clone(View);
|
|
|
|
CbField FieldView(Payload);
|
|
CbField Field = new CbField(View);
|
|
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeSingle(FieldView)), 1);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeSingle(CbField(FieldView))), 1);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeSingle(Field)), 1);
|
|
Assert.AreEqual(GetCount(CbFieldIterator.MakeSingle(CbField(Field))), 1);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
[TestMethod]
|
|
public void CbFieldParseTest()
|
|
{
|
|
// Test the optimal object parsing loop because it is expected to be required for high performance.
|
|
// Under ideal conditions, when the fields are in the expected order and there are no extra fields,
|
|
// the loop will execute once and only one comparison will be performed for each field name. Either
|
|
// way, each field will only be visited once even if the loop needs to execute several times.
|
|
static void ParseObject(CbObject obj, ref uint a, ref uint b, ref uint c, ref uint d)
|
|
{
|
|
for (CbFieldIterator it = obj.CreateIterator(); it;)
|
|
{
|
|
CbFieldIterator last = it;
|
|
if (it.Current.GetName() == new Utf8String("A"))
|
|
{
|
|
a = it.Current.AsUInt32();
|
|
++it;
|
|
}
|
|
if (it.Current.GetName() == new Utf8String("B"))
|
|
{
|
|
b = it.Current.AsUInt32();
|
|
++it;
|
|
}
|
|
if (it.Current.GetName() == new Utf8String("C"))
|
|
{
|
|
c = it.Current.AsUInt32();
|
|
++it;
|
|
}
|
|
if (it.Current.GetName() == new Utf8String("D"))
|
|
{
|
|
d = it.Current.AsUInt32();
|
|
++it;
|
|
}
|
|
if (last == it)
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool TestParseObject(byte[] data, uint a, uint b, uint c, uint d)
|
|
{
|
|
uint parsedA = 0, parsedB = 0, parsedC = 0, parsedD = 0;
|
|
ParseObject(new CbObject(data, CbFieldType.Object), ref parsedA, ref parsedB, ref parsedC, ref parsedD);
|
|
return a == parsedA && b == parsedB && c == parsedC && d == parsedD;
|
|
}
|
|
|
|
byte t = (byte)(CbFieldType.IntegerPositive | CbFieldType.HasFieldName);
|
|
Assert.IsTrue(TestParseObject([0], 0, 0, 0, 0));
|
|
Assert.IsTrue(TestParseObject([16, t, 1, (byte)'A', 1, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3, t, 1, (byte)'D', 4], 1, 2, 3, 4));
|
|
Assert.IsTrue(TestParseObject([16, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3, t, 1, (byte)'D', 4, t, 1, (byte)'A', 1], 1, 2, 3, 4));
|
|
Assert.IsTrue(TestParseObject([12, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3, t, 1, (byte)'D', 4], 0, 2, 3, 4));
|
|
Assert.IsTrue(TestParseObject([8, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3], 0, 2, 3, 0));
|
|
Assert.IsTrue(TestParseObject([20, t, 1, (byte)'A', 1, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3, t, 1, (byte)'D', 4, t, 1, (byte)'E', 5], 1, 2, 3, 4));
|
|
Assert.IsTrue(TestParseObject([20, t, 1, (byte)'E', 5, t, 1, (byte)'A', 1, t, 1, (byte)'B', 2, t, 1, (byte)'C', 3, t, 1, (byte)'D', 4], 1, 2, 3, 4));
|
|
Assert.IsTrue(TestParseObject([16, t, 1, (byte)'D', 4, t, 1, (byte)'C', 3, t, 1, (byte)'B', 2, t, 1, (byte)'A', 1], 1, 2, 3, 4));
|
|
}
|
|
}
|
|
}
|