Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
Extend detection for unsupported types#73241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -709,6 +709,13 @@ public static void ThrowNotSupportedException_NoMetadataForType(Type type, IJson | ||
| throw new NotSupportedException(SR.Format(SR.NoMetadataForType, type, resolver?.GetType().FullName ?? "<null>")); | ||
| } | ||
eiriktsarpalis marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. eiriktsarpalis marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| [DoesNotReturn] | ||
| public static void ThrowNotSupportedException_ConstructorContainsNullParameterNames(Type declaringType) | ||
eiriktsarpalis marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| throw new NotSupportedException(SR.Format(SR.ConstructorContainsNullParameterNames, declaringType)); | ||
| } | ||
| [DoesNotReturn] | ||
| public static void ThrowInvalidOperationException_NoMetadataForType(Type type, IJsonTypeInfoResolver? resolver) | ||
| { | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2,6 +2,7 @@ | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| using System.Collections.Generic; | ||
| using System.Reflection; | ||
| using System.Runtime.Serialization; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| @@ -20,110 +21,117 @@ public UnsupportedTypesTests( | ||
| SupportsJsonPathOnSerialize = supportsJsonPathOnSerialize; | ||
| } | ||
| [Fact] | ||
| public async Task DeserializeUnsupportedType() | ||
| [Theory] | ||
eiriktsarpalis marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| [MemberData(nameof(GetUnsupportedValues))] | ||
| public async Task DeserializeUnsupportedType<T>(ValueWrapper<T> wrapper) | ||
| { | ||
| // Any test payload is fine. | ||
| string json = @"""Some string"""; | ||
| _ = wrapper; // only used to instantiate T | ||
| await RunTest<Type>(json); | ||
| await RunTest<SerializationInfo>(json); | ||
| await RunTest<IntPtr>(json); | ||
| await RunTest<IntPtr?>(json); // One nullable variation. | ||
| await RunTest<UIntPtr>(json); | ||
| string json = @"""Some string"""; // Any test payload is fine. | ||
| async Task RunTest<T>(string json) | ||
| { | ||
| Type type = GetNullableOfTUnderlyingType(typeof(T), out bool isNullableOfT); | ||
| string fullName = type.FullName; | ||
| Type type = GetNullableOfTUnderlyingType(typeof(T), out bool isNullableOfT); | ||
| string fullName = type.FullName; | ||
| NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.DeserializeWrapper<T>(json)); | ||
| string exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.DeserializeWrapper<T>(json)); | ||
| string exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| json = $@"{{""Prop"":{json}}}"; | ||
| json = $@"{{""Prop"":{json}}}"; | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.DeserializeWrapper<ClassWithType<T>>(json)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$.Prop", exAsStr); | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.DeserializeWrapper<ClassWithType<T>>(json)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$.Prop", exAsStr); | ||
| // Verify Nullable<> semantics. NSE is not thrown because the serializer handles null. | ||
| if (isNullableOfT) | ||
| { | ||
| Assert.Null(JsonSerializer.Deserialize<T>("null")); | ||
| // Verify Nullable<> semantics. NSE is not thrown because the serializer handles null. | ||
| if (isNullableOfT) | ||
| { | ||
| Assert.Null(JsonSerializer.Deserialize<T>("null")); | ||
| json = $@"{{""Prop"":null}}"; | ||
| ClassWithType<T> obj = await Serializer.DeserializeWrapper<ClassWithType<T>>(json); | ||
| Assert.Null(obj.Prop); | ||
| } | ||
| json = $@"{{""Prop"":null}}"; | ||
| ClassWithType<T> obj = await Serializer.DeserializeWrapper<ClassWithType<T>>(json); | ||
| Assert.Null(obj.Prop); | ||
| } | ||
| } | ||
| [Fact] | ||
| public async Task SerializeUnsupportedType() | ||
| [Theory] | ||
| [MemberData(nameof(GetUnsupportedValues))] | ||
| public async Task SerializeUnsupportedType<T>(ValueWrapper<T> wrapper) | ||
| { | ||
| // TODO refactor to Xunit theory | ||
| await RunTest(typeof(int)); | ||
| await RunTest(new SerializationInfo(typeof(Type), new FormatterConverter())); | ||
| await RunTest((IntPtr)123); | ||
| await RunTest<IntPtr?>(new IntPtr(123)); // One nullable variation. | ||
| await RunTest((UIntPtr)123); | ||
| async Task RunTest<T>(T value) | ||
| T value = wrapper.value; | ||
| Type type = GetNullableOfTUnderlyingType(typeof(T), out bool isNullableOfT); | ||
| string fullName = type.FullName; | ||
| NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(value)); | ||
| string exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| ClassWithType<T> obj = new ClassWithType<T> { Prop = value }; | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(obj)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| if (SupportsJsonPathOnSerialize) | ||
| { | ||
| Assert.Contains("$.Prop", exAsStr); | ||
| } | ||
| else | ||
| { | ||
| Type type = GetNullableOfTUnderlyingType(typeof(T), out bool isNullableOfT); | ||
| string fullName = type.FullName; | ||
| NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(value)); | ||
| string exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| ClassWithType<T> obj = new ClassWithType<T> { Prop = value }; | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(obj)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(fullName, exAsStr); | ||
| if (SupportsJsonPathOnSerialize) | ||
| { | ||
| Assert.Contains("$.Prop", exAsStr); | ||
| } | ||
| else | ||
| { | ||
| Assert.Contains("$.", exAsStr); | ||
| Assert.DoesNotContain("$.Prop", exAsStr); | ||
| } | ||
| // Verify null semantics. NSE is not thrown because the serializer handles null. | ||
| if (!type.IsValueType || isNullableOfT) | ||
| { | ||
| string serialized = await Serializer.SerializeWrapper<T>((T)(object)null); | ||
| Assert.Equal("null", serialized); | ||
| obj.Prop = (T)(object)null; | ||
| serialized = await Serializer.SerializeWrapper(obj); | ||
| Assert.Equal(@"{""Prop"":null}", serialized); | ||
| serialized = await Serializer.SerializeWrapper(obj, new JsonSerializerOptions { IgnoreNullValues = true }); | ||
| Assert.Equal(@"{}", serialized); | ||
| } | ||
| Assert.Contains("$.", exAsStr); | ||
| Assert.DoesNotContain("$.Prop", exAsStr); | ||
| } | ||
| // Verify null semantics. NSE is not thrown because the serializer handles null. | ||
| if (!type.IsValueType || isNullableOfT) | ||
| { | ||
| string serialized = await Serializer.SerializeWrapper<T>((T)(object)null); | ||
| Assert.Equal("null", serialized); | ||
| obj.Prop = (T)(object)null; | ||
| serialized = await Serializer.SerializeWrapper(obj); | ||
| Assert.Equal(@"{""Prop"":null}", serialized); | ||
| serialized = await Serializer.SerializeWrapper(obj, new JsonSerializerOptions { IgnoreNullValues = true }); | ||
| Assert.Equal(@"{}", serialized); | ||
| } | ||
| #if !BUILDING_SOURCE_GENERATOR_TESTS | ||
| Type runtimeType = GetNullableOfTUnderlyingType(value.GetType(), out bool _); | ||
| Type runtimeType = GetNullableOfTUnderlyingType(value.GetType(), out bool _); | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper<object>(value)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(runtimeType.FullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper<object>(value)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(runtimeType.FullName, exAsStr); | ||
| Assert.Contains("$", exAsStr); | ||
| ClassWithType<object> polyObj = new ClassWithType<object> { Prop = value }; | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(polyObj)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(runtimeType.FullName, exAsStr); | ||
| ClassWithType<object> polyObj = new ClassWithType<object> { Prop = value }; | ||
| ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await Serializer.SerializeWrapper(polyObj)); | ||
| exAsStr = ex.ToString(); | ||
| Assert.Contains(runtimeType.FullName, exAsStr); | ||
| #endif | ||
| } | ||
| } | ||
| public static IEnumerable<object[]> GetUnsupportedValues() | ||
| { | ||
| yield return WrapArgs(typeof(int)); | ||
| yield return WrapArgs(typeof(ClassWithExtensionProperty).GetConstructor(Array.Empty<Type>())); | ||
| yield return WrapArgs(typeof(ClassWithExtensionProperty).GetProperty(nameof(ClassWithExtensionProperty.MyInt))); | ||
| yield return WrapArgs(new SerializationInfo(typeof(Type), new FormatterConverter())); | ||
| yield return WrapArgs((IntPtr)123); | ||
| yield return WrapArgs<IntPtr?>(new IntPtr(123)); // One nullable variation. | ||
| yield return WrapArgs((UIntPtr)123); | ||
| static object[] WrapArgs<T>(T value) => new object[] { new ValueWrapper<T>(value) }; | ||
| } | ||
| // Helper record used to path both value & type information to generic theories. | ||
| // This is needed e.g. when passing System.Type instances whose runtime type | ||
| // actually is System.Reflection.RuntimeType. | ||
| public record ValueWrapper<T>(T value) | ||
| { | ||
| public override string ToString() => value.ToString(); | ||
| } | ||
| public class ClassWithIntPtr | ||
| @@ -151,6 +159,21 @@ public override void Write(Utf8JsonWriter writer, IntPtr value, JsonSerializerOp | ||
| } | ||
| } | ||
| #if !BUILDING_SOURCE_GENERATOR_TESTS | ||
eiriktsarpalis marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| [Fact] | ||
| public async Task TypeWithNullConstructorParameterName_ThrowsNotSupportedException() | ||
| { | ||
| // Regression test for https://github.com/dotnet/runtime/issues/58690 | ||
| Type type = Assembly.GetExecutingAssembly().GetType("System.Runtime.CompilerServices.NullableContextAttribute")!; | ||
| ConstructorInfo ctorInfo = type.GetConstructor(new Type[] { typeof(byte) }); | ||
| Assert.True(string.IsNullOrEmpty(ctorInfo.GetParameters()[0].Name)); | ||
| object value = ctorInfo.Invoke(new object[] { (byte)0 }); | ||
| await Assert.ThrowsAnyAsync<NotSupportedException>(() => Serializer.SerializeWrapper(value)); | ||
| await Assert.ThrowsAnyAsync<NotSupportedException>(() => Serializer.DeserializeWrapper("{}", type)); | ||
| } | ||
| #endif | ||
| [Fact] | ||
| public async Task RuntimeConverterIsSupported_IntPtr() | ||
| { | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.