• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 15040977736

15 May 2025 09:02AM UTC coverage: 21.754% (+13.3%) from 8.423%
15040977736

Pull #6960

github

web-flow
Merge 7a7a13526 into 1862d03b7
Pull Request #6960: feat(json-schema): mutualize json schema between formats

320 of 460 new or added lines in 24 files covered. (69.57%)

1863 existing lines in 109 files now uncovered.

11069 of 50882 relevant lines covered (21.75%)

29.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Symfony/Tests/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Symfony\Tests\Validator\Metadata\Property;
15

16
use ApiPlatform\Metadata\ApiProperty;
17
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
18
use ApiPlatform\Symfony\Tests\Fixtures\DummyAtLeastOneOfValidatedEntity;
19
use ApiPlatform\Symfony\Tests\Fixtures\DummyCollectionValidatedEntity;
20
use ApiPlatform\Symfony\Tests\Fixtures\DummyCompoundValidatedEntity;
21
use ApiPlatform\Symfony\Tests\Fixtures\DummyCountValidatedEntity;
22
use ApiPlatform\Symfony\Tests\Fixtures\DummyIriWithValidationEntity;
23
use ApiPlatform\Symfony\Tests\Fixtures\DummyNumericValidatedEntity;
24
use ApiPlatform\Symfony\Tests\Fixtures\DummyRangeValidatedEntity;
25
use ApiPlatform\Symfony\Tests\Fixtures\DummySequentiallyValidatedEntity;
26
use ApiPlatform\Symfony\Tests\Fixtures\DummyUniqueValidatedEntity;
27
use ApiPlatform\Symfony\Tests\Fixtures\DummyValidatedChoiceEntity;
28
use ApiPlatform\Symfony\Tests\Fixtures\DummyValidatedEntity;
29
use ApiPlatform\Symfony\Tests\Fixtures\DummyValidatedHostnameEntity;
30
use ApiPlatform\Symfony\Tests\Fixtures\DummyValidatedUlidEntity;
31
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaChoiceRestriction;
32
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaCollectionRestriction;
33
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaCountRestriction;
34
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaFormat;
35
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanOrEqualRestriction;
36
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaGreaterThanRestriction;
37
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLengthRestriction;
38
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanOrEqualRestriction;
39
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaLessThanRestriction;
40
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaOneOfRestriction;
41
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRangeRestriction;
42
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRegexRestriction;
43
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaUniqueRestriction;
44
use ApiPlatform\Symfony\Validator\Metadata\Property\ValidatorPropertyMetadataFactory;
45
use PHPUnit\Framework\Attributes\DataProvider;
46
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
47
use PHPUnit\Framework\TestCase;
48
use Prophecy\PhpUnit\ProphecyTrait;
49
use Symfony\Component\PropertyInfo\Type as LegacyType;
50
use Symfony\Component\TypeInfo\Type;
51
use Symfony\Component\Validator\Constraints\Hostname;
52
use Symfony\Component\Validator\Constraints\Ulid;
53
use Symfony\Component\Validator\Mapping\ClassMetadata;
54
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
55
use Symfony\Component\Validator\Mapping\Loader\AttributeLoader;
56

57
/**
58
 * @author Baptiste Meyer <baptiste.meyer@gmail.com>
59
 */
60
class ValidatorPropertyMetadataFactoryTest extends TestCase
61
{
62
    use ProphecyTrait;
63

64
    private ClassMetadata $validatorClassMetadata;
65

66
    protected function setUp(): void
67
    {
68
        $this->validatorClassMetadata = new ClassMetadata(DummyValidatedEntity::class);
×
69
        (new AttributeLoader())->loadClassMetadata($this->validatorClassMetadata);
×
70
    }
71

72
    public function testCreateWithPropertyWithRequiredConstraints(): void
73
    {
74
        $dummyPropertyMetadata = (new ApiProperty())->withDescription('A dummy')->withReadable(true)->withWritable(true);
×
75
        $emailPropertyMetadata = (new ApiProperty())->withTypes(['https://schema.org/email'])->withReadable(true)->withWritable(true);
×
76

77
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
78
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummy', [])->willReturn($dummyPropertyMetadata)->shouldBeCalled();
×
79
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyEmail', [])->willReturn($emailPropertyMetadata)->shouldBeCalled();
×
80

81
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
82
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
83

84
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
85
            $validatorMetadataFactory->reveal(),
×
86
            $decoratedPropertyMetadataFactory->reveal(),
×
87
            []
×
88
        );
×
89

90
        $this->assertEquals(
×
91
            $dummyPropertyMetadata->withRequired(true),
×
92
            $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummy'),
×
93
        );
×
94

95
        $this->assertEquals(
×
96
            $emailPropertyMetadata->withRequired(false),
×
97
            $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyEmail'),
×
98
        );
×
99
    }
100

101
    public function testCreateWithPropertyWithNotRequiredConstraints(): void
102
    {
103
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy')->withReadable(true)->withWritable(true);
×
104
        $expectedPropertyMetadata = $propertyMetadata->withRequired(false);
×
105
        $expectedPropertyMetadata = $expectedPropertyMetadata->withTypes(['https://schema.org/Date']);
×
106

107
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
108
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyDate', [])->willReturn($propertyMetadata)->shouldBeCalled();
×
109

110
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
111
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
112

113
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
114
            $validatorMetadataFactory->reveal(),
×
115
            $decoratedPropertyMetadataFactory->reveal(),
×
116
            []
×
117
        );
