98 lines
3.0 KiB
PHP
98 lines
3.0 KiB
PHP
<?php
|
|
|
|
use App\Services\LoanAmortizationService;
|
|
|
|
beforeEach(function () {
|
|
$this->service = new LoanAmortizationService;
|
|
});
|
|
|
|
it('calculates monthly payment for a standard loan', function () {
|
|
// $200,000 loan at 3.5% for 30 years (360 months)
|
|
$payment = $this->service->calculateMonthlyPayment(20000000, 3.5, 360);
|
|
|
|
// Expected ~$898.09/month = ~89809 cents
|
|
expect($payment)->toBeGreaterThan(89500)
|
|
->toBeLessThan(90100);
|
|
});
|
|
|
|
it('calculates monthly payment for a zero interest loan', function () {
|
|
// $120,000 loan at 0% for 10 years (120 months) = $1000/month
|
|
$payment = $this->service->calculateMonthlyPayment(12000000, 0, 120);
|
|
|
|
expect($payment)->toBe(10000_0);
|
|
});
|
|
|
|
it('returns zero payment for zero term', function () {
|
|
$payment = $this->service->calculateMonthlyPayment(20000000, 3.5, 0);
|
|
|
|
expect($payment)->toBe(0);
|
|
});
|
|
|
|
it('calculates remaining balance after payments', function () {
|
|
// $200,000 at 3.5% for 360 months, after 12 payments
|
|
$remaining = $this->service->calculateRemainingBalance(20000000, 3.5, 360, 12);
|
|
|
|
// After 1 year, should still owe most of the principal
|
|
expect($remaining)->toBeGreaterThan(19500000)
|
|
->toBeLessThan(19800000);
|
|
});
|
|
|
|
it('returns zero balance when all payments made', function () {
|
|
$remaining = $this->service->calculateRemainingBalance(20000000, 3.5, 360, 360);
|
|
|
|
expect($remaining)->toBe(0);
|
|
});
|
|
|
|
it('returns zero balance when payments exceed term', function () {
|
|
$remaining = $this->service->calculateRemainingBalance(20000000, 3.5, 360, 400);
|
|
|
|
expect($remaining)->toBe(0);
|
|
});
|
|
|
|
it('returns full principal when no payments made', function () {
|
|
$remaining = $this->service->calculateRemainingBalance(20000000, 3.5, 360, 0);
|
|
|
|
expect($remaining)->toBe(20000000);
|
|
});
|
|
|
|
it('calculates remaining balance for zero interest loan', function () {
|
|
// $120,000 at 0% for 120 months, after 60 payments = $60,000 remaining
|
|
$remaining = $this->service->calculateRemainingBalance(12000000, 0, 120, 60);
|
|
|
|
expect($remaining)->toBe(6000000);
|
|
});
|
|
|
|
it('projects future balances from a known balance point', function () {
|
|
$projection = $this->service->projectFromBalance(
|
|
20000000,
|
|
now()->startOfMonth(),
|
|
3.5,
|
|
360,
|
|
6,
|
|
);
|
|
|
|
expect($projection)->toHaveCount(6);
|
|
|
|
// Each subsequent month should have a lower balance
|
|
$values = array_values($projection);
|
|
for ($i = 1; $i < count($values); $i++) {
|
|
expect($values[$i])->toBeLessThan($values[$i - 1]);
|
|
}
|
|
});
|
|
|
|
it('limits projection to remaining months when fewer than requested', function () {
|
|
$projection = $this->service->projectFromBalance(
|
|
100000,
|
|
now()->startOfMonth(),
|
|
3.5,
|
|
3,
|
|
12,
|
|
);
|
|
|
|
expect($projection)->toHaveCount(3);
|
|
});
|
|
|
|
// Tests for calculateRemainingMonths and getBalanceAtDate are in
|
|
// tests/Feature/LoanTest.php because they require Eloquent model
|
|
// instantiation which needs a database connection (HasUuids trait).
|