Skip to content

Commit

Permalink
feat: Adds implementation for NegativeBigDecimal.
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavofreze committed Oct 31, 2024
1 parent 9b145b4 commit cd05d1e
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 4 deletions.
17 changes: 17 additions & 0 deletions src/Internal/Exceptions/NonNegativeValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Math\Internal\Exceptions;

use RuntimeException;
use TinyBlocks\Math\Internal\Number;

final class NonNegativeValue extends RuntimeException
{
public function __construct(Number $number)
{
$template = 'Value <%s> is not valid. Must be a negative number less than zero.';
parent::__construct(message: sprintf($template, $number->value));
}
}
5 changes: 5 additions & 0 deletions src/Internal/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public function isNegative(): bool
return $this->value < self::ZERO;
}

public function isPositiveOrZero(): bool
{
return $this->isZero() || !$this->isNegative();
}

public function isNegativeOrZero(): bool
{
return $this->isZero() || $this->isNegative();
Expand Down
2 changes: 1 addition & 1 deletion src/Internal/Operations/Adapters/BcMathAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use TinyBlocks\Math\Internal\Operations\Adapters\Scales\Subtraction;
use TinyBlocks\Math\Internal\Operations\MathOperations;

final class BcMathAdapter implements MathOperations
final readonly class BcMathAdapter implements MathOperations
{
public function add(BigNumber $augend, BigNumber $addend): Result
{
Expand Down
2 changes: 1 addition & 1 deletion src/Internal/Operations/Extension/ExtensionAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace TinyBlocks\Math\Internal\Operations\Extension;

final class ExtensionAdapter implements Extension
final readonly class ExtensionAdapter implements Extension
{
public function isAvailable(string $extension): bool
{
Expand Down
4 changes: 2 additions & 2 deletions src/Internal/Scale.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
use TinyBlocks\Math\BigNumber;
use TinyBlocks\Math\Internal\Exceptions\InvalidScale;

final class Scale
final readonly class Scale
{
private const MINIMUM = 0;
private const MAXIMUM = 2147483647;
private const ZERO_DECIMAL_PLACE = 0;

private function __construct(public readonly ?int $value)
private function __construct(public ?int $value)
{
if (!$this->hasAutomaticScale() && ($this->value < self::MINIMUM || $this->value > self::MAXIMUM)) {
throw new InvalidScale(value: $this->value, minimum: self::MINIMUM, maximum: self::MAXIMUM);
Expand Down
35 changes: 35 additions & 0 deletions src/NegativeBigDecimal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Math;

use TinyBlocks\Math\Internal\BigNumberBehavior;
use TinyBlocks\Math\Internal\Exceptions\NonNegativeValue;
use TinyBlocks\Math\Internal\Number;
use TinyBlocks\Math\Internal\Scale;

class NegativeBigDecimal extends BigNumberBehavior implements BigNumber
{
protected function __construct(string|float $value, ?int $scale = null)
{
$scale = Scale::from(value: $scale);
$number = Number::from(value: $value);

if ($number->isPositiveOrZero()) {
throw new NonNegativeValue(number: $number);
}

parent::__construct(number: $number, scale: $scale);
}

public static function fromFloat(float $value, ?int $scale = BigNumber::AUTOMATIC_SCALE): NegativeBigDecimal
{
return new NegativeBigDecimal(value: $value, scale: $scale);
}

public static function fromString(string $value, ?int $scale = BigNumber::AUTOMATIC_SCALE): NegativeBigDecimal
{
return new NegativeBigDecimal(value: $value, scale: $scale);
}
}
74 changes: 74 additions & 0 deletions tests/NegativeBigDecimalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Math;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use TinyBlocks\Math\Internal\Exceptions\NonNegativeValue;

final class NegativeBigDecimalTest extends TestCase
{
public function testFromFloat(): void
{
/** @Given a negative float value */
$value = -1.0;

/** @When creating a NegativeBigDecimal from the float */
$actual = NegativeBigDecimal::fromFloat(value: $value);

/** @Then the created object should be an instance of both BigNumber and NegativeBigDecimal */
self::assertInstanceOf(BigNumber::class, $actual);
self::assertInstanceOf(NegativeBigDecimal::class, $actual);
}

public function testFromString(): void
{
/** @Given a negative string value */
$value = '-0.3333333333333333333333';

/** @When creating a NegativeBigDecimal from the string */
$actual = NegativeBigDecimal::fromString(value: $value);

/** @Then the created object should be an instance of both BigNumber and NegativeBigDecimal */
self::assertInstanceOf(BigNumber::class, $actual);
self::assertInstanceOf(NegativeBigDecimal::class, $actual);
}

#[DataProvider('dataProviderForTestNonNegativeValue')]
public function testNonNegativeValue(mixed $value): void
{
/** @Given a non-negative value */
$template = 'Value <%s> is not valid. Must be a negative number less than zero.';

/** @Then a NonNegativeValue exception should be thrown with the correct message */
$this->expectException(NonNegativeValue::class);
$this->expectExceptionMessage(sprintf($template, $value));

/** @When attempting to create a NegativeBigDecimal with a non-negative value */
NegativeBigDecimal::fromFloat(value: $value);
}

public function testNonNegativeValueWithNegate(): void
{
/** @Given a NegativeBigDecimal value */
$template = 'Value <%s> is not valid. Must be a negative number less than zero.';

/** @Then a NonNegativeValue exception should be thrown when the value is negated */
$this->expectException(NonNegativeValue::class);
$this->expectExceptionMessage(sprintf($template, 10.155));

/** @When negating a negative number, it should trigger an exception */
$negative = NegativeBigDecimal::fromFloat(value: -10.155);
$negative->negate();
}

public static function dataProviderForTestNonNegativeValue(): array
{
return [
'Zero value' => ['value' => 0],
'Positive integer' => ['value' => 1]
];
}
}

0 comments on commit cd05d1e

Please sign in to comment.