diff --git a/RedStar.Amounts.JsonNet.Tests/Properties/AssemblyInfo.cs b/RedStar.Amounts.JsonNet.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a338221 --- /dev/null +++ b/RedStar.Amounts.JsonNet.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RedStar.Amounts.JsonNet.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("RedStar.Amounts.JsonNet.Tests")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c707879a-6e92-4ab2-be60-2b8285cd3a89")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/RedStar.Amounts.JsonNet.Tests/RedStar.Amounts.JsonNet.Tests.csproj b/RedStar.Amounts.JsonNet.Tests/RedStar.Amounts.JsonNet.Tests.csproj new file mode 100644 index 0000000..f6f06b0 --- /dev/null +++ b/RedStar.Amounts.JsonNet.Tests/RedStar.Amounts.JsonNet.Tests.csproj @@ -0,0 +1,98 @@ + + + + + + Debug + AnyCPU + {ECC089C3-8167-4C25-8E9D-F76B1ED63799} + Library + Properties + RedStar.Amounts.JsonNet.Tests + RedStar.Amounts.JsonNet.Tests + v4.5.1 + 512 + 97d30ad2 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll + True + + + ..\packages\xunit.assert.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.assert.dll + True + + + ..\packages\xunit.extensibility.core.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.core.dll + True + + + ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll + True + + + + + + + + + + + + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2} + RedStar.Amounts.JsonNet + + + {B3EEAF5A-75DC-4C91-8BDB-C3E9A01B9E98} + RedStar.Amounts.StandardUnits + + + {961A7DCF-6242-41D5-A5B9-6195057C80D4} + RedStar.Amounts + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/RedStar.Amounts.JsonNet.Tests/StringAmountJsonConverterTests.cs b/RedStar.Amounts.JsonNet.Tests/StringAmountJsonConverterTests.cs new file mode 100644 index 0000000..7f4a25b --- /dev/null +++ b/RedStar.Amounts.JsonNet.Tests/StringAmountJsonConverterTests.cs @@ -0,0 +1,134 @@ +using System.Globalization; +using Newtonsoft.Json; +using RedStar.Amounts.StandardUnits; +using Xunit; + +namespace RedStar.Amounts.JsonNet.Tests +{ + public class StringAmountJsonConverterTests + { + private readonly JsonSerializerSettings _settings; + + public StringAmountJsonConverterTests() + { + UnitManager.RegisterByAssembly(typeof(LengthUnits).Assembly); + + _settings = new JsonSerializerSettings + { + Culture = new CultureInfo("en"), + Converters = new JsonConverter[] + { + new StringAmountJsonConverter() + } + }; + } + + [Fact] + public void WhenConvertingAmount_ReturnString() + { + var amount = new Amount(30, MassUnits.KiloGram); + + var result = JsonConvert.SerializeObject(amount, _settings); + + Assert.Equal("\"30 Kg\"", result); + } + + [Fact] + public void WhenConvertingNull_ReturnNull() + { + var result = JsonConvert.SerializeObject(null, _settings); + + Assert.Equal("null", result); + } + + [Fact] + public void WhenConvertingJson_ReturnAmount() + { + var json = "\"3.4 Kg\""; + + var result = JsonConvert.DeserializeObject(json, _settings); + + Assert.Equal(new Amount(3.4, MassUnits.KiloGram), result); + } + + [Fact] + public void WhenConvertingNullJson_ReturnNull() + { + var json = "null"; + + var result = JsonConvert.DeserializeObject(json, _settings); + + Assert.Null(result); + } + + [Fact] + public void WhenConvertingCalculatedUnit_ReturnAmount() + { + var expected = new Amount(3.4, VolumeUnits.Meter3 / TimeUnits.Hour); + var json = "\"3.4 m³/h\""; + + var actual = JsonConvert.DeserializeObject(json, _settings); + + Assert.Equal(expected, actual); + } + + [Fact] + public void WhenConvertingMultipleTimes_KeepValuesConsistent() + { + var amount = new Amount(0, TemperatureUnits.DegreeCelcius / TimeUnits.Second); + + for (var i = 0; i < 10; i++) + { + var json = JsonConvert.SerializeObject(amount, _settings); + amount = JsonConvert.DeserializeObject(json, _settings); + + Assert.Equal("\"0 °C/s\"", json); + Assert.Equal(new Amount(0, TemperatureUnits.DegreeCelcius / TimeUnits.Second), amount); + } + } + + [Fact] + public void WhenConvertingComplexCalculatedUnit_ReturnAMount() + { + var jsonString = "\"0.003 GJ/10*Kg\""; + var expectedAmount = new Amount(0.003, EnergyUnits.GigaJoule / 10 * MassUnits.KiloGram); + + var actualAmount = JsonConvert.DeserializeObject(jsonString, _settings); + Assert.Equal(expectedAmount, actualAmount); + } + + [Fact] + public void WhenConvertingComplexCalculatedUnit_ReturnJson() + { + var expectedJsonString = "\"0.003 GJ/10*Kg\""; + var amount = new Amount(0.003, EnergyUnits.GigaJoule / 10 * MassUnits.KiloGram); + + var actualJsonString = JsonConvert.SerializeObject(amount, _settings); + Assert.Equal(expectedJsonString, actualJsonString); + } + + [Fact] + public void WhenConvertingNullProperty_ReturnJson() + { + var obj = new MyClass(); + var expectedJsonString = "{\"MyProperty\":null}"; + + var actualJsonString = JsonConvert.SerializeObject(obj, _settings); + Assert.Equal(expectedJsonString, actualJsonString); + } + + [Fact] + public void WhenConvertingNullJson_ReturnObjectWithNullProperty() + { + var jsonString = "{\"MyProperty\":null}"; + + var newObj = JsonConvert.DeserializeObject(jsonString, _settings); + Assert.Null(newObj.MyProperty); + } + + private class MyClass + { + public Amount MyProperty { get; set; } + } + } +} diff --git a/RedStar.Amounts.JsonNet.Tests/packages.config b/RedStar.Amounts.JsonNet.Tests/packages.config new file mode 100644 index 0000000..1e25e08 --- /dev/null +++ b/RedStar.Amounts.JsonNet.Tests/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/RedStar.Amounts.JsonNet/Properties/AssemblyInfo.cs b/RedStar.Amounts.JsonNet/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..35bf469 --- /dev/null +++ b/RedStar.Amounts.JsonNet/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RedStar.Amounts.JsonNet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("RedStar.Amounts.JsonNet")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c62c3ce1-36b4-419f-ac35-8a4553ced732")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/RedStar.Amounts.JsonNet/RedStar.Amounts.JsonNet.csproj b/RedStar.Amounts.JsonNet/RedStar.Amounts.JsonNet.csproj new file mode 100644 index 0000000..afb486c --- /dev/null +++ b/RedStar.Amounts.JsonNet/RedStar.Amounts.JsonNet.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2} + Library + Properties + RedStar.Amounts.JsonNet + RedStar.Amounts.JsonNet + v4.5.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + + + + + + + + + {961A7DCF-6242-41D5-A5B9-6195057C80D4} + RedStar.Amounts + + + + + \ No newline at end of file diff --git a/RedStar.Amounts.JsonNet/StringAmountJsonConverter.cs b/RedStar.Amounts.JsonNet/StringAmountJsonConverter.cs new file mode 100644 index 0000000..b2f744b --- /dev/null +++ b/RedStar.Amounts.JsonNet/StringAmountJsonConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace RedStar.Amounts.JsonNet +{ + /// + /// Converts an Amount from and to a string. + /// + public class StringAmountJsonConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var amount = value as Amount; + + writer.WriteRawValue("\"" + amount.ToString(serializer.Culture) + "\""); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.Value == null) + return null; + + var json = reader.Value.ToString(); + + try + { + return Amount.Parse(json, serializer.Culture); + } + catch (Exception ex) + { + throw new SerializationException("Failed to deserialize " + json + " at " + reader.Path + ".", ex); + } + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Amount); + } + } +} diff --git a/RedStar.Amounts.JsonNet/packages.config b/RedStar.Amounts.JsonNet/packages.config new file mode 100644 index 0000000..db67311 --- /dev/null +++ b/RedStar.Amounts.JsonNet/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/RedStar.Amounts.Tests/AmountTests.cs b/RedStar.Amounts.Tests/AmountTests.cs index da251f7..89c7c48 100644 --- a/RedStar.Amounts.Tests/AmountTests.cs +++ b/RedStar.Amounts.Tests/AmountTests.cs @@ -11,22 +11,13 @@ namespace RedStar.Amounts.Tests { - public class AmountTests : IDisposable + public class AmountTests { - private readonly UnitManager _defaultUnitManager; - public AmountTests() { - _defaultUnitManager = UnitManager.Instance; - UnitManager.Instance = new UnitManager(); UnitManager.RegisterByAssembly(typeof(LengthUnits).Assembly); } - public void Dispose() - { - UnitManager.Instance = _defaultUnitManager; - } - [Fact] public void Construction01Test() { diff --git a/RedStar.Amounts.Tests/UnitTests.cs b/RedStar.Amounts.Tests/UnitTests.cs index 58792c0..c4af6bf 100644 --- a/RedStar.Amounts.Tests/UnitTests.cs +++ b/RedStar.Amounts.Tests/UnitTests.cs @@ -4,22 +4,13 @@ namespace RedStar.Amounts.Tests { - public class UnitTests : IDisposable + public class UnitTests { - private readonly UnitManager _defaultUnitManager; - public UnitTests() { - _defaultUnitManager = UnitManager.Instance; - UnitManager.Instance = new UnitManager(); UnitManager.RegisterByAssembly(typeof(LengthUnits).Assembly); } - public void Dispose() - { - UnitManager.Instance = _defaultUnitManager; - } - [Fact] public void UnitParseTestWithSimpleUnits() { diff --git a/RedStar.Amounts.sln b/RedStar.Amounts.sln index d89528e..18871aa 100644 --- a/RedStar.Amounts.sln +++ b/RedStar.Amounts.sln @@ -11,6 +11,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedStar.Amounts.Tests", "Re EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedStar.Amounts.StandardUnits.Tests", "RedStar.Amounts.StandardUnits.Tests\RedStar.Amounts.StandardUnits.Tests.csproj", "{3837C3CA-4D5A-4988-8928-44557712738D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedStar.Amounts.JsonNet", "RedStar.Amounts.JsonNet\RedStar.Amounts.JsonNet.csproj", "{A05B6FC6-465F-408D-ADFA-4A5B14A572B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedStar.Amounts.JsonNet.Tests", "RedStar.Amounts.JsonNet.Tests\RedStar.Amounts.JsonNet.Tests.csproj", "{ECC089C3-8167-4C25-8E9D-F76B1ED63799}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +37,14 @@ Global {3837C3CA-4D5A-4988-8928-44557712738D}.Debug|Any CPU.Build.0 = Debug|Any CPU {3837C3CA-4D5A-4988-8928-44557712738D}.Release|Any CPU.ActiveCfg = Release|Any CPU {3837C3CA-4D5A-4988-8928-44557712738D}.Release|Any CPU.Build.0 = Release|Any CPU + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A05B6FC6-465F-408D-ADFA-4A5B14A572B2}.Release|Any CPU.Build.0 = Release|Any CPU + {ECC089C3-8167-4C25-8E9D-F76B1ED63799}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECC089C3-8167-4C25-8E9D-F76B1ED63799}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECC089C3-8167-4C25-8E9D-F76B1ED63799}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECC089C3-8167-4C25-8E9D-F76B1ED63799}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RedStar.Amounts/Unit.cs b/RedStar.Amounts/Unit.cs index 8365502..877f1dd 100644 --- a/RedStar.Amounts/Unit.cs +++ b/RedStar.Amounts/Unit.cs @@ -255,6 +255,11 @@ internal static string SanitizeUnitString(string s) public static Unit operator *(double left, Unit right) { + if (left == 1) + { + return right; + } + right = right ?? _none; return new Unit(string.Concat('(', left.ToString(), '*', right._name, ')'), left.ToString() + '*' + right._symbol, left * right._factor, right._unitType, false); }