Skip to content

Commit 9c26356

Browse files
committed
Create assertion and type-class for xs:decimal
1 parent dbf1884 commit 9c26356

File tree

5 files changed

+182
-0
lines changed

5 files changed

+182
-0
lines changed

src/Assert/Assert.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @method static void validDate(mixed $value, string $message = '', string $exception = '')
1616
* @method static void validDateTime(mixed $value, string $message = '', string $exception = '')
1717
* @method static void validDay(mixed $value, string $message = '', string $exception = '')
18+
* @method static void validDecimal(mixed $value, string $message = '', string $exception = '')
1819
* @method static void validDuration(mixed $value, string $message = '', string $exception = '')
1920
* @method static void validEntity(mixed $value, string $message = '', string $exception = '')
2021
* @method static void validEntities(mixed $value, string $message = '', string $exception = '')
@@ -40,6 +41,7 @@
4041
* @method static void nullOrValidDate(mixed $value, string $message = '', string $exception = '')
4142
* @method static void nullOrValidDateTime(mixed $value, string $message = '', string $exception = '')
4243
* @method static void nullOrValidDay(mixed $value, string $message = '', string $exception = '')
44+
* @method static void nullOrValidDecimal(mixed $value, string $message = '', string $exception = '')
4345
* @method static void nullOrValidDuration(mixed $value, string $message = '', string $exception = '')
4446
* @method static void nullOrValidEntity(mixed $value, string $message = '', string $exception = '')
4547
* @method static void nullOrValidEntities(mixed $value, string $message = '', string $exception = '')
@@ -65,6 +67,7 @@
6567
* @method static void allValidDate(mixed $value, string $message = '', string $exception = '')
6668
* @method static void allValidDateTime(mixed $value, string $message = '', string $exception = '')
6769
* @method static void allValidDay(mixed $value, string $message = '', string $exception = '')
70+
* @method static void allValidDecimal(mixed $value, string $message = '', string $exception = '')
6871
* @method static void allValidDuration(mixed $value, string $message = '', string $exception = '')
6972
* @method static void allValidEntity(mixed $value, string $message = '', string $exception = '')
7073
* @method static void allValidEntities(mixed $value, string $message = '', string $exception = '')
@@ -93,6 +96,7 @@ class Assert extends BaseAssert
9396
use DateTrait;
9497
use DateTimeTrait;
9598
use DayTrait;
99+
use DecimalTrait;
96100
use DurationTrait;
97101
use HexBinaryTrait;
98102
use EntitiesTrait;

src/Assert/DecimalTrait.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XML\Assert;
6+
7+
use InvalidArgumentException;
8+
9+
/**
10+
* @package simplesamlphp/xml-common
11+
*/
12+
trait DecimalTrait
13+
{
14+
/** @var string */
15+
private static string $decimal_regex = '/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/';
16+
17+
/**
18+
* @param string $value
19+
* @param string $message
20+
*/
21+
protected static function validDecimal(string $value, string $message = ''): void
22+
{
23+
parent::regex(
24+
$value,
25+
self::$decimal_regex,
26+
$message ?: '%s is not a valid xs:decimal',
27+
InvalidArgumentException::class,
28+
);
29+
}
30+
}

src/Type/DecimalValue.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XML\Type;
6+
7+
use SimpleSAML\XML\Assert\Assert;
8+
use SimpleSAML\XML\Exception\SchemaViolationException;
9+
10+
/**
11+
* @package simplesaml/xml-common
12+
*/
13+
class DecimalValue extends AbstractValueType
14+
{
15+
/**
16+
* Sanitize the value.
17+
*
18+
* @param string $value The unsanitized value
19+
* @return string
20+
*/
21+
protected function sanitizeValue(string $value): string
22+
{
23+
return str_replace(["\f", "\r", "\n", "\t", "\v", ' '], '', $value);
24+
}
25+
26+
27+
/**
28+
* Validate the value.
29+
*
30+
* @param string $value
31+
* @throws \SimpleSAML\XML\Exception\SchemaViolationException on failure
32+
* @return void
33+
*/
34+
protected function validateValue(string $value): void
35+
{
36+
// Note: value must already be sanitized before validating
37+
Assert::validDecimal($this->sanitizeValue($value), SchemaViolationException::class);
38+
}
39+
}

