Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Numerics;
using System.Reflection;

public partial class ArraysOfPrimitivesTests : MessagePackSerializerTestBase
{
Expand All @@ -12,8 +11,8 @@ public partial class ArraysOfPrimitivesTests : MessagePackSerializerTestBase
private static readonly Random Random = new Random();
#endif

[Theory, PairwiseData]
public void BoolArray([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(byte))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<byte>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void BoolArray(int length)
{
bool[]? values = null;
if (length >= 0)
Expand All @@ -26,8 +25,8 @@ public void BoolArray([CombinatorialMemberData(nameof(GetInterestingLengths), ty
this.Roundtrip<bool[], Witness>(values);
}

[Theory, PairwiseData]
public void Boolean([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(byte))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<byte>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Boolean(int length)
{
bool[]? values = null;
if (length >= 0)
Expand All @@ -40,40 +39,40 @@ public void Boolean([CombinatorialMemberData(nameof(GetInterestingLengths), type
this.Roundtrip<Memory<bool>, Witness>(values);
}

[Theory, PairwiseData]
public void Int8([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(sbyte))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<sbyte>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Int8(int length)
=> this.Roundtrip<Memory<sbyte>, Witness>(GetRandomValues<sbyte>(length));

[Theory, PairwiseData]
public void Int16([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(short))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<short>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Int16(int length)
=> this.Roundtrip<Memory<short>, Witness>(GetRandomValues<short>(length));

[Theory, PairwiseData]
public void Int32([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(int))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<int>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Int32(int length)
=> this.Roundtrip<Memory<int>, Witness>(GetRandomValues<int>(length));

[Theory, PairwiseData]
public void Int64([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(long))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<long>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Int64(int length)
=> this.Roundtrip<Memory<long>, Witness>(GetRandomValues<long>(length));

[Theory, PairwiseData]
public void UInt8([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(byte))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<byte>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void UInt8(int length)
=> this.Roundtrip<Memory<byte>, Witness>(GetRandomValues<byte>(length));

[Theory, PairwiseData]
public void UInt16([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(ushort))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<ushort>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void UInt16(int length)
=> this.Roundtrip<Memory<ushort>, Witness>(GetRandomValues<ushort>(length));

[Theory, PairwiseData]
public void UInt32([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(uint))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<uint>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void UInt32(int length)
=> this.Roundtrip<Memory<uint>, Witness>(GetRandomValues<uint>(length));

[Theory, PairwiseData]
public void UInt64([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(ulong))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<ulong>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void UInt64(int length)
=> this.Roundtrip<Memory<ulong>, Witness>(GetRandomValues<ulong>(length));

[Theory, PairwiseData]
public void Single([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(float))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<float>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Single(int length)
{
float[]? values = null;
if (length >= 0)
Expand All @@ -92,8 +91,8 @@ public void Single([CombinatorialMemberData(nameof(GetInterestingLengths), typeo
this.Roundtrip<Memory<float>, Witness>(values);
}

[Theory, PairwiseData]
public void Double([CombinatorialMemberData(nameof(GetInterestingLengths), typeof(double))] int length)
[Test, MethodDataSource(typeof(GetInterestingLengthsHelper<double>), nameof(GetInterestingLengthsHelper<>.Helper))]
public void Double(int length)
{
double[]? values = null;
if (length >= 0)
Expand All @@ -108,7 +107,7 @@ public void Double([CombinatorialMemberData(nameof(GetInterestingLengths), typeo
this.Roundtrip<Memory<double>, Witness>(values);
}

[Fact]
[Test]
public void LargeEnumerableOfInt()
{
// A very large enumerable so that it exceeds any default buffer sizes.
Expand Down Expand Up @@ -138,13 +137,14 @@ public void LargeEnumerableOfInt()
return values;
}

private static int[] GetInterestingLengths(Type type) => (int[])typeof(ArraysOfPrimitivesTests).GetMethod(nameof(GetInterestingLengthsHelper), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type).Invoke(null, null)!;

public static class GetInterestingLengthsHelper<T>
{
#if NET
private static int[] GetInterestingLengthsHelper<T>() => [-1, 0, 4, Vector<T>.Count - 1, Vector<T>.Count, Vector<T>.Count + 1, (Vector<T>.Count * 2) + 2, 10_000];
public static int[] Helper() => [-1, 0, 4, Vector<T>.Count - 1, Vector<T>.Count, Vector<T>.Count + 1, (Vector<T>.Count * 2) + 2, 10_000];
#else
private static int[] GetInterestingLengthsHelper<T>() => [-1, 0, 4, 100, 10_000];
public static int[] Helper() => [-1, 0, 4, 100, 10_000];
#endif
}

[GenerateShapeFor<bool[]>]
[GenerateShapeFor<Memory<bool>>]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

[Trait("AsyncSerialization", "true")]
[Property("AsyncSerialization", "true")]
public partial class AsyncSerializationTests : MessagePackSerializerTestBase
{
private static readonly ReadOnlyMemory<byte> BigDataBlob = Enumerable.Range(0, 100).Select(n => (byte)(n % 256)).ToArray();

[Fact]
[Test]
public async Task RoundtripPoco() => await this.AssertRoundtripAsync(new Poco(1, 2));

[Fact]
[Test]
public async Task RoundtripPocoWithDefaultCtor() => await this.AssertRoundtripAsync(new PocoWithDefaultCtor { X = 1, Y = 2 });

[Fact]
[Test]
public async Task PocoDictionary()
{
DictionaryOfPocos value = new(new Dictionary<string, Poco>
Expand All @@ -25,7 +25,7 @@ public async Task PocoDictionary()
await this.AssertRoundtripAsync(value);
}

[Fact]
[Test]
public async Task PrimitivesDictionary()
{
DictionaryOfPrimitives value = new(new Dictionary<string, int>
Expand All @@ -38,62 +38,62 @@ public async Task PrimitivesDictionary()
await this.AssertRoundtripAsync(value);
}

[Fact]
[Test]
public async Task LargeArray() => await this.AssertRoundtripAsync(new ArrayOfPocos(Enumerable.Range(0, 1000).Select(i => new Poco(i, i)).ToArray()));

/// <summary>
/// Verifies that the array converter can handle async serialization when its elements are not async capable.
/// </summary>
[Fact]
[Test]
public async Task LargeArrayWithBigElements()
{
this.Serializer = this.Serializer with { Converters = [.. this.Serializer.Converters, new PocoNonAsyncConverter()] };

await this.AssertRoundtripAsync(new ArrayOfPocos(Enumerable.Range(0, 1000).Select(i => new Poco(i, i) { DataBlob = BigDataBlob }).ToArray()));
}

[Fact]
[Test]
public async Task LargeList() => await this.AssertRoundtripAsync(new ListOfPocos(Enumerable.Range(0, 1000).Select(i => new Poco(i, i)).ToList()));

[Fact]
[Test]
public async Task LargeImmutableArray() => await this.AssertRoundtripAsync(new ImmutableArrayOfPocos(Enumerable.Range(0, 1000).Select(i => new Poco(i, i)).ToImmutableArray()));

[Fact]
[Test]
public async Task Null_Array() => await this.AssertRoundtripAsync(new ArrayOfPocos(null));

[Fact]
[Test]
public async Task Null() => await this.AssertRoundtripAsync<Poco>(null);

[Fact]
[Test]
public async Task ArrayOfInts() => await this.AssertRoundtripAsync(new ArrayOfPrimitives([1, 2, 3]));

[Fact]
[Test]
public async Task ObjectAsArrayOfValues() => await this.AssertRoundtripAsync(new PocoAsArray(42));

[Fact]
[Test]
public async Task ObjectAsArrayOfValues_Null() => await this.AssertRoundtripAsync<PocoAsArray>(null);

[Fact]
[Test]
public async Task ObjectAsArrayOfValues_DefaultCtor() => await this.AssertRoundtripAsync(new PocoAsArrayWithDefaultCtor { Value = 42 });

[Fact]
[Test]
public async Task ObjectAsArrayOfValues_DefaultCtor_Null() => await this.AssertRoundtripAsync<PocoAsArrayWithDefaultCtor>(null);

[Fact]
[Test]
public async Task WithPreBuffering()
{
SpecialRecordConverter converter = new();
this.Serializer = this.Serializer with { Converters = [converter] };
var msgpack = new ReadOnlySequence<byte>(
this.Serializer.Serialize(new SpecialRecord { Property = 446 }, TestContext.Current.CancellationToken));
this.Serializer.Serialize(new SpecialRecord { Property = 446 }, this.TimeoutToken));

// Verify that with a sufficiently low async buffer, the async paths are taken.
this.Serializer = new()
{
MaxAsyncBuffer = 1,
Converters = [converter],
};
await this.Serializer.DeserializeAsync<SpecialRecord>(new FragmentedPipeReader(msgpack), TestContext.Current.CancellationToken);
await this.Serializer.DeserializeAsync<SpecialRecord>(new FragmentedPipeReader(msgpack), this.TimeoutToken);
Assert.Equal(1, converter.AsyncDeserializationCounter);

// Verify that with a sufficiently high async buffer, the sync paths are taken.
Expand All @@ -103,31 +103,31 @@ public async Task WithPreBuffering()
MaxAsyncBuffer = 15,
Converters = [converter],
};
await this.Serializer.DeserializeAsync<SpecialRecord>(new FragmentedPipeReader(msgpack), TestContext.Current.CancellationToken);
await this.Serializer.DeserializeAsync<SpecialRecord>(new FragmentedPipeReader(msgpack), this.TimeoutToken);
Assert.Equal(0, converter.AsyncDeserializationCounter);
}

[Fact]
[Test]
public async Task DecodeLargeString()
{
string expected = new string('a', 100 * 1024);
ReadOnlySequence<byte> msgpack = new(this.Serializer.Serialize<string, Witness>(expected, TestContext.Current.CancellationToken));
ReadOnlySequence<byte> msgpack = new(this.Serializer.Serialize<string, Witness>(expected, this.TimeoutToken));
FragmentedPipeReader pipeReader = new(msgpack, msgpack.GetPosition(0), msgpack.GetPosition(1), msgpack.GetPosition(512), msgpack.GetPosition(6000), msgpack.GetPosition(32 * 1024));
string? actual = await this.Serializer.DeserializeAsync(pipeReader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<string>(), TestContext.Current.CancellationToken);
string? actual = await this.Serializer.DeserializeAsync(pipeReader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<string>(), this.TimeoutToken);
Assert.Equal(expected, actual);
}

[Fact]
[Test]
public async Task DecodeEmptyString()
{
string expected = string.Empty;
ReadOnlySequence<byte> msgpack = new(this.Serializer.Serialize<string, Witness>(expected, TestContext.Current.CancellationToken));
ReadOnlySequence<byte> msgpack = new(this.Serializer.Serialize<string, Witness>(expected, this.TimeoutToken));
FragmentedPipeReader pipeReader = new(msgpack, msgpack.GetPosition(0));
string? actual = await this.Serializer.DeserializeAsync(pipeReader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<string>(), TestContext.Current.CancellationToken);
string? actual = await this.Serializer.DeserializeAsync(pipeReader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<string>(), this.TimeoutToken);
Assert.Equal(expected, actual);
}

[Theory, PairwiseData]
[Test, MatrixDataSource]
public async Task DeserializeAsyncAdvancesPipeReader(bool forceAsync)
{
this.Serializer = this.Serializer with { MaxAsyncBuffer = forceAsync ? 0 : 1024 };
Expand All @@ -140,11 +140,11 @@ public async Task DeserializeAsyncAdvancesPipeReader(bool forceAsync)
PipeReader reader = PipeReader.Create(sequence);

// Deserialize a value. It should advance the reader exactly across the msgpack structure.
int number = await this.Serializer.DeserializeAsync(reader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<int>(), TestContext.Current.CancellationToken);
int number = await this.Serializer.DeserializeAsync(reader, Witness.GeneratedTypeShapeProvider.GetTypeShapeOrThrow<int>(), this.TimeoutToken);
Assert.Equal(42, number);

// Verify that the reader is now positioned at the next byte.
ReadResult readResult = await reader.ReadAsync(TestContext.Current.CancellationToken);
ReadResult readResult = await reader.ReadAsync(this.TimeoutToken);
Assert.True(readResult.IsCompleted);
Assert.Equal("a"u8, readResult.Buffer.ToArray());
}
Expand Down
Loading