Skip to content

Commit 0c57081

Browse files
committed
optimize test
1 parent 31b4505 commit 0c57081

3 files changed

Lines changed: 210 additions & 25 deletions

File tree

phpstan.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#Dead catch - ReflectionException is never thrown in the try block#'

src/Schema/ObjectConstructorSchema.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,31 @@ public function __construct(array $fieldToSchema, private string $classname)
5353
}
5454

5555
if ([] !== $missingFieldToSchema) {
56-
throw new \InvalidArgumentException('Missing fieldToSchema for "'.$classname.'" __construct parameters: "'.implode('", "', $missingFieldToSchema).'"');
56+
throw new \InvalidArgumentException(
57+
'Missing fieldToSchema for "'.$classname.'" __construct parameters: "'
58+
.implode('", "', $missingFieldToSchema).'"'
59+
);
5760
}
5861

5962
if ([] !== $fieldToSchema) {
60-
throw new \InvalidArgumentException('Additional fieldToSchema for "'.$classname.'" __construct parameters: "'.implode('", "', array_keys($fieldToSchema)).'"');
63+
throw new \InvalidArgumentException(
64+
'Additional fieldToSchema for "'.$classname.'" __construct parameters: "'
65+
.implode('", "', array_keys($fieldToSchema)).'"'
66+
);
6167
}
6268

63-
$this->typeErrorPattern = \sprintf('/%s::__construct\(\): Argument #(\d+) \(([^)]+)\) must be of type ([^ ]+), ([^ ]+) given/', preg_quote($this->classname, '/'));
69+
$this->typeErrorPattern = \sprintf(
70+
'/%s::__construct\(\): Argument #(\d+) \(([^)]+)\) must be of type ([^ ]+), ([^ ]+) given/',
71+
preg_quote($this->classname, '/')
72+
);
6473

6574
parent::__construct($parameterFieldToSchema);
6675
}
6776

6877
/**
6978
* @param array<string, mixed> $input
7079
*/
71-
protected function parseFields(array $input, Errors $childrenErrors): ?object
80+
protected function parseFields(array $input, Errors $childrenErrors): object
7281
{
7382
$parameters = [];
7483

@@ -94,7 +103,12 @@ protected function parseFields(array $input, Errors $childrenErrors): ?object
94103
new Error(
95104
self::ERROR_PARAMETER_TYPE_CODE,
96105
self::ERROR_PARAMETER_TYPE_TEMPLATE,
97-
['index' => $matches[1], 'name' => $matches[2], 'type' => $matches[3], 'given' => $matches[4]]
106+
[
107+
'index' => $matches[1],
108+
'name' => $matches[2],
109+
'type' => $matches[3],
110+
'given' => $matches[4],
111+
]
98112
)
99113
);
100114
}

tests/Unit/Schema/ObjectConstructorSchemaTest.php

Lines changed: 188 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Chubbyphp\Tests\Parsing\Unit\Schema;
66

77
use Chubbyphp\Parsing\ErrorsException;
8+
use Chubbyphp\Parsing\Schema\BoolSchema;
89
use Chubbyphp\Parsing\Schema\FloatSchema;
910
use Chubbyphp\Parsing\Schema\IntSchema;
1011
use Chubbyphp\Parsing\Schema\ObjectConstructorSchema;
@@ -17,6 +18,7 @@ public function __construct(
1718
public readonly string $field1,
1819
public readonly int $field2,
1920
public readonly ?float $field3 = null,
21+
public readonly ?float $field4 = null,
2022
) {}
2123