tests/Assert/DecimalTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Test\XML\Assert;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\TestCase;
10+
use SimpleSAML\Assert\AssertionFailedException;
11+
use SimpleSAML\XML\Assert\Assert;
12+
13+
/**
14+
* Class \SimpleSAML\Test\XML\Assert\DecimalTest
15+
*
16+
* @package simplesamlphp/xml-common
17+
*/
18+
#[CoversClass(Assert::class)]
19+
final class DecimalTest extends TestCase
20+
{
21+
/**
22+
* @param boolean $shouldPass
23+
* @param string $decimal
24+
*/
25+
#[DataProvider('provideDecimal')]
26+
public function testValidDecimal(bool $shouldPass, string $decimal): void
27+
{
28+
try {
29+
Assert::validDecimal($decimal);
30+
$this->assertTrue($shouldPass);
31+
} catch (AssertionFailedException $e) {
32+
$this->assertFalse($shouldPass);
33+
}
34+
}
35+
36+
37+
/**
38+
* @return array<string, array{0: bool, 1: string}>
39+
*/
40+
public static function provideDecimal(): array
41+
{
42+
return [
43+
'empty' => [false, ''],
44+
'valid decimal' => [true, '123.456'],
45+
'valid positive signed' => [true, '+123.456'],
46+
'valid negative signed' => [true, '-123.456'],
47+
'valid fractional only' => [true, '-.456'],
48+
'valid without fraction' => [true, '-456'],
49+
'invalid with space' => [false, '1 234.456'],
50+
'invalid scientific notation' => [false, '1234.456E+2'],
51+
'invalid signed with space' => [false, '+ 1234.456'],
52+
'invalid with thousands-delimiter' => [false, '+1,234.456'],
53+
];
54+
}
55+
}

tests/Type/DecimalValueTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Test\XML\Type;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\TestCase;
10+
use SimpleSAML\XML\Exception\SchemaViolationException;
11+
use SimpleSAML\XML\Type\DecimalValue;
12+
13+
/**
14+
* Class \SimpleSAML\Test\Type\DecimalValueTest
15+
*
16+
* @package simplesamlphp/xml-common
17+
*/
18+
#[CoversClass(DecimalValue::class)]
19+
final class DecimalValueTest extends TestCase
20+
{
21+
/**
22+
* @param boolean $shouldPass
23+
* @param string $decimal
24+
*/
25+
#[DataProvider('provideDecimal')]
26+
public function testDecimal(bool $shouldPass, string $decimal): void
27+
{
28+
try {
29+
DecimalValue::fromString($decimal);
30+
$this->assertTrue($shouldPass);
31+
} catch (SchemaViolationException $e) {
32+
$this->assertFalse($shouldPass);
33+
}
34+
}
35+
36+
37+
/**
38+
* @return array<string, array{0: bool, 1: string}>
39+
*/
40+
public static function provideDecimal(): array
41+
{
42+
return [
43+
'empty' => [false, ''],
44+
'valid decimal' => [true, '123.456'],
45+
'valid positive signed' => [true, '+123.456'],
46+
'valid negative signed' => [true, '-123.456'],
47+
'valid fractional only' => [true, '-.456'],
48+
'valid without fraction' => [true, '-456'],
49+
'valid with whitespace collapse' => [true, ' 1 234.456 '],
50+
'invalid scientific notation' => [false, '1234.456E+2'],
51+
'invalid with thousands-delimiter' => [false, '+1,234.456'],
52+
];
53+
}
54+
}

0 commit comments

Comments
 (0)