×
118
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyDate');
×
119

120
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
121
    }
122

123
    public function testCreateWithPropertyWithoutConstraints(): void
124
    {
125
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy')->withReadable(true)->withWritable(true)->withIdentifier(true);
×
126
        $expectedPropertyMetadata = $propertyMetadata->withRequired(false);
×
127

128
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
129
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyId', [])->willReturn($propertyMetadata)->shouldBeCalled();
×
130

131
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
132
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
133

134
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
135
            $validatorMetadataFactory->reveal(),
×
136
            $decoratedPropertyMetadataFactory->reveal(),
×
137
            []
×
138
        );
×
139
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyId');
×
140

141
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
142
    }
143

144
    public function testCreateWithPropertyWithRightValidationGroupsAndRequiredConstraints(): void
145
    {
146
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true);
×
147
        $expectedPropertyMetadata = $propertyMetadata->withRequired(true);
×
148

149
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
150
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => ['dummy']])->willReturn($propertyMetadata)->shouldBeCalled();
×
151

152
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
153
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
154

155
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
156
            $validatorMetadataFactory->reveal(),
×
157
            $decoratedPropertyMetadataFactory->reveal(),
×
158
            []
×
159
        );
×
160
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => ['dummy']]);
×
161

162
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
163
    }
164

165
    public function testCreateWithPropertyWithBadValidationGroupsAndRequiredConstraints(): void
166
    {
167
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true);
×
168
        $expectedPropertyMetadata = $propertyMetadata->withRequired(false);
×
169

170
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
171
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => ['ymmud']])->willReturn($propertyMetadata)->shouldBeCalled();
×
172

173
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
174
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
175

176
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
177
            $validatorMetadataFactory->reveal(),
×
178
            $decoratedPropertyMetadataFactory->reveal(),
×
179
            []
×
180
        );
×
181
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => ['ymmud']]);
×
182

183
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
184
    }
185

186
    public function testCreateWithPropertyWithNonStringValidationGroupsAndRequiredConstraints(): void
187
    {
188
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true);
×
189
        $expectedPropertyMetadata = $propertyMetadata->withRequired(false);
×
190

191
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
192
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => [1312]])->willReturn($propertyMetadata)->shouldBeCalled();
×
193

194
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
195
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
196

197
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
198
            $validatorMetadataFactory->reveal(),
×
199
            $decoratedPropertyMetadataFactory->reveal(),
×
200
            []
×
201
        );
×
202
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => [1312]]);
×
203

204
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
205
    }
206

207
    public function testCreateWithRequiredByDecorated(): void
208
    {
209
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withRequired(true)->withTypes(['foo:bar']);
×
210
        $expectedPropertyMetadata = (clone $propertyMetadata)->withTypes(['foo:bar', 'https://schema.org/Date']);
×
211

212
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
213
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyDate', [])->willReturn($propertyMetadata)->shouldBeCalled();
×
214

215
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
216
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
217

218
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
219
            $validatorMetadataFactory->reveal(),
×
220
            $decoratedPropertyMetadataFactory->reveal(),
×
221
            []
×
222
        );
×
223
        $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyDate');
×
224

225
        $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata);
×
226
    }
227

228
    public function testCreateWithPropertyWithValidationConstraints(): void
229
    {
230
        $validatorClassMetadata = new ClassMetadata(DummyIriWithValidationEntity::class);
×
231
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
232

233
        $types = [
×
234
            'dummyUrl' => 'https://schema.org/url',
×
235
            'dummyEmail' => 'https://schema.org/email',
×
236
            'dummyUuid' => 'https://schema.org/identifier',
×
237
            'dummyCardScheme' => 'https://schema.org/identifier',
×
238
            'dummyBic' => 'https://schema.org/identifier',
×
239
            'dummyIban' => 'https://schema.org/identifier',
×
240
            'dummyDate' => 'https://schema.org/Date',
×
241
            'dummyDateTime' => 'https://schema.org/DateTime',
×
242
            'dummyTime' => 'https://schema.org/Time',
×
243
            'dummyImage' => 'https://schema.org/image',
×
244
            'dummyFile' => 'https://schema.org/MediaObject',
×
245
            'dummyCurrency' => 'https://schema.org/priceCurrency',
×
246
            'dummyIsbn' => 'https://schema.org/isbn',
×
247
            'dummyIssn' => 'https://schema.org/issn',
×
248
        ];
×
249

250
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
251
        foreach ($types as $property => $iri) {
×
252
            $decoratedPropertyMetadataFactory->create(DummyIriWithValidationEntity::class, $property, [])->willReturn(new ApiProperty())->shouldBeCalled();
×
253
        }
254

255
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
256
        $validatorMetadataFactory->getMetadataFor(DummyIriWithValidationEntity::class)->willReturn($validatorClassMetadata)->shouldBeCalled();
×
257

258
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
259
            $validatorMetadataFactory->reveal(),
×
260
            $decoratedPropertyMetadataFactory->reveal(),
×
261
            []
×
262
        );
