From 82f07be915f55a898b42206710f1156356aaddf8 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Wed, 12 Jun 2019 22:58:08 -0700 Subject: [PATCH] Add [DebuggerDisplay] to Json types (dotnet/corefx#38275) * Add [DebuggerDisplay] to Json types Note that there is an issue with turning the TokenType to string in Utf8JsonReader. Probably reflection related? I've been unable to create a more focused repro. * Add some simple sanity tests * Address some feedback. * Use JsonValueType Commit migrated from https://github.com/dotnet/corefx/commit/b506d4a4ff6ffe1a1877016811e2266eacc2ebbc --- .../Json/Document/JsonElement.ArrayEnumerator.cs | 1 + .../Json/Document/JsonElement.ObjectEnumerator.cs | 1 + .../src/System/Text/Json/Document/JsonElement.cs | 7 ++-- .../src/System/Text/Json/Document/JsonProperty.cs | 5 +++ .../src/System/Text/Json/Reader/Utf8JsonReader.cs | 24 +++++++++++++ .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 3 ++ .../System.Text.Json/tests/DebuggerTests.cs | 42 ++++++++++++++++++++++ .../tests/System.Text.Json.Tests.csproj | 1 + .../tests/TestClasses.ClassWithComplexObjects.cs | 3 +- 9 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/libraries/System.Text.Json/tests/DebuggerTests.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ArrayEnumerator.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ArrayEnumerator.cs index 53dda79..2362bdd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ArrayEnumerator.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ArrayEnumerator.cs @@ -13,6 +13,7 @@ namespace System.Text.Json /// /// An enumerable and enumerator for the contents of a JSON array. /// + [DebuggerDisplay("{Current,nq}")] public struct ArrayEnumerator : IEnumerable, IEnumerator { private readonly JsonElement _target; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ObjectEnumerator.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ObjectEnumerator.cs index 2b6bcbe..2b2b40a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ObjectEnumerator.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.ObjectEnumerator.cs @@ -13,6 +13,7 @@ namespace System.Text.Json /// /// An enumerable and enumerator for the properties of a JSON object. /// + [DebuggerDisplay("{Current,nq}")] public struct ObjectEnumerator : IEnumerable, IEnumerator { private readonly JsonElement _target; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs index e30ce73..fb26d2a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs @@ -2,18 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Buffers; -using System.Buffers.Text; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.InteropServices; namespace System.Text.Json { /// /// Represents a specific JSON value within a . /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] public readonly partial struct JsonElement { private readonly JsonDocument _parent; @@ -1286,5 +1283,7 @@ namespace System.Text.Json throw new InvalidOperationException(); } } + + private string DebuggerDisplay => $"Type = {Type} : \"{ToString()}\""; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs index 41900da..4b999a5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs @@ -3,12 +3,14 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; namespace System.Text.Json { /// /// Represents a single property for a JSON object. /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] public readonly struct JsonProperty { /// @@ -99,5 +101,8 @@ namespace System.Text.Json { return Value.GetPropertyRawText(); } + + private string DebuggerDisplay + => Value.Type == JsonValueType.Undefined ? "" : $"\"{ToString()}\""; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs index 74811ea..cae8054 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs @@ -19,6 +19,7 @@ namespace System.Text.Json /// To be able to set max depth while reading OR allow skipping comments, create an instance of /// and pass that in to the reader. /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] public ref partial struct Utf8JsonReader { private ReadOnlySpan _buffer; @@ -2434,5 +2435,28 @@ namespace System.Text.Json _tokenType = JsonTokenType.Comment; return true; } + + private string DebuggerDisplay => $"TokenType = {DebugTokenType} (TokenStartIndex = {TokenStartIndex}) Consumed = {BytesConsumed}"; + + // Using TokenType.ToString() (or {TokenType}) fails to render in the debug window. The + // message "The runtime refused to evaluate the expression at this time." is shown. This + // is a workaround until we root cause and fix the issue. + private string DebugTokenType + => TokenType switch + { + JsonTokenType.Comment => nameof(JsonTokenType.Comment), + JsonTokenType.EndArray => nameof(JsonTokenType.EndArray), + JsonTokenType.EndObject => nameof(JsonTokenType.EndObject), + JsonTokenType.False => nameof(JsonTokenType.False), + JsonTokenType.None => nameof(JsonTokenType.None), + JsonTokenType.Null => nameof(JsonTokenType.Null), + JsonTokenType.Number => nameof(JsonTokenType.Number), + JsonTokenType.PropertyName => nameof(JsonTokenType.PropertyName), + JsonTokenType.StartArray => nameof(JsonTokenType.StartArray), + JsonTokenType.StartObject => nameof(JsonTokenType.StartObject), + JsonTokenType.String => nameof(JsonTokenType.String), + JsonTokenType.True => nameof(JsonTokenType.True), + _ => ((byte)TokenType).ToString() + }; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs index 41101c7..9ac6d57 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs @@ -30,6 +30,7 @@ namespace System.Text.Json /// To be able to format the output with indentation and whitespace OR to skip validation, create an instance of /// and pass that in to the writer. /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] public sealed partial class Utf8JsonWriter : IDisposable #if BUILDING_INBOX_LIBRARY , IAsyncDisposable @@ -1091,5 +1092,7 @@ namespace System.Text.Json { _currentDepth |= 1 << 31; } + + private string DebuggerDisplay => $"BytesCommitted = {BytesCommitted} BytesPending = {BytesPending} CurrentDepth = {CurrentDepth}"; } } diff --git a/src/libraries/System.Text.Json/tests/DebuggerTests.cs b/src/libraries/System.Text.Json/tests/DebuggerTests.cs new file mode 100644 index 0000000..13a50ca --- /dev/null +++ b/src/libraries/System.Text.Json/tests/DebuggerTests.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Reflection; +using Xunit; + +namespace System.Text.Json.Tests +{ + public class DebuggerTests + { + [Fact] + public void DefaultJsonElement() + { + // Validating that we don't throw on default + JsonElement element = default; + GetDebuggerDisplayProperty(element); + } + + [Fact] + public void DefaultJsonProperty() + { + // Validating that we don't throw on default + JsonProperty property = default; + GetDebuggerDisplayProperty(property); + } + + [Fact] + public void DefaultUtf8JsonWriter() + { + // Validating that we don't throw on new object + Utf8JsonWriter writer = new Utf8JsonWriter(new MemoryStream()); + GetDebuggerDisplayProperty(writer); + } + + private static string GetDebuggerDisplayProperty(T value) + { + return (string)typeof(T).GetProperty("DebuggerDisplay", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(value); + } + } +} 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 6795834..a5388f1 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 @@ -11,6 +11,7 @@ + diff --git a/src/libraries/System.Text.Json/tests/TestClasses.ClassWithComplexObjects.cs b/src/libraries/System.Text.Json/tests/TestClasses.ClassWithComplexObjects.cs index da8cc66..502905d 100644 --- a/src/libraries/System.Text.Json/tests/TestClasses.ClassWithComplexObjects.cs +++ b/src/libraries/System.Text.Json/tests/TestClasses.ClassWithComplexObjects.cs @@ -51,7 +51,8 @@ namespace System.Text.Json.Serialization.Tests Assert.IsType(Object); JsonElement jsonObject = (JsonElement)Object; Assert.Equal(JsonValueType.Object, jsonObject.Type); - JsonProperty property = jsonObject.EnumerateObject().First(); + JsonElement.ObjectEnumerator enumerator = jsonObject.EnumerateObject(); + JsonProperty property = enumerator.First(); Assert.Equal("NestedArray", property.Name); Assert.True(property.NameEquals("NestedArray")); ValidateArray(property.Value); -- 2.7.4