Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -1,11 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
Expand All @@ -26,7 +27,7 @@ public async Task WriteRootLevelAsyncEnumerable<TElement>(IEnumerable<TElement>
JsonSerializerOptions options = Serializer.CreateOptions(makeReadOnly: false);
options.DefaultBufferSize = bufferSize;

string expectedJson = JsonSerializer.Serialize(source, options);
string expectedJson = await Serializer.SerializeWrapper(source, options);

using var stream = new Utf8MemoryStream();
var asyncEnumerable = new MockedAsyncEnumerable<TElement>(source, delayInterval);
Expand All @@ -49,7 +50,7 @@ public async Task WriteNestedAsyncEnumerable<TElement>(IEnumerable<TElement> sou
JsonSerializerOptions options = Serializer.CreateOptions(makeReadOnly: false);
options.DefaultBufferSize = bufferSize;

string expectedJson = JsonSerializer.Serialize(new EnumerableDto<TElement> { Data = source }, options);
string expectedJson = await Serializer.SerializeWrapper(new EnumerableDto<TElement> { Data = source }, options);

using var stream = new Utf8MemoryStream();
var asyncEnumerable = new MockedAsyncEnumerable<TElement>(source, delayInterval);
Expand All @@ -75,7 +76,7 @@ public async Task WriteNestedAsyncEnumerable_Nullable<TElement>(IEnumerable<TEle
options.DefaultBufferSize = bufferSize;
options.IncludeFields = true;

string expectedJson = JsonSerializer.Serialize<(IEnumerable<TElement>, bool)?>((source, false), options);
string expectedJson = await Serializer.SerializeWrapper<(IEnumerable<TElement>, bool)?>((source, false), options);

using var stream = new Utf8MemoryStream();
var asyncEnumerable = new MockedAsyncEnumerable<TElement>(source, delayInterval);
Expand All @@ -94,7 +95,7 @@ public async Task WriteAsyncEnumerable_CancellationToken_IsPassedToAsyncEnumerat
using var cts = new CancellationTokenSource();

IAsyncEnumerable<int> value = CreateEnumerable();
await JsonSerializer.SerializeAsync(utf8Stream, value, Serializer.DefaultOptions, cancellationToken: cts.Token);
await JsonSerializer.SerializeAsync(utf8Stream, value, Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<int>>(), cts.Token);
Assert.Equal("[1,2]", utf8Stream.AsString());

async IAsyncEnumerable<int> CreateEnumerable([EnumeratorCancellation] CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -128,7 +129,7 @@ public async Task WriteAsyncEnumerable_LongRunningEnumeration_Cancellation(
using var utf8Stream = new Utf8MemoryStream();
using var cts = new CancellationTokenSource(delay: TimeSpan.FromMilliseconds(cancellationTokenSourceDelayMilliseconds));
await Assert.ThrowsAsync<TaskCanceledException>(async () =>
await JsonSerializer.SerializeAsync(utf8Stream, longRunningEnumerable, Serializer.DefaultOptions, cancellationToken: cts.Token));
await JsonSerializer.SerializeAsync(utf8Stream, longRunningEnumerable, Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<int>>(), cts.Token));

Assert.Equal(1, longRunningEnumerable.TotalCreatedEnumerators);
Assert.Equal(1, longRunningEnumerable.TotalDisposedEnumerators);
Expand Down Expand Up @@ -168,7 +169,7 @@ public async Task WriteSequentialNestedAsyncEnumerables<TElement>(IEnumerable<TE
JsonSerializerOptions options = Serializer.CreateOptions(makeReadOnly: false);
options.DefaultBufferSize = bufferSize;

string expectedJson = JsonSerializer.Serialize(new EnumerableDtoWithTwoProperties<TElement> { Data1 = source, Data2 = source }, options);
string expectedJson = await Serializer.SerializeWrapper(new EnumerableDtoWithTwoProperties<TElement> { Data1 = source, Data2 = source }, options);

using var stream = new Utf8MemoryStream();
var asyncEnumerable = new MockedAsyncEnumerable<TElement>(source, delayInterval);
Expand All @@ -192,7 +193,7 @@ public async Task WriteAsyncEnumerableOfAsyncEnumerables<TElement>(IEnumerable<T
options.DefaultBufferSize = bufferSize;

const int OuterEnumerableCount = 5;
string expectedJson = JsonSerializer.Serialize(Enumerable.Repeat(source, OuterEnumerableCount), options);
string expectedJson = await Serializer.SerializeWrapper(Enumerable.Repeat(source, OuterEnumerableCount), options);

var innerAsyncEnumerable = new MockedAsyncEnumerable<TElement>(source, delayInterval);
var outerAsyncEnumerable =
Expand All @@ -213,16 +214,16 @@ public async Task WriteAsyncEnumerableOfAsyncEnumerables<TElement>(IEnumerable<T
public void WriteRootLevelAsyncEnumerableSync_ThrowsNotSupportedException()
{
IAsyncEnumerable<int> asyncEnumerable = new MockedAsyncEnumerable<int>(Enumerable.Range(1, 10));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(asyncEnumerable, Serializer.DefaultOptions));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), asyncEnumerable, Serializer.DefaultOptions));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(asyncEnumerable, Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<int>>()));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), asyncEnumerable, Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<int>>()));
}

