Skip to content

Commit e3c2a4e

Browse files
authored
Merge pull request #27 from person142/ppmt
TST: clean up `ppmt` tests
2 parents 03e194b + 81c35a0 commit e3c2a4e

File tree

1 file changed

+125
-117
lines changed

1 file changed

+125
-117
lines changed

numpy_financial/tests/test_financial.py

Lines changed: 125 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
21
from decimal import Decimal
2+
import math
33

44
# Don't use 'import numpy as np', to avoid accidentally testing
55
# the versions in numpy instead of numpy_financial.
66
import numpy
77
from numpy.testing import (
8-
assert_, assert_almost_equal, assert_allclose, assert_equal, assert_raises
8+
assert_, assert_almost_equal, assert_allclose, assert_equal
99
)
1010
import pytest
1111

@@ -90,35 +90,6 @@ def test_pmt_decimal(self):
9090
assert_equal(res[1][0], tgt[1][0])
9191
assert_equal(res[1][1], tgt[1][1])
9292

93-
def test_ppmt(self):
94-
assert_equal(numpy.round(npf.ppmt(0.1 / 12, 1, 60, 55000), 2), -710.25)
95-
96-
def test_ppmt_decimal(self):
97-
assert_equal(npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
98-
Decimal('60'), Decimal('55000')),
99-
Decimal('-710.2541257864217612489830917'))
100-
101-
# Two tests showing how Decimal is actually getting at a more exact result
102-
# .23 / 12 does not come out nicely as a float but does as a decimal
103-
def test_ppmt_special_rate(self):
104-
assert_equal(numpy.round(npf.ppmt(0.23 / 12, 1, 60, 10000000000), 8),
105-
-90238044.232277036)
106-
107-
def test_ppmt_special_rate_decimal(self):
108-
# When rounded out to 8 decimal places like the float based test,
109-
# this should not equal the same value as the float, substituted
110-
# for the decimal
111-
def raise_error_because_not_equal():
112-
assert_equal(
113-
round(npf.ppmt(Decimal('0.23') / Decimal('12'), 1, 60,
114-
Decimal('10000000000')), 8),
115-
Decimal('-90238044.232277036'))
116-
117-
assert_raises(AssertionError, raise_error_because_not_equal)
118-
assert_equal(npf.ppmt(Decimal('0.23') / Decimal('12'), 1, 60,
119-
Decimal('10000000000')),
120-
Decimal('-90238044.2322778884413969909'))
121-
12293
def test_npv(self):
12394
assert_almost_equal(
12495
npf.npv(0.05, [-15000, 1500, 2500, 3500, 4500, 6000]),
@@ -191,15 +162,6 @@ def test_when(self):
191162
assert_equal(npf.pmt(0.08 / 12, 5 * 12, 15000., 0, 0),
192163
npf.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end'))
193164

194-
# begin
195-
assert_equal(npf.ppmt(0.1 / 12, 1, 60, 55000, 0, 1),
196-
npf.ppmt(0.1 / 12, 1, 60, 55000, 0, 'begin'))
197-
# end
198-
assert_equal(npf.ppmt(0.1 / 12, 1, 60, 55000, 0),
199-
npf.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
200-
assert_equal(npf.ppmt(0.1 / 12, 1, 60, 55000, 0, 0),
201-
npf.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
202-
203165
# begin
204166
assert_equal(npf.nper(0.075, -2000, 0, 100000., 1),
205167
npf.nper(0.075, -2000, 0, 100000., 'begin'))
@@ -243,86 +205,10 @@ def test_decimal_with_when(self):
243205
npf.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'),
244206
Decimal('0'), 'end'))
245207

246-
# begin
247-
assert_equal(npf.pmt(Decimal('0.08') / Decimal('12'),
248-
Decimal('5') * Decimal('12'), Decimal('15000.'),
249-
Decimal('0'), Decimal('1')),
250-
npf.pmt(Decimal('0.08') / Decimal('12'),
251-
Decimal('5') * Decimal('12'), Decimal('15000.'),
252-
Decimal('0'), 'begin'))
253-
# end
254-
assert_equal(npf.pmt(Decimal('0.08') / Decimal('12'),
255-
Decimal('5') * Decimal('12'), Decimal('15000.'),
256-
Decimal('0')),
257-
npf.pmt(Decimal('0.08') / Decimal('12'),
258-
Decimal('5') * Decimal('12'), Decimal('15000.'),
259-
Decimal('0'), 'end'))
260-
assert_equal(npf.pmt(Decimal('0.08') / Decimal('12'),
261-
Decimal('5') * Decimal('12'), Decimal('15000.'),
262-
Decimal('0'), Decimal('0')),
263-
npf.pmt(Decimal('0.08') / Decimal('12'),
264-
Decimal('5') * Decimal('12'), Decimal('15000.'),
265-
Decimal('0'), 'end'))
266-
267-
# begin
268-
assert_equal(npf.ppmt(Decimal('0.1') / Decimal('12'),
269-
Decimal('1'), Decimal('60'), Decimal('55000'),
270-
Decimal('0'), Decimal('1')),
271-
npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
272-
Decimal('60'), Decimal('55000'),
273-
Decimal('0'), 'begin'))
274-
# end
275-
assert_equal(npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
276-
Decimal('60'), Decimal('55000'), Decimal('0')),
277-
npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
278-
Decimal('60'), Decimal('55000'), Decimal('0'),
279-
'end'))
280-
assert_equal(npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
281-
Decimal('60'), Decimal('55000'), Decimal('0'),
282-
Decimal('0')),
283-
npf.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'),
284-
Decimal('60'), Decimal('55000'), Decimal('0'),
285-
'end'))
286-
287208
def test_broadcast(self):
288209
assert_almost_equal(npf.nper(0.075, -2000, 0, 100000., [0, 1]),
289210
[21.5449442, 20.76156441], 4)
290211

