-
-
Notifications
You must be signed in to change notification settings - Fork 424
/
Copy pathRefTest.cs
128 lines (95 loc) · 3.23 KB
/
RefTest.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System.Linq;
using Xunit;
namespace LanguageExt.Tests;
public class Account
{
public readonly int Balance;
Account(int balance) =>
Balance = balance;
public Account SetBalance(int value) =>
new Account(value);
public Account AddBalance(int value) =>
new Account(Balance + value);
public Account Deposit(int value) =>
new Account(Balance + value);
public static Ref<Account> New(int balance) =>
Ref(new Account(balance), Account.Validate);
public static bool Validate(Account a) =>
a.Balance >= 0;
public override string ToString() =>
Balance.ToString();
}
public static class Transfer
{
public static Unit Do(Ref<Account> from, Ref<Account> to, int amount) =>
atomic(() =>
{
from.Value = from.Value.AddBalance(-amount);
to.Value = to.Value.AddBalance(amount);
});
}
public class RefTest
{
[Fact]
public void BankBalanceChangeTest()
{
var accountA = Account.New(200);
var accountB = Account.New(0);
var stateA = Option<Account>.None;
var stateB = Option<Account>.None;
var changedA = 0;
var changedB = 0;
accountA.Change += v => { stateA = v; changedA++; };
accountB.Change += v => { stateB = v; changedB++; };
atomic(() =>
{
accountA.Value = accountA.Value.AddBalance(-50);
accountB.Value = accountB.Value.AddBalance(50);
accountA.Value = accountA.Value.AddBalance(-5);
accountB.Value = accountB.Value.AddBalance(5);
Assert.Equal(None, stateA);
Assert.Equal(None, stateB);
});
Assert.Equal(Some(accountA.Value), stateA);
Assert.Equal(Some(accountB.Value), stateB);
Assert.Equal(1, changedA);
Assert.Equal(1, changedB);
}
[Fact]
public void SimpleBankBalanceTest()
{
var accountA = Account.New(200);
var accountB = Account.New(0);
Transfer.Do(accountA, accountB, 100);
var (balanceA, balanceB) = atomic(() => (accountA.Value.Balance, accountB.Value.Balance));
Assert.True(balanceA == balanceB);
}
[Fact]
public void CommuteTest()
{
const int count = 1000;
static int inc(Ref<int> counter) =>
atomic(() => commute(counter, static x => x + 1));
var num = Ref(0);
var res = Range(0, count).AsParallel()
.Select(_ => inc(num))
.AsIterable()
.ToSeq()
.Strict();
Assert.True(num == count);
}
[Fact]
static void DepositCommuteTest()
{
var bank = Account.New(0);
LogDeposit(bank, 100);
LogDeposit(bank, 50);
Assert.True(bank.Value.Balance == 150);
var bank2 = Account.New(0);
LogDeposit(bank2, 50);
LogDeposit(bank2, 100);
Assert.True(bank2.Value.Balance == 150);
}
static void LogDeposit(Ref<Account> account, int amount) =>
atomic(() => commute(account, a => a.Deposit(amount)));
}