* `JsonNull` class instead of `null` reference to node.
* No additional overloads of Add methods for primary types (bool, string, int, double, long...) for `JsonObject` and `JsonArray`. Instead - implicit cast operators in JsonNode.
* `Sort` not implemented for `JsonArray`, beacuse there is no right way to compare `JsonObjects`. If a user wants to sort a `JsonArray` of `JsonNumbers`, `JsonBooleans` or `JsonStrings` they now needs to do the following: convert the `JsonArray` to a regular array (by iterating through all elements), call sort (and convert back to `JsonArray` if needed).
-* Property names duplicates handling method possible to chose during parsing to `JsonNode`. When creating `JsonObject` Add method throws an exception for duplicates and indexer replaces old property value with new one.
+* Property names duplicates handling method possible to choose during parsing to `JsonNode`. When creating `JsonObject` Add method throws an exception for duplicates and indexer replaces old property value with new one.
* No support for escaped characters when creating `JsonNumber` from string.
* `JsonValueKind` property that a caller can inspect and cast to the right concrete type
* Transformation API:
* `DeepCopy` method allowing to change JsonElement into JsonNode recursively transforming all of the elements.
* `AsJsonElement`method allowing to change JsonNode into JsonElement with IsImmutable property set to false.
* `IsImmutable` property informing if JsonElement is keeping JsonDocument or JsonNode underneath.
- * `Parse(string)` method to be able to parse a JSON string right into JsonNode if the user knows they wants mutable version. It allows chosing duplicates handling method.
+ * `Parse(string)` method to be able to parse a JSON string right into JsonNode if the user knows they want a mutable version. It allows choosing duplicates handling method.
* `Clone` method to make a copy of the whole JsonNode tree.
- * `GetNode` and TryGetNode methods allowing to retrieve it from JsonElement.
+ * `GetNode` and `TryGetNode` methods allowing to retrieve it from JsonElement.
* Internal `WriteTo(Utf8JsonWriter)` method for writing a JsonNode to a Utf8JsonWriter without having to go through JsonElement.
* `ToJsonString` method transforming JsonNode to string representation using WriteTo.
* No recursive equals for `JsonArray` and `JsonObject`.
-* `JsonNode` derived types does not implement `IComparable`.
+* `JsonNode` derived types do not implement `IComparable`.
* `JsonObject` does not implement `IDictionary`, but `JsonArray` implements `IList`.
* We support order preservation when adding/removing values in `JsonArray`/`JsonObject`.
* We do not support creating `JsonNumber` from `BigInterger` without changing it to string.
- Internal struct field which has all the supported numeric types
- Unsigned long field accompanying string to store types that are <= 8 bytes long
+* Should we add overloads for all nullable types as well? For example:
+ ```csharp
+ public static implicit operator System.Text.Json.JsonNode (bool? value) { throw null; }
+ ```
+
+* Do we want to have implicit cast operators on `JsonNull`, `JsonBoolean`, `JsonString` and `JsonNumber` while we already have them in `JsonNode`? It would be consistent, but implicit cast from e.g. float.Infinity to `JsonNumber` would throw an exception, because we would not be able return `JsonString` in this case anymore.
+
## Useful links
### JSON
<value>The JSON array was modified during iteration.</value>
</data>
<data name="NotNodeJsonElementParent" xml:space="preserve">
- <value>This JsonElement instance was not built from JsonNode</value>
+ <value>This JsonElement instance was not built from a JsonNode and is immutable.</value>
</data>
</root>
\ No newline at end of file
<Compile Include="System\Text\Json\Node\JsonArray.cs" />
<Compile Include="System\Text\Json\Node\JsonArrayEnumerator.cs" />
<Compile Include="System\Text\Json\Node\JsonBoolean.cs" />
- <Compile Include="System\Text\Json\Node\JsonNode.cs" />
+ <Compile Include="System\Text\Json\Node\JsonNode.cs" />
+ <Compile Include="System\Text\Json\Node\JsonNode.RecursionStackFrame.cs" />
<Compile Include="System\Text\Json\Node\JsonNode.Traversal.cs" />
<Compile Include="System\Text\Json\Node\JsonNode.TraversalHelpers.cs" />
<Compile Include="System\Text\Json\Node\JsonNodeOptions.cs" />
if (_parent is JsonDocument document)
{
document.WriteElementTo(_idx, writer);
- return;
}
-
- var jsonNode = (JsonNode)_parent;
- jsonNode.WriteTo(writer);
+ else
+ {
+ var jsonNode = (JsonNode)_parent;
+ jsonNode.WriteTo(writer);
+ }
}
/// <summary>
/// Gets a string representation for the current value appropriate to the value type.
/// </summary>
/// <remarks>
- /// For JsonElement built from <see cref="JsonDocument"/>:
+ /// <para>
+ /// For JsonElement built from <see cref="JsonDocument"/>:
+ /// </para>
+ ///
/// <para>
/// For <see cref="JsonValueKind.Null"/>, <see cref="string.Empty"/> is returned.
/// </para>
/// <para>
/// For other types, the value of <see cref="GetRawText"/>() is returned.
/// </para>
- /// </remarks>
- /// <remarks>
- /// For JsonElement built from <see cref="JsonNode"/>, the value of <see cref="JsonNode.ToJsonString"/> is returned.
+ ///
+ /// <para>
+ /// For JsonElement built from <see cref="JsonNode"/>, the value of <see cref="JsonNode.ToJsonString"/> is returned.
+ /// </para>
/// </remarks>
/// <returns>
/// A string representation for the current value appropriate to the value type.
/// original <see cref="JsonDocument"/>.
/// </returns>
/// <remarks>
- /// If this JsonElement is itself the output of a previous call to Clone, or
- /// a value contained within another JsonElement which was the output of a previous
- /// call to Clone, this method results in no additional memory allocation.
- /// </remarks>
- /// <remarks>
- /// For <see cref="JsonElement"/> built from <see cref="JsonNode"/> performs <see cref="JsonNode.Clone"/>.
+ /// <para>
+ /// If this JsonElement is itself the output of a previous call to Clone, or
+ /// a value contained within another JsonElement which was the output of a previous
+ /// call to Clone, this method results in no additional memory allocation.
+ /// </para>
+ /// <para>
+ /// For <see cref="JsonElement"/> built from <see cref="JsonNode"/>, performs <see cref="JsonNode.Clone"/>.
+ /// </para>
/// </remarks>
public JsonElement Clone()
{
return false;
#else
return dictionary.TryAdd(key, value);
+#endif
+ }
+
+ internal static bool IsFinite(double value)
+ {
+#if BUILDING_INBOX_LIBRARY
+ return double.IsFinite(value);
+#else
+ return !(double.IsNaN(value) || double.IsInfinity(value));
+#endif
+ }
+
+ internal static bool IsFinite(float value)
+ {
+#if BUILDING_INBOX_LIBRARY
+ return float.IsFinite(value);
+#else
+ return !(float.IsNaN(value) || float.IsInfinity(value));
#endif
}
}
get => _list[idx];
set
{
- _list[idx] = value ?? new JsonNull();
+ _list[idx] = value ?? JsonNull.Instance;
_version++;
}
}
/// <remarks>Null value is allowed and will be converted to the <see cref="JsonNull"/> instance.</remarks>
public void Add(JsonNode value)
{
- _list.Add(value ?? new JsonNull());
+ _list.Add(value ?? JsonNull.Instance);
_version++;
}
/// <remarks>Null value is allowed and will be converted to the <see cref="JsonNull"/> instance.</remarks>
public void Insert(int index, JsonNode item)
{
- _list.Insert(index, item ?? new JsonNull());
+ _list.Insert(index, item ?? JsonNull.Instance);
_version++;
}
/// <see langword="false"/> otherwise.
/// </returns>
/// <remarks>Null value is allowed and will be converted to the <see cref="JsonNull"/> instance.</remarks>
- public bool Contains(JsonNode value) => _list.Contains(value ?? new JsonNull());
+ public bool Contains(JsonNode value) => _list.Contains(value ?? JsonNull.Instance);
/// <summary>
/// Gets the number of elements contained in the collection.
/// <param name="item">Item to find.</param>
/// <returns>The zero-based starting index of the search. 0 (zero) is valid in an empty collection.</returns>
/// <remarks>Null value is allowed and will be converted to the <see cref="JsonNull"/> instance.</remarks>
- public int IndexOf(JsonNode item) => _list.IndexOf(item ?? new JsonNull());
+ public int IndexOf(JsonNode item) => _list.IndexOf(item ?? JsonNull.Instance);
/// <summary>
/// Returns the zero-based index of the last occurrence of a specified item in the collection.
/// <param name="item">Item to find.</param>
/// <returns>The zero-based starting index of the search. 0 (zero) is valid in an empty collection.</returns>
/// <remarks>Null value is allowed and will be converted to the <see cref="JsonNull"/> instance.</remarks>
- public int LastIndexOf(JsonNode item) => _list.LastIndexOf(item ?? new JsonNull());
+ public int LastIndexOf(JsonNode item) => _list.LastIndexOf(item ?? JsonNull.Instance);
/// <summary>
/// Removes all elements from the JSON array.
public bool Remove(JsonNode item)
{
_version++;
- return _list.Remove(item ?? new JsonNull());
+ return _list.Remove(item ?? JsonNull.Instance);
}
/// <summary>
--- /dev/null
+// 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.
+
+namespace System.Text.Json
+{
+ /// <summary>
+ /// The base class that represents a single node within a mutable JSON document.
+ /// </summary>
+ public abstract partial class JsonNode
+ {
+ private readonly struct RecursionStackFrame
+ {
+ public string PropertyName { get; }
+ public JsonNode PropertyValue { get; }
+ public JsonValueKind ValueKind { get; } // to retrieve ValueKind when PropertyValue is null
+
+ public RecursionStackFrame(string propertyName, JsonNode propertyValue, JsonValueKind valueKind)
+ {
+ PropertyName = propertyName;
+ PropertyValue = propertyValue;
+ ValueKind = valueKind;
+ }
+
+ public RecursionStackFrame(string propertyName, JsonNode propertyValue) : this(propertyName, propertyValue, propertyValue.ValueKind)
+ {
+ }
+ }
+ }
+}
// 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.Collections.Generic;
using System.Diagnostics;
using System.IO;
AddToParent(new KeyValuePair<string, JsonNode>(currentPair.Key, jsonBooleanFalse), ref currentNodes, ref toReturn);
break;
case JsonValueKind.Null:
- var jsonNull = new JsonNull();
+ var jsonNull = JsonNull.Instance;
AddToParent(new KeyValuePair<string, JsonNode>(currentPair.Key, jsonNull), ref currentNodes, ref toReturn);
break;
default:
AddNewPair(new JsonBoolean(false));
break;
case JsonTokenType.Null:
- AddNewPair(new JsonNull());
+ AddNewPair(JsonNull.Instance);
break;
}
}
}
/// <summary>
- /// Writes this instance to provided writer.
+ /// Writes this instance to the provided writer.
/// </summary>
- /// <param name="writer">Writer to wrtire this instance to.</param>
+ /// <param name="writer">Writer to write this instance to.</param>
public void WriteTo(Utf8JsonWriter writer)
{
var recursionStack = new Stack<RecursionStackFrame>();
{
writer.WriteEndObject();
}
- if (currentFrame.ValueKind == JsonValueKind.Array)
+ else if (currentFrame.ValueKind == JsonValueKind.Array)
{
writer.WriteEndArray();
}
writer.WriteNullValue();
break;
}
-
- writer.Flush();
}
writer.Flush();
/// <returns>JSON representation of current instance.</returns>
public string ToJsonString()
{
- var stream = new MemoryStream();
- using (var writer = new Utf8JsonWriter(stream))
+ var output = new ArrayBufferWriter<byte>();
+ using (var writer = new Utf8JsonWriter(output))
{
WriteTo(writer);
- return JsonHelpers.Utf8GetString(stream.ToArray());
}
+ return JsonHelpers.Utf8GetString(output.WrittenSpan);
}
}
}
}
else
{
- toReturn = nodePair.Value;
- }
- }
-
- private struct RecursionStackFrame
- {
- public string PropertyName { get; set; }
- public JsonNode PropertyValue { get; set; }
- public JsonValueKind ValueKind { get; set; } // to retrieve ValueKind when PropertyValue is null
+ // We are at the top level, so adding node to parent means setting it as returned one
- public RecursionStackFrame(string propertyName, JsonNode propertyValue, JsonValueKind valueKind)
- {
- PropertyName = propertyName;
- PropertyValue = propertyValue;
- ValueKind = valueKind;
- }
-
- public RecursionStackFrame(string propertyName, JsonNode propertyValue) : this(propertyName, propertyValue, propertyValue.ValueKind)
- {
+ toReturn = nodePair.Value;
}
}
}
/// <summary>
/// Gets the <see cref="JsonNode"/> represented by <paramref name="jsonElement"/>.
/// Operations performed on the returned <see cref="JsonNode"/> will modify the <paramref name="jsonElement"/>.
+ /// See also: <seealso cref="JsonElement.IsImmutable"/>.
/// </summary>
/// <param name="jsonElement"><see cref="JsonElement"/> to get the <see cref="JsonNode"/> from.</param>
/// <returns><see cref="JsonNode"/> represented by <paramref name="jsonElement"/>.</returns>
/// <exception cref="ArgumentException">
- /// Provided <see cref="JsonElement"/> was not build from <see cref="JsonNode"/>.
+ /// Provided <see cref="JsonElement"/> was not built from <see cref="JsonNode"/>.
/// </exception>
public static JsonNode GetNode(JsonElement jsonElement) => !jsonElement.IsImmutable ? (JsonNode)jsonElement._parent : throw new ArgumentException(SR.NotNodeJsonElementParent);
/// Converts a <see cref="string"/> to a <see cref="JsonString"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
+ /// <remarks>
+ /// Null value is accepted and will be interpreted as <see cref="JsonNull"/>.
+ /// </remarks>
public static implicit operator JsonNode(string value)
{
if (value == null)
{
- return new JsonNull();
+ return JsonNull.Instance;
}
return new JsonString(value);
/// <param name="value">The value to convert.</param>
public static implicit operator JsonNode(float value)
{
- if (float.IsInfinity(value) || float.IsNaN(value))
+ if (!JsonHelpers.IsFinite(value))
{
return new JsonString(value.ToString());
}
/// <param name="value">The value to convert.</param>
public static implicit operator JsonNode(double value)
{
- if (double.IsInfinity(value) || double.IsNaN(value))
+ if (!JsonHelpers.IsFinite(value))
{
return new JsonString(value.ToString());
}
/// </summary>
public JsonNull() { }
+ internal static JsonNull Instance { get; } = new JsonNull();
+
/// <summary>
/// Converts the null value to the string in JSON format.
/// </summary>
if (_dictionary.ContainsKey(propertyName))
{
- _dictionary[propertyName].Value = value ?? new JsonNull();
+ _dictionary[propertyName].Value = value ?? JsonNull.Instance;
}
else
{
throw new ArgumentException(SR.Format(SR.JsonObjectDuplicateKey, propertyName));
}
+ JsonNode valueOrJsonNull = propertyValue ?? JsonNull.Instance;
+
// Add property to linked list:
if (_last == null)
{
- _last = new JsonObjectProperty(propertyName, propertyValue ?? new JsonNull(), null, null);
+ _last = new JsonObjectProperty(propertyName, valueOrJsonNull, null, null);
_first = _last;
}
else
{
- var newJsonObjectProperty = new JsonObjectProperty(propertyName, propertyValue ?? new JsonNull(), _last, null);
+ var newJsonObjectProperty = new JsonObjectProperty(propertyName, valueOrJsonNull, _last, null);
_last.Next = newJsonObjectProperty;
_last = newJsonObjectProperty;
}
/// Provided collection contains duplicates.
/// </exception>
/// <exception cref="ArgumentNullException">
- /// Some of property names are null.
+ /// Some of the property names are null.
/// </exception>
public void AddRange(IEnumerable<KeyValuePair<string, JsonNode>> jsonProperties)
{
/// <summary>
/// Removes the property with the specified name.
/// </summary>
- /// <param name="propertyName">>Name of a property to remove.</param>
+ /// <param name="propertyName">Name of the property to remove.</param>
/// <returns>
/// <see langword="true"/> if the property is successfully found in a JSON object and removed,
/// <see langword="false"/> otherwise.
/// <summary>
/// Removes the property with the specified name.
/// </summary>
- /// <param name="propertyName">>Name of a property to remove.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
+ /// <param name="propertyName">Name of the property to remove.</param>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
/// <returns>
/// <see langword="true"/> if the property is successfully found in a JSON object and removed,
/// <see langword="false"/> otherwise.
/// <exception cref="ArgumentNullException">
/// Provided property name is null.
/// </exception>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="Remove(string)"/>.
+ /// </remarks>
public bool Remove(string propertyName, StringComparison stringComparison)
{
+ if (stringComparison == StringComparison.Ordinal)
+ {
+ return Remove(propertyName);
+ }
+
if (propertyName == null)
{
throw new ArgumentNullException(nameof(propertyName));
public bool ContainsProperty(string propertyName) => propertyName != null ? _dictionary.ContainsKey(propertyName) : throw new ArgumentNullException(nameof(propertyName));
/// <summary>
- /// Determines whether a property is in a JSON object.
+ /// Determines whether a property is in this JSON object.
/// </summary>
/// <param name="propertyName">Name of the property to check.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
/// <returns>
- /// <see langword="true"/> if the property is successfully found in a JSON object,
+ /// <see langword="true"/> if the property is successfully found in the JSON object,
/// <see langword="false"/> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Provided property name is null.
/// </exception>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="ContainsProperty(string)"/>.
+ /// </remarks>
public bool ContainsProperty(string propertyName, StringComparison stringComparison)
{
+ if (stringComparison == StringComparison.Ordinal)
+ {
+ return ContainsProperty(propertyName);
+ }
+
foreach (KeyValuePair<string, JsonNode> property in this)
{
if (string.Equals(property.Key, propertyName, stringComparison))
/// Returns the value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <returns>Value of the property with the specified name.</returns>
+ /// <returns>The JSON value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON object.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
public JsonNode GetPropertyValue(string propertyName)
{
/// Returns the value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <returns>Value of the property with the specified name.</returns>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <returns>The JSON value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON object.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="GetPropertyValue(string)"/>.
+ /// </remarks>
public JsonNode GetPropertyValue(string propertyName, StringComparison stringComparison)
{
if (!TryGetPropertyValue(propertyName, stringComparison, out JsonNode jsonNode))
/// Returns the value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="jsonNode">Value of the property with specified name.</param>
+ /// <param name="jsonNode">The JSON value of the property with the specified name.</param>
/// <returns>
- /// <see langword="true"/> if property with specified name was found;
+ /// <see langword="true"/> if a property with the specified name was found;
/// otherwise, <see langword="false"/>
/// </returns>
/// <remarks>
- /// When returns <see langword="false"/>, the value of <paramref name="jsonNode"/> is meaningless.
+ /// When this method returns <see langword="false"/>, the value of <paramref name="jsonNode"/> is meaningless.
/// </remarks>
public bool TryGetPropertyValue(string propertyName, out JsonNode jsonNode)
{
/// Returns the value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <param name="jsonNode">Value of the property with specified name.</param>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <param name="jsonNode">The JSON value of the property with the specified name.</param>
/// <returns>
/// <see langword="true"/> if property with specified name was found;
/// otherwise, <see langword="false"/>
/// </returns>
/// <remarks>
- /// When returns <see langword="false"/>, the value of <paramref name="jsonNode"/> is meaningless.
+ /// When this method returns <see langword="false"/>, the value of <paramref name="jsonNode"/> is meaningless.
+ /// </remarks>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="TryGetPropertyValue(string, out JsonNode)"/>.
/// </remarks>
public bool TryGetPropertyValue(string propertyName, StringComparison stringComparison, out JsonNode jsonNode)
{
+ if (stringComparison == StringComparison.Ordinal)
+ {
+ return TryGetPropertyValue(propertyName, out jsonNode);
+ }
+
foreach (KeyValuePair<string, JsonNode> property in this)
{
if (string.Equals(property.Key, propertyName, stringComparison))
/// Returns the JSON object value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <returns>JSON objectvalue of a property with the specified name.</returns>
+ /// <returns>The JSON object value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON object.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
/// <exception cref="ArgumentException">
- /// Property with specified name is not a JSON object.
+ /// The property with the specified name is not a JSON object.
/// </exception>
public JsonObject GetJsonObjectPropertyValue(string propertyName)
{
/// Returns the JSON object value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <returns>JSON objectvalue of a property with the specified name.</returns>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <returns>The JSON object value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON object.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
/// <exception cref="ArgumentException">
- /// Property with specified name is not a JSON object.
+ /// The property with the specified name is not a JSON object.
/// </exception>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="GetJsonObjectPropertyValue(string)"/>.
+ /// </remarks>
public JsonObject GetJsonObjectPropertyValue(string propertyName, StringComparison stringComparison)
{
if (GetPropertyValue(propertyName, stringComparison) is JsonObject jsonObject)
/// Returns the JSON object value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="jsonObject">JSON object value of the property with specified name.</param>
+ /// <param name="jsonObject">The JSON object value of the property with the specified name.</param>
/// <returns>
/// <see langword="true"/> if JSON object property with specified name was found;
/// otherwise, <see langword="false"/>
/// Returns the JSON object value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <param name="jsonObject">JSON object value of the property with specified name.</param>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <param name="jsonObject">The JSON object value of the property with the specified name.</param>
/// <returns>
/// <see langword="true"/> if JSON object property with specified name was found;
/// otherwise, <see langword="false"/>
/// </returns>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="TryGetJsonObjectPropertyValue(string, out JsonObject)"/>.
+ /// </remarks>
public bool TryGetJsonObjectPropertyValue(string propertyName, StringComparison stringComparison, out JsonObject jsonObject)
{
if (TryGetPropertyValue(propertyName, stringComparison, out JsonNode jsonNode))
/// Returns the JSON array value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <returns>JSON objectvalue of a property with the specified name.</returns>
+ /// <returns>The JSON array value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON array.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
/// <exception cref="ArgumentException">
- /// Property with specified name is not a JSON array.
+ /// The property with the specified name is not a JSON array.
/// </exception>
public JsonArray GetJsonArrayPropertyValue(string propertyName)
{
/// Returns the JSON array value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <returns>JSON objectvalue of a property with the specified name.</returns>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <returns>The JSON array value of the property with the specified name.</returns>
/// <exception cref="KeyNotFoundException">
- /// Property with specified name is not found in JSON array.
+ /// A property with the specified name is not found in this JSON object.
/// </exception>
/// <exception cref="ArgumentException">
- /// Property with specified name is not a JSON array.
+ /// The property with the specified name is not a JSON array.
/// </exception>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="GetJsonArrayPropertyValue(string)"/>.
+ /// </remarks>
public JsonArray GetJsonArrayPropertyValue(string propertyName, StringComparison stringComparison)
{
if (GetPropertyValue(propertyName, stringComparison) is JsonArray jsonArray)
/// Returns the JSON array value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="jsonArray">JSON array value of the property with specified name.</param>
+ /// <param name="jsonArray">The JSON array value of the property with the specified name.</param>
/// <returns>
/// <see langword="true"/> if JSON array property with specified name was found;
/// otherwise, <see langword="false"/>
/// Returns the JSON array value of a property with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property to return.</param>
- /// <param name="stringComparison">The culture and case to be used when comparing string value.</param>
- /// <param name="jsonArray">JSON array value of the property with specified name.</param>
+ /// <param name="stringComparison">The culture, case, and sort rules to be used when comparing string value.</param>
+ /// <param name="jsonArray">The JSON array value of the property with the specified name.</param>
/// <returns>
/// <see langword="true"/> if JSON array property with specified name was found;
/// otherwise, <see langword="false"/>
/// </returns>
+ /// <remarks>
+ /// If <paramref name="stringComparison"/> is set to <see cref="StringComparison.Ordinal"/>, calling this method is equivalent to calling <see cref="TryGetJsonArrayPropertyValue(string, out JsonArray)"/>.
+ /// </remarks>
public bool TryGetJsonArrayPropertyValue(string propertyName, StringComparison stringComparison, out JsonArray jsonArray)
{
if (TryGetPropertyValue(propertyName, stringComparison, out JsonNode jsonNode))
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateDouble(double value)
{
-#if BUILDING_INBOX_LIBRARY
- if (!double.IsFinite(value))
-#else
- if (double.IsNaN(value) || double.IsInfinity(value))
-#endif
+ if (!JsonHelpers.IsFinite(value))
{
ThrowHelper.ThrowArgumentException_ValueNotSupported();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateSingle(float value)
{
-#if BUILDING_INBOX_LIBRARY
- if (!float.IsFinite(value))
-#else
- if (float.IsNaN(value) || float.IsInfinity(value))
-#endif
+ if (!JsonHelpers.IsFinite(value))
{
ThrowHelper.ThrowArgumentException_ValueNotSupported();
}
[Fact]
public static void TestHeterogeneousArray()
{
- var mixedTypesArray = new JsonArray { 1, "value", true };
+ var mixedTypesArray = new JsonArray { 1, "value", true, null, 2.3, new JsonObject() };
Assert.Equal(1, mixedTypesArray[0]);
Assert.Equal("value", mixedTypesArray[1]);
Assert.Equal(true, mixedTypesArray[2]);
+ Assert.IsType<JsonNull>(mixedTypesArray[3]);
+ Assert.Equal(2.3, mixedTypesArray[4]);
+ Assert.IsType<JsonObject>(mixedTypesArray[5]);
- mixedTypesArray.Add(17);
+ mixedTypesArray.Add(false);
mixedTypesArray.Insert(4, "another");
mixedTypesArray.Add(new JsonNull());
- Assert.Equal(17, mixedTypesArray[3]);
+ Assert.Equal(false, mixedTypesArray[7]);
Assert.Equal("another", mixedTypesArray[4]);
- Assert.IsType<JsonNull>(mixedTypesArray[5]);
-
+ Assert.IsType<JsonNull>(mixedTypesArray[8]);
}
[Fact]
Assert.Null(jsonArrayEnumerator.Current);
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal(1, jsonArrayEnumerator.Current);
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal("value", jsonArrayEnumerator.Current);
+ Assert.False(jsonArrayEnumerator.MoveNext());
jsonArrayEnumerator.Reset();
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal(1, jsonArrayEnumerator.Current);
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal("value", jsonArrayEnumerator.Current);
// Test non-generic IEnumerator:
jsonArrayEnumerator2.MoveNext();
Assert.Equal((JsonNumber)1, jsonArrayEnumerator2.Current);
- jsonArrayEnumerator2.MoveNext();
+ Assert.True(jsonArrayEnumerator2.MoveNext());
Assert.Equal((JsonString)"value", jsonArrayEnumerator2.Current);
+ Assert.False(jsonArrayEnumerator2.MoveNext());
jsonArrayEnumerator2.Reset();
- jsonArrayEnumerator2.MoveNext();
+ Assert.True(jsonArrayEnumerator2.MoveNext());
Assert.Equal((JsonNumber)1, jsonArrayEnumerator2.Current);
- jsonArrayEnumerator2.MoveNext();
+ Assert.True(jsonArrayEnumerator2.MoveNext());
Assert.Equal((JsonString)"value", jsonArrayEnumerator2.Current);
+ Assert.False(jsonArrayEnumerator2.MoveNext());
}
[Fact]
Assert.Null(jsonArrayEnumerator.Current);
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal((JsonNumber)1, jsonArrayEnumerator.Current);
- jsonArrayEnumerator.MoveNext();
+ Assert.True(jsonArrayEnumerator.MoveNext());
Assert.Equal((JsonString)"value", jsonArrayEnumerator.Current);
}
// 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.Globalization;
using System.IO;
using Xunit;
jsonObject["2"] = 4;
Assert.Throws<InvalidOperationException>(() => objectEnumerator.MoveNext());
-
JsonElement notObject = new JsonArray().AsJsonElement();
Assert.Throws<InvalidOperationException>(() => notObject.EnumerateObject());
}
["array"] = new JsonArray() { 1, 2 }
};
- var stream = new MemoryStream();
- using (var writer = new Utf8JsonWriter(stream))
+ var output = new ArrayBufferWriter<byte>();
+ using (var writer = new Utf8JsonWriter(output))
{
jsonObject.AsJsonElement().WriteTo(writer);
- string result = Encoding.UTF8.GetString(stream.ToArray());
- Assert.Equal(jsonObject.ToJsonString(), result);
}
+
+ JsonTestHelper.AssertContents(jsonObject.ToJsonString(), output);
}
[Fact]
{
var jsonObject = new JsonObject()
{
- ["text"] = "value",
+ ["text"] = "za\u017C\u00F3\u0142\u0107 g\u0119\u015Bl\u0105 ja\u017A\u0144",
+ ["text2"] = ">><++>>>\">>\\>>&>>>\u6f22\u5B57>>>",
+ ["text3"] = "..\t\r\n...\"quote\"",
+ ["<<.\t\r\n.\"quote\".\u017C\u00F3>>"] = "",
["boolean"] = true,
["null"] = null,
["array"] = new JsonArray() { 1, 2 }
{
jsonNode.WriteTo(writer);
stream.Seek(0, SeekOrigin.Begin);
- var jsonDocument = JsonDocument.Parse(stream, s_options);
+ JsonDocument jsonDocument = JsonDocument.Parse(stream, s_options);
return jsonDocument;
}
}
}
[Fact]
- public static void TestParseDoesNotOverflow()
+ public static void TestParseDoesNotStackOverflow()
{
var builder = new StringBuilder();
for (int i = 0; i < 2_000; i++)
var options = new JsonNodeOptions { MaxDepth = 5_000 };
JsonNode jsonNode = JsonNode.Parse(builder.ToString(), options);
+
+ Assert.Equal(1, ((JsonArray)jsonNode).Count);
}
[Fact]
- public static void TestDeepCopyDoesNotOverflow()
+ public static void TestParseFailsWhenExceedsMaxDepth()
+ {
+ var builder = new StringBuilder();
+ for (int i = 0; i < 100; i++)
+ {
+ builder.Append("[");
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ builder.Append("]");
+ }
+
+ Assert.ThrowsAny<JsonException>(() => JsonNode.Parse(builder.ToString()));
+ }
+
+ [Fact]
+ public static void TestDeepCopyDoesNotStackOverflow()
{
var builder = new StringBuilder();
for (int i = 0; i < 2_000; i++)
var options = new JsonDocumentOptions { MaxDepth = 5_000 };
using (JsonDocument dom = JsonDocument.Parse(builder.ToString(), options))
{
- JsonNode node = JsonNode.DeepCopy(dom.RootElement);
+ JsonNode jsonNode = JsonNode.DeepCopy(dom.RootElement);
+ Assert.Equal(1, ((JsonArray)jsonNode).Count);
}
}
Assert.Throws<ArgumentException>(() => JsonNode.Parse(stringWithDuplicates, new JsonNodeOptions() { DuplicatePropertyNameHandling = DuplicatePropertyNameHandlingStrategy.Error }));
}
+
+ [Theory]
+ [InlineData(DuplicatePropertyNameHandlingStrategy.Replace)]
+ [InlineData(DuplicatePropertyNameHandlingStrategy.Ignore)]
+ [InlineData(DuplicatePropertyNameHandlingStrategy.Error)]
+ public static void TestParseWithNestedDuplicates(DuplicatePropertyNameHandlingStrategy duplicatePropertyNameHandling)
+ {
+ var options = new JsonNodeOptions
+ {
+ DuplicatePropertyNameHandling = duplicatePropertyNameHandling
+ };
+
+ var stringWithDuplicates = @"
+ {
+ ""property"": ""first value"",
+ ""nested object"":
+ {
+ ""property"": ""duplicate value"",
+ ""more nested object"":
+ {
+ ""property"": ""last duplicate value""
+ }
+ },
+ ""array"" : [ ""property"" ]
+ }";
+
+ var jsonObject = (JsonObject)JsonNode.Parse(stringWithDuplicates, options);
+ Assert.Equal(3, jsonObject.GetPropertyNames().Count);
+ Assert.Equal(3, jsonObject.GetPropertyValues().Count);
+ Assert.Equal("first value", jsonObject["property"]);
+ CheckNestedValues(jsonObject);
+
+ jsonObject.Remove("property");
+
+ Assert.Equal(2, jsonObject.GetPropertyNames().Count);
+ Assert.Equal(2, jsonObject.GetPropertyValues().Count);
+ CheckNestedValues(jsonObject);
+
+ void CheckNestedValues(JsonObject jsonObject)
+ {
+ var nestedObject = (JsonObject)jsonObject["nested object"];
+ Assert.Equal(2, nestedObject.GetPropertyNames().Count);
+ Assert.Equal(2, nestedObject.GetPropertyValues().Count);
+ Assert.Equal("duplicate value", nestedObject["property"]);
+
+ var moreNestedObject = (JsonObject)nestedObject["more nested object"];
+ Assert.Equal(1, moreNestedObject.GetPropertyNames().Count);
+ Assert.Equal(1, moreNestedObject.GetPropertyValues().Count);
+ Assert.Equal("last duplicate value", moreNestedObject["property"]);
+
+ var array = (JsonArray)jsonObject["array"];
+ Assert.Equal(1, array.Count);
+ Assert.True(array.Contains("property"));
+ }
+
+ var nestedObject = (JsonObject)jsonObject["nested object"];
+ nestedObject.Add("array", new JsonNumber());
+
+ Assert.IsType<JsonArray>(jsonObject["array"]);
+ Assert.IsType<JsonNumber>(nestedObject["array"]);
+ }
}
}
IEquatable<JsonNull> jsonNullIEquatable = new JsonNull();
Assert.Equal(jsonNull.GetHashCode(), jsonNullIEquatable.GetHashCode());
- object jsonNullCopy= jsonNull;
+ object jsonNullCopy = jsonNull;
object jsonNullObject = new JsonNull();
Assert.Equal(jsonNull.GetHashCode(), jsonNullCopy.GetHashCode());
Assert.Equal(jsonNull.GetHashCode(), jsonNullObject.GetHashCode());
Assert.IsType<JsonNull>(jsonObject["null1"]);
}
+ [Fact]
+ public static void TestGetAndTryGetNullProperty()
+ {
+ var jsonObject = new JsonObject
+ {
+ { "null", null }
+ };
+
+ Assert.IsType<JsonNull>(jsonObject.GetPropertyValue("null"));
+ Assert.True(jsonObject.TryGetPropertyValue("null", out JsonNode node));
+ Assert.IsType<JsonNull>(node);
+ }
+
[Fact]
public static void TestContains()
{
});
}
+ [Fact]
+ public static void TestGetJsonObjectPropertyValueOnDifferentLevelFails()
+ {
+ var jsonObject = new JsonObject()
+ {
+ {
+ "inner object", new JsonObject()
+ {
+ { "object", new JsonObject() }
+ }
+ }
+ };
+
+ Assert.Equal(1, jsonObject.GetJsonObjectPropertyValue("inner object").GetPropertyNames().Count);
+ Assert.Throws<KeyNotFoundException>(() => jsonObject.GetJsonObjectPropertyValue("object"));
+ }
+
[Fact]
public static void TestTryGetObjectPropertyFails()
{
});
}
+ [Fact]
+ public static void TestGetJsonArrayPropertyValueOnDifferentLevelFails()
+ {
+ var jsonObject = new JsonObject()
+ {
+ {
+ "inner object", new JsonObject()
+ {
+ { "array", new JsonArray() { 1, 2 } }
+ }
+ }
+ };
+
+ Assert.Throws<KeyNotFoundException>(() => jsonObject.GetJsonArrayPropertyValue("array"));
+ }
+
[Fact]
public static void TestTryGetArrayPropertyFails()
{
}
[Fact]
- public static void TestStringComparisonEnum()
+ public static void TestStringComparisonEnumGetPropertyRemoveContains()
{
var jsonObject = new JsonObject()
{
Assert.False(jsonObject.TryGetPropertyValue("ENCYCLOPAEDIA", out JsonNode jsonNode));
Assert.Null(jsonNode);
Assert.Throws<KeyNotFoundException>(() => jsonObject.GetPropertyValue("ENCYCLOPAEDIA"));
- jsonObject.Remove("ENCYCLOPAEDIA");
+ Assert.False(jsonObject.Remove("ENCYCLOPAEDIA"));
Assert.Equal(4, jsonObject.Count());
- Assert.False(jsonObject.ContainsProperty("ENCYCLOPAEDIA", StringComparison.CurrentCulture));
- Assert.False(jsonObject.TryGetPropertyValue("ENCYCLOPAEDIA", StringComparison.CurrentCulture, out jsonNode));
- Assert.Null(jsonNode);
- Assert.Throws<KeyNotFoundException>(() => jsonObject.GetPropertyValue("ENCYCLOPAEDIA", StringComparison.CurrentCulture));
- jsonObject.Remove("ENCYCLOPAEDIA", StringComparison.CurrentCulture);
- Assert.Equal(4, jsonObject.Count());
+ Check(jsonObject, StringComparison.CurrentCulture);
+ Check(jsonObject, StringComparison.InvariantCulture);
+ Check(jsonObject, StringComparison.Ordinal);
+
+ CheckIgnoreCase(StringComparison.CurrentCultureIgnoreCase);
+ CheckIgnoreCase(StringComparison.InvariantCultureIgnoreCase);
+ CheckIgnoreCase(StringComparison.OrdinalIgnoreCase);
+
+ void Check(JsonObject jsonObject, StringComparison stringComparison)
+ {
+ Assert.False(jsonObject.ContainsProperty("ENCYCLOPAEDIA", stringComparison));
+ Assert.False(jsonObject.TryGetPropertyValue("ENCYCLOPAEDIA", stringComparison, out JsonNode jsonNode));
+ Assert.Null(jsonNode);
+ Assert.Throws<KeyNotFoundException>(() => jsonObject.GetPropertyValue("ENCYCLOPAEDIA", stringComparison));
+ Assert.False(jsonObject.Remove("ENCYCLOPAEDIA", stringComparison));
+ Assert.Equal(4, jsonObject.Count());
+ }
- Assert.True(jsonObject.ContainsProperty("ENCYCLOPAEDIA", StringComparison.InvariantCultureIgnoreCase));
- Assert.True(jsonObject.TryGetPropertyValue("ENCYCLOPAEDIA", StringComparison.InvariantCultureIgnoreCase, out jsonNode));
- Assert.Equal("value2", jsonNode);
- Assert.Equal("value2", jsonObject.GetPropertyValue("ENCYCLOPAEDIA", StringComparison.InvariantCultureIgnoreCase));
- jsonObject.Remove("ENCYCLOPAEDIA", StringComparison.InvariantCultureIgnoreCase);
- Assert.Equal(3, jsonObject.Count());
+ void CheckIgnoreCase(StringComparison stringComparison)
+ {
+ var jsonObject = new JsonObject()
+ {
+ { "not encyclopaedia", "value1" },
+ { "Encyclopaedia", "value2" },
+ { "NOT encyclopaedia", "value3" },
+ { "encyclopaedia", "value4" }
+ };
- IReadOnlyCollection<JsonNode> values = jsonObject.GetPropertyValues();
- Assert.False(values.Contains("value2"));
- Assert.True(values.Contains("value1"));
- Assert.True(values.Contains("value3"));
- Assert.True(values.Contains("value4"));
+ Assert.True(jsonObject.ContainsProperty("ENCYCLOPAEDIA", stringComparison));
+ Assert.True(jsonObject.TryGetPropertyValue("ENCYCLOPAEDIA", stringComparison, out jsonNode));
+ Assert.Equal("value2", jsonNode);
+ Assert.Equal("value2", jsonObject.GetPropertyValue("ENCYCLOPAEDIA", stringComparison));
+ Assert.True(jsonObject.Remove("ENCYCLOPAEDIA", stringComparison));
+ Assert.Equal(3, jsonObject.Count());
+
+ IReadOnlyCollection<JsonNode> values = jsonObject.GetPropertyValues();
+ Assert.False(values.Contains("value2"));
+ Assert.True(values.Contains("value1"));
+ Assert.True(values.Contains("value3"));
+ Assert.True(values.Contains("value4"));
+ }
+ }
- jsonObject = new JsonObject()
+ [Fact]
+ public static void TestStringComparisonEnumGetArrayOrObjectProperty()
+ {
+ var jsonObject = new JsonObject()
{
{ "object first", new JsonObject() },
{ "object FIRST", new JsonArray() },
{ "array FIRST", new JsonObject() }
};
- Assert.Equal(0, jsonObject.GetJsonObjectPropertyValue("OBJECT first",
- StringComparison.InvariantCultureIgnoreCase).GetPropertyNames().Count);
- Assert.True(jsonObject.TryGetJsonObjectPropertyValue("OBJECT first", StringComparison.InvariantCultureIgnoreCase,
- out JsonObject objectProperty));
- Assert.Equal(0, objectProperty.GetPropertyNames().Count);
+ Check(jsonObject, StringComparison.CurrentCulture);
+ Check(jsonObject, StringComparison.InvariantCulture);
+ Check(jsonObject, StringComparison.Ordinal);
- Assert.Throws<ArgumentException>(() =>
- jsonObject.GetJsonArrayPropertyValue("OBJECT first", StringComparison.InvariantCultureIgnoreCase));
- Assert.False(jsonObject.TryGetJsonArrayPropertyValue("OBJECT first", StringComparison.InvariantCultureIgnoreCase,
- out JsonArray arrayProperty));
- Assert.False(jsonObject.TryGetJsonArrayPropertyValue("something different", StringComparison.InvariantCultureIgnoreCase,
- out arrayProperty));
-
- Assert.Equal(0, jsonObject.GetJsonArrayPropertyValue("ARRAY first",
- StringComparison.InvariantCultureIgnoreCase).Count);
- Assert.True(jsonObject.TryGetJsonArrayPropertyValue("ARRAY first", StringComparison.InvariantCultureIgnoreCase,
- out arrayProperty));
- Assert.Equal(0, arrayProperty.Count);
+ CheckIgnoreCase(jsonObject, StringComparison.CurrentCultureIgnoreCase);
+ CheckIgnoreCase(jsonObject, StringComparison.InvariantCultureIgnoreCase);
+ CheckIgnoreCase(jsonObject, StringComparison.OrdinalIgnoreCase);
- Assert.Throws<ArgumentException>(() =>
- jsonObject.GetJsonObjectPropertyValue("ARRAY first", StringComparison.InvariantCultureIgnoreCase));
- Assert.False(jsonObject.TryGetJsonObjectPropertyValue("ARRAY first", StringComparison.InvariantCultureIgnoreCase,
- out objectProperty));
- Assert.False(jsonObject.TryGetJsonObjectPropertyValue("something different", StringComparison.InvariantCultureIgnoreCase,
- out objectProperty));
+ void Check(JsonObject jsonObject, StringComparison stringComparison)
+ {
+ Assert.Equal(0, jsonObject.GetJsonObjectPropertyValue("object first",
+ stringComparison).GetPropertyNames().Count);
+ Assert.True(jsonObject.TryGetJsonObjectPropertyValue("object first", stringComparison,
+ out JsonObject objectProperty));
+ Assert.Equal(0, objectProperty.GetPropertyNames().Count);
- Assert.Throws<ArgumentNullException>(() =>
- jsonObject.Remove(null, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Throws<ArgumentException>(() =>
+ jsonObject.GetJsonObjectPropertyValue("object FIRST", stringComparison));
+ Assert.False(jsonObject.TryGetJsonObjectPropertyValue("object FIRST", stringComparison,
+ out objectProperty));
+
+ Assert.Equal(0, jsonObject.GetJsonArrayPropertyValue("array first",
+ stringComparison).Count);
+ Assert.True(jsonObject.TryGetJsonArrayPropertyValue("array first", stringComparison,
+ out JsonArray arrayProperty));
+ Assert.Equal(0, arrayProperty.Count);
+
+ Assert.Throws<ArgumentException>(() =>
+ jsonObject.GetJsonArrayPropertyValue("array FIRST", stringComparison));
+ Assert.False(jsonObject.TryGetJsonArrayPropertyValue("array FIRST", stringComparison,
+ out arrayProperty));
+
+ Assert.Throws<ArgumentNullException>(() =>
+ jsonObject.Remove(null, stringComparison));
+ }
+
+ void CheckIgnoreCase(JsonObject jsonObject, StringComparison stringComparison)
+ {
+ Assert.Equal(0, jsonObject.GetJsonObjectPropertyValue("OBJECT first",
+ stringComparison).GetPropertyNames().Count);
+ Assert.True(jsonObject.TryGetJsonObjectPropertyValue("OBJECT first", stringComparison,
+ out JsonObject objectProperty));
+ Assert.Equal(0, objectProperty.GetPropertyNames().Count);
+
+ Assert.Throws<ArgumentException>(() =>
+ jsonObject.GetJsonArrayPropertyValue("OBJECT first", stringComparison));
+ Assert.False(jsonObject.TryGetJsonArrayPropertyValue("OBJECT first", stringComparison,
+ out JsonArray arrayProperty));
+ Assert.False(jsonObject.TryGetJsonArrayPropertyValue("something different", stringComparison,
+ out arrayProperty));
+
+ Assert.Equal(0, jsonObject.GetJsonArrayPropertyValue("ARRAY first",
+ stringComparison).Count);
+ Assert.True(jsonObject.TryGetJsonArrayPropertyValue("ARRAY first", stringComparison,
+ out arrayProperty));
+ Assert.Equal(0, arrayProperty.Count);
+
+ Assert.Throws<ArgumentException>(() =>
+ jsonObject.GetJsonObjectPropertyValue("ARRAY first", stringComparison));
+ Assert.False(jsonObject.TryGetJsonObjectPropertyValue("ARRAY first", stringComparison,
+ out objectProperty));
+ Assert.False(jsonObject.TryGetJsonObjectPropertyValue("something different", stringComparison,
+ out objectProperty));
+
+ Assert.Throws<ArgumentNullException>(() =>
+ jsonObject.Remove(null, stringComparison));
+ }
}
[Fact]
[InlineData("value")]
[InlineData("value with some spaces")]
[InlineData(" leading spaces")]
- [InlineData("trailing spaces")]
+ [InlineData("trailing spaces ")]
[InlineData("new lines\r\n")]
[InlineData("tabs\ttabs\t")]
[InlineData("\\u003e\\u003e\\u003e\\u003e\\u003e")]