Skip to content

Commit 7b3dd78

Browse files
committed
chore: Add MarkdigExtensionSetting json roundtrip tests
1 parent 2fa823a commit 7b3dd78

File tree

9 files changed

+238
-94
lines changed

9 files changed

+238
-94
lines changed

src/Docfx.Common/Json/JsonUtility.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,18 @@ private static bool IsSupported()
8787
var type = typeof(T);
8888
var fullName = type.FullName;
8989

90-
// TODO: Return `true` for types that support serialize/deserializenon with System.Text.Json.
9190
switch (fullName)
9291
{
92+
// TODO: Return `true` for types that support serialize/deserializenon with System.Text.Json.
9393
case "Docfx.Build.Engine.XRefMap":
94+
case "Docfx.DataContracts.ManagedReference.PageViewModel":
9495
return true;
95-
96+
97+
// Intermediate types for tests. it's expected to be removed later (And return true by default).
98+
case "Docfx.Plugins.MarkdownServiceProperties":
99+
return true;
100+
101+
// TODO: default to true
96102
default:
97103
return false;
98104
}

src/Docfx.Common/Json/System.Text.Json/SystemTextJsonUtility.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static SystemTextJsonUtility()
4040
NumberHandling = JsonNumberHandling.AllowReadingFromString,
4141
Converters =
4242
{
43-
// new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
43+
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
4444
new ObjectToInferredTypesConverter(), // Required for `Dictionary<string, object>` type deserialization.
4545
},
4646
WriteIndented = false,

src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,10 @@ namespace Docfx.MarkdigEngine.Extensions;
1414
/// Markdig extension setting.
1515
/// </summary>
1616
[DebuggerDisplay("Name = {Name}")]
17-
[Newtonsoft.Json.JsonConverter(typeof(MarkdigExtensionSettingConverter))]
17+
[Newtonsoft.Json.JsonConverter(typeof(MarkdigExtensionSettingConverter.NewtonsoftJsonConverter))]
18+
[System.Text.Json.Serialization.JsonConverter(typeof(MarkdigExtensionSettingConverter.SystemTextJsonConverter))]
1819
public class MarkdigExtensionSetting
1920
{
20-
private static readonly JsonSerializerOptions DefaultSerializerOptions = new()
21-
{
22-
AllowTrailingCommas = true,
23-
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
24-
Converters = {
25-
new JsonStringEnumConverter()
26-
},
27-
};
28-
2921
/// <summary>
3022
/// Initializes a new instance of the <see cref="MarkdigExtensionSetting"/> class.
3123
/// </summary>
@@ -59,7 +51,7 @@ public MarkdigExtensionSetting(string name, JsonNode? options = null)
5951
public T GetOptions<T>(T fallbackValue)
6052
{
6153
return Options is null ? fallbackValue
62-
: JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(Options), DefaultSerializerOptions) ?? fallbackValue;
54+
: JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(Options), MarkdigExtensionSettingConverter.DefaultSerializerOptions) ?? fallbackValue;
6355
}
6456

