Add WriteTo API on JsonDocument and JsonProperty (dotnet/corefx#39367)
authorVishnu Kumar <sasivishnu@gmail.com>
Fri, 12 Jul 2019 22:06:08 +0000 (03:36 +0530)
committerEric StJohn <ericstj@microsoft.com>
Fri, 12 Jul 2019 22:06:08 +0000 (15:06 -0700)
* 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

src/libraries/System.Text.Json/ref/System.Text.Json.cs
src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs
src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonElement.cs
src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonProperty.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterJsonElement.cs
src/libraries/System.Text.Json/tests/JsonDocumentTests.cs
src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs
src/libraries/System.Text.Json/tests/JsonPropertyTests.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj

index 2190c90..5b60ca2 100644 (file)
@@ -26,6 +26,7 @@ namespace System.Text.Json
         public static System.Threading.Tasks.Task<System.Text.Json.JsonDocument> 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<byte> utf8Text) { throw null; }
         public bool ValueEquals(System.ReadOnlySpan<char> text) { throw null; }
         public bool ValueEquals(string text) { throw null; }
-        public void WriteProperty(System.ReadOnlySpan<byte> utf8PropertyName, System.Text.Json.Utf8JsonWriter writer) { }
-        public void WriteProperty(System.ReadOnlySpan<char> 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.Text.Json.JsonElement>, System.Collections.Generic.IEnumerator<System.Text.Json.JsonElement>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
         {
             private object _dummy;
@@ -167,6 +164,7 @@ namespace System.Text.Json
         public bool NameEquals(System.ReadOnlySpan<byte> utf8Text) { throw null; }
         public bool NameEquals(System.ReadOnlySpan<char> 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
index 176f219..fc32f80 100644 (file)
@@ -75,6 +75,29 @@ namespace System.Text.Json
             }
         }
 
+        /// <summary>
+        ///  Write the document into the provided writer as a JSON value.
+        /// </summary>
+        /// <param name="writer"></param>
+        /// <exception cref="ArgumentNullException">
+        ///   The <paramref name="writer"/> parameter is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        ///   This <see cref="RootElement"/>'s <see cref="JsonElement.ValueKind"/> would result in an invalid JSON.
+        /// </exception>
+        /// <exception cref="ObjectDisposedException">
+        ///   The parent <see cref="JsonDocument"/> has been disposed.
+        /// </exception>
+        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<char> 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<byte> 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<byte> rented = default;
-
-            try
-            {
-                writer.WriteString(
-                    propertyName,
-                    UnescapeString(row, out rented));
-            }
-            finally
-            {
-                ClearAndReturn(rented);
-            }
-        }
-
         private void WriteString(ReadOnlySpan<byte> propertyName, in DbRow row, Utf8JsonWriter writer)
         {
             ArraySegment<byte> rented = default;
@@ -1063,23 +947,6 @@ namespace System.Text.Json
             }
         }
 
-        private void WriteString(ReadOnlySpan<char> propertyName, in DbRow row, Utf8JsonWriter writer)
-        {
-            ArraySegment<byte> rented = default;
-
-            try
-            {
-                writer.WriteString(
-                    propertyName,
-                    UnescapeString(row, out rented));
-            }
-            finally
-            {
-                ClearAndReturn(rented);
-
-            }
-        }
-
         private void WriteString(in DbRow row, Utf8JsonWriter writer)
         {
             ArraySegment<byte> rented = default;
index 214eaab..1b142fd 100644 (file)
@@ -1269,87 +1269,25 @@ namespace System.Text.Json
         }
 
         /// <summary>
-        ///   Write the element into the provided writer as a named JSON object property.
-        /// </summary>
-        /// <param name="propertyName">The name for this value within the JSON object.</param>
-        /// <param name="writer">The writer.</param>
-        /// <exception cref="InvalidOperationException">
-        ///   This value's <see cref="ValueKind"/> is <see cref="JsonValueKind.Undefined"/>.
-        /// </exception>
-        /// <exception cref="ObjectDisposedException">
-        ///   The parent <see cref="JsonDocument"/> has been disposed.
-        /// </exception>
-        public void WriteProperty(string propertyName, Utf8JsonWriter writer)
-            => WriteProperty(propertyName.AsSpan(), writer);
-
-        /// <summary>
-        ///   Write the element into the provided writer as a named JSON object property.
-        /// </summary>
-        /// <param name="propertyName">The name for this value within the JSON object.</param>
-        /// <param name="writer">The writer.</param>
-        /// <exception cref="InvalidOperationException">
-        ///   This value's <see cref="ValueKind"/> is <see cref="JsonValueKind.Undefined"/>.
-        /// </exception>
-        /// <exception cref="ObjectDisposedException">
-        ///   The parent <see cref="JsonDocument"/> has been disposed.
-        /// </exception>
-        public void WriteProperty(ReadOnlySpan<char> propertyName, Utf8JsonWriter writer)
-        {
-            CheckValidInstance();
-
-            _parent.WriteElementTo(_idx, writer, propertyName);
-        }
-
-        /// <summary>
-        ///   Write the element into the provided writer as a named JSON object property.
+        ///   Write the element into the provided writer as a JSON value.
         /// </summary>
