Skip to content

Commit

Permalink
refactor: Improves strict typing and tests. (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavofreze authored Oct 5, 2024
1 parent 9199b50 commit 0835561
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 84 deletions.
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/tests export-ignore
/vendor export-ignore

/LICENSE export-ignore
/Makefile export-ignore
/README.md export-ignore
/phpmd.xml export-ignore
/phpunit.xml export-ignore
/phpstan.neon.dist export-ignore
/infection.json.dist export-ignore

/.github export-ignore
/.gitignore export-ignore
/.gitattributes export-ignore
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Use PHP 8.2
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'

- name: Install dependencies
run: composer update --no-progress --optimize-autoloader

Expand All @@ -33,6 +38,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Use PHP 8.2
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'

- name: Install dependencies
run: composer update --no-progress --optimize-autoloader

Expand Down
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
DOCKER_RUN = docker run --rm -it --net=host -v ${PWD}:/app -w /app gustavofreze/php:8.2

.PHONY: configure test test-no-coverage review show-reports clean
.PHONY: configure test test-file test-no-coverage review show-reports clean

configure:
@${DOCKER_RUN} composer update --optimize-autoloader

test: review
test:
@${DOCKER_RUN} composer tests

test-no-coverage: review
test-file:
@${DOCKER_RUN} composer tests-file-no-coverage ${FILE}

test-no-coverage:
@${DOCKER_RUN} composer tests-no-coverage

review:
Expand All @@ -19,4 +22,4 @@ show-reports:

clean:
@sudo chown -R ${USER}:${USER} ${PWD}
@rm -rf report vendor
@rm -rf report vendor .phpunit.cache
28 changes: 17 additions & 11 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
"vo",
"psr",
"money",
"psr-4",
"psr-12",
"tiny-blocks",
"value-object"
],
Expand All @@ -21,6 +19,10 @@
"homepage": "https://github.com/gustavofreze"
}
],
"support": {
"issues": "https://github.com/tiny-blocks/money/issues",
"source": "https://github.com/tiny-blocks/money"
},
"config": {
"sort-packages": true,
"allow-plugins": {
Expand All @@ -38,30 +40,34 @@
}
},
"require": {
"php": "^8.1||^8.2",
"tiny-blocks/math": "^2.0",
"tiny-blocks/currency": "^2.0",
"tiny-blocks/value-object": "^2.0"
"php": "^8.2",
"tiny-blocks/math": "^2",
"tiny-blocks/currency": "^2",
"tiny-blocks/value-object": "^2",
"ext-bcmath": "*"
},
"require-dev": {
"infection/infection": "^0.26",
"phpmd/phpmd": "^2.13",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.7"
"phpmd/phpmd": "^2.15",
"phpunit/phpunit": "^11",
"phpstan/phpstan": "^1",
"infection/infection": "^0.29",
"squizlabs/php_codesniffer": "^3.10"
},
"suggest": {
"ext-bcmath": "Enables the extension which is an interface to the GNU implementation as a Basic Calculator utility library."
},
"scripts": {
"phpcs": "phpcs --standard=PSR12 --extensions=php ./src",
"phpmd": "phpmd ./src text phpmd.xml --suffixes php --exclude --ignore-violations-on-exit",
"phpstan": "phpstan analyse -c phpstan.neon.dist --quiet --no-progress",
"test": "phpunit --log-junit=report/coverage/junit.xml --coverage-xml=report/coverage/coverage-xml --coverage-html=report/coverage/coverage-html tests",
"test-mutation": "infection --only-covered --logger-html=report/coverage/mutation-report.html --coverage=report/coverage --min-msi=100 --min-covered-msi=100 --threads=4",
"test-no-coverage": "phpunit --no-coverage",
"test-mutation-no-coverage": "infection --only-covered --min-msi=100 --threads=4",
"review": [
"@phpcs",
"@phpmd"
"@phpmd",
"@phpstan"
],
"tests": [
"@test",
Expand Down
14 changes: 5 additions & 9 deletions infection.json.dist
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
{
"timeout": 10,
"testFramework": "phpunit",
"tmpDir": "report/",
"tmpDir": "report/infection/",
"source": {
"directories": [
"src"
]
},
"logs": {
"text": "report/logs/infection-text.log",
"summary": "report/logs/infection-summary.log"
"text": "report/infection/logs/infection-text.log",
"summary": "report/infection/logs/infection-summary.log"
},
"mutators": {
"@default": true,
"DecrementInteger": false,
"IncrementInteger": false,
"MethodCallRemoval": false,
"ProtectedVisibility": false
"@default": true
},
"phpUnit": {
"configDir": "",
"customPath": "./vendor/bin/phpunit"
}
}
}
7 changes: 7 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
parameters:
paths:
- src
level: 9
tmpDir: report/phpstan
ignoreErrors:
reportUnmatchedIgnoredErrors: false
38 changes: 24 additions & 14 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
cacheResultFile="report/.phpunit.result.cache"
backupGlobals="false"
backupStaticAttributes="false"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
cacheDirectory=".phpunit.cache"
beStrictAboutOutputDuringTests="true">

<source>
<include>
<directory>src</directory>
</include>
</source>

<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
<directory>tests</directory>
</testsuite>
</testsuites>

<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<text outputFile="report/coverage.txt"/>
<html outputDirectory="report/html/"/>
<clover outputFile="report/coverage-clover.xml"/>
</report>
</coverage>

<logging>
<junit outputFile="report/execution-result.xml"/>
</logging>

</phpunit>
2 changes: 2 additions & 0 deletions src/Internal/Exceptions/DifferentCurrencies.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Money\Internal\Exceptions;

use RuntimeException;
Expand Down
4 changes: 3 additions & 1 deletion src/Internal/Exceptions/InvalidCurrencyScale.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Money\Internal\Exceptions;

use RuntimeException;
Expand All @@ -17,7 +19,7 @@ public function __construct(BigNumber $amount, Currency $currency)
$template,
$amount->getScale(),
$currency->name,
$currency->getDefaultFractionDigits()
$currency->getFractionDigits()
)
);
}
Expand Down
41 changes: 29 additions & 12 deletions src/Money.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace TinyBlocks\Money;