[Fact]
public void WriteNestedAsyncEnumerableSync_ThrowsNotSupportedException()
{
IAsyncEnumerable<int> asyncEnumerable = new MockedAsyncEnumerable<int>(Enumerable.Range(1, 10));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions.GetTypeInfo<AsyncEnumerableDto<int>>()));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions.GetTypeInfo<AsyncEnumerableDto<int>>()));
}

[Fact]
Expand Down Expand Up @@ -331,7 +332,7 @@ public async Task RegressionTest_DisposingEnumeratorOnPendingMoveNextAsyncOperat
// Regression test for https://github.com/dotnet/runtime/issues/57360
using var stream = new Utf8MemoryStream();
using var cts = new CancellationTokenSource(millisecondsDelay: 1000);
await Assert.ThrowsAsync<TaskCanceledException>(async () => await JsonSerializer.SerializeAsync(stream, GetNumbersAsync(), Serializer.DefaultOptions, cancellationToken: cts.Token));
await Assert.ThrowsAsync<TaskCanceledException>(async () => await JsonSerializer.SerializeAsync(stream, GetNumbersAsync(), Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<int>>(), cts.Token));

static async IAsyncEnumerable<int> GetNumbersAsync()
{
Expand Down Expand Up @@ -417,13 +418,6 @@ public async Task WriteNestedAsyncEnumerableInsideAsyncEnumerable_InnerEnumerato
return;
}

// This test requires reflection to serialize custom IAsyncEnumerable types;
// skip in source-gen contexts where reflection is disabled.
if (!JsonSerializer.IsReflectionEnabledByDefault)
{
return;
}

var events = new List<string>();
var inner1 = new DisposalTrackingAsyncEnumerable<int>(
new[] { 1, 2 }, "Inner1", events, asyncDisposal);
Expand All @@ -434,7 +428,7 @@ public async Task WriteNestedAsyncEnumerableInsideAsyncEnumerable_InnerEnumerato
new IAsyncEnumerable<int>[] { inner1, inner2 }, "Outer", events, asyncDisposal);

using var stream = new Utf8MemoryStream();
await JsonSerializer.SerializeAsync<IAsyncEnumerable<IAsyncEnumerable<int>>>(stream, outer);
await JsonSerializer.SerializeAsync(stream, (IAsyncEnumerable<IAsyncEnumerable<int>>)outer, Serializer.DefaultOptions.GetTypeInfo<IAsyncEnumerable<IAsyncEnumerable<int>>>());