×
263

264
        foreach ($types as $property => $iri) {
×
265
            $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyIriWithValidationEntity::class, $property);
×
266
            $this->assertEquals($iri, $resultedPropertyMetadata->getTypes()[0]);
×
267
        }
268
    }
269

270
    public function testCreateWithPropertyLengthRestriction(): void
271
    {
272
        $validatorClassMetadata = new ClassMetadata(DummyValidatedEntity::class);
×
273
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
274

275
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
276
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)
×
277
            ->willReturn($validatorClassMetadata)
×
278
            ->shouldBeCalled();
×
279

280
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
281
        $property = 'dummy';
×
282
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, $property, [])->willReturn(
×
283
            (new ApiProperty())->withNativeType(Type::string())
×
284
        )->shouldBeCalled();
×
285

286
        $lengthRestrictions = new PropertySchemaLengthRestriction();
×
287
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
288
            $validatorMetadataFactory->reveal(),
×
289
            $decoratedPropertyMetadataFactory->reveal(),
×
290
            [$lengthRestrictions]
×
291
        );
×
292

293
        $schema = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, $property)->getSchema();
×
294
        $this->assertNotNull($schema);
×
295
        $this->assertArrayHasKey('minLength', $schema);
×
296
        $this->assertArrayHasKey('maxLength', $schema);
×
297
    }
298

299
    public function testCreateWithPropertyRegexRestriction(): void
300
    {
301
        $validatorClassMetadata = new ClassMetadata(DummyValidatedEntity::class);
×
302
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
303

304
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
305
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)
×
306
            ->willReturn($validatorClassMetadata)
×
307
            ->shouldBeCalled();
×
308

309
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
310
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummy', [])->willReturn(
×
311
            new ApiProperty()
×
312
        )->shouldBeCalled();
×
313

314
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
315
            $validatorMetadataFactory->reveal(),
×
316
            $decoratedPropertyMetadataFactory->reveal(),
×
317
            [new PropertySchemaRegexRestriction()]
×
318
        );
×
319

320
        $schema = $validationPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummy')->getSchema();
×
321
        $this->assertNotNull($schema);
×
322
        $this->assertArrayHasKey('pattern', $schema);
×
323
        $this->assertEquals('^(dummy)$', $schema['pattern']);
×
324
    }
325

326
    #[DataProvider('providePropertySchemaFormatCases')]
327
    public function testCreateWithPropertyFormatRestriction(string $property, string $class, array $expectedSchema): void
328
    {
329
        $validatorClassMetadata = new ClassMetadata($class);
×
330
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
331

332
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
333
        $validatorMetadataFactory->getMetadataFor($class)
×
334
            ->willReturn($validatorClassMetadata)
×
335
            ->shouldBeCalled();
×
336

337
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
338
        $decoratedPropertyMetadataFactory->create($class, $property, [])->willReturn(
×
339
            new ApiProperty()
×
340
        )->shouldBeCalled();
×
341
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
342
            $validatorMetadataFactory->reveal(),
×
343
            $decoratedPropertyMetadataFactory->reveal(),
×
344
            [new PropertySchemaFormat()]
×
345
        );
×
346
        $schema = $validationPropertyMetadataFactory->create($class, $property)->getSchema();
×
347

348
        $this->assertEquals($expectedSchema, $schema);
×
349
    }
350

351
    public static function providePropertySchemaFormatCases(): \Generator
352
    {
353
        yield ['dummyEmail', DummyValidatedEntity::class, ['format' => 'email']];
×
354
        yield ['dummyUuid', DummyValidatedEntity::class, ['format' => 'uuid']];
×
355
        yield ['dummyIpv4', DummyValidatedEntity::class, ['format' => 'ipv4']];
×
356
        yield ['dummyIpv6', DummyValidatedEntity::class, ['format' => 'ipv6']];
×
357
        yield ['dummyUrl', DummyValidatedEntity::class, ['format' => 'uri']];
×
358
        if (class_exists(Ulid::class)) {
×
359
            yield ['dummyUlid', DummyValidatedUlidEntity::class, ['format' => 'ulid']];
×
360
        }
361
        if (class_exists(Hostname::class)) {
×
362
            yield ['dummyHostname', DummyValidatedHostnameEntity::class, ['format' => 'hostname']];
×
363
        }
364
    }
365

366
    public function testCreateWithSequentiallyConstraint(): void
367
    {
368
        $validatorClassMetadata = new ClassMetadata(DummySequentiallyValidatedEntity::class);
×
369
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
370

371
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
372
        $validatorMetadataFactory->getMetadataFor(DummySequentiallyValidatedEntity::class)
×
373
            ->willReturn($validatorClassMetadata)
×
374
            ->shouldBeCalled();
×
375

376
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
377
        $decoratedPropertyMetadataFactory->create(DummySequentiallyValidatedEntity::class, 'dummy', [])->willReturn(
×
378
            (new ApiProperty())->withNativeType(Type::string())
×
379
        )->shouldBeCalled();
×
380
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
381
            $validatorMetadataFactory->reveal(),
×
382
            $decoratedPropertyMetadataFactory->reveal(),
×
383
            [new PropertySchemaLengthRestriction(), new PropertySchemaRegexRestriction()]
×
384
        );
