|
1 from budgettracker import Budget, Transaction, Decimal |
|
2 |
|
3 class Expect: |
|
4 def __init__(self, *cmds, verbose = False): |
|
5 self._cmds = cmds |
|
6 self._index = 0 |
|
7 self.verbose = verbose |
|
8 def __call__(self, prompt): |
|
9 assert(self._index < len(self._cmds)) |
|
10 idx = self._index |
|
11 self._index += 1 |
|
12 if self.verbose: |
|
13 print("{:<20} => {}".format(prompt, self._cmds[idx])) |
|
14 return self._cmds[idx] |
|
15 |
|
16 class Test: |
|
17 def run(self): |
|
18 self.test_load_save() |
|
19 self.test_report(True) |
|
20 self.test_envelops() |
|
21 self.test_read_transaction() |
|
22 |
|
23 def test_read_transaction(self, verbose = False): |
|
24 cmds = [ "Salary", "400", |
|
25 "Taxes", "100", |
|
26 "Taxes", "-100", |
|
27 "Grocery", "200" ] |
|
28 b = self.create_budget() |
|
29 t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["", "n"]))) |
|
30 assert(t is None) |
|
31 t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["", "y"]))) |
|
32 assert(t.amount == 400) |
|
33 assert(t.budget["Taxes"] == 100) |
|
34 assert(t.budget["Grocery"] == 200) |
|
35 assert(len(t.budget) == 2) |
|
36 assert(t.expenses["Taxes"] == 100) |
|
37 assert(len(t.expenses) == 1) |
|
38 assert(t.balance == 200) |
|
39 t = b.read_transaction(Expect(verbose = verbose, *(cmds + ["Hobbies", "", "y"]))) |
|
40 assert(t.amount == 400) |
|
41 assert(t.budget["Taxes"] == 100) |
|
42 assert(t.budget["Grocery"] == 200) |
|
43 assert(t.budget["Hobbies"] == 200) |
|
44 assert(len(t.budget) == 3) |
|
45 assert(t.expenses["Taxes"] == 100) |
|
46 assert(len(t.expenses) == 1) |
|
47 assert(t.balance == 0) |
|
48 |
|
49 def create_budget(self): |
|
50 b = Budget() |
|
51 salary = Decimal(500) |
|
52 taxes = salary * Decimal('0.20') |
|
53 # Salary: 500 - 100 in taxes = 400 |
|
54 # Budget: 200$ in Grocery, 100$ for Taxes |
|
55 # Expenses: Taxes 100$ |
|
56 # Unassigned: 200$ |
|
57 t = Transaction(name="Salary", amount=salary-taxes, |
|
58 budget = [("Grocery", Decimal(200)), |
|
59 ("Taxes", taxes)], |
|
60 expenses = [("Taxes", taxes)]) |
|
61 b.add_transaction(t) |
|
62 # Gift: 100$ |
|
63 # Budget: 100$ in Hobbies |
|
64 t = Transaction(name = "Gift", amount = Decimal(100), envelop = "Hobbies") |
|
65 b.add_transaction(t) |
|
66 # Costco: -75$ |
|
67 # Expenses: 75$ in Grocery |
|
68 t = Transaction(name="Costco", amount=Decimal(-75)) |
|
69 t.rebalance("Grocery") |
|
70 b.add_transaction(t) |
|
71 # Cinema: -50 |
|
72 # Expenses: 50$ in Hobbies |
|
73 t = Transaction(name="Cinema", amount=Decimal(-50), envelop="Hobbies") |
|
74 assert(t.balance == 0) |
|
75 b.add_transaction(t) |
|
76 # Missing money: -20$ |
|
77 # Unassigned: -20$ |
|
78 t = Transaction(name="Missing", amount=Decimal(-20)) |
|
79 b.add_transaction(t) |
|
80 # Total: |
|
81 # Budget: 200$ Grocery, 100$ Taxes, 100$ Hobbies = 400$ |
|
82 # Expenses: 100$ Taxes, 75$ Grocery, 50$ Hobbies = 225$ |
|
83 # Unassigned: 200$ Salary, -20$ Missing = 180$ |
|
84 |
|
85 b.set_envelop_description("Grocery", "stuff for stomach") |
|
86 b.rename_envelop("Grocery", "Food") |
|
87 return b |
|
88 |
|
89 def test_load_save(self, verbose = False): |
|
90 b = self.create_budget() |
|
91 |
|
92 from io import StringIO |
|
93 fp = StringIO() |
|
94 b.save(fp) |
|
95 saved = fp.getvalue() |
|
96 if verbose: print(saved) |
|
97 |
|
98 b2 = Budget() |
|
99 b2.load(StringIO(saved)) |
|
100 fp = StringIO() |
|
101 b2.save(fp) |
|
102 saved2 = fp.getvalue() |
|
103 if verbose: print(saved2) |
|
104 assert(saved == saved2) |
|
105 |
|
106 def test_envelops(self, verbose = False): |
|
107 b = self.create_budget() |
|
108 envelops = list(b.envelops) |
|
109 assert(len(envelops) == 5) |
|
110 total = envelops[-2] |
|
111 unassigned = envelops[-1] |
|
112 |
|
113 assert(total.budget == 400) |
|
114 assert(total.expenses == 225) |
|
115 assert(total.balance == 175) |
|
116 assert(unassigned.budget == 200) |
|
117 assert(unassigned.expenses == 20) |
|
118 assert(unassigned.balance == 180) |
|
119 |
|
120 def test_report(self, verbose = False): |
|
121 b = self.create_budget() |
|
122 for l in b.report(): |
|
123 if verbose: |
|
124 print(l) |
|
125 |
|
126 if __name__ == '__main__': |
|
127 Test().run() |