From f636b8d86216feeaab13ee1aa8f91d5d6df14d5a Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 27 Sep 2024 06:58:38 +0900 Subject: [PATCH] chore: add ManagedReference YAML roundtrip tests --- src/Docfx.Common/Json/JsonUtility.cs | 4 +- .../JTokenConverter.cs | 20 ++ .../ReferenceViewModel.cs | 14 +- .../ManagedReference/Models/ItemViewModel.cs | 14 +- .../Models/SyntaxDetailViewModel.cs | 14 +- test/docfx.Tests/Api.verified.cs | 3 + .../ManagedReference/BuildFromAssembly.yml | 32 ++ .../BuildFromCSharpSourceCode.CSharp.yml | 340 ++++++++++++++++++ .../TestData/ManagedReference/api.yml | 23 ++ .../YamlSerializationTest.ManagedReference.cs | 24 ++ 10 files changed, 481 insertions(+), 7 deletions(-) create mode 100644 test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromAssembly.yml create mode 100644 test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromCSharpSourceCode.CSharp.yml create mode 100644 test/docfx.Tests/SerializationTests/TestData/ManagedReference/api.yml create mode 100644 test/docfx.Tests/SerializationTests/YamlSerializationTest.ManagedReference.cs diff --git a/src/Docfx.Common/Json/JsonUtility.cs b/src/Docfx.Common/Json/JsonUtility.cs index 0f0b3c471e4..e20b0df1983 100644 --- a/src/Docfx.Common/Json/JsonUtility.cs +++ b/src/Docfx.Common/Json/JsonUtility.cs @@ -91,9 +91,11 @@ private static bool IsSupported() { // TODO: Return `true` for types that support serialize/deserializenon with System.Text.Json. case "Docfx.Build.Engine.XRefMap": - case "Docfx.DataContracts.ManagedReference.PageViewModel": return true; + case "Docfx.DataContracts.ManagedReference.PageViewModel": + return true; // TODO: Need to support ExtensionData + // Intermediate types for tests. it's expected to be removed later (And return true by default). case "Docfx.Plugins.MarkdownServiceProperties": return true; diff --git a/src/Docfx.DataContracts.Common/JTokenConverter.cs b/src/Docfx.DataContracts.Common/JTokenConverter.cs index d8d170127e8..64564775551 100644 --- a/src/Docfx.DataContracts.Common/JTokenConverter.cs +++ b/src/Docfx.DataContracts.Common/JTokenConverter.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Docfx.Common; using Newtonsoft.Json.Linq; namespace Docfx.DataContracts.Common; @@ -18,6 +20,24 @@ public static T Convert(object obj) { return jToken.ToObject(); } + + // Custom code path for `System.Text.Json` deserialization. + // `ObjectToInferredTypesConverter` deserialize items as `List`. + // So it need to convert `List` to `List`. + if (obj is List list && IsListType()) + { + var json = JsonUtility.Serialize(list); + var result = JsonUtility.Deserialize(new StringReader(json)); + return result; + } + throw new InvalidCastException(); } + + private static bool IsListType() + { + var type = typeof(T); + return type.GetTypeInfo().IsGenericType + && type.GetGenericTypeDefinition() == typeof(List<>); + } } diff --git a/src/Docfx.DataContracts.Common/ReferenceViewModel.cs b/src/Docfx.DataContracts.Common/ReferenceViewModel.cs index 71e1f36b81a..7810640f850 100644 --- a/src/Docfx.DataContracts.Common/ReferenceViewModel.cs +++ b/src/Docfx.DataContracts.Common/ReferenceViewModel.cs @@ -86,10 +86,14 @@ public class ReferenceViewModel [YamlIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [UniqueIdentityReferenceIgnore] [MarkdownContentIgnore] - public CompositeDictionary AdditionalJson => - CompositeDictionary + public CompositeDictionary AdditionalJson + { + get + { + return CompositeDictionary .CreateBuilder() .Add(Constants.ExtensionMemberPrefix.Name, NameInDevLangs, JTokenConverter.Convert) .Add(Constants.ExtensionMemberPrefix.NameWithType, NameWithTypeInDevLangs, JTokenConverter.Convert) @@ -97,6 +101,12 @@ public class ReferenceViewModel .Add(Constants.ExtensionMemberPrefix.Spec, Specs, JTokenConverter.Convert>) .Add(string.Empty, Additional) .Create(); + } + private init + { + // init or getter is required for deserialize data with System.Text.Json. + } + } public ReferenceViewModel Clone() { diff --git a/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs b/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs index 80252839716..d86d942c69c 100644 --- a/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs +++ b/src/Docfx.Dotnet/ManagedReference/Models/ItemViewModel.cs @@ -378,14 +378,24 @@ public string FullNameForVB [YamlIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [UniqueIdentityReferenceIgnore] [MarkdownContentIgnore] - public IDictionary ExtensionData => - CompositeDictionary + public IDictionary ExtensionData + { + get + { + return CompositeDictionary .CreateBuilder() .Add(Constants.ExtensionMemberPrefix.Name, Names, JTokenConverter.Convert) .Add(Constants.ExtensionMemberPrefix.NameWithType, NamesWithType, JTokenConverter.Convert) .Add(Constants.ExtensionMemberPrefix.FullName, FullNames, JTokenConverter.Convert) .Add(string.Empty, Metadata) .Create(); + } + private init + { + // init or getter is required for deserialize data with System.Text.Json. + } + } } diff --git a/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs b/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs index 330470f034b..8aa49b39a22 100644 --- a/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs +++ b/src/Docfx.Dotnet/ManagedReference/Models/SyntaxDetailViewModel.cs @@ -89,11 +89,21 @@ public string ContentForVB [YamlIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [UniqueIdentityReferenceIgnore] [MarkdownContentIgnore] - public IDictionary ExtensionData => - CompositeDictionary + public IDictionary ExtensionData + { + get + { + return CompositeDictionary .CreateBuilder() .Add(Constants.ExtensionMemberPrefix.Content, Contents, JTokenConverter.Convert) .Create(); + } + private init + { + // init or getter is required for deserialize data with System.Text.Json. + } + } } diff --git a/test/docfx.Tests/Api.verified.cs b/test/docfx.Tests/Api.verified.cs index 126141a7185..ce9d5f0f674 100644 --- a/test/docfx.Tests/Api.verified.cs +++ b/test/docfx.Tests/Api.verified.cs @@ -2503,6 +2503,7 @@ public ReferenceViewModel() { } [Docfx.DataContracts.Common.UniqueIdentityReferenceIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [YamlDotNet.Serialization.YamlIgnore] public Docfx.Common.CompositeDictionary AdditionalJson { get; } [Newtonsoft.Json.JsonProperty("commentId")] @@ -2877,6 +2878,7 @@ public ItemViewModel() { } [Docfx.DataContracts.Common.UniqueIdentityReferenceIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [YamlDotNet.Serialization.YamlIgnore] public System.Collections.Generic.IDictionary ExtensionData { get; } [Docfx.Common.EntityMergers.MergeOption(Docfx.Common.EntityMergers.MergeOption.Ignore)] @@ -3152,6 +3154,7 @@ public SyntaxDetailViewModel() { } [Docfx.DataContracts.Common.UniqueIdentityReferenceIgnore] [Newtonsoft.Json.JsonExtensionData] [System.Text.Json.Serialization.JsonExtensionData] + [System.Text.Json.Serialization.JsonInclude] [YamlDotNet.Serialization.YamlIgnore] public System.Collections.Generic.IDictionary ExtensionData { get; } [Newtonsoft.Json.JsonProperty("parameters")] diff --git a/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromAssembly.yml b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromAssembly.yml new file mode 100644 index 00000000000..99b16874956 --- /dev/null +++ b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromAssembly.yml @@ -0,0 +1,32 @@ +### YamlMime:ManagedReference +items: +- uid: BuildFromAssembly + commentId: N:BuildFromAssembly + id: BuildFromAssembly + children: + - BuildFromAssembly.Class1 + - BuildFromAssembly.Issue5432 + langs: + - csharp + - vb + name: BuildFromAssembly + nameWithType: BuildFromAssembly + fullName: BuildFromAssembly + type: Namespace + assemblies: + - BuildFromAssembly +references: +- uid: BuildFromAssembly.Class1 + commentId: T:BuildFromAssembly.Class1 + isExternal: true + href: BuildFromAssembly.Class1.html + name: Class1 + nameWithType: Class1 + fullName: BuildFromAssembly.Class1 +- uid: BuildFromAssembly.Issue5432 + commentId: T:BuildFromAssembly.Issue5432 + isExternal: true + href: BuildFromAssembly.Issue5432.html + name: Issue5432 + nameWithType: Issue5432 + fullName: BuildFromAssembly.Issue5432 diff --git a/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromCSharpSourceCode.CSharp.yml b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromCSharpSourceCode.CSharp.yml new file mode 100644 index 00000000000..cd06419191c --- /dev/null +++ b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/BuildFromCSharpSourceCode.CSharp.yml @@ -0,0 +1,340 @@ +### YamlMime:ManagedReference +items: +- uid: BuildFromCSharpSourceCode.CSharp + commentId: T:BuildFromCSharpSourceCode.CSharp + id: CSharp + parent: BuildFromCSharpSourceCode + children: + - BuildFromCSharpSourceCode.CSharp.Main(System.String[]) + langs: + - csharp + - vb + name: CSharp + nameWithType: CSharp + fullName: BuildFromCSharpSourceCode.CSharp + type: Class + source: + remote: + path: samples/seed/dotnet/csharp/CSharp.cs + branch: main + repo: https://github.com/dotnet/docfx + id: CSharp + path: dotnet/csharp/CSharp.cs + startLine: 7 + namespace: BuildFromCSharpSourceCode + syntax: + content: public class CSharp + content.vb: Public Class CSharp + inheritance: + - System.Object + inheritedMembers: + - System.Object.Equals(System.Object) + - System.Object.Equals(System.Object,System.Object) + - System.Object.GetHashCode + - System.Object.GetType + - System.Object.MemberwiseClone + - System.Object.ReferenceEquals(System.Object,System.Object) + - System.Object.ToString +- uid: BuildFromCSharpSourceCode.CSharp.Main(System.String[]) + commentId: M:BuildFromCSharpSourceCode.CSharp.Main(System.String[]) + id: Main(System.String[]) + parent: BuildFromCSharpSourceCode.CSharp + langs: + - csharp + - vb + name: Main(string[]) + nameWithType: CSharp.Main(string[]) + fullName: BuildFromCSharpSourceCode.CSharp.Main(string[]) + type: Method + source: + remote: + path: samples/seed/dotnet/csharp/CSharp.cs + branch: main + repo: https://github.com/dotnet/docfx + id: Main + path: dotnet/csharp/CSharp.cs + startLine: 9 + namespace: BuildFromCSharpSourceCode + syntax: + content: public static void Main(string[] args) + parameters: + - id: args + type: System.String[] + content.vb: Public Shared Sub Main(args As String()) + overload: BuildFromCSharpSourceCode.CSharp.Main* + nameWithType.vb: CSharp.Main(String()) + fullName.vb: BuildFromCSharpSourceCode.CSharp.Main(String()) + name.vb: Main(String()) +references: +- uid: BuildFromCSharpSourceCode + commentId: N:BuildFromCSharpSourceCode + href: BuildFromCSharpSourceCode.html + name: BuildFromCSharpSourceCode + nameWithType: BuildFromCSharpSourceCode + fullName: BuildFromCSharpSourceCode +- uid: System.Object + commentId: T:System.Object + parent: System + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + name: object + nameWithType: object + fullName: object + nameWithType.vb: Object + fullName.vb: Object + name.vb: Object +- uid: System.Object.Equals(System.Object) + commentId: M:System.Object.Equals(System.Object) + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + name: Equals(object) + nameWithType: object.Equals(object) + fullName: object.Equals(object) + nameWithType.vb: Object.Equals(Object) + fullName.vb: Object.Equals(Object) + name.vb: Equals(Object) + spec.csharp: + - uid: System.Object.Equals(System.Object) + name: Equals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - name: ( + - uid: System.Object + name: object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) + spec.vb: + - uid: System.Object.Equals(System.Object) + name: Equals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - name: ( + - uid: System.Object + name: Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) +- uid: System.Object.Equals(System.Object,System.Object) + commentId: M:System.Object.Equals(System.Object,System.Object) + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + name: Equals(object, object) + nameWithType: object.Equals(object, object) + fullName: object.Equals(object, object) + nameWithType.vb: Object.Equals(Object, Object) + fullName.vb: Object.Equals(Object, Object) + name.vb: Equals(Object, Object) + spec.csharp: + - uid: System.Object.Equals(System.Object,System.Object) + name: Equals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - name: ( + - uid: System.Object + name: object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ',' + - name: " " + - uid: System.Object + name: object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) + spec.vb: + - uid: System.Object.Equals(System.Object,System.Object) + name: Equals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - name: ( + - uid: System.Object + name: Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ',' + - name: " " + - uid: System.Object + name: Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) +- uid: System.Object.GetHashCode + commentId: M:System.Object.GetHashCode + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + name: GetHashCode() + nameWithType: object.GetHashCode() + fullName: object.GetHashCode() + nameWithType.vb: Object.GetHashCode() + fullName.vb: Object.GetHashCode() + spec.csharp: + - uid: System.Object.GetHashCode + name: GetHashCode + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - name: ( + - name: ) + spec.vb: + - uid: System.Object.GetHashCode + name: GetHashCode + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - name: ( + - name: ) +- uid: System.Object.GetType + commentId: M:System.Object.GetType + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gettype + name: GetType() + nameWithType: object.GetType() + fullName: object.GetType() + nameWithType.vb: Object.GetType() + fullName.vb: Object.GetType() + spec.csharp: + - uid: System.Object.GetType + name: GetType + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gettype + - name: ( + - name: ) + spec.vb: + - uid: System.Object.GetType + name: GetType + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.gettype + - name: ( + - name: ) +- uid: System.Object.MemberwiseClone + commentId: M:System.Object.MemberwiseClone + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + name: MemberwiseClone() + nameWithType: object.MemberwiseClone() + fullName: object.MemberwiseClone() + nameWithType.vb: Object.MemberwiseClone() + fullName.vb: Object.MemberwiseClone() + spec.csharp: + - uid: System.Object.MemberwiseClone + name: MemberwiseClone + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - name: ( + - name: ) + spec.vb: + - uid: System.Object.MemberwiseClone + name: MemberwiseClone + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - name: ( + - name: ) +- uid: System.Object.ReferenceEquals(System.Object,System.Object) + commentId: M:System.Object.ReferenceEquals(System.Object,System.Object) + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + name: ReferenceEquals(object, object) + nameWithType: object.ReferenceEquals(object, object) + fullName: object.ReferenceEquals(object, object) + nameWithType.vb: Object.ReferenceEquals(Object, Object) + fullName.vb: Object.ReferenceEquals(Object, Object) + name.vb: ReferenceEquals(Object, Object) + spec.csharp: + - uid: System.Object.ReferenceEquals(System.Object,System.Object) + name: ReferenceEquals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - name: ( + - uid: System.Object + name: object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ',' + - name: " " + - uid: System.Object + name: object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) + spec.vb: + - uid: System.Object.ReferenceEquals(System.Object,System.Object) + name: ReferenceEquals + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - name: ( + - uid: System.Object + name: Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ',' + - name: " " + - uid: System.Object + name: Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object + - name: ) +- uid: System.Object.ToString + commentId: M:System.Object.ToString + parent: System.Object + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.tostring + name: ToString() + nameWithType: object.ToString() + fullName: object.ToString() + nameWithType.vb: Object.ToString() + fullName.vb: Object.ToString() + spec.csharp: + - uid: System.Object.ToString + name: ToString + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.tostring + - name: ( + - name: ) + spec.vb: + - uid: System.Object.ToString + name: ToString + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.object.tostring + - name: ( + - name: ) +- uid: System + commentId: N:System + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system + name: System + nameWithType: System + fullName: System +- uid: BuildFromCSharpSourceCode.CSharp.Main* + commentId: Overload:BuildFromCSharpSourceCode.CSharp.Main + href: BuildFromCSharpSourceCode.CSharp.html#BuildFromCSharpSourceCode_CSharp_Main_System_String___ + name: Main + nameWithType: CSharp.Main + fullName: BuildFromCSharpSourceCode.CSharp.Main +- uid: System.String[] + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.string + name: string[] + nameWithType: string[] + fullName: string[] + nameWithType.vb: String() + fullName.vb: String() + name.vb: String() + spec.csharp: + - uid: System.String + name: string + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.string + - name: '[' + - name: ']' + spec.vb: + - uid: System.String + name: String + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.string + - name: ( + - name: ) diff --git a/test/docfx.Tests/SerializationTests/TestData/ManagedReference/api.yml b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/api.yml new file mode 100644 index 00000000000..91ba59c1bd1 --- /dev/null +++ b/test/docfx.Tests/SerializationTests/TestData/ManagedReference/api.yml @@ -0,0 +1,23 @@ +### YamlMime:ManagedReference +items: +- uid: dummy1 + source: + remote: + path: dummy1.cs + branch: main + repo: https://github.com/dotnet/docfx +- uid: dummy2 + source: + remote: + path: dummy2.cs + branch: main + repo: https://github.com/dotnet/docfx +references: + - uid: System.String + name: string + isExternal: true + href: https://learn.microsoft.com/dotnet/api/system.string +shouldSkipMarkup: false +memberLayout: separatePages +additionalMetadata1: 1 +additionalMetadata2: 2 diff --git a/test/docfx.Tests/SerializationTests/YamlSerializationTest.ManagedReference.cs b/test/docfx.Tests/SerializationTests/YamlSerializationTest.ManagedReference.cs new file mode 100644 index 00000000000..3012c8a890f --- /dev/null +++ b/test/docfx.Tests/SerializationTests/YamlSerializationTest.ManagedReference.cs @@ -0,0 +1,24 @@ +// 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; +using System.Runtime.CompilerServices; +using Docfx.DataContracts.ManagedReference; +using FluentAssertions; + +namespace docfx.Tests; + +public partial class YamlSerializationTest +{ + [Theory] + [TestData] + public void YamlSerializationTest_ManagedReference(string path) + { + // Arrange + var model = TestData.Load(path); + + // Act/Assert + ValidateYamlRoundTrip(model); + ValidateYamlJsonRoundTrip(model); + } +}