6557
/// <summary>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Newtonsoft.Json.Linq;
5+
using Newtonsoft.Json;
6+
7+
namespace Docfx.MarkdigEngine.Extensions;
8+
9+
internal partial class MarkdigExtensionSettingConverter
10+
{
11+
internal class NewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
12+
{
13+
/// <inheritdoc/>
14+
public override bool CanConvert(Type objectType)
15+
{
16+
return objectType == typeof(MarkdigExtensionSetting);
17+
}
18+
19+
/// <inheritdoc/>
20+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
21+
{
22+
// var value = reader.Value;
23+
switch (reader.TokenType)
24+
{
25+
case JsonToken.String:
26+
{
27+
var name = (string)reader.Value;
28+
return new MarkdigExtensionSetting(name);
29+
}
30+
case JsonToken.StartObject:
31+
{
32+
var jObj = JObject.Load(reader);
33+
34+
var props = jObj.Properties().ToArray();
35+
36+
// Object key must be the name of markdig extension.
37+
if (props.Length != 1)
38+
return null;
39+
40+
var prop = props[0];
41+
var name = prop.Name;
42+
43+
var options = prop.Value;
44+
if (options.Count() == 0)
45+
{
46+
return new MarkdigExtensionSetting(name);
47+
}
48+
49+
// Convert JToken to JsonElement.
50+
var json = options.ToString();
51+
using var doc = System.Text.Json.JsonDocument.Parse(json);
52+
var jsonElement = doc.RootElement.Clone();
53+
54+
return new MarkdigExtensionSetting(name)
55+
{
56+
Options = jsonElement,
57+
};
58+
}
59+
60+
default:
61+
return null;
62+
}
63+
}
64+
65+
/// <inheritdoc/>
66+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
67+
{
68+
if (value == null)
69+
return;
70+
71+
var model = (MarkdigExtensionSetting)value;
72+
73+
if (model.Options == null || !model.Options.HasValue)
74+
{
75+
writer.WriteValue(model.Name);
76+
}
77+
else
78+
{
79+
writer.WriteStartObject();
80+
writer.WritePropertyName(model.Name);
81+
var json = model.Options.ToString();
82+
writer.WriteRawValue(json);
83+
writer.WriteEndObject();
84+
}
85+
}
86+
}
87+
}
88+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
6+
using System.Text.Json.Nodes;
7+
using System.Xml.Linq;
8+
9+
namespace Docfx.MarkdigEngine.Extensions;
10+
11+
internal partial class MarkdigExtensionSettingConverter
12+
{
13+
internal class SystemTextJsonConverter : JsonConverter<MarkdigExtensionSetting>
14+
{
15+
public override MarkdigExtensionSetting Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
16+
{
17+
switch (reader.TokenType)
18+
{
19+
case JsonTokenType.String:
20+
{
21+
var name = reader.GetString();
22+
return new MarkdigExtensionSetting(name);
23+
}
24+
case JsonTokenType.StartObject:
25+
{
26+
var elem = JsonElement.ParseValue(ref reader);
27+
28+
var props = elem.EnumerateObject().ToArray();
29+
30+
// Object key must be the name of markdig extension.
31+
if (props.Length != 1)
32+
return null;
33+
34+
var prop = props[0];
35+
var name = prop.Name;
36+
var value = prop.Value;
37+
38+
if (value.ValueKind != JsonValueKind.Object)
39+
{
40+
return new MarkdigExtensionSetting(name);
41+
}
42+
43+
return new MarkdigExtensionSetting(name)
44+
{
45+
Options = value,
46+
};
47+
}
48+
49+
default:
50+
return null;
51+
}
52+
}
53+
54+
public override void Write(Utf8JsonWriter writer, MarkdigExtensionSetting value, JsonSerializerOptions options)
55+
{
56+
if (value == null)
57+
return;
58+
59+
var model = (MarkdigExtensionSetting)value;
60+
61+
if (model.Options == null || !model.Options.HasValue)
62+
{
63+
writer.WriteStringValue(model.Name);
64+
}
65+
else
66+
{
67+
writer.WriteStartObject();
68+
writer.WritePropertyName(model.Name);
69+
var json = model.Options.ToString();
70+
writer.WriteRawValue(json);
71+
writer.WriteEndObject();
72+
}
73+
}
74+
}
75+
}
Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,25 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Newtonsoft.Json;
5-
using Newtonsoft.Json.Linq;
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
66

77
namespace Docfx.MarkdigEngine.Extensions;
88