291-
assert_almost_equal(npf.ppmt(0.1 / 12, list(range(5)), 24, 2000),
292-
[numpy.nan, -75.62318601, -76.25337923,
293-
-76.88882405, -77.52956425], 4)
294-
295-
assert_almost_equal(npf.ppmt(0.1 / 12, list(range(5)), 24, 2000, 0,
296-
[0, 0, 1, 'end', 'begin']),
297-
[numpy.nan, -75.62318601, -75.62318601,
298-
-76.88882405, -76.88882405], 4)
299-
300-
def test_broadcast_decimal(self):
301-
# Use almost equal because precision is tested in the explicit tests,
302-
# this test is to ensure broadcast with Decimal is not broken.
303-
assert_almost_equal(npf.ppmt(Decimal('0.1') / Decimal('12'),
304-
list(range(1, 5)), Decimal('24'),
305-
Decimal('2000')),
306-
[Decimal('-75.62318601'),
307-
Decimal('-76.25337923'), Decimal('-76.88882405'),
308-
Decimal('-77.52956425')], 4)
309-
310-
result = npf.ppmt(
311-
Decimal('0.1') / Decimal('12'),
312-
list(range(1, 5)),
313-
Decimal('24'),
314-
Decimal('2000'),
315-
Decimal('0'),
316-
[Decimal('0'), Decimal('1'), 'end', 'begin']
317-
)
318-
desired = [
319-
Decimal('-75.62318601'),
320-
Decimal('-75.62318601'),
321-
Decimal('-76.88882405'),
322-
Decimal('-76.88882405')
323-
]
324-
assert_almost_equal(result, desired, decimal=4)
325-
326212

327213
class TestNper:
328214
def test_basic_values(self):
@@ -348,6 +234,129 @@ def test_no_interest(self):
348234
assert_(npf.nper(0, -100, 1000) == 10)
349235

350236