×
385
        $schema = $validationPropertyMetadataFactory->create(DummySequentiallyValidatedEntity::class, 'dummy')->getSchema();
×
386

387
        $this->assertNotNull($schema);
×
388
        $this->assertArrayHasKey('minLength', $schema);
×
389
        $this->assertArrayHasKey('maxLength', $schema);
×
390
        $this->assertArrayHasKey('pattern', $schema);
×
391
    }
392

393
    public function testCreateWithCompoundConstraint(): void
394
    {
395
        $validatorClassMetadata = new ClassMetadata(DummyCompoundValidatedEntity::class);
×
396
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
397

398
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
399
        $validatorMetadataFactory->getMetadataFor(DummyCompoundValidatedEntity::class)
×
400
            ->willReturn($validatorClassMetadata)
×
401
            ->shouldBeCalled();
×
402

403
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
404
        $decoratedPropertyMetadataFactory->create(DummyCompoundValidatedEntity::class, 'dummy', [])->willReturn(
×
405
            (new ApiProperty())->withNativeType(Type::string())
×
406
        )->shouldBeCalled();
×
407
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
408
            $validatorMetadataFactory->reveal(),
×
409
            $decoratedPropertyMetadataFactory->reveal(),
×
410
            [new PropertySchemaLengthRestriction(), new PropertySchemaRegexRestriction()]
×
411
        );
×
412
        $schema = $validationPropertyMetadataFactory->create(DummyCompoundValidatedEntity::class, 'dummy')->getSchema();
×
413

414
        $this->assertNotNull($schema);
×
415
        $this->assertArrayHasKey('minLength', $schema);
×
416
        $this->assertArrayHasKey('maxLength', $schema);
×
417
        $this->assertArrayHasKey('pattern', $schema);
×
418
    }
419

420
    public function testCreateWithAtLeastOneOfConstraint(): void
421
    {
422
        $validatorClassMetadata = new ClassMetadata(DummyAtLeastOneOfValidatedEntity::class);
×
423
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
424

425
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
426
        $validatorMetadataFactory->getMetadataFor(DummyAtLeastOneOfValidatedEntity::class)
×
427
            ->willReturn($validatorClassMetadata)
×
428
            ->shouldBeCalled();
×
429

430
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
431
        $decoratedPropertyMetadataFactory->create(DummyAtLeastOneOfValidatedEntity::class, 'dummy', [])->willReturn(
×
432
            (new ApiProperty())->withNativeType(Type::string())
×
433
        )->shouldBeCalled();
×
434
        $restrictionsMetadata = [new PropertySchemaLengthRestriction(), new PropertySchemaRegexRestriction()];
×
435
        $restrictionsMetadata = [new PropertySchemaOneOfRestriction($restrictionsMetadata), new PropertySchemaLengthRestriction(), new PropertySchemaRegexRestriction()];
×
436
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
437
            $validatorMetadataFactory->reveal(),
×
438
            $decoratedPropertyMetadataFactory->reveal(),
×
439
            $restrictionsMetadata
×
440
        );
×
441
        $schema = $validationPropertyMetadataFactory->create(DummyAtLeastOneOfValidatedEntity::class, 'dummy')->getSchema();
×
442

443
        $this->assertNotNull($schema);
×
444
        $this->assertArrayHasKey('oneOf', $schema);
×
445
        $this->assertEquals([
×
446
            ['pattern' => '^(.*#.*)$'],
×
447
            ['minLength' => 10],
×
448
        ], $schema['oneOf']);
×
449
    }
450

451
    public function testCreateWithPropertyUniqueRestriction(): void
452
    {
453
        $validatorClassMetadata = new ClassMetadata(DummyUniqueValidatedEntity::class);
×
454
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
455

456
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
457
        $validatorMetadataFactory->getMetadataFor(DummyUniqueValidatedEntity::class)
×
458
            ->willReturn($validatorClassMetadata)
×
459
            ->shouldBeCalled();
×
460

461
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
462
        $decoratedPropertyMetadataFactory->create(DummyUniqueValidatedEntity::class, 'dummyItems', [])->willReturn(
×
463
            new ApiProperty()
×
464
        )->shouldBeCalled();
×
465

466
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
467
            $validatorMetadataFactory->reveal(),
×
468
            $decoratedPropertyMetadataFactory->reveal(),
×
469
            [new PropertySchemaUniqueRestriction()]
×
470
        );
×
471

472
        $schema = $validationPropertyMetadataFactory->create(DummyUniqueValidatedEntity::class, 'dummyItems')->getSchema();
×
473

474
        $this->assertEquals(['uniqueItems' => true], $schema);
×
475
    }
476

477
    #[IgnoreDeprecations]
478
    public function testLegacyCreateWithRangeConstraint(): void
