From 600528b6ccc37bacbfc497c624785cd7afb3c191 Mon Sep 17 00:00:00 2001 From: Vishnu Kumar Date: Sat, 13 Jul 2019 03:36:08 +0530 Subject: [PATCH] Add WriteTo API on JsonDocument and JsonProperty (dotnet/corefx#39367) * Remove WriteProperty methods and rename WriteValue to WriteTo in JsonElement (dotnet/corefx#39037) * Add WriteTo method in JsonDocument and JsonProperty (dotnet/corefx#39037) * Remove all repeated tests from JsonDocument and JsonProperty for now. * Added null check for Utf8JsonWriter parameter in WriteTo methods on JsonElement, JsonDocument and JsonProperty * Code review changes Commit migrated from https://github.com/dotnet/corefx/commit/798468fb39d869a96104306483ed6ef4d63738ca --- .../System.Text.Json/ref/System.Text.Json.cs | 8 +- .../src/System/Text/Json/Document/JsonDocument.cs | 179 +++------------------ .../src/System/Text/Json/Document/JsonElement.cs | 88 ++-------- .../src/System/Text/Json/Document/JsonProperty.cs | 27 ++++ .../Converters/JsonValueConverterJsonElement.cs | 2 +- .../System.Text.Json/tests/JsonDocumentTests.cs | 142 +++++++--------- .../tests/JsonElementWriteTests.cs | 65 ++++---- .../System.Text.Json/tests/JsonPropertyTests.cs | 151 +++++++++++++++++ .../tests/System.Text.Json.Tests.csproj | 1 + 9 files changed, 311 insertions(+), 352 deletions(-) create mode 100644 src/libraries/System.Text.Json/tests/JsonPropertyTests.cs 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 2190c90..5b60ca2 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -26,6 +26,7 @@ namespace System.Text.Json public static System.Threading.Tasks.Task ParseAsync(System.IO.Stream utf8Json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Text.Json.JsonDocument ParseValue(ref System.Text.Json.Utf8JsonReader reader) { throw null; } public static bool TryParseValue(ref System.Text.Json.Utf8JsonReader reader, out System.Text.Json.JsonDocument document) { throw null; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } } public partial struct JsonDocumentOptions { @@ -95,11 +96,7 @@ namespace System.Text.Json public bool ValueEquals(System.ReadOnlySpan utf8Text) { throw null; } public bool ValueEquals(System.ReadOnlySpan text) { throw null; } public bool ValueEquals(string text) { throw null; } - public void WriteProperty(System.ReadOnlySpan utf8PropertyName, System.Text.Json.Utf8JsonWriter writer) { } - public void WriteProperty(System.ReadOnlySpan propertyName, System.Text.Json.Utf8JsonWriter writer) { } - public void WriteProperty(string propertyName, System.Text.Json.Utf8JsonWriter writer) { } - public void WriteProperty(System.Text.Json.JsonEncodedText propertyName, System.Text.Json.Utf8JsonWriter writer) { } - public void WriteValue(System.Text.Json.Utf8JsonWriter writer) { } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } public partial struct ArrayEnumerator : System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerator, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable { private object _dummy; @@ -167,6 +164,7 @@ namespace System.Text.Json public bool NameEquals(System.ReadOnlySpan utf8Text) { throw null; } public bool NameEquals(System.ReadOnlySpan text) { throw null; } public bool NameEquals(string text) { throw null; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } public override string ToString() { throw null; } } public partial struct JsonReaderOptions diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs index 176f219..fc32f80 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs @@ -75,6 +75,29 @@ namespace System.Text.Json } } + /// + /// Write the document into the provided writer as a JSON value. + /// + /// + /// + /// The parameter is . + /// + /// + /// This 's would result in an invalid JSON. + /// + /// + /// The parent has been disposed. + /// + public void WriteTo(Utf8JsonWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + RootElement.WriteTo(writer); + } + internal JsonTokenType GetJsonTokenType(int index) { CheckNotDisposed(); @@ -755,129 +778,6 @@ namespace System.Text.Json internal void WriteElementTo( int index, - Utf8JsonWriter writer, - ReadOnlySpan propertyName) - { - CheckNotDisposed(); - - DbRow row = _parsedData.Get(index); - - switch (row.TokenType) - { - case JsonTokenType.StartObject: - writer.WriteStartObject(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.StartArray: - writer.WriteStartArray(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.String: - WriteString(propertyName, row, writer); - return; - case JsonTokenType.True: - writer.WriteBoolean(propertyName, value: true); - return; - case JsonTokenType.False: - writer.WriteBoolean(propertyName, value: false); - return; - case JsonTokenType.Null: - writer.WriteNull(propertyName); - return; - case JsonTokenType.Number: - writer.WriteNumber( - propertyName, - _utf8Json.Slice(row.Location, row.SizeOrLength).Span); - return; - } - - Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}"); - } - - internal void WriteElementTo( - int index, - Utf8JsonWriter writer, - JsonEncodedText propertyName) - { - CheckNotDisposed(); - - DbRow row = _parsedData.Get(index); - - switch (row.TokenType) - { - case JsonTokenType.StartObject: - writer.WriteStartObject(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.StartArray: - writer.WriteStartArray(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.String: - WriteString(propertyName, row, writer); - return; - case JsonTokenType.True: - writer.WriteBoolean(propertyName, value: true); - return; - case JsonTokenType.False: - writer.WriteBoolean(propertyName, value: false); - return; - case JsonTokenType.Null: - writer.WriteNull(propertyName); - return; - case JsonTokenType.Number: - writer.WriteNumber( - propertyName, - _utf8Json.Slice(row.Location, row.SizeOrLength).Span); - return; - } - - Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}"); - } - - internal void WriteElementTo( - int index, - Utf8JsonWriter writer, - ReadOnlySpan propertyName) - { - CheckNotDisposed(); - - DbRow row = _parsedData.Get(index); - - switch (row.TokenType) - { - case JsonTokenType.StartObject: - writer.WriteStartObject(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.StartArray: - writer.WriteStartArray(propertyName); - WriteComplexElement(index, writer); - return; - case JsonTokenType.String: - WriteString(propertyName, row, writer); - return; - case JsonTokenType.True: - writer.WriteBoolean(propertyName, value: true); - return; - case JsonTokenType.False: - writer.WriteBoolean(propertyName, value: false); - return; - case JsonTokenType.Null: - writer.WriteNull(propertyName); - return; - case JsonTokenType.Number: - writer.WriteNumber( - propertyName, - _utf8Json.Slice(row.Location, row.SizeOrLength).Span); - return; - } - - Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}"); - } - - internal void WriteElementTo( - int index, Utf8JsonWriter writer) { CheckNotDisposed(); @@ -1031,22 +931,6 @@ namespace System.Text.Json } } - private void WriteString(JsonEncodedText propertyName, in DbRow row, Utf8JsonWriter writer) - { - ArraySegment rented = default; - - try - { - writer.WriteString( - propertyName, - UnescapeString(row, out rented)); - } - finally - { - ClearAndReturn(rented); - } - } - private void WriteString(ReadOnlySpan propertyName, in DbRow row, Utf8JsonWriter writer) { ArraySegment rented = default; @@ -1063,23 +947,6 @@ namespace System.Text.Json } } - private void WriteString(ReadOnlySpan propertyName, in DbRow row, Utf8JsonWriter writer) - { - ArraySegment rented = default; - - try - { - writer.WriteString( - propertyName, - UnescapeString(row, out rented)); - } - finally - { - ClearAndReturn(rented); - - } - } - private void WriteString(in DbRow row, Utf8JsonWriter writer) { ArraySegment rented = default; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs index 214eaab..1b142fd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs @@ -1269,87 +1269,25 @@ namespace System.Text.Json } /// - /// Write the element into the provided writer as a named JSON object property. - /// - /// The name for this value within the JSON object. - /// The writer. - /// - /// This value's is . - /// - /// - /// The parent has been disposed. - /// - public void WriteProperty(string propertyName, Utf8JsonWriter writer) - => WriteProperty(propertyName.AsSpan(), writer); - - /// - /// Write the element into the provided writer as a named JSON object property. - /// - /// The name for this value within the JSON object. - /// The writer. - /// - /// This value's is . - /// - /// - /// The parent has been disposed. - /// - public void WriteProperty(ReadOnlySpan propertyName, Utf8JsonWriter writer) - { - CheckValidInstance(); - - _parent.WriteElementTo(_idx, writer, propertyName); - } - - /// - /// Write the element into the provided writer as a named JSON object property. + /// Write the element into the provided writer as a JSON value. /// - /// The pre-encoded name for this value within the JSON object. /// The writer. - /// - /// This value's is . - /// - /// - /// The parent has been disposed. + /// + /// The parameter is . /// - public void WriteProperty(JsonEncodedText propertyName, Utf8JsonWriter writer) - { - CheckValidInstance(); - - _parent.WriteElementTo(_idx, writer, propertyName); - } - - /// - /// Write the element into the provided writer as a named JSON object property. - /// - /// - /// The name for this value within the JSON object, as UTF-8 text. - /// - /// The writer. /// /// This value's is . /// /// /// The parent has been disposed. /// - public void WriteProperty(ReadOnlySpan utf8PropertyName, Utf8JsonWriter writer) + public void WriteTo(Utf8JsonWriter writer) { - CheckValidInstance(); - - _parent.WriteElementTo(_idx, writer, utf8PropertyName); - } + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } - /// - /// Write the element into the provided writer as a JSON value. - /// - /// The writer. - /// - /// This value's is . - /// - /// - /// The parent has been disposed. - /// - public void WriteValue(Utf8JsonWriter writer) - { CheckValidInstance(); _parent.WriteElementTo(_idx, writer); @@ -1451,11 +1389,11 @@ namespace System.Text.Json case JsonTokenType.Number: case JsonTokenType.StartArray: case JsonTokenType.StartObject: - { - // null parent should have hit the None case - Debug.Assert(_parent != null); - return _parent.GetRawValueAsString(_idx); - } + { + // null parent should have hit the None case + Debug.Assert(_parent != null); + return _parent.GetRawValueAsString(_idx); + } case JsonTokenType.String: return GetString(); case JsonTokenType.Comment: diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs index fcab3e9..79d8fd8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs @@ -89,6 +89,33 @@ namespace System.Text.Json } /// + /// Write the property into the provided writer as a named JSON object property. + /// + /// The writer. + /// + /// The parameter is . + /// + /// + /// This 's length is too large to be a JSON object property. + /// + /// + /// This 's would result in an invalid JSON. + /// + /// + /// The parent has been disposed. + /// > + public void WriteTo(Utf8JsonWriter writer) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WritePropertyName(Name); + Value.WriteTo(writer); + } + + /// /// Provides a representation of the property for /// debugging purposes. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterJsonElement.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterJsonElement.cs index 57ed5b5..b8a4da3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterJsonElement.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterJsonElement.cs @@ -16,7 +16,7 @@ namespace System.Text.Json.Serialization.Converters public override void Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options) { - value.WriteValue(writer); + value.WriteTo(writer); } } } diff --git a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs index 44665cf..c22fbbc 100644 --- a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs @@ -432,7 +432,7 @@ namespace System.Text.Json.Tests [Fact] public static void ParseJson_Stream_ThrowsOn_ArrayPoolRent_CodeCoverage() { - using (Stream stream = new ThrowOnCanSeekStream (new byte[] { 1 })) + using (Stream stream = new ThrowOnCanSeekStream(new byte[] { 1 })) { Assert.Throws(() => JsonDocument.Parse(stream)); } @@ -441,7 +441,7 @@ namespace System.Text.Json.Tests [Fact] public static void ParseJson_Stream_Async_ThrowsOn_ArrayPoolRent_CodeCoverage() { - using (Stream stream = new ThrowOnCanSeekStream (new byte[] { 1 })) + using (Stream stream = new ThrowOnCanSeekStream(new byte[] { 1 })) { Assert.ThrowsAsync(async () => await JsonDocument.ParseAsync(stream)); } @@ -1728,9 +1728,11 @@ namespace System.Text.Json.Tests [Fact] public static void CheckUseAfterDispose() { - using (JsonDocument doc = JsonDocument.Parse("true", default)) + var buffer = new ArrayBufferWriter(1024); + using (JsonDocument doc = JsonDocument.Parse("{\"First\":1}", default)) { JsonElement root = doc.RootElement; + JsonProperty property = root.EnumerateObject().First(); doc.Dispose(); Assert.Throws(() => root.ValueKind); @@ -1767,26 +1769,20 @@ namespace System.Text.Json.Tests Assert.Throws(() => { - Utf8JsonWriter writer = default; - root.WriteValue(writer); + Utf8JsonWriter writer = new Utf8JsonWriter(buffer); + root.WriteTo(writer); }); Assert.Throws(() => { - Utf8JsonWriter writer = default; - root.WriteProperty(ReadOnlySpan.Empty, writer); + Utf8JsonWriter writer = new Utf8JsonWriter(buffer); + doc.WriteTo(writer); }); Assert.Throws(() => { - Utf8JsonWriter writer = default; - root.WriteProperty(ReadOnlySpan.Empty, writer); - }); - - Assert.Throws(() => - { - Utf8JsonWriter writer = default; - root.WriteProperty(JsonEncodedText.Encode(ReadOnlySpan.Empty), writer); + Utf8JsonWriter writer = new Utf8JsonWriter(buffer); + property.WriteTo(writer); }); } } @@ -1834,21 +1830,19 @@ namespace System.Text.Json.Tests Assert.Throws(() => { - Utf8JsonWriter writer = default; - root.WriteValue(writer); - }); - - Assert.Throws(() => - { - Utf8JsonWriter writer = default; - root.WriteProperty(ReadOnlySpan.Empty, writer); + var buffer = new ArrayBufferWriter(1024); + Utf8JsonWriter writer = new Utf8JsonWriter(buffer); + root.WriteTo(writer); }); + } - Assert.Throws(() => + [Fact] + public static void CheckByPassingNullWriter() + { + using (JsonDocument doc = JsonDocument.Parse("true", default)) { - Utf8JsonWriter writer = default; - root.WriteProperty(ReadOnlySpan.Empty, writer); - }); + AssertExtensions.Throws("writer", () => doc.WriteTo(null)); + } } [Fact] @@ -3605,49 +3599,6 @@ namespace System.Text.Json.Tests } [Fact] - public static void NameEquals_GivenPropertyAndValue_TrueForPropertyName() - { - string jsonString = $"{{ \"aPropertyName\" : \"itsValue\" }}"; - using (JsonDocument doc = JsonDocument.Parse(jsonString)) - { - JsonElement jElement = doc.RootElement; - JsonProperty property = jElement.EnumerateObject().First(); - - string text = "aPropertyName"; - byte[] expectedGetBytes = Encoding.UTF8.GetBytes(text); - Assert.True(property.NameEquals(text)); - Assert.True(property.NameEquals(text.AsSpan())); - Assert.True(property.NameEquals(expectedGetBytes)); - - text = "itsValue"; - expectedGetBytes = Encoding.UTF8.GetBytes(text); - Assert.False(property.NameEquals(text)); - Assert.False(property.NameEquals(text.AsSpan())); - Assert.False(property.NameEquals(expectedGetBytes)); - } - } - - [Theory] - [InlineData("conne\\u0063tionId", "connectionId")] - [InlineData("connectionId", "connectionId")] - [InlineData("123", "123")] - [InlineData("My name is \\\"Ahson\\\"", "My name is \"Ahson\"")] - public static void NameEquals_UseGoodMatches_True(string propertyName, string otherText) - { - string jsonString = $"{{ \"{propertyName}\" : \"itsValue\" }}"; - using (JsonDocument doc = JsonDocument.Parse(jsonString)) - { - JsonElement jElement = doc.RootElement; - JsonProperty property = jElement.EnumerateObject().First(); - - byte[] expectedGetBytes = Encoding.UTF8.GetBytes(otherText); - Assert.True(property.NameEquals(otherText)); - Assert.True(property.NameEquals(otherText.AsSpan())); - Assert.True(property.NameEquals(expectedGetBytes)); - } - } - - [Fact] public static void NameEquals_Empty_Throws() { const string jsonString = "{\"\" : \"some-value\"}"; @@ -3662,20 +3613,6 @@ namespace System.Text.Json.Tests } } - [Theory] - [InlineData("hello")] - [InlineData("")] - [InlineData(null)] - public static void NameEquals_InvalidInstance_Throws(string text) - { - const string ErrorMessage = "Operation is not valid due to the current state of the object."; - JsonProperty prop = default; - AssertExtensions.Throws(() => prop.NameEquals(text), ErrorMessage); - AssertExtensions.Throws(() => prop.NameEquals(text.AsSpan()), ErrorMessage); - byte[] expectedGetBytes = text == null ? null : Encoding.UTF8.GetBytes(text); - AssertExtensions.Throws(() => prop.NameEquals(expectedGetBytes), ErrorMessage); - } - private static void BuildSegmentedReader( out Utf8JsonReader reader, ReadOnlyMemory data, @@ -3740,6 +3677,41 @@ namespace System.Text.Json.Tests return s_compactJson[testCaseType] = existing; } + + [Fact] + public static void WriteNumberTooLargeScientific() + { + // This value is a reference "potential interoperability problem" from + // https://tools.ietf.org/html/rfc7159#section-6 + const string OneQuarticGoogol = "1e400"; + + // This just validates we write the literal number 1e400 even though it is too + // large to be represented by System.Double and would be converted to + // PositiveInfinity instead (or throw if using double.Parse on frameworks + // older than .NET Core 3.0). + var buffer = new ArrayBufferWriter(1024); + var expectedNonIndentedJson = $"[{OneQuarticGoogol}]"; + using (JsonDocument doc = JsonDocument.Parse($"[ {OneQuarticGoogol} ]")) + { + var writer = new Utf8JsonWriter(buffer, default); + doc.WriteTo(writer); + writer.Flush(); + + AssertContents(expectedNonIndentedJson, buffer); + } + } + + private static void AssertContents(string expectedValue, ArrayBufferWriter buffer) + { + Assert.Equal( + expectedValue, + Encoding.UTF8.GetString( + buffer.WrittenSpan +#if netfx + .ToArray() +#endif + )); + } } public class ThrowOnReadStream : MemoryStream @@ -3756,7 +3728,7 @@ namespace System.Text.Json.Tests public class ThrowOnCanSeekStream : MemoryStream { - public ThrowOnCanSeekStream (byte[] bytes) : base(bytes) + public ThrowOnCanSeekStream(byte[] bytes) : base(bytes) { } diff --git a/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs b/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs index 7866ef6..204dc6b 100644 --- a/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs +++ b/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs @@ -21,6 +21,16 @@ namespace System.Text.Json.Tests private static readonly bool s_replaceNewlines = !StringComparer.Ordinal.Equals(CompiledNewline, Environment.NewLine); + [Fact] + public static void CheckByPassingNullWriter() + { + using (JsonDocument doc = JsonDocument.Parse("true", default)) + { + JsonElement root = doc.RootElement; + AssertExtensions.Throws("writer", () => root.WriteTo(null)); + } + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -844,7 +854,7 @@ null, using (JsonDocument doc = JsonDocument.Parse(jsonIn, optionsCopy)) { var writer = new Utf8JsonWriter(buffer); - doc.RootElement.WriteValue(writer); + doc.RootElement.WriteTo(writer); writer.Flush(); ReadOnlySpan formatted = buffer.WrittenSpan; @@ -877,10 +887,14 @@ null, { foreach (JsonElement val in root.EnumerateArray()) { - val.WriteProperty(CharLabel, writer); - val.WriteProperty(CharLabel.AsSpan(), writer); - val.WriteProperty(byteUtf8, writer); - val.WriteProperty(JsonEncodedText.Encode(CharLabel), writer); + writer.WritePropertyName(CharLabel); + val.WriteTo(writer); + writer.WritePropertyName(CharLabel.AsSpan()); + val.WriteTo(writer); + writer.WritePropertyName(byteUtf8); + val.WriteTo(writer); + writer.WritePropertyName(JsonEncodedText.Encode(CharLabel)); + val.WriteTo(writer); } writer.Flush(); @@ -899,21 +913,10 @@ null, { foreach (JsonElement val in root.EnumerateArray()) { - JsonTestHelper.AssertThrows( - ref writer, - (ref Utf8JsonWriter w) => val.WriteProperty(CharLabel, w)); - - JsonTestHelper.AssertThrows( - ref writer, - (ref Utf8JsonWriter w) => val.WriteProperty(CharLabel.AsSpan(), w)); - - JsonTestHelper.AssertThrows( - ref writer, - (ref Utf8JsonWriter w) => val.WriteProperty(byteUtf8, w)); - - JsonTestHelper.AssertThrows( - ref writer, - (ref Utf8JsonWriter w) => val.WriteProperty(JsonEncodedText.Encode(CharLabel), w)); + Assert.Throws(() => writer.WritePropertyName(CharLabel)); + Assert.Throws(() => writer.WritePropertyName(CharLabel.AsSpan())); + Assert.Throws(() => writer.WritePropertyName(byteUtf8)); + Assert.Throws(() => writer.WritePropertyName(JsonEncodedText.Encode(CharLabel))); } writer.Flush(); @@ -944,7 +947,7 @@ null, { foreach (JsonElement val in root.EnumerateArray()) { - val.WriteValue(writer); + val.WriteTo(writer); } writer.WriteEndObject(); @@ -958,9 +961,7 @@ null, { foreach (JsonElement val in root.EnumerateArray()) { - JsonTestHelper.AssertThrows( - ref writer, - (ref Utf8JsonWriter w) => val.WriteValue(w)); + Assert.Throws(() => val.WriteTo(writer)); } writer.WriteEndObject(); @@ -985,7 +986,7 @@ null, var writer = new Utf8JsonWriter(buffer, options); - target.WriteValue(writer); + target.WriteTo(writer); writer.Flush(); AssertContents(jsonOut ?? jsonIn, buffer); @@ -1010,7 +1011,7 @@ null, var writer = new Utf8JsonWriter(buffer, options); - target.WriteValue(writer); + target.WriteTo(writer); writer.Flush(); if (indented && s_replaceNewlines) @@ -1081,7 +1082,8 @@ null, var writer = new Utf8JsonWriter(buffer, options); writer.WriteStartObject(); - target.WriteProperty(propertyName, writer); + writer.WritePropertyName(propertyName); + target.WriteTo(writer); writer.WriteEndObject(); writer.Flush(); @@ -1116,7 +1118,8 @@ null, var writer = new Utf8JsonWriter(buffer, options); writer.WriteStartObject(); - target.WriteProperty(propertyName, writer); + writer.WritePropertyName(propertyName); + target.WriteTo(writer); writer.WriteEndObject(); writer.Flush(); @@ -1151,7 +1154,8 @@ null, var writer = new Utf8JsonWriter(buffer, options); writer.WriteStartObject(); - target.WriteProperty(propertyName, writer); + writer.WritePropertyName(propertyName); + target.WriteTo(writer); writer.WriteEndObject(); writer.Flush(); @@ -1186,7 +1190,8 @@ null, var writer = new Utf8JsonWriter(buffer, options); writer.WriteStartObject(); - target.WriteProperty(propertyName, writer); + writer.WritePropertyName(propertyName); + target.WriteTo(writer); writer.WriteEndObject(); writer.Flush(); diff --git a/src/libraries/System.Text.Json/tests/JsonPropertyTests.cs b/src/libraries/System.Text.Json/tests/JsonPropertyTests.cs new file mode 100644 index 0000000..93055a1 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/JsonPropertyTests.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Tests +{ + public static class JsonPropertyTests + { + + [Fact] + public static void CheckByPassingNullWriter() + { + using (JsonDocument doc = JsonDocument.Parse("{\"First\":1}", default)) + { + foreach (JsonProperty property in doc.RootElement.EnumerateObject()) + { + AssertExtensions.Throws("writer", () => property.WriteTo(null)); + } + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public static void WriteObjectValidations(bool skipValidation) + { + var buffer = new ArrayBufferWriter(1024); + using (JsonDocument doc = JsonDocument.Parse("{\"First\":1}", default)) + { + JsonElement root = doc.RootElement; + var options = new JsonWriterOptions + { + SkipValidation = skipValidation, + }; + var writer = new Utf8JsonWriter(buffer, options); + if (skipValidation) + { + foreach (JsonProperty property in root.EnumerateObject()) + { + property.WriteTo(writer); + } + writer.Flush(); + AssertContents("\"First\":1", buffer); + } + else + { + foreach (JsonProperty property in root.EnumerateObject()) + { + Assert.Throws(() => + { + property.WriteTo(writer); + }); + } + writer.Flush(); + AssertContents("", buffer); + } + } + } + + [Fact] + public static void WriteSimpleObject() + { + var buffer = new ArrayBufferWriter(1024); + using (JsonDocument doc = JsonDocument.Parse("{\"First\":1, \"Number\":1e400}")) + { + var writer = new Utf8JsonWriter(buffer); + writer.WriteStartObject(); + foreach (JsonProperty prop in doc.RootElement.EnumerateObject()) + { + prop.WriteTo(writer); + } + writer.WriteEndObject(); + writer.Flush(); + + AssertContents("{\"First\":1,\"Number\":1e400}", buffer); + } + } + + private static void AssertContents(string expectedValue, ArrayBufferWriter buffer) + { + Assert.Equal( + expectedValue, + Encoding.UTF8.GetString( + buffer.WrittenSpan +#if netfx + .ToArray() +#endif + )); + } + + [Theory] + [InlineData("hello")] + [InlineData("")] + [InlineData(null)] + public static void NameEquals_InvalidInstance_Throws(string text) + { + const string ErrorMessage = "Operation is not valid due to the current state of the object."; + JsonProperty prop = default; + AssertExtensions.Throws(() => prop.NameEquals(text), ErrorMessage); + AssertExtensions.Throws(() => prop.NameEquals(text.AsSpan()), ErrorMessage); + byte[] expectedGetBytes = text == null ? null : Encoding.UTF8.GetBytes(text); + AssertExtensions.Throws(() => prop.NameEquals(expectedGetBytes), ErrorMessage); + } + + [Theory] + [InlineData("conne\\u0063tionId", "connectionId")] + [InlineData("connectionId", "connectionId")] + [InlineData("123", "123")] + [InlineData("My name is \\\"Ahson\\\"", "My name is \"Ahson\"")] + public static void NameEquals_UseGoodMatches_True(string propertyName, string otherText) + { + string jsonString = $"{{ \"{propertyName}\" : \"itsValue\" }}"; + using (JsonDocument doc = JsonDocument.Parse(jsonString)) + { + JsonElement jElement = doc.RootElement; + JsonProperty property = jElement.EnumerateObject().First(); + byte[] expectedGetBytes = Encoding.UTF8.GetBytes(otherText); + Assert.True(property.NameEquals(otherText)); + Assert.True(property.NameEquals(otherText.AsSpan())); + Assert.True(property.NameEquals(expectedGetBytes)); + } + } + + [Fact] + public static void NameEquals_GivenPropertyAndValue_TrueForPropertyName() + { + string jsonString = $"{{ \"aPropertyName\" : \"itsValue\" }}"; + using (JsonDocument doc = JsonDocument.Parse(jsonString)) + { + JsonElement jElement = doc.RootElement; + JsonProperty property = jElement.EnumerateObject().First(); + + string text = "aPropertyName"; + byte[] expectedGetBytes = Encoding.UTF8.GetBytes(text); + Assert.True(property.NameEquals(text)); + Assert.True(property.NameEquals(text.AsSpan())); + Assert.True(property.NameEquals(expectedGetBytes)); + + text = "itsValue"; + expectedGetBytes = Encoding.UTF8.GetBytes(text); + Assert.False(property.NameEquals(text)); + Assert.False(property.NameEquals(text.AsSpan())); + Assert.False(property.NameEquals(expectedGetBytes)); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 9495e76..a38fe95 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -21,6 +21,7 @@ + -- 2.7.4