From dcd4b2cb5c2ccd50cb73556664f6e062adc9463c Mon Sep 17 00:00:00 2001 From: Dejan Bratic Date: Wed, 28 Jun 2023 14:35:41 +0200 Subject: [PATCH 1/5] added Length value object; --- .../Common/MeasurementConversionFactor.cs | 66 +++++++ src/Nox.Types/Types/Area/Area.cs | 17 +- src/Nox.Types/Types/Distance/Distance.cs | 17 +- src/Nox.Types/Types/Length/Length.cs | 115 ++++++++++- src/Nox.Types/Types/Length/LengthTypeUnit.cs | 22 +++ .../MeasurementConversionFactorTests.cs | 72 +++++++ .../Types/Length/LengthTests.cs | 187 +++++++++++++++++- 7 files changed, 468 insertions(+), 28 deletions(-) create mode 100644 src/Nox.Types/Common/MeasurementConversionFactor.cs create mode 100644 src/Nox.Types/Types/Length/LengthTypeUnit.cs create mode 100644 tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs diff --git a/src/Nox.Types/Common/MeasurementConversionFactor.cs b/src/Nox.Types/Common/MeasurementConversionFactor.cs new file mode 100644 index 0000000..7d41d8b --- /dev/null +++ b/src/Nox.Types/Common/MeasurementConversionFactor.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; + +namespace Nox.Common; + +public class MeasurementConversionFactor +{ + private const string Foot = "Foot"; + private const string Meter = "Meter"; + private const string Kilometer = "Kilometer"; + private const string Mile = "Mile"; + private static readonly string[] _lengthUnits = new[] { Foot, Meter, Kilometer, Mile }; + + private const string SquareFoot = "SquareFoot"; + private const string SquareMeter = "SquareMeter"; + private static readonly string[] _areaUnits = new[] { SquareFoot, SquareMeter }; + + public double Value { get; } + + public MeasurementConversionFactor(Enum sourceUnit, Enum targetUnit) + : this(sourceUnit.ToString(), targetUnit.ToString()) + { + } + + public MeasurementConversionFactor(string sourceUnit, string targetUnit) + { + Value = ResolveConversionFactor(sourceUnit, targetUnit) + ?? throw new NotImplementedException($"No conversion defined from {sourceUnit} to {targetUnit}."); + } + + private double? ResolveConversionFactor(string sourceUnit, string targetUnit) + { + return IsSupported(sourceUnit) && IsSupported(targetUnit) + ? ResolveConversionFactorForSupportedUnits(sourceUnit, targetUnit) + : null; + } + + private bool IsSupported(string unit) + => _lengthUnits.Contains(unit) || _areaUnits.Contains(unit); + + private double? ResolveConversionFactorForSupportedUnits(string sourceUnit, string targetUnit) + { + if (sourceUnit == targetUnit) + return 1; + + else if (sourceUnit == Foot && targetUnit == Meter) + return 0.30480000033; + + else if (sourceUnit == Meter && targetUnit == Foot) + return 3.28083989142; + + else if (sourceUnit == Kilometer && targetUnit == Mile) + return 0.62137119102; + + else if (sourceUnit == Mile && targetUnit == Kilometer) + return 1.60934400315; + + else if (sourceUnit == SquareFoot && targetUnit == SquareMeter) + return 0.09290304; + + else if (sourceUnit == SquareMeter && targetUnit == SquareFoot) + return 10.76391042; + + return null; + } +} diff --git a/src/Nox.Types/Types/Area/Area.cs b/src/Nox.Types/Types/Area/Area.cs index 52e9421..3623b50 100644 --- a/src/Nox.Types/Types/Area/Area.cs +++ b/src/Nox.Types/Types/Area/Area.cs @@ -1,4 +1,5 @@ -using System; +using Nox.Common; +using System; using System.Collections.Generic; namespace Nox.Types; @@ -104,18 +105,10 @@ protected override IEnumerable> GetEqualityComponen private QuantityValue? _squareFeet; public QuantityValue ToSquareFeet() => (_squareFeet ??= GetAreaIn(AreaTypeUnit.SquareFoot)); - private QuantityValue GetAreaIn(AreaTypeUnit unit) + private QuantityValue GetAreaIn(AreaTypeUnit targetUnit) { - if (Unit == unit) - return Round(Value); - - else if (Unit == AreaTypeUnit.SquareMeter && unit == AreaTypeUnit.SquareFoot) - return Round(Value * 10.76391042); - - else if (Unit == AreaTypeUnit.SquareFoot && unit == AreaTypeUnit.SquareMeter) - return Round(Value * 0.09290304); - - throw new NotImplementedException($"No conversion defined from {Unit} to {unit}."); + var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + return Round(Value * factor); } private static QuantityValue Round(QuantityValue value) diff --git a/src/Nox.Types/Types/Distance/Distance.cs b/src/Nox.Types/Types/Distance/Distance.cs index c7de953..4d92726 100644 --- a/src/Nox.Types/Types/Distance/Distance.cs +++ b/src/Nox.Types/Types/Distance/Distance.cs @@ -1,4 +1,5 @@ -using System; +using Nox.Common; +using System; using System.Collections.Generic; namespace Nox.Types; @@ -122,18 +123,10 @@ protected override IEnumerable> GetEqualityComponen public QuantityValue ToMiles() => (_miles ??= GetDistanceIn(DistanceTypeUnit.Mile)); - private QuantityValue GetDistanceIn(DistanceTypeUnit unit) + private QuantityValue GetDistanceIn(DistanceTypeUnit targetUnit) { - if (Unit == unit) - return Round(Value); - - else if (Unit == DistanceTypeUnit.Kilometer && unit == DistanceTypeUnit.Mile) - return Round(Value * 0.62137119102); - - else if (Unit == DistanceTypeUnit.Mile && unit == DistanceTypeUnit.Kilometer) - return Round(Value * 1.60934400315); - - throw new NotImplementedException($"No conversion defined from {Unit} to {unit}."); + var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + return Round(Value * factor); } private static QuantityValue Round(QuantityValue value) diff --git a/src/Nox.Types/Types/Length/Length.cs b/src/Nox.Types/Types/Length/Length.cs index c96d70d..217c656 100644 --- a/src/Nox.Types/Types/Length/Length.cs +++ b/src/Nox.Types/Types/Length/Length.cs @@ -1,9 +1,118 @@ +using Nox.Common; +using System; +using System.Collections.Generic; + namespace Nox.Types; +/// +/// Represents a Nox type and value object. +/// +public sealed class Length : ValueObject +{ + private const int QuantityValueDecimalPrecision = 6; + + public LengthTypeUnit Unit { get; private set; } = LengthTypeUnit.Meter; + + public Length() { Value = 0; } + + /// + /// Creates a new instance of object in meters. + /// + /// The value to create the with + /// + /// + public static Length FromMeters(QuantityValue value) + => From(value, LengthTypeUnit.Meter); + + /// + /// Creates a new instance of object in feet. + /// + /// The origin value to create the with + /// + /// + public static Length FromFeet(QuantityValue value) + => From(value, LengthTypeUnit.Foot); + /// - /// Represents a Nox type and value object. + /// Creates a new instance of object in meters. /// - /// Placeholder, needs to be implemented - public sealed class Length : ValueObject + /// The value to create the with + /// + /// + public new static Length From(QuantityValue value) + => From(value, LengthTypeUnit.Meter); + + /// + /// Creates a new instance of object with the specified . + /// + /// The value to create the with + /// The to create the with + /// + /// + public static Length From(QuantityValue value, LengthTypeUnit unit) { + var newObject = new Length + { + Value = Round(value), + Unit = unit, + }; + + var validationResult = newObject.Validate(); + + if (!validationResult.IsValid) + { + throw new TypeValidationException(validationResult.Errors); + } + + return newObject; } + + /// + /// Validates a object. + /// + /// true if the value is valid. + internal override ValidationResult Validate() + { + var result = Value.Validate(); + + if (Value < 0) + { + result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Length type as negative length value {Value} is not allowed.")); + } + + if (!Enum.IsDefined(typeof(LengthTypeUnit), Unit)) + { + result.Errors.Add(new ValidationFailure(nameof(Unit), $"Could not create a Nox Length type as unit {Unit} is not supported.")); + } + + return result; + } + + protected override IEnumerable> GetEqualityComponents() + { + yield return new KeyValuePair(nameof(Value), ToMeters()); + } + + + public override string ToString() + => $"{Value:G} {Unit.ToSymbol()}"; + + private QuantityValue? _meters; + + public QuantityValue ToMeters() + => (_meters ??= GetLengthIn(LengthTypeUnit.Meter)); + + private QuantityValue? _feet; + + public QuantityValue ToFeet() + => (_feet ??= GetLengthIn(LengthTypeUnit.Foot)); + + private QuantityValue GetLengthIn(LengthTypeUnit targetUnit) + { + var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + return Round(Value * factor); + } + + private static QuantityValue Round(QuantityValue value) + => Math.Round((double)value, QuantityValueDecimalPrecision); +} \ No newline at end of file diff --git a/src/Nox.Types/Types/Length/LengthTypeUnit.cs b/src/Nox.Types/Types/Length/LengthTypeUnit.cs new file mode 100644 index 0000000..9cc6c04 --- /dev/null +++ b/src/Nox.Types/Types/Length/LengthTypeUnit.cs @@ -0,0 +1,22 @@ +using System; + +namespace Nox.Types; + +public enum LengthTypeUnit +{ + Foot, + Meter +} + +public static class LengthTypeUnitExtensions +{ + public static string ToSymbol(this LengthTypeUnit unit) + { + return unit switch + { + LengthTypeUnit.Foot => "ft", + LengthTypeUnit.Meter => "m", + _ => throw new NotImplementedException($"No symbol defined for unit {unit}.") + }; + } +} \ No newline at end of file diff --git a/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs new file mode 100644 index 0000000..8fe7d41 --- /dev/null +++ b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs @@ -0,0 +1,72 @@ +using Nox.Common; + +namespace Nox.Types.Tests.Common; + +public class MeasurementConversionFactorTests +{ + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromFootToMeter_ReturnsValue() + { + var factor = new MeasurementConversionFactor("Foot", "Meter"); + + Assert.Equal(0.30480000033, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromMeterToFoot_ReturnsValue() + { + var factor = new MeasurementConversionFactor("Meter", "Foot"); + + Assert.Equal(3.28083989142, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromKilometerToMile_ReturnsValue() + { + var factor = new MeasurementConversionFactor("Kilometer", "Mile"); + + Assert.Equal(0.62137119102, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromMileToKilometer_ReturnsValue() + { + var factor = new MeasurementConversionFactor("Mile", "Kilometer"); + + Assert.Equal(1.60934400315, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromSquareFootToSquareMeter_ReturnsValue() + { + var factor = new MeasurementConversionFactor("SquareFoot", "SquareMeter"); + + Assert.Equal(0.09290304, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_FromSquareMeterToSquareFoot_ReturnsValue() + { + var factor = new MeasurementConversionFactor("SquareMeter", "SquareFoot"); + + Assert.Equal(10.76391042, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_WithSameSourceAndTargetUnit_ReturnsValue() + { + var factor = new MeasurementConversionFactor("Foot", "Foot"); + + Assert.Equal(1, factor.Value); + } + + [Fact] + public void MeasurementUnitConverter_GetConversionFactor_WithUnsupportedConversion_ThrowsException() + { + var exception = Assert.Throws(() => _ = + new MeasurementConversionFactor("SquareMeter", "Meter") + ); + + Assert.Equal("No conversion defined from SquareMeter to Meter.", exception.Message); + } +} diff --git a/tests/Nox.Types.Tests/Types/Length/LengthTests.cs b/tests/Nox.Types.Tests/Types/Length/LengthTests.cs index cfd3de0..39818f1 100644 --- a/tests/Nox.Types.Tests/Types/Length/LengthTests.cs +++ b/tests/Nox.Types.Tests/Types/Length/LengthTests.cs @@ -4,8 +4,193 @@ namespace Nox.Types.Tests.Types; public class LengthTests { [Fact] - public void When_Create_Should() + public void Length_Constructor_ReturnsSameValueAndDefaultUnit() { + var length = Length.From(95.755663); + Assert.Equal(95.755663, length.Value); + Assert.Equal(LengthTypeUnit.Meter, length.Unit); + } + + [Fact] + public void Length_Constructor_WithUnit_ReturnsSameValueAndUnit() + { + var length = Length.From(314.158999, LengthTypeUnit.Foot); + + Assert.Equal(314.158999, length.Value); + Assert.Equal(LengthTypeUnit.Foot, length.Unit); + } + + [Fact] + public void Length_Constructor_WithUnitInFeet_ReturnsSameValueAndUnit() + { + var length = Length.FromFeet(314.158999); + + Assert.Equal(314.158999, length.Value); + Assert.Equal(LengthTypeUnit.Foot, length.Unit); + } + + [Fact] + public void Length_Constructor_WithUnitInMeters_ReturnsSameValueAndUnit() + { + var length = Length.FromMeters(95.755663); + + Assert.Equal(95.755663, length.Value); + Assert.Equal(LengthTypeUnit.Meter, length.Unit); + } + + [Fact] + public void Length_Constructor_WithNegativeValueInput_ThrowsException() + { + var exception = Assert.Throws(() => _ = + Length.From(-100) + ); + + Assert.Equal("Could not create a Nox Length type as negative length value -100 is not allowed.", exception.Errors.First().ErrorMessage); + } + + [Fact] + public void Length_Constructor_WithNaNValueInput_ThrowsException() + { + var exception = Assert.Throws(() => _ = + Length.From(double.NaN) + ); + + Assert.Equal("Could not create a Nox type as value NaN is not allowed.", exception.Errors.First().ErrorMessage); + } + + [Fact] + public void Length_Constructor_WithPositiveInfinityValueInput_ThrowsException() + { + var exception = Assert.Throws(() => _ = + Length.From(double.PositiveInfinity) + ); + + Assert.Equal("Could not create a Nox type as value Infinity is not allowed.", exception.Errors.First().ErrorMessage); + } + + [Fact] + public void Length_Constructor_WithNegativeInfinityValueInput_ThrowsException() + { + var exception = Assert.Throws(() => _ = + Length.From(double.NegativeInfinity) + ); + + Assert.Equal("Could not create a Nox type as value Infinity is not allowed.", exception.Errors.First().ErrorMessage); + } + + [Fact] + public void Length_Constructor_WithWithUnsupportedUnitInput_ThrowsException() + { + var exception = Assert.Throws(() => _ = + Length.From(95.755663, (LengthTypeUnit)1001) + ); + + Assert.Equal("Could not create a Nox Length type as unit 1001 is not supported.", exception.Errors.First().ErrorMessage); + } + + + [Fact] + public void Length_ToMeters_ReturnsValueInMeters() + { + var length = Length.FromMeters(95.755663); + + Assert.Equal(95.755663, length.ToMeters()); + } + + [Fact] + public void Length_ToFeet_ReturnsValueInFeet() + { + var length = Length.FromMeters(95.755663); + + Assert.Equal(314.158999, length.ToFeet()); + } + + [Fact] + public void Length_ValueInMeters_ToString_ReturnsValueAndUnit() + { + void Test() + { + var length = Length.FromMeters(95.755663); + Assert.Equal("95.755663 m", length.ToString()); + } + TestUtility.RunInInvariantCulture(Test); + } + + [Fact] + public void Length_ValueInFeet_ToString_ReturnsValueAndUnit() + { + void Test() + { + var length = Length.FromFeet(314.158999); + Assert.Equal("314.158999 ft", length.ToString()); + } + TestUtility.RunInInvariantCulture(Test); + } + + [Fact] + public void Length_Equality_SpecifyingLengthUnit_WithSameUnit_Tests() + { + var length1 = Length.FromMeters(95.755663); + + var length2 = Length.FromMeters(95.755663); + + AssertAreEquivalent(length1, length2); + } + + [Fact] + public void Length_Equality_SpecifyingLengthUnit_WithDifferentUnit_Tests() + { + var length1 = Length.FromMeters(95.755663); + + var length2 = Length.FromFeet(314.158999); + + AssertAreEquivalent(length1, length2); + } + + [Fact] + public void Length_NonEquality_SpecifyingLengthUnit_WithSameUnit_Tests() + { + var length1 = Length.FromMeters(95.755663); + + var length2 = Length.FromMeters(314.158999); + + AssertAreNotEquivalent(length1, length2); + } + + [Fact] + public void Length_NonEquality_SpecifyingLengthUnit_WithDifferentUnit_Tests() + { + var length1 = Length.FromMeters(95.755663); + + var length2 = Length.FromFeet(95.755663); + + AssertAreNotEquivalent(length1, length2); + } + + private static void AssertAreEquivalent(Length expected, Length actual) + { + Assert.Equal(expected, actual); + + Assert.True(expected.Equals(actual)); + + Assert.True(actual.Equals(expected)); + + Assert.True(expected == actual); + + Assert.False(expected != actual); + } + + private static void AssertAreNotEquivalent(Length expected, Length actual) + { + Assert.NotEqual(expected, actual); + + Assert.False(expected.Equals(actual)); + + Assert.False(actual.Equals(expected)); + + Assert.False(expected == actual); + + Assert.True(expected != actual); } } \ No newline at end of file From fe272aefe9104647373c3d6c7447acbe4e23a27e Mon Sep 17 00:00:00 2001 From: Dejan Bratic Date: Wed, 28 Jun 2023 14:48:37 +0200 Subject: [PATCH 2/5] added EF converter and tests; --- .../Types/Length/LengthConverter.cs | 12 ++++++++++++ .../Configuration/CountryDbConfiguration.cs | 1 + .../EntityFrameworkTests/Models/Country.cs | 5 +++++ .../NoxTypesEntityFrameworkTests.cs | 4 ++++ 4 files changed, 22 insertions(+) create mode 100644 src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs diff --git a/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs b/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs new file mode 100644 index 0000000..6399dca --- /dev/null +++ b/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Nox.Types.EntityFramework.Types; + +public class LengthToFootConverter : ValueConverter +{ + public LengthToFootConverter() : base(length => (double)length.ToFeet(), lengthValue => Length.FromFeet(lengthValue)) { } +} +public class LengthToMeterConverter : ValueConverter +{ + public LengthToMeterConverter() : base(lemgth => (double)lemgth.ToMeters(), lengthValue => Length.FromMeters(lengthValue)) { } +} diff --git a/tests/Nox.Types.Tests/EntityFrameworkTests/Configuration/CountryDbConfiguration.cs b/tests/Nox.Types.Tests/EntityFrameworkTests/Configuration/CountryDbConfiguration.cs index 2691ad3..c91dba9 100644 --- a/tests/Nox.Types.Tests/EntityFrameworkTests/Configuration/CountryDbConfiguration.cs +++ b/tests/Nox.Types.Tests/EntityFrameworkTests/Configuration/CountryDbConfiguration.cs @@ -23,6 +23,7 @@ public void Configure(EntityTypeBuilder builder) builder.Property(e => e.InternetDomain).HasConversion(); builder.Property(e => e.CountryCode3).HasConversion(); builder.Property(e => e.IPAddress).HasConversion(); + builder.Property(e => e.LongestHikingTrailInMeters).HasConversion(); // Configure Multi-value ValueObjects builder.OwnsOne(e => e.LatLong).Ignore(p => p.Value); diff --git a/tests/Nox.Types.Tests/EntityFrameworkTests/Models/Country.cs b/tests/Nox.Types.Tests/EntityFrameworkTests/Models/Country.cs index b02ced5..63efd5f 100644 --- a/tests/Nox.Types.Tests/EntityFrameworkTests/Models/Country.cs +++ b/tests/Nox.Types.Tests/EntityFrameworkTests/Models/Country.cs @@ -77,4 +77,9 @@ public sealed class Country /// Gets or sets the IP Address. /// public IpAddress IPAddress { get; set; } = null!; + + /// + /// Gets or sets the longest hiking trail in meters. + /// + public Length LongestHikingTrailInMeters { get; set; } = null!; } diff --git a/tests/Nox.Types.Tests/EntityFrameworkTests/NoxTypesEntityFrameworkTests.cs b/tests/Nox.Types.Tests/EntityFrameworkTests/NoxTypesEntityFrameworkTests.cs index b51ab1c..5b1a538 100644 --- a/tests/Nox.Types.Tests/EntityFrameworkTests/NoxTypesEntityFrameworkTests.cs +++ b/tests/Nox.Types.Tests/EntityFrameworkTests/NoxTypesEntityFrameworkTests.cs @@ -39,6 +39,7 @@ public void Countries_CanRead_LatLong() CountryCode3 = CountryCode3.From("CHE"), IPAddress = IpAddress.From("102.129.143.255"), DateTimeRange = DateTimeRange.From(new DateTime(2023, 01, 01), new DateTime(2023, 02, 01)), + LongestHikingTrailInMeters = Length.From(390_000), }; DbContext.Countries.Add(newItem); DbContext.SaveChanges(); @@ -70,6 +71,7 @@ public void AddedItemShouldGetGeneratedId() InternetDomain = InternetDomain.From("admin.ch"), CountryCode3 = CountryCode3.From("CHE"), IPAddress = IpAddress.From("102.129.143.255"), + LongestHikingTrailInMeters = Length.From(390_000), }; DbContext.Countries.Add(newItem); DbContext.SaveChanges(); @@ -102,5 +104,7 @@ public void AddedItemShouldGetGeneratedId() Assert.Equal("102.129.143.255", item.IPAddress.Value); Assert.Equal(new DateTime(2023, 01, 01), item.DateTimeRange.Start); Assert.Equal(new DateTime(2023, 02, 01), item.DateTimeRange.End); + Assert.Equal(390_000, item.LongestHikingTrailInMeters.Value); + Assert.Equal(LengthTypeUnit.Meter, item.LongestHikingTrailInMeters.Unit); } } From cc62028c18142f1eae96920590bf6d23b5921266 Mon Sep 17 00:00:00 2001 From: Dejan Bratic Date: Wed, 28 Jun 2023 14:50:07 +0200 Subject: [PATCH 3/5] fixed typo; --- src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs b/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs index 6399dca..a99295b 100644 --- a/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs +++ b/src/Nox.Types.EntityFramework/Types/Length/LengthConverter.cs @@ -8,5 +8,5 @@ public LengthToFootConverter() : base(length => (double)length.ToFeet(), lengthV } public class LengthToMeterConverter : ValueConverter { - public LengthToMeterConverter() : base(lemgth => (double)lemgth.ToMeters(), lengthValue => Length.FromMeters(lengthValue)) { } + public LengthToMeterConverter() : base(length => (double)length.ToMeters(), lengthValue => Length.FromMeters(lengthValue)) { } } From 7bdcafe1021a421a7720a965e3e92a91482d7ca4 Mon Sep 17 00:00:00 2001 From: Dejan Bratic Date: Thu, 29 Jun 2023 11:53:47 +0200 Subject: [PATCH 4/5] added changes related to PR comments; --- .../Common/MeasurementConversionFactor.cs | 67 +++------ src/Nox.Types/Common/MeasurementTypeUnit.cs | 14 ++ src/Nox.Types/Nox.Types.csproj | 1 + src/Nox.Types/Types/Area/Area.cs | 14 +- src/Nox.Types/Types/Area/AreaTypeUnit.cs | 4 +- src/Nox.Types/Types/Distance/Distance.cs | 14 +- .../Types/Distance/DistanceTypeUnit.cs | 4 +- src/Nox.Types/Types/Length/Length.cs | 16 ++- src/Nox.Types/Types/Length/LengthTypeUnit.cs | 4 +- .../MeasurementConversionFactorTests.cs | 16 +-- tests/Nox.Types.Tests/Types/Area/AreaTests.cs | 48 +++++-- .../Types/Distance/DistanceTests.cs | 48 ++++++- .../Types/Length/LengthTests.cs | 132 +++++++++++------- 13 files changed, 247 insertions(+), 135 deletions(-) create mode 100644 src/Nox.Types/Common/MeasurementTypeUnit.cs diff --git a/src/Nox.Types/Common/MeasurementConversionFactor.cs b/src/Nox.Types/Common/MeasurementConversionFactor.cs index 7d41d8b..43fe3c5 100644 --- a/src/Nox.Types/Common/MeasurementConversionFactor.cs +++ b/src/Nox.Types/Common/MeasurementConversionFactor.cs @@ -1,66 +1,37 @@ using System; -using System.Linq; +using System.Collections.Generic; namespace Nox.Common; -public class MeasurementConversionFactor +internal sealed class MeasurementConversionFactor { - private const string Foot = "Foot"; - private const string Meter = "Meter"; - private const string Kilometer = "Kilometer"; - private const string Mile = "Mile"; - private static readonly string[] _lengthUnits = new[] { Foot, Meter, Kilometer, Mile }; - - private const string SquareFoot = "SquareFoot"; - private const string SquareMeter = "SquareMeter"; - private static readonly string[] _areaUnits = new[] { SquareFoot, SquareMeter }; + private static readonly Dictionary<(MeasurementTypeUnit, MeasurementTypeUnit), double> DefinedConversionFactors = new() + { + { (MeasurementTypeUnit.Foot, MeasurementTypeUnit.Meter), 0.30480000033}, + { (MeasurementTypeUnit.Meter, MeasurementTypeUnit.Foot), 3.28083989142}, + { (MeasurementTypeUnit.Kilometer, MeasurementTypeUnit.Mile), 0.62137119102}, + { (MeasurementTypeUnit.Mile, MeasurementTypeUnit.Kilometer), 1.60934400315}, + { (MeasurementTypeUnit.SquareFoot, MeasurementTypeUnit.SquareMeter), 0.09290304}, + { (MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.SquareFoot), 10.76391042}, + }; public double Value { get; } - public MeasurementConversionFactor(Enum sourceUnit, Enum targetUnit) - : this(sourceUnit.ToString(), targetUnit.ToString()) + public MeasurementConversionFactor(MeasurementTypeUnit sourceUnit, MeasurementTypeUnit targetUnit) { + Value = ResolveConversionFactor(sourceUnit, targetUnit); } - public MeasurementConversionFactor(string sourceUnit, string targetUnit) + private static double ResolveConversionFactor(MeasurementTypeUnit sourceUnit, MeasurementTypeUnit targetUnit) { - Value = ResolveConversionFactor(sourceUnit, targetUnit) - ?? throw new NotImplementedException($"No conversion defined from {sourceUnit} to {targetUnit}."); - } + var conversion = (sourceUnit, targetUnit); - private double? ResolveConversionFactor(string sourceUnit, string targetUnit) - { - return IsSupported(sourceUnit) && IsSupported(targetUnit) - ? ResolveConversionFactorForSupportedUnits(sourceUnit, targetUnit) - : null; - } + if (DefinedConversionFactors.ContainsKey(conversion)) + return DefinedConversionFactors[conversion]; - private bool IsSupported(string unit) - => _lengthUnits.Contains(unit) || _areaUnits.Contains(unit); - - private double? ResolveConversionFactorForSupportedUnits(string sourceUnit, string targetUnit) - { - if (sourceUnit == targetUnit) + else if (sourceUnit == targetUnit) return 1; - else if (sourceUnit == Foot && targetUnit == Meter) - return 0.30480000033; - - else if (sourceUnit == Meter && targetUnit == Foot) - return 3.28083989142; - - else if (sourceUnit == Kilometer && targetUnit == Mile) - return 0.62137119102; - - else if (sourceUnit == Mile && targetUnit == Kilometer) - return 1.60934400315; - - else if (sourceUnit == SquareFoot && targetUnit == SquareMeter) - return 0.09290304; - - else if (sourceUnit == SquareMeter && targetUnit == SquareFoot) - return 10.76391042; - - return null; + throw new NotImplementedException($"No conversion defined from {sourceUnit} to {targetUnit}."); } } diff --git a/src/Nox.Types/Common/MeasurementTypeUnit.cs b/src/Nox.Types/Common/MeasurementTypeUnit.cs new file mode 100644 index 0000000..ebdc93b --- /dev/null +++ b/src/Nox.Types/Common/MeasurementTypeUnit.cs @@ -0,0 +1,14 @@ +namespace Nox.Common; + +internal enum MeasurementTypeUnit +{ + // Length + Foot = 1, + Meter = 2, + Kilometer = 3, + Mile = 4, + + // Area + SquareFoot = 5, + SquareMeter = 6, +} diff --git a/src/Nox.Types/Nox.Types.csproj b/src/Nox.Types/Nox.Types.csproj index 1075134..cc2f7be 100644 --- a/src/Nox.Types/Nox.Types.csproj +++ b/src/Nox.Types/Nox.Types.csproj @@ -24,5 +24,6 @@ + diff --git a/src/Nox.Types/Types/Area/Area.cs b/src/Nox.Types/Types/Area/Area.cs index 7d1eef6..883bc76 100644 --- a/src/Nox.Types/Types/Area/Area.cs +++ b/src/Nox.Types/Types/Area/Area.cs @@ -1,6 +1,7 @@ using Nox.Common; using System; using System.Collections.Generic; +using System.Globalization; namespace Nox.Types; @@ -92,7 +93,16 @@ internal override ValidationResult Validate() return result; } - public override string ToString() => $"{Value:G} {Unit.ToSymbol()}"; + public override string ToString() + => $"{Value.ToString($"0.{new string('#', QuantityValueDecimalPrecision)}", CultureInfo.InvariantCulture)} {Unit.ToSymbol()}"; + + /// + /// Returns a string representation of the object using the specified . + /// + /// The format provider for the length value. + /// A string representation of the object with the value formatted using the specified . + public string ToString(IFormatProvider formatProvider) + => $"{Value.ToString(formatProvider)} {Unit.ToSymbol()}"; protected override IEnumerable> GetEqualityComponents() { @@ -107,7 +117,7 @@ protected override IEnumerable> GetEqualityComponen private QuantityValue GetAreaIn(AreaTypeUnit targetUnit) { - var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + var factor = new MeasurementConversionFactor((MeasurementTypeUnit)Unit, (MeasurementTypeUnit)targetUnit).Value; return Round(Value * factor); } diff --git a/src/Nox.Types/Types/Area/AreaTypeUnit.cs b/src/Nox.Types/Types/Area/AreaTypeUnit.cs index ad55f08..55b1f04 100644 --- a/src/Nox.Types/Types/Area/AreaTypeUnit.cs +++ b/src/Nox.Types/Types/Area/AreaTypeUnit.cs @@ -4,8 +4,8 @@ namespace Nox.Types; public enum AreaTypeUnit { - SquareFoot, - SquareMeter, + SquareFoot = 5, + SquareMeter = 6, } public static class AreaTypeUnitExtensions diff --git a/src/Nox.Types/Types/Distance/Distance.cs b/src/Nox.Types/Types/Distance/Distance.cs index 9f25b37..57a6580 100644 --- a/src/Nox.Types/Types/Distance/Distance.cs +++ b/src/Nox.Types/Types/Distance/Distance.cs @@ -1,6 +1,7 @@ using Nox.Common; using System; using System.Collections.Generic; +using System.Globalization; namespace Nox.Types; @@ -113,7 +114,16 @@ protected override IEnumerable> GetEqualityComponen yield return new KeyValuePair(nameof(Value), ToKilometers()); } - public override string ToString() => $"{Value:G} {Unit.ToSymbol()}"; + public override string ToString() + => $"{Value.ToString($"0.{new string('#', QuantityValueDecimalPrecision)}", CultureInfo.InvariantCulture)} {Unit.ToSymbol()}"; + + /// + /// Returns a string representation of the object using the specified . + /// + /// The format provider for the length value. + /// A string representation of the object with the value formatted using the specified . + public string ToString(IFormatProvider formatProvider) + => $"{Value.ToString(formatProvider)} {Unit.ToSymbol()}"; private QuantityValue? _kilometers; @@ -125,7 +135,7 @@ protected override IEnumerable> GetEqualityComponen private QuantityValue GetDistanceIn(DistanceTypeUnit targetUnit) { - var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + var factor = new MeasurementConversionFactor((MeasurementTypeUnit)Unit, (MeasurementTypeUnit)targetUnit).Value; return Round(Value * factor); } diff --git a/src/Nox.Types/Types/Distance/DistanceTypeUnit.cs b/src/Nox.Types/Types/Distance/DistanceTypeUnit.cs index 007028e..b3b16e3 100644 --- a/src/Nox.Types/Types/Distance/DistanceTypeUnit.cs +++ b/src/Nox.Types/Types/Distance/DistanceTypeUnit.cs @@ -4,8 +4,8 @@ namespace Nox.Types; public enum DistanceTypeUnit { - Kilometer, - Mile + Kilometer = 3, + Mile = 4, } public static class DistanceTypeUnitExtensions diff --git a/src/Nox.Types/Types/Length/Length.cs b/src/Nox.Types/Types/Length/Length.cs index 217c656..6e1307e 100644 --- a/src/Nox.Types/Types/Length/Length.cs +++ b/src/Nox.Types/Types/Length/Length.cs @@ -1,6 +1,7 @@ using Nox.Common; using System; using System.Collections.Generic; +using System.Globalization; namespace Nox.Types; @@ -75,7 +76,7 @@ internal override ValidationResult Validate() { var result = Value.Validate(); - if (Value < 0) + if (Value < 0 && !double.IsNaN((double)Value) && !double.IsInfinity((double)Value)) { result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Length type as negative length value {Value} is not allowed.")); } @@ -93,9 +94,16 @@ protected override IEnumerable> GetEqualityComponen yield return new KeyValuePair(nameof(Value), ToMeters()); } - public override string ToString() - => $"{Value:G} {Unit.ToSymbol()}"; + => $"{Value.ToString($"0.{new string('#', QuantityValueDecimalPrecision)}", CultureInfo.InvariantCulture)} {Unit.ToSymbol()}"; + + /// + /// Returns a string representation of the object using the specified . + /// + /// The format provider for the length value. + /// A string representation of the object with the value formatted using the specified . + public string ToString(IFormatProvider formatProvider) + => $"{Value.ToString(formatProvider)} {Unit.ToSymbol()}"; private QuantityValue? _meters; @@ -109,7 +117,7 @@ public QuantityValue ToFeet() private QuantityValue GetLengthIn(LengthTypeUnit targetUnit) { - var factor = new MeasurementConversionFactor(Unit, targetUnit).Value; + var factor = new MeasurementConversionFactor((MeasurementTypeUnit)Unit, (MeasurementTypeUnit)targetUnit).Value; return Round(Value * factor); } diff --git a/src/Nox.Types/Types/Length/LengthTypeUnit.cs b/src/Nox.Types/Types/Length/LengthTypeUnit.cs index 9cc6c04..1f8bc04 100644 --- a/src/Nox.Types/Types/Length/LengthTypeUnit.cs +++ b/src/Nox.Types/Types/Length/LengthTypeUnit.cs @@ -4,8 +4,8 @@ namespace Nox.Types; public enum LengthTypeUnit { - Foot, - Meter + Foot = 1, + Meter = 2, } public static class LengthTypeUnitExtensions diff --git a/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs index 8fe7d41..2af01e4 100644 --- a/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs +++ b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs @@ -7,7 +7,7 @@ public class MeasurementConversionFactorTests [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromFootToMeter_ReturnsValue() { - var factor = new MeasurementConversionFactor("Foot", "Meter"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Foot, MeasurementTypeUnit.Meter); Assert.Equal(0.30480000033, factor.Value); } @@ -15,7 +15,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromFootToMeter_Returns [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromMeterToFoot_ReturnsValue() { - var factor = new MeasurementConversionFactor("Meter", "Foot"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Meter, MeasurementTypeUnit.Foot); Assert.Equal(3.28083989142, factor.Value); } @@ -23,7 +23,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromMeterToFoot_Returns [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromKilometerToMile_ReturnsValue() { - var factor = new MeasurementConversionFactor("Kilometer", "Mile"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Kilometer, MeasurementTypeUnit.Mile); Assert.Equal(0.62137119102, factor.Value); } @@ -31,7 +31,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromKilometerToMile_Ret [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromMileToKilometer_ReturnsValue() { - var factor = new MeasurementConversionFactor("Mile", "Kilometer"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Mile, MeasurementTypeUnit.Kilometer); Assert.Equal(1.60934400315, factor.Value); } @@ -39,7 +39,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromMileToKilometer_Ret [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromSquareFootToSquareMeter_ReturnsValue() { - var factor = new MeasurementConversionFactor("SquareFoot", "SquareMeter"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.SquareFoot, MeasurementTypeUnit.SquareMeter); Assert.Equal(0.09290304, factor.Value); } @@ -47,7 +47,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromSquareFootToSquareM [Fact] public void MeasurementUnitConverter_GetConversionFactor_FromSquareMeterToSquareFoot_ReturnsValue() { - var factor = new MeasurementConversionFactor("SquareMeter", "SquareFoot"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.SquareFoot); Assert.Equal(10.76391042, factor.Value); } @@ -55,7 +55,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromSquareMeterToSquare [Fact] public void MeasurementUnitConverter_GetConversionFactor_WithSameSourceAndTargetUnit_ReturnsValue() { - var factor = new MeasurementConversionFactor("Foot", "Foot"); + var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Foot, MeasurementTypeUnit.Foot); Assert.Equal(1, factor.Value); } @@ -64,7 +64,7 @@ public void MeasurementUnitConverter_GetConversionFactor_WithSameSourceAndTarget public void MeasurementUnitConverter_GetConversionFactor_WithUnsupportedConversion_ThrowsException() { var exception = Assert.Throws(() => _ = - new MeasurementConversionFactor("SquareMeter", "Meter") + new MeasurementConversionFactor(MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.Meter) ); Assert.Equal("No conversion defined from SquareMeter to Meter.", exception.Message); diff --git a/tests/Nox.Types.Tests/Types/Area/AreaTests.cs b/tests/Nox.Types.Tests/Types/Area/AreaTests.cs index 7ef17e3..09e13a7 100644 --- a/tests/Nox.Types.Tests/Types/Area/AreaTests.cs +++ b/tests/Nox.Types.Tests/Types/Area/AreaTests.cs @@ -1,3 +1,5 @@ +using System.Globalization; + namespace Nox.Types.Tests.Types; public class AreaTests @@ -145,30 +147,60 @@ public void Area_ToSquareFeet_ReturnsValue() Assert.Equal(134.54888, area.ToSquareFeet()); } - [Fact] - public void Area_ValueInSquareMeters_ToString_ReturnsString() + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Area_ValueInSquareMeters_ToString_IsCultureIndepdendent(string culture) { void Test() { var area = Area.FromSquareMeters(12.5); - Assert.Equal("12.5 m²", area.ToString()); } - TestUtility.RunInInvariantCulture(Test); + TestUtility.RunInCulture(Test, culture); } - [Fact] - public void Area_ValueInSquareFeet_ToString_ReturnsString() + [Theory] + [InlineData("en-US", "12.5 m²")] + [InlineData("pt-PT", "12,5 m²")] + public void Area_ValueInSquareMeters_ToString_IsCultureDependent(string culture, string expected) { void Test() { - var area = Area.FromSquareFeet(134.548880); + var area = Area.FromSquareMeters(12.5); + Assert.Equal(expected, area.ToString(new CultureInfo(culture))); + } + + TestUtility.RunInCulture(Test, culture); + } + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Area_ValueInSquareFeet_ToString_IsCultureIndependent(string culture) + { + void Test() + { + var area = Area.FromSquareFeet(134.548880); Assert.Equal("134.54888 ft²", area.ToString()); } - TestUtility.RunInInvariantCulture(Test); + TestUtility.RunInCulture(Test, culture); + } + + [Theory] + [InlineData("en-US", "134.54888 ft²")] + [InlineData("pt-PT", "134,54888 ft²")] + public void Area_ValueInSquareFeet_ToString_IsCultureDependent(string culture, string expected) + { + void Test() + { + var area = Area.FromSquareFeet(134.548880); + Assert.Equal(expected, area.ToString(new CultureInfo(culture))); + } + + TestUtility.RunInCulture(Test, culture); } [Fact] diff --git a/tests/Nox.Types.Tests/Types/Distance/DistanceTests.cs b/tests/Nox.Types.Tests/Types/Distance/DistanceTests.cs index 537a1df..58e92d1 100644 --- a/tests/Nox.Types.Tests/Types/Distance/DistanceTests.cs +++ b/tests/Nox.Types.Tests/Types/Distance/DistanceTests.cs @@ -1,4 +1,6 @@ -namespace Nox.Types.Tests.Types; +using System.Globalization; + +namespace Nox.Types.Tests.Types; public class DistanceTests { @@ -128,8 +130,10 @@ public void Distance_ToMiles_ReturnsValueInMiles() Assert.Equal(195.209352, distance.ToMiles()); } - [Fact] - public void Distance_ValueInKilometers_ToString_ReturnsValueAndUnit() + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Distance_ValueInKilometers_ToString_IsCultureIndepdendent(string culture) { void Test() { @@ -137,11 +141,27 @@ void Test() Assert.Equal("314.159 km", distance.ToString()); } - TestUtility.RunInInvariantCulture(Test); + TestUtility.RunInCulture(Test, culture); } - [Fact] - public void Distance_ValueInMiles_ToString_ReturnsValueAndUnit() + [Theory] + [InlineData("en-US", "314.159 km")] + [InlineData("pt-PT", "314,159 km")] + public void Distance_ValueInKilometers_ToString_IsCultureDependent(string culture, string expected) + { + void Test() + { + var distance = Distance.FromKilometers(314.159); + Assert.Equal(expected, distance.ToString(new CultureInfo(culture))); + } + + TestUtility.RunInCulture(Test, culture); + } + + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Distance_ValueInMiles_ToString_IsCultureIndependent(string culture) { void Test() { @@ -149,7 +169,21 @@ void Test() Assert.Equal("195.209 mi", distance.ToString()); } - TestUtility.RunInInvariantCulture(Test); + TestUtility.RunInCulture(Test, culture); + } + + [Theory] + [InlineData("en-US", "195.209 mi")] + [InlineData("pt-PT", "195,209 mi")] + public void Distance_ValueInMiles_ToString_IsCultureDependent(string culture, string expected) + { + void Test() + { + var distance = Distance.FromMiles(195.209); + Assert.Equal(expected, distance.ToString(new CultureInfo(culture))); + } + + TestUtility.RunInCulture(Test, culture); } [Fact] diff --git a/tests/Nox.Types.Tests/Types/Length/LengthTests.cs b/tests/Nox.Types.Tests/Types/Length/LengthTests.cs index 39818f1..e5ca74d 100644 --- a/tests/Nox.Types.Tests/Types/Length/LengthTests.cs +++ b/tests/Nox.Types.Tests/Types/Length/LengthTests.cs @@ -1,4 +1,7 @@ // ReSharper disable once CheckNamespace +using FluentAssertions; +using System.Globalization; + namespace Nox.Types.Tests.Types; public class LengthTests @@ -8,8 +11,8 @@ public void Length_Constructor_ReturnsSameValueAndDefaultUnit() { var length = Length.From(95.755663); - Assert.Equal(95.755663, length.Value); - Assert.Equal(LengthTypeUnit.Meter, length.Unit); + length.Value.Should().Be(95.755663); + length.Unit.Should().Be(LengthTypeUnit.Meter); } [Fact] @@ -17,8 +20,8 @@ public void Length_Constructor_WithUnit_ReturnsSameValueAndUnit() { var length = Length.From(314.158999, LengthTypeUnit.Foot); - Assert.Equal(314.158999, length.Value); - Assert.Equal(LengthTypeUnit.Foot, length.Unit); + length.Value.Should().Be(314.158999); + length.Unit.Should().Be(LengthTypeUnit.Foot); } [Fact] @@ -26,8 +29,8 @@ public void Length_Constructor_WithUnitInFeet_ReturnsSameValueAndUnit() { var length = Length.FromFeet(314.158999); - Assert.Equal(314.158999, length.Value); - Assert.Equal(LengthTypeUnit.Foot, length.Unit); + length.Value.Should().Be(314.158999); + length.Unit.Should().Be(LengthTypeUnit.Foot); } [Fact] @@ -35,67 +38,62 @@ public void Length_Constructor_WithUnitInMeters_ReturnsSameValueAndUnit() { var length = Length.FromMeters(95.755663); - Assert.Equal(95.755663, length.Value); - Assert.Equal(LengthTypeUnit.Meter, length.Unit); + length.Value.Should().Be(95.755663); + length.Unit.Should().Be(LengthTypeUnit.Meter); } [Fact] public void Length_Constructor_WithNegativeValueInput_ThrowsException() { - var exception = Assert.Throws(() => _ = - Length.From(-100) - ); + var action = () => Length.From(-100); - Assert.Equal("Could not create a Nox Length type as negative length value -100 is not allowed.", exception.Errors.First().ErrorMessage); + action.Should().Throw() + .And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox Length type as negative length value -100 is not allowed.") }); } [Fact] public void Length_Constructor_WithNaNValueInput_ThrowsException() { - var exception = Assert.Throws(() => _ = - Length.From(double.NaN) - ); + var action = () => Length.From(double.NaN); - Assert.Equal("Could not create a Nox type as value NaN is not allowed.", exception.Errors.First().ErrorMessage); + action.Should().Throw() + .And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox type as value NaN is not allowed.") }); } [Fact] public void Length_Constructor_WithPositiveInfinityValueInput_ThrowsException() { - var exception = Assert.Throws(() => _ = - Length.From(double.PositiveInfinity) - ); + var action = () => Length.From(double.PositiveInfinity); + - Assert.Equal("Could not create a Nox type as value Infinity is not allowed.", exception.Errors.First().ErrorMessage); + action.Should().Throw() + .And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox type as value Infinity is not allowed.") }); } [Fact] public void Length_Constructor_WithNegativeInfinityValueInput_ThrowsException() { - var exception = Assert.Throws(() => _ = - Length.From(double.NegativeInfinity) - ); + var action = () => Length.From(double.NegativeInfinity); - Assert.Equal("Could not create a Nox type as value Infinity is not allowed.", exception.Errors.First().ErrorMessage); + action.Should().Throw() + .And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox type as value Infinity is not allowed.") }); } [Fact] public void Length_Constructor_WithWithUnsupportedUnitInput_ThrowsException() { - var exception = Assert.Throws(() => _ = - Length.From(95.755663, (LengthTypeUnit)1001) - ); + var action = () => Length.From(95.755663, (LengthTypeUnit)1001); - Assert.Equal("Could not create a Nox Length type as unit 1001 is not supported.", exception.Errors.First().ErrorMessage); + action.Should().Throw() + .And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Unit", "Could not create a Nox Length type as unit 1001 is not supported.") }); } - [Fact] public void Length_ToMeters_ReturnsValueInMeters() { var length = Length.FromMeters(95.755663); - Assert.Equal(95.755663, length.ToMeters()); + length.ToMeters().Should().Be(95.755663); } [Fact] @@ -103,29 +101,63 @@ public void Length_ToFeet_ReturnsValueInFeet() { var length = Length.FromMeters(95.755663); - Assert.Equal(314.158999, length.ToFeet()); + length.ToFeet().Should().Be(314.158999); } - [Fact] - public void Length_ValueInMeters_ToString_ReturnsValueAndUnit() + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Length_ValueInMeters_ToString_IsCultureIndepdendent(string culture) { void Test() { var length = Length.FromMeters(95.755663); - Assert.Equal("95.755663 m", length.ToString()); + length.ToString().Should().Be("95.755663 m"); } - TestUtility.RunInInvariantCulture(Test); + + TestUtility.RunInCulture(Test, culture); } - [Fact] - public void Length_ValueInFeet_ToString_ReturnsValueAndUnit() + [Theory] + [InlineData("en-US", "95.755663 m")] + [InlineData("pt-PT", "95,755663 m")] + public void Length_ValueInMeters_ToString_IsCultureDependent(string culture, string expected) + { + void Test() + { + var length = Length.FromMeters(95.755663); + length.ToString(new CultureInfo(culture)).Should().Be(expected); + } + + TestUtility.RunInCulture(Test, culture); + } + + [Theory] + [InlineData("en-US")] + [InlineData("pt-PT")] + public void Length_ValueInFeet_ToString_IsCultureIndependent(string culture) { void Test() { var length = Length.FromFeet(314.158999); - Assert.Equal("314.158999 ft", length.ToString()); + length.ToString().Should().Be("314.158999 ft"); } - TestUtility.RunInInvariantCulture(Test); + + TestUtility.RunInCulture(Test, culture); + } + + [Theory] + [InlineData("en-US", "314.158999 ft")] + [InlineData("pt-PT", "314,158999 ft")] + public void Length_ValueInFeet_ToString_IsCultureDependent(string culture, string expected) + { + void Test() + { + var length = Length.FromFeet(314.158999); + length.ToString(new CultureInfo(culture)).Should().Be(expected); + } + + TestUtility.RunInCulture(Test, culture); } [Fact] @@ -170,27 +202,27 @@ public void Length_NonEquality_SpecifyingLengthUnit_WithDifferentUnit_Tests() private static void AssertAreEquivalent(Length expected, Length actual) { - Assert.Equal(expected, actual); + actual.Should().Be(expected); - Assert.True(expected.Equals(actual)); + expected.Equals(actual).Should().BeTrue(); - Assert.True(actual.Equals(expected)); + actual.Equals(expected).Should().BeTrue(); - Assert.True(expected == actual); + (expected == actual).Should().BeTrue(); - Assert.False(expected != actual); + (expected != actual).Should().BeFalse(); } private static void AssertAreNotEquivalent(Length expected, Length actual) { - Assert.NotEqual(expected, actual); + actual.Should().NotBe(expected); - Assert.False(expected.Equals(actual)); + expected.Equals(actual).Should().BeFalse(); - Assert.False(actual.Equals(expected)); + actual.Equals(expected).Should().BeFalse(); - Assert.False(expected == actual); + (expected == actual).Should().BeFalse(); - Assert.True(expected != actual); + (expected != actual).Should().BeTrue(); } -} \ No newline at end of file +} From 30fd4f5c6034bbf0c5bd7049fec27309d9b6156d Mon Sep 17 00:00:00 2001 From: Dejan Bratic Date: Thu, 29 Jun 2023 16:18:01 +0200 Subject: [PATCH 5/5] added unit tests for measurement related enum comparisson; --- .../MeasurementConversionFactorTests.cs | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs index 2af01e4..fa48e1f 100644 --- a/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs +++ b/tests/Nox.Types.Tests/Common/MeasurementConversionFactorTests.cs @@ -1,4 +1,5 @@ -using Nox.Common; +using FluentAssertions; +using Nox.Common; namespace Nox.Types.Tests.Common; @@ -9,7 +10,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromFootToMeter_Returns { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Foot, MeasurementTypeUnit.Meter); - Assert.Equal(0.30480000033, factor.Value); + factor.Value.Should().Be(0.30480000033); } [Fact] @@ -17,7 +18,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromMeterToFoot_Returns { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Meter, MeasurementTypeUnit.Foot); - Assert.Equal(3.28083989142, factor.Value); + factor.Value.Should().Be(3.28083989142); } [Fact] @@ -25,7 +26,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromKilometerToMile_Ret { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Kilometer, MeasurementTypeUnit.Mile); - Assert.Equal(0.62137119102, factor.Value); + factor.Value.Should().Be(0.62137119102); } [Fact] @@ -33,7 +34,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromMileToKilometer_Ret { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Mile, MeasurementTypeUnit.Kilometer); - Assert.Equal(1.60934400315, factor.Value); + factor.Value.Should().Be(1.60934400315); } [Fact] @@ -41,7 +42,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromSquareFootToSquareM { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.SquareFoot, MeasurementTypeUnit.SquareMeter); - Assert.Equal(0.09290304, factor.Value); + factor.Value.Should().Be(0.09290304); } [Fact] @@ -49,7 +50,7 @@ public void MeasurementUnitConverter_GetConversionFactor_FromSquareMeterToSquare { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.SquareFoot); - Assert.Equal(10.76391042, factor.Value); + factor.Value.Should().Be(10.76391042); } [Fact] @@ -57,16 +58,51 @@ public void MeasurementUnitConverter_GetConversionFactor_WithSameSourceAndTarget { var factor = new MeasurementConversionFactor(MeasurementTypeUnit.Foot, MeasurementTypeUnit.Foot); - Assert.Equal(1, factor.Value); + factor.Value.Should().Be(1); } [Fact] public void MeasurementUnitConverter_GetConversionFactor_WithUnsupportedConversion_ThrowsException() { - var exception = Assert.Throws(() => _ = - new MeasurementConversionFactor(MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.Meter) - ); + var action = () => new MeasurementConversionFactor(MeasurementTypeUnit.SquareMeter, MeasurementTypeUnit.Meter); - Assert.Equal("No conversion defined from SquareMeter to Meter.", exception.Message); + action.Should().Throw() + .WithMessage("No conversion defined from SquareMeter to Meter."); + } + + [Fact] + public void MeasurementUnitType_Foot_ReturnsSameValueAsLengthTypeUnit() + { + ((int)MeasurementTypeUnit.Foot).Should().Be((int)LengthTypeUnit.Foot); + } + + [Fact] + public void MeasurementUnitType_Meter_ReturnsSameValueAsLengthTypeUnit() + { + ((int)MeasurementTypeUnit.Meter).Should().Be((int)LengthTypeUnit.Meter); + } + + [Fact] + public void MeasurementUnitType_Kilometer_ReturnsSameValueAsDistanceTypeUnit() + { + ((int)MeasurementTypeUnit.Kilometer).Should().Be((int)DistanceTypeUnit.Kilometer); + } + + [Fact] + public void MeasurementUnitType_Mile_ReturnsSameValueAsDistanceTypeUnit() + { + ((int)MeasurementTypeUnit.Mile).Should().Be((int)DistanceTypeUnit.Mile); + } + + [Fact] + public void MeasurementUnitType_SquareFoot_ReturnsSameValueAsLengthTypeUnit() + { + ((int)MeasurementTypeUnit.SquareFoot).Should().Be((int)AreaTypeUnit.SquareFoot); + } + + [Fact] + public void MeasurementUnitType_SquareMeter_ReturnsSameValueAsLengthTypeUnit() + { + ((int)MeasurementTypeUnit.SquareMeter).Should().Be((int)AreaTypeUnit.SquareMeter); } }