479
    {
480
        foreach ($this->provideRangeConstraintCases() as ['type' => $type, 'property' => $property, 'expectedSchema' => $expectedSchema]) {
×
481
            $validatorClassMetadata = new ClassMetadata(DummyRangeValidatedEntity::class);
×
482
            (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
483

484
            $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
485
            $validatorMetadataFactory->getMetadataFor(DummyRangeValidatedEntity::class)
×
486
                ->willReturn($validatorClassMetadata)
×
487
                ->shouldBeCalled();
×
488

489
            $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
490
            $decoratedPropertyMetadataFactory->create(DummyRangeValidatedEntity::class, $property, [])->willReturn(
×
491
                (new ApiProperty())->withBuiltinTypes([$type])
×
492
            )->shouldBeCalled();
×
493
            $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
494
                $validatorMetadataFactory->reveal(),
×
495
                $decoratedPropertyMetadataFactory->reveal(),
×
496
                [new PropertySchemaRangeRestriction()]
×
497
            );
×
498
            $schema = $validationPropertyMetadataFactory->create(DummyRangeValidatedEntity::class, $property)->getSchema();
×
499

500
            $this->assertEquals($expectedSchema, $schema);
×
501
        }
502
    }
503

504
    public static function provideRangeConstraintCases(): \Generator
505
    {
506
        yield 'min int' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_INT), 'property' => 'dummyIntMin', 'expectedSchema' => ['minimum' => 1]];
×
507
        yield 'max int' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_INT), 'property' => 'dummyIntMax', 'expectedSchema' => ['maximum' => 10]];
×
508
        yield 'min/max int' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_INT), 'property' => 'dummyIntMinMax', 'expectedSchema' => ['minimum' => 1, 'maximum' => 10]];
×
509
        yield 'min float' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT), 'property' => 'dummyFloatMin', 'expectedSchema' => ['minimum' => 1.5]];
×
510
        yield 'max float' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT), 'property' => 'dummyFloatMax', 'expectedSchema' => ['maximum' => 10.5]];
×
511
        yield 'min/max float' => ['type' => new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT), 'property' => 'dummyFloatMinMax', 'expectedSchema' => ['minimum' => 1.5, 'maximum' => 10.5]];
×
512
    }
513

514
    #[DataProvider('provideRangeConstraintCasesWithNativeType')]
515
    public function testCreateWithRangeConstraintWithNativeType(Type $type, string $property, array $expectedSchema): void // Use new Type
516
    {
517
        $validatorClassMetadata = new ClassMetadata(DummyRangeValidatedEntity::class);
×
518
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
519

520
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
521
        $validatorMetadataFactory->getMetadataFor(DummyRangeValidatedEntity::class)
×
522
            ->willReturn($validatorClassMetadata)
×
523
            ->shouldBeCalled();
×
524

525
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
526
        $decoratedPropertyMetadataFactory->create(DummyRangeValidatedEntity::class, $property, [])->willReturn(
×
527
            (new ApiProperty())->withNativeType($type) // Use withNativeType and new Type
×
528
        )->shouldBeCalled();
×
529
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
530
            $validatorMetadataFactory->reveal(),
×
531
            $decoratedPropertyMetadataFactory->reveal(),
×
532
            [new PropertySchemaRangeRestriction()]
×
533
        );
×
534
        $schema = $validationPropertyMetadataFactory->create(DummyRangeValidatedEntity::class, $property)->getSchema();
×
535

536
        $this->assertEquals($expectedSchema, $schema);
×
537
    }
538

539
    public static function provideRangeConstraintCasesWithNativeType(): \Generator
540
    {
541
        yield 'native type: min int' => ['type' => Type::int(), 'property' => 'dummyIntMin', 'expectedSchema' => ['minimum' => 1]];
×
542
        yield 'native type: max int' => ['type' => Type::int(), 'property' => 'dummyIntMax', 'expectedSchema' => ['maximum' => 10]];
×
543
        yield 'native type: min/max int' => ['type' => Type::int(), 'property' => 'dummyIntMinMax', 'expectedSchema' => ['minimum' => 1, 'maximum' => 10]];
×
544
        yield 'native type: min float' => ['type' => Type::float(), 'property' => 'dummyFloatMin', 'expectedSchema' => ['minimum' => 1.5]];
×
545
        yield 'native type: max float' => ['type' => Type::float(), 'property' => 'dummyFloatMax', 'expectedSchema' => ['maximum' => 10.5]];
×
546
        yield 'native type: min/max float' => ['type' => Type::float(), 'property' => 'dummyFloatMinMax', 'expectedSchema' => ['minimum' => 1.5, 'maximum' => 10.5]];
×
547
    }
548

549
    #[IgnoreDeprecations]
550
    public function testCreateWithPropertyChoiceRestriction(): void
551
    {
552
        foreach ($this->provideChoiceConstraintCases() as ['propertyMetadata' => $propertyMetadata, 'property' => $property, 'expectedSchema' => $expectedSchema]) {
×
553
            $validatorClassMetadata = new ClassMetadata(DummyValidatedChoiceEntity::class);
×
554
            (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
555

556
            $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
557
            $validatorMetadataFactory->getMetadataFor(DummyValidatedChoiceEntity::class)
×
558
                ->willReturn($validatorClassMetadata)
×
559
                ->shouldBeCalled();
×
560

561
            $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
562
            $decoratedPropertyMetadataFactory->create(DummyValidatedChoiceEntity::class, $property, [])->willReturn(
×
563
                $propertyMetadata
×
564
            )->shouldBeCalled();
×
565

566
            $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
567
                $validatorMetadataFactory->reveal(),
×
568
                $decoratedPropertyMetadataFactory->reveal(),
×
569
                [new PropertySchemaChoiceRestriction()]
×
570
            );
×
571

572
            $schema = $validationPropertyMetadataFactory->create(DummyValidatedChoiceEntity::class, $property)->getSchema();
×
573

574
            $this->assertEquals($expectedSchema, $schema);
×
575
        }
576
    }
