Skip to content

Commit fa57db1

Browse files
authored
Merge pull request #3 from simPod/feat/tests
2 parents 5f8523e + 8bb5e25 commit fa57db1

17 files changed

+533
-5
lines changed

.github/workflows/tests.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: "Tests"
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- "main"
8+
9+
jobs:
10+
phpunit:
11+
name: "PHPUnit - ${{ matrix.package }} / PHP ${{ matrix.php-version }}"
12+
runs-on: "ubuntu-24.04"
13+
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
package:
18+
- "math"
19+
- "money"
20+
php-version:
21+
- "8.4"
22+
- "8.5"
23+
24+
defaults:
25+
run:
26+
working-directory: "${{ matrix.package }}"
27+
28+
steps:
29+
- name: "Checkout code"
30+
uses: "actions/checkout@v6"
31+
32+
- name: "Install PHP"
33+
uses: "shivammathur/setup-php@v2"
34+
with:
35+
coverage: "none"
36+
php-version: "${{ matrix.php-version }}"
37+
38+
- name: "Install dependencies with Composer"
39+
uses: "ramsey/composer-install@v3"
40+
with:
41+
working-directory: "${{ matrix.package }}"
42+
43+
- name: "Run tests with PHPUnit"
44+
run: "vendor/bin/phpunit"

math/composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"phpstan/phpstan": "^2.1"
1010
},
1111
"require-dev": {
12-
"cdn77/coding-standard": "^7.4"
12+
"cdn77/coding-standard": "^7.4",
13+
"phpunit/phpunit": "^11.5"
1314
},
1415
"extra": {
1516
"phpstan": {
@@ -27,5 +28,10 @@
2728
"psr-4": {
2829
"Brick\\Math\\PHPStan\\": "src/"
2930
}
31+
},
32+
"autoload-dev": {
33+
"psr-4": {
34+
"Brick\\Math\\PHPStan\\Tests\\": "tests/"
35+
}
3036
}
3137
}

math/phpunit.xml.dist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
5+
beStrictAboutChangesToGlobalState="true"
6+
beStrictAboutOutputDuringTests="true"
7+
executionOrder="random"
8+
colors="true"
9+
bootstrap="tests/bootstrap.php"
10+
>
11+
<testsuites>
12+
<testsuite name="Test Suite">
13+
<directory>tests</directory>
14+
</testsuite>
15+
</testsuites>
16+
17+
<source>
18+
<include>
19+
<directory>src</directory>
20+
</include>
21+
</source>
22+
</phpunit>

math/src/BigNumberOfThrowTypeExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ private function narrowNonRationalInput(
203203
*/
204204
private static function isNonZero(Type $type): bool
205205
{
206+
if (! (new IntegerType())->isSuperTypeOf($type)->yes()) {
207+
return false;
208+
}
209+
206210
return (new ConstantIntegerType(0))->isSuperTypeOf($type)->no();
207211
}
208212

math/src/BigNumberOperationThrowTypeExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ private static function getRequiredArgTypeForCallerType(Type $callerType): Type|
300300

301301
private static function isNonZero(Type $type): bool
302302
{
303+
if (! (new IntegerType())->isSuperTypeOf($type)->yes()) {
304+
return false;
305+
}
306+
303307
return (new ConstantIntegerType(0))->isSuperTypeOf($type)->no();
304308
}
305309

math/src/RoundingModeThrowTypeExtension.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,11 @@ private function isDivisorArgSafe(MethodReflection $methodReflection, Type $argT
210210
*/
211211
private static function isNonZero(Type $type): bool
212212
{
213-
$zeroType = new ConstantIntegerType(0);
213+
if (! (new IntegerType())->isSuperTypeOf($type)->yes()) {
214+
return false;
215+
}
214216

215-
return $zeroType->isSuperTypeOf($type)->no();
217+
return (new ConstantIntegerType(0))->isSuperTypeOf($type)->no();
216218
}
217219

218220
private static function isNotUnnecessary(Type $roundingModeType): bool
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Brick\Math\PHPStan\Tests;
6+
7+
use PHPStan\Testing\TypeInferenceTestCase;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
10+
class ThrowTypeExtensionTest extends TypeInferenceTestCase
11+
{
12+
/** @return iterable<mixed> */
13+
public static function dataFileAsserts(): iterable
14+
{
15+
yield from self::gatherAssertTypes(__DIR__ . '/data/BigNumberThrowTypes.php');
16+
}
17+
18+
#[DataProvider('dataFileAsserts')]
19+
public function testFileAsserts(string $assertType, string $file, mixed ...$args): void
20+
{
21+
$this->assertFileAsserts($assertType, $file, ...$args);
22+
}
23+
24+
/** @return list<string> */
25+
public static function getAdditionalConfigFiles(): array
26+
{
27+
return [__DIR__ . '/test.neon'];
28+
}
29+
}

math/tests/bootstrap.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require_once __DIR__ . '/../vendor/autoload.php';
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Brick\Math\PHPStan\Tests\Data;
6+
7+
use Brick\Math\BigDecimal;
8+
use Brick\Math\BigInteger;
9+
use Brick\Math\BigNumber;
10+
use Brick\Math\BigRational;
11+
use Brick\Math\RoundingMode;
12+
use PHPStan\TrinaryLogic;
13+
14+
use function PHPStan\Testing\assertVariableCertainty;
15+
16+
class BigNumberThrowTypes
17+
{
18+
// --- Factory methods ---
19+
20+
public function ofWithBigInteger(BigInteger $a): void
21+
{
22+
try {
23+
$result = BigInteger::of($a);
24+
} finally {
25+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
26+
}
27+
}
28+
29+
public function ofWithInt(): void
30+
{
31+
try {
32+
$result = BigDecimal::of(42);
33+
} finally {
34+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
35+
}
36+
}
37+
38+
public function ofWithString(string $s): void
39+
{
40+
try {
41+
$result = BigInteger::of($s);
42+
} finally {
43+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
44+
}
45+
}
46+
47+
// --- Conversion methods ---
48+
49+
public function toBigIntegerOnBigInteger(BigInteger $a): void
50+
{
51+
try {
52+
$result = $a->toBigInteger();
53+
} finally {
54+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
55+
}
56+
}
57+
58+
public function toBigDecimalOnBigRational(BigRational $a): void
59+
{
60+
try {
61+
$result = $a->toBigDecimal();
62+
} finally {
63+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
64+
}
65+
}
66+
67+
// --- Operation methods ---
68+
69+
public function plusWithSameType(BigInteger $a, BigInteger $b): void
70+
{
71+
try {
72+
$result = $a->plus($b);
73+
} finally {
74+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
75+
}
76+
}
77+
78+
public function plusWithInt(BigDecimal $a): void
79+
{
80+
try {
81+
$result = $a->plus(5);
82+
} finally {
83+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
84+
}
85+
}
86+
87+
public function plusWithString(BigInteger $a, string $s): void
88+
{
89+
try {
90+
$result = $a->plus($s);
91+
} finally {
92+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
93+
}
94+
}
95+
96+
public function quotientMayThrowDivisionByZero(BigInteger $a, BigInteger $b): void
97+
{
98+
try {
99+
$result = $a->quotient($b);
100+
} finally {
101+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
102+
}
103+
}
104+
105+
/** @param int<1, max> $divisor */
106+
public function quotientWithNonZeroDivisor(BigInteger $a, int $divisor): void
107+
{
108+
try {
109+
$result = $a->quotient($divisor);
110+
} finally {
111+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
112+
}
113+
}
114+
115+
public function compareToWithBigNumber(BigInteger $a, BigDecimal $b): void
116+
{
117+
try {
118+
$result = $a->compareTo($b);
119+
} finally {
120+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
121+
}
122+
}
123+
124+
// --- Rounding mode methods ---
125+
126+
/** @param int<0, max> $scale */
127+
public function toScaleWithSafeArgs(BigDecimal $a, int $scale): void
128+
{
129+
try {
130+
$result = $a->toScale($scale, RoundingMode::Down);
131+
} finally {
132+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
133+
}
134+
}
135+
136+
public function toScaleWithUnnecessary(BigDecimal $a): void
137+
{
138+
try {
139+
$result = $a->toScale(2, RoundingMode::Unnecessary);
140+
} finally {
141+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
142+
}
143+
}
144+
145+
public function dividedByWithSafeRounding(BigInteger $a, BigInteger $b): void
146+
{
147+
try {
148+
$result = $a->dividedBy($b, RoundingMode::Down);
149+
} finally {
150+
assertVariableCertainty(TrinaryLogic::createMaybe(), $result);
151+
}
152+
}
153+
154+
/** @param int<1, max> $divisor */
155+
public function dividedByWithSafeRoundingAndNonZero(BigInteger $a, int $divisor): void
156+
{
157+
try {
158+
$result = $a->dividedBy($divisor, RoundingMode::Down);
159+
} finally {
160+
assertVariableCertainty(TrinaryLogic::createYes(), $result);
161+
}
162+
}
163+
}

math/tests/test.neon

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
includes:
2+
- ../extension.neon
3+
4+
parameters:
5+
exceptions:
6+
implicitThrows: false
7+
check:
8+
missingCheckedExceptionInThrows: true
9+
tooWideThrowType: true
10+
checkedExceptionClasses:
11+
- Throwable

0 commit comments

Comments
 (0)