Skip to content

Commit e2f4d2f

Browse files
author
Marcel Nadzam
committed
Add settlement unit tests
1 parent 4732d57 commit e2f4d2f

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0-windows</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="coverlet.collector" Version="6.0.0" />
14+
<PackageReference Include="FluentAssertions" Version="8.7.1" />
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
16+
<PackageReference Include="xunit" Version="2.5.3" />
17+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\FairSplit.Domain\FairSplit.Domain.csproj" />
22+
<ProjectReference Include="..\FairSplit\FairSplit.csproj" />
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<Using Include="Xunit" />
27+
</ItemGroup>
28+
29+
</Project>

FairSplit.Tests/SettlementTests.cs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using FairSplit.Domain.Model;
2+
using FairSplit.Domain.Model.Enums;
3+
using FairSplit.Utils;
4+
using FluentAssertions;
5+
6+
namespace FairSplit.Tests
7+
{
8+
public class SettlementTests
9+
{
10+
private static Transaction MakeTransaction(
11+
string name,
12+
decimal total,
13+
Member payer,
14+
IEnumerable<MemberPayment> recipients)
15+
{
16+
return new(Guid.NewGuid(), name, total, payer, DateTime.UtcNow, false, default, recipients.ToList());
17+
}
18+
19+
private static Group MakeGroup(
20+
string name,
21+
IEnumerable<Member> members,
22+
IEnumerable<Transaction> transactions)
23+
{
24+
var g = new Group(name);
25+
foreach (var m in members) g.AddMember(m);
26+
foreach (var t in transactions) g.AddTransaction(t);
27+
return g;
28+
}
29+
30+
[Fact]
31+
public void PaidForThemselves()
32+
{
33+
var personA = new Member("PersonA");
34+
var personB = new Member("PersonB");
35+
36+
var t1 = MakeTransaction("t1", 50m, personA,
37+
[
38+
new(personA, 50m)
39+
]);
40+
var t2 = MakeTransaction("t2", 50m, personB,
41+
[
42+
new(personB, 50m)
43+
]);
44+
45+
Group group = MakeGroup("TestGroup", [personA, personB], [t1, t2]);
46+
47+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
48+
pays.Should().BeEmpty();
49+
}
50+
51+
[Fact]
52+
public void TwoPeople_OneOwer()
53+
{
54+
var personA = new Member("PersonA");
55+
var personB = new Member("PersonB");
56+
57+
var transaction = MakeTransaction("t1", 100m, personA,
58+
[
59+
new(personA, 50m),
60+
new(personB, 50m)
61+
]);
62+
63+
Group group = MakeGroup("TestGroup", [personA, personB], [transaction]);
64+
65+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
66+
pays.Should().HaveCount(1);
67+
68+
var payment = pays.Single();
69+
payment.From.Should().Be(personB);
70+
payment.To.Should().Be(personA);
71+
payment.Amount.Should().Be(50m);
72+
}
73+
74+
[Fact]
75+
public void PaidOffTransaction()
76+
{
77+
var personA = new Member("A");
78+
var personB = new Member("B");
79+
80+
var paidOff = MakeTransaction("Done", 100m, personA,
81+
[
82+
new(personA, 50m),
83+
new(personB, 50m)
84+
]);
85+
paidOff.IsPaidOff = true;
86+
87+
var group = MakeGroup("TestGroup", [personA, personB], [paidOff]);
88+
89+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
90+
pays.Should().BeEmpty();
91+
}
92+
93+
[Fact]
94+
public void PerfectCycle_CancelsOut()
95+
{
96+
var personA = new Member("A");
97+
var personB = new Member("B");
98+
var personC = new Member("C");
99+
100+
var t1 = MakeTransaction("B paid for A", 10m, personB,
101+
[
102+
new(personA, 10m),
103+
]);
104+
var t2 = MakeTransaction("C paid for B", 10m, personC,
105+
[
106+
new(personB, 10m),
107+
]);
108+
var t3 = MakeTransaction("A paid for C", 10m, personA,
109+
[
110+
new(personC, 10m),
111+
]);
112+
var group = MakeGroup("TestGroup", [personA, personB, personC], [t1, t2, t3]);
113+
114+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
115+
pays.Should().BeEmpty();
116+
}
117+
118+
[Fact]
119+
public void FourPeople_TransitivePayment()
120+
{
121+
var a = new Member("A");
122+
var b = new Member("B");
123+
var c = new Member("C");
124+
var d = new Member("D");
125+
126+
var t1 = MakeTransaction("B for A", 10m, b,
127+
[
128+
new MemberPayment(a, 10m),
129+
]);
130+
var t2 = MakeTransaction("C for B", 10m, c,
131+
[
132+
new MemberPayment(b, 10m),
133+
]);
134+
var t3 = MakeTransaction("D for C", 10m, d,
135+
[
136+
new MemberPayment(c, 10m),
137+
]);
138+
139+
var group = MakeGroup("TestGroup", [a, b, c, d], [t1, t2, t3]);
140+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
141+
142+
pays.Should().HaveCount(1);
143+
var p = pays.Single();
144+
p.From.Should().Be(a);
145+
p.To.Should().Be(d);
146+
p.Amount.Should().Be(10m);
147+
}
148+
149+
[Fact]
150+
public void ThreePeople_SharedPayment()
151+
{
152+
var personA = new Member("PersonA");
153+
var personB = new Member("PersonB");
154+
var personC = new Member("PersonC");
155+
156+
var t1 = MakeTransaction("t1", 90m, personA, []);
157+
var group = MakeGroup("TestGroup", [personA, personB, personC], [t1]);
158+
159+
var pays = TransactionSettler.CalculateBestSettleOptions(group);
160+
161+
pays.Should().HaveCount(2);
162+
pays.Should().ContainEquivalentOf(new Payment(personB, personA, 30m));
163+
pays.Should().ContainEquivalentOf(new Payment(personC, personA, 30m));
164+
}
165+
}
166+
}

FairSplit.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FairSplit.EntityFramework",
99
EndProject
1010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FairSplit.Domain", "FairSplit.Domain\FairSplit.Domain.csproj", "{95997C82-5B05-44D6-A170-B62642EACF86}"
1111
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FairSplit.Tests", "FairSplit.Tests\FairSplit.Tests.csproj", "{9383F9ED-A217-49F8-911C-D1D3D645BF6E}"
13+
EndProject
1214
Global
1315
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1416
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
2729
{95997C82-5B05-44D6-A170-B62642EACF86}.Debug|Any CPU.Build.0 = Debug|Any CPU
2830
{95997C82-5B05-44D6-A170-B62642EACF86}.Release|Any CPU.ActiveCfg = Release|Any CPU
2931
{95997C82-5B05-44D6-A170-B62642EACF86}.Release|Any CPU.Build.0 = Release|Any CPU
32+
{9383F9ED-A217-49F8-911C-D1D3D645BF6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{9383F9ED-A217-49F8-911C-D1D3D645BF6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{9383F9ED-A217-49F8-911C-D1D3D645BF6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
35+
{9383F9ED-A217-49F8-911C-D1D3D645BF6E}.Release|Any CPU.Build.0 = Release|Any CPU
3036
EndGlobalSection
3137
GlobalSection(SolutionProperties) = preSolution
3238
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)