577

578
    public static function provideChoiceConstraintCases(): \Generator
579
    {
580
        yield 'single choice' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummySingleChoice', 'expectedSchema' => ['enum' => ['a', 'b']]];
×
581
        yield 'single choice callback' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummySingleChoiceCallback', 'expectedSchema' => ['enum' => ['a', 'b', 'c', 'd']]];
×
582
        yield 'multi choice' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummyMultiChoice', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b']]]];
×
583
        yield 'multi choice callback' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummyMultiChoiceCallback', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']]]];
×
584
        yield 'multi choice min' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummyMultiChoiceMin', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'minItems' => 2]];
×
585
        yield 'multi choice max' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummyMultiChoiceMax', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'maxItems' => 4]];
×
586
        yield 'multi choice min/max' => ['propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)]), 'property' => 'dummyMultiChoiceMinMax', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'minItems' => 2, 'maxItems' => 4]];
×
587
    }
588

589
    #[DataProvider('provideChoiceConstraintCasesWithNativeType')]
590
    public function testCreateWithPropertyChoiceRestrictionWithNativeType(ApiProperty $propertyMetadata, string $property, array $expectedSchema): void
591
    {
592
        $validatorClassMetadata = new ClassMetadata(DummyValidatedChoiceEntity::class);
×
593
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
594

595
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
596
        $validatorMetadataFactory->getMetadataFor(DummyValidatedChoiceEntity::class)
×
597
            ->willReturn($validatorClassMetadata)
×
598
            ->shouldBeCalled();
×
599

600
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
601
        $decoratedPropertyMetadataFactory->create(DummyValidatedChoiceEntity::class, $property, [])->willReturn(
×
602
            $propertyMetadata // Provider now sends ApiProperty configured with withNativeType
×
603
        )->shouldBeCalled();
×
604

605
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
606
            $validatorMetadataFactory->reveal(),
×
607
            $decoratedPropertyMetadataFactory->reveal(),
×
608
            [new PropertySchemaChoiceRestriction()]
×
609
        );
×
610

611
        $schema = $validationPropertyMetadataFactory->create(DummyValidatedChoiceEntity::class, $property)->getSchema();
×
612

613
        $this->assertEquals($expectedSchema, $schema);
×
614
    }
615

616
    public static function provideChoiceConstraintCasesWithNativeType(): \Generator
617
    {
618
        yield 'native type: single choice' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummySingleChoice', 'expectedSchema' => ['enum' => ['a', 'b']]];
×
619
        yield 'native type: single choice callback' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummySingleChoiceCallback', 'expectedSchema' => ['enum' => ['a', 'b', 'c', 'd']]];
×
620
        yield 'native type: multi choice' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummyMultiChoice', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b']]]];
×
621
        yield 'native type: multi choice callback' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummyMultiChoiceCallback', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']]]];
×
622
        yield 'native type: multi choice min' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummyMultiChoiceMin', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'minItems' => 2]];
×
623
        yield 'native type: multi choice max' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummyMultiChoiceMax', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'maxItems' => 4]];
×
624
        yield 'native type: multi choice min/max' => ['propertyMetadata' => (new ApiProperty())->withNativeType(Type::string()), 'property' => 'dummyMultiChoiceMinMax', 'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string', 'enum' => ['a', 'b', 'c', 'd']], 'minItems' => 2, 'maxItems' => 4]];
×
625
    }
626

627
    #[DataProvider('provideCountConstraintCases')]
628
    public function testCreateWithPropertyCountRestriction(string $property, array $expectedSchema): void
629
    {
630
        $validatorClassMetadata = new ClassMetadata(DummyCountValidatedEntity::class);
×
631
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
632

633
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
634
        $validatorMetadataFactory->getMetadataFor(DummyCountValidatedEntity::class)
×
635
            ->willReturn($validatorClassMetadata)
×
636
            ->shouldBeCalled();
×
637

638
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
639
        $decoratedPropertyMetadataFactory->create(DummyCountValidatedEntity::class, $property, [])->willReturn(
×
640
            new ApiProperty()
×
641
        )->shouldBeCalled();
×
642

643
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
644
            $validatorMetadataFactory->reveal(),
×
645
            $decoratedPropertyMetadataFactory->reveal(),
×
646
            [new PropertySchemaCountRestriction()]
×
647
        );
×
648

649
        $schema = $validationPropertyMetadataFactory->create(DummyCountValidatedEntity::class, $property)->getSchema();
×
650

651
        $this->assertEquals($expectedSchema, $schema);
×
652
    }
653

654
    public static function provideCountConstraintCases(): \Generator
655
    {
656
        yield 'min' => ['property' => 'dummyMin', 'expectedSchema' => ['minItems' => 1]];
×
657
        yield 'max' => ['property' => 'dummyMax', 'expectedSchema' => ['maxItems' => 10]];
×
658
        yield 'min/max' => ['property' => 'dummyMinMax', 'expectedSchema' => ['minItems' => 1, 'maxItems' => 10]];
×
659
    }
