Skip to content

Commit 9d63718

Browse files
committed
Add validation and tests for invalid data creation and serialization
Refactor the `BaseData::create` method to handle invalid input more effectively, using a specific exception for clarity. Introduce `UselessDataCipher` as a test dummy and add unit tests to ensure proper exception handling for invalid serialization and data creation.
1 parent 839fc90 commit 9d63718

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

src/Concerns/BaseData.php

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,12 @@ trait BaseData
2121
*/
2222
final public static function create(mixed ...$args): static
2323
{
24-
if (array_any(
25-
array_keys($args),
26-
static fn (string|int $arg) => is_numeric($arg)
27-
)) {
28-
throw DataCreationException::invalidProperty();
29-
}
30-
3124
try {
32-
$value = static::normalizeValue($args, static::class);
25+
$value = static::normalizeValue($args, static::class)
26+
?: static::normalizeValue($args[0] ?? [], static::class);
3327

3428
if ($value === false) {
35-
throw new DeserializeException(
36-
code: DeserializeException::INVALID_VALUE_ERROR_CODE
37-
);
29+
throw DataCreationException::invalidParamsPassed(static::class);
3830
}
3931

4032
/** @var ClassContext<static> $context */
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Nuxtifyts\PhpDto\Tests\Dummies\DataCiphers;
4+
5+
use Nuxtifyts\PhpDto\DataCiphers\DataCipher;
6+
use Nuxtifyts\PhpDto\Exceptions\DataCipherException;
7+
8+
class UselessDataCipher implements DataCipher
9+
{
10+
11+
/**
12+
* @throws DataCipherException
13+
*/
14+
public static function cipher(mixed $data, string $secret, bool $encode = false): never
15+
{
16+
throw DataCipherException::failedToCipherData();
17+
}
18+
19+
/**
20+
* @throws DataCipherException
21+
*/
22+
public static function decipher(string $data, string $secret, bool $decode = false): never
23+
{
24+
throw DataCipherException::failedToDecipherData();
25+
}
26+
}

tests/Unit/Concerns/BaseDataTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use DateTimeImmutable;
66
use DateTimeInterface;
7+
use Nuxtifyts\PhpDto\Attributes\Property\CipherTarget;
78
use Nuxtifyts\PhpDto\Attributes\Property\Computed;
89
use Nuxtifyts\PhpDto\Data;
10+
use Nuxtifyts\PhpDto\Exceptions\DataCreationException;
911
use Nuxtifyts\PhpDto\Exceptions\DeserializeException;
1012
use Nuxtifyts\PhpDto\Exceptions\SerializeException;
1113
use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipeline;
@@ -21,6 +23,7 @@
2123
use Nuxtifyts\PhpDto\Tests\Dummies\ComputedPropertiesData;
2224
use Nuxtifyts\PhpDto\Tests\Dummies\CoordinatesData;
2325
use Nuxtifyts\PhpDto\Tests\Dummies\CountryData;
26+
use Nuxtifyts\PhpDto\Tests\Dummies\DataCiphers\UselessDataCipher;
2427
use Nuxtifyts\PhpDto\Tests\Dummies\Enums\YesNoBackedEnum;
2528
use Nuxtifyts\PhpDto\Tests\Dummies\FallbackResolvers\DummyPointsFallbackResolver;
2629
use Nuxtifyts\PhpDto\Tests\Dummies\InvitationData;
@@ -54,6 +57,7 @@
5457
#[CoversClass(DateTimeSerializer::class)]
5558
#[CoversClass(DataSerializer::class)]
5659
#[CoversClass(BackedEnumSerializer::class)]
60+
#[CoversClass(DataCreationException::class)]
5761
#[UsesClass(PersonData::class)]
5862
#[UsesClass(UnionTypedData::class)]
5963
#[UsesClass(YesOrNoData::class)]
@@ -70,6 +74,7 @@
7074
#[UsesClass(PointGroupData::class)]
7175
#[UsesClass(PointData::class)]
7276
#[UsesClass(DummyPointsFallbackResolver::class)]
77+
#[UsesClass(UselessDataCipher::class)]
7378
final class BaseDataTest extends UnitCase
7479
{
7580
/**
@@ -591,6 +596,29 @@ public static function will_perform_serialization_and_deserialization_data_provi
591596
];
592597
}
593598

599+
#[Test]
600+
public function will_throw_an_exception_when_property_serialization_fails(): void
601+
{
602+
$object = new readonly class ('secret') extends Data {
603+
public function __construct(
604+
#[CipherTarget(UselessDataCipher::class)]
605+
public string $secret
606+
) {
607+
}
608+
};
609+
610+
self::expectException(SerializeException::class);
611+
$object->jsonSerialize();
612+
}
613+
614+
#[Test]
615+
public function will_throw_an_exception_when_invalid_data_is_passed_to_create_function(): void
616+
{
617+
self::expectException(DataCreationException::class);
618+
619+
PointData::create('{"x: 1, "y": 2}');
620+
}
621+
594622
/**
595623
* @throws Throwable
596624
*/
@@ -606,6 +634,12 @@ public function will_be_able_to_create_an_instance_using_create(): void
606634
self::assertEquals(1, $point->x);
607635
self::assertEquals(2, $point->y);
608636

637+
$point = PointData::create('{"x": 3, "y": 4}');
638+
639+
self::assertInstanceOf(PointData::class, $point);
640+
self::assertEquals(3, $point->x);
641+
self::assertEquals(4, $point->y);
642+
609643
// Make sure we skip deciphering the key
610644
$pointGroup = PointGroupData::create(
611645
key: 'random-key'

0 commit comments

Comments
 (0)