Skip to content

Commit 3221861

Browse files
Rework of UnitsNetJsonConverter (#746)
* Reworked UnitsNetJsonConverter according to #732. Also split up serialization and deserialization tests into seperate files for better readability and extracted test objects into their own classes. Consider this an overall clean-up of the test project * Corrected naming of converters and added converter tests * Rename field * Resolved PR remarks Co-authored-by: Andreas Gullberg Larsen <[email protected]>
1 parent 966caf0 commit 3221861

17 files changed

+1267
-431
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
5+
{
6+
public sealed class TestObject
7+
{
8+
public Frequency? NullableFrequency { get; set; }
9+
public Frequency NonNullableFrequency { get; set; }
10+
}
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System;
5+
6+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
7+
{
8+
public sealed class TestObjectWithIComparable
9+
{
10+
public IComparable Value { get; set; }
11+
}
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System;
5+
6+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
7+
{
8+
public sealed class TestObjectWithThreeIComparable
9+
{
10+
public IComparable Value1 { get; set; }
11+
12+
public IComparable Value2 { get; set; }
13+
14+
public IComparable Value3 { get; set; }
15+
}
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System;
5+
6+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
7+
{
8+
public sealed class TestObjectWithValueAndUnitAsIComparable : IComparable
9+
{
10+
public double Value { get; set; }
11+
public string Unit { get; set; }
12+
13+
public int CompareTo(object obj)
14+
{
15+
return ((IComparable)Value).CompareTo(obj);
16+
}
17+
}
18+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System;
5+
6+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
7+
{
8+
public sealed class TestObjectWithValueAsIComparable : IComparable
9+
{
10+
public int Value { get; set; }
11+
12+
public int CompareTo(object obj)
13+
{
14+
return ((IComparable)Value).CompareTo(obj);
15+
}
16+
17+
// Needed for verifying that the deserialized object is the same, should not affect the serialization code
18+
public override bool Equals(object obj)
19+
{
20+
if (obj == null || GetType() != obj.GetType())
21+
{
22+
return false;
23+
}
24+
return Value.Equals(((TestObjectWithValueAsIComparable)obj).Value);
25+
}
26+
27+
public override int GetHashCode()
28+
{
29+
return Value.GetHashCode();
30+
}
31+
}
32+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using Newtonsoft.Json;
5+
6+
namespace UnitsNet.Serialization.JsonNet.Tests.Infrastructure
7+
{
8+
public abstract class UnitsNetJsonBaseTest
9+
{
10+
private readonly JsonSerializerSettings _jsonSerializerSettings;
11+
12+
protected UnitsNetJsonBaseTest()
13+
{
14+
_jsonSerializerSettings = new JsonSerializerSettings {Formatting = Formatting.Indented};
15+
_jsonSerializerSettings.Converters.Add(new UnitsNetIQuantityJsonConverter());
16+
_jsonSerializerSettings.Converters.Add(new UnitsNetIComparableJsonConverter());
17+
}
18+
19+
protected string SerializeObject(object obj, TypeNameHandling typeNameHandling = TypeNameHandling.None)
20+
{
21+
_jsonSerializerSettings.TypeNameHandling = typeNameHandling;
22+
23+
return JsonConvert.SerializeObject(obj, _jsonSerializerSettings).Replace("\r\n", "\n");
24+
}
25+
26+
protected T DeserializeObject<T>(string json, TypeNameHandling typeNameHandling = TypeNameHandling.None)
27+
{
28+
_jsonSerializerSettings.TypeNameHandling = typeNameHandling;
29+
30+
return JsonConvert.DeserializeObject<T>(json, _jsonSerializerSettings);
31+
}
32+
}
33+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Newtonsoft.Json;
7+
using Newtonsoft.Json.Converters;
8+
using Newtonsoft.Json.Linq;
9+
using Newtonsoft.Json.Serialization;
10+
using Xunit;
11+
12+
namespace UnitsNet.Serialization.JsonNet.Tests
13+
{
14+
public sealed class UnitsNetBaseJsonConverterTest
15+
{
16+
private TestConverter _sut;
17+
18+
public UnitsNetBaseJsonConverterTest()
19+
{
20+
_sut = new TestConverter();
21+
}
22+
23+
[Fact]
24+
public void UnitsNetBaseJsonConverter_ConvertIQuantity_works_as_expected()
25+
{
26+
var result = _sut.Test_ConvertIQuantity(Power.FromWatts(10.2365D));
27+
28+
Assert.Equal("PowerUnit.Watt", result.Unit);
29+
Assert.Equal(10.2365D, result.Value);
30+
}
31+
32+
[Fact]
33+
public void UnitsNetBaseJsonConverter_ConvertIQuantity_throws_ArgumentNullException_when_quantity_is_NULL()
34+
{
35+
var result = Assert.Throws<ArgumentNullException>(() => _sut.Test_ConvertIQuantity(null));
36+
37+
Assert.Equal("Value cannot be null.\r\nParameter name: quantity", result.Message);
38+
}
39+
40+
[Fact]
41+
public void UnitsNetBaseJsonConverter_ConvertValueUnit_works_as_expected()
42+
{
43+
var result = _sut.Test_ConvertValueUnit("PowerUnit.Watt", 10.2365D);
44+
45+
Assert.NotNull(result);
46+
Assert.IsType<Power>(result);
47+
Assert.True(Power.FromWatts(10.2365D).Equals((Power)result, 1E-5, ComparisonType.Absolute));
48+
49+
}
50+
51+
[Fact]
52+
public void UnitsNetBaseJsonConverter_ConvertValueUnit_works_with_NULL_value()
53+
{
54+
var result = _sut.Test_ConvertValueUnit();
55+
56+
Assert.Null(result);
57+
}
58+
59+
[Fact]
60+
public void UnitsNetBaseJsonConverter_ConvertValueUnit_throws_UnitsNetException_when_unit_does_not_exist()
61+
{
62+
var result = Assert.Throws<UnitsNetException>(() => _sut.Test_ConvertValueUnit("SomeImaginaryUnit.Watt", 10.2365D));
63+
64+
Assert.Equal("Unable to find enum type.", result.Message);
65+
Assert.True(result.Data.Contains("type"));
66+
Assert.Equal("UnitsNet.Units.SomeImaginaryUnit,UnitsNet", result.Data["type"]);
67+
}
68+
69+
[Fact]
70+
public void UnitsNetBaseJsonConverter_ConvertValueUnit_throws_UnitsNetException_when_unit_is_in_unexpected_format()
71+
{
72+
var result = Assert.Throws<UnitsNetException>(() => _sut.Test_ConvertValueUnit("PowerUnit Watt", 10.2365D));
73+
74+
Assert.Equal("\"PowerUnit Watt\" is not a valid unit.", result.Message);
75+
Assert.True(result.Data.Contains("type"));
76+
Assert.Equal("PowerUnit Watt", result.Data["type"]);
77+
}
78+
79+
[Fact]
80+
public void UnitsNetBaseJsonConverter_CreateLocalSerializer_works_as_expected()
81+
{
82+
//Possible improvement: Set all possible settings and test each one. But the main goal of CreateLocalSerializer is that the current serializer is left out.
83+
var serializer = JsonSerializer.Create(new JsonSerializerSettings()
84+
{
85+
TypeNameHandling = TypeNameHandling.Arrays,
86+
Converters = new List<JsonConverter>()
87+
{
88+
89+
new BinaryConverter(),
90+
_sut,
91+
new DataTableConverter()
92+
},
93+
ContractResolver = new CamelCasePropertyNamesContractResolver()
94+
});
95+
96+
var result = _sut.Test_CreateLocalSerializer(serializer);
97+
98+
Assert.Equal(TypeNameHandling.Arrays, result.TypeNameHandling);
99+
Assert.Equal(2, result.Converters.Count);
100+
Assert.Collection(result.Converters,
101+
(converter) => Assert.IsType<BinaryConverter>(converter),
102+
(converter) => Assert.IsType<DataTableConverter>(converter));
103+
Assert.IsType<CamelCasePropertyNamesContractResolver>(result.ContractResolver);
104+
}
105+
106+
[Fact]
107+
public void UnitsNetBaseJsonConverter_ReadValueUnit_work_as_expected()
108+
{
109+
var token = new JObject();
110+
111+
token.Add("Unit", "PowerUnit.Watt");
112+
token.Add("Value", 10.2365D);
113+
114+
var result = _sut.Test_ReadValueUnit(token);
115+
116+
Assert.NotNull(result);
117+
Assert.Equal("PowerUnit.Watt", result?.Unit);
118+
Assert.Equal(10.2365D, result?.Value);
119+
}
120+
121+
[Fact]
122+
public void UnitsNetBaseJsonConverter_ReadValueUnit_works_with_empty_token()
123+
{
124+
var token = new JObject();
125+
126+
var result = _sut.Test_ReadValueUnit(token);
127+
128+
Assert.Null(result);
129+
}
130+
131+
[Theory]
132+
[InlineData(false, true)]
133+
[InlineData(true, false)]
134+
public void UnitsNetBaseJsonConverter_ReadValueUnit_returns_null_when_unit_or_value_is_missing(bool withUnit, bool withValue)
135+
{
136+
var token = new JObject();
137+
138+
if (withUnit)
139+
{
140+
token.Add("Unit", "PowerUnit.Watt");
141+
}
142+
143+
if (withValue)
144+
{
145+
token.Add("Value", 10.2365D);
146+
}
147+
148+
var result = _sut.Test_ReadValueUnit(token);
149+
150+
Assert.Null(result);
151+
}
152+
153+
[Theory]
154+
[InlineData("Unit", "Value")]
155+
[InlineData("unit", "Value")]
156+
[InlineData("Unit", "value")]
157+
[InlineData("unit", "value")]
158+
[InlineData("unIT", "vAlUe")]
159+
public void UnitsNetBaseJsonConverter_ReadValueUnit_works_case_insensitive(string unitPropertyName, string valuePropertyName)
160+
{
161+
var token = new JObject();
162+
163+
token.Add(unitPropertyName, "PowerUnit.Watt");
164+
token.Add(valuePropertyName, 10.2365D);
165+
166+
var result = _sut.Test_ReadValueUnit(token);
167+
168+
Assert.NotNull(result);
169+
Assert.Equal("PowerUnit.Watt", result?.Unit);
170+
Assert.Equal(10.2365D, result?.Value);
171+
}
172+
173+
/// <summary>
174+
/// Dummy converter, used to access protected methods on abstract UnitsNetBaseJsonConverter{T}
175+
/// </summary>
176+
private class TestConverter : UnitsNetBaseJsonConverter<string>
177+
{
178+
public override bool CanRead => false;
179+
public override bool CanWrite => false;
180+
public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer) => throw new NotImplementedException();
181+
public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException();
182+
183+
public (string Unit, double Value) Test_ConvertIQuantity(IQuantity value)
184+
{
185+
var result = ConvertIQuantity(value);
186+
187+
return (result.Unit, result.Value);
188+
}
189+
190+
public IQuantity Test_ConvertValueUnit(string unit, double value) => Test_ConvertValueUnit(new ValueUnit() {Unit = unit, Value = value});
191+
public IQuantity Test_ConvertValueUnit() => Test_ConvertValueUnit(null);
192+
private IQuantity Test_ConvertValueUnit(ValueUnit valueUnit) => ConvertValueUnit(valueUnit);
193+
194+
public JsonSerializer Test_CreateLocalSerializer(JsonSerializer serializer) => CreateLocalSerializer(serializer, this);
195+
196+
public (string Unit, double Value)? Test_ReadValueUnit(JToken jsonToken)
197+
{
198+
var result = ReadValueUnit(jsonToken);
199+
200+
if (result == null)
201+
{
202+
return null;
203+
}
204+
205+
return (result.Unit, result.Value);
206+
}
207+
}
208+
}
209+
}

0 commit comments

Comments
 (0)