Fix JsonElement.WriteTo handling of escaped property names (dotnet/corefx#40784)
authorJeremy Barton <jbarton@microsoft.com>
Tue, 3 Sep 2019 22:59:24 +0000 (15:59 -0700)
committerAhson Khan <ahson_ahmedk@yahoo.com>
Tue, 3 Sep 2019 22:59:24 +0000 (15:59 -0700)
This removes the duplicate switch statement from writing properties,
as the usage of the new WritePropertyName API on the writer simplifies the logic here.

Commit migrated from https://github.com/dotnet/corefx/commit/2d2abb32db879c877e14310c892faeeef756e27d

src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs
src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs

index 28f4535..56d5634 100644 (file)
@@ -855,45 +855,8 @@ namespace System.Text.Json
                         writer.WriteEndArray();
                         continue;
                     case JsonTokenType.PropertyName:
-                        {
-                            DbRow propertyValue = _parsedData.Get(i + DbRow.Size);
-
-                            ReadOnlySpan<byte> propertyName =
-                                _utf8Json.Slice(row.Location, row.SizeOrLength).Span;
-
-                            // "Move" to the value.
-                            i += DbRow.Size;
-
-                            switch (propertyValue.TokenType)
-                            {
-                                case JsonTokenType.String:
-                                    WriteString(propertyName, propertyValue, writer);
-                                    continue;
-                                case JsonTokenType.Number:
-                                    writer.WriteNumber(
-                                        propertyName,
-                                        _utf8Json.Slice(propertyValue.Location, propertyValue.SizeOrLength).Span);
-                                    continue;
-                                case JsonTokenType.True:
-                                    writer.WriteBoolean(propertyName, value: true);
-                                    continue;
-                                case JsonTokenType.False:
-                                    writer.WriteBoolean(propertyName, value: false);
-                                    continue;
-                                case JsonTokenType.Null:
-                                    writer.WriteNull(propertyName);
-                                    continue;
-                                case JsonTokenType.StartObject:
-                                    writer.WriteStartObject(propertyName);
-                                    continue;
-                                case JsonTokenType.StartArray:
-                                    writer.WriteStartArray(propertyName);
-                                    continue;
-                            }
-
-                            Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
-                            break;
-                        }
+                        WritePropertyName(row, writer);
+                        continue;
                 }
 
                 Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
@@ -902,7 +865,7 @@ namespace System.Text.Json
 
         private ReadOnlySpan<byte> UnescapeString(in DbRow row, out ArraySegment<byte> rented)
         {
-            Debug.Assert(row.TokenType == JsonTokenType.String);
+            Debug.Assert(row.TokenType == JsonTokenType.String || row.TokenType == JsonTokenType.PropertyName);
             int loc = row.Location;
             int length = row.SizeOrLength;
             ReadOnlySpan<byte> text = _utf8Json.Slice(loc, length).Span;
@@ -933,15 +896,13 @@ namespace System.Text.Json
             }
         }
 
-        private void WriteString(ReadOnlySpan<byte> propertyName, in DbRow row, Utf8JsonWriter writer)
+        private void WritePropertyName(in DbRow row, Utf8JsonWriter writer)
         {
             ArraySegment<byte> rented = default;
 
             try
             {
-                writer.WriteString(
-                    propertyName,
-                    UnescapeString(row, out rented));
+                writer.WritePropertyName(UnescapeString(row, out rented));
             }
             finally
             {
index 2423dc2..f3f7b55 100644 (file)
@@ -644,6 +644,24 @@ null,
         [Theory]
         [InlineData(false)]
         [InlineData(true)]
+        public void ReadWriteEscapedPropertyNames(bool indented)
+        {
+            const string jsonIn = " { \"p\\u0069zza\": 1, \"hello\\u003c\\u003e\": 2, \"normal\": 3 }";
+
+            WriteComplexValue(
+                indented,
+                jsonIn,
+                @"{
+  ""pizza"": 1,
+  ""hello\u003c\u003e"": 2,
+  ""normal"": 3
+}",
+                "{\"pizza\":1,\"hello\\u003c\\u003e\":2,\"normal\":3}");
+        }
+
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
         public void WriteNumberAsProperty(bool indented)
         {
             WritePropertyValueBothForms(
@@ -1209,20 +1227,39 @@ null,
             string expectedMinimal)
         {
             var buffer = new ArrayBufferWriter<byte>(1024);
+            byte[] bufferOutput;
 
-            using (JsonDocument doc = PrepareDocument(jsonIn))
+            var options = new JsonWriterOptions
             {
-                var options = new JsonWriterOptions
-                {
-                    Indented = indented
-                };
+                Indented = indented
+            };
 
+            using (JsonDocument doc = PrepareDocument(jsonIn))
+            {
                 using (var writer = new Utf8JsonWriter(buffer, options))
                 {
                     WriteSingleValue(doc, writer);
                 }
 
                 JsonTestHelper.AssertContents(indented ? expectedIndent : expectedMinimal, buffer);
+
+                bufferOutput = buffer.WrittenSpan.ToArray();
+            }
+
+            // After reading the output and writing it again, it should be byte-for-byte identical.
+            {
+                string bufferString = Encoding.UTF8.GetString(bufferOutput);
+                buffer.Clear();
+
+                using (JsonDocument doc2 = PrepareDocument(bufferString))
+                {
+                    using (var writer = new Utf8JsonWriter(buffer, options))
+                    {
+                        WriteSingleValue(doc2, writer);
+                    }
+                }
+
+                Assert.True(buffer.WrittenSpan.SequenceEqual(bufferOutput));
             }
         }