diff --git a/Source/Singulink.Globalization.Currency/Money.GenericMath.cs b/Source/Singulink.Globalization.Currency/Money.GenericMath.cs new file mode 100644 index 0000000..8b2d041 --- /dev/null +++ b/Source/Singulink.Globalization.Currency/Money.GenericMath.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +namespace Singulink.Globalization; + +#if NET7_0_OR_GREATER + +/// +/// Contains generic math implementation of . +/// +partial struct Money : + IAdditionOperators, + IAdditionOperators, + IComparisonOperators, + IDecrementOperators, + IDivisionOperators, + IDivisionOperators, + IIncrementOperators, + IMultiplyOperators, + ISubtractionOperators, + ISubtractionOperators, + IUnaryNegationOperators, + IUnaryPlusOperators; + +#endif \ No newline at end of file diff --git a/Source/Singulink.Globalization.Currency/Money.cs b/Source/Singulink.Globalization.Currency/Money.cs index 6a48cf1..44e9f46 100644 --- a/Source/Singulink.Globalization.Currency/Money.cs +++ b/Source/Singulink.Globalization.Currency/Money.cs @@ -133,25 +133,28 @@ public Currency Currency return x._amount >= y._amount; } - public static Money operator +(Money x, Money y) => CreateDefaultable(x._amount + y._amount, CombineCurrencies(x._currency, y._currency)); + public static Money operator +(Money x, Money y) => CreateDefaultable(x._amount + y._amount, CombineCurrenciesForAddOrSubtract(x._currency, y._currency)); public static Money operator +(Money x, decimal y) => CreateDefaultable(x._amount + y, x._currency); - public static Money operator +(decimal x, Money y) => y + x; - - public static Money operator -(Money x, Money y) => CreateDefaultable(x._amount - y._amount, CombineCurrencies(x._currency, y._currency)); + public static Money operator -(Money x, Money y) => CreateDefaultable(x._amount - y._amount, CombineCurrenciesForAddOrSubtract(x._currency, y._currency)); public static Money operator -(Money x, decimal y) => CreateDefaultable(x._amount - y, x._currency); - public static Money operator -(decimal x, Money y) => CreateDefaultable(x - y._amount, y._currency); - public static Money operator *(Money x, decimal y) => CreateDefaultable(x._amount * y, x._currency); - public static Money operator *(decimal x, Money y) => y * x; - public static Money operator /(Money x, decimal y) => CreateDefaultable(x._amount / y, x._currency); - public static Money operator /(decimal x, Money y) => CreateDefaultable(x / y._amount, y._currency); + public static decimal operator /(Money x, Money y) + { + if (x._currency != y._currency) + { + void Throw() => throw new ArgumentException("Currencies must match to divide money values."); + Throw(); + } + + return x._amount / y._amount; + } public static Money operator ++(Money value) { @@ -245,7 +248,7 @@ private static void EnsureSameCurrencyForCompare(Currency? x, Currency? y) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Currency? CombineCurrencies(Currency? x, Currency? y) + private static Currency? CombineCurrenciesForAddOrSubtract(Currency? x, Currency? y) { if (x == y) return x; @@ -255,7 +258,7 @@ private static void EnsureSameCurrencyForCompare(Currency? x, Currency? y) if (y is not null) { - static void Throw() => throw new ArgumentException("Currencies must match (or one of the values can be a default value that has no currency associated with it)."); + static void Throw() => throw new ArgumentException("Currencies must match to add or subtract money values (or one of the values can be a default value that has no currency associated with it)."); Throw(); } diff --git a/Tests/Singulink.Globalization.Currency.Tests/MoneyTests/Operators.cs b/Tests/Singulink.Globalization.Currency.Tests/MoneyTests/Operators.cs index 3e8e66b..5dfcd69 100644 --- a/Tests/Singulink.Globalization.Currency.Tests/MoneyTests/Operators.cs +++ b/Tests/Singulink.Globalization.Currency.Tests/MoneyTests/Operators.cs @@ -146,40 +146,34 @@ public void Addition_DifferentCurrency_ThrowsArgumentException() } [TestMethod] - public void Addition_OneDefault_ReturnsNonDefaultValue() + public void Addition_BothMoneyOneDefault_ReturnsNonDefaultValue() { (Usd100 + Money.Default).ShouldBe(Usd100); (Money.Default + Usd100).ShouldBe(Usd100); } [TestMethod] - public void Addition_BothDefault_ReturnsDefault() + public void Addition_BothDefaultMoney_ReturnsDefault() { (Money.Default + Money.Default).ShouldBe(Money.Default); } [TestMethod] - public void Addition_MoneyAndDecimal_ReturnsCorrectResult() - { - (Usd100 + 200m).ShouldBe(Usd300); - } - - [TestMethod] - public void Addition_MoneyAndNegativeDecimal_ReturnsCorrectResult() + public void Addition_DefaultMoneyAndZero_ReturnsDefault () { - (Usd200 + -100m).ShouldBe(Usd100); + (Money.Default + 0m).ShouldBe(Money.Default); } [TestMethod] - public void Addition_DecimalAndMoney_ReturnsCorrectResult() + public void Addition_DefaultMoneyAndDecimal_Throws() { - (100m + Usd200).ShouldBe(Usd300); + Should.Throw(() => Money.Default + 5); } [TestMethod] - public void Addition_NegativeDecimalAndMoney_ReturnsCorrectResult() + public void Addition_MoneyAndDecimal_ReturnsCorrectResult() { - (-100m + Usd200).ShouldBe(Usd100); + (Usd100 + 200m).ShouldBe(Usd300); } [TestMethod] @@ -195,52 +189,40 @@ public void Subtraction_DifferentCurrency_ThrowsArgumentException() } [TestMethod] - public void Subtraction_OneDefault_ReturnsNonDefaultValue() + public void Subtraction_BothMoneyOneDefault_ReturnsNonDefaultValue() { (Usd100 - Money.Default).ShouldBe(Usd100); (Money.Default - Usd100).ShouldBe(-Usd100); } [TestMethod] - public void Subtraction_BothDefault_ReturnsDefault() + public void Subtraction_BothDefaultMoney_ReturnsDefault() { (Money.Default - Money.Default).ShouldBe(Money.Default); } [TestMethod] - public void Subtraction_MoneyAndDecimal_ReturnsCorrectResult() - { - (Usd200 - 100m).ShouldBe(Usd100); - } - - [TestMethod] - public void Subtraction_MoneyAndNegativeDecimal_ReturnsCorrectResult() - { - (Usd200 - -100m).ShouldBe(Usd300); - } - - [TestMethod] - public void Subtraction_DecimalAndMoney_ReturnsCorrectResult() + public void Subtraction_DefaultMoneyAndZero_ReturnsDefault() { - (200m - Usd100).ShouldBe(Usd100); + (Money.Default - 0m).ShouldBe(Money.Default); } [TestMethod] - public void Subtraction_NegativeDecimalAndMoney_ReturnsCorrectResult() + public void Subtraction_DefaultMoneyAndDecimal_Throws() { - (-100m - Usd200).ShouldBe(-Usd300); + Should.Throw(() => Money.Default - 5); } [TestMethod] - public void Subtraction_DecimalMinusMoney_ReturnsCorrectResult() + public void Subtraction_MoneyAndDecimal_ReturnsCorrectResult() { - (200m - Usd100).ShouldBe(Usd100); + (Usd200 - 100m).ShouldBe(Usd100); } [TestMethod] - public void Subtraction_NegativeDecimalMinusMoney_ReturnsCorrectResult() + public void Subtraction_MoneyAndNegativeDecimal_ReturnsCorrectResult() { - (-100m - Usd200).ShouldBe(-Usd300); + (Usd200 - -100m).ShouldBe(Usd300); } [TestMethod] @@ -261,24 +243,6 @@ public void Multiplication_MoneyAndZero_ReturnsZero() (Usd100 * 0m).ShouldBe(Usd0); } - [TestMethod] - public void Multiplication_DecimalAndMoney_ReturnsCorrectResult() - { - (2m * Usd100).ShouldBe(Usd200); - } - - [TestMethod] - public void Multiplication_NegativeDecimalAndMoney_ReturnsCorrectResult() - { - (-2m * Usd100).ShouldBe(-Usd200); - } - - [TestMethod] - public void Multiplication_ZeroAndMoney_ReturnsZero() - { - (0m * Usd100).ShouldBe(Usd0); - } - [TestMethod] public void Division_MoneyAndDecimal_ReturnsCorrectResult() { @@ -304,21 +268,28 @@ public void Division_MoneyAndZero_ThrowsDivideByZeroException() } [TestMethod] - public void Division_DecimalAndMoney_ReturnsCorrectResult() + public void Division_SameCurrency_ReturnsCorrectResult() + { + (Usd200 / Usd100).ShouldBe(2m); + } + + [TestMethod] + public void Division_OneDefaultMoney_Throws() { - (20000m / Usd100).ShouldBe(Usd200); + Should.Throw(() => Money.Default / Usd100); + Should.Throw(() => Usd100 / Money.Default); } [TestMethod] - public void Division_NegativeDecimalAndMoney_ReturnsCorrectResult() + public void Division_DifferentCurrencies_Throws() { - (-20000m / Usd100).ShouldBe(UsdMinus200); + Should.Throw(() => Usd100 / Cad100); } [TestMethod] - public void Division_DecimalAndZeroMoney_ThrowsDivideByZeroException() + public void Division_BothDefaultMoney_ThrowsDivideByZeroException() { - Should.Throw(() => 200m / Usd0); + Should.Throw(() => Money.Default / Money.Default); } [TestMethod] @@ -343,7 +314,7 @@ public void Decrement_ReturnsCorrectResult() } [TestMethod] - public void Decrement_DefaultVakue_Throws() + public void Decrement_DefaultValue_Throws() { var value = Money.Default; Should.Throw(() => value--);