use TinyBlocks\Currency\Currency;
Expand All @@ -10,23 +12,38 @@
use TinyBlocks\Vo\ValueObject;
use TinyBlocks\Vo\ValueObjectAdapter;

final class Money implements ValueObject
final readonly class Money implements ValueObject
{
use ValueObjectAdapter;

private function __construct(public readonly BigNumber $amount, public readonly Currency $currency)
private const ONE = 1;

private function __construct(public BigNumber $amount, public Currency $currency)
{
$withAmountScale = $this->amount->multiply(multiplier: BigDecimal::from(value: 1));
$withAmountScale = $this->amount->multiply(multiplier: BigDecimal::from(value: self::ONE));

if ($withAmountScale->getScale() > $this->currency->getDefaultFractionDigits()) {
if ($withAmountScale->getScale() > $this->currency->getFractionDigits()) {
throw new InvalidCurrencyScale(amount: $withAmountScale, currency: $this->currency);
}
}

public static function from(float|string|BigNumber $value, string|Currency $currency): Money
public static function from(BigNumber $value, Currency $currency): Money
{
return new Money(amount: $value, currency: $currency);
}

public static function fromFloat(float $value, string $currency): Money
{
$amount = BigDecimal::from(value: $value);
$currency = Currency::from(value: $currency);

return new Money(amount: $amount, currency: $currency);
}

public static function fromString(string $value, string $currency): Money
{
$currency = is_string($currency) ? Currency::from(value: $currency) : $currency;
$amount = is_scalar($value) ? BigDecimal::from(value: $value) : $value;
$amount = BigDecimal::from(value: $value);
$currency = Currency::from(value: $currency);

return new Money(amount: $amount, currency: $currency);
}
Expand All @@ -39,7 +56,7 @@ public function add(Money $addend): Money

$result = $this->amount->add(addend: $addend->amount);

return self::from(value: $result->toString(), currency: $this->currency);
return self::fromString(value: $result->toString(), currency: $this->currency->value);
}

public function subtract(Money $subtrahend): Money
Expand All @@ -50,7 +67,7 @@ public function subtract(Money $subtrahend): Money

$result = $this->amount->subtract(subtrahend: $subtrahend->amount);

return self::from(value: $result->toString(), currency: $this->currency);
return self::fromString(value: $result->toString(), currency: $this->currency->value);
}

public function multiply(Money $multiplier): Money
Expand All @@ -61,7 +78,7 @@ public function multiply(Money $multiplier): Money

$result = $this->amount->multiply(multiplier: $multiplier->amount);

return self::from(value: $result->toString(), currency: $this->currency);
return self::fromString(value: $result->toString(), currency: $this->currency->value);
}

public function divide(Money $divisor): Money
Expand All @@ -72,9 +89,9 @@ public function divide(Money $divisor): Money

$result = $this->amount
->divide(divisor: $divisor->amount)
->withScale(scale: $this->currency->getDefaultFractionDigits());
->withScale(scale: $this->currency->getFractionDigits());

return self::from(value: $result->toString(), currency: $this->currency);
return self::fromString(value: $result->toString(), currency: $this->currency->value);
}

private function areCurrenciesDifferent(Currency $currency): bool
Expand Down
Loading

0 comments on commit 0835561

Please sign in to comment.