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);
}