JsonTestHelper.AssertJsonEqual("[[1,2],[3,4]]", stream.AsString());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
Expand Down Expand Up @@ -731,6 +732,8 @@ public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerO
// levels deep, along with matching JSON, encompassing the various planes of
// dictionaries that can be combined: generic, non-generic, BCL, user-derived,
// immutable, mutable, readonly, concurrent, specialized.
[RequiresUnreferencedCode("Uses Type.MakeGenericType to construct nested dictionary types.")]
[RequiresDynamicCode("Uses Type.MakeGenericType to construct nested dictionary types.")]
private static IEnumerable<(Type, string)> NestedDictionaryTypeData()
{
string testJson = """{"Key":1}""";
Expand Down Expand Up @@ -793,6 +796,8 @@ public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerO
#endif
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/66220", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
[RequiresUnreferencedCode("Uses Type.MakeGenericType to construct nested dictionary types.")]
[RequiresDynamicCode("Uses Type.MakeGenericType to construct nested dictionary types.")]
public async Task NestedDictionariesRoundtrip()
{
JsonSerializerOptions options = new JsonSerializerOptions();
Expand Down Expand Up @@ -1300,11 +1305,11 @@ public async Task IgnoreDictionaryPropertyWithDifferentOrdering()
await VerifyIgnore<ClassWithIgnoredImmutableDictionary>(false, true, false, addMissing: true);
}

private async Task VerifyIgnore<T>(bool skip1, bool skip2, bool skip3, bool addMissing = false)
private async Task VerifyIgnore<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(bool skip1, bool skip2, bool skip3, bool addMissing = false)
{
static IDictionary<string, int> GetProperty(T objectToVerify, string propertyName)
{
return (IDictionary<string, int>)objectToVerify.GetType().GetProperty(propertyName).GetValue(objectToVerify);
return (IDictionary<string, int>)typeof(T).GetProperty(propertyName).GetValue(objectToVerify);
Comment thread
eiriktsarpalis marked this conversation as resolved.
}

void Verify(T objectToVerify)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -396,7 +397,7 @@ private class TrailingAngleBracketPolicy : JsonNamingPolicy
[Theory]
[InlineData(typeof(KeyNameNullPolicy), "Key")]
[InlineData(typeof(ValueNameNullPolicy), "Value")]
public async Task InvalidPropertyNameFail(Type policyType, string offendingProperty)
public async Task InvalidPropertyNameFail([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type policyType, string offendingProperty)
{
var options = new JsonSerializerOptions
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -34,20 +35,20 @@ async Task DeserializeObjectAsync(string json, Type type, JsonSerializerOptions
((ITestClassWithParameterizedCtor)obj).Verify();
}

async Task DeserializeObjectMinimalAsync(Type type, JsonSerializerOptions options)
async Task DeserializeObjectMinimalAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, JsonSerializerOptions options)
{
string json = (string)type.GetProperty("s_json_minimal").GetValue(null);
var obj = await Serializer.DeserializeWrapper(json, type, options);
((ITestClassWithParameterizedCtor)obj).VerifyMinimal();
};

async Task DeserializeObjectFlippedAsync(Type type, JsonSerializerOptions options)
async Task DeserializeObjectFlippedAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, JsonSerializerOptions options)
{
string json = (string)type.GetProperty("s_json_flipped").GetValue(null);
await DeserializeObjectAsync(json, type, options);
};

async Task DeserializeObjectNormalAsync(Type type, JsonSerializerOptions options)
async Task DeserializeObjectNormalAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type, JsonSerializerOptions options)
{
string json = (string)type.GetProperty("s_json").GetValue(null);
await DeserializeObjectAsync(json, type, options);
Expand All @@ -59,7 +60,7 @@ async Task SerializeObject(Type type, JsonSerializerOptions options)
await Serializer.SerializeWrapper(obj, options);
};

async Task RunTestAsync(Type type)
async Task RunTestAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type)
{
// Use local options to avoid obtaining already cached metadata from the default options.
JsonSerializerOptions options = Serializer.CreateOptions();
Expand Down Expand Up @@ -129,7 +130,7 @@ public async Task PropertyCacheWithMinInputsLast()
[SkipOnCoreClr("https://github.com/dotnet/runtime/issues/45464", ~RuntimeConfiguration.Release)]
public async Task MultipleTypes()
{
async Task Serialize<T>(object[] args)
async Task Serialize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(object[] args)
{
Type type = typeof(T);

Expand All @@ -145,7 +146,7 @@ async Task DeserializeAsync<T>(string json)
obj.Verify();
};

async Task RunTestAsync<T>(T testObj, object[] args)
async Task RunTestAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(T testObj, object[] args)
{
// Get the test json with the default options to avoid cache pollution of DeserializeAsync() below.
((ITestClass)testObj).Initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ public async Task ConstructorHandlingHonorsCustomConverters()
[Fact]
public async Task CanDeserialize_ObjectWith_Ctor_With_64_Params()
{
async Task RunTestAsync<T>()
async Task RunTestAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>()
{
StringBuilder sb = new StringBuilder();
sb.Append("{");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json.Nodes;
Expand Down Expand Up @@ -1353,7 +1354,7 @@ public class ClassWithExtensionPropertyCustomIImmutableJsonElement
[InlineData(typeof(ClassWithExtensionPropertyNoGenericParameters))]
[InlineData(typeof(ClassWithExtensionPropertyOneGenericParameter))]
[InlineData(typeof(ClassWithExtensionPropertyThreeGenericParameters))]
public async Task DeserializeIntoGenericDictionaryParameterCount(Type type)
public async Task DeserializeIntoGenericDictionaryParameterCount([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type)
{
object obj = await Serializer.DeserializeWrapper("{\"hello\":\"world\"}", type);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;

namespace System.Text.Json.Serialization.Tests;
Expand Down Expand Up @@ -825,10 +827,11 @@ public class ClassWithRecursiveRequiredProperty
public ClassWithRecursiveRequiredProperty? Next { get; set; }
}

[Theory]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
[InlineData(typeof(SimpleClass))]
[InlineData(typeof(SimpleClassWithSmallParametrizedCtor))]
[InlineData(typeof(SimpleClassWithLargeParametrizedCtor))]
[RequiresDynamicCode("Uses Type.MakeGenericType to construct the generic type under test.")]
public async Task CreationHandlingSetWithAttribute_CanPopulateOrSerialize_Callbacks(Type type)
{
Type finalType = typeof(ClassWithWritableProperty<>).MakeGenericType(type);
Expand Down Expand Up @@ -879,7 +882,10 @@ async Task DeserializeAndEnsureCallbacksCalled(string json, int expectedTimesCal
[InlineData(typeof(ClassImplementingInterfaceWithPopulateOnTypeWithInterfaceProperty), null, false)]
[InlineData(typeof(IInterfaceWithInterfaceProperty), typeof(ClassImplementingInterfaceWithInterfaceProperty), false)]
[InlineData(typeof(ClassImplementingInterfaceWithInterfaceProperty), null, true)]
public async Task CreationHandlingSetWithAttributeOnType_Interfaces(Type typeToDeserialize, Type? typeToCreate, bool shouldPopulate)
public async Task CreationHandlingSetWithAttributeOnType_Interfaces(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type typeToDeserialize,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type? typeToCreate,
bool shouldPopulate)
{
JsonSerializerOptions options = Serializer.CreateOptions(modifier: ti =>
{
Expand Down Expand Up @@ -1169,7 +1175,7 @@ public class ClassWithInvalidPropertyAnnotation
[Theory]
[InlineData(typeof(ClassWithParameterizedConstructorWithPopulateProperty))]
[InlineData(typeof(ClassWithParameterizedConstructorWithPopulateType))]
public async Task ClassWithParameterizedCtor_UsingPopulateConfiguration_ThrowsNotSupportedException(Type type)
public async Task ClassWithParameterizedCtor_UsingPopulateConfiguration_ThrowsNotSupportedException([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type)
{
object instance = Activator.CreateInstance(type, "Jim");
string json = """{"Username":"Jim","PhoneNumbers":["123456"]}""";
Expand Down
Loading
Loading