From fcacfcd44756e2a72e8fe61b6c6ba3ace381da00 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Thu, 30 Jul 2020 14:52:15 -0700 Subject: [PATCH] Verify JsonSerializer support for init-only properties (#40150) --- ...pertyVisibilityTests.NonPublicAccessors.cs | 21 +++++ .../Serialization/PropertyVisibilityTests.cs | 2 +- .../PropertyVisiblityTests.InitOnly.cs | 94 +++++++++++++++++++ .../tests/System.Text.Json.Tests.csproj | 1 + 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Text.Json/tests/Serialization/PropertyVisiblityTests.InitOnly.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs index be76b5e424a07..0dd3657e6f5c3 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs @@ -298,6 +298,9 @@ private class ClassWithMixedPropertyAccessors_PropertyAttributes [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty))] [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty))] [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty))] public static void NonPublicProperty_WithJsonInclude_Invalid(Type type) { InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize("", type)); @@ -350,5 +353,23 @@ private class ClassWithProtectedField_WithJsonIncludeProperty [JsonInclude] protected string MyString = null; } + + private class ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty + { + [JsonInclude] + private string MyString { get; init; } + } + + private class ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty + { + [JsonInclude] + internal string MyString { get; init; } + } + + private class ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty + { + [JsonInclude] + protected string MyString { get; init; } + } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs index 6e377f8340bee..062813373ae21 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Collections.Concurrent; -using Xunit; using System.Numerics; +using Xunit; namespace System.Text.Json.Serialization.Tests { diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisiblityTests.InitOnly.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisiblityTests.InitOnly.cs new file mode 100644 index 0000000000000..48fe1e34c935b --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisiblityTests.InitOnly.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class PropertyVisibilityTests + { + [Theory] + [InlineData(typeof(ClassWithInitOnlyProperty))] + [InlineData(typeof(StructWithInitOnlyProperty))] + public static void InitOnlyProperties_Work(Type type) + { + // Init-only property included by default. + object obj = JsonSerializer.Deserialize(@"{""MyInt"":1}", type); + Assert.Equal(1, (int)type.GetProperty("MyInt").GetValue(obj)); + + // Init-only properties can be serialized. + Assert.Equal(@"{""MyInt"":1}", JsonSerializer.Serialize(obj)); + } + + [Theory] + [InlineData(typeof(Class_PropertyWith_PrivateInitOnlySetter))] + [InlineData(typeof(Class_PropertyWith_InternalInitOnlySetter))] + [InlineData(typeof(Class_PropertyWith_ProtectedInitOnlySetter))] + public static void NonPublicInitOnlySetter_Without_JsonInclude_Fails(Type type) + { + // Non-public init-only property setter ignored. + object obj = JsonSerializer.Deserialize(@"{""MyInt"":1}", type); + Assert.Equal(0, (int)type.GetProperty("MyInt").GetValue(obj)); + + // Public getter can be used for serialization. + Assert.Equal(@"{""MyInt"":0}", JsonSerializer.Serialize(obj)); + } + + [Theory] + [InlineData(typeof(Class_PropertyWith_PrivateInitOnlySetter_WithAttribute))] + [InlineData(typeof(Class_PropertyWith_InternalInitOnlySetter_WithAttribute))] + [InlineData(typeof(Class_PropertyWith_ProtectedInitOnlySetter_WithAttribute))] + public static void NonPublicInitOnlySetter_With_JsonInclude_Works(Type type) + { + // Non-public init-only property setter included with [JsonInclude]. + object obj = JsonSerializer.Deserialize(@"{""MyInt"":1}", type); + Assert.Equal(1, (int)type.GetProperty("MyInt").GetValue(obj)); + + // Init-only properties can be serialized. + Assert.Equal(@"{""MyInt"":1}", JsonSerializer.Serialize(obj)); + } + + public class ClassWithInitOnlyProperty + { + public int MyInt { get; init; } + } + + public struct StructWithInitOnlyProperty + { + public int MyInt { get; init; } + } + + public class Class_PropertyWith_PrivateInitOnlySetter + { + public int MyInt { get; private init; } + } + + public class Class_PropertyWith_InternalInitOnlySetter + { + public int MyInt { get; internal init; } + } + + public class Class_PropertyWith_ProtectedInitOnlySetter + { + public int MyInt { get; protected init; } + } + + public class Class_PropertyWith_PrivateInitOnlySetter_WithAttribute + { + [JsonInclude] + public int MyInt { get; private init; } + } + + public class Class_PropertyWith_InternalInitOnlySetter_WithAttribute + { + [JsonInclude] + public int MyInt { get; internal init; } + } + + public class Class_PropertyWith_ProtectedInitOnlySetter_WithAttribute + { + [JsonInclude] + public int MyInt { get; protected init; } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 808880d9af6a4..74459b8f4f6b7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -99,6 +99,7 @@ +