Skip to content

Commit

Permalink
Allow deserialization when properties case doesn't match (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
torbacz committed Oct 20, 2022
1 parent a17027b commit f727302
Show file tree
Hide file tree
Showing 31 changed files with 752 additions and 220 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
|:-|---|---|
| Json | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.Json/_apis/build/status/nanoFramework.Json?repoName=nanoframework%2FnanoFramework.Json&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.Json/_build/latest?definitionId=59&repoName=nanoframework%2FnanoFramework.Json&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Json.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Json/) |

## Case insensitive members resolving
By default nanoFramework.JSON deserialization is case sensitive. This behaviour can be switched by changing nanoFramework.Json.Configuration.Settings.CaseSensitive flag to false.
Note, case insensitive resolving is 3-5 times slower than case sensitive. Keep that in mind before using it.


## Feedback and documentation

For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using nanoFramework.Json.Converters;
using nanoFramework.Json.Configuration;
using nanoFramework.Json.Converters;
using nanoFramework.TestFramework;
using System;
using System.Text;

namespace nanoFramework.Json.Test.Converters
namespace nanoFramework.Json.Test.Configuration
{
[TestClass]
public class ConvertersMappingTests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using nanoFramework.Json.Converters;
using nanoFramework.Json.Configuration;
using nanoFramework.Json.Converters;
using nanoFramework.TestFramework;
using System;
using System.Text;

namespace nanoFramework.Json.Test
namespace nanoFramework.Json.Test.Configuration
{
[TestClass]
public class JsonCustomTypeTests
Expand All @@ -28,13 +29,13 @@ public object ToType(object value)
}

[Setup]
public void Setup()
public void JsonCustomTypeTests_Setup()
{
ConvertersMapping.Add(typeof(TestObject), new CustomConverter());
}

[Cleanup]
public void CleanUp()
public void JsonCustomTypeTests_CleanUp()
{
ConvertersMapping.Remove(typeof(TestObject));
}
Expand Down
23 changes: 23 additions & 0 deletions nanoFramework.Json.Test/Configuration/SettingsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using nanoFramework.Json.Configuration;
using nanoFramework.TestFramework;
using System;
using System.Text;

namespace nanoFramework.Json.Test.Configuration
{
[TestClass]
public class SettingsTests
{
[TestMethod]
public void CaseSensitive_Should_BeTrueByDefault()
{
Assert.Equal(Settings.CaseSensitive, true);
}

[TestMethod]
public void ThrowExceptionWhenPropertyNotFound_Should_BeFalseByDefault()
{
Assert.Equal(Settings.ThrowExceptionWhenPropertyNotFound, false);
}
}
}
10 changes: 5 additions & 5 deletions nanoFramework.Json.Test/Converters/BoolConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ namespace nanoFramework.Json.Test.Converters
[TestClass]
public class BoolConverterTests
{
/*[TestMethod]
[DataRow("true", true)]
[DataRow("false", false)]
public void ToType_ShouldReturnValidData(string value, bool expectedValue)
[TestMethod]
[DataRow(true, true)]
[DataRow(false, false)]
public void BoolConverter_ToType_ShouldReturnValidData(object value, bool expectedValue)
{
var converter = new Json.Converters.BoolConverter();
var convertedValue = (bool)converter.ToType(value);

Assert.Equal(expectedValue, convertedValue);
}*/
}

[TestMethod]
[DataRow(true, "true")]
Expand Down
20 changes: 20 additions & 0 deletions nanoFramework.Json.Test/Converters/DateTimeConverterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using nanoFramework.TestFramework;
using System;
using System.Text;

namespace nanoFramework.Json.Test.Converters
{
[TestClass]
public class DateTimeConverterTests
{
[TestMethod]
[DataRow(0, "\"1970-01-01T00:00:00.0000000Z\"")]
public void DateTimeConverter_BoolConverter_ToJson_Should_ReturnValidData(int value, string expectedValue)
{
var converter = new Json.Converters.DateTimeConverter();
var convertedValue = converter.ToJson(DateTime.FromUnixTimeSeconds(value));

Assert.Equal(expectedValue, convertedValue);
}
}
}
9 changes: 9 additions & 0 deletions nanoFramework.Json.Test/Converters/DoubleConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public void DoubleConverter_ToType_ShouldReturnValidData(string value, double ex
Assert.Equal(expectedValue, convertedValue);
}

[TestMethod]
public void DoubleConverter_ToType_NullShouldReturnNaN()
{
var converter = new Json.Converters.DoubleConverter();
var convertedValue = (double)converter.ToType(null);

Assert.Equal(double.NaN.ToString(), convertedValue.ToString());
}

[TestMethod]
[DataRow(120.5, "120.5")]
[DataRow(42.5, "42.5")]
Expand Down
9 changes: 9 additions & 0 deletions nanoFramework.Json.Test/Converters/FloatConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public void FloatConverter_ToType_ShouldReturnValidData(string value, float expe
Assert.Equal(expectedValue, convertedValue);
}

[TestMethod]
public void FloatConverter_ToType_NullShouldReturnNaN()
{
var converter = new Json.Converters.FloatConverter();
var convertedValue = (float)converter.ToType(null);

Assert.Equal(float.NaN.ToString(), convertedValue.ToString());
}

[TestMethod]
[DataRow(120.5f, "120.5")]
[DataRow(42.5f, "42.5")]
Expand Down
14 changes: 12 additions & 2 deletions nanoFramework.Json.Test/Converters/StringConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace nanoFramework.Json.Test.Converters
public class StringConverterTests
{
[TestMethod]
[DataRow("\"TestJson\"", "TestJson")]
[DataRow("\"TestJson\"", "\"TestJson\"")]
[DataRow("TestJson1", "TestJson1")]
public void StringConverter_ToType_ShouldReturnValidData(string value, string expectedValue)
{
var converter = new Json.Converters.StringConverter();
Expand All @@ -17,7 +18,16 @@ public void StringConverter_ToType_ShouldReturnValidData(string value, string ex
}

[TestMethod]
[DataRow("TestJson", "\"TestJson\"")]
public void StringConverter_ToType_ShouldReturnStringEmptyForNull()
{
var converter = new Json.Converters.StringConverter();
var convertedValue = (string)converter.ToType(null);

Assert.Equal(string.Empty, convertedValue);
}

[TestMethod]
[DataRow("TestJson2", "\"TestJson2\"")]
public void StringConverter_ToJson_Should_ReturnValidData(string value, string expectedValue)
{
var converter = new Json.Converters.StringConverter();
Expand Down
2 changes: 2 additions & 0 deletions nanoFramework.Json.Test/Converters/TimeSpanConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class TimeSpanConverterTests
{
[TestMethod]
[DataRow("10:00:00", 10)]
[DataRow("24:00:00", 24)]
public void TimeSpanConverter_ToType_ShouldReturnValidData(string value, int expectedValueHours)
{
var converter = new Json.Converters.TimeSpanConverter();
Expand All @@ -19,6 +20,7 @@ public void TimeSpanConverter_ToType_ShouldReturnValidData(string value, int exp

[TestMethod]
[DataRow(10, "\"10:00:00\"")]
[DataRow(24, "\"24:00:00\"")]
public void TimeSpanConverter_ToJson_Should_ReturnValidData(int valueHours, string expectedValue)
{
var converter = new Json.Converters.TimeSpanConverter();
Expand Down
37 changes: 37 additions & 0 deletions nanoFramework.Json.Test/JsonDeserializationArraysTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using nanoFramework.TestFramework;
using System;
using System.Text;

namespace nanoFramework.Json.Test
{
[TestClass]
public class JsonDeserializationArraysTests
{
const string IntArrayJson = "[405421362,1082483948,1131707654,345242860,1111968802]";
const string ShortArrayJson = "[12345,25463,22546,18879,12453]";

[TestMethod]
public void CanDeserializeIntArray()
{
var result = (int[])JsonConvert.DeserializeObject(IntArrayJson, typeof(int[]));

Assert.Equal(result[0], 405421362);
Assert.Equal(result[1], 1082483948);
Assert.Equal(result[2], 1131707654);
Assert.Equal(result[3], 345242860);
Assert.Equal(result[4], 1111968802);
}

[TestMethod]
public void CanDeserializeShortArray()
{
var result = (short[])JsonConvert.DeserializeObject(ShortArrayJson, typeof(short[]));

Assert.Equal(result[0], (short)12345);
Assert.Equal(result[1], (short)25463);
Assert.Equal(result[2], (short)22546);
Assert.Equal(result[3], (short)18879);
Assert.Equal(result[4], (short)12453);
}
}
}
40 changes: 2 additions & 38 deletions nanoFramework.Json.Test/JsonUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,42 +314,6 @@ public void Can_serialize_deserialize_timespan_01()
OutputHelper.WriteLine("");
}

[TestMethod]
public void DeserialzieInvalidTimeSpan_Should_ThrowInvalidCaseException()
{
OutputHelper.WriteLine("Can_serialize_deserialize_timespan_02() - Starting test...");

string[] strArr = new string[] {
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"24:0:0\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"0:0:60\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"10:\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\":10\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"10:20:\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\".123\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"10.\"}",
"{\"Duration5\":\"00:00:00\",\"Duration1\":\"01:09:00\",\"DummyValue2\":777,\"Duration2\":\"00:00:00\",\"DummyValue1\":-999,\"Duration3\":\"00:00:00\",\"Duration4\":\"10.12\"}",
};

for (int i = 0; i < strArr.Length; i++)
{
try
{
// The method should throw InvalidCaseException as each strArr has at least one invalid value for TimeSpan
JsonConvert.DeserializeObject(strArr[i], typeof(JsonTestClassTimeSpan));

// If the method above haven't throw InvalidCastException then the test should fail
throw new InvalidOperationException($"Should throw exception {nameof(InvalidCastException)}.");
}
catch (InvalidCastException)
{
// Deserialization should throw exception and test should not fail.
}
}

OutputHelper.WriteLine("Can_serialize_deserialize_timespan_02() - Finished - test succeeded.");
OutputHelper.WriteLine("");
}

[TestMethod]
public void Can_serialize_short_array()
{
Expand Down Expand Up @@ -977,8 +941,8 @@ public void CanDeserializeInvocationReceiveMessage_05()

string arg1 = (string)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dserResult.arguments[1]), typeof(string));

Assert.Equal(arg0, "I_am_a_string", $"arg0 has unexpected value: {arg0}");
Assert.Equal(arg1, "I_am_another_string", $"arg1 has unexpected value: {arg1}");
Assert.Equal(arg0, "\"I_am_a_string\"", $"arg0 has unexpected value: {arg0}");
Assert.Equal(arg1, "\"I_am_another_string\"", $"arg1 has unexpected value: {arg1}");
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using nanoFramework.Json.Configuration;
using nanoFramework.Json.Resolvers;
using nanoFramework.TestFramework;
using System;

namespace nanoFramework.Json.Test.Resolvers
{
[TestClass]
public class MemberResolverCaseInsensitiveExceptionTests
{
private class TestClass
{
public int NoGetProperty { private get; set; } = 1;
public int NoSetProperty { get; } = 1;
}

[Setup]
public void MemberResolverCaseInsensitiveExceptionTests_Setup()
{
Settings.ThrowExceptionWhenPropertyNotFound = true;
Settings.CaseSensitive = false;
}

[Cleanup]
public void MemberResolverCaseInsensitiveExceptionTests_Cleanup()
{
Settings.ThrowExceptionWhenPropertyNotFound = false;
Settings.CaseSensitive = true;
}

[TestMethod]
public void MemberResolverCaseInsensitiveExceptionTests_Get_ShouldSkipPropertyWithoutGet()
{
var resolver = new MemberResolver();

try
{
resolver.Get(nameof(TestClass.NoGetProperty), typeof(TestClass));
}
catch (DeserializationException)
{
// Intended. Method should throw this type of exception when no set method.
return;
}

throw new InvalidOperationException($"Should throw {nameof(DeserializationException)}.");
}

[TestMethod]
public void MemberResolverCaseInsensitiveExceptionTests_Get_ShouldSkipPropertyWithoutSet()
{
var resolver = new MemberResolver();

try
{
resolver.Get(nameof(TestClass.NoSetProperty), typeof(TestClass));
}
catch (DeserializationException)
{
// Intended. Method should throw this type of exception when no set method.
return;
}

throw new InvalidOperationException($"Should throw {nameof(DeserializationException)}.");
}
}
}
Loading

0 comments on commit f727302

Please sign in to comment.