660

661
    public function testCreateWithPropertyCollectionRestriction(): void
662
    {
663
        $validatorClassMetadata = new ClassMetadata(DummyCollectionValidatedEntity::class);
×
664
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
665

666
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
667
        $validatorMetadataFactory->getMetadataFor(DummyCollectionValidatedEntity::class)
×
668
            ->willReturn($validatorClassMetadata)
×
669
            ->shouldBeCalled();
×
670

671
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
672
        $decoratedPropertyMetadataFactory->create(DummyCollectionValidatedEntity::class, 'dummyData', [])->willReturn(
×
673
            (new ApiProperty())->withNativeType(Type::list())
×
674
        )->shouldBeCalled();
×
675

676
        $greaterThanRestriction = new PropertySchemaGreaterThanRestriction();
×
677
        $lengthRestriction = new PropertySchemaLengthRestriction();
×
678
        $regexRestriction = new PropertySchemaRegexRestriction();
×
679
        $formatRestriction = new PropertySchemaFormat();
×
680
        $restrictionsMetadata = [
×
681
            $greaterThanRestriction,
×
682
            $lengthRestriction,
×
683
            $regexRestriction,
×
684
            $formatRestriction,
×
685
            new PropertySchemaCollectionRestriction([
×
686
                $greaterThanRestriction,
×
687
                $lengthRestriction,
×
688
                $regexRestriction,
×
689
                $formatRestriction,
×
690
                new PropertySchemaCollectionRestriction([
×
691
                    $greaterThanRestriction,
×
692
                    $lengthRestriction,
×
693
                    $regexRestriction,
×
694
                    $formatRestriction,
×
695
                ]),
×
696
            ]),
×
697
        ];
×
698

699
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
700
            $validatorMetadataFactory->reveal(),
×
701
            $decoratedPropertyMetadataFactory->reveal(),
×
702
            $restrictionsMetadata
×
703
        );
×
704

705
        $schema = $validationPropertyMetadataFactory->create(DummyCollectionValidatedEntity::class, 'dummyData')->getSchema();
×
706

707
        $this->assertEquals([
×
708
            'type' => 'object',
×
709
            'properties' => new \ArrayObject([
×
710
                'name' => new \ArrayObject(),
×
711
                'email' => ['format' => 'email', 'minLength' => 2, 'maxLength' => 255],
×
712
                'phone' => ['pattern' => '^([+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*)$'],
×
713
                'age' => [
×
714
                    'exclusiveMinimum' => 0,
×
NEW
715
                    'minimum' => 0,
×
716
                ],
×
717
                'social' => [
×
718
                    'type' => 'object',
×
719
                    'properties' => new \ArrayObject([
×
720
                        'githubUsername' => new \ArrayObject(),
×
721
                    ]),
×
722
                    'additionalProperties' => false,
×
723
                    'required' => ['githubUsername'],
×
724
                ],
×
725
            ]),
×
726
            'additionalProperties' => true,
×
727
            'required' => ['name', 'email', 'social'],
×
728
        ], $schema);
×
729
    }
730

731
    #[IgnoreDeprecations]
732
    public function testCreateWithPropertyNumericRestriction(): void
733
    {
734
        foreach ($this->provideNumericConstraintCases() as ['propertyMetadata' => $propertyMetadata, 'property' => $property, 'expectedSchema' => $expectedSchema]) {
×
735
            $validatorClassMetadata = new ClassMetadata(DummyNumericValidatedEntity::class);
×
736
            (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
737

738
            $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
739
            $validatorMetadataFactory->getMetadataFor(DummyNumericValidatedEntity::class)
×
740
                ->willReturn($validatorClassMetadata)
×
741
                ->shouldBeCalled();
×
742

743
            $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
744
            $decoratedPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property, [])->willReturn(
×
745
                $propertyMetadata
×
746
            )->shouldBeCalled();
×
747

748
            $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
749
                $validatorMetadataFactory->reveal(),
×
750
                $decoratedPropertyMetadataFactory->reveal(),
×
751
                [
×
752
                    new PropertySchemaGreaterThanOrEqualRestriction(),
×
753
                    new PropertySchemaGreaterThanRestriction(),
×
754
                    new PropertySchemaLessThanOrEqualRestriction(),
×
755
                    new PropertySchemaLessThanRestriction(),
×
756
                ]
×
757
            );
×
758

759
            $schema = $validationPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property)->getSchema();
×
760

761
            $this->assertEquals($expectedSchema, $schema);
×
762
        }
763
    }
764

765
    public static function provideNumericConstraintCases(): \Generator
766
    {
767
        yield [
×
768
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
769
            'property' => 'greaterThanMe',
×
NEW
770
            'expectedSchema' => ['exclusiveMinimum' => 10, 'minimum' => 10],
×
771
        ];
×
772

773
        yield [
×
774
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]),
×
775
            'property' => 'greaterThanOrEqualToMe',
×
776
            'expectedSchema' => ['minimum' => 10.99],
×
777
        ];
×
778

779
        yield [
×
780
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
781
            'property' => 'lessThanMe',
×
NEW
782
            'expectedSchema' => ['exclusiveMaximum' => 99, 'maximum' => 99],
×
783
        ];