237+
class TestPpmt:
238+
def test_float(self):
239+
assert_allclose(
240+
npf.ppmt(0.1 / 12, 1, 60, 55000),
241+
-710.25,
242+
rtol=1e-4
243+
)
244+
245+
def test_decimal(self):
246+
result = npf.ppmt(
247+
Decimal('0.1') / Decimal('12'),
248+
Decimal('1'),
249+
Decimal('60'),
250+
Decimal('55000')
251+
)
252+
assert_equal(
253+
result,
254+
Decimal('-710.2541257864217612489830917'),
255+
)
256+
257+
@pytest.mark.parametrize('when', [1, 'begin'])
258+
def test_when_is_begin(self, when):
259+
assert_allclose(
260+
npf.ppmt(0.1 / 12, 1, 60, 55000, 0, when),
261+
-1158.929712, # Computed using Google Sheet's PPMT
262+
rtol=1e-9,
263+
)
264+
265+
@pytest.mark.parametrize('when', [None, 0, 'end'])
266+
def test_when_is_end(self, when):
267+
args = (0.1 / 12, 1, 60, 55000, 0)
268+
result = npf.ppmt(*args) if when is None else npf.ppmt(*args, when)
269+
assert_allclose(
270+
result,
271+
-710.254126, # Computed using Google Sheet's PPMT
272+
rtol=1e-9,
273+
)
274+
275+
@pytest.mark.parametrize('when', [Decimal('1'), 'begin'])
276+
def test_when_is_begin_decimal(self, when):
277+
result = npf.ppmt(
278+
Decimal('0.08') / Decimal('12'),
279+
Decimal('1'),
280+
Decimal('60'),
281+
Decimal('15000.'),
282+
Decimal('0'),
283+
when
284+
)
285+
assert_almost_equal(
286+
result,
287+
Decimal('-302.131703'), # Computed using Google Sheet's PPMT
288+
decimal=5,
289+
)
290+
291+
@pytest.mark.parametrize('when', [None, Decimal('0'), 'end'])
292+
def test_when_is_end_decimal(self, when):
293+
args = (
294+
Decimal('0.08') / Decimal('12'),
295+
Decimal('1'),
296+
Decimal('60'),
297+
Decimal('15000.'),
298+
Decimal('0')
299+
)
300+
result = npf.ppmt(*args) if when is None else npf.ppmt(*args, when)
301+
assert_almost_equal(
302+
result,
303+
Decimal('-204.145914'), # Computed using Google Sheet's PPMT
304+
decimal=5,
305+
)
306+
307+
@pytest.mark.parametrize('args', [
308+
(0.1 / 12, 0, 60, 15000),
309+
(Decimal('0.012'), Decimal('0'), Decimal('60'), Decimal('15000'))
310+
])
311+
def test_invalid_per(self, args):
312+
# Note that math.isnan() handles Decimal NaN correctly.
313+
assert math.isnan(npf.ppmt(*args))
314+
315+
@pytest.mark.parametrize('when, desired', [
316+
(
317+
None,
318+
[-75.62318601, -76.25337923, -76.88882405, -77.52956425],
319+
), (
320+
[0, 1, 'end', 'begin'],
321+
[-75.62318601, -75.62318601, -76.88882405, -76.88882405],
322+
)
323+
])
324+
def test_broadcast(self, when, desired):
325+
args = (0.1 / 12, numpy.arange(1, 5), 24, 2000, 0)
326+
result = npf.ppmt(*args) if when is None else npf.ppmt(*args, when)
327+
assert_allclose(result, desired, rtol=1e-5)
328+
329+
@pytest.mark.parametrize('when, desired', [
330+
(
331+
None,
332+
[
333+
Decimal('-75.62318601'),
334+
Decimal('-76.25337923'),
335+
Decimal('-76.88882405'),
336+
Decimal('-77.52956425')
337+
],
338+
), (
339+
[Decimal('0'), Decimal('1'), 'end', 'begin'],
340+
[
341+
Decimal('-75.62318601'),
342+
Decimal('-75.62318601'),
343+
Decimal('-76.88882405'),
344+
Decimal('-76.88882405')
345+
]
346+
)
347+
])
348+
def test_broadcast_decimal(self, when, desired):
349+
args = (
350+
Decimal('0.1') / Decimal('12'),
351+
numpy.arange(1, 5),
352+
Decimal('24'),
353+
Decimal('2000'),
354+
Decimal('0')
355+
)
356+
result = npf.ppmt(*args) if when is None else npf.ppmt(*args, when)
357+
assert_almost_equal(result, desired, decimal=8)
358+
359+
351360
class TestIpmt:
352361
def test_float(self):
353362
assert_allclose(
@@ -372,7 +381,6 @@ def test_when_is_end(self, when):
372381
result = npf.ipmt(0.1 / 12, 1, 24, 2000, 0, when)
373382
assert_allclose(result, -16.666667, rtol=1e-6)
374383

375-
376384
@pytest.mark.parametrize('when', [Decimal('1'), 'begin'])
377385
def test_when_is_begin_decimal(self, when):
378386
result = npf.ipmt(

0 commit comments

Comments
 (0)