9-
internal class MarkdigExtensionSettingConverter : Newtonsoft.Json.JsonConverter
9+
internal partial class MarkdigExtensionSettingConverter
1010
{
11-
// JsonSerializerOptions that used to deserialize MarkdigExtension options.
11+
// Shared JsonSerializerOptions instance.
1212
internal static readonly System.Text.Json.JsonSerializerOptions DefaultSerializerOptions = new()
1313
{
1414
IncludeFields = true,
1515
AllowTrailingCommas = true,
16-
DictionaryKeyPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
17-
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
16+
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
17+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
1818
PropertyNameCaseInsensitive = true,
1919
Converters = {
20-
new System.Text.Json.Serialization.JsonStringEnumConverter()
20+
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
2121
},
2222
WriteIndented = false,
2323
};
24-
25-
/// <inheritdoc/>
26-
public override bool CanConvert(Type objectType)
27-
{
28-
return objectType == typeof(MarkdigExtensionSetting);
29-
}
30-
31-
/// <inheritdoc/>
32-
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
33-
{
34-
// var value = reader.Value;
35-
switch (reader.TokenType)
36-
{
37-
case JsonToken.String:
38-
{
39-
var name = (string)reader.Value;
40-
return new MarkdigExtensionSetting(name);
41-
}
42-
case JsonToken.StartObject:
43-
{
44-
var jObj = JObject.Load(reader);
45-
46-
var props = jObj.Properties().ToArray();
47-
48-
// Object key must be the name of markdig extension.
49-
if (props.Length != 1)
50-
return null;
51-
52-
var prop = props[0];
53-
var name = prop.Name;
54-
55-
var options = prop.Value;
56-
if (options.Count() == 0)
57-
{
58-
return new MarkdigExtensionSetting(name);
59-
}
60-
61-
// Serialize options to JsonElement.
62-
var jsonElement = System.Text.Json.JsonSerializer.SerializeToElement(options, DefaultSerializerOptions);
63-
64-
return new MarkdigExtensionSetting(name)
65-
{
66-
Options = jsonElement,
67-
};
68-
}
69-
70-
default:
71-
return null;
72-
}
73-
}
74-
75-
/// <inheritdoc/>
76-
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
77-
{
78-
if (value == null)
79-
return;
80-
81-
var model = (MarkdigExtensionSetting)value;
82-
83-
if (model.Options == null || !model.Options.HasValue)
84-
{
85-
writer.WriteValue(model.Name);
86-
}
87-
else
88-
{
89-
writer.WriteStartObject();
90-
writer.WritePropertyName(model.Name);
91-
var json = model.Options.ToString();
92-
writer.WriteRawValue(json);
93-
writer.WriteEndObject();
94-
}
95-
}
9624
}
25+

test/docfx.Tests/Api.verified.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3575,8 +3575,9 @@ public LineNumberExtension(System.Func<object, string> getFilePath = null) { }
35753575
public void Setup(Markdig.MarkdownPipelineBuilder pipeline) { }
35763576
public void Setup(Markdig.MarkdownPipeline pipeline, Markdig.Renderers.IMarkdownRenderer renderer) { }
35773577
}
3578-
[Newtonsoft.Json.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter))]
3578+
[Newtonsoft.Json.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter.NewtonsoftJsonConverter))]
35793579
[System.Diagnostics.DebuggerDisplay("Name = {Name}")]
3580+
[System.Text.Json.Serialization.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter.SystemTextJsonConverter))]
35803581
public class MarkdigExtensionSetting
35813582
{
35823583
public MarkdigExtensionSetting(string name, System.Text.Json.Nodes.JsonNode? options = null) { }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text.Json;
5+
using Docfx;
6+
using Docfx.Common;
7+
using Docfx.MarkdigEngine.Extensions;
8+
using Docfx.Plugins;
9+
using FluentAssertions;
10+
11+
namespace docfx.Tests;
12+
13+
public partial class JsonSerializationTest
14+
{
15+
[Theory]
16+
[TestData<MarkdownServiceProperties>]
17+
public void JsonSerializationTest_MarkdownServiceProperties(string path)
18+
{
19+
// Arrange
20+
var model = TestData.Load<MarkdownServiceProperties>(path);
21+
22+
// Act/Assert
23+
ValidateJsonRoundTrip(model);
24+
}
25+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"enableSourceInfo": false,
3+
"markdigExtensions": [
4+
"FootNotes",
5+
{ "Emojis": "default" },
6+
{ "AutoIdentifiers": "default" },
7+
{
8+
"MediaLinks": {
9+
"width": 800,
10+
"height": 400
11+
}
12+
}
13+
],
14+
"fallbackFolders": [
15+
"fallbackdir"
16+
],
17+
"alerts": {
18+
"TODO": "alert alert-secondary"
19+
},
20+
"plantUml": {
21+
"javaPath": "dummy",
22+
"localGraphvizDotPath": "dummy",
23+
"localPlantUmlPath": "dummy",
24+
"outputFormat": "svg",
25+
"remoteUrl": "dummy",
26+
"renderingMode": "local"
27+
}
28+
}

0 commit comments

Comments
 (0)