Skip to content

Commit

Permalink
add JToken extension methods support
Browse files Browse the repository at this point in the history
  • Loading branch information
viklover committed Jan 21, 2025
1 parent 7162d66 commit db25e5e
Show file tree
Hide file tree
Showing 4 changed files with 348 additions and 8 deletions.
152 changes: 152 additions & 0 deletions JsonHelper.Net.Test/JTokenExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using Newtonsoft.Json.Linq;

namespace NewtonsoftJsonHelper.Test;

public class JTokenExtensionsTests {
/// <summary>
/// String selection test
/// </summary>
[TestCase("{\"field\":\"hello\"}", "$.field", "hello")]
[TestCase("{\"field\": true}", "$.field", null)]
public async Task SelectStringTest(string json, string path, string? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected);
var jtoken = JToken.Parse(json);
if (expected != null) {
var result = jtoken.SelectStringOrThrow(path);
await Console.Out.WriteLineAsync(result);
Assert.That(result, Is.EqualTo(expected));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectStringOrThrow(path));
}
}
/// <summary>
/// Boolean selection test
/// </summary>
[TestCase("{\"field\": true}", "$.field", true)]
[TestCase("{\"field\":\"hello\"}", "$.field", null)]
public async Task SelectBooleanTest(string json, string path, bool? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected.ToString());
var jtoken = JToken.Parse(json);
if (expected != null) {
var result = jtoken.SelectBooleanOrThrow(path);
await Console.Out.WriteLineAsync(result.ToString());
Assert.That(result, Is.EqualTo(expected.Value));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectBooleanOrThrow(path));
}
}
/// <summary>
/// Integer selection test
/// </summary>
[TestCase("{\"field\": 12}", "$.field", 12)]
[TestCase("{\"field\":\"hello\"}", "$.field", null)]
public async Task SelectIntegerTest(string json, string path, int? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected.ToString());
var jtoken = JToken.Parse(json);
if (expected != null) {
var result = jtoken.SelectIntOrThrow(path);
await Console.Out.WriteLineAsync(result.ToString());
Assert.That(result, Is.EqualTo(expected.Value));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectIntOrThrow(path));
}
}
/// <summary>
/// Float selection test
/// </summary>
[TestCase("{\"field\": -127.0}", "$.field", -127f)]
[TestCase("{\"field\":\"hello\"}", "$.field", null)]
public async Task SelectFloatTest(string json, string path, float? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected.ToString());
var jtoken = JToken.Parse(json);
if (expected != null) {
var result = jtoken.SelectFloatOrThrow(path);
await Console.Out.WriteLineAsync(result.ToString());
Assert.That(result, Is.EqualTo(expected.Value));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectFloatOrThrow(path));
}
}
/// <summary>
/// List selection test
/// </summary>
[TestCase("{\"field\": [\"a\",\"b\",\"c\"]}", "$.field", "a", "b", "c")]
public async Task SelectListWithStringsTest(string json, string path, params string[] items) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(items.Length.ToString());
foreach (var item in items) {
await Console.Out.WriteLineAsync(item);
}
var jtoken = JToken.Parse(json);
var result = jtoken.SelectList<string>(path);
Assert.That(result, Is.Not.Null);
foreach (var item in result!) {
await Console.Out.WriteLineAsync(item);
}
Assert.That(result, Is.EquivalentTo(items));
}
/// <summary>
/// Date selection test
/// </summary>
[TestCase("{\"field\": \"2024-01-05T00:00:00\"}", "$.field", "2024-01-05T00:00:00.0000000")]
[TestCase("{\"field\":\"hello\"}", "$.field", null)]
public async Task SelectDateTest(string json, string path, string? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected?.ToString());
var jtoken = JToken.Parse(json);
if (expected != null) {
var date = jtoken.SelectDateOrThrow(path);
var dateISO = date.ToString("O");
await Console.Out.WriteLineAsync(dateISO);
Assert.That(dateISO, Is.EqualTo(expected));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectDateOrThrow(path));
}
}
/// <summary>
/// Guid selection test
/// </summary>
[TestCase("{\"field\": \"8c69a274-e68b-4b5e-bc1b-a465d234c2c0\"}", "$.field", "8c69a274-e68b-4b5e-bc1b-a465d234c2c0")]
[TestCase("{\"field\":\"LLLLLLLL-e68b-4b5e-bc1b-a465d234c20\"}", "$.field", null)]
[TestCase("{\"field\":\"hello\"}", "$.field", null)]
public async Task SelectGuidTest(string json, string path, string? expected) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expected?.ToString());
var jtoken = JToken.Parse(json);
if (expected != null) {
var guid = jtoken.SelectGuidOrThrow(path);
var guidString = guid.ToString();
await Console.Out.WriteLineAsync(guidString);
Assert.That(guidString, Is.EqualTo(expected));
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectGuidOrThrow(path));
}
}
/// <summary>
/// Json token selection test
/// </summary>
[TestCase("{\"field\":{\"hello\":1,\"world\":2}}", "$.field", false)]
[TestCase("{}", "$.field", true)]
public async Task SelectObjectTest(string json, string path, bool expectedNull) {
await Console.Out.WriteLineAsync(json);
await Console.Out.WriteLineAsync(path);
await Console.Out.WriteLineAsync(expectedNull.ToString());
var jtoken = JToken.Parse(json);
if (expectedNull == false) {
jtoken.SelectOrThrow(path, JTokenType.Object);
} else {
Assert.Throws<JsonHelperException>(() => jtoken.SelectOrThrow(path, JTokenType.Object));
}
}
}
188 changes: 188 additions & 0 deletions JsonHelper.Net/JTokenExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
using Newtonsoft.Json.Linq;

