• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / money / 22258348283

21 Feb 2026 02:17PM UTC coverage: 97.711% (-0.2%) from 97.88%
22258348283

Pull #32

github

web-flow
Merge f840a0878 into 1052a0541
Pull Request #32: Reorganize exceptions structure

2 of 4 new or added lines in 2 files covered. (50.0%)

555 of 568 relevant lines covered (97.71%)

28.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/src/Context/CustomContext.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Money\Context;
6

7
use Brick\Math\BigDecimal;
8
use Brick\Math\BigInteger;
9
use Brick\Math\BigNumber;
10
use Brick\Math\RoundingMode;
11
use Brick\Money\Context;
12
use Brick\Money\Currency;
13
use Brick\Money\Exception\InvalidArgumentException;
14
use Override;
15

16
/**
17
 * Adjusts a number to a custom scale and optionally step.
18
 */
19
final readonly class CustomContext implements Context
20
{
21
    /**
22
     * @param non-negative-int $scale The scale of the monies using this context.
23
     * @param positive-int     $step  An optional cash rounding step. Must either divide 10^scale or be a multiple of 10^scale.
24
     *                                For example, scale=2 and step=5 allows 0.00, 0.05, 0.10, etc.
25
     *                                And scale=2 and step=1000 allows 0.00, 10.00, 20.00, etc.
26
     */
27
    public function __construct(
28
        private int $scale,
29
        private int $step = 1,
30
    ) {
31
        /** @psalm-suppress DocblockTypeContradiction, NoValue */
32
        if ($scale < 0) {
142✔
NEW
33
            throw InvalidArgumentException::invalidScale($scale);
×
34
        }
35

36
        if ($step < 1 || ! $this->isValidStepForScale($scale, $step)) {
142✔
37
            throw InvalidArgumentException::invalidStep($step);
49✔
38
        }
39
    }
40

41
    #[Override]
42
    public function applyTo(BigNumber $amount, Currency $currency, RoundingMode $roundingMode): BigDecimal
43
    {
44
        if ($this->step === 1) {
82✔
45
            return $amount->toScale($this->scale, $roundingMode);
49✔
46
        }
47

48
        return $amount
33✔
49
            ->toBigRational()
33✔
50
            ->dividedBy($this->step)
33✔
51
            ->toScale($this->scale, $roundingMode)
33✔
52
            ->multipliedBy($this->step);
33✔
53
    }
54

55
    #[Override]
56
    public function getStep(): int
57
    {
58
        return $this->step;
53✔
59
    }
60

61
    #[Override]
62
    public function isFixedScale(): bool
63
    {
64
        return true;
1✔
65
    }
66

67
    /**
68
     * Returns the scale used by this context.
69
     *
70
     * @return non-negative-int
71
     */
72
    public function getScale(): int
73
    {
74
        return $this->scale;
1✔
75
    }
76

77
    /**
78
     * @param non-negative-int $scale
79
     * @param positive-int     $step
80
     */
81
    private function isValidStepForScale(int $scale, int $step): bool
82
    {
83
        $step = BigInteger::of($step);
122✔
84
        $power = BigInteger::ten()->power($scale);
122✔
85

86
        return $power->mod($step)->isZero() || $step->mod($power)->isZero();
122✔
87
    }
88
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc