Skip to content

Commit

Permalink
chore: Add MarkdigExtensionSetting json roundtrip tests
Browse files Browse the repository at this point in the history
  • Loading branch information
filzrev committed Sep 28, 2024
1 parent 3b3bd35 commit aece12e
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 94 deletions.
10 changes: 8 additions & 2 deletions src/Docfx.Common/Json/JsonUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,18 @@ private static bool IsSupported()
var type = typeof(T);
var fullName = type.FullName;

// TODO: Return `true` for types that support serialize/deserializenon with System.Text.Json.
switch (fullName)
{
// 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;


// Intermediate types for tests. it's expected to be removed later (And return true by default).
case "Docfx.Plugins.MarkdownServiceProperties":
return true;

// TODO: default to true
default:
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static SystemTextJsonUtility()
NumberHandling = JsonNumberHandling.AllowReadingFromString,
Converters =
{
// new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
new ObjectToInferredTypesConverter(), // Required for `Dictionary<string, object>` type deserialization.
},
WriteIndented = false,
Expand Down
14 changes: 3 additions & 11 deletions src/Docfx.MarkdigEngine.Extensions/MarkdigExtensionSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,10 @@ namespace Docfx.MarkdigEngine.Extensions;
/// Markdig extension setting.
/// </summary>
[DebuggerDisplay("Name = {Name}")]
[Newtonsoft.Json.JsonConverter(typeof(MarkdigExtensionSettingConverter))]
[Newtonsoft.Json.JsonConverter(typeof(MarkdigExtensionSettingConverter.NewtonsoftJsonConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(MarkdigExtensionSettingConverter.SystemTextJsonConverter))]
public class MarkdigExtensionSetting
{
private static readonly JsonSerializerOptions DefaultSerializerOptions = new()
{
AllowTrailingCommas = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = {
new JsonStringEnumConverter()
},
};

/// <summary>
/// Initializes a new instance of the <see cref="MarkdigExtensionSetting"/> class.
/// </summary>
Expand Down Expand Up @@ -59,7 +51,7 @@ public MarkdigExtensionSetting(string name, JsonNode? options = null)
public T GetOptions<T>(T fallbackValue)
{
return Options is null ? fallbackValue
: JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(Options), DefaultSerializerOptions) ?? fallbackValue;
: JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(Options), MarkdigExtensionSettingConverter.DefaultSerializerOptions) ?? fallbackValue;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;

namespace Docfx.MarkdigEngine.Extensions;

internal partial class MarkdigExtensionSettingConverter
{
internal class NewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
{
/// <inheritdoc/>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MarkdigExtensionSetting);
}

/// <inheritdoc/>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// var value = reader.Value;
switch (reader.TokenType)
{
case JsonToken.String:
{
var name = (string)reader.Value;
return new MarkdigExtensionSetting(name);
}
case JsonToken.StartObject:
{
var jObj = JObject.Load(reader);

var props = jObj.Properties().ToArray();

// Object key must be the name of markdig extension.
if (props.Length != 1)
return null;

var prop = props[0];
var name = prop.Name;

var options = prop.Value;
if (options.Count() == 0)
{
return new MarkdigExtensionSetting(name);
}

// Convert JToken to JsonElement.
var json = options.ToString();
using var doc = System.Text.Json.JsonDocument.Parse(json);
var jsonElement = doc.RootElement.Clone();

return new MarkdigExtensionSetting(name)
{
Options = jsonElement,
};
}

default:
return null;
}
}

/// <inheritdoc/>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
return;

var model = (MarkdigExtensionSetting)value;

if (model.Options == null || !model.Options.HasValue)
{
writer.WriteValue(model.Name);
}
else
{
writer.WriteStartObject();
writer.WritePropertyName(model.Name);
var json = model.Options.ToString();
writer.WriteRawValue(json);
writer.WriteEndObject();
}
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
using System.Xml.Linq;

namespace Docfx.MarkdigEngine.Extensions;

internal partial class MarkdigExtensionSettingConverter
{
internal class SystemTextJsonConverter : JsonConverter<MarkdigExtensionSetting>
{
public override MarkdigExtensionSetting Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.String:
{
var name = reader.GetString();
return new MarkdigExtensionSetting(name);
}
case JsonTokenType.StartObject:
{
var elem = JsonElement.ParseValue(ref reader);

var props = elem.EnumerateObject().ToArray();

// Object key must be the name of markdig extension.
if (props.Length != 1)
return null;

var prop = props[0];
var name = prop.Name;
var value = prop.Value;

if (value.ValueKind != JsonValueKind.Object)
{
return new MarkdigExtensionSetting(name);
}

return new MarkdigExtensionSetting(name)
{
Options = value,
};
}

default:
return null;
}
}

public override void Write(Utf8JsonWriter writer, MarkdigExtensionSetting value, JsonSerializerOptions options)
{
if (value == null)
return;

var model = (MarkdigExtensionSetting)value;

if (model.Options == null || !model.Options.HasValue)
{
writer.WriteStringValue(model.Name);
}
else
{
writer.WriteStartObject();
writer.WritePropertyName(model.Name);
var json = model.Options.ToString();
writer.WriteRawValue(json);
writer.WriteEndObject();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,96 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Docfx.MarkdigEngine.Extensions;

internal class MarkdigExtensionSettingConverter : Newtonsoft.Json.JsonConverter
internal partial class MarkdigExtensionSettingConverter
{
// JsonSerializerOptions that used to deserialize MarkdigExtension options.
// Shared JsonSerializerOptions instance.
internal static readonly System.Text.Json.JsonSerializerOptions DefaultSerializerOptions = new()
{
IncludeFields = true,
AllowTrailingCommas = true,
DictionaryKeyPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
Converters = {
new System.Text.Json.Serialization.JsonStringEnumConverter()
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
},
WriteIndented = false,
};

/// <inheritdoc/>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MarkdigExtensionSetting);
}

/// <inheritdoc/>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// var value = reader.Value;
switch (reader.TokenType)
{
case JsonToken.String:
{
var name = (string)reader.Value;
return new MarkdigExtensionSetting(name);
}
case JsonToken.StartObject:
{
var jObj = JObject.Load(reader);

var props = jObj.Properties().ToArray();

// Object key must be the name of markdig extension.
if (props.Length != 1)
return null;

var prop = props[0];
var name = prop.Name;

var options = prop.Value;
if (options.Count() == 0)
{
return new MarkdigExtensionSetting(name);
}

// Serialize options to JsonElement.
var jsonElement = System.Text.Json.JsonSerializer.SerializeToElement(options, DefaultSerializerOptions);

return new MarkdigExtensionSetting(name)
{
Options = jsonElement,
};
}

default:
return null;
}
}

/// <inheritdoc/>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
return;

var model = (MarkdigExtensionSetting)value;

if (model.Options == null || !model.Options.HasValue)
{
writer.WriteValue(model.Name);
}
else
{
writer.WriteStartObject();
writer.WritePropertyName(model.Name);
var json = model.Options.ToString();
writer.WriteRawValue(json);
writer.WriteEndObject();
}
}
}

3 changes: 2 additions & 1 deletion test/docfx.Tests/Api.verified.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3575,8 +3575,9 @@ public LineNumberExtension(System.Func<object, string> getFilePath = null) { }
public void Setup(Markdig.MarkdownPipelineBuilder pipeline) { }
public void Setup(Markdig.MarkdownPipeline pipeline, Markdig.Renderers.IMarkdownRenderer renderer) { }
}
[Newtonsoft.Json.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter))]
[Newtonsoft.Json.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter.NewtonsoftJsonConverter))]
[System.Diagnostics.DebuggerDisplay("Name = {Name}")]
[System.Text.Json.Serialization.JsonConverter(typeof(Docfx.MarkdigEngine.Extensions.MarkdigExtensionSettingConverter.SystemTextJsonConverter))]
public class MarkdigExtensionSetting
{
public MarkdigExtensionSetting(string name, System.Text.Json.Nodes.JsonNode? options = null) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using Docfx;
using Docfx.Common;
using Docfx.MarkdigEngine.Extensions;
using Docfx.Plugins;
using FluentAssertions;

namespace docfx.Tests;

public partial class JsonSerializationTest
{
[Theory]
[TestData<MarkdownServiceProperties>]
public void JsonSerializationTest_MarkdownServiceProperties(string path)
{
// Arrange
var model = TestData.Load<MarkdownServiceProperties>(path);

// Act/Assert
ValidateJsonRoundTrip(model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"enableSourceInfo": false,
"markdigExtensions": [
"FootNotes",
{ "Emojis": "default" },
{ "AutoIdentifiers": "default" },
{
"MediaLinks": {
"width": 800,
"height": 400
}
}
],
"fallbackFolders": [
"fallbackdir"
],
"alerts": {
"TODO": "alert alert-secondary"
},
"plantUml": {
"javaPath": "dummy",
"localGraphvizDotPath": "dummy",
"localPlantUmlPath": "dummy",
"outputFormat": "svg",
"remoteUrl": "dummy",
"renderingMode": "local"
}
}

0 comments on commit aece12e

Please sign in to comment.