namespace NewtonsoftJsonHelper;
/// <summary>
/// <see cref="JToken"/> extension methods
/// </summary>
public static class JTokenExtensions {
/// <summary>
/// Read json token by expected <paramref name="tokenType"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <param name="tokenType">Expected json type</param>
/// <returns>Resolved token or null</returns>
/// <exception cref="JsonHelperException">Unexpected <paramref name="tokenType"/></exception>
public static JToken? Select(this JToken json, string path, JTokenType tokenType) {
return JsonHelper.Select(json, path, tokenType);
}
/// <summary>
/// Read json token by expected <paramref name="tokenType"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <param name="tokenType">Expected json type</param>
/// <returns>Resolved token</returns>
/// <exception cref="JsonHelperException">Unexpected <paramref name="tokenType"/></exception>
public static JToken SelectOrThrow(this JToken json, string path, JTokenType tokenType) {
var token = Select(json, path, tokenType);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token;
}
/// <summary>
/// Select <see cref="string"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>String value</returns>
public static string? SelectString(this JToken json, string path) {
return JsonHelper.SelectString(json, path);
}
/// <summary>
/// Select <see cref="string"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>String value</returns>
public static string SelectStringOrThrow(this JToken json, string path) {
var token = SelectString(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token;
}
/// <summary>
/// Select <see cref="bool"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Boolean value</returns>
public static bool? SelectBoolean(this JToken json, string path) {
return JsonHelper.SelectBoolean(json, path);
}
/// <summary>
/// Select <see cref="bool"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Boolean value</returns>
public static bool SelectBooleanOrThrow(this JToken json, string path) {
var token = SelectBoolean(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token.Value;
}
/// <summary>
/// Select <see cref="int"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Integer value</returns>
public static int? SelectInt(this JToken json, string path) {
return JsonHelper.SelectInt(json, path);
}
/// <summary>
/// Select <see cref="int"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Integer value</returns>
public static int SelectIntOrThrow(this JToken json, string path) {
var token = SelectInt(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token.Value;
}
/// <summary>
/// Select <see cref="float"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Float value</returns>
public static float? SelectFloat(this JToken json, string path) {
return JsonHelper.SelectFloat(json, path);
}
/// <summary>
/// Select <see cref="int"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Float value</returns>
public static float SelectFloatOrThrow(this JToken json, string path) {
var token = SelectFloat(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token.Value;
}
/// <summary>
/// Select <see cref="List{T}"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="List{T}"/></returns>
public static List<T>? SelectList<T>(this JToken json, string path) {
return JsonHelper.SelectList<T>(json, path);
}
/// <summary>
/// Select <see cref="List{T}"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="List{T}"/></returns>
public static List<T> SelectListOrThrow<T>(this JToken json, string path) {
var token = SelectList<T>(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token;
}
/// <summary>
/// Select <see cref="DateTime"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="DateTime"/></returns>
public static DateTime? SelectDate(this JToken json, string path) {
return JsonHelper.SelectDate(json, path);
}
/// <summary>
/// Select <see cref="DateTime"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="DateTime"/></returns>
public static DateTime SelectDateOrThrow(this JToken json, string path) {
var token = SelectDate(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token.Value;
}
/// <summary>
/// Select <see cref="Guid"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="Guid"/></returns>
public static Guid? SelectGuid(this JToken json, string path) {
return JsonHelper.SelectGuid(json, path);
}
/// <summary>
/// Select <see cref="Guid"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Resolved <see cref="Guid"/></returns>
public static Guid SelectGuidOrThrow(this JToken json, string path) {
var token = SelectGuid(json, path);
if (token == null) {
throw new JsonHelperException("Failed to select JToken: token is null");
}
return token.Value;
}
}
4 changes: 2 additions & 2 deletions JsonHelper.Net/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static class JsonHelper {
/// <summary>
/// Read json token by expected <paramref name="tokenType"/> or throw <see cref="JsonHelperException"/>
/// </summary>
/// <param name="json">Initial json token</param>
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <param name="tokenType">Expected json type</param>
/// <returns>Resolved token</returns>
Expand Down Expand Up @@ -109,7 +109,7 @@ public static bool SelectBooleanOrThrow(JToken json, string path) {
/// <param name="json">Initial json token</param>
/// <param name="path">JSON path</param>
/// <returns>Integer value</returns>
public static int? SelectIntOrThrow(JToken json, string path) {
public static int SelectIntOrThrow(JToken json, string path) {
var value = SelectInt(json, path);
if (value == null) {
throw new JsonHelperException($"Failed to select a integer at {path}");
Expand Down
Loading

0 comments on commit db25e5e

Please sign in to comment.