Skip to content

Commit

Permalink
Remove usage of System.Text.Json for now (#1637)
Browse files Browse the repository at this point in the history
* started moving back to newtonsoft json

* removed system text json

* update change log

* nit

---------

Co-authored-by: David Mueller x <[email protected]>
  • Loading branch information
daveMueller and David Mueller x authored Mar 8, 2024
1 parent 813f36c commit 6bd8783
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 83 deletions.
1 change: 0 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Reflection.Metadata" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.2" />
<PackageVersion Include="Tmds.ExecFunction" Version="0.7.1" />
<PackageVersion Include="xunit" Version="2.6.6" />
<PackageVersion Include="xunit.assemblyfixture" Version="2.2.0" />
Expand Down
1 change: 1 addition & 0 deletions Documentation/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
- Threshold-stat triggers error [#1634](https://github.com/coverlet-coverage/coverlet/issues/1634)
- Fixed coverlet collector 6.0.1 requires dotnet sdk 8 [#1625](https://github.com/coverlet-coverage/coverlet/issues/1625)
- Exception when multiple exclude-by-attribute filters specified [#1624](https://github.com/coverlet-coverage/coverlet/issues/1624)

### Improvements
Expand Down
18 changes: 5 additions & 13 deletions src/coverlet.core/Coverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Nodes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Instrumentation;
Expand Down Expand Up @@ -60,14 +60,6 @@ internal class Coverage

public string Identifier { get; }

readonly JsonSerializerOptions _options = new()
{
PropertyNameCaseInsensitive = true,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
IncludeFields = true,
WriteIndented = true
};

public Coverage(string moduleOrDirectory,
CoverageParameters parameters,
ILogger logger,
Expand Down Expand Up @@ -325,7 +317,7 @@ public CoverageResult GetCoverageResult()
{
_logger.LogInformation($"MergeWith: '{_parameters.MergeWith}'.");
string json = _fileSystem.ReadAllText(_parameters.MergeWith);
coverageResult.Merge(JsonSerializer.Deserialize<Modules>(json, _options));
coverageResult.Merge(JsonConvert.DeserializeObject<Modules>(json));
} else
{
_logger.LogInformation($"MergeWith: file '{_parameters.MergeWith}' does not exist.");
Expand Down Expand Up @@ -387,8 +379,8 @@ private void CalculateCoverage()
var documents = result.Documents.Values.ToList();
if (_parameters.UseSourceLink && result.SourceLink != null)
{
JsonNode jObject = JsonNode.Parse(result.SourceLink)["documents"];
Dictionary<string, string> sourceLinkDocuments = JsonSerializer.Deserialize<Dictionary<string, string>>(jObject.ToString());
JToken jObject = JObject.Parse(result.SourceLink)["documents"];
Dictionary<string, string> sourceLinkDocuments = JsonConvert.DeserializeObject<Dictionary<string, string>>(jObject.ToString());
foreach (Document document in documents)
{
document.Path = GetSourceLinkUrl(sourceLinkDocuments, document.Path);
Expand Down
8 changes: 3 additions & 5 deletions src/coverlet.core/CoverageResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Coverlet.Core.Enums;
using Coverlet.Core.Instrumentation;

Expand All @@ -23,11 +22,10 @@ internal class Branches : List<BranchInfo> { }

internal class Method
{
[JsonConstructor]
public Method()
internal Method()
{
Lines = [];
Branches = [];
Lines = new Lines();
Branches = new Branches();
}

public Lines Lines;
Expand Down
21 changes: 10 additions & 11 deletions src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Exceptions;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.DependencyModel.Resolution;
using Mono.Cecil;
using Newtonsoft.Json.Linq;
using NuGet.Versioning;

namespace Coverlet.Core.Instrumentation
Expand Down Expand Up @@ -298,25 +298,24 @@ public RuntimeConfigurationReader(string runtimeConfigFile)
{
string jsonString = File.ReadAllText(_runtimeConfigFile);

var documentOptions = new JsonDocumentOptions
var jsonLoadSettings = new JsonLoadSettings()
{
CommentHandling = JsonCommentHandling.Skip
CommentHandling = CommentHandling.Ignore
};

using var configuration = JsonDocument.Parse(jsonString, documentOptions);
var configuration = JObject.Parse(jsonString, jsonLoadSettings);

JsonElement rootElement = configuration.RootElement;
JToken rootElement = configuration.Root;
JToken runtimeOptionsElement = rootElement["runtimeOptions"];

JsonElement runtimeOptionsElement = rootElement.GetProperty("runtimeOptions");

if (runtimeOptionsElement.TryGetProperty("framework", out JsonElement frameworkElement))
if (runtimeOptionsElement?["framework"] != null)
{
return new[] { (frameworkElement.GetProperty("name").GetString(), frameworkElement.GetProperty("version").GetString()) };
return new[] { (runtimeOptionsElement["framework"]["name"]?.Value<string>(), runtimeOptionsElement["framework"]["version"]?.Value<string>()) };
}

if (runtimeOptionsElement.TryGetProperty("frameworks", out JsonElement frameworksElement))
if (runtimeOptionsElement?["frameworks"] != null)
{
return frameworksElement.EnumerateArray().Select(x => (x.GetProperty("name").GetString(), x.GetProperty("version").GetString())).ToList();
return runtimeOptionsElement["frameworks"].Select(x => (x["name"]?.Value<string>(), x["version"]?.Value<string>())).ToList();
}

throw new InvalidOperationException($"Unable to read runtime configuration from {_runtimeConfigFile}.");
Expand Down
11 changes: 2 additions & 9 deletions src/coverlet.core/Reporters/JsonReporter.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Text.Encodings.Web;
using System.Text.Json;
using Coverlet.Core.Abstractions;
using Newtonsoft.Json;

namespace Coverlet.Core.Reporters
{
Expand All @@ -17,13 +16,7 @@ internal class JsonReporter : IReporter

public string Report(CoverageResult result, ISourceRootTranslator _)
{
var options = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
IncludeFields = true,
WriteIndented = true,
};
return JsonSerializer.Serialize(result.Modules, options);
return JsonConvert.SerializeObject(result.Modules, Formatting.Indented);
}
}
}
2 changes: 1 addition & 1 deletion src/coverlet.core/coverlet.core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" VersionOverride="6.0.1"/>
<PackageReference Include="Mono.Cecil" />
<PackageReference Include="NuGet.Versioning" />
<PackageReference Include="System.Text.Json" VersionOverride="6.0.9"/>
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
Expand Down
68 changes: 25 additions & 43 deletions test/coverlet.core.tests/Coverage/CoverageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,23 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using Coverlet.Core.Abstractions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Instrumentation;
using Coverlet.Core.Symbols;
using Moq;
using Newtonsoft.Json;
using Xunit;

namespace Coverlet.Core.Tests
{
public partial class CoverageTests
{
private readonly Mock<ILogger> _mockLogger = new();
readonly JsonSerializerOptions _options = new()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
IncludeFields = true,
WriteIndented = true,
Converters =
{
new BranchDictionaryConverterFactory()
}
};

[Fact]
public void TestCoverage()
Expand Down Expand Up @@ -102,7 +91,7 @@ public void TestCoverageWithTestAssembly()
new SourceRootTranslator(module, _mockLogger.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper());
coverage.PrepareModules();

string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options);
string result = JsonConvert.SerializeObject(coverage.GetCoverageResult(), Formatting.Indented, new BranchDictionaryConverter());

Assert.Contains("coverlet.core.tests.dll", result);

Expand Down Expand Up @@ -141,7 +130,7 @@ public void TestCoverageMergeWithParameter()
var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper());
coverage.PrepareModules();

string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options);
string result = JsonConvert.SerializeObject(coverage.GetCoverageResult(), Formatting.Indented, new BranchDictionaryConverter());

Assert.Contains("DeepThought.cs", result);

Expand Down Expand Up @@ -182,51 +171,44 @@ public void TestCoverageMergeWithWrongParameter()
var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper());
coverage.PrepareModules();

string result = JsonSerializer.Serialize(coverage.GetCoverageResult(), _options);
JsonConvert.SerializeObject(coverage.GetCoverageResult());

_mockLogger.Verify(l => l.LogInformation(It.Is<string>(v => v.Equals("MergeWith: file 'FileDoesNotExist.json' does not exist.")), It.IsAny<bool>()), Times.Once);

directory.Delete(true);
}
}
}
public class BranchDictionaryConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
return typeof(Dictionary<BranchKey, Branch>).IsAssignableFrom(typeToConvert);
}

public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
public class BranchDictionaryConverter: JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Type[] genericArgs = typeToConvert.GetGenericArguments();
Type keyType = genericArgs[0];
Type valueType = genericArgs[1];
Type type = value.GetType();
var keys = (IEnumerable)type.GetProperty("Keys")?.GetValue(value, null);
var values = (IEnumerable)type.GetProperty("Values")?.GetValue(value, null);
IEnumerator valueEnumerator = values.GetEnumerator();

JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(BranchDictionaryConverter<,>).MakeGenericType(new Type[] { keyType, valueType }));
writer.WriteStartArray();
foreach (object key in keys)
{
valueEnumerator.MoveNext();

return converter;
writer.WriteStartArray();
serializer.Serialize(writer, key);
serializer.Serialize(writer, valueEnumerator.Current);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
}

public class BranchDictionaryConverter<TKey, TValue> : JsonConverter<Dictionary<TKey, TValue>>
{
public override Dictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override void Write(Utf8JsonWriter writer, Dictionary<TKey, TValue> value, JsonSerializerOptions options)
public override bool CanConvert(Type objectType)
{
writer.WriteStartObject();

foreach (KeyValuePair<TKey, TValue> pair in value)
{
writer.WritePropertyName(pair.Key.ToString());
JsonSerializer.Serialize(writer, pair.Value, options);
}

writer.WriteEndObject();
return typeof(Dictionary<BranchKey, Branch>).IsAssignableFrom(objectType);
}
}

0 comments on commit 6bd8783

Please sign in to comment.