Skip to content

Commit eea7739

Browse files
authored
Fix bug when adding / appending string values (Azure#53025)
1 parent 39deb6a commit eea7739

File tree

5 files changed

+58
-15
lines changed

5 files changed

+58
-15
lines changed

sdk/core/System.ClientModel/src/ModelReaderWriter/JsonPatch.Implementation.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,11 @@ private void SetInternal(ReadOnlySpan<byte> jsonPath, EncodedValue encodedValue)
453453
nextPath = localPath.GetFirstProperty();
454454
parentPath = "$"u8;
455455
}
456+
if (nextPath.IsArrayIndex() && !encodedValue.Kind.HasFlag(ValueKind.ArrayItemAppend))
457+
{
458+
nextPath = parentPath;
459+
kind |= ValueKind.ArrayItemAppend;
460+
}
456461
}
457462
else
458463
{
@@ -470,16 +475,15 @@ private void SetInternal(ReadOnlySpan<byte> jsonPath, EncodedValue encodedValue)
470475
{
471476
nextPath = pathReader.GetParsedPath();
472477
parentPath = nextPath.GetParent();
478+
if (nextPath.IsArrayIndex() && !encodedValue.Kind.HasFlag(ValueKind.ArrayItemAppend))
479+
{
480+
nextPath = parentPath;
481+
kind |= ValueKind.ArrayItemAppend;
482+
}
473483
}
474484
}
475485
}
476486

477-
if (nextPath.IsArrayIndex() && !encodedValue.Kind.HasFlag(ValueKind.ArrayItemAppend))
478-
{
479-
nextPath = parentPath;
480-
kind |= ValueKind.ArrayItemAppend;
481-
}
482-
483487
if (nextPath.SequenceEqual(localPath))
484488
{
485489
kind = encodedValue.Kind;

sdk/core/System.ClientModel/src/ModelReaderWriter/JsonPatch.Serialization.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,23 @@ public void WriteTo(Utf8JsonWriter writer)
179179
}
180180
else
181181
{
182-
if (kvp.Key.IsArrayIndex())
183-
{
184-
newJson = newJson.InsertAt(kvp.Key, kvp.Value.Value);
185-
}
186-
else
187-
{
188-
newJson = newJson.Set(kvp.Key, kvp.Value.Value);
189-
}
182+
newJson = newJson.Set(kvp.Key, GetEncodedBytes(kvp.Value));
190183
}
191184
}
192185
writer.WriteRawValue(newJson.Span);
193186
}
194187
}
195188

189+
private static ReadOnlyMemory<byte> GetEncodedBytes(EncodedValue value)
190+
{
191+
ValueKind kind = value.Kind;
192+
if (kind.HasFlag(ValueKind.Utf8String) || kind.HasFlag(ValueKind.DateTime) || kind.HasFlag(ValueKind.Guid) || kind.HasFlag(ValueKind.TimeSpan))
193+
{
194+
return new([(byte)'"', .. value.Value.Span, (byte)'"']);
195+
}
196+
return value.Value;
197+
}
198+
196199
private static void WriteEncodedValueAsJson(Utf8JsonWriter writer, ReadOnlySpan<byte> propertyName, EncodedValue encodedValue)
197200
{
198201
if (encodedValue.Value.Length == 0)

sdk/core/System.ClientModel/src/ModelReaderWriter/JsonPathExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,9 @@ private static bool IsFirstProperty(ReadOnlyMemory<byte> json, ReadOnlySpan<byte
428428
public static byte[] Set(this ReadOnlyMemory<byte> json, ReadOnlySpan<byte> jsonPath, ReadOnlyMemory<byte> jsonReplacement)
429429
{
430430
bool found = TryFind(json.Span, jsonPath, out Utf8JsonReader jsonReader);
431-
return jsonReader.SetCurrentValue(found, jsonPath.GetPropertyName(), json, jsonReplacement);
431+
return !found && jsonPath.IsArrayIndex()
432+
? json.InsertAt(jsonPath, jsonReplacement)
433+
: jsonReader.SetCurrentValue(found, jsonPath.GetPropertyName(), json, jsonReplacement);
432434
}
433435

434436
/// <summary>

sdk/core/System.ClientModel/tests/ModelReaderWriterTests/JsonPatchTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,5 +461,21 @@ public void NullException_Format()
461461
Assert.AreEqual("Value cannot be null. (Parameter 'format')", ex!.Message);
462462
#endif
463463
}
464+
465+
[Test]
466+
public void AddStringPropertyToComplexObject()
467+
{
468+
JsonPatch jp = new("{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true}}}"u8.ToArray());
469+
jp.Set("$.a.new"u8, "newValue");
470+
Assert.AreEqual("{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true},\"new\":\"newValue\"}}", jp.ToString("J"));
471+
}
472+
473+
[Test]
474+
public void AddStringArrayElement()
475+
{
476+
JsonPatch jp = new("{\"a\":[\"one\",\"two\",\"three\"]}"u8.ToArray());
477+
jp.Set("$.a[1]"u8, "newTwo");
478+
Assert.AreEqual("{\"a\":[\"one\",\"newTwo\",\"three\"]}", jp.ToString("J"));
479+
}
464480
}
465481
}

