From b0e800383a814e011da98396b83e896b8ebf64e7 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sat, 25 Nov 2023 15:59:09 +0100 Subject: [PATCH 01/27] Add IndentText json option --- .../System.Text.Json/ref/System.Text.Json.cs | 2 ++ .../JsonSerializerOptions.Caching.cs | 2 ++ .../Serialization/JsonSerializerOptions.cs | 24 ++++++++++++++++++ .../Text/Json/Writer/JsonWriterHelper.cs | 12 +++++++++ .../Text/Json/Writer/JsonWriterOptions.cs | 15 +++++++++++ .../Utf8JsonWriter.WriteProperties.Bytes.cs | 4 +-- ...Utf8JsonWriter.WriteProperties.DateTime.cs | 4 +-- ...onWriter.WriteProperties.DateTimeOffset.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Decimal.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Double.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Float.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Guid.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Helpers.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.Literal.cs | 4 +-- ...JsonWriter.WriteProperties.SignedNumber.cs | 4 +-- .../Utf8JsonWriter.WriteProperties.String.cs | 12 ++++----- ...onWriter.WriteProperties.UnsignedNumber.cs | 4 +-- .../Utf8JsonWriter.WriteValues.Bytes.cs | 2 +- .../Utf8JsonWriter.WriteValues.Comment.cs | 4 +-- .../Utf8JsonWriter.WriteValues.DateTime.cs | 2 +- ...f8JsonWriter.WriteValues.DateTimeOffset.cs | 2 +- .../Utf8JsonWriter.WriteValues.Decimal.cs | 2 +- .../Utf8JsonWriter.WriteValues.Double.cs | 2 +- .../Utf8JsonWriter.WriteValues.Float.cs | 2 +- ...8JsonWriter.WriteValues.FormattedNumber.cs | 2 +- .../Writer/Utf8JsonWriter.WriteValues.Guid.cs | 2 +- .../Utf8JsonWriter.WriteValues.Literal.cs | 2 +- ...Utf8JsonWriter.WriteValues.SignedNumber.cs | 2 +- .../Utf8JsonWriter.WriteValues.String.cs | 4 +-- ...f8JsonWriter.WriteValues.UnsignedNumber.cs | 2 +- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 25 ++++++++++++++++--- .../Serialization/CacheTests.cs | 1 + .../Serialization/OptionsTests.cs | 4 +++ 33 files changed, 125 insertions(+), 46 deletions(-) diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 0a308dbe6afa96..85785c70c0d819 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -394,6 +394,7 @@ public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } public System.Text.Json.Serialization.JsonUnknownTypeHandling UnknownTypeHandling { get { throw null; } set { } } public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } + public string? IndentText { get { throw null; } set { } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("JsonSerializerOptions.AddContext is obsolete. To register a JsonSerializerContext, use either the TypeInfoResolver or TypeInfoResolverChain properties.", DiagnosticId="SYSLIB0049", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public void AddContext() where TContext : System.Text.Json.Serialization.JsonSerializerContext, new() { } @@ -439,6 +440,7 @@ public partial struct JsonWriterOptions private int _dummyPrimitive; public System.Text.Encodings.Web.JavaScriptEncoder? Encoder { readonly get { throw null; } set { } } public bool Indented { get { throw null; } set { } } + public string? IndentText { get { throw null; } set { } } public int MaxDepth { readonly get { throw null; } set { } } public bool SkipValidation { get { throw null; } set { } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs index 68551c7eedf12a..394cfd4c441eab 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs @@ -511,6 +511,7 @@ public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right) left._includeFields == right._includeFields && left._propertyNameCaseInsensitive == right._propertyNameCaseInsensitive && left._writeIndented == right._writeIndented && + left._indentText == right._indentText && left._typeInfoResolver == right._typeInfoResolver && CompareLists(left._converters, right._converters); @@ -565,6 +566,7 @@ public int GetHashCode(JsonSerializerOptions options) AddHashCode(ref hc, options._includeFields); AddHashCode(ref hc, options._propertyNameCaseInsensitive); AddHashCode(ref hc, options._writeIndented); + AddHashCode(ref hc, options._indentText?.GetHashCode() ?? 0); AddHashCode(ref hc, options._typeInfoResolver); AddListHashCode(ref hc, options._converters); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 30792d75d53bc9..1f694b71ee3b8d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -75,6 +75,7 @@ public static JsonSerializerOptions Default private bool _includeFields; private bool _propertyNameCaseInsensitive; private bool _writeIndented; + private string? _indentText; /// /// Constructs a new instance. @@ -124,6 +125,7 @@ public JsonSerializerOptions(JsonSerializerOptions options) _includeFields = options._includeFields; _propertyNameCaseInsensitive = options._propertyNameCaseInsensitive; _writeIndented = options._writeIndented; + _indentText = options._indentText; _typeInfoResolver = options._typeInfoResolver; EffectiveMaxDepth = options.EffectiveMaxDepth; ReferenceHandlingStrategy = options.ReferenceHandlingStrategy; @@ -645,6 +647,27 @@ public bool WriteIndented } } + /// + /// Defines the text used as indent when is enabled + /// By default, the JSON is indented with 2 white spaces. + /// + /// + /// Thrown if this property is set after serialization or deserialization has occurred. + /// + public string? IndentText + { + get + { + return _indentText; + } + set + { + VerifyMutable(); + // Validation? + _indentText = value; + } + } + /// /// Configures how object references are handled when reading and writing JSON. /// @@ -876,6 +899,7 @@ internal JsonWriterOptions GetWriterOptions() { Encoder = Encoder, Indented = WriteIndented, + IndentText = IndentText, MaxDepth = EffectiveMaxDepth, #if !DEBUG SkipValidation = true diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 97037ddbff7270..dda96253bca198 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -32,6 +32,18 @@ public static void WriteIndentation(Span buffer, int indent) } } + public static void WriteIndentation(Span buffer, int indentation, Span indent) + { + Debug.Assert(buffer.Length >= indentation); + + int offset = 0; + while (offset < indentation) + { + indent.CopyTo(buffer.Slice(offset)); + offset += indent.Length; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateProperty(ReadOnlySpan propertyName) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 2d89a261e33535..f662317a6da49e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -17,6 +17,7 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; + private string? _indentText; /// /// The encoder to use when escaping strings, or to use the default encoder. @@ -43,6 +44,20 @@ public bool Indented } } + /// + /// Defines the text used as indent by the when is enabled + /// By default, the JSON is written with 2 white spaces. + /// + public string? IndentText + { + get => _indentText; + set + { + // Validation? + _indentText = value; + } + } + /// /// Gets or sets the maximum depth allowed when writing JSON, with the default (i.e. 0) indicating a max depth of 1000. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs index 9c4785e56bfab1..435005e7ecc47b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs @@ -309,7 +309,7 @@ private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -359,7 +359,7 @@ private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs index 55c079f008faa2..154c28d34babef 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs @@ -311,7 +311,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -359,7 +359,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs index 9ace783d791e48..80485289695967 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs @@ -310,7 +310,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -358,7 +358,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs index 933fcffc4fc1b1..452cf44b339e08 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs @@ -304,7 +304,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -349,7 +349,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs index 73bcc75f72edeb..ca3c5ca65e200b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs @@ -308,7 +308,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -353,7 +353,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs index bb695740d290fa..27c0255b61c299 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs @@ -308,7 +308,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float v WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -353,7 +353,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float v WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs index a0c5713374ca1b..a46dc3ebbf7d9c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs @@ -312,7 +312,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid va WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -361,7 +361,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid va WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs index cd56c0a99aa9e3..808d9c679ee850 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs @@ -115,7 +115,7 @@ private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, b WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -188,7 +188,7 @@ private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, b WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs index e73131b7192f93..cce486a5e7883c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs @@ -455,7 +455,7 @@ private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOn WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -500,7 +500,7 @@ private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOn WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs index 10c390a98ffc43..d60cbe66fcf05b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs @@ -380,7 +380,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long va WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -425,7 +425,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long va WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs index 7db29516ddbe0f..f0939ab11a8f00 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs @@ -213,7 +213,7 @@ private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyN WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -402,7 +402,7 @@ private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyN WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -1541,7 +1541,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -1590,7 +1590,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -1642,7 +1642,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -1693,7 +1693,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs index ab73c36582c640..7188e889aafede 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs @@ -389,7 +389,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong v WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; @@ -434,7 +434,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong v WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = JsonConstants.Quote; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs index 6d04df1c3ce6e6..d4b3e49627b0fb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs @@ -124,7 +124,7 @@ private void WriteBase64Indented(ReadOnlySpan bytes) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs index 7e3d3a30d661be..e56f894d6b6964 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs @@ -123,7 +123,7 @@ private void WriteCommentIndented(ReadOnlySpan value) if (_tokenType != JsonTokenType.None || _commentAfterNoneOrPropertyName) { WriteNewLine(output); - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } @@ -230,7 +230,7 @@ private void WriteCommentIndented(ReadOnlySpan utf8Value) { WriteNewLine(output); - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs index f87753be0ae37d..5bb765eaca59f2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs @@ -89,7 +89,7 @@ private void WriteStringValueIndented(DateTime value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs index 2608606375b396..7f55861794151a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs @@ -90,7 +90,7 @@ private void WriteStringValueIndented(DateTimeOffset value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs index 2462b667fe8ba1..947a9788170eda 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs @@ -85,7 +85,7 @@ private void WriteNumberValueIndented(decimal value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs index 036b9e3d122547..691e49b8532f56 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs @@ -89,7 +89,7 @@ private void WriteNumberValueIndented(double value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs index 5e173a7dc0ecee..0cd1a6614eff25 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs @@ -89,7 +89,7 @@ private void WriteNumberValueIndented(float value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs index f9005243fac4c6..6747646a23dad3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs @@ -91,7 +91,7 @@ private void WriteNumberValueIndented(ReadOnlySpan utf8Value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs index 227af26a3d2c00..6e91872d7f7694 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs @@ -90,7 +90,7 @@ private void WriteStringValueIndented(Guid value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs index b4bcc5b480246c..490cb6ad6b0819 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs @@ -109,7 +109,7 @@ private void WriteLiteralIndented(ReadOnlySpan utf8Value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs index dd47dfe230550f..55dbb9734ee57f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs @@ -98,7 +98,7 @@ private void WriteNumberValueIndented(long value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs index 6513d001930b77..f6215c9f68300b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs @@ -169,7 +169,7 @@ private void WriteStringIndented(ReadOnlySpan escapedValue) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } @@ -315,7 +315,7 @@ private void WriteStringIndented(ReadOnlySpan escapedValue) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs index a348c125c8172c..d068a433f5d363 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs @@ -100,7 +100,7 @@ private void WriteNumberValueIndented(ulong value) { WriteNewLine(output); } - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } 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 c84b864a0cfec6..abb3d6474f8241 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 @@ -56,6 +56,8 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable // else, no list separator is needed since we are writing the first item. private int _currentDepth; + private Memory? _indentBytes; + private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. /// @@ -80,7 +82,11 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int Indentation => CurrentDepth * JsonConstants.SpacesPerIndent; + private int IndentLength => _options.IndentText?.Length ?? JsonConstants.SpacesPerIndent; + + private int Indentation => CurrentDepth * IndentLength; + + private Memory IndentBytes => _indentBytes ??= _options.IndentText is not null ? Encoding.UTF8.GetBytes(_options.IndentText) : default; internal JsonTokenType TokenType => _tokenType; @@ -573,7 +579,7 @@ private void WriteStartIndented(byte token) if (_tokenType is not JsonTokenType.PropertyName and not JsonTokenType.None || _commentAfterNoneOrPropertyName) { WriteNewLine(output); - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; } @@ -1011,7 +1017,7 @@ private void WriteEndIndented(byte token) WriteNewLine(output); - JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent); + WriteIndentation(output.Slice(BytesPending), indent); BytesPending += indent; output[BytesPending++] = token; @@ -1029,6 +1035,19 @@ private void WriteNewLine(Span output) output[BytesPending++] = JsonConstants.LineFeed; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteIndentation(Span buffer, int indentation) + { + if (_options.IndentText is null) + { + JsonWriterHelper.WriteIndentation(buffer, indentation); + } + else + { + JsonWriterHelper.WriteIndentation(buffer, indentation, IndentBytes.Span); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void UpdateBitStackOnStart(byte token) { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs index 979defdc010ac5..22e937224325b2 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs @@ -372,6 +372,7 @@ public static void JsonSerializerOptions_EqualityComparer_ChangingAnySettingShou yield return (GetProp(nameof(JsonSerializerOptions.ReadCommentHandling)), JsonCommentHandling.Skip); yield return (GetProp(nameof(JsonSerializerOptions.UnknownTypeHandling)), JsonUnknownTypeHandling.JsonNode); yield return (GetProp(nameof(JsonSerializerOptions.WriteIndented)), true); + yield return (GetProp(nameof(JsonSerializerOptions.IndentText)), "\t"); yield return (GetProp(nameof(JsonSerializerOptions.ReferenceHandler)), ReferenceHandler.Preserve); yield return (GetProp(nameof(JsonSerializerOptions.TypeInfoResolver)), new DefaultJsonTypeInfoResolver()); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index c63dccb61653c3..e291972c6a5a08 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -1288,6 +1288,10 @@ and not nameof(JsonSerializerOptions.IsReadOnly)) // Property is not structural { property.SetValue(options, 32); } + else if (propertyType == typeof(string)) + { + property.SetValue(options, "\t"); + } else if (propertyType == typeof(IList)) { options.Converters.Add(new JsonStringEnumConverter()); From d283b538fa60f0be86cf143cd6972b1236d3a66f Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:25:39 +0100 Subject: [PATCH 02/27] Add IndentText for json source generator --- .../Common/JsonSourceGenerationOptionsAttribute.cs | 5 +++++ .../System.Text.Json/gen/JsonSourceGenerator.Emitter.cs | 3 +++ .../System.Text.Json/gen/JsonSourceGenerator.Parser.cs | 6 ++++++ .../gen/Model/SourceGenerationOptionsSpec.cs | 2 ++ src/libraries/System.Text.Json/ref/System.Text.Json.cs | 1 + .../JsonSourceGenerationOptionsTests.cs | 3 ++- 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs index 8084d4a6f613f2..e33106823aab7d 100644 --- a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs +++ b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs @@ -125,6 +125,11 @@ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults) /// public bool WriteIndented { get; set; } + /// + /// Specifies the default value of when set. + /// + public string? IndentText { get; set; } + /// /// Specifies the default source generation mode for type declarations that don't set a . /// diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 90575721c507d7..4a70521c490903 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -1168,6 +1168,9 @@ private static void GetLogicForDefaultSerializerOptionsInit(SourceGenerationOpti if (optionsSpec.WriteIndented is bool writeIndented) writer.WriteLine($"WriteIndented = {FormatBool(writeIndented)},"); + if (optionsSpec.IndentText is string indentText) + writer.WriteLine($"IndentText = {FormatStringLiteral(indentText)},"); + writer.Indentation--; writer.WriteLine("};"); diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 594f7ad9770c3c..f455ebdd5c6557 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -280,6 +280,7 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN JsonUnmappedMemberHandling? unmappedMemberHandling = null; bool? useStringEnumConverter = null; bool? writeIndented = null; + string? indentText = null; if (attributeData.ConstructorArguments.Length > 0) { @@ -373,6 +374,10 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN writeIndented = (bool)namedArg.Value.Value!; break; + case nameof(JsonSourceGenerationOptionsAttribute.IndentText): + indentText = (string?)namedArg.Value.Value; + break; + case nameof(JsonSourceGenerationOptionsAttribute.GenerationMode): generationMode = (JsonSourceGenerationMode)namedArg.Value.Value!; break; @@ -404,6 +409,7 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN UnmappedMemberHandling = unmappedMemberHandling, UseStringEnumConverter = useStringEnumConverter, WriteIndented = writeIndented, + IndentText = indentText, }; } diff --git a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs index 83b587fb962f7e..b5e6331d9843e0 100644 --- a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs @@ -52,6 +52,8 @@ public sealed record SourceGenerationOptionsSpec public required bool? WriteIndented { get; init; } + public required string? IndentText { get; init; } + public JsonKnownNamingPolicy? GetEffectivePropertyNamingPolicy() => PropertyNamingPolicy ?? (Defaults is JsonSerializerDefaults.Web ? JsonKnownNamingPolicy.CamelCase : null); } diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 85785c70c0d819..ec12cd39cc7bf7 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -1076,6 +1076,7 @@ public JsonSourceGenerationOptionsAttribute(System.Text.Json.JsonSerializerDefau public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool UseStringEnumConverter { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } + public string? IndentText { get { throw null; } set { } } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JsonStringEnumConverter cannot be statically analyzed and requires runtime code generation. Applications should use the generic JsonStringEnumConverter instead.")] public partial class JsonStringEnumConverter : System.Text.Json.Serialization.JsonConverterFactory diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs index eb855b0241dfd5..8ee653f9474989 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs @@ -104,7 +104,8 @@ public static void ContextWithAllOptionsSet_GeneratesExpectedOptions() ReadCommentHandling = JsonCommentHandling.Skip, UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode, UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, - WriteIndented = true)] + WriteIndented = true, + IndentText = "\t")] [JsonSerializable(typeof(PersonStruct))] public partial class ContextWithAllOptionsSet : JsonSerializerContext { } From eb0d433a0b2028f89d0d99ead1698e687a11211d Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:54:58 +0100 Subject: [PATCH 03/27] Add tests --- .../Utf8JsonWriter.WriteProperties.Helpers.cs | 4 +- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 4 +- .../JsonSourceGenerationOptionsTests.cs | 1 + .../JsonWriterOptionsTests.cs | 13 +- .../Utf8JsonWriterTests.cs | 1553 ++++++----------- 5 files changed, 570 insertions(+), 1005 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs index 808d9c679ee850..881075e1239991 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs @@ -89,7 +89,7 @@ private void WritePropertyNameMinimized(ReadOnlySpan escapedPropertyName, private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, byte token) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= IndentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - 6 - s_newLineLength); @@ -161,7 +161,7 @@ private void WritePropertyNameMinimized(ReadOnlySpan escapedPropertyName, private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, byte token) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= IndentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 6 - s_newLineLength); 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 abb3d6474f8241..1ed85fe8f6fbf6 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 @@ -559,7 +559,7 @@ private void ValidateStart() private void WriteStartIndented(byte token) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= IndentLength * _options.MaxDepth); int minRequired = indent + 1; // 1 start token int maxRequired = minRequired + 3; // Optionally, 1 list separator and 1-2 bytes for new line @@ -1000,7 +1000,7 @@ private void WriteEndIndented(byte token) { // The end token should be at an outer indent and since we haven't updated // current depth yet, explicitly subtract here. - indent -= JsonConstants.SpacesPerIndent; + indent -= IndentLength; } Debug.Assert(indent <= 2 * _options.MaxDepth); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs index 8ee653f9474989..1257e168bc0020 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs @@ -78,6 +78,7 @@ public static void ContextWithAllOptionsSet_GeneratesExpectedOptions() UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode, UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, WriteIndented = true, + IndentText = "\t", TypeInfoResolver = ContextWithAllOptionsSet.Default, }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 41a6c5c203a917..c17c33326a39eb 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -29,6 +29,7 @@ public static void JsonWriterOptionsCtor() var expectedOption = new JsonWriterOptions { Indented = false, + IndentText = null, SkipValidation = false, MaxDepth = 0, }; @@ -36,20 +37,22 @@ public static void JsonWriterOptionsCtor() } [Theory] - [InlineData(true, true, 0)] - [InlineData(true, false, 1)] - [InlineData(false, true, 1024)] - [InlineData(false, false, 1024 * 1024)] - public static void JsonWriterOptions(bool indented, bool skipValidation, int maxDepth) + [InlineData(true, "\t", true, 0)] + [InlineData(true, " ", false, 1)] + [InlineData(false, "", true, 1024)] + [InlineData(false, "", false, 1024 * 1024)] + public static void JsonWriterOptions(bool indented, string indentText, bool skipValidation, int maxDepth) { var options = new JsonWriterOptions(); options.Indented = indented; + options.IndentText = indentText; options.SkipValidation = skipValidation; options.MaxDepth = maxDepth; var expectedOption = new JsonWriterOptions { Indented = indented, + IndentText = indentText, SkipValidation = skipValidation, MaxDepth = maxDepth, }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index 331f81947ae5d5..526693055c84c7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -15,6 +15,7 @@ using Microsoft.DotNet.XUnitExtensions; using Newtonsoft.Json; using Xunit; +using System.Linq; namespace System.Text.Json.Tests { @@ -64,15 +65,14 @@ public partial class Utf8JsonWriterTests /*Comment at start of doc*//*Multiple comment line*/{/*Comment before first object property*//*Multiple comment line*/"property1":/*Comment of string property value*/"stringValue","property2":/*Comment of object property value*/{}/*Comment in the middle of object*/,"property3":/*Comment of array property value*/[]/*Comment after the last property*/}/*Comment at end of doc*/ """; + public static IEnumerable JsonOptions_TestData() => + from options in JsonOptions() + select new object[] { options }; + [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void NullCtor(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void NullCtor(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - Assert.Throws(() => new Utf8JsonWriter((Stream)null)); Assert.Throws(() => new Utf8JsonWriter((IBufferWriter)null)); Assert.Throws(() => new Utf8JsonWriter((Stream)null, options)); @@ -80,13 +80,9 @@ public void NullCtor(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void CantWriteToNonWritableStream(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void CantWriteToNonWritableStream(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var stream = new MemoryStream(); stream.Dispose(); @@ -836,14 +832,9 @@ public void WriteLargeJsonToStreamWithoutFlushing() } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InitialState(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InitialState(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var stream = new MemoryStream(); using (var writer = new Utf8JsonWriter(stream, options)) { @@ -851,8 +842,8 @@ public void InitialState(bool formatted, bool skipValidation) Assert.Equal(0, writer.BytesPending); Assert.Equal(0, writer.CurrentDepth); Assert.Null(writer.Options.Encoder); - Assert.Equal(formatted, writer.Options.Indented); - Assert.Equal(skipValidation, writer.Options.SkipValidation); + Assert.Equal(options.Indented, writer.Options.Indented); + Assert.Equal(options.SkipValidation, writer.Options.SkipValidation); Assert.Equal(0, stream.Position); } @@ -863,21 +854,16 @@ public void InitialState(bool formatted, bool skipValidation) Assert.Equal(0, writer.BytesPending); Assert.Equal(0, writer.CurrentDepth); Assert.Null(writer.Options.Encoder); - Assert.Equal(formatted, writer.Options.Indented); - Assert.Equal(skipValidation, writer.Options.SkipValidation); + Assert.Equal(options.Indented, writer.Options.Indented); + Assert.Equal(options.SkipValidation, writer.Options.SkipValidation); Assert.Equal(0, output.FormattedCount); } } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void Reset(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void Reset(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var stream = new MemoryStream(); using var writeToStream = new Utf8JsonWriter(stream, options); writeToStream.WriteNumberValue(1); @@ -890,8 +876,8 @@ public void Reset(bool formatted, bool skipValidation) Assert.Equal(0, writeToStream.BytesPending); Assert.Equal(0, writeToStream.CurrentDepth); Assert.Null(writeToStream.Options.Encoder); - Assert.Equal(formatted, writeToStream.Options.Indented); - Assert.Equal(skipValidation, writeToStream.Options.SkipValidation); + Assert.Equal(options.Indented, writeToStream.Options.Indented); + Assert.Equal(options.SkipValidation, writeToStream.Options.SkipValidation); Assert.True(stream.Position != 0); long previousWritten = stream.Position; @@ -910,8 +896,8 @@ public void Reset(bool formatted, bool skipValidation) Assert.Equal(0, writeToIBW.BytesPending); Assert.Equal(0, writeToIBW.CurrentDepth); Assert.Null(writeToIBW.Options.Encoder); - Assert.Equal(formatted, writeToIBW.Options.Indented); - Assert.Equal(skipValidation, writeToIBW.Options.SkipValidation); + Assert.Equal(options.Indented, writeToIBW.Options.Indented); + Assert.Equal(options.SkipValidation, writeToIBW.Options.SkipValidation); Assert.True(output.FormattedCount != 0); previousWritten = output.FormattedCount; @@ -920,14 +906,9 @@ public void Reset(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void ResetWithSameOutput(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void ResetWithSameOutput(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var stream = new MemoryStream(); using var writeToStream = new Utf8JsonWriter(stream, options); writeToStream.WriteNumberValue(1); @@ -940,8 +921,8 @@ public void ResetWithSameOutput(bool formatted, bool skipValidation) Assert.Equal(0, writeToStream.BytesPending); Assert.Equal(0, writeToStream.CurrentDepth); Assert.Null(writeToStream.Options.Encoder); - Assert.Equal(formatted, writeToStream.Options.Indented); - Assert.Equal(skipValidation, writeToStream.Options.SkipValidation); + Assert.Equal(options.Indented, writeToStream.Options.Indented); + Assert.Equal(options.SkipValidation, writeToStream.Options.SkipValidation); Assert.True(stream.Position != 0); long previousWritten = stream.Position; @@ -966,8 +947,8 @@ public void ResetWithSameOutput(bool formatted, bool skipValidation) Assert.Equal(0, writeToIBW.BytesPending); Assert.Equal(0, writeToIBW.CurrentDepth); Assert.Null(writeToIBW.Options.Encoder); - Assert.Equal(formatted, writeToIBW.Options.Indented); - Assert.Equal(skipValidation, writeToIBW.Options.SkipValidation); + Assert.Equal(options.Indented, writeToIBW.Options.Indented); + Assert.Equal(options.SkipValidation, writeToIBW.Options.SkipValidation); Assert.True(output.FormattedCount != 0); previousWritten = output.FormattedCount; @@ -982,14 +963,9 @@ public void ResetWithSameOutput(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void ResetChangeOutputMode(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void ResetChangeOutputMode(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var stream = new MemoryStream(); using var writeToStream = new Utf8JsonWriter(stream, options); writeToStream.WriteNumberValue(1); @@ -1003,8 +979,8 @@ public void ResetChangeOutputMode(bool formatted, bool skipValidation) Assert.Equal(0, writeToStream.BytesPending); Assert.Equal(0, writeToStream.CurrentDepth); Assert.Null(writeToStream.Options.Encoder); - Assert.Equal(formatted, writeToStream.Options.Indented); - Assert.Equal(skipValidation, writeToStream.Options.SkipValidation); + Assert.Equal(options.Indented, writeToStream.Options.Indented); + Assert.Equal(options.SkipValidation, writeToStream.Options.SkipValidation); Assert.True(stream.Position != 0); long previousWrittenStream = stream.Position; @@ -1034,8 +1010,8 @@ public void ResetChangeOutputMode(bool formatted, bool skipValidation) Assert.Equal(0, writeToIBW.BytesPending); Assert.Equal(0, writeToIBW.CurrentDepth); Assert.Null(writeToIBW.Options.Encoder); - Assert.Equal(formatted, writeToIBW.Options.Indented); - Assert.Equal(skipValidation, writeToIBW.Options.SkipValidation); + Assert.Equal(options.Indented, writeToIBW.Options.Indented); + Assert.Equal(options.SkipValidation, writeToIBW.Options.SkipValidation); Assert.True(output.FormattedCount != 0); previousWrittenStream = stream.Position; @@ -1054,14 +1030,9 @@ public void ResetChangeOutputMode(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidReset(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidReset(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var stream = new MemoryStream(); using var writeToStream = new Utf8JsonWriter(stream, options); @@ -1082,13 +1053,9 @@ public void InvalidReset(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FlushEmpty(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FlushEmpty(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(0); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1104,13 +1071,9 @@ public void FlushEmpty(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public async Task FlushEmptyAsync(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public async Task FlushEmptyAsync(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(0); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1126,13 +1089,9 @@ public async Task FlushEmptyAsync(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FlushMultipleTimes(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FlushMultipleTimes(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1168,13 +1127,9 @@ public void FlushMultipleTimes(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public async Task FlushMultipleTimesAsync(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public async Task FlushMultipleTimesAsync(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1210,13 +1165,9 @@ public async Task FlushMultipleTimesAsync(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void DisposeAutoFlushes(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void DisposeAutoFlushes(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1240,13 +1191,9 @@ public void DisposeAutoFlushes(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public async Task DisposeAutoFlushesAsync(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public async Task DisposeAutoFlushesAsync(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1270,13 +1217,9 @@ public async Task DisposeAutoFlushesAsync(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void UseAfterDisposeInvalid(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void UseAfterDisposeInvalid(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1316,13 +1259,9 @@ public void UseAfterDisposeInvalid(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public async Task UseAfterDisposeInvalidAsync(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public async Task UseAfterDisposeInvalidAsync(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new FixedSizedBufferWriter(256); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1419,13 +1358,9 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidBufferWriter(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidBufferWriter(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new InvalidBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1434,34 +1369,26 @@ public void InvalidBufferWriter(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public async Task WriteLargeToStream(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public async Task WriteLargeToStream(JsonWriterOptions options) { var stream = new MemoryStream(); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + await WriteLargeToStreamHelper(stream, options); - string expectedString = GetExpectedLargeString(formatted); + string expectedString = GetExpectedLargeString(options.Indented, options.IndentText); string actualString = Encoding.UTF8.GetString(stream.ToArray()); Assert.Equal(expectedString, actualString); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void GrowBeyondBufferSize(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void GrowBeyondBufferSize(JsonWriterOptions options) { const int InitialGrowthSize = 256; var output = new FixedSizedBufferWriter(InitialGrowthSize); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + byte[] utf8String = "this is a string long enough to overflow the buffer and cause an exception to be thrown."u8.ToArray(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -1496,7 +1423,7 @@ private static async Task WriteLargeToStreamHelper(Stream stream, JsonWriterOpti jsonUtf8.WriteEndArray(); } - private static string GetExpectedLargeString(bool prettyPrint) + private static string GetExpectedLargeString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -1515,18 +1442,14 @@ private static string GetExpectedLargeString(bool prettyPrint) json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FixedSizeBufferWriter_Guid(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FixedSizeBufferWriter_Guid(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + int sizeTooSmall = 256; var output = new FixedSizedBufferWriter(sizeTooSmall); @@ -1541,7 +1464,7 @@ public void FixedSizeBufferWriter_Guid(bool formatted, bool skipValidation) Assert.Throws(() => jsonUtf8.WriteStringValue(guid)); } - sizeTooSmall += formatted ? 9 : 1; + sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 5 : 1; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1552,7 +1475,7 @@ public void FixedSizeBufferWriter_Guid(bool formatted, bool skipValidation) } string actualStr = Encoding.UTF8.GetString(output.Formatted); - if (!formatted) + if (!options.Indented) { Assert.Equal(257, output.Formatted.Length); } @@ -1560,14 +1483,10 @@ public void FixedSizeBufferWriter_Guid(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FixedSizeBufferWriter_DateTime(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FixedSizeBufferWriter_DateTime(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + int sizeTooSmall = 256; var output = new FixedSizedBufferWriter(sizeTooSmall); @@ -1582,7 +1501,8 @@ public void FixedSizeBufferWriter_DateTime(bool formatted, bool skipValidation) Assert.Throws(() => jsonUtf8.WriteStringValue(date)); } - sizeTooSmall += formatted ? 23 : 15; + sizeTooSmall += options.Indented ? 23 : 15; + sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 19 : 15; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1593,7 +1513,7 @@ public void FixedSizeBufferWriter_DateTime(bool formatted, bool skipValidation) } string actualStr = Encoding.UTF8.GetString(output.Formatted); - if (!formatted) + if (!options.Indented) { Assert.Equal(257, output.Formatted.Length); } @@ -1601,14 +1521,10 @@ public void FixedSizeBufferWriter_DateTime(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FixedSizeBufferWriter_DateTimeOffset(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FixedSizeBufferWriter_DateTimeOffset(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + int sizeTooSmall = 256; var output = new FixedSizedBufferWriter(sizeTooSmall); @@ -1623,7 +1539,7 @@ public void FixedSizeBufferWriter_DateTimeOffset(bool formatted, bool skipValida Assert.Throws(() => jsonUtf8.WriteStringValue(date)); } - sizeTooSmall += formatted ? 23 : 15; + sizeTooSmall += options.Indented ? 23 : 15; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1634,7 +1550,7 @@ public void FixedSizeBufferWriter_DateTimeOffset(bool formatted, bool skipValida } string actualStr = Encoding.UTF8.GetString(output.Formatted); - if (!formatted) + if (!options.Indented) { Assert.Equal(257, output.Formatted.Length); } @@ -1642,13 +1558,9 @@ public void FixedSizeBufferWriter_DateTimeOffset(bool formatted, bool skipValida } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void FixedSizeBufferWriter_Decimal(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void FixedSizeBufferWriter_Decimal(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var random = new Random(42); for (int i = 0; i < 1_000; i++) @@ -1721,7 +1633,7 @@ public void FixedSizeBufferWriter_Decimal(bool formatted, bool skipValidation) Assert.Throws(() => jsonUtf8.WriteNumberValue(value)); } - sizeTooSmall += formatted ? 9 : 1; + sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 5 : 1; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1733,7 +1645,7 @@ public void FixedSizeBufferWriter_Decimal(bool formatted, bool skipValidation) } string actualStr = Encoding.UTF8.GetString(output.Formatted); - if (!formatted) + if (!options.Indented) { Assert.Equal(257, output.Formatted.Length); } @@ -1741,134 +1653,117 @@ public void FixedSizeBufferWriter_Decimal(bool formatted, bool skipValidation) } } + public static IEnumerable InvalidJsonDueToWritingMultipleValues_TestData() => + JsonOptionsWith([ + JsonValueKind.Array, + JsonValueKind.Object, + JsonValueKind.String, + JsonValueKind.Number, + JsonValueKind.True, + JsonValueKind.False, + JsonValueKind.Null, + ]); + [Theory] - [InlineData(JsonValueKind.Array, true, true)] - [InlineData(JsonValueKind.Array, true, false)] - [InlineData(JsonValueKind.Array, false, true)] - [InlineData(JsonValueKind.Array, false, false)] - [InlineData(JsonValueKind.Object, true, true)] - [InlineData(JsonValueKind.Object, true, false)] - [InlineData(JsonValueKind.Object, false, true)] - [InlineData(JsonValueKind.Object, false, false)] - [InlineData(JsonValueKind.String, true, true)] - [InlineData(JsonValueKind.String, true, false)] - [InlineData(JsonValueKind.String, false, true)] - [InlineData(JsonValueKind.String, false, false)] - [InlineData(JsonValueKind.Number, true, true)] - [InlineData(JsonValueKind.Number, true, false)] - [InlineData(JsonValueKind.Number, false, true)] - [InlineData(JsonValueKind.Number, false, false)] - [InlineData(JsonValueKind.True, true, true)] - [InlineData(JsonValueKind.True, true, false)] - [InlineData(JsonValueKind.True, false, true)] - [InlineData(JsonValueKind.True, false, false)] - [InlineData(JsonValueKind.False, true, true)] - [InlineData(JsonValueKind.False, true, false)] - [InlineData(JsonValueKind.False, false, true)] - [InlineData(JsonValueKind.False, false, false)] - [InlineData(JsonValueKind.Null, true, true)] - [InlineData(JsonValueKind.Null, true, false)] - [InlineData(JsonValueKind.Null, false, true)] - [InlineData(JsonValueKind.Null, false, false)] - public void InvalidJsonDueToWritingMultipleValues(JsonValueKind kind, bool formatted, bool skipValidation) - { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(InvalidJsonDueToWritingMultipleValues_TestData))] + public void InvalidJsonDueToWritingMultipleValues(JsonWriterOptions options, JsonValueKind kind) + { var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartArray(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartArray(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndObject(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndObject(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndArray(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndArray(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WritePropertyName("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WritePropertyName("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteString("key", "foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteString("key", "foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStringValue("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStringValue("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumber("key", 123), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumber("key", 123), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumberValue(123), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumberValue(123), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", true), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", true), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(true), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(true), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", false), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", false), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(false), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(false), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNull("key"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNull("key"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNullValue(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNullValue(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -1880,133 +1775,105 @@ public void InvalidJsonDueToWritingMultipleValues(JsonValueKind kind, bool forma } [Theory] - [InlineData(JsonValueKind.Array, true, true)] - [InlineData(JsonValueKind.Array, true, false)] - [InlineData(JsonValueKind.Array, false, true)] - [InlineData(JsonValueKind.Array, false, false)] - [InlineData(JsonValueKind.Object, true, true)] - [InlineData(JsonValueKind.Object, true, false)] - [InlineData(JsonValueKind.Object, false, true)] - [InlineData(JsonValueKind.Object, false, false)] - [InlineData(JsonValueKind.String, true, true)] - [InlineData(JsonValueKind.String, true, false)] - [InlineData(JsonValueKind.String, false, true)] - [InlineData(JsonValueKind.String, false, false)] - [InlineData(JsonValueKind.Number, true, true)] - [InlineData(JsonValueKind.Number, true, false)] - [InlineData(JsonValueKind.Number, false, true)] - [InlineData(JsonValueKind.Number, false, false)] - [InlineData(JsonValueKind.True, true, true)] - [InlineData(JsonValueKind.True, true, false)] - [InlineData(JsonValueKind.True, false, true)] - [InlineData(JsonValueKind.True, false, false)] - [InlineData(JsonValueKind.False, true, true)] - [InlineData(JsonValueKind.False, true, false)] - [InlineData(JsonValueKind.False, false, true)] - [InlineData(JsonValueKind.False, false, false)] - [InlineData(JsonValueKind.Null, true, true)] - [InlineData(JsonValueKind.Null, true, false)] - [InlineData(JsonValueKind.Null, false, true)] - [InlineData(JsonValueKind.Null, false, false)] - public void InvalidJsonDueToWritingMultipleValuesWithComments(JsonValueKind kind, bool formatted, bool skipValidation) - { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(InvalidJsonDueToWritingMultipleValues_TestData))] + public void InvalidJsonDueToWritingMultipleValuesWithComments(JsonWriterOptions options, JsonValueKind kind) + { var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartObject("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartArray(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStartArray(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndObject(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndObject(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndArray(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteEndArray(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WritePropertyName("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WritePropertyName("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteString("key", "foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteString("key", "foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteStringValue("foo"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteStringValue("foo"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumber("key", 123), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumber("key", 123), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumberValue(123), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNumberValue(123), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", true), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", true), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(true), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(true), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", false), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBoolean("key", false), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(false), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteBooleanValue(false), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNull("key"), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNull("key"), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { WritePreamble(jsonUtf8, kind, addComments: true); - ValidateAction(jsonUtf8, () => jsonUtf8.WriteNullValue(), skipValidation); + ValidateAction(jsonUtf8, () => jsonUtf8.WriteNullValue(), options.SkipValidation); } using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -2078,18 +1945,14 @@ private void ValidateAction(Utf8JsonWriter writer, Action action, bool skipValid } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidJsonMismatch(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidJsonMismatch(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2101,7 +1964,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2113,7 +1976,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray("property at start"); } @@ -2125,7 +1988,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject("property at start"); } @@ -2138,7 +2001,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray("property inside array"); } @@ -2151,7 +2014,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject(); } @@ -2164,7 +2027,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2177,7 +2040,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStringValue("key"); } @@ -2190,7 +2053,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteString("key", "value"); } @@ -2203,7 +2066,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteString(JsonEncodedText.Encode("key"), JsonEncodedText.Encode("value")); } @@ -2216,7 +2079,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2229,7 +2092,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray(); } @@ -2244,7 +2107,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) jsonUtf8.WriteStartArray(); jsonUtf8.WriteStartArray(); jsonUtf8.WriteEndArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2259,7 +2122,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) jsonUtf8.WriteStartObject(); jsonUtf8.WriteStartObject("some object"); jsonUtf8.WriteEndObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2272,7 +2135,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject("some object"); jsonUtf8.WriteEndObject(); @@ -2289,7 +2152,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) jsonUtf8.WriteStartObject(); jsonUtf8.WriteStartArray("test array"); jsonUtf8.WriteEndArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2303,7 +2166,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartArray(); jsonUtf8.WriteEndArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2317,7 +2180,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WriteEndObject(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2331,7 +2194,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartArray(); jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2345,7 +2208,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WriteStartObject("test object"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2357,7 +2220,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); jsonUtf8.WritePropertyName(JsonEncodedText.Encode("test name")); @@ -2376,7 +2239,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartArray(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2390,7 +2253,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2404,7 +2267,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray("test name"); } @@ -2418,7 +2281,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject("test name"); } @@ -2432,7 +2295,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2446,7 +2309,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteString("another property name", "some value"); } @@ -2460,7 +2323,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteNumber("another property name", 12345); } @@ -2474,7 +2337,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteNull("another property name"); } @@ -2488,7 +2351,7 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) { jsonUtf8.WriteStartObject(); jsonUtf8.WritePropertyName("first name"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteBoolean("another property name", true); } @@ -2500,13 +2363,9 @@ public void InvalidJsonMismatch(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidJsonIncomplete(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidJsonIncomplete(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -2554,19 +2413,15 @@ public void InvalidJsonIncomplete(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidJsonPrimitive(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidJsonPrimitive(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteNumberValue(12345); } @@ -2579,7 +2434,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray(); } @@ -2592,7 +2447,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject(); } @@ -2605,7 +2460,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartArray("property name"); } @@ -2618,7 +2473,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject("property name"); } @@ -2631,7 +2486,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteString("property name", "value"); } @@ -2644,7 +2499,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteString(JsonEncodedText.Encode("property name"), JsonEncodedText.Encode("value")); } @@ -2657,7 +2512,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndArray(); } @@ -2670,7 +2525,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteEndObject(); } @@ -2683,7 +2538,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNumberValue(12345); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2696,7 +2551,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteBooleanValue(true); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2709,7 +2564,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteNullValue(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2722,7 +2577,7 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStringValue("some string"); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WritePropertyName("test name"); } @@ -2734,13 +2589,9 @@ public void InvalidJsonPrimitive(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void InvalidNumbersJson(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void InvalidNumbersJson(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -2831,12 +2682,12 @@ public void InvalidJsonContinueShouldSucceed(bool formatted) var sb = new StringBuilder(); for (int i = 0; i < 100; i++) { - if (formatted) + if (options.Indented) sb.Append(Environment.NewLine); sb.Append("]"); } sb.Append(","); - if (formatted) + if (options.Indented) sb.Append(Environment.NewLine); sb.Append("[]"); @@ -2844,19 +2695,15 @@ public void InvalidJsonContinueShouldSucceed(bool formatted) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteSeparateProperties(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteSeparateProperties(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); var stringWriter = new StringWriter(); var json = new JsonTextWriter(stringWriter) { - Formatting = formatted ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, }; json.WriteStartObject(); @@ -2875,7 +2722,7 @@ public void WriteSeparateProperties(bool formatted, bool skipValidation) json.Flush(); - string expectedStr = stringWriter.ToString(); + string expectedStr = HandleIndent(stringWriter.ToString(), options.IndentText); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartObject(); @@ -2896,13 +2743,9 @@ public void WriteSeparateProperties(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingTooDeep(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingTooDeep(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -2916,13 +2759,9 @@ public void WritingTooDeep(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingTooDeepProperty(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingTooDeepProperty(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -3017,11 +2856,8 @@ public static void CustomMaxDepth_DepthExceedingLimit_ShouldFail(int maxDepth) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingTooLargeProperty(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingTooLargeProperty(JsonWriterOptions options) { try { @@ -3034,8 +2870,7 @@ public void WritingTooLargeProperty(bool formatted, bool skipValidation) key.AsSpan().Fill((byte)'a'); keyChars.AsSpan().Fill('a'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(1024); + var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -3062,11 +2897,8 @@ public void WritingTooLargeProperty(bool formatted, bool skipValidation) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingTooLargePropertyStandalone(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingTooLargePropertyStandalone(JsonWriterOptions options) { try { @@ -3079,8 +2911,7 @@ public void WritingTooLargePropertyStandalone(bool formatted, bool skipValidatio key.AsSpan().Fill((byte)'a'); keyChars.AsSpan().Fill('a'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(1024); + var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -3102,19 +2933,15 @@ public void WritingTooLargePropertyStandalone(bool formatted, bool skipValidatio [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingTooLargeBase64Bytes(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingTooLargeBase64Bytes(JsonWriterOptions options) { try { byte[] value = new byte[200_000_000]; value.AsSpan().Fill((byte)'a'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(value.Length); + var output = new ArrayBufferWriter(value.Length); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -3185,11 +3012,8 @@ public void WritingTooLargeBase64Bytes(bool formatted, bool skipValidation) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritingHugeBase64Bytes(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritingHugeBase64Bytes(JsonWriterOptions options) { try { @@ -3197,8 +3021,7 @@ public void WritingHugeBase64Bytes(bool formatted, bool skipValidation) value.AsSpan().Fill(168); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(1024); + var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -3245,12 +3068,9 @@ public void WritingHugeBase64Bytes(bool formatted, bool skipValidation) // https://github.com/dotnet/runtime/issues/30746 [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] + [MemberData(nameof(JsonOptions_TestData))] [SkipOnCoreClr("https://github.com/dotnet/runtime/issues/45464", ~RuntimeConfiguration.Release)] - public void Writing3MBBase64Bytes(bool formatted, bool skipValidation) + public void Writing3MBBase64Bytes(JsonWriterOptions options) { byte[] value = new byte[3 * 1024 * 1024]; @@ -3260,9 +3080,8 @@ public void Writing3MBBase64Bytes(bool formatted, bool skipValidation) Base64.EncodeToUtf8(value, base64StringUtf8, out _, out int bytesWritten); string expectedValue = Encoding.UTF8.GetString(base64StringUtf8.AsSpan(0, bytesWritten).ToArray()); - string expectedJson = formatted ? $"{{{Environment.NewLine} \"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; + string expectedJson = options.Indented ? $"{{{Environment.NewLine}{options.IndentText ?? " "}\"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) @@ -3309,16 +3128,12 @@ public void Writing3MBBase64Bytes(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteSingleValue(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteSingleValue(JsonWriterOptions options) { string expectedStr = "123456789012345"; - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + var output = new ArrayBufferWriter(1024); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -3330,15 +3145,12 @@ public void WriteSingleValue(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteHelloWorld(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteHelloWorld(JsonWriterOptions options) { string propertyName = "message"; string value = "Hello, World!"; - string expectedStr = GetHelloWorldExpectedString(prettyPrint: formatted, propertyName, value); + string expectedStr = GetHelloWorldExpectedString(prettyPrint: options.Indented, options.IndentText, propertyName, value); JsonEncodedText encodedPropertyName = JsonEncodedText.Encode(propertyName); JsonEncodedText encodedValue = JsonEncodedText.Encode(value); @@ -3346,8 +3158,7 @@ public void WriteHelloWorld(bool formatted, bool skipValidation) ReadOnlySpan utf8PropertyName = "message"u8; ReadOnlySpan utf8Value = "Hello, World!"u8; - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + for (int i = 0; i < 32; i++) { var output = new ArrayBufferWriter(32); @@ -3527,18 +3338,13 @@ public void WriteHelloWorld(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteHelloWorldEscaped(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteHelloWorldEscaped(JsonWriterOptions options) { string propertyName = "mess> propertyNameSpan = propertyName.AsSpan(); ReadOnlySpan valueSpan = value.AsSpan(); ReadOnlySpan propertyNameSpanUtf8 = Encoding.UTF8.GetBytes(propertyName); @@ -3734,14 +3540,10 @@ public void WriteHelloWorldEscaped(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritePartialHelloWorld(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritePartialHelloWorld(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -3753,15 +3555,15 @@ public void WritePartialHelloWorld(bool formatted, bool skipValidation) jsonUtf8.WriteString("message", "Hello, World!"); Assert.Equal(0, jsonUtf8.BytesCommitted); - if (formatted) - Assert.Equal(26 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesPending); jsonUtf8.Flush(); - if (formatted) - Assert.Equal(26 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesCommitted); @@ -3770,50 +3572,41 @@ public void WritePartialHelloWorld(bool formatted, bool skipValidation) jsonUtf8.WriteString("message", "Hello, World!"); jsonUtf8.WriteEndObject(); - if (formatted) - Assert.Equal(26 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + if (options.Indented) + Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(26, jsonUtf8.BytesCommitted); - if (formatted) - Assert.Equal(27 + 2 + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(27 + (options.IndentText?.Length ?? 2) + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(27, jsonUtf8.BytesPending); jsonUtf8.Flush(); - if (formatted) - Assert.Equal(53 + (2 * 2) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(53 + (2 * (options.IndentText?.Length ?? 2)) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(53, jsonUtf8.BytesCommitted); Assert.Equal(0, jsonUtf8.BytesPending); } + public static IEnumerable WriteBase64String_TestData() => + JsonOptionsWith([ + "message", + "escape mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ]); + [Theory] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "escape mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteBase64String(bool formatted, bool skipValidation, string inputValue) + [MemberData(nameof(WriteBase64String_TestData))] + public void WriteBase64String(JsonWriterOptions options, string inputValue) { string propertyName = inputValue; byte[] value = { 1, 2, 3, 4, 5, 6 }; - string expectedStr = GetBase64ExpectedString(prettyPrint: formatted, propertyName, value); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetBase64ExpectedString(options, propertyName, value); ReadOnlySpan propertyNameSpan = propertyName.AsSpan(); ReadOnlySpan propertyNameSpanUtf8 = Encoding.UTF8.GetBytes(propertyName); @@ -3865,14 +3658,9 @@ public void WriteBase64String(bool formatted, bool skipValidation, string inputV } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WritePartialBase64String(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WritePartialBase64String(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -3884,15 +3672,15 @@ public void WritePartialBase64String(bool formatted, bool skipValidation) jsonUtf8.WriteBase64String("message", new byte[] { 201, 153, 199 }); Assert.Equal(0, jsonUtf8.BytesCommitted); - if (formatted) - Assert.Equal(17 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesPending); jsonUtf8.Flush(); - if (formatted) - Assert.Equal(17 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesCommitted); @@ -3901,20 +3689,20 @@ public void WritePartialBase64String(bool formatted, bool skipValidation) jsonUtf8.WriteBase64String("message", new byte[] { 201, 153, 199 }); jsonUtf8.WriteEndObject(); - if (formatted) - Assert.Equal(17 + 2 + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + if (options.Indented) + Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(17, jsonUtf8.BytesCommitted); - if (formatted) - Assert.Equal(18 + 2 + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(18 + (options.IndentText?.Length ?? 2) + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(18, jsonUtf8.BytesPending); jsonUtf8.Flush(); - if (formatted) - Assert.Equal(35 + (2 * 2) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + if (options.Indented) + Assert.Equal(35 + (2 * (options.IndentText?.Length ?? 2)) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(35, jsonUtf8.BytesCommitted); @@ -3922,13 +3710,9 @@ public void WritePartialBase64String(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteInvalidPartialJson(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteInvalidPartialJson(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -3942,7 +3726,7 @@ public void WriteInvalidPartialJson(bool formatted, bool skipValidation) Assert.Equal(1, jsonUtf8.BytesCommitted); Assert.Equal(0, jsonUtf8.BytesPending); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStringValue("Hello, World!"); jsonUtf8.WriteEndArray(); @@ -3955,15 +3739,11 @@ public void WriteInvalidPartialJson(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteInvalidBase64(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteInvalidBase64(JsonWriterOptions options) { { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(10); + var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartObject(); @@ -3976,7 +3756,7 @@ public void WriteInvalidBase64(bool formatted, bool skipValidation) Assert.Equal(1, jsonUtf8.BytesCommitted); Assert.Equal(0, jsonUtf8.BytesPending); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteBase64StringValue(new byte[] { 1, 2 }); jsonUtf8.WriteEndArray(); @@ -3988,8 +3768,7 @@ public void WriteInvalidBase64(bool formatted, bool skipValidation) } } { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(10); + var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartArray(); @@ -4002,7 +3781,7 @@ public void WriteInvalidBase64(bool formatted, bool skipValidation) Assert.Equal(1, jsonUtf8.BytesCommitted); Assert.Equal(0, jsonUtf8.BytesPending); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteBase64String("foo", new byte[] { 1, 2 }); jsonUtf8.WriteEndObject(); @@ -4060,15 +3839,11 @@ public void WriteBase64DoesNotEscapeLarge() } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteInvalidDepthPartial(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteInvalidDepthPartial(JsonWriterOptions options) { { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(10); + var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartObject(); @@ -4077,7 +3852,7 @@ public void WriteInvalidDepthPartial(bool formatted, bool skipValidation) Assert.Equal(0, jsonUtf8.CurrentDepth); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject(); } @@ -4088,15 +3863,14 @@ public void WriteInvalidDepthPartial(bool formatted, bool skipValidation) } { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(10); + var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartObject(); jsonUtf8.WriteEndObject(); jsonUtf8.Flush(); - if (skipValidation) + if (options.SkipValidation) { jsonUtf8.WriteStartObject("name"); } @@ -4107,24 +3881,18 @@ public void WriteInvalidDepthPartial(bool formatted, bool skipValidation) } } + public static IEnumerable WriteComments_TestData() => + JsonOptionsWith([ + "comment", + "comm>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ]); + [Theory] - [InlineData(true, true, "comment")] - [InlineData(true, false, "comment")] - [InlineData(false, true, "comment")] - [InlineData(false, false, "comment")] - [InlineData(true, true, "comm>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteCommentsInArray(bool formatted, bool skipValidation, string comment) - { - string expectedStr = GetCommentInArrayExpectedString(prettyPrint: formatted, comment); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteComments_TestData))] + public void WriteCommentsInArray(JsonWriterOptions options, string comment) + { + string expectedStr = GetCommentInArrayExpectedString(options, comment); for (int i = 0; i < 3; i++) { @@ -4175,23 +3943,10 @@ public void WriteCommentsInArray(bool formatted, bool skipValidation, string com } [Theory] - [InlineData(true, true, "comment")] - [InlineData(true, false, "comment")] - [InlineData(false, true, "comment")] - [InlineData(false, false, "comment")] - [InlineData(true, true, "comm>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteCommentsInObject(bool formatted, bool skipValidation, string comment) - { - string expectedStr = GetCommentInObjectExpectedString(prettyPrint: formatted, comment); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteComments_TestData))] + public void WriteCommentsInObject(JsonWriterOptions options, string comment) + { + string expectedStr = GetCommentInObjectExpectedString(options, comment); for (int i = 0; i < 3; i++) { @@ -4245,14 +4000,9 @@ private static void WriteCommentValue(Utf8JsonWriter jsonUtf8, int i, string com } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteInvalidComment(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteInvalidComment(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(32); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -4270,14 +4020,9 @@ public void WriteInvalidComment(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteCommentsInvalidTextAllowed(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteCommentsInvalidTextAllowed(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(32); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -4298,11 +4043,11 @@ public void WriteCommentsInvalidTextAllowed(bool formatted, bool skipValidation) jsonUtf8.WriteCommentValue(comment.AsSpan()); jsonUtf8.Flush(); - string expectedStr = GetCommentExpectedString(prettyPrint: formatted); + string expectedStr = GetCommentExpectedString(prettyPrint: options.Indented, options.IndentText); JsonTestHelper.AssertContents(expectedStr, output); } - private static string GetCommentExpectedString(bool prettyPrint) + private static string GetCommentExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -4331,7 +4076,7 @@ private static string GetCommentExpectedString(bool prettyPrint) json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } [Theory] @@ -4421,17 +4166,12 @@ public void WriteCommentsInObject_ComparedWithStringLiteral(bool formatted, stri } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteStrings(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteStrings(JsonWriterOptions options) { string value = "temp"; - string expectedStr = GetStringsExpectedString(prettyPrint: formatted, value); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + string expectedStr = GetStringsExpectedString(prettyPrint: options.Indented, options.IndentText, value); + for (int i = 0; i < 3; i++) { var output = new ArrayBufferWriter(1024); @@ -4462,32 +4202,21 @@ public void WriteStrings(bool formatted, bool skipValidation) } } + public static IEnumerable WriteHelloWorldEscaped_AdditionalCases_TestData() => + JsonOptionsWith([ + "mess\nage", + "message" + ], + [ + "Hello, \nWorld!", + "Hello, World!" + ]); + [Theory] - [InlineData(true, true, "mess\nage", "Hello, \nWorld!")] - [InlineData(true, false, "mess\nage", "Hello, \nWorld!")] - [InlineData(false, true, "mess\nage", "Hello, \nWorld!")] - [InlineData(false, false, "mess\nage", "Hello, \nWorld!")] - [InlineData(true, true, "message", "Hello, \nWorld!")] - [InlineData(true, false, "message", "Hello, \nWorld!")] - [InlineData(false, true, "message", "Hello, \nWorld!")] - [InlineData(false, false, "message", "Hello, \nWorld!")] - [InlineData(true, true, "mess\nage", "Hello, World!")] - [InlineData(true, false, "mess\nage", "Hello, World!")] - [InlineData(false, true, "mess\nage", "Hello, World!")] - [InlineData(false, false, "mess\nage", "Hello, World!")] - [InlineData(true, true, "message", "Hello, World!")] - [InlineData(true, false, "message", "Hello, World!")] - [InlineData(false, true, "message", "Hello, World!")] - [InlineData(false, false, "message", "Hello, World!")] - [InlineData(true, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>mess\nage", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Hello, \nWorld!")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>mess\nage", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Hello, \nWorld!")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>mess\nage", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Hello, \nWorld!")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>mess\nage", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Hello, \nWorld!")] - public void WriteHelloWorldEscaped_AdditionalCases(bool formatted, bool skipValidation, string key, string value) - { - string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, key, value, StringEscapeHandling.EscapeHtml); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteHelloWorldEscaped_AdditionalCases_TestData))] + public void WriteHelloWorldEscaped_AdditionalCases(JsonWriterOptions options, string key, string value) + { + string expectedStr = GetEscapedExpectedString(options, key, value, StringEscapeHandling.EscapeHtml); byte[] keyUtf8 = Encoding.UTF8.GetBytes(key); byte[] valueUtf8 = Encoding.UTF8.GetBytes(value); @@ -4626,11 +4355,8 @@ public void WriteHelloWorldEscaped_AdditionalCases(bool formatted, bool skipVali } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void EscapeAsciiCharacters(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void EscapeAsciiCharacters(JsonWriterOptions options) { var propertyArray = new char[128]; @@ -4650,9 +4376,8 @@ public void EscapeAsciiCharacters(bool formatted, bool skipValidation) string propertyName = new string(propertyArray); string value = new string(propertyArray); - string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeHtml); + string expectedStr = GetEscapedExpectedString(options, propertyName, value, StringEscapeHandling.EscapeHtml); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; for (int i = 0; i < 6; i++) { var output = new ArrayBufferWriter(1024); @@ -4693,11 +4418,8 @@ public void EscapeAsciiCharacters(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void EscapeCharacters(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void EscapeCharacters(JsonWriterOptions options) { // Do not include surrogate pairs. var propertyArray = new char[0xD800 + (0xFFFF - 0xE000) + 1]; @@ -4713,9 +4435,8 @@ public void EscapeCharacters(bool formatted, bool skipValidation) string propertyName = new string(propertyArray); string value = new string(propertyArray); - string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeNonAscii); + string expectedStr = GetEscapedExpectedString(options, propertyName, value, StringEscapeHandling.EscapeNonAscii); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; for (int i = 0; i < 6; i++) { var output = new ArrayBufferWriter(1024); @@ -4756,20 +4477,16 @@ public void EscapeCharacters(bool formatted, bool skipValidation) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void HighSurrogateMissingGetsReplaced(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void HighSurrogateMissingGetsReplaced(JsonWriterOptions options) { var propertyArray = new char[10] { 'a', (char)0xD800, (char)0xDC00, (char)0xD803, (char)0xDE6D, (char)0xD834, (char)0xDD1E, (char)0xDBFF, (char)0xDFFF, 'a' }; string propertyName = new string(propertyArray); string value = new string(propertyArray); - string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeNonAscii); + string expectedStr = GetEscapedExpectedString(options, propertyName, value, StringEscapeHandling.EscapeNonAscii); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; for (int i = 0; i < 6; i++) { var output = new ArrayBufferWriter(1024); @@ -5074,13 +4791,9 @@ public void CustomEscaper(string value, string expectedStr) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteCustomStrings(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteCustomStrings(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(10); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5094,19 +4807,15 @@ public void WriteCustomStrings(bool formatted, bool skipValidation) jsonUtf8.WriteEndObject(); jsonUtf8.Flush(); - JsonTestHelper.AssertContents(GetCustomExpectedString(formatted), output); + JsonTestHelper.AssertContents(GetCustomExpectedString(options.Indented, options.IndentText), output); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteStartEnd(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteStartEnd(JsonWriterOptions options) { - string expectedStr = GetStartEndExpectedString(prettyPrint: formatted); + string expectedStr = GetStartEndExpectedString(prettyPrint: options.Indented, options.IndentText); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; var output = new ArrayBufferWriter(1024); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5157,16 +4866,12 @@ public void WriteStartEndInvalid(bool formatted) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteStartEndWithPropertyNameArray(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteStartEndWithPropertyNameArray(JsonWriterOptions options) { - string expectedStr = GetStartEndWithPropertyArrayExpectedString(prettyPrint: formatted); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetStartEndWithPropertyArrayExpectedString(prettyPrint: options.Indented, options.IndentText); + for (int i = 0; i < 3; i++) { var output = new ArrayBufferWriter(1024); @@ -5195,16 +4900,15 @@ public void WriteStartEndWithPropertyNameArray(bool formatted, bool skipValidati } } + public static IEnumerable WriteStartEndWithPropertyName_TestData() => + JsonOptionsWith([ + 10, + 100 + ]); + [Theory] - [InlineData(true, true, 10)] - [InlineData(true, false, 10)] - [InlineData(false, true, 10)] - [InlineData(false, false, 10)] - [InlineData(true, true, 100)] - [InlineData(true, false, 100)] - [InlineData(false, true, 100)] - [InlineData(false, false, 100)] - public void WriteStartEndWithPropertyNameArrayDifferentKeyLengths(bool formatted, bool skipValidation, int keyLength) + [MemberData(nameof(WriteStartEndWithPropertyName_TestData))] + public void WriteStartEndWithPropertyNameArrayDifferentKeyLengths(JsonWriterOptions options, int keyLength) { var keyChars = new char[keyLength]; for (int i = 0; i < keyChars.Length; i++) @@ -5213,9 +4917,7 @@ public void WriteStartEndWithPropertyNameArrayDifferentKeyLengths(bool formatted } var key = new string(keyChars); - string expectedStr = GetStartEndWithPropertyArrayExpectedString(key, prettyPrint: formatted, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetStartEndWithPropertyArrayExpectedString(key, options, escape: true); for (int i = 0; i < 3; i++) { @@ -5246,15 +4948,10 @@ public void WriteStartEndWithPropertyNameArrayDifferentKeyLengths(bool formatted } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteStartEndWithPropertyNameObject(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteStartEndWithPropertyNameObject(JsonWriterOptions options) { - string expectedStr = GetStartEndWithPropertyObjectExpectedString(prettyPrint: formatted); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetStartEndWithPropertyObjectExpectedString(prettyPrint: options.Indented, options.IndentText); for (int i = 0; i < 3; i++) { @@ -5285,15 +4982,8 @@ public void WriteStartEndWithPropertyNameObject(bool formatted, bool skipValidat } [Theory] - [InlineData(true, true, 10)] - [InlineData(true, false, 10)] - [InlineData(false, true, 10)] - [InlineData(false, false, 10)] - [InlineData(true, true, 100)] - [InlineData(true, false, 100)] - [InlineData(false, true, 100)] - [InlineData(false, false, 100)] - public void WriteStartEndWithPropertyNameObjectDifferentKeyLengths(bool formatted, bool skipValidation, int keyLength) + [MemberData(nameof(WriteStartEndWithPropertyName_TestData))] + public void WriteStartEndWithPropertyNameObjectDifferentKeyLengths(JsonWriterOptions options, int keyLength) { var keyChars = new char[keyLength]; for (int i = 0; i < keyChars.Length; i++) @@ -5302,9 +4992,7 @@ public void WriteStartEndWithPropertyNameObjectDifferentKeyLengths(bool formatte } var key = new string(keyChars); - string expectedStr = GetStartEndWithPropertyObjectExpectedString(key, prettyPrint: formatted, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetStartEndWithPropertyObjectExpectedString(key, options, escape: true); for (int i = 0; i < 3; i++) { @@ -5335,15 +5023,10 @@ public void WriteStartEndWithPropertyNameObjectDifferentKeyLengths(bool formatte } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteArrayWithProperty(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteArrayWithProperty(JsonWriterOptions options) { - string expectedStr = GetArrayWithPropertyExpectedString(prettyPrint: formatted); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetArrayWithPropertyExpectedString(prettyPrint: options.Indented, options.IndentText); for (int i = 0; i < 3; i++) { @@ -5373,36 +5056,22 @@ public void WriteArrayWithProperty(bool formatted, bool skipValidation) } } + public static IEnumerable WriteBooleanValue_TestData() => + JsonOptionsWith([ + true, + false + ], + [ + "message", + "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ]); + [Theory] - [InlineData(true, true, true, "message")] - [InlineData(true, false, true, "message")] - [InlineData(false, true, true, "message")] - [InlineData(false, false, true, "message")] - [InlineData(true, true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, true, false, "message")] - [InlineData(true, false, false, "message")] - [InlineData(false, true, false, "message")] - [InlineData(false, false, false, "message")] - [InlineData(true, true, false, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteBooleanValue(bool formatted, bool skipValidation, bool value, string keyString) - { - string expectedStr = GetBooleanExpectedString(prettyPrint: formatted, keyString, value, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteBooleanValue_TestData))] + public void WriteBooleanValue(JsonWriterOptions options, bool value, string keyString) + { + string expectedStr = GetBooleanExpectedString(options, keyString, value, escape: true); for (int i = 0; i < 4; i++) { @@ -5442,24 +5111,18 @@ public void WriteBooleanValue(bool formatted, bool skipValidation, bool value, s } } + public static IEnumerable WriteValue_TestData() => + JsonOptionsWith([ + "message", + "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ]); + [Theory] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteNullValue(bool formatted, bool skipValidation, string keyString) - { - string expectedStr = GetNullExpectedString(prettyPrint: formatted, keyString, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteValue_TestData))] + public void WriteNullValue(JsonWriterOptions options, string keyString) + { + string expectedStr = GetNullExpectedString(options, keyString, escape: true); for (int i = 0; i < 4; i++) { @@ -5502,36 +5165,21 @@ public void WriteNullValue(bool formatted, bool skipValidation, string keyString } } + public static IEnumerable WriteIntegerValue_TestData() => + JsonOptionsWith([ + 0, + -1, + 1, + int.MaxValue, + int.MinValue, + 12345 + ]); + [Theory] - [InlineData(true, true, 0)] - [InlineData(true, false, 0)] - [InlineData(false, true, 0)] - [InlineData(false, false, 0)] - [InlineData(true, true, -1)] - [InlineData(true, false, -1)] - [InlineData(false, true, -1)] - [InlineData(false, false, -1)] - [InlineData(true, true, 1)] - [InlineData(true, false, 1)] - [InlineData(false, true, 1)] - [InlineData(false, false, 1)] - [InlineData(true, true, int.MaxValue)] - [InlineData(true, false, int.MaxValue)] - [InlineData(false, true, int.MaxValue)] - [InlineData(false, false, int.MaxValue)] - [InlineData(true, true, int.MinValue)] - [InlineData(true, false, int.MinValue)] - [InlineData(false, true, int.MinValue)] - [InlineData(false, false, int.MinValue)] - [InlineData(true, true, 12345)] - [InlineData(true, false, 12345)] - [InlineData(false, true, 12345)] - [InlineData(false, false, 12345)] - public void WriteIntegerValue(bool formatted, bool skipValidation, int value) - { - string expectedStr = GetPropertyExpectedString(prettyPrint: formatted, value); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + [MemberData(nameof(WriteIntegerValue_TestData))] + public void WriteIntegerValue(JsonWriterOptions options, int value) + { + string expectedStr = GetPropertyExpectedString(options, value); for (int i = 0; i < 4; i++) { @@ -5564,20 +5212,17 @@ public void WriteIntegerValue(bool formatted, bool skipValidation, int value) } } + public static IEnumerable WriteFloatValue_TestData() => + JsonOptionsWith([ + float.MinValue, + float.MaxValue + ]); + [Theory] - [InlineData(true, true, float.MinValue)] - [InlineData(true, false, float.MinValue)] - [InlineData(false, true, float.MinValue)] - [InlineData(false, false, float.MinValue)] - [InlineData(true, true, float.MaxValue)] - [InlineData(true, false, float.MaxValue)] - [InlineData(false, true, float.MaxValue)] - [InlineData(false, false, float.MaxValue)] - public void WriteFloatValue(bool formatted, bool skipValidation, float value) + [MemberData(nameof(WriteFloatValue_TestData))] + public void WriteFloatValue(JsonWriterOptions options, float value) { - string expectedStr = GetPropertyExpectedString(prettyPrint: formatted, value); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetPropertyExpectedString(options, value); for (int i = 0; i < 4; i++) { @@ -5610,20 +5255,17 @@ public void WriteFloatValue(bool formatted, bool skipValidation, float value) } } + public static IEnumerable WriteDoubleValue_TestData() => + JsonOptionsWith([ + double.MinValue, + double.MaxValue + ]); + [Theory] - [InlineData(true, true, double.MinValue)] - [InlineData(true, false, double.MinValue)] - [InlineData(false, true, double.MinValue)] - [InlineData(false, false, double.MinValue)] - [InlineData(true, true, double.MaxValue)] - [InlineData(true, false, double.MaxValue)] - [InlineData(false, true, double.MaxValue)] - [InlineData(false, false, double.MaxValue)] - public void WriteDoubleValue(bool formatted, bool skipValidation, double value) + [MemberData(nameof(WriteDoubleValue_TestData))] + public void WriteDoubleValue(JsonWriterOptions options, double value) { - string expectedStr = GetPropertyExpectedString(prettyPrint: formatted, value); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetPropertyExpectedString(options, value); for (int i = 0; i < 4; i++) { @@ -5658,19 +5300,8 @@ public void WriteDoubleValue(bool formatted, bool skipValidation, double value) [Theory] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteNumbers(bool formatted, bool skipValidation, string keyString) + [MemberData(nameof(WriteValue_TestData))] + public void WriteNumbers(JsonWriterOptions options, string keyString) { var random = new Random(42); const int numberOfItems = 1_000; @@ -5798,9 +5429,7 @@ public void WriteNumbers(bool formatted, bool skipValidation, string keyString) } } - string expectedStr = GetNumbersExpectedString(prettyPrint: formatted, keyString, ints, uints, longs, ulongs, floats, doubles, decimals, escape: false); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetNumbersExpectedString(options, keyString, ints, uints, longs, ulongs, floats, doubles, decimals, escape: false); for (int j = 0; j < 3; j++) { @@ -5884,14 +5513,9 @@ public void WriteNumbers(bool formatted, bool skipValidation, string keyString) } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteNumberValueInt32(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteNumberValueInt32(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5908,19 +5532,14 @@ public void WriteNumberValueInt32(bool formatted, bool skipValidation) jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteNumberValueInt64(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteNumberValueInt64(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5937,19 +5556,14 @@ public void WriteNumberValueInt64(bool formatted, bool skipValidation) jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteNumberValueUInt32(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteNumberValueUInt32(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5966,19 +5580,14 @@ public void WriteNumberValueUInt32(bool formatted, bool skipValidation) jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteNumberValueUInt64(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteNumberValueUInt64(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -5995,23 +5604,14 @@ public void WriteNumberValueUInt64(bool formatted, bool skipValidation) jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true, float.MinValue)] - [InlineData(true, false, float.MinValue)] - [InlineData(false, true, float.MinValue)] - [InlineData(false, false, float.MinValue)] - [InlineData(true, true, float.MaxValue)] - [InlineData(true, false, float.MaxValue)] - [InlineData(false, true, float.MaxValue)] - [InlineData(false, false, float.MaxValue)] - public void WriteNumberValueSingle(bool formatted, bool skipValidation, float value) - { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + [MemberData(nameof(WriteFloatValue_TestData))] + public void WriteNumberValueSingle(JsonWriterOptions options, float value) + { var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -6027,23 +5627,14 @@ public void WriteNumberValueSingle(bool formatted, bool skipValidation, float va jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true, double.MinValue)] - [InlineData(true, false, double.MinValue)] - [InlineData(false, true, double.MinValue)] - [InlineData(false, false, double.MinValue)] - [InlineData(true, true, double.MaxValue)] - [InlineData(true, false, double.MaxValue)] - [InlineData(false, true, double.MaxValue)] - [InlineData(false, false, double.MaxValue)] - public void WriteNumberValueDouble(bool formatted, bool skipValidation, double value) - { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + [MemberData(nameof(WriteDoubleValue_TestData))] + public void WriteNumberValueDouble(JsonWriterOptions options, double value) + { var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -6059,19 +5650,14 @@ public void WriteNumberValueDouble(bool formatted, bool skipValidation, double v jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } [Theory] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteNumberValueDecimal(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteNumberValueDecimal(JsonWriterOptions options) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -6088,7 +5674,7 @@ public void WriteNumberValueDecimal(bool formatted, bool skipValidation) jsonUtf8.WriteEndArray(); jsonUtf8.Flush(); - string expectedStr = GetNumbersExpectedString(formatted, numberOfElements, value); + string expectedStr = GetNumbersExpectedString(options, numberOfElements, value); JsonTestHelper.AssertContents(expectedStr, output); } @@ -6168,19 +5754,8 @@ private static void WriteStringHelper(JsonWriterOptions options, string keyStrin } [Theory] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteGuidsValue(bool formatted, bool skipValidation, string keyString) + [MemberData(nameof(WriteValue_TestData))] + public void WriteGuidsValue(JsonWriterOptions options, string keyString) { const int numberOfItems = 1_000; @@ -6190,9 +5765,7 @@ public void WriteGuidsValue(bool formatted, bool skipValidation, string keyStrin guids[i] = Guid.NewGuid(); } - string expectedStr = GetGuidsExpectedString(prettyPrint: formatted, keyString, guids, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetGuidsExpectedString(options, keyString, guids, escape: true); ReadOnlySpan keyUtf16 = keyString.AsSpan(); ReadOnlySpan keyUtf8 = Encoding.UTF8.GetBytes(keyString); @@ -6235,19 +5808,8 @@ public void WriteGuidsValue(bool formatted, bool skipValidation, string keyStrin } [Theory] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteDateTimesValue(bool formatted, bool skipValidation, string keyString) + [MemberData(nameof(WriteValue_TestData))] + public void WriteDateTimesValue(JsonWriterOptions options, string keyString) { var random = new Random(42); const int numberOfItems = 1_000; @@ -6259,9 +5821,7 @@ public void WriteDateTimesValue(bool formatted, bool skipValidation, string keyS for (int i = 0; i < numberOfItems; i++) dates[i] = start.AddDays(random.Next(range)); - string expectedStr = GetDatesExpectedString(prettyPrint: formatted, keyString, dates, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetDatesExpectedString(options, keyString, dates, escape: true); ReadOnlySpan keyUtf16 = keyString.AsSpan(); ReadOnlySpan keyUtf8 = Encoding.UTF8.GetBytes(keyString); @@ -6304,19 +5864,8 @@ public void WriteDateTimesValue(bool formatted, bool skipValidation, string keyS } [Theory] - [InlineData(true, true, "message")] - [InlineData(true, false, "message")] - [InlineData(false, true, "message")] - [InlineData(false, false, "message")] - [InlineData(true, true, "mess>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(true, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, true, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - [InlineData(false, false, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")] - public void WriteDateTimeOffsetsValue(bool formatted, bool skipValidation, string keyString) + [MemberData(nameof(WriteValue_TestData))] + public void WriteDateTimeOffsetsValue(JsonWriterOptions options, string keyString) { var random = new Random(42); const int numberOfItems = 1_000; @@ -6328,9 +5877,7 @@ public void WriteDateTimeOffsetsValue(bool formatted, bool skipValidation, strin for (int i = 0; i < numberOfItems; i++) dates[i] = new DateTimeOffset(start.AddDays(random.Next(range))); - string expectedStr = GetDatesExpectedString(prettyPrint: formatted, keyString, dates, escape: true); - - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + string expectedStr = GetDatesExpectedString(options, keyString, dates, escape: true); ReadOnlySpan keyUtf16 = keyString.AsSpan(); ReadOnlySpan keyUtf8 = Encoding.UTF8.GetBytes(keyString); @@ -6379,11 +5926,8 @@ public void WriteDateTimeOffsetsValue(bool formatted, bool skipValidation, strin [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteLargeKeyOrValue(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteLargeKeyOrValue(JsonWriterOptions options) { try { @@ -6396,8 +5940,6 @@ public void WriteLargeKeyOrValue(bool formatted, bool skipValidation) key.AsSpan().Fill((byte)'a'); value.AsSpan().Fill((byte)'b'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - { var output = new ArrayBufferWriter(1024); using var jsonUtf8 = new Utf8JsonWriter(output, options); @@ -6427,16 +5969,12 @@ public void WriteLargeKeyOrValue(bool formatted, bool skipValidation) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteLargeKeyValue(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteLargeKeyValue(JsonWriterOptions options) { try { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + Span key; Span value; @@ -6461,16 +5999,12 @@ public void WriteLargeKeyValue(bool formatted, bool skipValidation) [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(true, false)] - [InlineData(false, true)] - [InlineData(false, false)] - public void WriteLargeKeyEscapedValue(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteLargeKeyEscapedValue(JsonWriterOptions options) { try { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - + Span key; Span value; @@ -6855,16 +6389,11 @@ private static void WriteStringHelper(JsonEncodedText text, string expectedMessa [ConditionalTheory(typeof(Environment), nameof(Environment.Is64BitProcess))] [OuterLoop] - [InlineData(true, true)] - [InlineData(false, true)] - [InlineData(true, false)] - [InlineData(false, false)] - public void WriteTooLargeArguments(bool formatted, bool skipValidation) + [MemberData(nameof(JsonOptions_TestData))] + public void WriteTooLargeArguments(JsonWriterOptions options) { try { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - byte[] bytesTooLarge; char[] charsTooLarge; var bytes = new byte[5]; @@ -7405,7 +6934,7 @@ private static void WriteNullValue_InArray( JsonTestHelper.AssertContents($"[{nullValue},{wireValue},{wireValue}]", output); } - private static string GetHelloWorldExpectedString(bool prettyPrint, string propertyName, string value) + private static string GetHelloWorldExpectedString(bool prettyPrint, string indentText, string propertyName, string value) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7425,17 +6954,17 @@ private static string GetHelloWorldExpectedString(bool prettyPrint, string prope json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetBase64ExpectedString(bool prettyPrint, string propertyName, byte[] value) + private static string GetBase64ExpectedString(JsonWriterOptions options, string propertyName, byte[] value) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml }; @@ -7453,23 +6982,23 @@ private static string GetBase64ExpectedString(bool prettyPrint, string propertyN json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetCommentInArrayExpectedString(bool prettyPrint, string comment) + private static string GetCommentInArrayExpectedString(JsonWriterOptions options, string comment) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; json.WriteComment(comment); - CompensateNewLine(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); json.WriteStartArray(); for (int j = 0; j < 10; j++) json.WriteComment(comment); @@ -7483,80 +7012,80 @@ private static string GetCommentInArrayExpectedString(bool prettyPrint, string c json.WriteComment(comment); json.WriteEnd(); - CompensateNewLine(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); json.WriteComment(comment); json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetCommentInObjectExpectedString(bool prettyPrint, string comment) + private static string GetCommentInObjectExpectedString(JsonWriterOptions options, string comment) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; json.WriteComment(comment); - CompensateNewLine(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); json.WriteStartObject(); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter, 2); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter, 2); json.WriteComment(comment); json.WritePropertyName("property1"); - CompensateWhitespaces(prettyPrint, json, streamWriter); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); json.WriteComment(comment); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); json.WriteStartArray(); json.WriteEndArray(); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter, 2); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter, 2); json.WriteComment(comment); json.WritePropertyName("property2"); - CompensateWhitespaces(prettyPrint, json, streamWriter); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); json.WriteComment(comment); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter); json.WriteStartObject(); json.WriteEndObject(); - CompensateNewLine(prettyPrint, json, streamWriter); - CompensateWhitespaces(prettyPrint, json, streamWriter, 2); + CompensateNewLine(options.Indented, json, streamWriter); + CompensateWhitespaces(options.Indented, json, streamWriter, 2); json.WriteComment(comment); json.WriteEnd(); - CompensateNewLine(prettyPrint, json, streamWriter); + CompensateNewLine(options.Indented, json, streamWriter); json.WriteComment(comment); json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetStringsExpectedString(bool prettyPrint, string value) + private static string GetStringsExpectedString(bool prettyPrint, string indentText, string value) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7573,15 +7102,15 @@ private static string GetStringsExpectedString(bool prettyPrint, string value) json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetEscapedExpectedString(bool prettyPrint, string propertyName, string value, StringEscapeHandling escaping, bool escape = true) + private static string GetEscapedExpectedString(JsonWriterOptions options, string propertyName, string value, StringEscapeHandling escaping, bool escape = true) { using (TextWriter stringWriter = new StringWriter()) using (var json = new JsonTextWriter(stringWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = escaping }) { @@ -7591,11 +7120,11 @@ private static string GetEscapedExpectedString(bool prettyPrint, string property json.WriteEnd(); json.Flush(); - return stringWriter.ToString(); + return HandleIndent(stringWriter.ToString(), options.IndentText); } } - private static string GetCustomExpectedString(bool prettyPrint) + private static string GetCustomExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7615,10 +7144,10 @@ private static string GetCustomExpectedString(bool prettyPrint) json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetStartEndExpectedString(bool prettyPrint) + private static string GetStartEndExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7635,10 +7164,10 @@ private static string GetStartEndExpectedString(bool prettyPrint) json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetStartEndWithPropertyArrayExpectedString(bool prettyPrint) + private static string GetStartEndWithPropertyArrayExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7656,17 +7185,17 @@ private static string GetStartEndWithPropertyArrayExpectedString(bool prettyPrin json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetStartEndWithPropertyArrayExpectedString(string key, bool prettyPrint, bool escape = false) + private static string GetStartEndWithPropertyArrayExpectedString(string key, JsonWriterOptions options, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml }; @@ -7678,10 +7207,10 @@ private static string GetStartEndWithPropertyArrayExpectedString(string key, boo json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetStartEndWithPropertyObjectExpectedString(bool prettyPrint) + private static string GetStartEndWithPropertyObjectExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7699,17 +7228,17 @@ private static string GetStartEndWithPropertyObjectExpectedString(bool prettyPri json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetStartEndWithPropertyObjectExpectedString(string key, bool prettyPrint, bool escape = false) + private static string GetStartEndWithPropertyObjectExpectedString(string key, JsonWriterOptions options, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml }; @@ -7721,10 +7250,10 @@ private static string GetStartEndWithPropertyObjectExpectedString(string key, bo json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetArrayWithPropertyExpectedString(bool prettyPrint) + private static string GetArrayWithPropertyExpectedString(bool prettyPrint, string indentText) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); @@ -7741,17 +7270,17 @@ private static string GetArrayWithPropertyExpectedString(bool prettyPrint) json.WriteEndObject(); json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); } - private static string GetBooleanExpectedString(bool prettyPrint, string keyString, bool value, bool escape = false) + private static string GetBooleanExpectedString(JsonWriterOptions options, string keyString, bool value, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; @@ -7771,17 +7300,17 @@ private static string GetBooleanExpectedString(bool prettyPrint, string keyStrin json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetNullExpectedString(bool prettyPrint, string keyString, bool escape = false) + private static string GetNullExpectedString(JsonWriterOptions options, string keyString, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; @@ -7801,17 +7330,17 @@ private static string GetNullExpectedString(bool prettyPrint, string keyString, json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetPropertyExpectedString(bool prettyPrint, T value) + private static string GetPropertyExpectedString(JsonWriterOptions options, T value) { var sb = new StringBuilder(); StringWriter stringWriter = new StringWriter(sb); var json = new JsonTextWriter(stringWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7821,17 +7350,17 @@ private static string GetPropertyExpectedString(bool prettyPrint, T value) json.Flush(); - return sb.ToString(); + return HandleIndent(sb.ToString(), options.IndentText); } - private static string GetNumbersExpectedString(bool prettyPrint, string keyString, int[] ints, uint[] uints, long[] longs, ulong[] ulongs, float[] floats, double[] doubles, decimal[] decimals, bool escape = false) + private static string GetNumbersExpectedString(JsonWriterOptions options, string keyString, int[] ints, uint[] uints, long[] longs, ulong[] ulongs, float[] floats, double[] doubles, decimal[] decimals, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7887,7 +7416,7 @@ private static string GetNumbersExpectedString(bool prettyPrint, string keyStrin json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } private static string GetExpectedString_RelaxedEscaping(bool prettyPrint, string keyString) @@ -7918,14 +7447,14 @@ private static string GetExpectedString_RelaxedEscaping(bool prettyPrint, string return Encoding.UTF8.GetString(ms.ToArray()); } - private static string GetGuidsExpectedString(bool prettyPrint, string keyString, Guid[] guids, bool escape = false) + private static string GetGuidsExpectedString(JsonWriterOptions options, string keyString, Guid[] guids, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml }; @@ -7947,17 +7476,17 @@ private static string GetGuidsExpectedString(bool prettyPrint, string keyString, json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetNumbersExpectedString(bool prettyPrint, int numberOfElements, T value) + private static string GetNumbersExpectedString(JsonWriterOptions options, int numberOfElements, T value) { var sb = new StringBuilder(); StringWriter stringWriter = new StringWriter(sb); var json = new JsonTextWriter(stringWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, }; json.WriteStartArray(); @@ -7969,17 +7498,17 @@ private static string GetNumbersExpectedString(bool prettyPrint, int numberOf json.Flush(); - return sb.ToString(); + return HandleIndent(sb.ToString(), options.IndentText); } - private static string GetDatesExpectedString(bool prettyPrint, string keyString, DateTime[] dates, bool escape = false) + private static string GetDatesExpectedString(JsonWriterOptions options, string keyString, DateTime[] dates, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; @@ -8001,17 +7530,17 @@ private static string GetDatesExpectedString(bool prettyPrint, string keyString, json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } - private static string GetDatesExpectedString(bool prettyPrint, string keyString, DateTimeOffset[] dates, bool escape = false) + private static string GetDatesExpectedString(JsonWriterOptions options, string keyString, DateTimeOffset[] dates, bool escape = false) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; @@ -8033,7 +7562,7 @@ private static string GetDatesExpectedString(bool prettyPrint, string keyString, json.Flush(); - return Encoding.UTF8.GetString(ms.ToArray()); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); } private static void CompensateWhitespaces(bool prettyPrint, JsonTextWriter json, TextWriter streamWriter, int whitespaceCount = 1) @@ -8054,6 +7583,11 @@ private static void CompensateNewLine(bool prettyPrint, JsonTextWriter json, Tex } } + private static string HandleIndent(string? text, string? indentText) + { + return text?.Replace(" ", indentText ?? " "); + } + public static IEnumerable JsonEncodedTextStrings { get @@ -8069,6 +7603,33 @@ public static IEnumerable JsonEncodedTextStrings }; } } + + private static IEnumerable JsonOptions() + { + return from indented in new[] { true, false } + from skipValidation in new[] { true, false } + from indentText in indented ? new[] { null, "", " ", " ", " ", "\t" } : [] + select CreateOptions(indented, indentText, skipValidation); + + static JsonWriterOptions CreateOptions(bool indented, string indentText, bool skipValidation) + { + var options = new JsonWriterOptions { Indented = indented, SkipValidation = skipValidation }; + if (indentText is not null) options.IndentText = indentText; + return options; + } + } + + private static IEnumerable JsonOptionsWith(IEnumerable others) => + from options in JsonOptions() + from inputValue in others + select new object[] { options, inputValue }; + + private static IEnumerable JsonOptionsWith(IEnumerable others, IEnumerable anothers) => + from options in JsonOptions() + from inputValue in others + from anotherValue in anothers + select new object[] { options, inputValue, anotherValue }; + } public static class WriterHelpers From 6ea532e26cbbcc5b548b98aca908f0ce90759cbe Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 26 Nov 2023 15:02:28 +0100 Subject: [PATCH 04/27] IndentText must be non-nullable --- .../System.Text.Json/Common/JsonConstants.cs | 2 ++ .../JsonSourceGenerationOptionsAttribute.cs | 2 +- .../gen/JsonSourceGenerator.Parser.cs | 2 +- .../System.Text.Json/ref/System.Text.Json.cs | 6 ++-- .../src/System/Text/Json/JsonConstants.cs | 1 - .../Serialization/JsonSerializerOptions.cs | 9 ++++-- .../Text/Json/Writer/JsonWriterHelper.cs | 11 +++---- .../Text/Json/Writer/JsonWriterOptions.cs | 11 ++++--- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 30 ++++++++++++++--- .../JsonWriterOptionsTests.cs | 1 - .../Utf8JsonWriterTests.cs | 32 +++++++++---------- 11 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs index 4a7209f9a4aba2..4ffc5859ad7b4f 100644 --- a/src/libraries/System.Text.Json/Common/JsonConstants.cs +++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs @@ -11,5 +11,7 @@ internal static partial class JsonConstants public const int StackallocByteThreshold = 256; public const int StackallocCharThreshold = StackallocByteThreshold / 2; + + public const string DefaultIndent = " "; } } diff --git a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs index e33106823aab7d..8bb6e81f860257 100644 --- a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs +++ b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs @@ -128,7 +128,7 @@ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults) /// /// Specifies the default value of when set. /// - public string? IndentText { get; set; } + public string IndentText { get; set; } = JsonConstants.DefaultIndent; /// /// Specifies the default source generation mode for type declarations that don't set a . diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index f455ebdd5c6557..250bfed673cad3 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -375,7 +375,7 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN break; case nameof(JsonSourceGenerationOptionsAttribute.IndentText): - indentText = (string?)namedArg.Value.Value; + indentText = (string)namedArg.Value.Value!; break; case nameof(JsonSourceGenerationOptionsAttribute.GenerationMode): diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index ec12cd39cc7bf7..5e9030e450a086 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -394,7 +394,7 @@ public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } public System.Text.Json.Serialization.JsonUnknownTypeHandling UnknownTypeHandling { get { throw null; } set { } } public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } - public string? IndentText { get { throw null; } set { } } + public string IndentText { get { throw null; } set { } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("JsonSerializerOptions.AddContext is obsolete. To register a JsonSerializerContext, use either the TypeInfoResolver or TypeInfoResolverChain properties.", DiagnosticId="SYSLIB0049", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public void AddContext() where TContext : System.Text.Json.Serialization.JsonSerializerContext, new() { } @@ -440,7 +440,7 @@ public partial struct JsonWriterOptions private int _dummyPrimitive; public System.Text.Encodings.Web.JavaScriptEncoder? Encoder { readonly get { throw null; } set { } } public bool Indented { get { throw null; } set { } } - public string? IndentText { get { throw null; } set { } } + public string IndentText { get { throw null; } set { } } public int MaxDepth { readonly get { throw null; } set { } } public bool SkipValidation { get { throw null; } set { } } } @@ -1076,7 +1076,7 @@ public JsonSourceGenerationOptionsAttribute(System.Text.Json.JsonSerializerDefau public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool UseStringEnumConverter { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } - public string? IndentText { get { throw null; } set { } } + public string IndentText { get { throw null; } set { } } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JsonStringEnumConverter cannot be statically analyzed and requires runtime code generation. Applications should use the generic JsonStringEnumConverter instead.")] public partial class JsonStringEnumConverter : System.Text.Json.Serialization.JsonConverterFactory diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 30751a04a363e7..139fc5f5053ed3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -47,7 +47,6 @@ internal static partial class JsonConstants // Explicitly skipping ReverseSolidus since that is handled separately public static ReadOnlySpan EscapableChars => "\"nrt/ubf"u8; - public const int SpacesPerIndent = 2; public const int RemoveFlagsBitMask = 0x7FFFFFFF; // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 1f694b71ee3b8d..962b4af0d7cb9c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -75,7 +75,7 @@ public static JsonSerializerOptions Default private bool _includeFields; private bool _propertyNameCaseInsensitive; private bool _writeIndented; - private string? _indentText; + private string _indentText = JsonConstants.DefaultIndent; /// /// Constructs a new instance. @@ -654,7 +654,7 @@ public bool WriteIndented /// /// Thrown if this property is set after serialization or deserialization has occurred. /// - public string? IndentText + public string IndentText { get { @@ -662,8 +662,11 @@ public string? IndentText } set { + if (value is null) + { + ThrowHelper.ThrowArgumentNullException(nameof(value)); + } VerifyMutable(); - // Validation? _indentText = value; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index dda96253bca198..20ab79367698ae 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -10,25 +10,24 @@ namespace System.Text.Json { internal static partial class JsonWriterHelper { - public static void WriteIndentation(Span buffer, int indent) + public static void WriteIndentation(Span buffer, int indent, byte indentByte) { - Debug.Assert(indent % JsonConstants.SpacesPerIndent == 0); Debug.Assert(buffer.Length >= indent); // Based on perf tests, the break-even point where vectorized Fill is faster // than explicitly writing the space in a loop is 8. - if (indent < 8) + if (indent < 8 && indent % 2 == 0) { int i = 0; while (i < indent) { - buffer[i++] = JsonConstants.Space; - buffer[i++] = JsonConstants.Space; + buffer[i++] = indentByte; + buffer[i++] = indentByte; } } else { - buffer.Slice(0, indent).Fill(JsonConstants.Space); + buffer.Slice(0, indent).Fill(indentByte); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index f662317a6da49e..efaa72c11893fc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -17,7 +17,7 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; - private string? _indentText; + private string _indentText; /// /// The encoder to use when escaping strings, or to use the default encoder. @@ -48,12 +48,15 @@ public bool Indented /// Defines the text used as indent by the when is enabled /// By default, the JSON is written with 2 white spaces. /// - public string? IndentText + public string IndentText { - get => _indentText; + get => _indentText ?? JsonConstants.DefaultIndent; set { - // Validation? + if (value is null) + { + ThrowHelper.ThrowArgumentNullException(nameof(value)); + } _indentText = value; } } 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 1ed85fe8f6fbf6..e9fee171259450 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 @@ -57,6 +57,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable private int _currentDepth; private Memory? _indentBytes; + private byte? _indentByte; private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. @@ -82,11 +83,30 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int IndentLength => _options.IndentText?.Length ?? JsonConstants.SpacesPerIndent; + private int IndentLength => _options.IndentText.Length; private int Indentation => CurrentDepth * IndentLength; - private Memory IndentBytes => _indentBytes ??= _options.IndentText is not null ? Encoding.UTF8.GetBytes(_options.IndentText) : default; + private Memory IndentBytes => _indentBytes ??= Encoding.UTF8.GetBytes(_options.IndentText); + + private byte? IndentByte => _indentByte ??= GetUniqueIndentByte(); + + private byte? GetUniqueIndentByte() + { + byte? indentByte = null; + foreach (byte b in IndentBytes.Span) + { + byte? previous = indentByte; + indentByte = b; + if (previous is not null && indentByte != previous) + { + indentByte = null; + break; + } + } + + return indentByte; + } internal JsonTokenType TokenType => _tokenType; @@ -1038,11 +1058,11 @@ private void WriteNewLine(Span output) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteIndentation(Span buffer, int indentation) { - if (_options.IndentText is null) + if (IndentByte is not null) { - JsonWriterHelper.WriteIndentation(buffer, indentation); + JsonWriterHelper.WriteIndentation(buffer, indentation, (byte)IndentByte); } - else + else if (IndentBytes.Length > 0) { JsonWriterHelper.WriteIndentation(buffer, indentation, IndentBytes.Span); } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index c17c33326a39eb..cc36cf18450cfa 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -29,7 +29,6 @@ public static void JsonWriterOptionsCtor() var expectedOption = new JsonWriterOptions { Indented = false, - IndentText = null, SkipValidation = false, MaxDepth = 0, }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index 526693055c84c7..da94fdad028884 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -1464,7 +1464,7 @@ public void FixedSizeBufferWriter_Guid(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStringValue(guid)); } - sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 5 : 1; + sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 5 : 1; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1502,7 +1502,7 @@ public void FixedSizeBufferWriter_DateTime(JsonWriterOptions options) } sizeTooSmall += options.Indented ? 23 : 15; - sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 19 : 15; + sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 19 : 15; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1633,7 +1633,7 @@ public void FixedSizeBufferWriter_Decimal(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteNumberValue(value)); } - sizeTooSmall += options.Indented ? 2 * (options.IndentText?.Length ?? 2) + 5 : 1; + sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 5 : 1; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -3080,7 +3080,7 @@ public void Writing3MBBase64Bytes(JsonWriterOptions options) Base64.EncodeToUtf8(value, base64StringUtf8, out _, out int bytesWritten); string expectedValue = Encoding.UTF8.GetString(base64StringUtf8.AsSpan(0, bytesWritten).ToArray()); - string expectedJson = options.Indented ? $"{{{Environment.NewLine}{options.IndentText ?? " "}\"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; + string expectedJson = options.Indented ? $"{{{Environment.NewLine}{options.IndentText}\"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; var output = new ArrayBufferWriter(1024); @@ -3556,14 +3556,14 @@ public void WritePartialHelloWorld(JsonWriterOptions options) Assert.Equal(0, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesCommitted); @@ -3573,19 +3573,19 @@ public void WritePartialHelloWorld(JsonWriterOptions options) jsonUtf8.WriteEndObject(); if (options.Indented) - Assert.Equal(26 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(26, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(27 + (options.IndentText?.Length ?? 2) + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(27 + options.IndentText.Length + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(27, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(53 + (2 * (options.IndentText?.Length ?? 2)) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(53 + (2 * options.IndentText.Length) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(53, jsonUtf8.BytesCommitted); @@ -3673,14 +3673,14 @@ public void WritePartialBase64String(JsonWriterOptions options) Assert.Equal(0, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesCommitted); @@ -3690,19 +3690,19 @@ public void WritePartialBase64String(JsonWriterOptions options) jsonUtf8.WriteEndObject(); if (options.Indented) - Assert.Equal(17 + (options.IndentText?.Length ?? 2) + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(17, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(18 + (options.IndentText?.Length ?? 2) + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(18 + options.IndentText.Length + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(18, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(35 + (2 * (options.IndentText?.Length ?? 2)) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(35 + (2 * options.IndentText.Length) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(35, jsonUtf8.BytesCommitted); @@ -7583,9 +7583,9 @@ private static void CompensateNewLine(bool prettyPrint, JsonTextWriter json, Tex } } - private static string HandleIndent(string? text, string? indentText) + private static string HandleIndent(string text, string indentText) { - return text?.Replace(" ", indentText ?? " "); + return text.Replace(" ", indentText); } public static IEnumerable JsonEncodedTextStrings From c8995a19a64e6e2b43f3cfda7fbeb8e35d90f663 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:03:54 +0100 Subject: [PATCH 05/27] Improve performance --- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) 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 e9fee171259450..02732e0e824ae5 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 @@ -87,27 +87,6 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable private int Indentation => CurrentDepth * IndentLength; - private Memory IndentBytes => _indentBytes ??= Encoding.UTF8.GetBytes(_options.IndentText); - - private byte? IndentByte => _indentByte ??= GetUniqueIndentByte(); - - private byte? GetUniqueIndentByte() - { - byte? indentByte = null; - foreach (byte b in IndentBytes.Span) - { - byte? previous = indentByte; - indentByte = b; - if (previous is not null && indentByte != previous) - { - indentByte = null; - break; - } - } - - return indentByte; - } - internal JsonTokenType TokenType => _tokenType; /// @@ -1058,13 +1037,46 @@ private void WriteNewLine(Span output) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteIndentation(Span buffer, int indentation) { - if (IndentByte is not null) + EnsureIndentation(); + + if (_indentByte is not null) + { + JsonWriterHelper.WriteIndentation(buffer, indentation, (byte)_indentByte); + } + else if (_indentBytes is { Length: > 0 } indentBytes) + { + JsonWriterHelper.WriteIndentation(buffer, indentation, indentBytes.Span); + } + } + + private void EnsureIndentation() + { + Debug.Assert(_options.Indented); + + if (_indentByte is not null || _indentBytes is not null) return; + + if (_options.IndentText is JsonConstants.DefaultIndent) { - JsonWriterHelper.WriteIndentation(buffer, indentation, (byte)IndentByte); + _indentByte = JsonConstants.Space; + return; } - else if (IndentBytes.Length > 0) + + byte[] indentBytes = Encoding.UTF8.GetBytes(_options.IndentText); + + foreach (byte b in indentBytes) + { + byte? previous = _indentByte; + _indentByte = b; + if (previous is not null && _indentByte != previous) + { + _indentByte = null; + break; + } + } + + if (_indentByte is null) { - JsonWriterHelper.WriteIndentation(buffer, indentation, IndentBytes.Span); + _indentBytes = indentBytes; } } From 3f82e03236367aeb3180d5600eb1e8362a594ee4 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:10:29 +0100 Subject: [PATCH 06/27] Add extra tests --- .../JsonWriterOptionsTests.cs | 7 +++ .../Serialization/OptionsTests.cs | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index cc36cf18450cfa..716d552ca8bdaf 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -66,5 +66,12 @@ public static void JsonWriterOptions_MaxDepth_InvalidParameters(int maxDepth) var options = new JsonWriterOptions(); Assert.Throws(() => options.MaxDepth = maxDepth); } + + [Fact] + public static void JsonWriterOptions_IndentText_InvalidParameters() + { + var options = new JsonWriterOptions(); + Assert.Throws(() => options.IndentText = null); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index e291972c6a5a08..fa2c7b013209c9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -330,6 +330,51 @@ public static void WriteIndented() Assert.Contains(Environment.NewLine, json); } + [Fact] + public static void IndentText_WhenNull_ThrowsArgumentNullException() + { + var options = new JsonSerializerOptions(); + Assert.Throws(() => options.IndentText = null); + } + + [Fact] + public static void IndentText() + { + var obj = new BasicCompany(); + obj.Initialize(); + + // Verify default value. + var defaultIndent = " "; + string json = JsonSerializer.Serialize(obj); + Assert.DoesNotContain(defaultIndent, json); + + // Verify default value on options. + var options = new JsonSerializerOptions(); + json = JsonSerializer.Serialize(obj, options); + Assert.DoesNotContain(defaultIndent, json); + + // Enable default indentation. + options = new JsonSerializerOptions(); + options.WriteIndented = true; + json = JsonSerializer.Serialize(obj, options); + Assert.Contains(defaultIndent, json); + + // Set custom indentText without enabling indentation + var tab = "\t"; + Assert.DoesNotContain(tab, json); + options = new JsonSerializerOptions(); + options.IndentText = tab; + json = JsonSerializer.Serialize(obj, options); + Assert.DoesNotContain(tab, json); + + // Set custom indentText with indentation enabled + options = new JsonSerializerOptions(); + options.WriteIndented = true; + options.IndentText = tab; + json = JsonSerializer.Serialize(obj, options); + Assert.DoesNotContain(tab, json); + } + [Fact] public static void ExtensionDataUsesReaderOptions() { From c88aaf3adb2e82a6aa815a1d12f9591e0cd7cc9d Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Mon, 27 Nov 2023 21:13:38 +0100 Subject: [PATCH 07/27] Cleanup --- .../Text/Json/Serialization/JsonSerializerOptions.Caching.cs | 2 +- .../tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs index 394cfd4c441eab..a9cb31d845c756 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs @@ -566,7 +566,7 @@ public int GetHashCode(JsonSerializerOptions options) AddHashCode(ref hc, options._includeFields); AddHashCode(ref hc, options._propertyNameCaseInsensitive); AddHashCode(ref hc, options._writeIndented); - AddHashCode(ref hc, options._indentText?.GetHashCode() ?? 0); + AddHashCode(ref hc, options._indentText.GetHashCode()); AddHashCode(ref hc, options._typeInfoResolver); AddListHashCode(ref hc, options._converters); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index da94fdad028884..cc8eeede632760 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.IO; using System.IO.Pipelines; +using System.Linq; using System.Text.Encodings.Web; using System.Text.Unicode; using System.Threading; @@ -15,7 +16,6 @@ using Microsoft.DotNet.XUnitExtensions; using Newtonsoft.Json; using Xunit; -using System.Linq; namespace System.Text.Json.Tests { From 86c4de54a4ff3c9041c3a90f4176bcd3be6fd4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Andr=C3=A9?= <2341261+manandre@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:00:14 +0100 Subject: [PATCH 08/27] Apply suggestions from code review Co-authored-by: Eirik Tsarpalis --- src/libraries/System.Text.Json/Common/JsonConstants.cs | 1 + .../System/Text/Json/Serialization/JsonSerializerOptions.cs | 3 +-- .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs index 4ffc5859ad7b4f..c7c87d519f6b57 100644 --- a/src/libraries/System.Text.Json/Common/JsonConstants.cs +++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs @@ -12,6 +12,7 @@ internal static partial class JsonConstants public const int StackallocByteThreshold = 256; public const int StackallocCharThreshold = StackallocByteThreshold / 2; + // Two space characters is the default indentation. public const string DefaultIndent = " "; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 962b4af0d7cb9c..468fe2640b5730 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -648,8 +648,7 @@ public bool WriteIndented } /// - /// Defines the text used as indent when is enabled - /// By default, the JSON is indented with 2 white spaces. + /// Defines the indentation string being used when is enabled. Defaults to two space characters. /// /// /// Thrown if this property is set after serialization or deserialization has occurred. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index efaa72c11893fc..d9d13e4911fc94 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -45,8 +45,7 @@ public bool Indented } /// - /// Defines the text used as indent by the when is enabled - /// By default, the JSON is written with 2 white spaces. + /// Defines the indentation string used by when is enabled. Defaults to two space characters. /// public string IndentText { From 976651fb1c31526b1ce09f0a8988ec417abb48e8 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:58:36 +0100 Subject: [PATCH 09/27] Fixes following code review --- .../System/Text/Json/Serialization/JsonSerializerOptions.cs | 1 + .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 3 ++- .../tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs | 2 +- .../tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 468fe2640b5730..499c01f7d00f96 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -650,6 +650,7 @@ public bool WriteIndented /// /// Defines the indentation string being used when is enabled. Defaults to two space characters. /// + /// is . /// /// Thrown if this property is set after serialization or deserialization has occurred. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index d9d13e4911fc94..6c4d9bc268eaa0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -45,8 +45,9 @@ public bool Indented } /// - /// Defines the indentation string used by when is enabled. Defaults to two space characters. + /// Defines the indentation string used by when is enabled. Defaults to two space characters. /// + /// is . public string IndentText { get => _indentText ?? JsonConstants.DefaultIndent; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 716d552ca8bdaf..d9c45756e5c5ce 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -39,7 +39,7 @@ public static void JsonWriterOptionsCtor() [InlineData(true, "\t", true, 0)] [InlineData(true, " ", false, 1)] [InlineData(false, "", true, 1024)] - [InlineData(false, "", false, 1024 * 1024)] + [InlineData(false, "\f\t", false, 1024 * 1024)] public static void JsonWriterOptions(bool indented, string indentText, bool skipValidation, int maxDepth) { var options = new JsonWriterOptions(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index cc8eeede632760..bab19917399410 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -7608,7 +7608,7 @@ private static IEnumerable JsonOptions() { return from indented in new[] { true, false } from skipValidation in new[] { true, false } - from indentText in indented ? new[] { null, "", " ", " ", " ", "\t" } : [] + from indentText in indented ? new[] { "", " ", " ", " ", "\t", "\n", "\r\n", "\t\f\r\n" } : [] select CreateOptions(indented, indentText, skipValidation); static JsonWriterOptions CreateOptions(bool indented, string indentText, bool skipValidation) From 71e77db3ffa29a54481056e0c0069ede3f4aa166 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 1 Dec 2023 01:24:30 +0100 Subject: [PATCH 10/27] Fixes following code review #2 --- .../src/System.Text.Json.csproj | 1 + .../src/System/Text/Json/JsonConstants.cs | 3 + .../Serialization/JsonSerializerOptions.cs | 10 +-- .../Text/Json/Writer/JsonWriterHelper.cs | 67 ++++++++++++++----- .../Text/Json/Writer/JsonWriterOptions.cs | 10 +-- .../System/Text/Json/Writer/RawIndentation.cs | 35 ++++++++++ .../System/Text/Json/Writer/Utf8JsonWriter.cs | 44 +----------- .../JsonWriterOptionsTests.cs | 2 +- .../Serialization/OptionsTests.cs | 2 +- .../Utf8JsonWriterTests.cs | 2 +- 10 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index e9e81da963d5ac..cf3a67e34f65f6 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -154,6 +154,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 139fc5f5053ed3..72246b9062efcf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -27,6 +27,7 @@ internal static partial class JsonConstants public const byte Hyphen = (byte)'-'; public const byte UtcOffsetToken = (byte)'Z'; public const byte TimePrefix = (byte)'T'; + public const byte Null = (byte)'\0'; // \u2028 and \u2029 are considered respectively line and paragraph separators // UTF-8 representation for them is E2, 80, A8/A9 @@ -47,6 +48,8 @@ internal static partial class JsonConstants // Explicitly skipping ReverseSolidus since that is handled separately public static ReadOnlySpan EscapableChars => "\"nrt/ubf"u8; + public static ReadOnlySpan IndentChars => " \t"u8; + public const int RemoveFlagsBitMask = 0x7FFFFFFF; // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 499c01f7d00f96..444470750bdadc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -129,6 +129,7 @@ public JsonSerializerOptions(JsonSerializerOptions options) _typeInfoResolver = options._typeInfoResolver; EffectiveMaxDepth = options.EffectiveMaxDepth; ReferenceHandlingStrategy = options.ReferenceHandlingStrategy; + RawIndent = options.RawIndent; TrackOptionsInstance(this); } @@ -662,15 +663,15 @@ public string IndentText } set { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(nameof(value)); - } VerifyMutable(); + RawIndent = JsonWriterHelper.GetRawIndentation(value); _indentText = value; } } + internal RawIndentation RawIndent { get; private set; } + + /// /// Configures how object references are handled when reading and writing JSON. /// @@ -903,6 +904,7 @@ internal JsonWriterOptions GetWriterOptions() Encoder = Encoder, Indented = WriteIndented, IndentText = IndentText, + RawIndent = RawIndent, MaxDepth = EffectiveMaxDepth, #if !DEBUG SkipValidation = true diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 20ab79367698ae..05fda929ac623b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -10,36 +10,67 @@ namespace System.Text.Json { internal static partial class JsonWriterHelper { - public static void WriteIndentation(Span buffer, int indent, byte indentByte) + public static RawIndentation GetRawIndentation(string value) { - Debug.Assert(buffer.Length >= indent); + if (value is null) + { + ThrowHelper.ThrowArgumentNullException(nameof(value)); + } + + byte[] indentBytes = Encoding.UTF8.GetBytes(value); + byte? indentByte = null; - // Based on perf tests, the break-even point where vectorized Fill is faster - // than explicitly writing the space in a loop is 8. - if (indent < 8 && indent % 2 == 0) + foreach (byte b in indentBytes) { - int i = 0; - while (i < indent) + if (JsonConstants.IndentChars.IndexOf(b) is -1) { - buffer[i++] = indentByte; - buffer[i++] = indentByte; + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} contains an invalid character. Allowed characters are space and horizontal tab."); + } + + if (indentByte is not JsonConstants.Null) + { + byte? previous = indentByte; + indentByte = b; + if (previous is not null && indentByte != previous) + { + indentByte = JsonConstants.Null; + } } } - else - { - buffer.Slice(0, indent).Fill(indentByte); - } + + return new(indentByte, (indentByte is JsonConstants.Null) ? indentBytes : []); } - public static void WriteIndentation(Span buffer, int indentation, Span indent) + public static void WriteIndentation(Span buffer, int indentation, RawIndentation rawIndent) { Debug.Assert(buffer.Length >= indentation); - int offset = 0; - while (offset < indentation) + if (rawIndent.Byte is not JsonConstants.Null) { - indent.CopyTo(buffer.Slice(offset)); - offset += indent.Length; + // Based on perf tests, the break-even point where vectorized Fill is faster + // than explicitly writing the space in a loop is 8. + if (indentation < 8 && indentation % 2 == 0) + { + int i = 0; + while (i < indentation) + { + buffer[i++] = rawIndent.Byte; + buffer[i++] = rawIndent.Byte; + } + } + else + { + buffer.Slice(0, indentation).Fill(rawIndent.Byte); + } + } + else if (rawIndent.Bytes is { Length: > 0 } indentBytes) + { + int offset = 0; + while (offset < indentation) + { + indentBytes.CopyTo(buffer.Slice(offset)); + offset += indentBytes.Length; + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 6c4d9bc268eaa0..63f21830993181 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -48,19 +48,19 @@ public bool Indented /// Defines the indentation string used by when is enabled. Defaults to two space characters. /// /// is . + /// contains an invalid character. Allowed characters are space and horizontal tab. public string IndentText { - get => _indentText ?? JsonConstants.DefaultIndent; + readonly get => _indentText ?? JsonConstants.DefaultIndent; set { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(nameof(value)); - } + RawIndent = JsonWriterHelper.GetRawIndentation(value); _indentText = value; } } + internal RawIndentation RawIndent { get; set; } + /// /// Gets or sets the maximum depth allowed when writing JSON, with the default (i.e. 0) indicating a max depth of 1000. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs new file mode 100644 index 00000000000000..ed539358989882 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Text.Json +{ + internal struct RawIndentation(byte? @byte, Memory bytes) : IEquatable + { + public readonly byte Byte => @byte ?? JsonConstants.Space; + public readonly ReadOnlySpan Bytes => bytes.Span; + + public readonly bool Equals(RawIndentation other) => Byte == other.Byte && Bytes.SequenceEqual(other.Bytes); + + public override bool Equals(object? obj) => obj is RawIndentation indentation && Equals(indentation); + + public override readonly int GetHashCode() + { + HashCode hc = default; + hc.Add(Byte); + hc.Add(Bytes.GetHashCode()); + return hc.ToHashCode(); + } + +#if !NETCOREAPP + /// + /// Polyfill for System.HashCode. + /// + private struct HashCode + { + private int _hashCode; + public void Add(T? value) => _hashCode = (_hashCode, value).GetHashCode(); + public int ToHashCode() => _hashCode; + } +#endif + } +} 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 02732e0e824ae5..724be868c73bd6 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 @@ -56,9 +56,6 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable // else, no list separator is needed since we are writing the first item. private int _currentDepth; - private Memory? _indentBytes; - private byte? _indentByte; - private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. /// @@ -1034,50 +1031,11 @@ private void WriteNewLine(Span output) output[BytesPending++] = JsonConstants.LineFeed; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteIndentation(Span buffer, int indentation) - { - EnsureIndentation(); - - if (_indentByte is not null) - { - JsonWriterHelper.WriteIndentation(buffer, indentation, (byte)_indentByte); - } - else if (_indentBytes is { Length: > 0 } indentBytes) - { - JsonWriterHelper.WriteIndentation(buffer, indentation, indentBytes.Span); - } - } - - private void EnsureIndentation() { Debug.Assert(_options.Indented); - if (_indentByte is not null || _indentBytes is not null) return; - - if (_options.IndentText is JsonConstants.DefaultIndent) - { - _indentByte = JsonConstants.Space; - return; - } - - byte[] indentBytes = Encoding.UTF8.GetBytes(_options.IndentText); - - foreach (byte b in indentBytes) - { - byte? previous = _indentByte; - _indentByte = b; - if (previous is not null && _indentByte != previous) - { - _indentByte = null; - break; - } - } - - if (_indentByte is null) - { - _indentBytes = indentBytes; - } + JsonWriterHelper.WriteIndentation(buffer, indentation, _options.RawIndent); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index d9c45756e5c5ce..983741c17e2e77 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -39,7 +39,7 @@ public static void JsonWriterOptionsCtor() [InlineData(true, "\t", true, 0)] [InlineData(true, " ", false, 1)] [InlineData(false, "", true, 1024)] - [InlineData(false, "\f\t", false, 1024 * 1024)] + [InlineData(false, "\t ", false, 1024 * 1024)] public static void JsonWriterOptions(bool indented, string indentText, bool skipValidation, int maxDepth) { var options = new JsonWriterOptions(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index fa2c7b013209c9..9620e7a38910af 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -372,7 +372,7 @@ public static void IndentText() options.WriteIndented = true; options.IndentText = tab; json = JsonSerializer.Serialize(obj, options); - Assert.DoesNotContain(tab, json); + Assert.Contains(tab, json); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index bab19917399410..727368901dd745 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -7608,7 +7608,7 @@ private static IEnumerable JsonOptions() { return from indented in new[] { true, false } from skipValidation in new[] { true, false } - from indentText in indented ? new[] { "", " ", " ", " ", "\t", "\n", "\r\n", "\t\f\r\n" } : [] + from indentText in indented ? new[] { null, "", " ", " ", " ", "\t", "\t " } : [] select CreateOptions(indented, indentText, skipValidation); static JsonWriterOptions CreateOptions(bool indented, string indentText, bool skipValidation) From 7c44ddaf147580c6d7641c873bf885bae834ad33 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 1 Dec 2023 20:49:43 +0100 Subject: [PATCH 11/27] Add tests for invalid characters --- .../JsonWriterOptionsTests.cs | 15 +++++++++++++++ .../Serialization/OptionsTests.cs | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 983741c17e2e77..061af5a03e85d7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -73,5 +73,20 @@ public static void JsonWriterOptions_IndentText_InvalidParameters() var options = new JsonWriterOptions(); Assert.Throws(() => options.IndentText = null); } + + [Theory] + [InlineData("\f")] + [InlineData("\t\f")] + [InlineData("\n")] + [InlineData("\r")] + [InlineData("\r\n")] + [InlineData("a")] + [InlineData("a ")] + [InlineData("abc")] + public static void JsonWriterOptions_IndentText_InvalidCharacters(string text) + { + var options = new JsonWriterOptions(); + Assert.Throws(() => options.IndentText = text); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index 9620e7a38910af..012b00ce2f6514 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -337,6 +337,21 @@ public static void IndentText_WhenNull_ThrowsArgumentNullException() Assert.Throws(() => options.IndentText = null); } + [Theory] + [InlineData("\f")] + [InlineData("\t\f")] + [InlineData("\n")] + [InlineData("\r")] + [InlineData("\r\n")] + [InlineData("a")] + [InlineData("a ")] + [InlineData("abc")] + public static void IndentText_WithInvalidChartacters_ThrowsArgumentOutOfRangeException(string text) + { + var options = new JsonSerializerOptions(); + Assert.Throws(() => options.IndentText = text); + } + [Fact] public static void IndentText() { From e42ea758eedb59bf6cd9a1284489b11372ea4a89 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:52:53 +0100 Subject: [PATCH 12/27] Handle RawIndent length --- .../src/System/Text/Json/Writer/JsonWriterHelper.cs | 4 +++- .../src/System/Text/Json/Writer/RawIndentation.cs | 4 +++- .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 05fda929ac623b..e217f109d76e03 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -38,7 +38,7 @@ public static RawIndentation GetRawIndentation(string value) } } - return new(indentByte, (indentByte is JsonConstants.Null) ? indentBytes : []); + return new((indentByte is JsonConstants.Null) ? indentBytes : [], indentByte, indentBytes.Length); } public static void WriteIndentation(Span buffer, int indentation, RawIndentation rawIndent) @@ -65,6 +65,8 @@ public static void WriteIndentation(Span buffer, int indentation, RawInden } else if (rawIndent.Bytes is { Length: > 0 } indentBytes) { + Debug.Assert(indentation % indentBytes.Length == 0); + int offset = 0; while (offset < indentation) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs index ed539358989882..e813a5729dc635 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs @@ -3,11 +3,13 @@ namespace System.Text.Json { - internal struct RawIndentation(byte? @byte, Memory bytes) : IEquatable + internal struct RawIndentation(Memory bytes, byte? @byte, int? length) : IEquatable { public readonly byte Byte => @byte ?? JsonConstants.Space; public readonly ReadOnlySpan Bytes => bytes.Span; + public readonly int Length => length ?? 2; + public readonly bool Equals(RawIndentation other) => Byte == other.Byte && Bytes.SequenceEqual(other.Bytes); public override bool Equals(object? obj) => obj is RawIndentation indentation && Equals(indentation); 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 724be868c73bd6..92a079875034b3 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 @@ -80,7 +80,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int IndentLength => _options.IndentText.Length; + private int IndentLength => _options.RawIndent.Length; private int Indentation => CurrentDepth * IndentLength; From face6cc400552a9de1235012b58f33ecda58e892 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 1 Dec 2023 22:47:47 +0100 Subject: [PATCH 13/27] Move all to RawIndentation --- .../src/System/Text/Json/JsonConstants.cs | 1 - .../Serialization/JsonSerializerOptions.cs | 3 +- .../Text/Json/Writer/JsonWriterHelper.cs | 66 ------------ .../Text/Json/Writer/JsonWriterOptions.cs | 2 +- .../System/Text/Json/Writer/RawIndentation.cs | 100 ++++++++++++++++-- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 2 +- 6 files changed, 95 insertions(+), 79 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 72246b9062efcf..d54cc11f13916d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -27,7 +27,6 @@ internal static partial class JsonConstants public const byte Hyphen = (byte)'-'; public const byte UtcOffsetToken = (byte)'Z'; public const byte TimePrefix = (byte)'T'; - public const byte Null = (byte)'\0'; // \u2028 and \u2029 are considered respectively line and paragraph separators // UTF-8 representation for them is E2, 80, A8/A9 diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 444470750bdadc..1ee60adede5738 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -664,14 +664,13 @@ public string IndentText set { VerifyMutable(); - RawIndent = JsonWriterHelper.GetRawIndentation(value); + RawIndent = RawIndentation.FromString(value); _indentText = value; } } internal RawIndentation RawIndent { get; private set; } - /// /// Configures how object references are handled when reading and writing JSON. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index e217f109d76e03..303970b7586f9d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -10,72 +10,6 @@ namespace System.Text.Json { internal static partial class JsonWriterHelper { - public static RawIndentation GetRawIndentation(string value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(nameof(value)); - } - - byte[] indentBytes = Encoding.UTF8.GetBytes(value); - byte? indentByte = null; - - foreach (byte b in indentBytes) - { - if (JsonConstants.IndentChars.IndexOf(b) is -1) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} contains an invalid character. Allowed characters are space and horizontal tab."); - } - - if (indentByte is not JsonConstants.Null) - { - byte? previous = indentByte; - indentByte = b; - if (previous is not null && indentByte != previous) - { - indentByte = JsonConstants.Null; - } - } - } - - return new((indentByte is JsonConstants.Null) ? indentBytes : [], indentByte, indentBytes.Length); - } - - public static void WriteIndentation(Span buffer, int indentation, RawIndentation rawIndent) - { - Debug.Assert(buffer.Length >= indentation); - - if (rawIndent.Byte is not JsonConstants.Null) - { - // Based on perf tests, the break-even point where vectorized Fill is faster - // than explicitly writing the space in a loop is 8. - if (indentation < 8 && indentation % 2 == 0) - { - int i = 0; - while (i < indentation) - { - buffer[i++] = rawIndent.Byte; - buffer[i++] = rawIndent.Byte; - } - } - else - { - buffer.Slice(0, indentation).Fill(rawIndent.Byte); - } - } - else if (rawIndent.Bytes is { Length: > 0 } indentBytes) - { - Debug.Assert(indentation % indentBytes.Length == 0); - - int offset = 0; - while (offset < indentation) - { - indentBytes.CopyTo(buffer.Slice(offset)); - offset += indentBytes.Length; - } - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateProperty(ReadOnlySpan propertyName) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 63f21830993181..0e70e16ce00944 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -54,7 +54,7 @@ public string IndentText readonly get => _indentText ?? JsonConstants.DefaultIndent; set { - RawIndent = JsonWriterHelper.GetRawIndentation(value); + RawIndent = RawIndentation.FromString(value); _indentText = value; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs index e813a5729dc635..61e015492a60af 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs @@ -1,24 +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.Diagnostics; + namespace System.Text.Json { - internal struct RawIndentation(Memory bytes, byte? @byte, int? length) : IEquatable + internal readonly struct RawIndentation : IEquatable { - public readonly byte Byte => @byte ?? JsonConstants.Space; - public readonly ReadOnlySpan Bytes => bytes.Span; + private readonly Memory _bytes; + private readonly int? _length; + private readonly byte? _byte; + + private const byte Null = (byte)'\0'; + + public readonly byte Byte => _byte ?? JsonConstants.Space; + public readonly ReadOnlySpan Bytes => _bytes.Span; + public readonly int Length => _length ?? 2; + + public static RawIndentation FromString(string value) => new(value); - public readonly int Length => length ?? 2; + private RawIndentation(string value) + { + if (value is null) + { + ThrowHelper.ThrowArgumentNullException(nameof(value)); + } + + byte[] indentBytes = Encoding.UTF8.GetBytes(value); + byte? indentByte = null; - public readonly bool Equals(RawIndentation other) => Byte == other.Byte && Bytes.SequenceEqual(other.Bytes); + foreach (byte b in indentBytes) + { + if (JsonConstants.IndentChars.IndexOf(b) is -1) + { + throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} contains an invalid character. Allowed characters are space and horizontal tab."); + } - public override bool Equals(object? obj) => obj is RawIndentation indentation && Equals(indentation); + if (indentByte is not Null) + { + byte? previous = indentByte; + indentByte = b; + if (previous is not null && indentByte != previous) + { + indentByte = Null; + } + } + } + + _byte = indentByte; + _length = indentBytes.Length; + + if (indentByte is Null) + { + _bytes = indentBytes; + } + } + + public readonly bool Equals(RawIndentation other) => + _byte == other._byte && + _length == other._length && + _bytes.Span.SequenceEqual(other._bytes.Span); + + public override bool Equals(object? obj) => + obj is RawIndentation indentation && Equals(indentation); public override readonly int GetHashCode() { HashCode hc = default; - hc.Add(Byte); - hc.Add(Bytes.GetHashCode()); + hc.Add(_byte); + hc.Add(_length); + hc.Add(_bytes.GetHashCode()); return hc.ToHashCode(); } @@ -33,5 +84,38 @@ private struct HashCode public int ToHashCode() => _hashCode; } #endif + + public void Write(Span buffer, int indentation) + { + Debug.Assert(buffer.Length >= indentation); + + if (Byte is not Null) + { + // Based on perf tests, the break-even point where vectorized Fill is faster + // than explicitly writing the space in a loop is 8. + if (indentation < 8 && indentation % 2 == 0) + { + int i = 0; + while (i < indentation) + { + buffer[i++] = Byte; + buffer[i++] = Byte; + } + } + else + { + buffer.Slice(0, indentation).Fill(Byte); + } + } + else if (Bytes is { Length: > 0 } indentBytes) + { + int offset = 0; + while (offset + indentBytes.Length <= indentation) + { + indentBytes.CopyTo(buffer.Slice(offset)); + offset += indentBytes.Length; + } + } + } } } 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 92a079875034b3..4f675dfc7735b3 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 @@ -1035,7 +1035,7 @@ private void WriteIndentation(Span buffer, int indentation) { Debug.Assert(_options.Indented); - JsonWriterHelper.WriteIndentation(buffer, indentation, _options.RawIndent); + _options.RawIndent.Write(buffer, indentation); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 29118b43eb1466c084ba42b83c1fd6648a71073e Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:05:22 +0100 Subject: [PATCH 14/27] Update documentation --- .../System/Text/Json/Serialization/JsonSerializerOptions.cs | 2 ++ .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 1ee60adede5738..3d84c410a715be 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -651,7 +651,9 @@ public bool WriteIndented /// /// Defines the indentation string being used when is enabled. Defaults to two space characters. /// + /// Allowed characters are space and horizontal tab. /// is . + /// contains an invalid character. /// /// Thrown if this property is set after serialization or deserialization has occurred. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 0e70e16ce00944..76090549bd44e7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -47,8 +47,9 @@ public bool Indented /// /// Defines the indentation string used by when is enabled. Defaults to two space characters. /// + /// Allowed characters are space and horizontal tab. /// is . - /// contains an invalid character. Allowed characters are space and horizontal tab. + /// contains an invalid character. public string IndentText { readonly get => _indentText ?? JsonConstants.DefaultIndent; From 6f6eca73112c72ec55d38486506f7a6b284ddf99 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Mon, 4 Dec 2023 21:39:03 +0100 Subject: [PATCH 15/27] Additional fixes from code review --- .../System.Text.Json/src/System.Text.Json.csproj | 2 +- .../src/System/Text/Json/JsonConstants.cs | 2 +- .../Text/Json/Serialization/JsonSerializerOptions.cs | 8 ++++---- ...awIndentation.cs => JsonWriterIndentationData.cs} | 12 ++++++------ .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 4 ++-- .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) rename src/libraries/System.Text.Json/src/System/Text/Json/Writer/{RawIndentation.cs => JsonWriterIndentationData.cs} (88%) diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index cf3a67e34f65f6..9016b507a5b905 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -154,7 +154,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET - + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index d54cc11f13916d..0767adfabcf77b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -47,7 +47,7 @@ internal static partial class JsonConstants // Explicitly skipping ReverseSolidus since that is handled separately public static ReadOnlySpan EscapableChars => "\"nrt/ubf"u8; - public static ReadOnlySpan IndentChars => " \t"u8; + public static ReadOnlySpan ValidIndentChars => " \t"u8; public const int RemoveFlagsBitMask = 0x7FFFFFFF; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 3d84c410a715be..90f47c0f15ca2a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -129,7 +129,7 @@ public JsonSerializerOptions(JsonSerializerOptions options) _typeInfoResolver = options._typeInfoResolver; EffectiveMaxDepth = options.EffectiveMaxDepth; ReferenceHandlingStrategy = options.ReferenceHandlingStrategy; - RawIndent = options.RawIndent; + IndentData = options.IndentData; TrackOptionsInstance(this); } @@ -666,12 +666,12 @@ public string IndentText set { VerifyMutable(); - RawIndent = RawIndentation.FromString(value); + IndentData = JsonWriterIndentationData.FromString(value); _indentText = value; } } - internal RawIndentation RawIndent { get; private set; } + internal JsonWriterIndentationData IndentData { get; private set; } /// /// Configures how object references are handled when reading and writing JSON. @@ -905,7 +905,7 @@ internal JsonWriterOptions GetWriterOptions() Encoder = Encoder, Indented = WriteIndented, IndentText = IndentText, - RawIndent = RawIndent, + IndentData = IndentData, MaxDepth = EffectiveMaxDepth, #if !DEBUG SkipValidation = true diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs similarity index 88% rename from src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs index 61e015492a60af..c096e839907adf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/RawIndentation.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs @@ -5,7 +5,7 @@ namespace System.Text.Json { - internal readonly struct RawIndentation : IEquatable + internal readonly struct JsonWriterIndentationData : IEquatable { private readonly Memory _bytes; private readonly int? _length; @@ -17,9 +17,9 @@ namespace System.Text.Json public readonly ReadOnlySpan Bytes => _bytes.Span; public readonly int Length => _length ?? 2; - public static RawIndentation FromString(string value) => new(value); + public static JsonWriterIndentationData FromString(string value) => new(value); - private RawIndentation(string value) + private JsonWriterIndentationData(string value) { if (value is null) { @@ -31,7 +31,7 @@ private RawIndentation(string value) foreach (byte b in indentBytes) { - if (JsonConstants.IndentChars.IndexOf(b) is -1) + if (JsonConstants.ValidIndentChars.IndexOf(b) is -1) { throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} contains an invalid character. Allowed characters are space and horizontal tab."); } @@ -56,13 +56,13 @@ private RawIndentation(string value) } } - public readonly bool Equals(RawIndentation other) => + public readonly bool Equals(JsonWriterIndentationData other) => _byte == other._byte && _length == other._length && _bytes.Span.SequenceEqual(other._bytes.Span); public override bool Equals(object? obj) => - obj is RawIndentation indentation && Equals(indentation); + obj is JsonWriterIndentationData indentation && Equals(indentation); public override readonly int GetHashCode() { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 76090549bd44e7..02af9a198401fa 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -55,12 +55,12 @@ public string IndentText readonly get => _indentText ?? JsonConstants.DefaultIndent; set { - RawIndent = RawIndentation.FromString(value); + IndentData = JsonWriterIndentationData.FromString(value); _indentText = value; } } - internal RawIndentation RawIndent { get; set; } + internal JsonWriterIndentationData IndentData { get; set; } /// /// Gets or sets the maximum depth allowed when writing JSON, with the default (i.e. 0) indicating a max depth of 1000. 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 4f675dfc7735b3..e8193bb5558e37 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 @@ -80,7 +80,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int IndentLength => _options.RawIndent.Length; + private int IndentLength => _options.IndentData.Length; private int Indentation => CurrentDepth * IndentLength; @@ -1035,7 +1035,7 @@ private void WriteIndentation(Span buffer, int indentation) { Debug.Assert(_options.Indented); - _options.RawIndent.Write(buffer, indentation); + _options.IndentData.Write(buffer, indentation); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 037f2fa71c8e6d1d675b783cc5ecde553db2b9bf Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 15 Dec 2023 22:33:48 +0100 Subject: [PATCH 16/27] Move to the new API --- .../System.Text.Json/Common/JsonConstants.cs | 5 +- .../JsonSourceGenerationOptionsAttribute.cs | 9 +- .../gen/JsonSourceGenerator.Emitter.cs | 8 +- .../gen/JsonSourceGenerator.Parser.cs | 14 +- .../gen/Model/SourceGenerationOptionsSpec.cs | 4 +- .../System.Text.Json/ref/System.Text.Json.cs | 9 +- .../src/Resources/Strings.resx | 6 + .../src/System.Text.Json.csproj | 1 - .../JsonSerializerOptions.Caching.cs | 6 +- .../Serialization/JsonSerializerOptions.cs | 44 +++-- .../src/System/Text/Json/ThrowHelper.cs | 12 ++ .../Text/Json/Writer/JsonWriterHelper.cs | 35 ++++ .../Json/Writer/JsonWriterIndentationData.cs | 121 ------------- .../Text/Json/Writer/JsonWriterOptions.cs | 29 ++- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 8 +- .../JsonSourceGenerationOptionsTests.cs | 6 +- .../JsonWriterOptionsTests.cs | 43 ++--- .../Serialization/CacheTests.cs | 3 +- .../Serialization/OptionsTests.cs | 62 +++++-- .../Utf8JsonWriterTests.cs | 166 +++++++++--------- 20 files changed, 306 insertions(+), 285 deletions(-) delete mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs index c7c87d519f6b57..ccfd426be25610 100644 --- a/src/libraries/System.Text.Json/Common/JsonConstants.cs +++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs @@ -13,6 +13,9 @@ internal static partial class JsonConstants public const int StackallocCharThreshold = StackallocByteThreshold / 2; // Two space characters is the default indentation. - public const string DefaultIndent = " "; + public const char DefaultIndentCharacter = ' '; + public const int DefaultIndentSize = 2; + public const int MinimumIndentSize = 0; + public const int MaximumIndentSize = 127; } } diff --git a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs index 8bb6e81f860257..e7d6032fede4e7 100644 --- a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs +++ b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs @@ -126,9 +126,14 @@ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults) public bool WriteIndented { get; set; } /// - /// Specifies the default value of when set. + /// Specifies the default value of when set. /// - public string IndentText { get; set; } = JsonConstants.DefaultIndent; + public char IndentCharacter { get; set; } = JsonConstants.DefaultIndentCharacter; + + /// + /// Specifies the default value of when set. + /// + public int IndentSize { get; set; } = JsonConstants.DefaultIndentSize; /// /// Specifies the default source generation mode for type declarations that don't set a . diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 4a70521c490903..025a8be741cf7d 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -1168,8 +1168,11 @@ private static void GetLogicForDefaultSerializerOptionsInit(SourceGenerationOpti if (optionsSpec.WriteIndented is bool writeIndented) writer.WriteLine($"WriteIndented = {FormatBool(writeIndented)},"); - if (optionsSpec.IndentText is string indentText) - writer.WriteLine($"IndentText = {FormatStringLiteral(indentText)},"); + if (optionsSpec.IndentCharacter is char indentCharacter) + writer.WriteLine($"IndentCharacter = {FormatChar(indentCharacter)},"); + + if (optionsSpec.IndentSize is int indentSize) + writer.WriteLine($"IndentSize = {indentSize},"); writer.Indentation--; writer.WriteLine("};"); @@ -1347,6 +1350,7 @@ private static string FormatJsonSerializerDefaults(JsonSerializerDefaults defaul private static string FormatBool(bool value) => value ? "true" : "false"; private static string FormatStringLiteral(string? value) => value is null ? "null" : $"\"{value}\""; + private static string FormatChar(char value) => $"'{value}'"; /// /// Method used to generate JsonTypeInfo given options instance diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 250bfed673cad3..3be80faceb84fe 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -280,7 +280,8 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN JsonUnmappedMemberHandling? unmappedMemberHandling = null; bool? useStringEnumConverter = null; bool? writeIndented = null; - string? indentText = null; + char? indentCharacter = null; + int? indentSize = null; if (attributeData.ConstructorArguments.Length > 0) { @@ -374,8 +375,12 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN writeIndented = (bool)namedArg.Value.Value!; break; - case nameof(JsonSourceGenerationOptionsAttribute.IndentText): - indentText = (string)namedArg.Value.Value!; + case nameof(JsonSourceGenerationOptionsAttribute.IndentCharacter): + indentCharacter = (char)namedArg.Value.Value!; + break; + + case nameof(JsonSourceGenerationOptionsAttribute.IndentSize): + indentSize = (int)namedArg.Value.Value!; break; case nameof(JsonSourceGenerationOptionsAttribute.GenerationMode): @@ -409,7 +414,8 @@ private SourceGenerationOptionsSpec ParseJsonSourceGenerationOptionsAttribute(IN UnmappedMemberHandling = unmappedMemberHandling, UseStringEnumConverter = useStringEnumConverter, WriteIndented = writeIndented, - IndentText = indentText, + IndentCharacter = indentCharacter, + IndentSize = indentSize, }; } diff --git a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs index b5e6331d9843e0..17126929c0e096 100644 --- a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs @@ -52,7 +52,9 @@ public sealed record SourceGenerationOptionsSpec public required bool? WriteIndented { get; init; } - public required string? IndentText { get; init; } + public required char? IndentCharacter { get; init; } + + public required int? IndentSize { get; init; } public JsonKnownNamingPolicy? GetEffectivePropertyNamingPolicy() => PropertyNamingPolicy ?? (Defaults is JsonSerializerDefaults.Web ? JsonKnownNamingPolicy.CamelCase : null); diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 5e9030e450a086..fe9371a28d2491 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -394,7 +394,8 @@ public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } public System.Text.Json.Serialization.JsonUnknownTypeHandling UnknownTypeHandling { get { throw null; } set { } } public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } - public string IndentText { get { throw null; } set { } } + public char IndentCharacter { get { throw null; } set { } } + public int IndentSize { get { throw null; } set { } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("JsonSerializerOptions.AddContext is obsolete. To register a JsonSerializerContext, use either the TypeInfoResolver or TypeInfoResolverChain properties.", DiagnosticId="SYSLIB0049", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public void AddContext() where TContext : System.Text.Json.Serialization.JsonSerializerContext, new() { } @@ -440,7 +441,8 @@ public partial struct JsonWriterOptions private int _dummyPrimitive; public System.Text.Encodings.Web.JavaScriptEncoder? Encoder { readonly get { throw null; } set { } } public bool Indented { get { throw null; } set { } } - public string IndentText { get { throw null; } set { } } + public char IndentCharacter { get { throw null; } set { } } + public int IndentSize { get { throw null; } set { } } public int MaxDepth { readonly get { throw null; } set { } } public bool SkipValidation { get { throw null; } set { } } } @@ -1076,7 +1078,8 @@ public JsonSourceGenerationOptionsAttribute(System.Text.Json.JsonSerializerDefau public System.Text.Json.Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get { throw null; } set { } } public bool UseStringEnumConverter { get { throw null; } set { } } public bool WriteIndented { get { throw null; } set { } } - public string IndentText { get { throw null; } set { } } + public char IndentCharacter { get { throw null; } set { } } + public int IndentSize { get { throw null; } set { } } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JsonStringEnumConverter cannot be statically analyzed and requires runtime code generation. Applications should use the generic JsonStringEnumConverter instead.")] public partial class JsonStringEnumConverter : System.Text.Json.Serialization.JsonConverterFactory diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index 411d20d45d6be0..acd31cc6cce253 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -708,4 +708,10 @@ Either the JSON value is not in a supported format, or is out of bounds for a Half. + + Supported indentation characters are space and horizontal tab. + + + Indentation size must be between {0} and {1}. + diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 9016b507a5b905..e9e81da963d5ac 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -154,7 +154,6 @@ The System.Text.Json library is built-in as part of the shared framework in .NET - diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs index a9cb31d845c756..f76bdea2de2a36 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs @@ -511,7 +511,8 @@ public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right) left._includeFields == right._includeFields && left._propertyNameCaseInsensitive == right._propertyNameCaseInsensitive && left._writeIndented == right._writeIndented && - left._indentText == right._indentText && + left._indentCharacter == right._indentCharacter && + left._indentSize == right._indentSize && left._typeInfoResolver == right._typeInfoResolver && CompareLists(left._converters, right._converters); @@ -566,7 +567,8 @@ public int GetHashCode(JsonSerializerOptions options) AddHashCode(ref hc, options._includeFields); AddHashCode(ref hc, options._propertyNameCaseInsensitive); AddHashCode(ref hc, options._writeIndented); - AddHashCode(ref hc, options._indentText.GetHashCode()); + AddHashCode(ref hc, options._indentCharacter); + AddHashCode(ref hc, options._indentSize); AddHashCode(ref hc, options._typeInfoResolver); AddListHashCode(ref hc, options._converters); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 90f47c0f15ca2a..dad6af3f43999f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -75,7 +75,8 @@ public static JsonSerializerOptions Default private bool _includeFields; private bool _propertyNameCaseInsensitive; private bool _writeIndented; - private string _indentText = JsonConstants.DefaultIndent; + private char _indentCharacter = JsonConstants.DefaultIndentCharacter; + private int _indentSize = JsonConstants.DefaultIndentSize; /// /// Constructs a new instance. @@ -125,11 +126,11 @@ public JsonSerializerOptions(JsonSerializerOptions options) _includeFields = options._includeFields; _propertyNameCaseInsensitive = options._propertyNameCaseInsensitive; _writeIndented = options._writeIndented; - _indentText = options._indentText; + _indentCharacter = options._indentCharacter; + _indentSize = options._indentSize; _typeInfoResolver = options._typeInfoResolver; EffectiveMaxDepth = options.EffectiveMaxDepth; ReferenceHandlingStrategy = options.ReferenceHandlingStrategy; - IndentData = options.IndentData; TrackOptionsInstance(this); } @@ -649,29 +650,48 @@ public bool WriteIndented } /// - /// Defines the indentation string being used when is enabled. Defaults to two space characters. + /// Defines the indentation character being used when is enabled. Defaults to the space character. /// /// Allowed characters are space and horizontal tab. - /// is . /// contains an invalid character. /// /// Thrown if this property is set after serialization or deserialization has occurred. /// - public string IndentText + public char IndentCharacter { get { - return _indentText; + return _indentCharacter; } set { + JsonWriterHelper.ValidateIndentCharacter(value); VerifyMutable(); - IndentData = JsonWriterIndentationData.FromString(value); - _indentText = value; + _indentCharacter = value; } } - internal JsonWriterIndentationData IndentData { get; private set; } + /// + /// Defines the indentation size being used when is enabled. Defaults to two. + /// + /// Allowed values are all integers between 0 and 127. + /// is out of the allowed range. + /// + /// Thrown if this property is set after serialization or deserialization has occurred. + /// + public int IndentSize + { + get + { + return _indentSize; + } + set + { + JsonWriterHelper.ValidateIndentSize(value); + VerifyMutable(); + _indentSize = value; + } + } /// /// Configures how object references are handled when reading and writing JSON. @@ -904,8 +924,8 @@ internal JsonWriterOptions GetWriterOptions() { Encoder = Encoder, Indented = WriteIndented, - IndentText = IndentText, - IndentData = IndentData, + IndentCharacter = IndentCharacter, + IndentSize = IndentSize, MaxDepth = EffectiveMaxDepth, #if !DEBUG SkipValidation = true diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs index 3d8913f8d2c782..58bd0a71724911 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs @@ -12,6 +12,18 @@ internal static partial class ThrowHelper // If the exception source is this value, the serializer will re-throw as JsonException. public const string ExceptionSourceValueToRethrowAsJsonException = "System.Text.Json.Rethrowable"; + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException_IndentCharacter(string parameterName) + { + throw GetArgumentOutOfRangeException(parameterName, SR.InvalidIndentCharacter); + } + + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException_IndentSize(string parameterName, int minimumSize, int maximumSize) + { + throw GetArgumentOutOfRangeException(parameterName, SR.Format(SR.InvalidIndentSize, minimumSize, maximumSize)); + } + [DoesNotReturn] public static void ThrowArgumentOutOfRangeException_MaxDepthMustBePositive(string parameterName) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 303970b7586f9d..f642d7c0cbfdf1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -10,6 +10,41 @@ namespace System.Text.Json { internal static partial class JsonWriterHelper { + public static void WriteIndentation(Span buffer, int indent, byte indentByte) + { + Debug.Assert(buffer.Length >= indent); + + // Based on perf tests, the break-even point where vectorized Fill is faster + // than explicitly writing the space in a loop is 8. + if (indent is 2 or 4 or 6) + { + int i = 0; + while (i < indent) + { + buffer[i++] = indentByte; + buffer[i++] = indentByte; + } + } + else if (indent is not 0) + { + buffer.Slice(0, indent).Fill(indentByte); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ValidateIndentCharacter(char value) + { + if ((byte)value is not JsonConstants.Space and not JsonConstants.Tab) + ThrowHelper.ThrowArgumentOutOfRangeException_IndentCharacter(nameof(value)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ValidateIndentSize(int value) + { + if (value is < JsonConstants.MinimumIndentSize or > JsonConstants.MaximumIndentSize) + ThrowHelper.ThrowArgumentOutOfRangeException_IndentSize(nameof(value), JsonConstants.MinimumIndentSize, JsonConstants.MaximumIndentSize); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateProperty(ReadOnlySpan propertyName) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs deleted file mode 100644 index c096e839907adf..00000000000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterIndentationData.cs +++ /dev/null @@ -1,121 +0,0 @@ -// 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; - -namespace System.Text.Json -{ - internal readonly struct JsonWriterIndentationData : IEquatable - { - private readonly Memory _bytes; - private readonly int? _length; - private readonly byte? _byte; - - private const byte Null = (byte)'\0'; - - public readonly byte Byte => _byte ?? JsonConstants.Space; - public readonly ReadOnlySpan Bytes => _bytes.Span; - public readonly int Length => _length ?? 2; - - public static JsonWriterIndentationData FromString(string value) => new(value); - - private JsonWriterIndentationData(string value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(nameof(value)); - } - - byte[] indentBytes = Encoding.UTF8.GetBytes(value); - byte? indentByte = null; - - foreach (byte b in indentBytes) - { - if (JsonConstants.ValidIndentChars.IndexOf(b) is -1) - { - throw new ArgumentOutOfRangeException(nameof(value), $"{nameof(value)} contains an invalid character. Allowed characters are space and horizontal tab."); - } - - if (indentByte is not Null) - { - byte? previous = indentByte; - indentByte = b; - if (previous is not null && indentByte != previous) - { - indentByte = Null; - } - } - } - - _byte = indentByte; - _length = indentBytes.Length; - - if (indentByte is Null) - { - _bytes = indentBytes; - } - } - - public readonly bool Equals(JsonWriterIndentationData other) => - _byte == other._byte && - _length == other._length && - _bytes.Span.SequenceEqual(other._bytes.Span); - - public override bool Equals(object? obj) => - obj is JsonWriterIndentationData indentation && Equals(indentation); - - public override readonly int GetHashCode() - { - HashCode hc = default; - hc.Add(_byte); - hc.Add(_length); - hc.Add(_bytes.GetHashCode()); - return hc.ToHashCode(); - } - -#if !NETCOREAPP - /// - /// Polyfill for System.HashCode. - /// - private struct HashCode - { - private int _hashCode; - public void Add(T? value) => _hashCode = (_hashCode, value).GetHashCode(); - public int ToHashCode() => _hashCode; - } -#endif - - public void Write(Span buffer, int indentation) - { - Debug.Assert(buffer.Length >= indentation); - - if (Byte is not Null) - { - // Based on perf tests, the break-even point where vectorized Fill is faster - // than explicitly writing the space in a loop is 8. - if (indentation < 8 && indentation % 2 == 0) - { - int i = 0; - while (i < indentation) - { - buffer[i++] = Byte; - buffer[i++] = Byte; - } - } - else - { - buffer.Slice(0, indentation).Fill(Byte); - } - } - else if (Bytes is { Length: > 0 } indentBytes) - { - int offset = 0; - while (offset + indentBytes.Length <= indentation) - { - indentBytes.CopyTo(buffer.Slice(offset)); - offset += indentBytes.Length; - } - } - } - } -} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 02af9a198401fa..38c0e22591c185 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -17,7 +17,8 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; - private string _indentText; + private char? _indentCharacter; + private int? _indentSize; /// /// The encoder to use when escaping strings, or to use the default encoder. @@ -45,22 +46,34 @@ public bool Indented } /// - /// Defines the indentation string used by when is enabled. Defaults to two space characters. + /// Defines the indentation character used by when is enabled. Defaults to the space character. /// /// Allowed characters are space and horizontal tab. - /// is . /// contains an invalid character. - public string IndentText + public char IndentCharacter { - readonly get => _indentText ?? JsonConstants.DefaultIndent; + readonly get => _indentCharacter ?? JsonConstants.DefaultIndentCharacter; set { - IndentData = JsonWriterIndentationData.FromString(value); - _indentText = value; + JsonWriterHelper.ValidateIndentCharacter(value); + _indentCharacter = value; } } - internal JsonWriterIndentationData IndentData { get; set; } + /// + /// Defines the indentation size used by when is enabled. Defaults to two. + /// + /// Allowed values are integers between 0 and 127. + /// is out of the allowed range. + public int IndentSize + { + readonly get => _indentSize ?? JsonConstants.DefaultIndentSize; + set + { + JsonWriterHelper.ValidateIndentSize(value); + _indentSize = value; + } + } /// /// Gets or sets the maximum depth allowed when writing JSON, with the default (i.e. 0) indicating a max depth of 1000. 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 e8193bb5558e37..0d4ce926ba24b8 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 @@ -80,7 +80,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int IndentLength => _options.IndentData.Length; + private int IndentLength => _options.IndentSize; private int Indentation => CurrentDepth * IndentLength; @@ -1031,11 +1031,9 @@ private void WriteNewLine(Span output) output[BytesPending++] = JsonConstants.LineFeed; } - private void WriteIndentation(Span buffer, int indentation) + private void WriteIndentation(Span buffer, int indent) { - Debug.Assert(_options.Indented); - - _options.IndentData.Write(buffer, indentation); + JsonWriterHelper.WriteIndentation(buffer, indent, (byte)_options.IndentCharacter); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs index 1257e168bc0020..9c1c30818f6b2d 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSourceGenerationOptionsTests.cs @@ -78,7 +78,8 @@ public static void ContextWithAllOptionsSet_GeneratesExpectedOptions() UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode, UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, WriteIndented = true, - IndentText = "\t", + IndentCharacter = '\t', + IndentSize = 1, TypeInfoResolver = ContextWithAllOptionsSet.Default, }; @@ -106,7 +107,8 @@ public static void ContextWithAllOptionsSet_GeneratesExpectedOptions() UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode, UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, WriteIndented = true, - IndentText = "\t")] + IndentCharacter = '\t', + IndentSize = 1)] [JsonSerializable(typeof(PersonStruct))] public partial class ContextWithAllOptionsSet : JsonSerializerContext { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 061af5a03e85d7..0957f4fbe10e53 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -36,22 +36,24 @@ public static void JsonWriterOptionsCtor() } [Theory] - [InlineData(true, "\t", true, 0)] - [InlineData(true, " ", false, 1)] - [InlineData(false, "", true, 1024)] - [InlineData(false, "\t ", false, 1024 * 1024)] - public static void JsonWriterOptions(bool indented, string indentText, bool skipValidation, int maxDepth) + [InlineData(true, '\t', 1, true, 0)] + [InlineData(true, ' ', 1, false, 1)] + [InlineData(false, ' ', 0, true, 1024)] + [InlineData(false, ' ', 4, false, 1024 * 1024)] + public static void JsonWriterOptions(bool indented, char indentCharacter, int indentSize, bool skipValidation, int maxDepth) { var options = new JsonWriterOptions(); options.Indented = indented; - options.IndentText = indentText; + options.IndentCharacter = indentCharacter; + options.IndentSize = indentSize; options.SkipValidation = skipValidation; options.MaxDepth = maxDepth; var expectedOption = new JsonWriterOptions { Indented = indented, - IndentText = indentText, + IndentCharacter = indentCharacter, + IndentSize = indentSize, SkipValidation = skipValidation, MaxDepth = maxDepth, }; @@ -67,26 +69,27 @@ public static void JsonWriterOptions_MaxDepth_InvalidParameters(int maxDepth) Assert.Throws(() => options.MaxDepth = maxDepth); } - [Fact] - public static void JsonWriterOptions_IndentText_InvalidParameters() + [Theory] + [InlineData('\f')] + [InlineData('\n')] + [InlineData('\r')] + [InlineData('\0')] + [InlineData('a')] + public static void JsonWriterOptions_IndentCharacter_InvalidCharacter(char character) { var options = new JsonWriterOptions(); - Assert.Throws(() => options.IndentText = null); + Assert.Throws(() => options.IndentCharacter = character); } [Theory] - [InlineData("\f")] - [InlineData("\t\f")] - [InlineData("\n")] - [InlineData("\r")] - [InlineData("\r\n")] - [InlineData("a")] - [InlineData("a ")] - [InlineData("abc")] - public static void JsonWriterOptions_IndentText_InvalidCharacters(string text) + [InlineData(-1)] + [InlineData(128)] + [InlineData(int.MinValue)] + [InlineData(int.MaxValue)] + public static void JsonWriterOptions_IndentSize_OutOfRange(int size) { var options = new JsonWriterOptions(); - Assert.Throws(() => options.IndentText = text); + Assert.Throws(() => options.IndentSize = size); } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs index 22e937224325b2..05e2e0b48c37ff 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs @@ -372,7 +372,8 @@ public static void JsonSerializerOptions_EqualityComparer_ChangingAnySettingShou yield return (GetProp(nameof(JsonSerializerOptions.ReadCommentHandling)), JsonCommentHandling.Skip); yield return (GetProp(nameof(JsonSerializerOptions.UnknownTypeHandling)), JsonUnknownTypeHandling.JsonNode); yield return (GetProp(nameof(JsonSerializerOptions.WriteIndented)), true); - yield return (GetProp(nameof(JsonSerializerOptions.IndentText)), "\t"); + yield return (GetProp(nameof(JsonSerializerOptions.IndentCharacter)), '\t'); + yield return (GetProp(nameof(JsonSerializerOptions.IndentSize)), 1); yield return (GetProp(nameof(JsonSerializerOptions.ReferenceHandler)), ReferenceHandler.Preserve); yield return (GetProp(nameof(JsonSerializerOptions.TypeInfoResolver)), new DefaultJsonTypeInfoResolver()); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index 012b00ce2f6514..6eca101c811cbc 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -330,30 +330,31 @@ public static void WriteIndented() Assert.Contains(Environment.NewLine, json); } - [Fact] - public static void IndentText_WhenNull_ThrowsArgumentNullException() + [Theory] + [InlineData('\f')] + [InlineData('\n')] + [InlineData('\r')] + [InlineData('\0')] + [InlineData('a')] + public static void IndentCharacters_WithInvalidChartacters_ThrowsArgumentOutOfRangeException(char character) { var options = new JsonSerializerOptions(); - Assert.Throws(() => options.IndentText = null); + Assert.Throws(() => options.IndentCharacter = character); } [Theory] - [InlineData("\f")] - [InlineData("\t\f")] - [InlineData("\n")] - [InlineData("\r")] - [InlineData("\r\n")] - [InlineData("a")] - [InlineData("a ")] - [InlineData("abc")] - public static void IndentText_WithInvalidChartacters_ThrowsArgumentOutOfRangeException(string text) + [InlineData(-1)] + [InlineData(128)] + [InlineData(int.MinValue)] + [InlineData(int.MaxValue)] + public static void IndentSize_WithInvalidSize_ThrowsArgumentOutOfRangeException(int size) { var options = new JsonSerializerOptions(); - Assert.Throws(() => options.IndentText = text); + Assert.Throws(() => options.IndentSize = size); } [Fact] - public static void IndentText() + public static void IndentCharacter() { var obj = new BasicCompany(); obj.Initialize(); @@ -374,22 +375,45 @@ public static void IndentText() json = JsonSerializer.Serialize(obj, options); Assert.Contains(defaultIndent, json); - // Set custom indentText without enabling indentation - var tab = "\t"; + // Set custom indentCharacter without enabling indentation + var tab = '\t'; Assert.DoesNotContain(tab, json); options = new JsonSerializerOptions(); - options.IndentText = tab; + options.IndentCharacter = tab; json = JsonSerializer.Serialize(obj, options); Assert.DoesNotContain(tab, json); - // Set custom indentText with indentation enabled + // Set custom indentCharacter with indentation enabled options = new JsonSerializerOptions(); options.WriteIndented = true; - options.IndentText = tab; + options.IndentCharacter = tab; json = JsonSerializer.Serialize(obj, options); Assert.Contains(tab, json); } + [Fact] + public static void IndentSize() + { + var obj = new BasicCompany(); + obj.Initialize(); + + var tab = '\t'; + // Set custom indentSize without enabling indentation + var options = new JsonSerializerOptions(); + options.IndentCharacter = tab; + options.IndentSize = 1; + var json = JsonSerializer.Serialize(obj, options); + Assert.DoesNotContain(tab, json); + + // Set custom indentSize with indentation enabled + options = new JsonSerializerOptions(); + options.WriteIndented = true; + options.IndentCharacter = tab; + options.IndentSize = 4; + json = JsonSerializer.Serialize(obj, options); + Assert.Contains(new string(tab, 4), json); + } + [Fact] public static void ExtensionDataUsesReaderOptions() { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index 727368901dd745..c4fa1c9e6c3eb5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -1376,7 +1376,7 @@ public async Task WriteLargeToStream(JsonWriterOptions options) await WriteLargeToStreamHelper(stream, options); - string expectedString = GetExpectedLargeString(options.Indented, options.IndentText); + string expectedString = GetExpectedLargeString(options); string actualString = Encoding.UTF8.GetString(stream.ToArray()); Assert.Equal(expectedString, actualString); @@ -1423,14 +1423,14 @@ private static async Task WriteLargeToStreamHelper(Stream stream, JsonWriterOpti jsonUtf8.WriteEndArray(); } - private static string GetExpectedLargeString(bool prettyPrint, string indentText) + private static string GetExpectedLargeString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartArray(); @@ -1442,15 +1442,15 @@ private static string GetExpectedLargeString(bool prettyPrint, string indentText json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } [Theory] [MemberData(nameof(JsonOptions_TestData))] public void FixedSizeBufferWriter_Guid(JsonWriterOptions options) { - - int sizeTooSmall = 256; + int sizeTooSmall = options.Indented ? options.IndentSize + 229 : 225; + sizeTooSmall = Math.Max(sizeTooSmall, 256); var output = new FixedSizedBufferWriter(sizeTooSmall); byte[] utf8String = Encoding.UTF8.GetBytes(new string('a', 215)); @@ -1464,7 +1464,7 @@ public void FixedSizeBufferWriter_Guid(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStringValue(guid)); } - sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 5 : 1; + sizeTooSmall += options.Indented ? options.IndentSize + 40 : 38; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1486,8 +1486,8 @@ public void FixedSizeBufferWriter_Guid(JsonWriterOptions options) [MemberData(nameof(JsonOptions_TestData))] public void FixedSizeBufferWriter_DateTime(JsonWriterOptions options) { - - int sizeTooSmall = 256; + int sizeTooSmall = options.Indented ? options.IndentSize + 240 : 236; + sizeTooSmall = Math.Max(sizeTooSmall, 256); var output = new FixedSizedBufferWriter(sizeTooSmall); byte[] utf8String = Encoding.UTF8.GetBytes(new string('a', 232)); @@ -1501,8 +1501,7 @@ public void FixedSizeBufferWriter_DateTime(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStringValue(date)); } - sizeTooSmall += options.Indented ? 23 : 15; - sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 19 : 15; + sizeTooSmall += options.Indented ? options.IndentSize + 37 : 35; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1524,8 +1523,8 @@ public void FixedSizeBufferWriter_DateTime(JsonWriterOptions options) [MemberData(nameof(JsonOptions_TestData))] public void FixedSizeBufferWriter_DateTimeOffset(JsonWriterOptions options) { - - int sizeTooSmall = 256; + int sizeTooSmall = options.Indented ? options.IndentSize + 240 : 236; + sizeTooSmall = Math.Max(sizeTooSmall, 256); var output = new FixedSizedBufferWriter(sizeTooSmall); byte[] utf8String = Encoding.UTF8.GetBytes(new string('a', 226)); @@ -1539,7 +1538,7 @@ public void FixedSizeBufferWriter_DateTimeOffset(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStringValue(date)); } - sizeTooSmall += options.Indented ? 23 : 15; + sizeTooSmall += options.Indented ? options.IndentSize + 37 : 35; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -1619,7 +1618,8 @@ public void FixedSizeBufferWriter_Decimal(JsonWriterOptions options) } { - int sizeTooSmall = 256; + int sizeTooSmall = options.Indented ? options.IndentSize + 230 : 226; + sizeTooSmall = Math.Max(sizeTooSmall, 256); var output = new FixedSizedBufferWriter(sizeTooSmall); byte[] utf8String = Encoding.UTF8.GetBytes(new string('a', 222)); @@ -1633,7 +1633,7 @@ public void FixedSizeBufferWriter_Decimal(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteNumberValue(value)); } - sizeTooSmall += options.Indented ? 2 * options.IndentText.Length + 5 : 1; + sizeTooSmall += options.Indented ? options.IndentSize + 33 : 31; output = new FixedSizedBufferWriter(sizeTooSmall); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { @@ -2722,7 +2722,7 @@ public void WriteSeparateProperties(JsonWriterOptions options) json.Flush(); - string expectedStr = HandleIndent(stringWriter.ToString(), options.IndentText); + string expectedStr = HandleIndent(stringWriter.ToString(), options); using var jsonUtf8 = new Utf8JsonWriter(output, options); jsonUtf8.WriteStartObject(); @@ -3080,7 +3080,7 @@ public void Writing3MBBase64Bytes(JsonWriterOptions options) Base64.EncodeToUtf8(value, base64StringUtf8, out _, out int bytesWritten); string expectedValue = Encoding.UTF8.GetString(base64StringUtf8.AsSpan(0, bytesWritten).ToArray()); - string expectedJson = options.Indented ? $"{{{Environment.NewLine}{options.IndentText}\"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; + string expectedJson = options.Indented ? $"{{{Environment.NewLine}{GetIndentText(options)}\"foo\": \"{expectedValue}\"{Environment.NewLine}}}" : $"{{\"foo\":\"{expectedValue}\"}}"; var output = new ArrayBufferWriter(1024); @@ -3150,7 +3150,7 @@ public void WriteHelloWorld(JsonWriterOptions options) { string propertyName = "message"; string value = "Hello, World!"; - string expectedStr = GetHelloWorldExpectedString(prettyPrint: options.Indented, options.IndentText, propertyName, value); + string expectedStr = GetHelloWorldExpectedString(options, propertyName, value); JsonEncodedText encodedPropertyName = JsonEncodedText.Encode(propertyName); JsonEncodedText encodedValue = JsonEncodedText.Encode(value); @@ -3343,7 +3343,7 @@ public void WriteHelloWorldEscaped(JsonWriterOptions options) { string propertyName = "mess> propertyNameSpan = propertyName.AsSpan(); ReadOnlySpan valueSpan = value.AsSpan(); @@ -3556,14 +3556,14 @@ public void WritePartialHelloWorld(JsonWriterOptions options) Assert.Equal(0, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(26 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(26 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(26, jsonUtf8.BytesCommitted); @@ -3573,19 +3573,19 @@ public void WritePartialHelloWorld(JsonWriterOptions options) jsonUtf8.WriteEndObject(); if (options.Indented) - Assert.Equal(26 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + Assert.Equal(26 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(26, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(27 + options.IndentText.Length + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(27 + options.IndentSize + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(27, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(53 + (2 * options.IndentText.Length) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(53 + (2 * options.IndentSize) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(53, jsonUtf8.BytesCommitted); @@ -3673,14 +3673,14 @@ public void WritePartialBase64String(JsonWriterOptions options) Assert.Equal(0, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(17 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(17 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(17, jsonUtf8.BytesCommitted); @@ -3690,19 +3690,19 @@ public void WritePartialBase64String(JsonWriterOptions options) jsonUtf8.WriteEndObject(); if (options.Indented) - Assert.Equal(17 + options.IndentText.Length + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); + Assert.Equal(17 + options.IndentSize + Environment.NewLine.Length + 1, jsonUtf8.BytesCommitted); else Assert.Equal(17, jsonUtf8.BytesCommitted); if (options.Indented) - Assert.Equal(18 + options.IndentText.Length + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space + Assert.Equal(18 + options.IndentSize + (2 * Environment.NewLine.Length) + 1, jsonUtf8.BytesPending); // new lines, indentation, white space else Assert.Equal(18, jsonUtf8.BytesPending); jsonUtf8.Flush(); if (options.Indented) - Assert.Equal(35 + (2 * options.IndentText.Length) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space + Assert.Equal(35 + (2 * options.IndentSize) + (3 * Environment.NewLine.Length) + (1 * 2), jsonUtf8.BytesCommitted); // new lines, indentation, white space else Assert.Equal(35, jsonUtf8.BytesCommitted); @@ -4043,18 +4043,18 @@ public void WriteCommentsInvalidTextAllowed(JsonWriterOptions options) jsonUtf8.WriteCommentValue(comment.AsSpan()); jsonUtf8.Flush(); - string expectedStr = GetCommentExpectedString(prettyPrint: options.Indented, options.IndentText); + string expectedStr = GetCommentExpectedString(options); JsonTestHelper.AssertContents(expectedStr, output); } - private static string GetCommentExpectedString(bool prettyPrint, string indentText) + private static string GetCommentExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml, }; @@ -4076,7 +4076,7 @@ private static string GetCommentExpectedString(bool prettyPrint, string indentTe json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } [Theory] @@ -4170,7 +4170,7 @@ public void WriteCommentsInObject_ComparedWithStringLiteral(bool formatted, stri public void WriteStrings(JsonWriterOptions options) { string value = "temp"; - string expectedStr = GetStringsExpectedString(prettyPrint: options.Indented, options.IndentText, value); + string expectedStr = GetStringsExpectedString(options, value); for (int i = 0; i < 3; i++) { @@ -4807,14 +4807,14 @@ public void WriteCustomStrings(JsonWriterOptions options) jsonUtf8.WriteEndObject(); jsonUtf8.Flush(); - JsonTestHelper.AssertContents(GetCustomExpectedString(options.Indented, options.IndentText), output); + JsonTestHelper.AssertContents(GetCustomExpectedString(options), output); } [Theory] [MemberData(nameof(JsonOptions_TestData))] public void WriteStartEnd(JsonWriterOptions options) { - string expectedStr = GetStartEndExpectedString(prettyPrint: options.Indented, options.IndentText); + string expectedStr = GetStartEndExpectedString(options); var output = new ArrayBufferWriter(1024); @@ -4869,7 +4869,7 @@ public void WriteStartEndInvalid(bool formatted) [MemberData(nameof(JsonOptions_TestData))] public void WriteStartEndWithPropertyNameArray(JsonWriterOptions options) { - string expectedStr = GetStartEndWithPropertyArrayExpectedString(prettyPrint: options.Indented, options.IndentText); + string expectedStr = GetStartEndWithPropertyArrayExpectedString(options); for (int i = 0; i < 3; i++) @@ -4951,7 +4951,7 @@ public void WriteStartEndWithPropertyNameArrayDifferentKeyLengths(JsonWriterOpti [MemberData(nameof(JsonOptions_TestData))] public void WriteStartEndWithPropertyNameObject(JsonWriterOptions options) { - string expectedStr = GetStartEndWithPropertyObjectExpectedString(prettyPrint: options.Indented, options.IndentText); + string expectedStr = GetStartEndWithPropertyObjectExpectedString(options); for (int i = 0; i < 3; i++) { @@ -5026,7 +5026,7 @@ public void WriteStartEndWithPropertyNameObjectDifferentKeyLengths(JsonWriterOpt [MemberData(nameof(JsonOptions_TestData))] public void WriteArrayWithProperty(JsonWriterOptions options) { - string expectedStr = GetArrayWithPropertyExpectedString(prettyPrint: options.Indented, options.IndentText); + string expectedStr = GetArrayWithPropertyExpectedString(options); for (int i = 0; i < 3; i++) { @@ -6934,14 +6934,14 @@ private static void WriteNullValue_InArray( JsonTestHelper.AssertContents($"[{nullValue},{wireValue},{wireValue}]", output); } - private static string GetHelloWorldExpectedString(bool prettyPrint, string indentText, string propertyName, string value) + private static string GetHelloWorldExpectedString(JsonWriterOptions options, string propertyName, string value) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None, + Formatting = options.Indented ? Formatting.Indented : Formatting.None, StringEscapeHandling = StringEscapeHandling.EscapeHtml }; @@ -6954,7 +6954,7 @@ private static string GetHelloWorldExpectedString(bool prettyPrint, string inden json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetBase64ExpectedString(JsonWriterOptions options, string propertyName, byte[] value) @@ -6982,7 +6982,7 @@ private static string GetBase64ExpectedString(JsonWriterOptions options, string json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetCommentInArrayExpectedString(JsonWriterOptions options, string comment) @@ -7016,7 +7016,7 @@ private static string GetCommentInArrayExpectedString(JsonWriterOptions options, json.WriteComment(comment); json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetCommentInObjectExpectedString(JsonWriterOptions options, string comment) @@ -7082,17 +7082,17 @@ private static string GetCommentInObjectExpectedString(JsonWriterOptions options json.WriteComment(comment); json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } - private static string GetStringsExpectedString(bool prettyPrint, string indentText, string value) + private static string GetStringsExpectedString(JsonWriterOptions options, string value) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartArray(); @@ -7102,7 +7102,7 @@ private static string GetStringsExpectedString(bool prettyPrint, string indentTe json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetEscapedExpectedString(JsonWriterOptions options, string propertyName, string value, StringEscapeHandling escaping, bool escape = true) @@ -7120,18 +7120,18 @@ private static string GetEscapedExpectedString(JsonWriterOptions options, string json.WriteEnd(); json.Flush(); - return HandleIndent(stringWriter.ToString(), options.IndentText); + return HandleIndent(stringWriter.ToString(), options); } } - private static string GetCustomExpectedString(bool prettyPrint, string indentText) + private static string GetCustomExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7144,17 +7144,17 @@ private static string GetCustomExpectedString(bool prettyPrint, string indentTex json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } - private static string GetStartEndExpectedString(bool prettyPrint, string indentText) + private static string GetStartEndExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartArray(); @@ -7164,17 +7164,17 @@ private static string GetStartEndExpectedString(bool prettyPrint, string indentT json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } - private static string GetStartEndWithPropertyArrayExpectedString(bool prettyPrint, string indentText) + private static string GetStartEndWithPropertyArrayExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7185,7 +7185,7 @@ private static string GetStartEndWithPropertyArrayExpectedString(bool prettyPrin json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetStartEndWithPropertyArrayExpectedString(string key, JsonWriterOptions options, bool escape = false) @@ -7207,17 +7207,17 @@ private static string GetStartEndWithPropertyArrayExpectedString(string key, Jso json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } - private static string GetStartEndWithPropertyObjectExpectedString(bool prettyPrint, string indentText) + private static string GetStartEndWithPropertyObjectExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7228,7 +7228,7 @@ private static string GetStartEndWithPropertyObjectExpectedString(bool prettyPri json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetStartEndWithPropertyObjectExpectedString(string key, JsonWriterOptions options, bool escape = false) @@ -7250,17 +7250,17 @@ private static string GetStartEndWithPropertyObjectExpectedString(string key, Js json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } - private static string GetArrayWithPropertyExpectedString(bool prettyPrint, string indentText) + private static string GetArrayWithPropertyExpectedString(JsonWriterOptions options) { var ms = new MemoryStream(); TextWriter streamWriter = new StreamWriter(ms, new UTF8Encoding(false), 1024, true); var json = new JsonTextWriter(streamWriter) { - Formatting = prettyPrint ? Formatting.Indented : Formatting.None + Formatting = options.Indented ? Formatting.Indented : Formatting.None }; json.WriteStartObject(); @@ -7270,7 +7270,7 @@ private static string GetArrayWithPropertyExpectedString(bool prettyPrint, strin json.WriteEndObject(); json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), indentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetBooleanExpectedString(JsonWriterOptions options, string keyString, bool value, bool escape = false) @@ -7300,7 +7300,7 @@ private static string GetBooleanExpectedString(JsonWriterOptions options, string json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetNullExpectedString(JsonWriterOptions options, string keyString, bool escape = false) @@ -7330,7 +7330,7 @@ private static string GetNullExpectedString(JsonWriterOptions options, string ke json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetPropertyExpectedString(JsonWriterOptions options, T value) @@ -7350,7 +7350,7 @@ private static string GetPropertyExpectedString(JsonWriterOptions options, T json.Flush(); - return HandleIndent(sb.ToString(), options.IndentText); + return HandleIndent(sb.ToString(), options); } private static string GetNumbersExpectedString(JsonWriterOptions options, string keyString, int[] ints, uint[] uints, long[] longs, ulong[] ulongs, float[] floats, double[] doubles, decimal[] decimals, bool escape = false) @@ -7416,7 +7416,7 @@ private static string GetNumbersExpectedString(JsonWriterOptions options, string json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetExpectedString_RelaxedEscaping(bool prettyPrint, string keyString) @@ -7476,7 +7476,7 @@ private static string GetGuidsExpectedString(JsonWriterOptions options, string k json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetNumbersExpectedString(JsonWriterOptions options, int numberOfElements, T value) @@ -7498,7 +7498,7 @@ private static string GetNumbersExpectedString(JsonWriterOptions options, int json.Flush(); - return HandleIndent(sb.ToString(), options.IndentText); + return HandleIndent(sb.ToString(), options); } private static string GetDatesExpectedString(JsonWriterOptions options, string keyString, DateTime[] dates, bool escape = false) @@ -7530,7 +7530,7 @@ private static string GetDatesExpectedString(JsonWriterOptions options, string k json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static string GetDatesExpectedString(JsonWriterOptions options, string keyString, DateTimeOffset[] dates, bool escape = false) @@ -7562,7 +7562,7 @@ private static string GetDatesExpectedString(JsonWriterOptions options, string k json.Flush(); - return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options.IndentText); + return HandleIndent(Encoding.UTF8.GetString(ms.ToArray()), options); } private static void CompensateWhitespaces(bool prettyPrint, JsonTextWriter json, TextWriter streamWriter, int whitespaceCount = 1) @@ -7583,11 +7583,13 @@ private static void CompensateNewLine(bool prettyPrint, JsonTextWriter json, Tex } } - private static string HandleIndent(string text, string indentText) + private static string HandleIndent(string text, JsonWriterOptions options) { - return text.Replace(" ", indentText); + return text.Replace(" ", GetIndentText(options)); } + private static string GetIndentText(JsonWriterOptions options) => new(options.IndentCharacter, options.IndentSize); + public static IEnumerable JsonEncodedTextStrings { get @@ -7608,13 +7610,15 @@ private static IEnumerable JsonOptions() { return from indented in new[] { true, false } from skipValidation in new[] { true, false } - from indentText in indented ? new[] { null, "", " ", " ", " ", "\t", "\t " } : [] - select CreateOptions(indented, indentText, skipValidation); + from indentCharacter in indented ? new char?[] { null, ' ', '\t' } : [] + from indentSize in indented ? new int?[] { null, 0, 1, 2, 127 } : [] + select CreateOptions(indented, indentCharacter, indentSize, skipValidation); - static JsonWriterOptions CreateOptions(bool indented, string indentText, bool skipValidation) + static JsonWriterOptions CreateOptions(bool indented, char? indentCharacter, int? indentSize, bool skipValidation) { var options = new JsonWriterOptions { Indented = indented, SkipValidation = skipValidation }; - if (indentText is not null) options.IndentText = indentText; + if (indentCharacter is not null) options.IndentCharacter = (char)indentCharacter; + if (indentSize is not null) options.IndentSize = (int)indentSize; return options; } } From 7c76a353f1490c766359d1479de583faba164de0 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sat, 16 Dec 2023 00:41:29 +0100 Subject: [PATCH 17/27] Extra fixes and enhancements --- .../ConsoleLoggerConfigureOptions.cs | 2 +- .../ConsoleLoggerExtensionsTests.cs | 1 + .../gen/JsonSourceGenerator.Emitter.cs | 4 ++-- .../src/System/Text/Json/JsonConstants.cs | 2 -- .../src/System/Text/Json/Writer/JsonWriterHelper.cs | 3 +-- .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 8 +++++--- .../Writer/Utf8JsonWriter.WriteProperties.Bytes.cs | 4 ++-- .../Utf8JsonWriter.WriteProperties.DateTime.cs | 4 ++-- .../Utf8JsonWriter.WriteProperties.DateTimeOffset.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.Decimal.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.Double.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.Float.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.Guid.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.Literal.cs | 4 ++-- .../Utf8JsonWriter.WriteProperties.SignedNumber.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteProperties.String.cs | 12 ++++++------ .../Utf8JsonWriter.WriteProperties.UnsignedNumber.cs | 4 ++-- .../Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs | 2 +- .../Writer/Utf8JsonWriter.WriteValues.Comment.cs | 4 ++-- .../Writer/Utf8JsonWriter.WriteValues.DateTime.cs | 2 +- .../Utf8JsonWriter.WriteValues.DateTimeOffset.cs | 2 +- .../Writer/Utf8JsonWriter.WriteValues.Decimal.cs | 2 +- .../Json/Writer/Utf8JsonWriter.WriteValues.Double.cs | 2 +- .../Json/Writer/Utf8JsonWriter.WriteValues.Float.cs | 2 +- .../Utf8JsonWriter.WriteValues.FormattedNumber.cs | 2 +- .../Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs | 2 +- .../Writer/Utf8JsonWriter.WriteValues.Literal.cs | 2 +- .../Utf8JsonWriter.WriteValues.SignedNumber.cs | 2 +- .../Json/Writer/Utf8JsonWriter.WriteValues.String.cs | 4 ++-- .../Utf8JsonWriter.WriteValues.UnsignedNumber.cs | 2 +- .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 4 ++-- 31 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerConfigureOptions.cs b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerConfigureOptions.cs index c30e842d3fc3ee..3b725f1cb59e03 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerConfigureOptions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerConfigureOptions.cs @@ -25,7 +25,7 @@ public void EnsureConsoleLoggerOptions_ConfigureOptions_SupportsAllProperties() Assert.Equal(3, typeof(ConsoleFormatterOptions).GetProperties(flags).Length); Assert.Equal(5, typeof(SimpleConsoleFormatterOptions).GetProperties(flags).Length); Assert.Equal(4, typeof(JsonConsoleFormatterOptions).GetProperties(flags).Length); - Assert.Equal(4, typeof(JsonWriterOptions).GetProperties(flags).Length); + Assert.Equal(6, typeof(JsonWriterOptions).GetProperties(flags).Length); } [Theory] diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs index 99b49170ed8e1d..aa138a8d5c8f0c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs @@ -597,6 +597,7 @@ private static void VerifyHasOnlySimpleProperties(Type type) // or else NativeAOT would break Assert.True(prop.PropertyType == typeof(string) || prop.PropertyType == typeof(bool) || + prop.PropertyType == typeof(char) || prop.PropertyType == typeof(int) || prop.PropertyType.IsEnum, $"ConsoleOptions property '{type.Name}.{prop.Name}' must be a simple type in order for NativeAOT to work"); } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 025a8be741cf7d..f9c8eca55444ba 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -1169,7 +1169,7 @@ private static void GetLogicForDefaultSerializerOptionsInit(SourceGenerationOpti writer.WriteLine($"WriteIndented = {FormatBool(writeIndented)},"); if (optionsSpec.IndentCharacter is char indentCharacter) - writer.WriteLine($"IndentCharacter = {FormatChar(indentCharacter)},"); + writer.WriteLine($"IndentCharacter = {FormatIndentChar(indentCharacter)},"); if (optionsSpec.IndentSize is int indentSize) writer.WriteLine($"IndentSize = {indentSize},"); @@ -1350,7 +1350,7 @@ private static string FormatJsonSerializerDefaults(JsonSerializerDefaults defaul private static string FormatBool(bool value) => value ? "true" : "false"; private static string FormatStringLiteral(string? value) => value is null ? "null" : $"\"{value}\""; - private static string FormatChar(char value) => $"'{value}'"; + private static string FormatIndentChar(char value) => value is '\t' ? "'\\t'" : $"'{value}'"; /// /// Method used to generate JsonTypeInfo given options instance diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 0767adfabcf77b..139fc5f5053ed3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -47,8 +47,6 @@ internal static partial class JsonConstants // Explicitly skipping ReverseSolidus since that is handled separately public static ReadOnlySpan EscapableChars => "\"nrt/ubf"u8; - public static ReadOnlySpan ValidIndentChars => " \t"u8; - public const int RemoveFlagsBitMask = 0x7FFFFFFF; // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index f642d7c0cbfdf1..e59729bdfb35c9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -16,13 +16,12 @@ public static void WriteIndentation(Span buffer, int indent, byte indentBy // Based on perf tests, the break-even point where vectorized Fill is faster // than explicitly writing the space in a loop is 8. - if (indent is 2 or 4 or 6) + if (indent is < 8) { int i = 0; while (i < indent) { buffer[i++] = indentByte; - buffer[i++] = indentByte; } } else if (indent is not 0) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 38c0e22591c185..1e23be69d15042 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -17,9 +17,11 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; - private char? _indentCharacter; + private byte? _indentByte; private int? _indentSize; + internal readonly byte IndentByte => _indentByte ?? JsonConstants.Space; + /// /// The encoder to use when escaping strings, or to use the default encoder. /// @@ -52,11 +54,11 @@ public bool Indented /// contains an invalid character. public char IndentCharacter { - readonly get => _indentCharacter ?? JsonConstants.DefaultIndentCharacter; + readonly get => (char)IndentByte; set { JsonWriterHelper.ValidateIndentCharacter(value); - _indentCharacter = value; + _indentByte = (byte)value; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs index 435005e7ecc47b..be446e93a3de99 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs @@ -280,7 +280,7 @@ private void WriteBase64Minimized(ReadOnlySpan escapedPropertyName, ReadOn private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int encodedLength = Base64.GetMaxEncodedToUtf8Length(bytes.Length); @@ -330,7 +330,7 @@ private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int encodedLength = Base64.GetMaxEncodedToUtf8Length(bytes.Length); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs index 154c28d34babef..993adf00a2a453 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs @@ -284,7 +284,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, DateTi private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTime value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); @@ -333,7 +333,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTime value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs index 80485289695967..0d881aac48393b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs @@ -283,7 +283,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, DateTi private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); @@ -332,7 +332,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs index 452cf44b339e08..c52cd838779cec 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs @@ -277,7 +277,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, decima private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDecimalLength - 5 - s_newLineLength); @@ -323,7 +323,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDecimalLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs index ca3c5ca65e200b..d229bdffcc4843 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs @@ -281,7 +281,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, double private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDoubleLength - 5 - s_newLineLength); @@ -327,7 +327,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDoubleLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs index 27c0255b61c299..79a80f67b6b649 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs @@ -281,7 +281,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, float private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatSingleLength - 5 - s_newLineLength); @@ -327,7 +327,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatSingleLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs index a46dc3ebbf7d9c..c11c3e37e1a468 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs @@ -285,7 +285,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, Guid v private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatGuidLength - 7 - s_newLineLength); @@ -335,7 +335,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid va private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatGuidLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs index cce486a5e7883c..2ba0269cf5eb5d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs @@ -427,7 +427,7 @@ private void WriteLiteralSection(ReadOnlySpan escapedPropertyNameSection, private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(value.Length <= JsonConstants.MaxUnescapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - value.Length - 5 - s_newLineLength); @@ -473,7 +473,7 @@ private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOn private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(value.Length <= JsonConstants.MaxUnescapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - value.Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs index d60cbe66fcf05b..85e80494e59731 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs @@ -353,7 +353,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, long v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatInt64Length - 5 - s_newLineLength); @@ -399,7 +399,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long va private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatInt64Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs index f0939ab11a8f00..f1eea86026b586 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs @@ -187,7 +187,7 @@ private void WriteStringMinimizedPropertyName(ReadOnlySpan escapedProperty private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyName) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue - 5 - indent - s_newLineLength) / JsonConstants.MaxExpansionFactorWhileTranscoding); @@ -375,7 +375,7 @@ private void WriteStringPropertyNameSection(ReadOnlySpan escapedPropertyNa private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyName) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - 5 - s_newLineLength); @@ -1513,7 +1513,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, ReadOn private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < ((int.MaxValue - 7 - indent - s_newLineLength) / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length); @@ -1563,7 +1563,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - escapedValue.Length - 7 - s_newLineLength); @@ -1614,7 +1614,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length - 7 - indent - s_newLineLength); @@ -1665,7 +1665,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length - 7 - indent - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs index 7188e889aafede..21b91cd2437cf5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs @@ -362,7 +362,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, ulong private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatUInt64Length - 5 - s_newLineLength); @@ -408,7 +408,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatUInt64Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs index d4b3e49627b0fb..649212df9a1df9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs @@ -88,7 +88,7 @@ private void WriteBase64Minimized(ReadOnlySpan bytes) private void WriteBase64Indented(ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); // Base64.GetMaxEncodedToUtf8Length checks to make sure the length is <= int.MaxValue / 4 * 3, // as a length longer than that would overflow int.MaxValue when Base64 encoded. However, we diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs index e56f894d6b6964..3a18a3260f2cd8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs @@ -105,7 +105,7 @@ private void WriteCommentMinimized(ReadOnlySpan value) private void WriteCommentIndented(ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(value.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 4 - s_newLineLength); @@ -212,7 +212,7 @@ private void WriteCommentMinimized(ReadOnlySpan utf8Value) private void WriteCommentIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(utf8Value.Length < int.MaxValue - indent - 4 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs index 5bb765eaca59f2..7923ef745802a7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs @@ -66,7 +66,7 @@ private void WriteStringValueMinimized(DateTime value) private void WriteStringValueIndented(DateTime value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatDateTimeOffsetLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs index 7f55861794151a..dc085940d76106 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs @@ -67,7 +67,7 @@ private void WriteStringValueMinimized(DateTimeOffset value) private void WriteStringValueIndented(DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatDateTimeOffsetLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs index 947a9788170eda..0f45358672d2b9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs @@ -63,7 +63,7 @@ private void WriteNumberValueMinimized(decimal value) private void WriteNumberValueIndented(decimal value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatDecimalLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs index 691e49b8532f56..7879a19ab19a63 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(double value) private void WriteNumberValueIndented(double value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatDoubleLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs index 0cd1a6614eff25..f1135d178c7f90 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(float value) private void WriteNumberValueIndented(float value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatSingleLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs index 6747646a23dad3..5ef69a940b2602 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(ReadOnlySpan utf8Value) private void WriteNumberValueIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(utf8Value.Length < int.MaxValue - indent - 1 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs index 6e91872d7f7694..8d79346276a120 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs @@ -67,7 +67,7 @@ private void WriteStringValueMinimized(Guid value) private void WriteStringValueIndented(Guid value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatGuidLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs index 490cb6ad6b0819..0de3df484c20db 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs @@ -86,7 +86,7 @@ private void WriteLiteralMinimized(ReadOnlySpan utf8Value) private void WriteLiteralIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(utf8Value.Length <= 5); int maxRequired = indent + utf8Value.Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs index 55dbb9734ee57f..e428c17437c960 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs @@ -76,7 +76,7 @@ private void WriteNumberValueMinimized(long value) private void WriteNumberValueIndented(long value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatInt64Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs index f6215c9f68300b..06198c8d23c7ba 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs @@ -143,7 +143,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedValue) private void WriteStringIndented(ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 3 - s_newLineLength); @@ -290,7 +290,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedValue) private void WriteStringIndented(ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(escapedValue.Length < int.MaxValue - indent - 3 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs index d068a433f5d363..0ff59a7a94c878 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs @@ -78,7 +78,7 @@ private void WriteNumberValueMinimized(ulong value) private void WriteNumberValueIndented(ulong value) { int indent = Indentation; - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatUInt64Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line 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 0d4ce926ba24b8..bdfe1be22ef88e 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 @@ -999,7 +999,7 @@ private void WriteEndIndented(byte token) indent -= IndentLength; } - Debug.Assert(indent <= 2 * _options.MaxDepth); + Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); Debug.Assert(_options.SkipValidation || _tokenType != JsonTokenType.None); int maxRequired = indent + 3; // 1 end token, 1-2 bytes for new line @@ -1033,7 +1033,7 @@ private void WriteNewLine(Span output) private void WriteIndentation(Span buffer, int indent) { - JsonWriterHelper.WriteIndentation(buffer, indent, (byte)_options.IndentCharacter); + JsonWriterHelper.WriteIndentation(buffer, indent, _options.IndentByte); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From cbd6dba515b6a12cac511744db4e51587e75a68c Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 24 Dec 2023 14:10:41 +0100 Subject: [PATCH 18/27] Fixes from code review --- .../ConsoleLoggerExtensionsTests.cs | 2 +- .../Common/JsonSourceGenerationOptionsAttribute.cs | 4 ++-- .../src/System/Text/Json/Writer/JsonWriterHelper.cs | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs index aa138a8d5c8f0c..fec2d737c8d2c8 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs @@ -597,7 +597,7 @@ private static void VerifyHasOnlySimpleProperties(Type type) // or else NativeAOT would break Assert.True(prop.PropertyType == typeof(string) || prop.PropertyType == typeof(bool) || - prop.PropertyType == typeof(char) || + prop.PropertyType == typeof(char) || prop.PropertyType == typeof(int) || prop.PropertyType.IsEnum, $"ConsoleOptions property '{type.Name}.{prop.Name}' must be a simple type in order for NativeAOT to work"); } diff --git a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs index e7d6032fede4e7..0bfaf896c40343 100644 --- a/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs +++ b/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs @@ -128,12 +128,12 @@ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults) /// /// Specifies the default value of when set. /// - public char IndentCharacter { get; set; } = JsonConstants.DefaultIndentCharacter; + public char IndentCharacter { get; set; } /// /// Specifies the default value of when set. /// - public int IndentSize { get; set; } = JsonConstants.DefaultIndentSize; + public int IndentSize { get; set; } /// /// Specifies the default source generation mode for type declarations that don't set a . diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index e59729bdfb35c9..291aabf05f099a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -16,15 +16,21 @@ public static void WriteIndentation(Span buffer, int indent, byte indentBy // Based on perf tests, the break-even point where vectorized Fill is faster // than explicitly writing the space in a loop is 8. - if (indent is < 8) + if (indent < 8) { int i = 0; - while (i < indent) + while (i + 1 < indent) { buffer[i++] = indentByte; + buffer[i++] = indentByte; + } + + if (i < indent) + { + buffer[i] = indentByte; } } - else if (indent is not 0) + else { buffer.Slice(0, indent).Fill(indentByte); } From 37a305a08f0c3e698bd6680afa9c29d7d32175d8 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 24 Dec 2023 14:12:24 +0100 Subject: [PATCH 19/27] Avoid introducing extra fields in JsonWriterOptions --- .../Text/Json/Writer/JsonWriterOptions.cs | 24 ++++++--- .../JsonWriterOptionsTests.cs | 52 ++++++++++++++++++- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 1e23be69d15042..8176709e77fae7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -17,10 +17,8 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; - private byte? _indentByte; - private int? _indentSize; - internal readonly byte IndentByte => _indentByte ?? JsonConstants.Space; + internal readonly byte IndentByte => (_optionsMask & IndentCharacterBit) != 0 ? JsonConstants.Tab : JsonConstants.Space; /// /// The encoder to use when escaping strings, or to use the default encoder. @@ -58,7 +56,10 @@ public char IndentCharacter set { JsonWriterHelper.ValidateIndentCharacter(value); - _indentByte = (byte)value; + if (value is not JsonConstants.DefaultIndentCharacter) + _optionsMask |= IndentCharacterBit; + else + _optionsMask &= ~IndentCharacterBit; } } @@ -69,14 +70,21 @@ public char IndentCharacter /// is out of the allowed range. public int IndentSize { - readonly get => _indentSize ?? JsonConstants.DefaultIndentSize; + readonly get => HandleDefaultIndentSize((_optionsMask & IndentSizeMask) >> 3); set { JsonWriterHelper.ValidateIndentSize(value); - _indentSize = value; + _optionsMask = (_optionsMask & ~IndentSizeMask) + (HandleDefaultIndentSize(value) << 3); } } + private static int HandleDefaultIndentSize(int value) => value switch + { + 0 => JsonConstants.DefaultIndentSize, + JsonConstants.DefaultIndentSize => 0, + _ => value + }; + /// /// Gets or sets the maximum depth allowed when writing JSON, with the default (i.e. 0) indicating a max depth of 1000. /// @@ -127,9 +135,11 @@ public bool SkipValidation } } - internal bool IndentedOrNotSkipValidation => _optionsMask != SkipValidationBit; // Equivalent to: Indented || !SkipValidation; + internal bool IndentedOrNotSkipValidation => Indented || !SkipValidation; private const int IndentBit = 1; private const int SkipValidationBit = 2; + private const int IndentCharacterBit = 4; + private const int IndentSizeMask = JsonConstants.MaximumIndentSize << 3; } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 0957f4fbe10e53..9f4476bb2745ac 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -37,7 +37,7 @@ public static void JsonWriterOptionsCtor() [Theory] [InlineData(true, '\t', 1, true, 0)] - [InlineData(true, ' ', 1, false, 1)] + [InlineData(true, ' ', 127, false, 1)] [InlineData(false, ' ', 0, true, 1024)] [InlineData(false, ' ', 4, false, 1024 * 1024)] public static void JsonWriterOptions(bool indented, char indentCharacter, int indentSize, bool skipValidation, int maxDepth) @@ -60,6 +60,56 @@ public static void JsonWriterOptions(bool indented, char indentCharacter, int in Assert.Equal(expectedOption, options); } + [Theory] + [InlineData(true, '\t', 1, true, 0)] + [InlineData(true, ' ', 127, false, 1)] + [InlineData(false, ' ', 0, true, 1024)] + [InlineData(false, ' ', 4, false, 1024 * 1024)] + public static void JsonWriterOptions_Properties(bool indented, char indentCharacter, int indentSize, bool skipValidation, int maxDepth) + { + var options = new JsonWriterOptions(); + options.Indented = indented; + options.IndentCharacter = indentCharacter; + options.IndentSize = indentSize; + options.SkipValidation = skipValidation; + options.MaxDepth = maxDepth; + + Assert.Equal(indented, options.Indented); + Assert.Equal(indentCharacter, options.IndentCharacter); + Assert.Equal(indentSize, options.IndentSize); + Assert.Equal(skipValidation, options.SkipValidation); + Assert.Equal(maxDepth, options.MaxDepth); + } + + [Fact] + public static void JsonWriterOptions_MultipleValues() + { + JsonWriterOptions defaultOptions = default; + var options = new JsonWriterOptions(); + + options.Indented = true; + options.Indented = defaultOptions.Indented; + Assert.Equal(defaultOptions.Indented, options.Indented); + + options.IndentCharacter = '\t'; + options.IndentCharacter = defaultOptions.IndentCharacter; + Assert.Equal(defaultOptions.IndentCharacter, options.IndentCharacter); + + options.IndentSize = 127; + options.IndentSize = defaultOptions.IndentSize; + Assert.Equal(defaultOptions.IndentSize, options.IndentSize); + + options.SkipValidation = true; + options.SkipValidation = defaultOptions.SkipValidation; + Assert.Equal(defaultOptions.SkipValidation, options.SkipValidation); + + options.MaxDepth = 1024 * 1024; + options.MaxDepth = defaultOptions.MaxDepth; + Assert.Equal(defaultOptions.MaxDepth, options.MaxDepth); + + Assert.Equal(defaultOptions, options); + } + [Theory] [InlineData(-1)] [InlineData(-100)] From 5b11220db9fc81494a170dc84e58f710b3a09d3a Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Sun, 24 Dec 2023 22:32:30 +0100 Subject: [PATCH 20/27] Fix OOM error --- .../tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index c4fa1c9e6c3eb5..eacf72a0939fa3 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -2762,8 +2762,8 @@ public void WritingTooDeep(JsonWriterOptions options) [MemberData(nameof(JsonOptions_TestData))] public void WritingTooDeepProperty(JsonWriterOptions options) { - var output = new ArrayBufferWriter(1024); - + var capacity = 3 + 1000 * (11 + 1001 * options.IndentSize / 2); + var output = new ArrayBufferWriter(capacity); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); @@ -2775,6 +2775,7 @@ public void WritingTooDeepProperty(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStartArray("name")); } + output = new ArrayBufferWriter(capacity); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); @@ -2785,6 +2786,7 @@ public void WritingTooDeepProperty(JsonWriterOptions options) Assert.Throws(() => jsonUtf8.WriteStartArray("name"u8)); } + output = new ArrayBufferWriter(capacity); using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { jsonUtf8.WriteStartObject(); From ed7e1b2825ef389bdfaff9b754f09c2d31c9736c Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Tue, 26 Dec 2023 12:36:44 +0100 Subject: [PATCH 21/27] Use bitwise logic for IndentedOrNotSkipValidation --- .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 8176709e77fae7..36f107d99c7558 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -135,7 +135,7 @@ public bool SkipValidation } } - internal bool IndentedOrNotSkipValidation => Indented || !SkipValidation; + internal bool IndentedOrNotSkipValidation => (_optionsMask & (IndentBit + SkipValidationBit)) != SkipValidationBit; // Equivalent to: Indented || !SkipValidation; private const int IndentBit = 1; private const int SkipValidationBit = 2; From 01fc002329cd41a98cfdbe0ce736380edabe8743 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Tue, 26 Dec 2023 12:49:54 +0100 Subject: [PATCH 22/27] Cache indentation options in Utf8JsonWriter --- .../Utf8JsonWriter.WriteProperties.Bytes.cs | 4 +- ...Utf8JsonWriter.WriteProperties.DateTime.cs | 4 +- ...onWriter.WriteProperties.DateTimeOffset.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Decimal.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Double.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Float.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Guid.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Helpers.cs | 4 +- .../Utf8JsonWriter.WriteProperties.Literal.cs | 4 +- ...JsonWriter.WriteProperties.SignedNumber.cs | 4 +- .../Utf8JsonWriter.WriteProperties.String.cs | 12 +++--- ...onWriter.WriteProperties.UnsignedNumber.cs | 4 +- .../Utf8JsonWriter.WriteValues.Bytes.cs | 2 +- .../Utf8JsonWriter.WriteValues.Comment.cs | 4 +- .../Utf8JsonWriter.WriteValues.DateTime.cs | 2 +- ...f8JsonWriter.WriteValues.DateTimeOffset.cs | 2 +- .../Utf8JsonWriter.WriteValues.Decimal.cs | 2 +- .../Utf8JsonWriter.WriteValues.Double.cs | 2 +- .../Utf8JsonWriter.WriteValues.Float.cs | 2 +- ...8JsonWriter.WriteValues.FormattedNumber.cs | 2 +- .../Writer/Utf8JsonWriter.WriteValues.Guid.cs | 2 +- .../Utf8JsonWriter.WriteValues.Literal.cs | 2 +- ...Utf8JsonWriter.WriteValues.SignedNumber.cs | 2 +- .../Utf8JsonWriter.WriteValues.String.cs | 4 +- ...f8JsonWriter.WriteValues.UnsignedNumber.cs | 2 +- .../System/Text/Json/Writer/Utf8JsonWriter.cs | 40 +++++++++---------- 26 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs index be446e93a3de99..a8d53aef63dec0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs @@ -280,7 +280,7 @@ private void WriteBase64Minimized(ReadOnlySpan escapedPropertyName, ReadOn private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int encodedLength = Base64.GetMaxEncodedToUtf8Length(bytes.Length); @@ -330,7 +330,7 @@ private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteBase64Indented(ReadOnlySpan escapedPropertyName, ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int encodedLength = Base64.GetMaxEncodedToUtf8Length(bytes.Length); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs index 993adf00a2a453..392facd7d85ee2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs @@ -284,7 +284,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, DateTi private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTime value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); @@ -333,7 +333,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTime value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs index 0d881aac48393b..313693b3b7665f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs @@ -283,7 +283,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, DateTi private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); @@ -332,7 +332,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTim private void WriteStringIndented(ReadOnlySpan escapedPropertyName, DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDateTimeOffsetLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs index c52cd838779cec..3f1af56067cd9b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs @@ -277,7 +277,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, decima private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDecimalLength - 5 - s_newLineLength); @@ -323,7 +323,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, decimal value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDecimalLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs index d229bdffcc4843..eee0535903cfa1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs @@ -281,7 +281,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, double private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatDoubleLength - 5 - s_newLineLength); @@ -327,7 +327,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, double value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatDoubleLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs index 79a80f67b6b649..133c95ece5d865 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs @@ -281,7 +281,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, float private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatSingleLength - 5 - s_newLineLength); @@ -327,7 +327,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, float value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatSingleLength - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs index c11c3e37e1a468..1ded7b8f3f6a15 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs @@ -285,7 +285,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, Guid v private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatGuidLength - 7 - s_newLineLength); @@ -335,7 +335,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid va private void WriteStringIndented(ReadOnlySpan escapedPropertyName, Guid value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatGuidLength - 7 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs index 881075e1239991..c09aaa40c8a23e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs @@ -89,7 +89,7 @@ private void WritePropertyNameMinimized(ReadOnlySpan escapedPropertyName, private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, byte token) { int indent = Indentation; - Debug.Assert(indent <= IndentLength * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - 6 - s_newLineLength); @@ -161,7 +161,7 @@ private void WritePropertyNameMinimized(ReadOnlySpan escapedPropertyName, private void WritePropertyNameIndented(ReadOnlySpan escapedPropertyName, byte token) { int indent = Indentation; - Debug.Assert(indent <= IndentLength * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 6 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs index 2ba0269cf5eb5d..aff0da471b1a3f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs @@ -427,7 +427,7 @@ private void WriteLiteralSection(ReadOnlySpan escapedPropertyNameSection, private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(value.Length <= JsonConstants.MaxUnescapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - value.Length - 5 - s_newLineLength); @@ -473,7 +473,7 @@ private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOn private void WriteLiteralIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(value.Length <= JsonConstants.MaxUnescapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - value.Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs index 85e80494e59731..82694f738cc76c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs @@ -353,7 +353,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, long v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatInt64Length - 5 - s_newLineLength); @@ -399,7 +399,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long va private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, long value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatInt64Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs index f1eea86026b586..16629ea424f4cf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs @@ -187,7 +187,7 @@ private void WriteStringMinimizedPropertyName(ReadOnlySpan escapedProperty private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyName) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue - 5 - indent - s_newLineLength) / JsonConstants.MaxExpansionFactorWhileTranscoding); @@ -375,7 +375,7 @@ private void WriteStringPropertyNameSection(ReadOnlySpan escapedPropertyNa private void WriteStringIndentedPropertyName(ReadOnlySpan escapedPropertyName) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - 5 - s_newLineLength); @@ -1513,7 +1513,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedPropertyName, ReadOn private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < ((int.MaxValue - 7 - indent - s_newLineLength) / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length); @@ -1563,7 +1563,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - escapedValue.Length - 7 - s_newLineLength); @@ -1614,7 +1614,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length - 7 - indent - s_newLineLength); @@ -1665,7 +1665,7 @@ private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnl private void WriteStringIndented(ReadOnlySpan escapedPropertyName, ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length <= JsonConstants.MaxEscapedTokenSize); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - escapedValue.Length - 7 - indent - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs index 21b91cd2437cf5..37aad462665995 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs @@ -362,7 +362,7 @@ private void WriteNumberMinimized(ReadOnlySpan escapedPropertyName, ulong private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - JsonConstants.MaximumFormatUInt64Length - 5 - s_newLineLength); @@ -408,7 +408,7 @@ private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong v private void WriteNumberIndented(ReadOnlySpan escapedPropertyName, ulong value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - JsonConstants.MaximumFormatUInt64Length - 5 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs index 649212df9a1df9..31500fb2b00ec1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs @@ -88,7 +88,7 @@ private void WriteBase64Minimized(ReadOnlySpan bytes) private void WriteBase64Indented(ReadOnlySpan bytes) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); // Base64.GetMaxEncodedToUtf8Length checks to make sure the length is <= int.MaxValue / 4 * 3, // as a length longer than that would overflow int.MaxValue when Base64 encoded. However, we diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs index 3a18a3260f2cd8..93f11451f454d7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs @@ -105,7 +105,7 @@ private void WriteCommentMinimized(ReadOnlySpan value) private void WriteCommentIndented(ReadOnlySpan value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(value.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 4 - s_newLineLength); @@ -212,7 +212,7 @@ private void WriteCommentMinimized(ReadOnlySpan utf8Value) private void WriteCommentIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(utf8Value.Length < int.MaxValue - indent - 4 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs index 7923ef745802a7..ad8a887cdf55a0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs @@ -66,7 +66,7 @@ private void WriteStringValueMinimized(DateTime value) private void WriteStringValueIndented(DateTime value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatDateTimeOffsetLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs index dc085940d76106..1ee48004f21fd8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs @@ -67,7 +67,7 @@ private void WriteStringValueMinimized(DateTimeOffset value) private void WriteStringValueIndented(DateTimeOffset value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatDateTimeOffsetLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs index 0f45358672d2b9..35089030c2d454 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs @@ -63,7 +63,7 @@ private void WriteNumberValueMinimized(decimal value) private void WriteNumberValueIndented(decimal value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatDecimalLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs index 7879a19ab19a63..b638931ce12293 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(double value) private void WriteNumberValueIndented(double value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatDoubleLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs index f1135d178c7f90..c1755c7c4dc5d3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(float value) private void WriteNumberValueIndented(float value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatSingleLength + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs index 5ef69a940b2602..f4c902e184af4c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs @@ -67,7 +67,7 @@ private void WriteNumberValueMinimized(ReadOnlySpan utf8Value) private void WriteNumberValueIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(utf8Value.Length < int.MaxValue - indent - 1 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs index 8d79346276a120..695cc83e03680b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs @@ -67,7 +67,7 @@ private void WriteStringValueMinimized(Guid value) private void WriteStringValueIndented(Guid value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); // 2 quotes, and optionally, 1 list separator and 1-2 bytes for new line int maxRequired = indent + JsonConstants.MaximumFormatGuidLength + 3 + s_newLineLength; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs index 0de3df484c20db..8c0dee44e785e4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs @@ -86,7 +86,7 @@ private void WriteLiteralMinimized(ReadOnlySpan utf8Value) private void WriteLiteralIndented(ReadOnlySpan utf8Value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(utf8Value.Length <= 5); int maxRequired = indent + utf8Value.Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs index e428c17437c960..b2126de77fb2f1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs @@ -76,7 +76,7 @@ private void WriteNumberValueMinimized(long value) private void WriteNumberValueIndented(long value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatInt64Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs index 06198c8d23c7ba..4ede0fc9bce938 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs @@ -143,7 +143,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedValue) private void WriteStringIndented(ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length < (int.MaxValue / JsonConstants.MaxExpansionFactorWhileTranscoding) - indent - 3 - s_newLineLength); @@ -290,7 +290,7 @@ private void WriteStringMinimized(ReadOnlySpan escapedValue) private void WriteStringIndented(ReadOnlySpan escapedValue) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(escapedValue.Length < int.MaxValue - indent - 3 - s_newLineLength); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs index 0ff59a7a94c878..82ec4677b2224e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs @@ -78,7 +78,7 @@ private void WriteNumberValueMinimized(ulong value) private void WriteNumberValueIndented(ulong value) { int indent = Indentation; - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int maxRequired = indent + JsonConstants.MaximumFormatUInt64Length + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line 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 bdfe1be22ef88e..70e6c7d95fba06 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 @@ -58,6 +58,10 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. + // Cache indentation options from JsonWriterOptions to optimize performance. + private byte _indentByte; + private int _indentLength; + /// /// Returns the amount of bytes written by the so far /// that have not yet been flushed to the output and committed. @@ -80,9 +84,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// public JsonWriterOptions Options => _options; - private int IndentLength => _options.IndentSize; - - private int Indentation => CurrentDepth * IndentLength; + private int Indentation => CurrentDepth * _indentLength; internal JsonTokenType TokenType => _tokenType; @@ -114,12 +116,7 @@ public Utf8JsonWriter(IBufferWriter bufferWriter, JsonWriterOptions option } _output = bufferWriter; - _options = options; - - if (_options.MaxDepth == 0) - { - _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. - } + SetOptions(options); } /// @@ -143,14 +140,21 @@ public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) throw new ArgumentException(SR.StreamNotWritable); _stream = utf8Json; + SetOptions(options); + + _arrayBufferWriter = new ArrayBufferWriter(); + } + + private void SetOptions(JsonWriterOptions options) + { _options = options; + _indentByte = _options.IndentByte; + _indentLength = options.IndentSize; if (_options.MaxDepth == 0) { _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. } - - _arrayBufferWriter = new ArrayBufferWriter(); } /// @@ -247,11 +251,7 @@ internal void Reset(IBufferWriter bufferWriter, JsonWriterOptions options) Debug.Assert(_output is null && _stream is null && _arrayBufferWriter is null); _output = bufferWriter; - _options = options; - if (_options.MaxDepth == 0) - { - _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. - } + SetOptions(options); } internal static Utf8JsonWriter CreateEmptyInstanceForCaching() => new Utf8JsonWriter(); @@ -555,7 +555,7 @@ private void ValidateStart() private void WriteStartIndented(byte token) { int indent = Indentation; - Debug.Assert(indent <= IndentLength * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); int minRequired = indent + 1; // 1 start token int maxRequired = minRequired + 3; // Optionally, 1 list separator and 1-2 bytes for new line @@ -996,10 +996,10 @@ private void WriteEndIndented(byte token) { // The end token should be at an outer indent and since we haven't updated // current depth yet, explicitly subtract here. - indent -= IndentLength; + indent -= _indentLength; } - Debug.Assert(indent <= _options.IndentSize * _options.MaxDepth); + Debug.Assert(indent <= _indentLength * _options.MaxDepth); Debug.Assert(_options.SkipValidation || _tokenType != JsonTokenType.None); int maxRequired = indent + 3; // 1 end token, 1-2 bytes for new line @@ -1033,7 +1033,7 @@ private void WriteNewLine(Span output) private void WriteIndentation(Span buffer, int indent) { - JsonWriterHelper.WriteIndentation(buffer, indent, _options.IndentByte); + JsonWriterHelper.WriteIndentation(buffer, indent, _indentByte); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From f00943ee38b8ca8aa20a5024ee9ac12e9532751d Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Wed, 27 Dec 2023 00:08:19 +0100 Subject: [PATCH 23/27] Add missing test around indentation options --- .../System.Text.Json.Tests/Utf8JsonWriterTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index eacf72a0939fa3..643762183c713e 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -6783,6 +6783,20 @@ public static void WriteStringValue_JsonEncodedTextProperty_NullString() (writer, value) => writer.WriteString(jet, value)); } + [Fact] + public static void WriteStringValue_IndentationOptions() + { + var options = new JsonWriterOptions(); + var expectedOutput = GetCustomExpectedString(options); + + options.IndentCharacter = '\t'; + options.IndentSize = 127; + + var output = GetCustomExpectedString(options); + + Assert.Equal(expectedOutput, output); + } + private delegate void WriteValueSpanAction( Utf8JsonWriter writer, ReadOnlySpan value); From 5dc575b4c18d0528e0de7eeecb604d556c3b6cd1 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 29 Dec 2023 00:20:52 +0100 Subject: [PATCH 24/27] New fixes from code review --- .../System.Text.Json/Common/JsonConstants.cs | 6 ------ .../src/System/Text/Json/JsonConstants.cs | 8 ++++++++ .../System/Text/Json/Writer/JsonWriterHelper.cs | 2 +- .../System/Text/Json/Writer/JsonWriterOptions.cs | 14 +++++++------- .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 4 ++-- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs index ccfd426be25610..4a7209f9a4aba2 100644 --- a/src/libraries/System.Text.Json/Common/JsonConstants.cs +++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs @@ -11,11 +11,5 @@ internal static partial class JsonConstants public const int StackallocByteThreshold = 256; public const int StackallocCharThreshold = StackallocByteThreshold / 2; - - // Two space characters is the default indentation. - public const char DefaultIndentCharacter = ' '; - public const int DefaultIndentSize = 2; - public const int MinimumIndentSize = 0; - public const int MaximumIndentSize = 127; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 139fc5f5053ed3..99012e30e8b36b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -109,5 +109,13 @@ internal static partial class JsonConstants // The maximum number of parameters a constructor can have where it can be considered // for a path on deserialization where we don't box the constructor arguments. public const int UnboxedParameterCountThreshold = 4; + + // Two space characters is the default indentation. + public const char DefaultIndentCharacter = ' '; + public const char TabIndentCharacter = '\t'; + public const int DefaultIndentSize = 2; + public const int MinimumIndentSize = 0; + public const int MaximumIndentSize = 127; // If this value is changed, the impact on the options masking used in the JsonWriterOptions struct must be checked carefully. + } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 291aabf05f099a..c34c8cd3d672f9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -39,7 +39,7 @@ public static void WriteIndentation(Span buffer, int indent, byte indentBy [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ValidateIndentCharacter(char value) { - if ((byte)value is not JsonConstants.Space and not JsonConstants.Tab) + if (value is not JsonConstants.DefaultIndentCharacter and not JsonConstants.TabIndentCharacter) ThrowHelper.ThrowArgumentOutOfRangeException_IndentCharacter(nameof(value)); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 36f107d99c7558..88ca2028fc2447 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -18,8 +18,6 @@ public struct JsonWriterOptions private int _maxDepth; private int _optionsMask; - internal readonly byte IndentByte => (_optionsMask & IndentCharacterBit) != 0 ? JsonConstants.Tab : JsonConstants.Space; - /// /// The encoder to use when escaping strings, or to use the default encoder. /// @@ -52,7 +50,7 @@ public bool Indented /// contains an invalid character. public char IndentCharacter { - readonly get => (char)IndentByte; + readonly get => (_optionsMask & IndentCharacterBit) != 0 ? JsonConstants.TabIndentCharacter : JsonConstants.DefaultIndentCharacter; set { JsonWriterHelper.ValidateIndentCharacter(value); @@ -70,15 +68,17 @@ public char IndentCharacter /// is out of the allowed range. public int IndentSize { - readonly get => HandleDefaultIndentSize((_optionsMask & IndentSizeMask) >> 3); + readonly get => EncodeIndentSize((_optionsMask & IndentSizeMask) >> 3); set { JsonWriterHelper.ValidateIndentSize(value); - _optionsMask = (_optionsMask & ~IndentSizeMask) + (HandleDefaultIndentSize(value) << 3); + _optionsMask = (_optionsMask & ~IndentSizeMask) | (EncodeIndentSize(value) << 3); } } - private static int HandleDefaultIndentSize(int value) => value switch + // Encoding is applied by swapping 0 with the default value to ensure default(JsonWriterOptions) instances are well-defined. + // As this operation is symmetrical, it can also be used to decode. + private static int EncodeIndentSize(int value) => value switch { 0 => JsonConstants.DefaultIndentSize, JsonConstants.DefaultIndentSize => 0, @@ -135,7 +135,7 @@ public bool SkipValidation } } - internal bool IndentedOrNotSkipValidation => (_optionsMask & (IndentBit + SkipValidationBit)) != SkipValidationBit; // Equivalent to: Indented || !SkipValidation; + internal bool IndentedOrNotSkipValidation => (_optionsMask & (IndentBit | SkipValidationBit)) != SkipValidationBit; // Equivalent to: Indented || !SkipValidation; private const int IndentBit = 1; private const int SkipValidationBit = 2; 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 70e6c7d95fba06..8aa1ff86f25deb 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 @@ -58,7 +58,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. - // Cache indentation options from JsonWriterOptions to optimize performance. + // Cache indentation settings from JsonWriterOptions to avoid recomputating them in the hot path. private byte _indentByte; private int _indentLength; @@ -148,7 +148,7 @@ public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) private void SetOptions(JsonWriterOptions options) { _options = options; - _indentByte = _options.IndentByte; + _indentByte = (byte)_options.IndentCharacter; _indentLength = options.IndentSize; if (_options.MaxDepth == 0) From d5e8835a269c6a93987b9383df7b5e7fced430d2 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 29 Dec 2023 15:29:22 +0000 Subject: [PATCH 25/27] Update src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs --- .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8aa1ff86f25deb..315b7a30b8e207 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 @@ -58,7 +58,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable private JsonWriterOptions _options; // Since JsonWriterOptions is a struct, use a field to avoid a copy for internal code. - // Cache indentation settings from JsonWriterOptions to avoid recomputating them in the hot path. + // Cache indentation settings from JsonWriterOptions to avoid recomputing them in the hot path. private byte _indentByte; private int _indentLength; From 2bfbf0c370eb1d9e77f5691dd62f2d27e28312e2 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:17:02 +0100 Subject: [PATCH 26/27] Add test to check default values of the JsonWriterOptions properties --- .../JsonWriterOptionsTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs index 9f4476bb2745ac..127ca9601150db 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonWriterOptionsTests.cs @@ -15,6 +15,8 @@ public static void JsonWriterOptionsDefaultCtor() var expectedOption = new JsonWriterOptions { Indented = false, + IndentCharacter = ' ', + IndentSize = 2, SkipValidation = false, MaxDepth = 0, }; @@ -29,6 +31,8 @@ public static void JsonWriterOptionsCtor() var expectedOption = new JsonWriterOptions { Indented = false, + IndentCharacter = ' ', + IndentSize = 2, SkipValidation = false, MaxDepth = 0, }; @@ -81,6 +85,18 @@ public static void JsonWriterOptions_Properties(bool indented, char indentCharac Assert.Equal(maxDepth, options.MaxDepth); } + [Fact] + public static void JsonWriterOptions_DefaultValues() + { + JsonWriterOptions options = default; + + Assert.False(options.Indented); + Assert.Equal(' ', options.IndentCharacter); + Assert.Equal(2, options.IndentSize); + Assert.False(options.SkipValidation); + Assert.Equal(0, options.MaxDepth); + } + [Fact] public static void JsonWriterOptions_MultipleValues() { From 00617c23368c693f5f70390490a68bd219a85421 Mon Sep 17 00:00:00 2001 From: Emmanuel ANDRE <2341261+manandre@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:32:32 +0100 Subject: [PATCH 27/27] Fix comment --- .../src/System/Text/Json/Serialization/JsonSerializerOptions.cs | 2 +- .../src/System/Text/Json/Writer/JsonWriterOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index dad6af3f43999f..b3febb51930a67 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -674,7 +674,7 @@ public char IndentCharacter /// /// Defines the indentation size being used when is enabled. Defaults to two. /// - /// Allowed values are all integers between 0 and 127. + /// Allowed values are all integers between 0 and 127, included. /// is out of the allowed range. /// /// Thrown if this property is set after serialization or deserialization has occurred. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs index 88ca2028fc2447..1d89e5d6aa1499 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterOptions.cs @@ -64,7 +64,7 @@ public char IndentCharacter /// /// Defines the indentation size used by when is enabled. Defaults to two. /// - /// Allowed values are integers between 0 and 127. + /// Allowed values are integers between 0 and 127, included. /// is out of the allowed range. public int IndentSize {