2224
public function jsonSerialize(): array
@@ -25,6 +27,7 @@ public function jsonSerialize(): array
2527
'field1' => $this->field1,
2628
'field2' => $this->field2,
2729
'field3' => $this->field3,
30+
'field4' => $this->field4,
2831
];
2932
}
3033
}
@@ -47,7 +50,12 @@ final class ObjectConstructorSchemaTest extends TestCase
4750
{
4851
public function testImmutability(): void
4952
{
50-
$schema = new ObjectConstructorSchema(['field1' => new StringSchema(), 'field2' => new IntSchema(), 'field3' => new FloatSchema()], ObjectConstructorDemo::class);
53+
$schema = new ObjectConstructorSchema([
54+
'field1' => new StringSchema(),
55+
'field2' => new IntSchema(),
56+
'field3' => new FloatSchema()->nullable(),
57+
'field4' => new FloatSchema()->nullable(),
58+
], ObjectConstructorDemo::class);
5159

5260
self::assertNotSame($schema, $schema->nullable());
5361
self::assertNotSame($schema, $schema->nullable(false));
@@ -108,28 +116,30 @@ public function testConstructWithAdditionalFieldSchema(): void
108116
new ObjectConstructorSchema([
109117
'field1' => new StringSchema(),
110118
'field2' => new IntSchema(),
111-
'field3' => new FloatSchema(),
112-
'field4' => new FloatSchema(),
113-
], ObjectConstructorDemo::class)->optional(['field3']);
119+
'field3' => new FloatSchema()->nullable(),
120+
'field4' => new FloatSchema()->nullable(),
121+
'field5' => new FloatSchema(),
122+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
114123

115124
throw new \Exception('code should not be reached');
116125
} catch (\InvalidArgumentException $invalidArgumentException) {
117126
self::assertSame(
118-
'Additional fieldToSchema for "'.ObjectConstructorDemo::class.'" __construct parameters: "field4"',
127+
'Additional fieldToSchema for "'.ObjectConstructorDemo::class.'" __construct parameters: "field5"',
119128
$invalidArgumentException->getMessage()
120129
);
121130
}
122131
}
123132

124133
public function testSuccessWithAllParameters(): void
125134
{
126-
$input = ['field1' => 'test', 'field2' => 5, 'field3' => 3.14159];
135+
$input = ['field1' => 'test', 'field2' => 5, 'field3' => 3.14159, 'field4' => 1.61803];
127136

128137
$schema = new ObjectConstructorSchema([
129138
'field1' => new StringSchema(),
130139
'field2' => new IntSchema(),
131-
'field3' => new FloatSchema(),
132-
], ObjectConstructorDemo::class)->optional(['field3']);
140+
'field3' => new FloatSchema()->nullable(),
141+
'field4' => new FloatSchema()->nullable(),
142+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
133143

134144
/** @var ObjectConstructorDemo $object */
135145
$object = $schema->parse($input);
@@ -141,20 +151,26 @@ public function testSuccessWithAllParameters(): void
141151

142152
public function testSuccessWithAllParametersOptionalConsidered(): void
143153
{
144-
$input = ['field1' => 'test', 'field2' => 5];
154+
$input = ['field1' => 'test', 'field2' => 5, 'field4' => 1.61803];
145155

146156
$schema = new ObjectConstructorSchema([
147157
'field1' => new StringSchema(),
148158
'field2' => new IntSchema(),
149-
'field3' => new FloatSchema(),
150-
], ObjectConstructorDemo::class)->optional(['field3']);
159+
'field3' => new FloatSchema()->nullable(),
160+
'field4' => new FloatSchema()->nullable(),
161+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
151162

152163
/** @var ObjectConstructorDemo $object */
153164
$object = $schema->parse($input);
154165

155166
self::assertInstanceOf(ObjectConstructorDemo::class, $object);
156167

157-
self::assertSame([...$input, 'field3' => null], $object->jsonSerialize());
168+
self::assertSame([
169+
'field1' => 'test',
170+
'field2' => 5,
171+
'field3' => null,
172+
'field4' => 1.61803,
173+
], $object->jsonSerialize());
158174
}
159175

160176
public function testSuccessWithRequiredParameters(): void
@@ -164,14 +180,14 @@ public function testSuccessWithRequiredParameters(): void
164180
$schema = new ObjectConstructorSchema([
165181
'field1' => new StringSchema(),
166182
'field2' => new IntSchema(),
167-
], ObjectConstructorDemo::class)->optional(['field3']);
183+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
168184

169185
/** @var ObjectConstructorDemo $object */
170186
$object = $schema->parse($input);
171187

172188
self::assertInstanceOf(ObjectConstructorDemo::class, $object);
173189

174-
self::assertSame([...$input, 'field3' => null], $object->jsonSerialize());
190+
self::assertSame([...$input, 'field3' => null, 'field4' => null], $object->jsonSerialize());
175191
}
176192