-        /// <param name="propertyName">The pre-encoded name for this value within the JSON object.</param>
         /// <param name="writer">The writer.</param>
-        /// <exception cref="InvalidOperationException">
-        ///   This value's <see cref="ValueKind"/> is <see cref="JsonValueKind.Undefined"/>.
-        /// </exception>
-        /// <exception cref="ObjectDisposedException">
-        ///   The parent <see cref="JsonDocument"/> has been disposed.
+        /// <exception cref="ArgumentNullException">
+        ///   The <paramref name="writer"/> parameter is <see langword="null"/>.
         /// </exception>
-        public void WriteProperty(JsonEncodedText propertyName, Utf8JsonWriter writer)
-        {
-            CheckValidInstance();
-
-            _parent.WriteElementTo(_idx, writer, propertyName);
-        }
-
-        /// <summary>
-        ///   Write the element into the provided writer as a named JSON object property.
-        /// </summary>
-        /// <param name="utf8PropertyName">
-        ///   The name for this value within the JSON object, as UTF-8 text.
-        /// </param>
-        /// <param name="writer">The writer.</param>
         /// <exception cref="InvalidOperationException">
         ///   This value's <see cref="ValueKind"/> is <see cref="JsonValueKind.Undefined"/>.
         /// </exception>
         /// <exception cref="ObjectDisposedException">
         ///   The parent <see cref="JsonDocument"/> has been disposed.
         /// </exception>
-        public void WriteProperty(ReadOnlySpan<byte> utf8PropertyName, Utf8JsonWriter writer)
+        public void WriteTo(Utf8JsonWriter writer)
         {
-            CheckValidInstance();
-
-            _parent.WriteElementTo(_idx, writer, utf8PropertyName);
-        }
+            if (writer == null)
+            {
+                throw new ArgumentNullException(nameof(writer));
+            }
 
-        /// <summary>
-        ///   Write the element into the provided writer as a JSON value.
-        /// </summary>
-        /// <param name="writer">The writer.</param>
-        /// <exception cref="InvalidOperationException">
-        ///   This value's <see cref="ValueKind"/> is <see cref="JsonValueKind.Undefined"/>.
-        /// </exception>
-        /// <exception cref="ObjectDisposedException">
-        ///   The parent <see cref="JsonDocument"/> has been disposed.
-        /// </exception>
-        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:
index fcab3e9..79d8fd8 100644 (file)
@@ -89,6 +89,33 @@ namespace System.Text.Json
         }
 
         /// <summary>
+        ///   Write the property into the provided writer as a named JSON object property.
+        /// </summary>
+        /// <param name="writer">The writer.</param>
+        /// <exception cref="ArgumentNullException">
+        ///   The <paramref name="writer"/> parameter is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   This <see cref="Name"/>'s length is too large to be a JSON object property.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        ///   This <see cref="Value"/>'s <see cref="JsonElement.ValueKind"/> would result in an invalid JSON.
+        /// </exception>
+        /// <exception cref="ObjectDisposedException">
+        ///   The parent <see cref="JsonDocument"/> has been disposed.
+        /// </exception>>
+        public void WriteTo(Utf8JsonWriter writer)
+        {
+            if (writer == null)
+            {
+                throw new ArgumentNullException(nameof(writer));
+            }
+
+            writer.WritePropertyName(Name);
+            Value.WriteTo(writer);
+        }
+
+        /// <summary>
         ///   Provides a <see cref="string"/> representation of the property for
         ///   debugging purposes.
         /// </summary>
index 57ed5b5..b8a4da3 100644 (file)
@@ -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);
         }
     }
 }
index 44665cf..c22fbbc 100644 (file)
@@ -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<InsufficientMemoryException>(() => 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<InsufficientMemoryException>(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<byte>(1024);
+            using (JsonDocument doc = JsonDocument.Parse("{\"First\":1}", default))
             {
                 JsonElement root = doc.RootElement;
+                JsonProperty property = root.EnumerateObject().First();
                 doc.Dispose();
 
                 Assert.Throws<ObjectDisposedException>(() => root.ValueKind);
@@ -1767,26 +1769,20 @@ namespace System.Text.Json.Tests
 
                 Assert.Throws<ObjectDisposedException>(() =>
                 {
-                    Utf8JsonWriter writer = default;
-                    root.WriteValue(writer);
+                    Utf8JsonWriter writer = new Utf8JsonWriter(buffer);
+                    root.WriteTo(writer);
                 });
 
                 Assert.Throws<ObjectDisposedException>(() =>
                 {
-                    Utf8JsonWriter writer = default;
-                    root.WriteProperty(ReadOnlySpan<char>.Empty, writer);
+                    Utf8JsonWriter writer = new Utf8JsonWriter(buffer);
+                    doc.WriteTo(writer);
                 });
 
                 Assert.Throws<ObjectDisposedException>(() =>
                 {
-                    Utf8JsonWriter writer = default;
-                    root.WriteProperty(ReadOnlySpan<byte>.Empty, writer);
-                });
-
-                Assert.Throws<ObjectDisposedException>(() =>
-                {
-                    Utf8JsonWriter writer = default;
-                    root.WriteProperty(JsonEncodedText.Encode(ReadOnlySpan<byte>.Empty), writer);
+                    Utf8JsonWriter writer = new Utf8JsonWriter(buffer);
+                    property.WriteTo(writer);
                 });
             }
         }
@@ -1834,21 +1830,19 @@ namespace System.Text.Json.Tests
 
             Assert.Throws<InvalidOperationException>(() =>
             {
-                Utf8JsonWriter writer = default;
-                root.WriteValue(writer);
-            });
-
-            Assert.Throws<InvalidOperationException>(() =>
-            {
-                Utf8JsonWriter writer = default;
-                root.WriteProperty(ReadOnlySpan<char>.Empty, writer);
+                var buffer = new ArrayBufferWriter<byte>(1024);
+                Utf8JsonWriter writer = new Utf8JsonWriter(buffer);                
+                root.WriteTo(writer);
             });
+        }
 
