diff options
author | Kristóf Marussy <kristof@marussy.com> | 2021-01-25 01:14:28 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2021-01-25 01:14:28 +0100 |
commit | a1c2a999e449054d6641bbb633954e45fcd63f90 (patch) | |
tree | 47628c10ded721d66e47b5f87f501293cd8af003 /beancount_extras_kris7t/plugins/selective_implicit_prices_test.py | |
parent | Initialize package (diff) | |
download | beancount-extras-kris7t-a1c2a999e449054d6641bbb633954e45fcd63f90.tar.gz beancount-extras-kris7t-a1c2a999e449054d6641bbb633954e45fcd63f90.tar.zst beancount-extras-kris7t-a1c2a999e449054d6641bbb633954e45fcd63f90.zip |
Add plugins and importers from private config
The importers are missing tests, because not having any specifications
for the import formats means we must use real, private data as test inputs
Diffstat (limited to 'beancount_extras_kris7t/plugins/selective_implicit_prices_test.py')
-rw-r--r-- | beancount_extras_kris7t/plugins/selective_implicit_prices_test.py | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/beancount_extras_kris7t/plugins/selective_implicit_prices_test.py b/beancount_extras_kris7t/plugins/selective_implicit_prices_test.py new file mode 100644 index 0000000..6ead45d --- /dev/null +++ b/beancount_extras_kris7t/plugins/selective_implicit_prices_test.py | |||
@@ -0,0 +1,410 @@ | |||
1 | __copyright__ = "Copyright (C) 2015-2017 Martin Blais, " + \ | ||
2 | "2020 Kristóf Marussy <kristof@marussy.com>" | ||
3 | __license__ = "GNU GPLv2" | ||
4 | |||
5 | import unittest | ||
6 | |||
7 | from beancount.core.number import D | ||
8 | from beancount.core import data | ||
9 | from beancount.parser import cmptest | ||
10 | from beancount import loader | ||
11 | |||
12 | from beancount_extras_kris7t.plugins import selective_implicit_prices as implicit_prices | ||
13 | |||
14 | |||
15 | class TestImplicitPrices(cmptest.TestCase): | ||
16 | |||
17 | @loader.load_doc() | ||
18 | def test_add_implicit_prices__all_cases(self, entries, _, options_map): | ||
19 | """ | ||
20 | 1702-04-02 commodity USD | ||
21 | implicit-prices: TRUE | ||
22 | |||
23 | 2013-01-01 commodity HOOL | ||
24 | implicit-prices: TRUE | ||
25 | |||
26 | 2013-01-01 open Assets:Account1 | ||
27 | 2013-01-01 open Assets:Account2 | ||
28 | 2013-01-01 open Assets:Other | ||
29 | |||
30 | ;; An explicit price directive. | ||
31 | 2013-02-01 price USD 1.10 CAD | ||
32 | |||
33 | 2013-04-01 * "A transaction with a price conversion." | ||
34 | Assets:Account1 150 USD @ 1.12 CAD | ||
35 | Assets:Other | ||
36 | |||
37 | ;; This should book at price at the cost. | ||
38 | 2013-04-02 * "A transaction with a cost." | ||
39 | Assets:Account1 1500 HOOL {520 USD} | ||
40 | Assets:Other | ||
41 | |||
42 | ;; This one should be IGNORED because it books against the above. | ||
43 | 2013-04-03 * "A transaction with a cost that reduces an existing position" | ||
44 | Assets:Account1 -500 HOOL {520 USD} | ||
45 | Assets:Other | ||
46 | |||
47 | ;; This one should generate the price, even if it is reducing. | ||
48 | 2013-04-04 * "A transaction with a cost that reduces existing position, with price" | ||
49 | Assets:Account1 -100 HOOL {520 USD} @ 530 USD | ||
50 | Assets:Other | ||
51 | |||
52 | ;; This is not reducing and should also book a price at cost. | ||
53 | 2013-04-05 * "A transaction with another cost that is not reducing." | ||
54 | Assets:Account1 500 HOOL {540 USD} | ||
55 | Assets:Other | ||
56 | |||
57 | ;; The price here overrides the cost and should create an entry. | ||
58 | 2013-04-06 * "A transaction with a cost and a price." | ||
59 | Assets:Account1 500 HOOL {540 USD} @ 560 USD | ||
60 | Assets:Other | ||
61 | """ | ||
62 | self.assertEqual(12, len(entries)) | ||
63 | new_entries, _ = implicit_prices.add_implicit_prices(entries, options_map) | ||
64 | price_entries = [entry for entry in new_entries if isinstance(entry, data.Price)] | ||
65 | |||
66 | self.assertEqualEntries(""" | ||
67 | 1702-04-02 commodity USD | ||
68 | implicit-prices: TRUE | ||
69 | |||
70 | 2013-01-01 commodity HOOL | ||
71 | implicit-prices: TRUE | ||
72 | |||
73 | 2013-01-01 open Assets:Account1 | ||
74 | 2013-01-01 open Assets:Account2 | ||
75 | 2013-01-01 open Assets:Other | ||
76 | |||
77 | 2013-02-01 price USD 1.10 CAD | ||
78 | |||
79 | 2013-04-01 * "A transaction with a price conversion." | ||
80 | Assets:Account1 150 USD @ 1.12 CAD | ||
81 | Assets:Other -168.00 CAD | ||
82 | |||
83 | 2013-04-01 price USD 1.12 CAD | ||
84 | |||
85 | 2013-04-02 * "A transaction with a cost." | ||
86 | Assets:Account1 1500 HOOL {520 USD} | ||
87 | Assets:Other -780000 USD | ||
88 | |||
89 | 2013-04-02 price HOOL 520 USD | ||
90 | |||
91 | 2013-04-03 * "A transaction with a cost that reduces an existing position" | ||
92 | Assets:Account1 -500 HOOL {520 USD} | ||
93 | Assets:Other 260000 USD | ||
94 | |||
95 | 2013-04-04 * "A transaction with a cost that reduces existing position, with price" | ||
96 | Assets:Account1 -100 HOOL {520 USD} @ 530 USD | ||
97 | Assets:Other 52000 USD | ||
98 | |||
99 | 2013-04-04 price HOOL 530 USD | ||
100 | |||
101 | 2013-04-05 * "A transaction with another cost that is not reducing." | ||
102 | Assets:Account1 500 HOOL {540 USD} | ||
103 | Assets:Other -270000 USD | ||
104 | |||
105 | 2013-04-05 price HOOL 540 USD | ||
106 | |||
107 | 2013-04-06 * "A transaction with a cost and a price." | ||
108 | Assets:Account1 500 HOOL {540 USD} @ 560 USD | ||
109 | Assets:Other -270000 USD | ||
110 | |||
111 | 2013-04-06 price HOOL 560 USD | ||
112 | """, new_entries) | ||
113 | |||
114 | self.assertEqual(6, len(price_entries)) | ||
115 | expected_values = [(x[0], x[1], D(x[2])) for x in [ | ||
116 | ('USD', 'CAD', '1.10'), | ||
117 | ('USD', 'CAD', '1.12'), | ||
118 | ('HOOL', 'USD', '520.00'), | ||
119 | ('HOOL', 'USD', '530.00'), | ||
120 | ('HOOL', 'USD', '540.00'), | ||
121 | ('HOOL', 'USD', '560.00') | ||
122 | ]] | ||
123 | for expected, price in zip(expected_values, price_entries): | ||
124 | actual = (price.currency, price.amount.currency, price.amount.number) | ||
125 | self.assertEqual(expected, actual) | ||
126 | |||
127 | @loader.load_doc() | ||
128 | def test_add_implicit_prices__other_account(self, entries, errors, options_map): | ||
129 | """ | ||
130 | 2013-01-01 commodity HOOL | ||
131 | implicit-prices: TRUE | ||
132 | |||
133 | 2013-01-01 open Assets:Account1 | ||
134 | 2013-01-01 open Assets:Account2 "NONE" | ||
135 | 2013-01-01 open Assets:Other | ||
136 | |||
137 | 2013-04-01 * | ||
138 | Assets:Account1 1500 HOOL {520 USD} | ||
139 | Assets:Other | ||
140 | |||
141 | 2013-04-02 * | ||
142 | Assets:Account2 1500 HOOL {530 USD} | ||
143 | Assets:Other | ||
144 | |||
145 | 2013-04-10 * "Reduces existing position in account 1" | ||
146 | Assets:Account1 -100 HOOL {520 USD} | ||
147 | Assets:Other 52000 USD | ||
148 | |||
149 | 2013-04-11 * "Does not find an existing position in account 2" | ||
150 | Assets:Account2 -200 HOOL {531 USD} | ||
151 | Assets:Other 106200 USD | ||
152 | |||
153 | """ | ||
154 | new_entries, _ = implicit_prices.add_implicit_prices(entries, options_map) | ||
155 | self.assertEqualEntries(""" | ||
156 | 2013-01-01 commodity HOOL | ||
157 | implicit-prices: TRUE | ||
158 | |||
159 | 2013-01-01 open Assets:Account1 | ||
160 | 2013-01-01 open Assets:Account2 "NONE" | ||
161 | 2013-01-01 open Assets:Other | ||
162 | |||
163 | 2013-04-01 * | ||
164 | Assets:Account1 1500 HOOL {520 USD} | ||
165 | Assets:Other -780000 USD | ||
166 | |||
167 | 2013-04-02 * | ||
168 | Assets:Account2 1500 HOOL {530 USD} | ||
169 | Assets:Other -795000 USD | ||
170 | |||
171 | 2013-04-01 price HOOL 520 USD | ||
172 | |||
173 | 2013-04-02 price HOOL 530 USD | ||
174 | |||
175 | 2013-04-10 * "Reduces existing position in account 1" | ||
176 | Assets:Account1 -100 HOOL {520 USD} | ||
177 | Assets:Other 52000 USD | ||
178 | |||
179 | 2013-04-11 * "Does not find an existing position in account 2" | ||
180 | Assets:Account2 -200 HOOL {531 USD} | ||
181 | Assets:Other 106200 USD | ||
182 | |||
183 | ;; Because a match was not found against the inventory, a price will be added. | ||
184 | 2013-04-11 price HOOL 531 USD | ||
185 | |||
186 | """, new_entries) | ||
187 | |||
188 | @loader.load_doc() | ||
189 | def test_add_implicit_prices__duplicates_on_same_transaction(self, | ||
190 | entries, _, options_map): | ||
191 | """ | ||
192 | 2013-01-01 commodity HOOL | ||
193 | implicit-prices: TRUE | ||
194 | |||
195 | 2013-01-01 open Assets:Account1 | ||
196 | 2013-01-01 open Assets:Account2 | ||
197 | 2013-01-01 open Assets:Other | ||
198 | |||
199 | 2013-04-01 * "Allowed because of same price" | ||
200 | Assets:Account1 1500 HOOL {520 USD} | ||
201 | Assets:Account2 1500 HOOL {520 USD} | ||
202 | Assets:Other | ||
203 | |||
204 | 2013-04-02 * "Second one is disallowed because of different price" | ||
205 | Assets:Account1 1500 HOOL {520 USD} | ||
206 | Assets:Account2 1500 HOOL {530 USD} | ||
207 | Assets:Other | ||
208 | |||
209 | """ | ||
210 | new_entries, errors = implicit_prices.add_implicit_prices(entries, options_map) | ||
211 | self.assertEqual([], [type(error) for error in errors]) | ||
212 | self.assertEqualEntries(""" | ||
213 | 2013-01-01 commodity HOOL | ||
214 | implicit-prices: TRUE | ||
215 | |||
216 | 2013-01-01 open Assets:Account1 | ||
217 | 2013-01-01 open Assets:Account2 | ||
218 | 2013-01-01 open Assets:Other | ||
219 | |||
220 | 2013-04-01 * "Allowed because of same price" | ||
221 | Assets:Account1 1500 HOOL {520 USD} | ||
222 | Assets:Account2 1500 HOOL {520 USD} | ||
223 | Assets:Other -1560000 USD | ||
224 | |||
225 | 2013-04-01 price HOOL 520 USD | ||
226 | |||
227 | 2013-04-02 * "Second one is disallowed because of different price" | ||
228 | Assets:Account1 1500 HOOL {520 USD} | ||
229 | Assets:Account2 1500 HOOL {530 USD} | ||
230 | Assets:Other -1575000 USD | ||
231 | |||
232 | 2013-04-02 price HOOL 520 USD | ||
233 | 2013-04-02 price HOOL 530 USD ;; Allowed for now. | ||
234 | |||
235 | """, new_entries) | ||
236 | |||
237 | @loader.load_doc() | ||
238 | def test_add_implicit_prices__duplicates_on_different_transactions(self, | ||
239 | entries, _, | ||
240 | options_map): | ||
241 | """ | ||
242 | 2013-01-01 commodity HOOL | ||
243 | implicit-prices: TRUE | ||
244 | |||
245 | 2013-01-01 open Assets:Account1 | ||
246 | 2013-01-01 open Assets:Account2 | ||
247 | 2013-01-01 open Assets:Other | ||
248 | |||
249 | 2013-04-01 * "Allowed because of same price #1" | ||
250 | Assets:Account1 1500 HOOL {520 USD} | ||
251 | Assets:Other | ||
252 | |||
253 | 2013-04-01 * "Allowed because of same price #2" | ||
254 | Assets:Account2 1500 HOOL {520 USD} | ||
255 | Assets:Other | ||
256 | |||
257 | 2013-04-02 * "Second one is disallowed because of different price #1" | ||
258 | Assets:Account1 1500 HOOL {520 USD} | ||
259 | Assets:Other | ||
260 | |||
261 | 2013-04-02 * "Second one is disallowed because of different price #2" | ||
262 | Assets:Account2 1500 HOOL {530 USD} | ||
263 | Assets:Other | ||
264 | |||
265 | """ | ||
266 | new_entries, errors = implicit_prices.add_implicit_prices(entries, options_map) | ||
267 | self.assertEqual([], [type(error) for error in errors]) | ||
268 | self.assertEqualEntries(""" | ||
269 | 2013-01-01 commodity HOOL | ||
270 | implicit-prices: TRUE | ||
271 | |||
272 | 2013-01-01 open Assets:Account1 | ||
273 | 2013-01-01 open Assets:Account2 | ||
274 | 2013-01-01 open Assets:Other | ||
275 | |||
276 | 2013-04-01 * "Allowed because of same price #1" | ||
277 | Assets:Account1 1500 HOOL {520 USD} | ||
278 | Assets:Other -780000 USD | ||
279 | |||
280 | 2013-04-01 * "Allowed because of same price #2" | ||
281 | Assets:Account2 1500 HOOL {520 USD} | ||
282 | Assets:Other -780000 USD | ||
283 | |||
284 | 2013-04-01 price HOOL 520 USD | ||
285 | |||
286 | 2013-04-02 * "Second one is disallowed because of different price #1" | ||
287 | Assets:Account1 1500 HOOL {520 USD} | ||
288 | Assets:Other -780000 USD | ||
289 | |||
290 | 2013-04-02 * "Second one is disallowed because of different price #2" | ||
291 | Assets:Account2 1500 HOOL {530 USD} | ||
292 | Assets:Other -795000 USD | ||
293 | |||
294 | 2013-04-02 price HOOL 520 USD | ||
295 | 2013-04-02 price HOOL 530 USD ;; Allowed for now. | ||
296 | |||
297 | """, new_entries) | ||
298 | |||
299 | @loader.load_doc() | ||
300 | def test_add_implicit_prices__duplicates_overloaded(self, entries, _, options_map): | ||
301 | """ | ||
302 | 2013-01-01 commodity HOOL | ||
303 | implicit-prices: TRUE | ||
304 | |||
305 | 2013-01-01 open Assets:Account1 | ||
306 | 2013-01-01 open Assets:Other | ||
307 | |||
308 | 2013-04-01 * "Allowed, sets the price for that day" | ||
309 | Assets:Account1 1500 HOOL {520 USD} | ||
310 | Assets:Other | ||
311 | |||
312 | 2013-04-01 * "Will be ignored, price for the day already set" | ||
313 | Assets:Account1 1500 HOOL {530 USD} | ||
314 | Assets:Other | ||
315 | |||
316 | 2013-04-01 * "Should be ignored too, price for the day already set" | ||
317 | Assets:Account1 1500 HOOL {530 USD} | ||
318 | Assets:Other | ||
319 | """ | ||
320 | new_entries, errors = implicit_prices.add_implicit_prices(entries, options_map) | ||
321 | self.assertEqual([], [type(error) for error in errors]) | ||
322 | self.assertEqualEntries(""" | ||
323 | 2013-01-01 commodity HOOL | ||
324 | implicit-prices: TRUE | ||
325 | |||
326 | 2013-01-01 open Assets:Account1 | ||
327 | 2013-01-01 open Assets:Other | ||
328 | |||
329 | 2013-04-01 * "Allowed, sets the price for that day" | ||
330 | Assets:Account1 1500 HOOL {520 USD} | ||
331 | Assets:Other -780000 USD | ||
332 | |||
333 | 2013-04-01 * "Will be ignored, price for the day already set" | ||
334 | Assets:Account1 1500 HOOL {530 USD} | ||
335 | Assets:Other -795000 USD | ||
336 | |||
337 | 2013-04-01 * "Should be ignored too, price for the day already set" | ||
338 | Assets:Account1 1500 HOOL {530 USD} | ||
339 | Assets:Other -795000 USD | ||
340 | |||
341 | 2013-04-01 price HOOL 520 USD | ||
342 | 2013-04-01 price HOOL 530 USD | ||
343 | |||
344 | """, new_entries) | ||
345 | |||
346 | @loader.load_doc() | ||
347 | def test_add_implicit_prices__not_enabled(self, entries, errors, options_map): | ||
348 | """ | ||
349 | 2013-01-01 open Assets:Account1 | ||
350 | 2013-01-01 open Assets:Other | ||
351 | |||
352 | 2013-04-01 * | ||
353 | Assets:Account1 1500 HOOL {520 USD} | ||
354 | Assets:Other | ||
355 | """ | ||
356 | new_entries, _ = implicit_prices.add_implicit_prices(entries, options_map) | ||
357 | self.assertEqualEntries(""" | ||
358 | 2013-01-01 open Assets:Account1 | ||
359 | 2013-01-01 open Assets:Other | ||
360 | |||
361 | 2013-04-01 * | ||
362 | Assets:Account1 1500 HOOL {520 USD} | ||
363 | Assets:Other -780000 USD | ||
364 | """, new_entries) | ||
365 | |||
366 | @loader.load_doc() | ||
367 | def test_add_implicit_prices__disabled(self, entries, errors, options_map): | ||
368 | """ | ||
369 | 2013-01-01 commodity HOOL | ||
370 | implicit-prices: FALSE | ||
371 | |||
372 | 2013-01-01 open Assets:Account1 | ||
373 | 2013-01-01 open Assets:Other | ||
374 | |||
375 | 2013-04-01 * | ||
376 | Assets:Account1 1500 HOOL {520 USD} | ||
377 | Assets:Other | ||
378 | """ | ||
379 | new_entries, _ = implicit_prices.add_implicit_prices(entries, options_map) | ||
380 | self.assertEqualEntries(""" | ||
381 | 2013-01-01 commodity HOOL | ||
382 | implicit-prices: FALSE | ||
383 | |||
384 | 2013-01-01 open Assets:Account1 | ||
385 | 2013-01-01 open Assets:Other | ||
386 | |||
387 | 2013-04-01 * | ||
388 | Assets:Account1 1500 HOOL {520 USD} | ||
389 | Assets:Other -780000 USD | ||
390 | """, new_entries) | ||
391 | |||
392 | @loader.load_doc() | ||
393 | def test_add_implicit_prices__invalid(self, entries, errors, options_map): | ||
394 | """ | ||
395 | 2013-01-01 commodity HOOL | ||
396 | implicit-prices: "yes" | ||
397 | |||
398 | 2013-01-01 open Assets:Account1 | ||
399 | 2013-01-01 open Assets:Other | ||
400 | |||
401 | 2013-04-01 * | ||
402 | Assets:Account1 1500 HOOL {520 USD} | ||
403 | Assets:Other | ||
404 | """ | ||
405 | _, new_errors = implicit_prices.add_implicit_prices(entries, options_map) | ||
406 | self.assertRegex(new_errors[0].message, '^implicit-prices must be Boolean') | ||
407 | |||
408 | |||
409 | if __name__ == '__main__': | ||
410 | unittest.main() | ||