177193
public function testFailedWithInvalidValue(): void
@@ -181,8 +197,9 @@ public function testFailedWithInvalidValue(): void
181197
$schema = new ObjectConstructorSchema([
182198
'field1' => new StringSchema(),
183199
'field2' => new IntSchema(),
184-
'field3' => new FloatSchema(),
185-
], ObjectConstructorDemo::class)->optional(['field3']);
200+
'field3' => new FloatSchema()->nullable(),
201+
'field4' => new FloatSchema()->nullable(),
202+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
186203

187204
try {
188205
$schema->parse($input);
@@ -211,8 +228,9 @@ public function testFailedWithInvalidValueNotCatchedByFieldSchema(): void
211228
$schema = new ObjectConstructorSchema([
212229
'field1' => new StringSchema(),
213230
'field2' => new IntSchema(),
214-
'field3' => new StringSchema(),
215-
], ObjectConstructorDemo::class)->optional(['field3']);
231+
'field3' => new StringSchema()->nullable(),
232+
'field4' => new FloatSchema()->nullable(),
233+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
216234

217235
try {
218236
$schema->parse($input);
@@ -246,8 +264,9 @@ public function testFailedWithUnknownException(): void
246264
$schema = new ObjectConstructorSchema([
247265
'field1' => new StringSchema(),
248266
'field2' => new IntSchema(),
249-
'field3' => new FloatSchema()->postParse(static fn () => throw $exception),
250-
], ObjectConstructorDemo::class)->optional(['field3']);
267+
'field3' => new FloatSchema()->nullable()->postParse(static fn () => throw $exception),
268+
'field4' => new FloatSchema()->nullable(),
269+
], ObjectConstructorDemo::class)->optional(['field3', 'field4']);
251270

