Skip to content

Commit

Permalink
Merge pull request #25 from polyadic/remove-zero
Browse files Browse the repository at this point in the history
Remove zero
  • Loading branch information
FreeApophis authored Sep 12, 2023
2 parents 9909c9f + a55d87e commit 0776f3d
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 47 deletions.
31 changes: 2 additions & 29 deletions Funcky.Money.Test/MoneyTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections;
using System.Globalization;
using FsCheck;
using FsCheck.Xunit;
using Xunit;
Expand Down Expand Up @@ -172,21 +173,6 @@ public void WeCanDefineMoneyExpressionsWithOperators()
Assert.Equal(Money.USD(30), product.Evaluate());
}

[Property]
public Property TheMoneyNeutralElementWorksWithAnyCurrency(Money money)
{
return (money == (money + Money.Zero).Evaluate()
&& (money == (Money.Zero + money).Evaluate())).ToProperty().When(!money.IsZero);
}

[Property]
public Property InASumOfMultipleZerosWithDifferentCurrenciesTheEvaluationHasTheSameCurrencyAsTheFirstMoneyInTheExpression(Currency c1, Currency c2, Currency c3)
{
var sum = new Money(0m, c1) + new Money(0m, c2) + new Money(0m, c3) + new Money(0m, c2);

return (sum.Evaluate().Currency == c1).ToProperty();
}

[Fact]
public void MoneyFormatsCorrectlyAccordingToTheCurrency()
{
Expand Down Expand Up @@ -302,19 +288,6 @@ public void WeCanDelegateTheExchangeRatesToABank()
Assert.Equal(30m, sum.Evaluate(OneToOneContext(Currency.CHF)).Amount);
}

[Fact]
public void EvaluationOnZeroMoneysWorks()
{
var sum = (Money.Zero + Money.Zero) * 1.5m;

var context = OneToOneContext(Currency.JPY);

Assert.True(Money.Zero.Evaluate(context).IsZero);
Assert.True(sum.Evaluate(context).IsZero);
Assert.True(Money.Zero.Evaluate().IsZero);
Assert.True(sum.Evaluate().IsZero);
}

[Fact]
public void DifferentPrecisionsCannotBeEvaluatedWithoutAnEvaluationContext()
{
Expand Down Expand Up @@ -479,7 +452,7 @@ public void DividingTwoMoneysWithDifferentCurrenciesNeedAnEvaluationContext()
[Fact]
public void DividingTwoMoneysOnlyWorksIfTheDivisorIsNonZero()
{
Assert.Throws<DivideByZeroException>(() => Money.CHF(5) / Money.Zero);
Assert.Throws<DivideByZeroException>(() => Money.CHF(5) / Money.CHF(0.0m));
Assert.Throws<DivideByZeroException>(() => Money.USD(3).Divide(Money.USD(0)));
}

Expand Down
11 changes: 10 additions & 1 deletion Funcky.Money/Funcky.Money.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
<Product>Funcky.Money</Product>
<Description>Funcky.Money is based on Kent Beck's TDD exercise but with more features.</Description>
<PackageTags>Functional Money</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IsPackable>true</IsPackable>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).Test" />
Expand All @@ -19,6 +20,14 @@
<PackageReference Include="Funcky.DiscriminatedUnion" PrivateAssets="all" />
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Funcky.Money.SourceGenerator\Funcky.Money.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
Expand Down
2 changes: 0 additions & 2 deletions Funcky.Money/Money.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ namespace Funcky;
[DebuggerDisplay("{Amount} {Currency.AlphabeticCurrencyCode,nq}")]
public sealed partial record Money : IMoneyExpression
{
public static readonly Money Zero = new(0m);

public Money(decimal amount, Option<Currency> currency = default)
{
Amount = amount;
Expand Down
17 changes: 3 additions & 14 deletions Funcky.Money/Visitors/MoneyBag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ internal sealed class MoneyBag
{
private readonly Dictionary<Currency, List<Money>> _currencies = new();
private Option<IRoundingStrategy> _roundingStrategy;
private Option<Currency> _emptyCurrency;

public MoneyBag(Money money)
{
Expand Down Expand Up @@ -39,18 +38,8 @@ public Money CalculateTotal(Option<MoneyEvaluationContext> context)

private void Add(Money money)
{
if (money.IsZero)
{
if (_currencies.None())
{
_emptyCurrency = money.Currency;
}
}
else
{
CreateMoneyBagByCurrency(money.Currency);
_currencies[money.Currency].Add(money);
}
CreateMoneyBagByCurrency(money.Currency);
_currencies[money.Currency].Add(money);
}

private static List<Money> MultiplyBag(decimal factor, IEnumerable<Money> bag)
Expand All @@ -74,7 +63,7 @@ private Money AggregateSingleMoneyBag()
=> _currencies
.SingleOrNone() // Single or None throws an InvalidOperationException if we have more than one currency in the Bag
.Match(
none: () => _emptyCurrency.Match(Money.Zero, c => Money.Zero with { Currency = c }),
none: () => throw new Exception("nothing to Aggregate"),
some: m => CheckAndAggregateBag(m.Value));

private Money CheckAndAggregateBag(IEnumerable<Money> bag)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ These is the evolving list of TDD requirements which led to the implementation.
* [x] Every construction of `Money` currently rounds to two digits, while this is interesting for 5.7f, it has bad effects in evaluation. We should remove the rounding again.
* [x] The default `MidpointRounding` mechanism is bankers rounding (`MidpointRounding.ToEven`).
* [x] Multiply a `Money` with a real number (`int`, and `decimal`).
* [x] There is a neutral `Money` element (`Zero`).
* [x] Distribute `Money` equally into n slices (1CHF into 3 slices: [0.33, 0.33, 0.34]).
* [x] Distribute `Money` proportionally (1 CHF in 1:5 -> [0.17, 0.83]).
* [x] Extract distribution of money into a strategy which is injected.
Expand Down Expand Up @@ -121,6 +120,7 @@ These is the evolving list of TDD requirements which led to the implementation.
* We prepare a distribution strategy but do not make it chosable at this point.
* We support the following operators: unary + and -, and the binary operators ==, !=, +, -, * and /.
* You can divide two different currencies only with the `Divide(IMoneyExpression, IMoneyExpression, Option<MoneyEvaluationContext>)` method where you have to give a `MoneyEvaluationContext` with the necessary exchange rates.
* We removed the neutral `Money` element (`Zero`), there are too many unsolved problems. If we add it again we should probaly make a NeutralElement : `IMoneyExpression`.

### Open Decisions

Expand Down

0 comments on commit 0776f3d

Please sign in to comment.