From fba61c2c85f36aa6ff4ff669ef6ba357a6e215dc Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Sun, 17 Mar 2019 00:08:19 +0100 Subject: [PATCH 01/12] Initial implementation of UnitsNetTypeConverter --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 264 ++++++++++++++++++++ UnitsNet/QuantityTypeConverter.cs | 205 +++++++++++++++ 2 files changed, 469 insertions(+) create mode 100644 UnitsNet.Tests/QuantityTypeConverterTest.cs create mode 100644 UnitsNet/QuantityTypeConverter.cs diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs new file mode 100644 index 0000000000..1da303f808 --- /dev/null +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Reflection; +using System.Text; +using UnitsNet; +using Xunit; + +namespace UnitsNet.Tests +{ + public class QuantityTypeConverterTest + { + // https://stackoverflow.com/questions/3612909/why-is-this-typeconverter-not-working + private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + AppDomain domain = (AppDomain)sender; + foreach (Assembly asm in domain.GetAssemblies()) + { + if (asm.FullName == args.Name) + { + return asm; + } + } + return null; + } + + static QuantityTypeConverterTest() + { + // NOTE: After this, you can use your typeconverter. + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); + } + + static CultureInfo culture = CultureInfo.GetCultureInfo("en-US"); + + public class TypeDescriptorContext : ITypeDescriptorContext + { + public class PropertyDescriptor_ : PropertyDescriptor + { + public PropertyDescriptor_(string name, Attribute[] attributes) : base(name, attributes) + { + + } + + public override Type ComponentType => throw new NotImplementedException(); + + public override bool IsReadOnly => throw new NotImplementedException(); + + public override Type PropertyType => throw new NotImplementedException(); + + public override bool CanResetValue(object component) + { + throw new NotImplementedException(); + } + + public override object GetValue(object component) + { + throw new NotImplementedException(); + } + + public override void ResetValue(object component) + { + throw new NotImplementedException(); + } + + public override void SetValue(object component, object value) + { + throw new NotImplementedException(); + } + + public override bool ShouldSerializeValue(object component) + { + throw new NotImplementedException(); + } + } + + public TypeDescriptorContext(string name, Attribute[] attributes) + { + PropertyDescriptor = new PropertyDescriptor_(name, attributes); + } + + public IContainer Container => throw new NotImplementedException(); + + public object Instance => throw new NotImplementedException(); + + public PropertyDescriptor PropertyDescriptor { get; set; } + + public object GetService(Type serviceType) + { + throw new NotImplementedException(); + } + + public void OnComponentChanged() + { + throw new NotImplementedException(); + } + + public bool OnComponentChanging() + { + throw new NotImplementedException(); + } + } + + [Theory] + [InlineData(typeof(string))] + public void CanConvertFrom_GiveSomeTypes_ReturnsTrue(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + + Assert.True(unitsNETTypeConverter.CanConvertFrom(value)); + } + + [Theory] + [InlineData(typeof(double))] + [InlineData(typeof(object))] + [InlineData(typeof(float))] + [InlineData(typeof(Length))] + public void CanConvertFrom_GiveSomeTypes_ReturnsFalse(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + + Assert.False(unitsNETTypeConverter.CanConvertFrom(value)); + } + + [Theory] + [InlineData(typeof(string))] + public void CanConvertTo_GiveSomeTypes_ReturnsTrue(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + + Assert.True(unitsNETTypeConverter.CanConvertTo(value)); + } + + [Theory] + [InlineData(typeof(double))] + [InlineData(typeof(object))] + [InlineData(typeof(float))] + [InlineData(typeof(Length))] + public void CanConvertTo_GiveSomeTypes_ReturnsFalse(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + + Assert.False(unitsNETTypeConverter.CanConvertTo(value)); + } + + [Fact] + public void ConvertFrom_GiveSomeStrings() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(Length.FromMillimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); + Assert.Equal(Length.FromKilometers(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter) }); + + Assert.Equal(Length.FromMillimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); + Assert.Equal(Length.FromCentimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); + Assert.Equal(Length.FromKilometers(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DefaultUnitAttribute(Units.LengthUnit.Centimeter), + new ConvertToUnitAttribute(Units.LengthUnit.Meter) + }); + + Assert.Equal(Length.FromMeters(0.001), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); + Assert.Equal(Length.FromMeters(0.01), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); + Assert.Equal(Length.FromMeters(1000), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); + } + + [Fact] + public void ConvertFrom_GiveEmpyString() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "")); + } + + [Fact] + public void ConvertFrom_GiveWrongQuantity() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1m^2")); + } + + [Fact] + public void WrongUnitTypeInAttribut_DefaultUnit() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter) }); + + Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_1() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); + Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^1")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_2() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(Area.FromSquareMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m²")); + Assert.Equal(Area.FromSquareMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^2")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_3() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(Volume.FromCubicMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m³")); + Assert.Equal(Volume.FromCubicMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^3")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_4() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m⁴")); + Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^4")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_minus1() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1K⁻¹")); + Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1K^-1")); + } + + [Fact] + public void ConvertFrom_GiveStringWithPower_minus2() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg·s⁻¹·m⁻²")); + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg·s^-1·m^-2")); + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg*s^-1*m^-2")); + } + } +} diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs new file mode 100644 index 0000000000..7873da5dfd --- /dev/null +++ b/UnitsNet/QuantityTypeConverter.cs @@ -0,0 +1,205 @@ +// Licensed under MIT No Attribution, see LICENSE file at the root. +// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet. + +using System; +using System.ComponentModel; +using System.Globalization; +using System.Runtime.CompilerServices; + +namespace UnitsNet +{ + /// + /// Is the base class for all attributes that are related to + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public abstract class UnitAttributeBase : Attribute + { + /// + /// This property hold the UnitType information + /// + public Enum UnitType { get; set; } + + /// + /// Constructor of this class + /// + /// + public UnitAttributeBase(object unitType) + { + UnitType = unitType as Enum; + } + } + + /// + /// This attribute defines the default Unit to use. It is only used when the string only consists of digits + /// + public class DefaultUnitAttribute : UnitAttributeBase + { + /// + /// Constructor for ConvertToUnit attribute + /// + /// The unit the quantity gets when the string parsing dose only consist of digits + public DefaultUnitAttribute(object unitType) : base(unitType) { } + } + + /// + /// This attribute defines the Unit the quantity is converted to after it has been parsed. + /// + public class ConvertToUnitAttribute : DefaultUnitAttribute + { + /// + /// Constructor for ConvertToUnit attribute + /// + /// The unit the quantity is converted to when parsing from string + public ConvertToUnitAttribute(object unitType) : base(unitType) { } + } + + /// + /// This attribute defines the unit the quantity has when converting to string + /// + public class DisplayAsUnitAttribute : DefaultUnitAttribute + { + /// + /// The formating used when the quantity is converted to string + /// + public string Format { get; set; } + + /// + /// Constructor for DisplayAsUnit attribute + /// + /// The unit the quantity should be displayed in + /// Formating string + public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitType) { Format = format; } + } + + /// + /// Converts IQuantitys from string and to string. + /// Implements the TypeConverter interface so that eg the PropertyGrid can read and write the properties implementing the IQuantity interface. + /// + /// Quantity value type, such as or . + public class UnitsNetTypeConverter : TypeConverter where TQuantity : IQuantity + { + /// + /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. + /// + /// An System.ComponentModel.ITypeDescriptorContext that provides a format context. + /// A System.Type that represents the type you want to convert from. + /// true if this converter can perform the conversion; otherwise, false. + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return (sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType); + } + + private static TAttribute GetAttribute(ITypeDescriptorContext context) where TAttribute : UnitAttributeBase + { + TAttribute attribute = null; + AttributeCollection ua = context?.PropertyDescriptor.Attributes; + + attribute = (TAttribute)ua?[typeof(TAttribute)]; + + if(attribute != null) + { + QuantityType expected = default(TQuantity).Type; + QuantityType actual = Quantity.From(1, attribute.UnitType).Type; + if(expected != actual) + { + throw new InvalidOperationException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'"); + } + } + + return attribute; + } + + /// + /// Converts the given object to the type of this converter, using the specified context and culture information. + /// + /// An System.ComponentModel.ITypeDescriptorContext that provides a format context. + /// The System.Globalization.CultureInfo to use as the current culture. + /// The System.Object to convert. + /// An object. + /// The conversion cannot be performed. + /// Unit value is not a know unit enum type. + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + string stringValue = value as string; + object result = null; + + if (!string.IsNullOrEmpty(stringValue)) + { + if (double.TryParse(stringValue, NumberStyles.Any, culture, out double dvalue)) + { + DefaultUnitAttribute defaultUnit = GetAttribute(context) ?? new DefaultUnitAttribute(default(TQuantity).Unit); + + result = Quantity.From(dvalue, defaultUnit.UnitType); + } + else + { + // this should not be part of QuantityTypeConverter. it should rather be part of the parse function + stringValue = stringValue.Replace("^-9", "⁻⁹"); + stringValue = stringValue.Replace("^-8", "⁻⁸"); + stringValue = stringValue.Replace("^-7", "⁻⁷"); + stringValue = stringValue.Replace("^-6", "⁻⁶"); + stringValue = stringValue.Replace("^-5", "⁻⁵"); + stringValue = stringValue.Replace("^-4", "⁻⁴"); + stringValue = stringValue.Replace("^-3", "⁻³"); + stringValue = stringValue.Replace("^-2", "⁻²"); + stringValue = stringValue.Replace("^-1", "⁻¹"); + stringValue = stringValue.Replace("^1", ""); + stringValue = stringValue.Replace("^2", "²"); + stringValue = stringValue.Replace("^3", "³"); + stringValue = stringValue.Replace("^4", "⁴"); + stringValue = stringValue.Replace("^5", "⁵"); + stringValue = stringValue.Replace("^6", "⁶"); + stringValue = stringValue.Replace("^7", "⁷"); + stringValue = stringValue.Replace("^8", "⁸"); + stringValue = stringValue.Replace("^9", "⁹"); + stringValue = stringValue.Replace("*", "·"); + + result = Quantity.Parse(culture, typeof(TQuantity), stringValue); + } + + ConvertToUnitAttribute convertToUnit = GetAttribute(context); + if (convertToUnit != null) + { + result = ((IQuantity)result).ToUnit(convertToUnit.UnitType); + } + } + + return result ?? base.ConvertFrom(context, culture, value); + } + + /// Returns whether this converter can convert the object to the specified type, using the specified context. + /// true if this converter can perform the conversion; otherwise, false. + /// An that provides a format context. + /// A that represents the type you want to convert to. + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType); + } + + /// Converts the given value object to the specified type, using the specified context and culture information. + /// An that represents the converted value. + /// An that provides a format context. + /// A . If null is passed, the current culture is assumed. + /// The to convert. + /// The to convert the parameter to. + /// The parameter is null. + /// The conversion cannot be performed. + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + IQuantity qvalue = value as IQuantity; + object result = null; + DisplayAsUnitAttribute displayAsUnit = GetAttribute(context); + + if (destinationType == typeof(string) && qvalue != null && displayAsUnit != null) + { + result = qvalue.ToUnit(displayAsUnit.UnitType).ToString(displayAsUnit.Format, culture); + } + else + { + result = base.ConvertTo(context, culture, value, destinationType); + } + + return result; + } + } +} From 851b335512895041561b2cecb76f58ef5855c670 Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Sun, 17 Mar 2019 00:53:35 +0100 Subject: [PATCH 02/12] Added testcase for ConvertTo --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 86 ++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 1da303f808..8a63f40623 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -1,4 +1,7 @@ -using System; +// Licensed under MIT No Attribution, see LICENSE file at the root. +// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet. + +using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; @@ -191,6 +194,83 @@ public void ConvertFrom_GiveWrongQuantity() Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1m^2")); } + [Theory] + [InlineData(typeof(Length))] + [InlineData(typeof(IQuantity))] + [InlineData(typeof(object))] + public void ConvertTo_GiveWrongType_ThrowException(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + Length length = Length.FromMeters(1); + + Assert.Throws(() => unitsNETTypeConverter.ConvertTo(length, value)); + } + + [Theory] + [InlineData(typeof(string))] + public void ConvertTo_GiveRigthType_DoConvertion(Type value) + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + Length length = Length.FromMeters(1); + + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, value)); + } + + [Fact] + public void ConvertTo_GiveSomeValues_ConvertToString() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + Length length = Length.FromMeters(1); + + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DefaultUnitAttribute(Units.LengthUnit.Centimeter), + new ConvertToUnitAttribute(Units.LengthUnit.Millimeter) + }); + + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DefaultUnitAttribute(Units.LengthUnit.Centimeter), + new ConvertToUnitAttribute(Units.LengthUnit.Millimeter), + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) + }); + + Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); + Assert.Equal("10 dm", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + } + + [Fact] + public void ConvertTo_TestDisplayAsFormating_ConvertToFormatedString() + { + UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); + Length length = Length.FromMeters(1); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) + }); + + Assert.Equal("10 dm", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + + context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") + }); + + Assert.Equal("10", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + } + + [Fact] public void WrongUnitTypeInAttribut_DefaultUnit() { @@ -200,6 +280,10 @@ public void WrongUnitTypeInAttribut_DefaultUnit() Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1")); } + + + + [Fact] public void ConvertFrom_GiveStringWithPower_1() { From 7398eed244f1287f24bb54b4ffe6e288438e680a Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Thu, 18 Apr 2019 23:34:07 +0200 Subject: [PATCH 03/12] Reworked test cases Improved XMLdoc --- .../Helpers/TypeDescriptorContext.cs | 78 +++++ UnitsNet.Tests/QuantityTypeConverterTest.cs | 309 ++++++++---------- UnitsNet/QuantityTypeConverter.cs | 31 +- 3 files changed, 231 insertions(+), 187 deletions(-) create mode 100644 UnitsNet.Tests/Helpers/TypeDescriptorContext.cs diff --git a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs new file mode 100644 index 0000000000..73928e12f8 --- /dev/null +++ b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace UnitsNet.Tests.Helpers +{ + /// + /// Is used to imitate e property with attributes + /// + public class TypeDescriptorContext : ITypeDescriptorContext + { + public class PropertyDescriptor_ : PropertyDescriptor + { + public PropertyDescriptor_(string name, Attribute[] attributes) : base(name, attributes) + { + + } + + public override Type ComponentType => throw new NotImplementedException(); + + public override bool IsReadOnly => throw new NotImplementedException(); + + public override Type PropertyType => throw new NotImplementedException(); + + public override bool CanResetValue(object component) + { + throw new NotImplementedException(); + } + + public override object GetValue(object component) + { + throw new NotImplementedException(); + } + + public override void ResetValue(object component) + { + throw new NotImplementedException(); + } + + public override void SetValue(object component, object value) + { + throw new NotImplementedException(); + } + + public override bool ShouldSerializeValue(object component) + { + throw new NotImplementedException(); + } + } + + public TypeDescriptorContext(string name, Attribute[] attributes) + { + PropertyDescriptor = new PropertyDescriptor_(name, attributes); + } + + public IContainer Container => throw new NotImplementedException(); + + public object Instance => throw new NotImplementedException(); + + public PropertyDescriptor PropertyDescriptor { get; set; } + + public object GetService(Type serviceType) + { + throw new NotImplementedException(); + } + + public void OnComponentChanged() + { + throw new NotImplementedException(); + } + + public bool OnComponentChanging() + { + throw new NotImplementedException(); + } + } +} diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 8a63f40623..d670653a8c 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Text; using UnitsNet; +using UnitsNet.Tests.Helpers; using Xunit; namespace UnitsNet.Tests @@ -34,315 +35,269 @@ static QuantityTypeConverterTest() AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); } + /// + /// Is used for tests that are culture dependent + /// static CultureInfo culture = CultureInfo.GetCultureInfo("en-US"); - public class TypeDescriptorContext : ITypeDescriptorContext - { - public class PropertyDescriptor_ : PropertyDescriptor - { - public PropertyDescriptor_(string name, Attribute[] attributes) : base(name, attributes) - { - - } - - public override Type ComponentType => throw new NotImplementedException(); - - public override bool IsReadOnly => throw new NotImplementedException(); - - public override Type PropertyType => throw new NotImplementedException(); - - public override bool CanResetValue(object component) - { - throw new NotImplementedException(); - } - - public override object GetValue(object component) - { - throw new NotImplementedException(); - } - - public override void ResetValue(object component) - { - throw new NotImplementedException(); - } - - public override void SetValue(object component, object value) - { - throw new NotImplementedException(); - } - - public override bool ShouldSerializeValue(object component) - { - throw new NotImplementedException(); - } - } - - public TypeDescriptorContext(string name, Attribute[] attributes) - { - PropertyDescriptor = new PropertyDescriptor_(name, attributes); - } - - public IContainer Container => throw new NotImplementedException(); - - public object Instance => throw new NotImplementedException(); - - public PropertyDescriptor PropertyDescriptor { get; set; } - - public object GetService(Type serviceType) - { - throw new NotImplementedException(); - } - - public void OnComponentChanged() - { - throw new NotImplementedException(); - } - - public bool OnComponentChanging() - { - throw new NotImplementedException(); - } - } - [Theory] - [InlineData(typeof(string))] - public void CanConvertFrom_GiveSomeTypes_ReturnsTrue(Type value) + [InlineData(typeof(string), true)] + [InlineData(typeof(double), false)] + [InlineData(typeof(object), false)] + [InlineData(typeof(float), false)] + [InlineData(typeof(Length), false)] + public void CanConvertFrom_GivenSomeTypes(Type value, bool expectedResult) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); - Assert.True(unitsNETTypeConverter.CanConvertFrom(value)); + Assert.True(converter.CanConvertFrom(value) == expectedResult); } [Theory] - [InlineData(typeof(double))] - [InlineData(typeof(object))] - [InlineData(typeof(float))] - [InlineData(typeof(Length))] - public void CanConvertFrom_GiveSomeTypes_ReturnsFalse(Type value) + [InlineData(typeof(string), true)] + [InlineData(typeof(double), false)] + [InlineData(typeof(object), false)] + [InlineData(typeof(float), false)] + [InlineData(typeof(Length), false)] + public void CanConvertTo_GivenSomeTypes(Type value, bool expectedResult) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); - Assert.False(unitsNETTypeConverter.CanConvertFrom(value)); + Assert.True(converter.CanConvertTo(value) == expectedResult); } [Theory] - [InlineData(typeof(string))] - public void CanConvertTo_GiveSomeTypes_ReturnsTrue(Type value) + [InlineData("1mm", 1, Units.LengthUnit.Millimeter)] + [InlineData("1m", 1, Units.LengthUnit.Meter)] + [InlineData("1", 1, Units.LengthUnit.Meter)] + [InlineData("1km", 1, Units.LengthUnit.Kilometer)] + public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQuantityWithBaseUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.True(unitsNETTypeConverter.CanConvertTo(value)); + var convertedValue = (Length)converter.ConvertFrom(context, culture, str); + + Assert.Equal(convertedValue.Value, expectedValue); + Assert.Equal(convertedValue.Unit, expectedUnit); } [Theory] - [InlineData(typeof(double))] - [InlineData(typeof(object))] - [InlineData(typeof(float))] - [InlineData(typeof(Length))] - public void CanConvertTo_GiveSomeTypes_ReturnsFalse(Type value) + [InlineData("1mm", 1, Units.LengthUnit.Millimeter)] + [InlineData("1m", 1, Units.LengthUnit.Meter)] + [InlineData("1", 1, Units.LengthUnit.Centimeter)] + [InlineData("1km", 1, Units.LengthUnit.Kilometer)] + public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAttribute_ReturnsQuantityWithGivenDefaultUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter) }); - Assert.False(unitsNETTypeConverter.CanConvertTo(value)); + var convertedValue = (Length)converter.ConvertFrom(context, culture, str); + + Assert.Equal(convertedValue.Value, expectedValue); + Assert.Equal(convertedValue.Unit, expectedUnit); } - [Fact] - public void ConvertFrom_GiveSomeStrings() + [Theory] + [InlineData("1mm", 0.001, Units.LengthUnit.Meter)] + [InlineData("1m", 1, Units.LengthUnit.Meter)] + [InlineData("1", 0.01, Units.LengthUnit.Meter)] + [InlineData("1km", 1000, Units.LengthUnit.Meter)] + public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertToUnitAttributes_ReturnsQuantityConvertedToUnit(string str, double expectedValue, Enum expectedUnit) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); - ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - - Assert.Equal(Length.FromMillimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); - Assert.Equal(Length.FromKilometers(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); - - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter) }); - - Assert.Equal(Length.FromMillimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); - Assert.Equal(Length.FromCentimeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); - Assert.Equal(Length.FromKilometers(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); - - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter), new ConvertToUnitAttribute(Units.LengthUnit.Meter) }); - Assert.Equal(Length.FromMeters(0.001), unitsNETTypeConverter.ConvertFrom(context, culture, "1mm")); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); - Assert.Equal(Length.FromMeters(0.01), unitsNETTypeConverter.ConvertFrom(context, culture, "1")); - Assert.Equal(Length.FromMeters(1000), unitsNETTypeConverter.ConvertFrom(context, culture, "1km")); + var convertedValue = (Length)converter.ConvertFrom(context, culture, str); + + Assert.Equal(convertedValue.Value, expectedValue); + Assert.Equal(convertedValue.Unit, expectedUnit); } [Fact] - public void ConvertFrom_GiveEmpyString() + public void ConvertFrom_GivenEmpyString_ThrowsNotSupportedException() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "")); + Assert.Throws(() => converter.ConvertFrom(context, culture, "")); } [Fact] - public void ConvertFrom_GiveWrongQuantity() + public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1m^2")); + Assert.Throws(() => converter.ConvertFrom(context, culture, "1m^2")); } [Theory] [InlineData(typeof(Length))] [InlineData(typeof(IQuantity))] [InlineData(typeof(object))] - public void ConvertTo_GiveWrongType_ThrowException(Type value) + public void ConvertTo_GivenWrongType_ThrowsExceptionNotSupportedException(Type value) { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); - Assert.Throws(() => unitsNETTypeConverter.ConvertTo(length, value)); + Assert.Throws(() => converter.ConvertTo(length, value)); } - [Theory] - [InlineData(typeof(string))] - public void ConvertTo_GiveRigthType_DoConvertion(Type value) + [Fact] + public void ConvertTo_GivenStringType_ReturnsQuantityString() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, value)); + Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); } [Fact] - public void ConvertTo_GiveSomeValues_ConvertToString() + public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuantityStringInUnitOfQuantity() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); + Assert.Equal("1 m", converter.ConvertTo(context, culture, length, typeof(string))); + } - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + [Fact] + public void ConvertTo_GivenSomeQuantitysAndContextWithDefaultUnitAndConvertToUnitAttributes_ReturnsQuantityStringInUnitOfQuantity() + { + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter), new ConvertToUnitAttribute(Units.LengthUnit.Millimeter) }); + Length length = Length.FromMeters(1); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); + Assert.Equal("1 m", converter.ConvertTo(context, culture, length, typeof(string))); + } - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + [Fact] + public void ConvertTo_GivenSomeQuantitysAndContextWithDefaultUnitAndConvertToUnitAndDisplayAsUnitAttributes_ReturnsQuantityStringInSpecifiedDisplayUnit() + { + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter), new ConvertToUnitAttribute(Units.LengthUnit.Millimeter), new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); - Assert.Equal("1 m", unitsNETTypeConverter.ConvertTo(length, typeof(string))); - Assert.Equal("10 dm", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + Length length = Length.FromMeters(1); + + Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); + Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); } [Fact] - public void ConvertTo_TestDisplayAsFormating_ConvertToFormatedString() + public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitDefaultFormating() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); - ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Length length = Length.FromMeters(1); - - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); - Assert.Equal("10 dm", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); + Length length = Length.FromMeters(1); + + Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); + } - context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + [Fact] + public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitFormateAsValueOnly() + { + var converter = new UnitsNetTypeConverter(); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") }); - Assert.Equal("10", unitsNETTypeConverter.ConvertTo(context, culture, length, typeof(string))); - } + Length length = Length.FromMeters(1); + Assert.Equal("10", converter.ConvertTo(context, culture, length, typeof(string))); + } [Fact] public void WrongUnitTypeInAttribut_DefaultUnit() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter) }); - Assert.Throws(() => unitsNETTypeConverter.ConvertFrom(context, culture, "1")); + Assert.Throws(() => converter.ConvertFrom(context, culture, "1")); } - - - - [Fact] - public void ConvertFrom_GiveStringWithPower_1() + public void ConvertFrom_GivenStringWithPower_1() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m")); - Assert.Equal(Length.FromMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^1")); + Assert.Equal(Length.FromMeters(1), converter.ConvertFrom(context, culture, "1m")); + Assert.Equal(Length.FromMeters(1), converter.ConvertFrom(context, culture, "1m^1")); } [Fact] - public void ConvertFrom_GiveStringWithPower_2() + public void ConvertFrom_GivenStringWithPower_2() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(Area.FromSquareMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m²")); - Assert.Equal(Area.FromSquareMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^2")); + Assert.Equal(Area.FromSquareMeters(1), converter.ConvertFrom(context, culture, "1m²")); + Assert.Equal(Area.FromSquareMeters(1), converter.ConvertFrom(context, culture, "1m^2")); } [Fact] - public void ConvertFrom_GiveStringWithPower_3() + public void ConvertFrom_GivenStringWithPower_3() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(Volume.FromCubicMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m³")); - Assert.Equal(Volume.FromCubicMeters(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^3")); + Assert.Equal(Volume.FromCubicMeters(1), converter.ConvertFrom(context, culture, "1m³")); + Assert.Equal(Volume.FromCubicMeters(1), converter.ConvertFrom(context, culture, "1m^3")); } [Fact] - public void ConvertFrom_GiveStringWithPower_4() + public void ConvertFrom_GivenStringWithPower_4() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m⁴")); - Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1m^4")); + Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), converter.ConvertFrom(context, culture, "1m⁴")); + Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), converter.ConvertFrom(context, culture, "1m^4")); } [Fact] - public void ConvertFrom_GiveStringWithPower_minus1() + public void ConvertFrom_GivenStringWithPower_minus1() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1K⁻¹")); - Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1K^-1")); + Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), converter.ConvertFrom(context, culture, "1K⁻¹")); + Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), converter.ConvertFrom(context, culture, "1K^-1")); } [Fact] - public void ConvertFrom_GiveStringWithPower_minus2() + public void ConvertFrom_GivenStringWithPower_minus2() { - UnitsNetTypeConverter unitsNETTypeConverter = new UnitsNetTypeConverter(); + var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); - Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg·s⁻¹·m⁻²")); - Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg·s^-1·m^-2")); - Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), unitsNETTypeConverter.ConvertFrom(context, culture, "1kg*s^-1*m^-2")); + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg·s⁻¹·m⁻²")); + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg·s^-1·m^-2")); + Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg*s^-1*m^-2")); } } } diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs index 7873da5dfd..c5a927c478 100644 --- a/UnitsNet/QuantityTypeConverter.cs +++ b/UnitsNet/QuantityTypeConverter.cs @@ -15,12 +15,12 @@ namespace UnitsNet public abstract class UnitAttributeBase : Attribute { /// - /// This property hold the UnitType information + /// The unit enum type, such as /// public Enum UnitType { get; set; } /// - /// Constructor of this class + /// Initializes a new instance of the class. /// /// public UnitAttributeBase(object unitType) @@ -35,7 +35,7 @@ public UnitAttributeBase(object unitType) public class DefaultUnitAttribute : UnitAttributeBase { /// - /// Constructor for ConvertToUnit attribute + /// Initializes a new instance of the class. /// /// The unit the quantity gets when the string parsing dose only consist of digits public DefaultUnitAttribute(object unitType) : base(unitType) { } @@ -47,7 +47,7 @@ public DefaultUnitAttribute(object unitType) : base(unitType) { } public class ConvertToUnitAttribute : DefaultUnitAttribute { /// - /// Constructor for ConvertToUnit attribute + /// Initializes a new instance of the class. /// /// The unit the quantity is converted to when parsing from string public ConvertToUnitAttribute(object unitType) : base(unitType) { } @@ -59,25 +59,33 @@ public ConvertToUnitAttribute(object unitType) : base(unitType) { } public class DisplayAsUnitAttribute : DefaultUnitAttribute { /// - /// The formating used when the quantity is converted to string + /// The formating used when the quantity is converted to string. See /// public string Format { get; set; } /// - /// Constructor for DisplayAsUnit attribute + /// Initializes a new instance of the class. /// /// The unit the quantity should be displayed in /// Formating string - public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitType) { Format = format; } + public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitType) + { + Format = format; + } } + // TODO example or documentation ? when documentation where? /// - /// Converts IQuantitys from string and to string. + /// Converts between IQuantity and string. /// Implements the TypeConverter interface so that eg the PropertyGrid can read and write the properties implementing the IQuantity interface. /// + /// + /// + /// /// Quantity value type, such as or . public class UnitsNetTypeConverter : TypeConverter where TQuantity : IQuantity { + // TODO be more specific that only string is supported same below /// /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. /// @@ -102,13 +110,14 @@ private static TAttribute GetAttribute(ITypeDescriptorContext contex QuantityType actual = Quantity.From(1, attribute.UnitType).Type; if(expected != actual) { - throw new InvalidOperationException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'"); + throw new ArgumentException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'"); } } return attribute; } + // TODO /// /// Converts the given object to the type of this converter, using the specified context and culture information. /// @@ -133,7 +142,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c } else { - // this should not be part of QuantityTypeConverter. it should rather be part of the parse function + // TODO this should not be part of QuantityTypeConverter. it should rather be part of the parse function stringValue = stringValue.Replace("^-9", "⁻⁹"); stringValue = stringValue.Replace("^-8", "⁻⁸"); stringValue = stringValue.Replace("^-7", "⁻⁷"); @@ -167,6 +176,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c return result ?? base.ConvertFrom(context, culture, value); } + // TODO /// Returns whether this converter can convert the object to the specified type, using the specified context. /// true if this converter can perform the conversion; otherwise, false. /// An that provides a format context. @@ -176,6 +186,7 @@ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinati return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType); } + // TODO /// Converts the given value object to the specified type, using the specified context and culture information. /// An that represents the converted value. /// An that provides a format context. From 75523e1c63f5775fbe9360c93e8eb3772025a6ef Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Mon, 22 Apr 2019 13:08:28 +0200 Subject: [PATCH 04/12] Reworked unit tests Updated xmldoc --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 38 +++++------ UnitsNet/QuantityTypeConverter.cs | 71 +++++++++++++++------ 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index d670653a8c..a91ef4480c 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -171,70 +171,72 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuanti } [Fact] - public void ConvertTo_GivenSomeQuantitysAndContextWithDefaultUnitAndConvertToUnitAttributes_ReturnsQuantityStringInUnitOfQuantity() + public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitDefaultFormating() { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { - new DefaultUnitAttribute(Units.LengthUnit.Centimeter), - new ConvertToUnitAttribute(Units.LengthUnit.Millimeter) + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); + Length length = Length.FromMeters(1); - Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); - Assert.Equal("1 m", converter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); } [Fact] - public void ConvertTo_GivenSomeQuantitysAndContextWithDefaultUnitAndConvertToUnitAndDisplayAsUnitAttributes_ReturnsQuantityStringInSpecifiedDisplayUnit() + public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitFormateAsValueOnly() { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { - new DefaultUnitAttribute(Units.LengthUnit.Centimeter), - new ConvertToUnitAttribute(Units.LengthUnit.Millimeter), - new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") }); Length length = Length.FromMeters(1); - Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); - Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("10", converter.ConvertTo(context, culture, length, typeof(string))); } [Fact] - public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitDefaultFormating() + public void ConvertTo_TestDisplayAsFormattingWithoutDefinedUnit_ReturnsQuantityStringWithQuantetiesUnitAndFormatedAsValueOnly() { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { - new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) + new DisplayAsUnitAttribute(null, "v") }); Length length = Length.FromMeters(1); - Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("1", converter.ConvertTo(context, culture, length, typeof(string))); } [Fact] - public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitFormateAsValueOnly() + public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_ReturnsQuantityStringInSpecifiedDisplayUnit() { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { - new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") + new DefaultUnitAttribute(Units.LengthUnit.Centimeter), + new ConvertToUnitAttribute(Units.LengthUnit.Millimeter), + new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); Length length = Length.FromMeters(1); - Assert.Equal("10", converter.ConvertTo(context, culture, length, typeof(string))); + Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); + Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); } [Fact] public void WrongUnitTypeInAttribut_DefaultUnit() { var converter = new UnitsNetTypeConverter(); - ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter) }); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter) + }); Assert.Throws(() => converter.ConvertFrom(context, culture, "1")); } diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs index c5a927c478..518144ef1f 100644 --- a/UnitsNet/QuantityTypeConverter.cs +++ b/UnitsNet/QuantityTypeConverter.cs @@ -30,7 +30,7 @@ public UnitAttributeBase(object unitType) } /// - /// This attribute defines the default Unit to use. It is only used when the string only consists of digits + /// This attribute defines the default Unit to use if the string to convert only consists of digits /// public class DefaultUnitAttribute : UnitAttributeBase { @@ -53,6 +53,7 @@ public class ConvertToUnitAttribute : DefaultUnitAttribute public ConvertToUnitAttribute(object unitType) : base(unitType) { } } + // TODO what about formating without defined unit /// /// This attribute defines the unit the quantity has when converting to string /// @@ -74,23 +75,51 @@ public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitTy } } - // TODO example or documentation ? when documentation where? /// - /// Converts between IQuantity and string. - /// Implements the TypeConverter interface so that eg the PropertyGrid can read and write the properties implementing the IQuantity interface. + /// + /// Converts between IQuantity and string. + /// Implements the interface so that eg the PropertyGrid can read and write the properties implementing the interface. + /// + /// For basic understanding of TypeConverters consult the .NET documentation. /// + /// Quantity value type, such as or . /// + /// + /// This example shows how to use this typeConverter. + /// It will convert between string to a Length object. The properties unit is displayed. + /// When converting a string to Length the unit of the string is used. When no unit is given by the string the base unit is used. + /// The displayed unit can be defined by the . + /// + /// + /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] + /// Units.Length Length { get; set; } + /// + /// + /// + /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter)] + /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] + /// Units.Length Length { get; set; } + /// /// + /// + /// [ConvertToUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] + /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] + /// Units.Length Length { get; set; } + /// + /// + /// + /// [DefaultUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] + /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] + /// Units.Length Length { get; set; } + /// /// - /// Quantity value type, such as or . public class UnitsNetTypeConverter : TypeConverter where TQuantity : IQuantity { - // TODO be more specific that only string is supported same below /// - /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. + /// Returns true if sourceType if of type /// - /// An System.ComponentModel.ITypeDescriptorContext that provides a format context. - /// A System.Type that represents the type you want to convert from. + /// An that provides a format context. + /// A that represents the type you want to convert from. /// true if this converter can perform the conversion; otherwise, false. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { @@ -107,8 +136,10 @@ private static TAttribute GetAttribute(ITypeDescriptorContext contex if(attribute != null) { QuantityType expected = default(TQuantity).Type; - QuantityType actual = Quantity.From(1, attribute.UnitType).Type; - if(expected != actual) + QuantityType actual = QuantityType.Undefined; + + if(attribute.UnitType != null) actual = Quantity.From(1, attribute.UnitType).Type; + if(actual != QuantityType.Undefined && expected != actual) { throw new ArgumentException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'"); } @@ -117,9 +148,8 @@ private static TAttribute GetAttribute(ITypeDescriptorContext contex return attribute; } - // TODO /// - /// Converts the given object to the type of this converter, using the specified context and culture information. + /// Converts the given object, when it is of type to the type of this converter, using the specified context and culture information. /// /// An System.ComponentModel.ITypeDescriptorContext that provides a format context. /// The System.Globalization.CultureInfo to use as the current culture. @@ -176,8 +206,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c return result ?? base.ConvertFrom(context, culture, value); } - // TODO - /// Returns whether this converter can convert the object to the specified type, using the specified context. + /// Returns true whether this converter can convert the to string, using the specified context. /// true if this converter can perform the conversion; otherwise, false. /// An that provides a format context. /// A that represents the type you want to convert to. @@ -186,8 +215,7 @@ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinati return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType); } - // TODO - /// Converts the given value object to the specified type, using the specified context and culture information. + /// Converts the given object to , using the specified context and culture information. /// An that represents the converted value. /// An that provides a format context. /// A . If null is passed, the current culture is assumed. @@ -203,7 +231,14 @@ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo cul if (destinationType == typeof(string) && qvalue != null && displayAsUnit != null) { - result = qvalue.ToUnit(displayAsUnit.UnitType).ToString(displayAsUnit.Format, culture); + if (displayAsUnit.UnitType != null) + { + result = qvalue.ToUnit(displayAsUnit.UnitType).ToString(displayAsUnit.Format, culture); + } + else + { + result = qvalue.ToString(displayAsUnit.Format, culture); + } } else { From 5c21e9714cb2fcac80a1363f6a36fd8d207ab7e6 Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 22 Apr 2019 18:23:54 +0200 Subject: [PATCH 05/12] Fix whitespace --- UnitsNet.Tests/Helpers/TypeDescriptorContext.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs index 73928e12f8..98f1d0be80 100644 --- a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs +++ b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs @@ -6,7 +6,7 @@ namespace UnitsNet.Tests.Helpers { /// - /// Is used to imitate e property with attributes + /// Is used to imitate e property with attributes /// public class TypeDescriptorContext : ITypeDescriptorContext { @@ -14,7 +14,6 @@ public class PropertyDescriptor_ : PropertyDescriptor { public PropertyDescriptor_(string name, Attribute[] attributes) : base(name, attributes) { - } public override Type ComponentType => throw new NotImplementedException(); From b72eebf144159eaa46b785682eb356edebf225e8 Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 22 Apr 2019 18:26:45 +0200 Subject: [PATCH 06/12] Fix typo --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index a91ef4480c..4d45393c70 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -119,7 +119,7 @@ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertTo } [Fact] - public void ConvertFrom_GivenEmpyString_ThrowsNotSupportedException() + public void ConvertFrom_GivenEmptyString_ThrowsNotSupportedException() { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); From beadc6bd5006d2ad7d5414f2cd6cc3a532631787 Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 22 Apr 2019 18:28:53 +0200 Subject: [PATCH 07/12] Add file header --- UnitsNet.Tests/Helpers/TypeDescriptorContext.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs index 98f1d0be80..a4675599c3 100644 --- a/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs +++ b/UnitsNet.Tests/Helpers/TypeDescriptorContext.cs @@ -1,4 +1,7 @@ -using System; +// Licensed under MIT No Attribution, see LICENSE file at the root. +// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet. + +using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; From b90b54ee6952077439247f88b57450b5b82c843e Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 22 Apr 2019 18:35:40 +0200 Subject: [PATCH 08/12] Fix typo --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 4d45393c70..426ba7fb60 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -140,7 +140,7 @@ public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException() [InlineData(typeof(Length))] [InlineData(typeof(IQuantity))] [InlineData(typeof(object))] - public void ConvertTo_GivenWrongType_ThrowsExceptionNotSupportedException(Type value) + public void ConvertTo_GivenWrongType_ThrowsNotSupportedException(Type value) { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); From d76675be712da240269a259aa7cfefc981a1efd9 Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 22 Apr 2019 19:11:23 +0200 Subject: [PATCH 09/12] Fix typo --- UnitsNet/QuantityTypeConverter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs index 518144ef1f..08e90bb6db 100644 --- a/UnitsNet/QuantityTypeConverter.cs +++ b/UnitsNet/QuantityTypeConverter.cs @@ -85,29 +85,29 @@ public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitTy /// Quantity value type, such as or . /// /// - /// This example shows how to use this typeConverter. + /// This example shows how to use this TypeConverter. /// It will convert between string to a Length object. The properties unit is displayed. /// When converting a string to Length the unit of the string is used. When no unit is given by the string the base unit is used. /// The displayed unit can be defined by the . /// - /// + /// /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } /// /// - /// + /// /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } /// /// - /// + /// /// [ConvertToUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } /// /// - /// + /// /// [DefaultUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } From a4f44442e7ee9976fe3376832d65bfe8ef0f7376 Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Wed, 24 Apr 2019 09:16:16 +0200 Subject: [PATCH 10/12] Use AAA stryle for unit tests Clean up Better description of UnitsNetTypeConverter --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 74 ++++++++++++--------- UnitsNet/QuantityTypeConverter.cs | 56 ++++++++++------ 2 files changed, 76 insertions(+), 54 deletions(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 426ba7fb60..49e6176787 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -2,12 +2,9 @@ // Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet. using System; -using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Reflection; -using System.Text; -using UnitsNet; using UnitsNet.Tests.Helpers; using Xunit; @@ -31,14 +28,14 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven static QuantityTypeConverterTest() { - // NOTE: After this, you can use your typeconverter. + // NOTE: After this, you can use your TypeConverter. AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); } /// /// Is used for tests that are culture dependent /// - static CultureInfo culture = CultureInfo.GetCultureInfo("en-US"); + private static CultureInfo culture = CultureInfo.GetCultureInfo("en-US"); [Theory] [InlineData(typeof(string), true)] @@ -50,7 +47,9 @@ public void CanConvertFrom_GivenSomeTypes(Type value, bool expectedResult) { var converter = new UnitsNetTypeConverter(); - Assert.True(converter.CanConvertFrom(value) == expectedResult); + bool canConvertFrom = converter.CanConvertFrom(value); + + Assert.Equal(expectedResult, canConvertFrom); } [Theory] @@ -63,7 +62,9 @@ public void CanConvertTo_GivenSomeTypes(Type value, bool expectedResult) { var converter = new UnitsNetTypeConverter(); - Assert.True(converter.CanConvertTo(value) == expectedResult); + bool canConvertTo = converter.CanConvertTo(value); + + Assert.Equal(expectedResult, canConvertTo); } [Theory] @@ -78,8 +79,8 @@ public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQua var convertedValue = (Length)converter.ConvertFrom(context, culture, str); - Assert.Equal(convertedValue.Value, expectedValue); - Assert.Equal(convertedValue.Unit, expectedUnit); + Assert.Equal(expectedValue, convertedValue.Value); + Assert.Equal(expectedUnit, convertedValue.Unit); } [Theory] @@ -90,12 +91,15 @@ public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQua public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAttribute_ReturnsQuantityWithGivenDefaultUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit) { var converter = new UnitsNetTypeConverter(); - ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter) }); + ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] + { + new DefaultUnitAttribute(Units.LengthUnit.Centimeter) + }); var convertedValue = (Length)converter.ConvertFrom(context, culture, str); - Assert.Equal(convertedValue.Value, expectedValue); - Assert.Equal(convertedValue.Unit, expectedUnit); + Assert.Equal(expectedValue, convertedValue.Value); + Assert.Equal(expectedUnit, convertedValue.Unit); } [Theory] @@ -107,15 +111,15 @@ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertTo { var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] - { - new DefaultUnitAttribute(Units.LengthUnit.Centimeter), - new ConvertToUnitAttribute(Units.LengthUnit.Meter) - }); + { + new DefaultUnitAttribute(Units.LengthUnit.Centimeter), + new ConvertToUnitAttribute(Units.LengthUnit.Meter) + }); var convertedValue = (Length)converter.ConvertFrom(context, culture, str); - Assert.Equal(convertedValue.Value, expectedValue); - Assert.Equal(convertedValue.Unit, expectedUnit); + Assert.Equal(expectedValue, convertedValue.Value); + Assert.Equal(expectedUnit, convertedValue.Unit); } [Fact] @@ -156,7 +160,9 @@ public void ConvertTo_GivenStringType_ReturnsQuantityString() ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); - Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); + string convertedQuantity = (string)converter.ConvertTo(length, typeof(string)); + + Assert.Equal("1 m", convertedQuantity); } [Fact] @@ -166,8 +172,9 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuanti ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); - Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); - Assert.Equal("1 m", converter.ConvertTo(context, culture, length, typeof(string))); + string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string)); + + Assert.Equal("1 m", convertedQuantity); } [Fact] @@ -178,10 +185,11 @@ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUn { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); - Length length = Length.FromMeters(1); - Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); + string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string)); + + Assert.Equal("10 dm", convertedQuantity); } [Fact] @@ -192,10 +200,11 @@ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUn { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") }); - Length length = Length.FromMeters(1); - Assert.Equal("10", converter.ConvertTo(context, culture, length, typeof(string))); + string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string)); + + Assert.Equal("10", convertedQuantity); } [Fact] @@ -206,10 +215,11 @@ public void ConvertTo_TestDisplayAsFormattingWithoutDefinedUnit_ReturnsQuantityS { new DisplayAsUnitAttribute(null, "v") }); - Length length = Length.FromMeters(1); - Assert.Equal("1", converter.ConvertTo(context, culture, length, typeof(string))); + string convertedQuantity = (string)converter.ConvertTo(context, culture, length, typeof(string)); + + Assert.Equal("1", convertedQuantity); } [Fact] @@ -218,15 +228,15 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_Re var converter = new UnitsNetTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { - new DefaultUnitAttribute(Units.LengthUnit.Centimeter), - new ConvertToUnitAttribute(Units.LengthUnit.Millimeter), new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) }); - Length length = Length.FromMeters(1); - Assert.Equal("1 m", converter.ConvertTo(length, typeof(string))); - Assert.Equal("10 dm", converter.ConvertTo(context, culture, length, typeof(string))); + string convertedQuantityDefaultCulture = (string)converter.ConvertTo(length, typeof(string)); + string convertedQuantitySpecificCulture = (string)converter.ConvertTo(context, culture, length, typeof(string)); + + Assert.Equal("1 m", convertedQuantityDefaultCulture); + Assert.Equal("10 dm", convertedQuantitySpecificCulture); } [Fact] diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs index 08e90bb6db..cb0f7a4eb2 100644 --- a/UnitsNet/QuantityTypeConverter.cs +++ b/UnitsNet/QuantityTypeConverter.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel; using System.Globalization; -using System.Runtime.CompilerServices; namespace UnitsNet { @@ -53,7 +52,6 @@ public class ConvertToUnitAttribute : DefaultUnitAttribute public ConvertToUnitAttribute(object unitType) : base(unitType) { } } - // TODO what about formating without defined unit /// /// This attribute defines the unit the quantity has when converting to string /// @@ -68,7 +66,7 @@ public class DisplayAsUnitAttribute : DefaultUnitAttribute /// Initializes a new instance of the class. /// /// The unit the quantity should be displayed in - /// Formating string + /// Formating string public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitType) { Format = format; @@ -76,38 +74,52 @@ public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitTy } /// - /// - /// Converts between IQuantity and string. - /// Implements the interface so that eg the PropertyGrid can read and write the properties implementing the interface. + /// + /// Converts between IQuantity and string. + /// Implements a TypeConverter for IQuantitys. This allows eg the PropertyGrid to read and write properties of type IQuantity. /// - /// For basic understanding of TypeConverters consult the .NET documentation. + /// For basic understanding of TypeConverters consult the .NET documentation. /// /// Quantity value type, such as or . + /// + /// + /// When a string is converted a Quantity the unit given by the string is used. + /// When no unit is given by the string the base unit is used. + /// The base unit can be overwritten by use of the . + /// The converted Quantity can be forced to be in a certain unit by use of the . + /// + /// + /// The displayed unit can be forced to a certain unit by use of the . + /// The provides the possibility to format the displayed Quantity. + /// + /// /// - /// - /// This example shows how to use this TypeConverter. - /// It will convert between string to a Length object. The properties unit is displayed. - /// When converting a string to Length the unit of the string is used. When no unit is given by the string the base unit is used. - /// The displayed unit can be defined by the . + /// These examples show how to use this TypeConverter. /// /// /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] - /// Units.Length Length { get; set; } + /// Units.Length PropertyName { get; set; } /// - /// - /// + /// + /// /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } /// - /// - /// + /// + /// + /// [DisplayAsUnit(UnitsNet.Units.LengthUnit.Meter, "g")] + /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] + /// Units.Length Length { get; set; } + /// + /// + /// /// [ConvertToUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } /// /// - /// + /// /// [DefaultUnitAttribute(UnitsNet.Units.LengthUnit.Meter)] /// [TypeConverter(typeof(UnitsNetTypeConverter{Length}))] /// Units.Length Length { get; set; } @@ -133,13 +145,13 @@ private static TAttribute GetAttribute(ITypeDescriptorContext contex attribute = (TAttribute)ua?[typeof(TAttribute)]; - if(attribute != null) + if (attribute != null) { QuantityType expected = default(TQuantity).Type; QuantityType actual = QuantityType.Undefined; - if(attribute.UnitType != null) actual = Quantity.From(1, attribute.UnitType).Type; - if(actual != QuantityType.Undefined && expected != actual) + if (attribute.UnitType != null) actual = Quantity.From(1, attribute.UnitType).Type; + if (actual != QuantityType.Undefined && expected != actual) { throw new ArgumentException($"The specified UnitType:'{attribute.UnitType}' dose not match QuantityType:'{expected}'"); } @@ -173,7 +185,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c else { // TODO this should not be part of QuantityTypeConverter. it should rather be part of the parse function - stringValue = stringValue.Replace("^-9", "⁻⁹"); + stringValue = stringValue.Replace("^-9", "⁻⁹"); stringValue = stringValue.Replace("^-8", "⁻⁸"); stringValue = stringValue.Replace("^-7", "⁻⁷"); stringValue = stringValue.Replace("^-6", "⁻⁶"); From ee30fb6938c700c8eea626c510cf0998451f2c7d Mon Sep 17 00:00:00 2001 From: Wilhelm Wiens Date: Wed, 24 Apr 2019 09:24:05 +0200 Subject: [PATCH 11/12] Rename the typeconverter to QuantityTypeConverter --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 42 ++++++++++----------- UnitsNet/QuantityTypeConverter.cs | 4 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 49e6176787..7e71b56ae0 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -45,7 +45,7 @@ static QuantityTypeConverterTest() [InlineData(typeof(Length), false)] public void CanConvertFrom_GivenSomeTypes(Type value, bool expectedResult) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); bool canConvertFrom = converter.CanConvertFrom(value); @@ -60,7 +60,7 @@ public void CanConvertFrom_GivenSomeTypes(Type value, bool expectedResult) [InlineData(typeof(Length), false)] public void CanConvertTo_GivenSomeTypes(Type value, bool expectedResult) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); bool canConvertTo = converter.CanConvertTo(value); @@ -74,7 +74,7 @@ public void CanConvertTo_GivenSomeTypes(Type value, bool expectedResult) [InlineData("1km", 1, Units.LengthUnit.Kilometer)] public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQuantityWithBaseUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); var convertedValue = (Length)converter.ConvertFrom(context, culture, str); @@ -90,7 +90,7 @@ public void ConvertFrom_GivenQuantityStringAndContextWithNoAttributes_ReturnsQua [InlineData("1km", 1, Units.LengthUnit.Kilometer)] public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAttribute_ReturnsQuantityWithGivenDefaultUnitIfNotSpecified(string str, double expectedValue, Enum expectedUnit) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter) @@ -109,7 +109,7 @@ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAttribute_Re [InlineData("1km", 1000, Units.LengthUnit.Meter)] public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertToUnitAttributes_ReturnsQuantityConvertedToUnit(string str, double expectedValue, Enum expectedUnit) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.LengthUnit.Centimeter), @@ -125,7 +125,7 @@ public void ConvertFrom_GivenQuantityStringAndContextWithDefaultUnitAndConvertTo [Fact] public void ConvertFrom_GivenEmptyString_ThrowsNotSupportedException() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Throws(() => converter.ConvertFrom(context, culture, "")); @@ -134,7 +134,7 @@ public void ConvertFrom_GivenEmptyString_ThrowsNotSupportedException() [Fact] public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Throws(() => converter.ConvertFrom(context, culture, "1m^2")); @@ -146,7 +146,7 @@ public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException() [InlineData(typeof(object))] public void ConvertTo_GivenWrongType_ThrowsNotSupportedException(Type value) { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); @@ -156,7 +156,7 @@ public void ConvertTo_GivenWrongType_ThrowsNotSupportedException(Type value) [Fact] public void ConvertTo_GivenStringType_ReturnsQuantityString() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); @@ -168,7 +168,7 @@ public void ConvertTo_GivenStringType_ReturnsQuantityString() [Fact] public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuantityStringInUnitOfQuantity() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Length length = Length.FromMeters(1); @@ -180,7 +180,7 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithNoAttributes_ReturnsQuanti [Fact] public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitDefaultFormating() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) @@ -195,7 +195,7 @@ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUn [Fact] public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUnitFormateAsValueOnly() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter, "v") @@ -210,7 +210,7 @@ public void ConvertTo_TestDisplayAsFormatting_ReturnsQuantityStringWithDisplayUn [Fact] public void ConvertTo_TestDisplayAsFormattingWithoutDefinedUnit_ReturnsQuantityStringWithQuantetiesUnitAndFormatedAsValueOnly() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(null, "v") @@ -225,7 +225,7 @@ public void ConvertTo_TestDisplayAsFormattingWithoutDefinedUnit_ReturnsQuantityS [Fact] public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_ReturnsQuantityStringInSpecifiedDisplayUnit() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DisplayAsUnitAttribute(Units.LengthUnit.Decimeter) @@ -242,7 +242,7 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_Re [Fact] public void WrongUnitTypeInAttribut_DefaultUnit() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { new DefaultUnitAttribute(Units.VolumeUnit.CubicMeter) @@ -254,7 +254,7 @@ public void WrongUnitTypeInAttribut_DefaultUnit() [Fact] public void ConvertFrom_GivenStringWithPower_1() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(Length.FromMeters(1), converter.ConvertFrom(context, culture, "1m")); @@ -264,7 +264,7 @@ public void ConvertFrom_GivenStringWithPower_1() [Fact] public void ConvertFrom_GivenStringWithPower_2() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(Area.FromSquareMeters(1), converter.ConvertFrom(context, culture, "1m²")); @@ -274,7 +274,7 @@ public void ConvertFrom_GivenStringWithPower_2() [Fact] public void ConvertFrom_GivenStringWithPower_3() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(Volume.FromCubicMeters(1), converter.ConvertFrom(context, culture, "1m³")); @@ -284,7 +284,7 @@ public void ConvertFrom_GivenStringWithPower_3() [Fact] public void ConvertFrom_GivenStringWithPower_4() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(AreaMomentOfInertia.FromMetersToTheFourth(1), converter.ConvertFrom(context, culture, "1m⁴")); @@ -294,7 +294,7 @@ public void ConvertFrom_GivenStringWithPower_4() [Fact] public void ConvertFrom_GivenStringWithPower_minus1() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(CoefficientOfThermalExpansion.FromInverseKelvin(1), converter.ConvertFrom(context, culture, "1K⁻¹")); @@ -304,7 +304,7 @@ public void ConvertFrom_GivenStringWithPower_minus1() [Fact] public void ConvertFrom_GivenStringWithPower_minus2() { - var converter = new UnitsNetTypeConverter(); + var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { }); Assert.Equal(MassFlux.FromKilogramsPerSecondPerSquareMeter(1), converter.ConvertFrom(context, culture, "1kg·s⁻¹·m⁻²")); diff --git a/UnitsNet/QuantityTypeConverter.cs b/UnitsNet/QuantityTypeConverter.cs index cb0f7a4eb2..0b0ab77a77 100644 --- a/UnitsNet/QuantityTypeConverter.cs +++ b/UnitsNet/QuantityTypeConverter.cs @@ -8,7 +8,7 @@ namespace UnitsNet { /// - /// Is the base class for all attributes that are related to + /// Is the base class for all attributes that are related to /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public abstract class UnitAttributeBase : Attribute @@ -125,7 +125,7 @@ public DisplayAsUnitAttribute(object unitType, string format = "") : base(unitTy /// Units.Length Length { get; set; } /// /// - public class UnitsNetTypeConverter : TypeConverter where TQuantity : IQuantity + public class QuantityTypeConverter : TypeConverter where TQuantity : IQuantity { /// /// Returns true if sourceType if of type From 373e125104ab026f0ae5b73772069aea8201a6ff Mon Sep 17 00:00:00 2001 From: Andreas Gullberg Larsen Date: Mon, 29 Apr 2019 17:43:56 +0200 Subject: [PATCH 12/12] Rename test method --- UnitsNet.Tests/QuantityTypeConverterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitsNet.Tests/QuantityTypeConverterTest.cs b/UnitsNet.Tests/QuantityTypeConverterTest.cs index 7e71b56ae0..94dbac7d04 100644 --- a/UnitsNet.Tests/QuantityTypeConverterTest.cs +++ b/UnitsNet.Tests/QuantityTypeConverterTest.cs @@ -240,7 +240,7 @@ public void ConvertTo_GivenSomeQuantitysAndContextWithDisplayAsUnitAttributes_Re } [Fact] - public void WrongUnitTypeInAttribut_DefaultUnit() + public void ConvertFrom_GivenDefaultUnitAttributeWithWrongUnitType_ThrowsArgumentException() { var converter = new QuantityTypeConverter(); ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[]