diff --git a/Makefile b/Makefile
index 6476e3d..f8745a6 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ help:
.PHONY: run run-php7.4 run-php8.0 run-php8.1 run-php8.2
run-php7.4:
@# Help: It creates and runs a docker image with PHP 7.4
- docker-compose run --rm php74 bash -c "rm composer.lock || true; composer install --no-interaction; bash"
+ docker compose run --rm php74 bash -c "rm composer.lock || true; composer install --no-interaction; bash"
run-php8.0:
@# Help: It creates and runs a docker image with PHP 8.0
docker-compose run --rm php80 bash -c "rm composer.lock || true; composer install --no-interaction; bash"
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 5605487..246ad85 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,12 +1,42 @@
-
-
-
-
-
- Generators::oneOf(Generators::int(), Generators::float(), Generators::bool())
- Generators::oneOf(Generators::string(), Generators::float(), Generators::bool())
-
+
+
+ new BoolDecoder()
+ new BoolDecoder()
+
+
+ decode
+ decode
+
+
+
+
+ new CallableDecoder()
+ new CallableDecoder()
+
+
+ decode
+ decode
+
+
+
+
+ assertSame
+
+
+
+
+ new BoundedIntDecoder(10, 20)
+ new BoundedIntDecoder(10, 20)
+ new BoundedIntDecoder(20, 10)
+
+
+ decode
+ decode
+ new BoundedIntDecoder(10, 20)
+ new BoundedIntDecoder(10, 20)
+ new BoundedIntDecoder(20, 10)
+
diff --git a/src/Internal/Primitives/FloatDecoder.php b/src/Internal/Primitives/FloatDecoder.php
index 090aa3a..a90f233 100644
--- a/src/Internal/Primitives/FloatDecoder.php
+++ b/src/Internal/Primitives/FloatDecoder.php
@@ -13,8 +13,6 @@
* @template I of mixed
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class FloatDecoder implements Decoder
{
diff --git a/src/Internal/Primitives/IntDecoder.php b/src/Internal/Primitives/IntDecoder.php
index 41f4b7c..493e1af 100644
--- a/src/Internal/Primitives/IntDecoder.php
+++ b/src/Internal/Primitives/IntDecoder.php
@@ -13,8 +13,6 @@
* @template I of mixed
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class IntDecoder implements Decoder
{
diff --git a/src/Internal/Primitives/MixedDecoder.php b/src/Internal/Primitives/MixedDecoder.php
index b143307..09b4914 100644
--- a/src/Internal/Primitives/MixedDecoder.php
+++ b/src/Internal/Primitives/MixedDecoder.php
@@ -13,8 +13,6 @@
* @psalm-template U of mixed
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class MixedDecoder implements Decoder
{
diff --git a/src/Internal/Primitives/NullDecoder.php b/src/Internal/Primitives/NullDecoder.php
index 3718c9f..429d901 100644
--- a/src/Internal/Primitives/NullDecoder.php
+++ b/src/Internal/Primitives/NullDecoder.php
@@ -13,8 +13,6 @@
* @template I of mixed
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class NullDecoder implements Decoder
{
diff --git a/src/Internal/Primitives/StringDecoder.php b/src/Internal/Primitives/StringDecoder.php
index 912aede..b2e1542 100644
--- a/src/Internal/Primitives/StringDecoder.php
+++ b/src/Internal/Primitives/StringDecoder.php
@@ -13,8 +13,6 @@
* @template I of mixed
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class StringDecoder implements Decoder
{
diff --git a/src/Internal/Primitives/UndefinedDecoder.php b/src/Internal/Primitives/UndefinedDecoder.php
index 3c9dd6b..a28d5aa 100644
--- a/src/Internal/Primitives/UndefinedDecoder.php
+++ b/src/Internal/Primitives/UndefinedDecoder.php
@@ -14,8 +14,6 @@
* @psalm-template U
*
* @template-implements Decoder
- *
- * @psalm-internal Facile\PhpCodec
*/
final class UndefinedDecoder implements Decoder
{
diff --git a/src/Internal/Useful/BoundedIntDecoder.php b/src/Internal/Useful/BoundedIntDecoder.php
new file mode 100644
index 0000000..25172de
--- /dev/null
+++ b/src/Internal/Useful/BoundedIntDecoder.php
@@ -0,0 +1,61 @@
+
+ *
+ * @psalm-internal Facile\PhpCodec
+ */
+final class BoundedIntDecoder implements Decoder
+{
+ /**
+ * @psalm-readonly
+ */
+ private int $min;
+
+ /**
+ * @psalm-readonly
+ */
+ private int $max;
+
+ public function __construct(int $min, int $max)
+ {
+ if ($min > $max) {
+ throw new \InvalidArgumentException('Lower bound cannot be greater than upper bound.');
+ }
+
+ $this->min = $min;
+ $this->max = $max;
+ }
+
+ public function validate($i, Context $context): Validation
+ {
+ if (! \is_int($i)) {
+ return Validation::failure($i, $context);
+ }
+
+ if ($i < $this->min || $i > $this->max) {
+ return Validation::failure($i, $context);
+ }
+
+ return Validation::success($i);
+ }
+
+ public function decode($i): Validation
+ {
+ return FunctionUtils::standardDecode($this, $i);
+ }
+
+ public function getName(): string
+ {
+ return sprintf('BoundedInt(%d, %d)', $this->min, $this->max);
+ }
+}
diff --git a/tests/unit/DecodersTest.php b/tests/unit/DecodersTest.php
index c288c8a..cc14455 100644
--- a/tests/unit/DecodersTest.php
+++ b/tests/unit/DecodersTest.php
@@ -23,20 +23,21 @@ public function testMap(): void
/** @psalm-suppress UndefinedFunction */
$this
->forAll(
- Generators::int()
+ Generators::int() // provare il decoder con molti interi casuali
)
->then(function (int $i) use ($decoder): void {
$a = self::assertSuccessInstanceOf(
DecodersTest\A::class,
$decoder->decode($i)
);
- self::assertSame($i, $a->getValue());
+ self::assertSame($i, $a->getValue()); // verifica che il valore dentro l'oggetto A sia uguale a $i
});
}
}
namespace Tests\Facile\PhpCodec\DecodersTest;
+// wrapper class usata per testare la trasformazione: prende un int e lo incapsula in un oggetto
class A
{
private int $v;
diff --git a/tests/unit/Internal/Primitives/BoolDecoderTest.php b/tests/unit/Internal/Primitives/BoolDecoderTest.php
new file mode 100644
index 0000000..310e15a
--- /dev/null
+++ b/tests/unit/Internal/Primitives/BoolDecoderTest.php
@@ -0,0 +1,59 @@
+decode($input);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidBoolProvider
+ *
+ * @param mixed $input
+ */
+ public function testInvalidBools($input): void
+ {
+ $decoder = new BoolDecoder();
+ $result = $decoder->decode($input);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function validBoolProvider(): array
+ {
+ return [
+ 'true' => [true],
+ 'false' => [false],
+ ];
+ }
+
+ public static function invalidBoolProvider(): array
+ {
+ return [
+ 'int' => [1],
+ 'string true' => ['true'],
+ 'string false' => ['false'],
+ 'null' => [null],
+ 'float' => [1.0],
+ 'array' => [[true]],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/CallableDecoderTest.php b/tests/unit/Internal/Primitives/CallableDecoderTest.php
new file mode 100644
index 0000000..addba04
--- /dev/null
+++ b/tests/unit/Internal/Primitives/CallableDecoderTest.php
@@ -0,0 +1,64 @@
+decode($input);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidCallableProvider
+ *
+ * @param mixed $input
+ */
+ public function testInvalidCallables($input): void
+ {
+ $decoder = new CallableDecoder();
+ $result = $decoder->decode($input);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function validCallableProvider(): array
+ {
+ return [
+ 'anonymous function' => [fn() => null],
+ 'named function' => ['strlen'],
+ 'static method as array' => [[self::class, 'helperStatic']],
+ ];
+ }
+
+ public static function invalidCallableProvider(): array
+ {
+ return [
+ 'int' => [123],
+ 'string' => ['not_callable'],
+ 'array of strings' => [['a', 'b']],
+ 'null' => [null],
+ 'object' => [new \stdClass()],
+ ];
+ }
+
+ public static function helperStatic(): void
+ {
+ // Metodo statico valido per test
+ }
+}
diff --git a/tests/unit/Internal/Primitives/FloatDecoderTest.php b/tests/unit/Internal/Primitives/FloatDecoderTest.php
new file mode 100644
index 0000000..876c730
--- /dev/null
+++ b/tests/unit/Internal/Primitives/FloatDecoderTest.php
@@ -0,0 +1,45 @@
+decode(3.14);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidFloatProvider
+ *
+ * @param mixed $invalidValue
+ */
+ public function testInvalidValues($invalidValue): void
+ {
+ $decoder = new FloatDecoder();
+ $result = $decoder->decode($invalidValue);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function invalidFloatProvider(): array
+ {
+ return [
+ 'int' => [42],
+ 'string' => ['3.14'],
+ 'bool' => [true],
+ 'array' => [[3.14]],
+ 'null' => [null],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/IntDecoderTest.php b/tests/unit/Internal/Primitives/IntDecoderTest.php
new file mode 100644
index 0000000..1bdaa05
--- /dev/null
+++ b/tests/unit/Internal/Primitives/IntDecoderTest.php
@@ -0,0 +1,46 @@
+decode(42);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidIntProvider
+ *
+ * @param mixed $input
+ */
+ public function testInvalidValues($input): void
+ {
+ $decoder = new IntDecoder();
+ $result = $decoder->decode($input);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function invalidIntProvider(): array
+ {
+ return [
+ 'float' => [3.14],
+ 'string' => ['42'],
+ 'bool' => [true],
+ 'null' => [null],
+ 'array' => [[1]],
+ 'object' => [new \stdClass()],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/MixedDecoderTest.php b/tests/unit/Internal/Primitives/MixedDecoderTest.php
new file mode 100644
index 0000000..1bca640
--- /dev/null
+++ b/tests/unit/Internal/Primitives/MixedDecoderTest.php
@@ -0,0 +1,41 @@
+decode($value);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ $this->assertSame($value, $result->getValue());
+ }
+
+ public static function provideValues(): array
+ {
+ return [
+ 'string' => ['hello'],
+ 'int' => [42],
+ 'float' => [3.14],
+ 'bool true' => [true],
+ 'bool false' => [false],
+ 'null' => [null],
+ 'array' => [[1, 2, 3]],
+ 'object' => [new \stdClass()],
+ 'callable' => [fn() => 'test'],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/NullDecoderTest.php b/tests/unit/Internal/Primitives/NullDecoderTest.php
new file mode 100644
index 0000000..0711d6e
--- /dev/null
+++ b/tests/unit/Internal/Primitives/NullDecoderTest.php
@@ -0,0 +1,48 @@
+decode(null);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ $this->assertSame(null, $result->getValue());
+ }
+
+ /**
+ * @dataProvider provideInvalidValues
+ *
+ * @param mixed $value
+ */
+ public function testInvalidValues($value): void
+ {
+ $decoder = new NullDecoder();
+ $result = $decoder->decode($value);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function provideInvalidValues(): array
+ {
+ return [
+ 'int' => [42],
+ 'string' => ['null'],
+ 'bool' => [true],
+ 'float' => [3.14],
+ 'array' => [[null]],
+ 'object' => [new \stdClass()],
+ 'callable' => [fn() => null],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/StringDecoderTest.php b/tests/unit/Internal/Primitives/StringDecoderTest.php
new file mode 100644
index 0000000..a0604f4
--- /dev/null
+++ b/tests/unit/Internal/Primitives/StringDecoderTest.php
@@ -0,0 +1,46 @@
+decode('ciao');
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidValuesProvider
+ *
+ * @param mixed $input
+ */
+ public function testInvalidValues($input): void
+ {
+ $decoder = new StringDecoder();
+ $result = $decoder->decode($input);
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function invalidValuesProvider(): array
+ {
+ return [
+ 'integer' => [123],
+ 'float' => [3.14],
+ 'boolean' => [true],
+ 'array' => [['not', 'a', 'string']],
+ 'object' => [new \stdClass()],
+ 'null' => [null],
+ ];
+ }
+}
diff --git a/tests/unit/Internal/Primitives/UndefinedDecoderTest.php b/tests/unit/Internal/Primitives/UndefinedDecoderTest.php
index e541180..ce17022 100644
--- a/tests/unit/Internal/Primitives/UndefinedDecoderTest.php
+++ b/tests/unit/Internal/Primitives/UndefinedDecoderTest.php
@@ -6,7 +6,10 @@
use Eris\TestTrait;
use Facile\PhpCodec\Decoders;
+use Facile\PhpCodec\Internal\Primitives\UndefinedDecoder;
use Facile\PhpCodec\Internal\Undefined;
+use Facile\PhpCodec\Validation\ValidationFailures;
+use Facile\PhpCodec\Validation\ValidationSuccess;
use Tests\Facile\PhpCodec\BaseTestCase;
use Tests\Facile\PhpCodec\GeneratorUtils;
@@ -29,8 +32,51 @@ function ($default): void {
$x = self::assertValidationSuccess(
Decoders::undefined($default)->decode(new Undefined())
);
+
self::assertSame($default, $x);
}
);
}
+
+ // Aggiunti Michele
+ public function testValidUndefined(): void
+ {
+ $default = 'default-value';
+ $decoder = new UndefinedDecoder($default);
+ $result = $decoder->decode(new Undefined());
+
+ // fwrite(STDOUT, "\n[testValidUndefined] result: " . var_export($result, true) . "\n");
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+
+ $this->assertSame($default, $result->getValue());
+ }
+
+ /**
+ * @dataProvider provideInvalidValues
+ *
+ * @param mixed $input
+ */
+ public function testInvalidValues($input): void
+ {
+ $decoder = new UndefinedDecoder('default');
+ $result = $decoder->decode($input);
+
+ // fwrite(STDOUT, "\n[testInvalidValues] input: " . var_export($input, true) . "\n");
+ // fwrite(STDOUT, "[testInvalidValues] result: " . var_export($result, true) . "\n");
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function provideInvalidValues(): array
+ {
+ return [
+ 'null' => [null],
+ 'string' => ['undefined'],
+ 'int' => [0],
+ 'bool' => [true],
+ 'array' => [[]],
+ 'object' => [new \stdClass()],
+ ];
+ }
}
diff --git a/tests/unit/Internal/Useful/BoundedIntDecoderTest.php b/tests/unit/Internal/Useful/BoundedIntDecoderTest.php
new file mode 100644
index 0000000..55a837f
--- /dev/null
+++ b/tests/unit/Internal/Useful/BoundedIntDecoderTest.php
@@ -0,0 +1,61 @@
+decode($input);
+
+ $this->assertInstanceOf(ValidationSuccess::class, $result);
+ }
+
+ /**
+ * @dataProvider invalidIntProvider
+ *
+ * @param mixed $input
+ */
+ public function testInvalidInts($input): void
+ {
+ $decoder = new BoundedIntDecoder(10, 20);
+ $result = $decoder->decode($input);
+
+ $this->assertInstanceOf(ValidationFailures::class, $result);
+ }
+
+ public static function validIntProvider(): array
+ {
+ return [
+ 'lower bound' => [10],
+ 'middle' => [15],
+ 'upper bound' => [20],
+ ];
+ }
+
+ public static function invalidIntProvider(): array
+ {
+ return [
+ 'below range' => [9],
+ 'above range' => [21],
+ 'string' => ['15'],
+ 'float' => [15.0],
+ 'null' => [null],
+ 'bool' => [true],
+ 'array' => [[15]],
+ 'object' => [new \stdClass()],
+ ];
+}