×
784

785
        yield [
×
786
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_FLOAT)]),
×
787
            'property' => 'lessThanOrEqualToMe',
×
788
            'expectedSchema' => ['maximum' => 99.33],
×
789
        ];
×
790

791
        yield [
×
792
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
793
            'property' => 'positive',
×
NEW
794
            'expectedSchema' => ['exclusiveMinimum' => 0, 'minimum' => 0],
×
795
        ];
×
796

797
        yield [
×
798
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
799
            'property' => 'positiveOrZero',
×
800
            'expectedSchema' => ['minimum' => 0],
×
801
        ];
×
802

803
        yield [
×
804
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
805
            'property' => 'negative',
×
NEW
806
            'expectedSchema' => ['exclusiveMaximum' => 0, 'maximum' => 0],
×
807
        ];
×
808

809
        yield [
×
810
            'propertyMetadata' => (new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_INT)]),
×
811
            'property' => 'negativeOrZero',
×
812
            'expectedSchema' => ['maximum' => 0],
×
813
        ];
×
814
    }
815

816
    #[DataProvider('provideNumericConstraintCasesWithNativeType')]
817
    public function testCreateWithPropertyNumericRestrictionWithNativeType(ApiProperty $propertyMetadata, string $property, array $expectedSchema): void
818
    {
819
        $validatorClassMetadata = new ClassMetadata(DummyNumericValidatedEntity::class);
×
820
        (new AttributeLoader())->loadClassMetadata($validatorClassMetadata);
×
821

822
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
823
        $validatorMetadataFactory->getMetadataFor(DummyNumericValidatedEntity::class)
×
824
            ->willReturn($validatorClassMetadata)
×
825
            ->shouldBeCalled();
×
826

827
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
828
        $decoratedPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property, [])->willReturn(
×
829
            $propertyMetadata
×
830
        )->shouldBeCalled();
×
831

832
        $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
833
            $validatorMetadataFactory->reveal(),
×
834
            $decoratedPropertyMetadataFactory->reveal(),
×
835
            [
×
836
                new PropertySchemaGreaterThanOrEqualRestriction(),
×
837
                new PropertySchemaGreaterThanRestriction(),
×
838
                new PropertySchemaLessThanOrEqualRestriction(),
×
839
                new PropertySchemaLessThanRestriction(),
×
840
            ]
×
841
        );
×
842

843
        $schema = $validationPropertyMetadataFactory->create(DummyNumericValidatedEntity::class, $property)->getSchema();
×
844

845
        $this->assertEquals($expectedSchema, $schema);
×
846
    }
847

848
    public static function provideNumericConstraintCasesWithNativeType(): \Generator
849
    {
850
        yield [
×
851
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
852
            'property' => 'greaterThanMe',
×
NEW
853
            'expectedSchema' => ['exclusiveMinimum' => 10, 'minimum' => 10],
×
854
        ];
×
855

856
        yield [
×
857
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::float()),
×
858
            'property' => 'greaterThanOrEqualToMe',
×
859
            'expectedSchema' => ['minimum' => 10.99],
×
860
        ];
×
861

862
        yield [
×
863
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
864
            'property' => 'lessThanMe',
×
NEW
865
            'expectedSchema' => ['exclusiveMaximum' => 99, 'maximum' => 99],
×
866
        ];
×
867

868
        yield [
×
869
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::float()),
×
870
            'property' => 'lessThanOrEqualToMe',
×
871
            'expectedSchema' => ['maximum' => 99.33],
×
872
        ];
×
873

874
        yield [
×
875
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
876
            'property' => 'positive',
×
NEW
877
            'expectedSchema' => ['exclusiveMinimum' => 0, 'minimum' => 0],
×
878
        ];
×
879

880
        yield [
×
881
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
882
            'property' => 'positiveOrZero',
×
883
            'expectedSchema' => ['minimum' => 0],
×
884
        ];
×
885

886
        yield [
×
887
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
888
            'property' => 'negative',
×
NEW
889
            'expectedSchema' => ['exclusiveMaximum' => 0, 'maximum' => 0],
×
890
        ];
×
891

892
        yield [
×
893
            'propertyMetadata' => (new ApiProperty())->withNativeType(Type::int()),
×
894
            'property' => 'negativeOrZero',
×
895
            'expectedSchema' => ['maximum' => 0],
×
896
        ];
×
897
    }
898

899
    public function testCallableGroup(): void
900
    {
901
        $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true);
×
902

903
        $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
904
        $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => [DummyValidatedEntity::class, 'getValidationGroups']])->willReturn($propertyMetadata)->shouldBeCalled();
×
905

906
        $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class);
×
907
        $validatorMetadataFactory->getMetadataFor(DummyValidatedEntity::class)->willReturn($this->validatorClassMetadata)->shouldBeCalled();
×
908

909
        $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory(
×
910
            $validatorMetadataFactory->reveal(),
×
911
            $decoratedPropertyMetadataFactory->reveal(),
×
912
            []
×
913
        );
×
914
        $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummyGroup', ['validation_groups' => [DummyValidatedEntity::class, 'getValidationGroups']]);
×
915
    }
916
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc