Files
budget/scripts/self-test.php
T
Ty Clifford 51ee4ecb5a -
Finished the planner end to end.
Corrected rollover and yearly accounting, recurring targets, savings 
rules, and targeted dormant restorations.
Added editing/deletion for income, expenses, targets, and categories.
Rebuilt dashboard, analytics, calendar, settings, exports, 
authentication, and responsive mobile UI.
Added original artwork at 
[financial-flow.png](/Users/tyemeclifford/Documents/GH/budget/public/assets/images/financial-flow.png), 
generated with built-in Imagegen using an abstract financial-momentum 
landscape prompt.
Added 
[self-test.php](/Users/tyemeclifford/Documents/GH/budget/scripts/self-test.php).
Verification passed: automated accounting/export tests, full browser 
workflow, responsive 390px layout, light/dark themes, and no console 
errors. Tested with FrankenPHP v1.12.4. Live Mailgun delivery was not 
attempted without credentials.
2026-06-15 10:33:55 -04:00

61 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
use Budget\ExportService;
$databasePath = sys_get_temp_dir() . '/neon-ledger-self-test-' . getmypid() . '.sqlite';
putenv('BUDGET_SQLITE_PATH=' . $databasePath);
register_shutdown_function(static function () use ($databasePath): void {
foreach ([$databasePath, $databasePath . '-shm', $databasePath . '-wal'] as $file) {
if (is_file($file)) {
unlink($file);
}
}
});
require __DIR__ . '/../app/bootstrap.php';
$assert = static function (bool $condition, string $message): void {
if (!$condition) {
throw new RuntimeException($message);
}
};
$settings->set('dead.income_mode', 'percent');
$settings->set('dead.income_value', 10);
$settings->set('dead.transaction_mode', 'fixed');
$settings->set('dead.transaction_value', 1);
$budget->savePlan('2026-01', 1000, 0, true, 'Self-test');
$categoryId = $budget->addCategory('Utilities', '#49a8ff', 200);
$itemId = $budget->addBudgetItem('2026-01', $categoryId, 'Internet', 55, '2026-01-20', 'monthly', '');
$transactionId = $budget->addTransaction('2026-01', $itemId, null, 'Internet payment', 10, '2026-01-10', '');
$january = $budget->summary('2026-01');
$assert(abs($january['remaining'] - 889) < 0.001, 'January remaining balance is incorrect.');
$assert(abs($budget->budgetItems('2026-01')[0]['remaining_amount'] - 45) < 0.001, 'Target progress is incorrect.');
$budget->updateTransaction($transactionId, '2026-01', $itemId, null, 'Internet payment', 20, '2026-01-10', '');
$budget->moveDeadAccount('2026-01', 'restore', 50, '', 'item', $itemId);
$january = $budget->summary('2026-01');
$assert(abs($january['remaining'] - 929) < 0.001, 'Dormant restoration accounting is incorrect.');
$assert(abs($budget->deadBalance() - 51) < 0.001, 'Dormant balance is incorrect.');
$february = $budget->ensureMonth('2026-02');
$februaryItems = $budget->budgetItems('2026-02');
$assert(abs((float) $february['rollover_in'] - 929) < 0.001, 'Rolling budget did not carry the remainder forward.');
$assert(count($februaryItems) === 1 && $februaryItems[0]['name'] === 'Internet', 'Recurring target was not materialized.');
$year = $budget->yearlySummary(2026);
$assert(abs($year['totals']['fresh_income'] - 1000) < 0.001, 'Yearly income double-counted rollover.');
$exporter = new ExportService($pdo, $settings, $budget);
$package = json_decode($exporter->package(), true);
$assert(($package['format'] ?? null) === 'neon-ledger/budget-planner', 'JSON package format is invalid.');
$assert(str_contains($exporter->html('2026-01'), 'Internet'), 'HTML export is missing target data.');
$assert(str_starts_with($exporter->pdf('2026-01'), '%PDF-1.4'), 'PDF export is invalid.');
echo "Neon Ledger self-test passed.\n";