1
exercism fetch delphi bank-account

uBankAccountTests.pas

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
unit uBankAccountTests;

interface
uses
  DUnitX.TestFramework;

type

  [TestFixture]
  BankAccountTests = class(TObject)
  public
    [Test]
//  [Ignore('Comment the "[Ignore]" statement to run the test')]
    procedure Returns_empty_balance_after_opening;

    [Test]
    [Ignore]
    procedure Check_basic_balance;

    [Test]
    [Ignore]
    procedure Balance_can_increment_and_decrement;

    [Test]
    [Ignore]
    procedure Closed_account_throws_exception_when_checking_balance;

    [Test]
    [Ignore]
    procedure Change_account_balance_from_multiple_threads;
  end;

implementation
uses System.SysUtils, System.Classes, System.SyncObjs, uBankAccount;

const HalfCentTolerance = 0.005;

procedure BankAccountTests.Returns_empty_balance_after_opening;
var account: IBankAccount;
begin
  account := TBankAccount.Create;
  account.Open;
  assert.AreEqual(0.00,account.Balance,HalfCentTolerance);
end;

procedure BankAccountTests.Check_basic_balance;
var account: IBankAccount;
    openingBalance: Double;
    updatedBalance: Double;
begin
  account := TBankAccount.Create;
  account.Open;

  openingBalance := account.Balance;
  account.UpdateBalance(10);

  updatedBalance := account.Balance;

  assert.AreEqual(0, openingBalance, HalfCentTolerance);
  assert.AreEqual(10, updatedBalance, HalfCentTolerance);
end;

procedure BankAccountTests.Balance_can_increment_and_decrement;
var account: IBankAccount;
    openingBalance: Double;
    addedBalance: Double;
    subtractedBalance: Double;
begin
  account := TBankAccount.Create;
  account.Open;

  openingBalance := account.Balance;

  account.UpdateBalance(10);
  addedBalance := account.Balance;

  account.UpdateBalance(-15);
  subtractedBalance := account.Balance;

  assert.AreEqual(0, openingBalance, HalfCentTolerance);
  assert.AreEqual(10, addedBalance, HalfCentTolerance);
  assert.AreEqual(-5, subtractedBalance, HalfCentTolerance);
end;

procedure BankAccountTests.Closed_account_throws_exception_when_checking_balance;
var MyProc: TTestLocalMethod;
begin
  MyProc := procedure
            var account: IBankAccount;
            begin
              account := TBankAccount.Create;
              account.Open;
              account.Close;
              account.Balance;
            end;

  assert.WillRaise(MyProc, EAccountNotOpen);
end;

procedure BankAccountTests.Change_account_balance_from_multiple_threads;
const threads = 500;
      iterations = 100;

var account: IBankAccount;
    activeThreadCount: integer;
    allthreadsDone: TEvent;
    i: integer;
begin
  activeThreadCount := threads;
  account := TBankAccount.Create;
  account.Open;

  allThreadsDone := TEvent.Create(nil, True, False,'AllThreadsDone');
  allThreadsDone.ResetEvent;
  for i := 1 to threads do
  begin
    TThread.CreateAnonymousThread(
      procedure
      var j: integer;
      begin
        try
          for j := 1 to iterations do
          begin
            account.UpdateBalance(1);
            account.UpdateBalance(-1);
          end;
        finally
          dec(activeThreadCount);
          if activeThreadCount <= 0 then
            allthreadsDone.SetEvent;
        end;
      end)
      .Start;
  end;

  assert.AreEqual(wrSignaled,allthreadsDone.WaitFor(60000), format('%d threads still active',[activeThreadCount]));
  assert.AreEqual(0, account.Balance, HalfCentTolerance);
end;

initialization
  TDUnitX.RegisterTestFixture(BankAccountTests);
end.