sdk/core/System.ClientModel/tests/internal/ModelReaderWriter/JsonPathExtensionsTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,24 @@ public void GetFirstProperty(string jsonPathStr, string expected)
260260
Assert.AreEqual(expected, Encoding.UTF8.GetString(first.ToArray()));
261261
}
262262

263+
[TestCase("{\"a\":1,\"b\":2}", "$.b", "100", "{\"a\":1,\"b\":100}")]
264+
[TestCase("{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true}}}", "$.a.new", "\"stringValue\"", "{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true},\"new\":\"stringValue\"}}")]
265+
[TestCase("{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true}}}", "$.a.new", "100", "{\"a\":{\"b\":{\"bProp\":1},\"c\":{\"cProp\":true},\"new\":100}}")]
266+
[TestCase("{\"a\":{\"b\":[\"1\",\"2\",\"3\"]}}", "$.a.b[0]", "\"new\"", "{\"a\":{\"b\":[\"new\",\"2\",\"3\"]}}")]
267+
[TestCase("{\"a\":{\"b\":[\"1\",\"2\",\"3\"]}}", "$.a.b[1]", "\"new\"", "{\"a\":{\"b\":[\"1\",\"new\",\"3\"]}}")]
268+
[TestCase("{\"a\":{\"b\":[\"1\",\"2\",\"3\"]}}", "$.a.b[2]", "\"new\"", "{\"a\":{\"b\":[\"1\",\"2\",\"new\"]}}")]
269+
[TestCase("{\"a\":{\"b\":[1,2,3]}}", "$.a.b[0]", "10", "{\"a\":{\"b\":[10,2,3]}}")]
270+
[TestCase("{\"a\":{\"b\":[1,2,3]}}", "$.a.b[1]", "10", "{\"a\":{\"b\":[1,10,3]}}")]
271+
[TestCase("{\"a\":{\"b\":[1,2,3]}}", "$.a.b[2]", "10", "{\"a\":{\"b\":[1,2,10]}}")]
272+
public void Set(string jsonStr, string jsonPathStr, string newValue, string expected)
273+
{
274+
ReadOnlyMemory<byte> json = Encoding.UTF8.GetBytes(jsonStr);
275+
ReadOnlySpan<byte> jsonPath = Encoding.UTF8.GetBytes(jsonPathStr);
276+
ReadOnlyMemory<byte> value = Encoding.UTF8.GetBytes(newValue);
277+
var result = json.Set(jsonPath, value);
278+
Assert.AreEqual(expected, Encoding.UTF8.GetString(result));
279+
}
280+
263281
[TestCase("{\"a\":1,\"b\":2}", "$.c", "3", false, "{\"a\":1,\"b\":2,\"c\":3}")]
264282
[TestCase("{\"a\":1}", "$.a", "2", true, "{\"a\":2}")]
265283
[TestCase("{\"arr\":[1,2]}", "$.arr[1]", "10", true, "{\"arr\":[1,10]}")]

0 commit comments

Comments
 (0)