252271
try {
253272
$schema->parse($input);
@@ -274,4 +293,153 @@ public function testFailedWithTypeErrorNotMatchingPattern(): void
274293
self::assertSame('some unrelated type error', $e->getMessage());
275294
}
276295
}
296+
297+
public function testParseSuccessWithPreParse(): void
298+
{
299+
$input = ['field1' => 'test', 'field2' => 5, 'field3' => null, 'field4' => null];
300+
301+
$schema = new ObjectConstructorSchema([
302+
'field1' => new StringSchema(),
303+
'field2' => new IntSchema(),
304+
'field3' => new FloatSchema()->nullable(),
305+
'field4' => new FloatSchema()->nullable(),
306+
], ObjectConstructorDemo::class)
307+
->optional(['field3', 'field4'])
308+
->preParse(static fn () => $input)
309+
;
310+
311+
self::assertSame($input, $schema->parse(null)->jsonSerialize());
312+
}
313+
314+
public function testParseSuccessWithPostParse(): void
315+
{
316+
$input = ['field1' => 'test', 'field2' => 5];
317+
318+
$schema = new ObjectConstructorSchema([
319+
'field1' => new StringSchema(),
320+
'field2' => new IntSchema(),
321+
'field3' => new FloatSchema()->nullable(),
322+
'field4' => new FloatSchema()->nullable(),
323+
], ObjectConstructorDemo::class)
324+
->optional(['field3', 'field4'])
325+
->postParse(static fn (ObjectConstructorDemo $output) => new ObjectConstructorDemo(...[...$output->jsonSerialize(), 'field2' => 10]))
326+
;
327+
328+
self::assertSame(
329+
[...$input, 'field2' => 10, 'field3' => null, 'field4' => null],
330+
(array) $schema->parse($input)
331+
);
332+
}
333+
334+
public function testParseFailedWithCatch(): void
335+
{
336+
$schema = (new ObjectConstructorSchema([
337+
'field1' => new StringSchema(),
338+
'field2' => new IntSchema(),
339+
'field3' => new FloatSchema()->nullable(),
340+
'field4' => new FloatSchema()->nullable(),
341+
], ObjectConstructorDemo::class))
342+
->optional(['field3', 'field4'])
343+
->catch(static function (mixed $input, ErrorsException $errorsException) {
344+
self::assertNull($input);
345+
self::assertSame([
346+
[
347+
'path' => '',
348+
'error' => [
349+
'code' => 'object.type',
350+
'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given',
351+
'variables' => [
352+
'given' => 'NULL',
353+
],
354+
],
355+
],
356+
], $errorsException->errors->jsonSerialize());
357+
358+
return 'catched';
359+
})
360+
;
361+
362+
self::assertSame('catched', $schema->parse(null));
363+
}
364+
365+
public function testSafeParseSuccess(): void
366+
{
367+
$input = ['field1' => 'test', 'field2' => 1];
368+
369+
$schema = (new ObjectConstructorSchema([
370+
'field1' => new StringSchema(),
371+
'field2' => new IntSchema(),
372+
'field3' => new FloatSchema()->nullable(),
373+
'field4' => new FloatSchema()->nullable(),
374+
], ObjectConstructorDemo::class))
375+
->optional(['field3', 'field4'])
376+
;
377+
378+
self::assertSame(
379+
[...$input, 'field3' => null, 'field4' => null],
380+
$schema->safeParse($input)->data->jsonSerialize()
381+
);
382+
}
383+
384+
public function testSafeParseFailed(): void
385+
{
386+
$schema = (new ObjectConstructorSchema([
387+
'field1' => new StringSchema(),
388+
'field2' => new IntSchema(),
389+
'field3' => new FloatSchema()->nullable(),
390+
'field4' => new FloatSchema()->nullable(),
391+
], ObjectConstructorDemo::class))
392+
->optional(['field3', 'field4'])
393+
;
394+
395+
self::assertSame([
396+
[
397+
'path' => '',
398+
'error' => [
399+
'code' => 'object.type',
400+
'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given',
401+
'variables' => [
402+
'given' => 'NULL',
403+
],
404+
],
405+
],
406+
], $schema->safeParse(null)->exception->errors->jsonSerialize());
407+
}
408+
409+
public function testGetFieldToSchema(): void
410+
{
411+
$fieldToSchema = ['field1' => new StringSchema(), 'field2' => new IntSchema()];
412+
413+
$schema = new ObjectConstructorSchema($fieldToSchema, ObjectConstructorDemo::class);
414+
415+
self::assertSame($fieldToSchema, $schema->getFieldToSchema());
416+
417+
$fieldToSchema2 = [...$schema->getFieldToSchema(), 'field3' => new BoolSchema()];
418+
419+
$schema2 = new ObjectConstructorSchema($fieldToSchema2, ObjectConstructorDemo::class);
420+
421+
self::assertSame($fieldToSchema2, $schema2->getFieldToSchema());
422+
}
423+
424+
public function testGetFieldSchemaSuccess(): void
425+
{
426+
$field2Schema = new IntSchema();
427+
428+
$schema = new ObjectConstructorSchema([
429+
'field1' => new StringSchema(),
430+
'field2' => $field2Schema,
431+
], ObjectConstructorDemo::class);
432+
433+
self::assertSame($field2Schema, $schema->getFieldSchema('field2'));
434+
}
435+
436+
public function testGetFieldSchemaFailed(): void
437+
{
438+
$schema = new ObjectConstructorSchema([
439+
'field1' => new StringSchema(),
440+
'field2' => new IntSchema(),
441+
], ObjectConstructorDemo::class);
442+
443+
self::assertNull($schema->getFieldSchema('field3'));
444+
}
277445
}

0 commit comments

Comments
 (0)