-            Assert.Throws<InvalidOperationException>(() =>
+        [Fact]
+        public static void CheckByPassingNullWriter()
+        {
+            using (JsonDocument doc = JsonDocument.Parse("true", default))
             {
-                Utf8JsonWriter writer = default;
-                root.WriteProperty(ReadOnlySpan<byte>.Empty, writer);
-            });
+                AssertExtensions.Throws<ArgumentNullException>("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<InvalidOperationException>(() => prop.NameEquals(text), ErrorMessage);
-            AssertExtensions.Throws<InvalidOperationException>(() => prop.NameEquals(text.AsSpan()), ErrorMessage);
-            byte[] expectedGetBytes = text == null ? null : Encoding.UTF8.GetBytes(text);
-            AssertExtensions.Throws<InvalidOperationException>(() => prop.NameEquals(expectedGetBytes), ErrorMessage);
-        }
-
         private static void BuildSegmentedReader(
             out Utf8JsonReader reader,
             ReadOnlyMemory<byte> 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<byte>(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<byte> 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)
         {
         }
 
index 7866ef6..204dc6b 100644 (file)
@@ -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<ArgumentNullException>("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<byte> 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<InvalidOperationException>(
-                            ref writer,
-                            (ref Utf8JsonWriter w) => val.WriteProperty(CharLabel, w));
-
-                        JsonTestHelper.AssertThrows<InvalidOperationException>(
-                            ref writer,
-                            (ref Utf8JsonWriter w) => val.WriteProperty(CharLabel.AsSpan(), w));
-
-                        JsonTestHelper.AssertThrows<InvalidOperationException>(
-                            ref writer,
-                            (ref Utf8JsonWriter w) => val.WriteProperty(byteUtf8, w));
-
-                        JsonTestHelper.AssertThrows<InvalidOperationException>(
-                            ref writer,
-                            (ref Utf8JsonWriter w) => val.WriteProperty(JsonEncodedText.Encode(CharLabel), w));
+                        Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(CharLabel));
+                        Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(CharLabel.AsSpan()));
+                        Assert.Throws<InvalidOperationException>(() => writer.WritePropertyName(byteUtf8));
+                        Assert.Throws<InvalidOperationException>(() => 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<InvalidOperationException>(
-                            ref writer,
-                            (ref Utf8JsonWriter w) => val.WriteValue(w));
+                        Assert.Throws<InvalidOperationException>(() => 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 (file)
index 0000000..93055a1
--- /dev/null
@@ -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<ArgumentNullException>("writer", () => property.WriteTo(null));
+                }
+            }
+        }
+
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public static void WriteObjectValidations(bool skipValidation)
+        {
+            var buffer = new ArrayBufferWriter<byte>(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<InvalidOperationException>(() =>
+                        {
+                            property.WriteTo(writer);
+                        });
+                    }
+                    writer.Flush();
+                    AssertContents("", buffer);
+                }
+            }
+        }
+
+        [Fact]
+        public static void WriteSimpleObject()
+        {
+            var buffer = new ArrayBufferWriter<byte>(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<byte> 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<InvalidOperationException>(() => prop.NameEquals(text), ErrorMessage);
+            AssertExtensions.Throws<InvalidOperationException>(() => prop.NameEquals(text.AsSpan()), ErrorMessage);
+            byte[] expectedGetBytes = text == null ? null : Encoding.UTF8.GetBytes(text);
+            AssertExtensions.Throws<InvalidOperationException>(() => 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));
+            }
+        }
+    }
+}
index 9495e76..a38fe95 100644 (file)
@@ -21,6 +21,7 @@
     <Compile Include="JsonEncodedTextTests.cs" />
     <Compile Include="JsonGuidTestData.cs" />
     <Compile Include="JsonNumberTestData.cs" />
+    <Compile Include="JsonPropertyTests.cs" />
     <Compile Include="JsonReaderStateAndOptionsTests.cs" />
     <Compile Include="JsonTestHelper.cs" />
     <Compile Include="JsonWriterOptionsTests.cs" />