50 lines
1.7 KiB
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);
|
|
}
|
|
});
|