Skip to content

Commit 3f8c949

Browse files
committed
Add FloatPositive type with validation, alias PositiveFloat, and tests
- Introduced `FloatPositive` class to enforce positive float values with strict validation. - Added `PositiveFloat` alias for enhanced readability and usage clarity. - Implemented comprehensive test suite to verify valid cases and exception handling on invalid values. - Updated `psalmTest.php` with usage demonstrations for `PositiveFloat`.
1 parent 026e096 commit 3f8c949

File tree

5 files changed

+122
-1
lines changed

5 files changed

+122
-1
lines changed

phpunit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<directory>src</directory>
2121
</include>
2222
<exclude>
23-
<file>src/psalmTest.php</file>
23+
<file>src/typeUsageTest.php</file>
2424
</exclude>
2525
</source>
2626
</phpunit>

src/Float/Alias/PositiveFloat.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpTypedValues\Float\Alias;
6+
7+
use PhpTypedValues\Float\FloatPositive;
8+
9+
/**
10+
* @psalm-immutable
11+
*/
12+
readonly class PositiveFloat extends FloatPositive
13+
{
14+
}

src/Float/FloatPositive.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpTypedValues\Float;
6+
7+
use PhpTypedValues\Abstract\Float\FloatType;
8+
use PhpTypedValues\Exception\FloatTypeException;
9+
10+
use function sprintf;
11+
12+
/**
13+
* Positive float (> 0.0).
14+
*
15+
* Example "0.1"
16+
*
17+
* @psalm-immutable
18+
*/
19+
readonly class FloatPositive extends FloatType
20+
{
21+
protected float $value;
22+
23+
/**
24+
* @throws FloatTypeException
25+
*/
26+
public function __construct(float $value)
27+
{
28+
if ($value <= 0.0) {
29+
throw new FloatTypeException(sprintf('Expected positive float, got "%s"', $value));
30+
}
31+
32+
$this->value = $value;
33+
}
34+
35+
/**
36+
* @throws FloatTypeException
37+
*/
38+
public static function fromFloat(float $value): static
39+
{
40+
return new static($value);
41+
}
42+
43+
/**
44+
* @throws FloatTypeException
45+
*/
46+
public static function fromString(string $value): static
47+
{
48+
parent::assertFloatString($value);
49+
50+
return new static((float) $value);
51+
}
52+
53+
public function value(): float
54+
{
55+
return $this->value;
56+
}
57+
}

src/psalmTest.php renamed to src/typeUsageTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PhpTypedValues\Float\Alias\Double;
2020
use PhpTypedValues\Float\Alias\FloatType;
2121
use PhpTypedValues\Float\Alias\NonNegativeFloat;
22+
use PhpTypedValues\Float\Alias\PositiveFloat;
2223
use PhpTypedValues\Float\FloatNonNegative;
2324
use PhpTypedValues\Float\FloatStandard;
2425
use PhpTypedValues\Integer\Alias\Id;
@@ -84,6 +85,7 @@
8485
echo NonNegativeFloat::fromString('2.71828')->toString() . \PHP_EOL;
8586
echo FloatType::fromString('2.71828')->toString() . \PHP_EOL;
8687
echo Double::fromString('2.71828')->toString() . \PHP_EOL;
88+
echo PositiveFloat::fromString('2.8')->toString() . \PHP_EOL;
8789

8890
// PositiveFloat usage
8991
testPositiveFloat(FloatNonNegative::fromFloat(0.5)->value());
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PhpTypedValues\Exception\FloatTypeException;
6+
use PhpTypedValues\Float\FloatPositive;
7+
8+
it('constructs positive float via constructor', function (): void {
9+
$v = new FloatPositive(0.1);
10+
expect($v->value())->toBe(0.1)
11+
->and($v->toString())->toBe('0.1');
12+
});
13+
14+
it('creates from float factory', function (): void {
15+
$v = FloatPositive::fromFloat(1.5);
16+
expect($v->value())->toBe(1.5);
17+
});
18+
19+
it('creates from string factory', function (): void {
20+
$v = FloatPositive::fromString('2.5');
21+
expect($v->value())->toBe(2.5)
22+
->and($v->toString())->toBe('2.5');
23+
});
24+
25+
it('throws on zero via constructor', function (): void {
26+
expect(fn() => new FloatPositive(0.0))
27+
->toThrow(FloatTypeException::class, 'Expected positive float, got "0"');
28+
});
29+
30+
it('throws on zero via fromString', function (): void {
31+
expect(fn() => FloatPositive::fromString('0.0'))
32+
->toThrow(FloatTypeException::class, 'Expected positive float, got "0"');
33+
});
34+
35+
it('throws on negative via constructor', function (): void {
36+
expect(fn() => new FloatPositive(-0.1))
37+
->toThrow(FloatTypeException::class, 'Expected positive float, got "-0.1"');
38+
});
39+
40+
it('throws on negative via fromString', function (): void {
41+
expect(fn() => FloatPositive::fromString('-1.23'))
42+
->toThrow(FloatTypeException::class, 'Expected positive float, got "-1.23"');
43+
});
44+
45+
it('throws on string not float', function (): void {
46+
expect(fn() => FloatPositive::fromString('unknown'))
47+
->toThrow(FloatTypeException::class, 'String "unknown" has no valid float value');
48+
});

0 commit comments

Comments
 (0)