CluPilotCloud/tests/Unit/MoneyTest.php

50 lines
1.7 KiB
PHP

<?php
use App\Support\Money;
/**
* Euros in, cents out.
*
* The console asked the owner to type cents, so a €799 plan was entered as
* "79900" and one slipped digit was a factor of ten on an invoice.
*/
it('converts what an operator actually types', function (string $typed, ?int $cents) {
expect(Money::toCents($typed))->toBe($cents);
})->with([
['799', 79900],
['79,90', 7990], // German keyboard
['79.90', 7990], // copied from somewhere
['0', 0],
['0,05', 5],
[' 149 ', 14900],
['79,9', 7990], // one decimal is still a price
['', null],
['neunzehn', null],
['1.000', null], // a thousand, or one euro? refuse rather than guess
['79,999', null], // no fractions of a cent
['-5', null],
// Parses fine, then overflows the unsigned column — a typo must come back
// as a message beside the field, not as a database error on submit.
['999999999', null],
['42949672,96', null],
['42949672,95', 4294967295],
]);
it('does not lose a cent to binary floating point', function () {
// (float) '79.90' * 100 is 7989.999… and casting truncates to 7989 — one
// cent short, on exactly the prices people charge.
foreach (['79,90', '19,90', '0,29', '1234,56'] as $typed) {
expect(Money::toCents($typed))->toBe((int) round((float) str_replace(',', '.', $typed) * 100), $typed);
}
expect(Money::toCents('79,90'))->toBe(7990)
->and(Money::toCents('0,29'))->toBe(29);
});
it('round-trips through the form', function () {
foreach ([0, 5, 7990, 79900, 958800] as $cents) {
expect(Money::toCents(Money::fromCents($cents)))->toBe($cents);
}
});