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

api-platform / core / 19799200245

30 Nov 2025 12:55PM UTC coverage: 25.257% (+1.2%) from 24.059%
19799200245

push

github

web-flow
chore: support symfony 8 (#7561)

17 of 211 new or added lines in 28 files covered. (8.06%)

265 existing lines in 25 files now uncovered.

14551 of 57612 relevant lines covered (25.26%)

27.67 hits per line

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

0.0
/src/JsonSchema/Tests/Metadata/Property/Factory/SchemaPropertyMetadataFactoryTest.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\JsonSchema\Tests\Metadata\Property\Factory;
15

16
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
17
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithCustomOpenApiContext;
18
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithEnum;
19
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithMixed;
20
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithUnionTypeProperty;
21
use ApiPlatform\JsonSchema\Tests\Fixtures\Enum\IntEnumAsIdentifier;
22
use ApiPlatform\Metadata\ApiProperty;
23
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
24
use ApiPlatform\Metadata\ResourceClassResolverInterface;
25
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
26
use PHPUnit\Framework\TestCase;
27
use Symfony\Component\PropertyInfo\Type as LegacyType;
28
use Symfony\Component\TypeInfo\Type;
29

30
class SchemaPropertyMetadataFactoryTest extends TestCase
31
{
32
    #[IgnoreDeprecations]
33
    public function testEnumLegacy(): void
34
    {
NEW
35
        if (!class_exists(LegacyType::class)) {
×
NEW
36
            $this->markTestSkipped();
×
37
        }
38
        $this->expectUserDeprecationMessage('Since api_platform/metadata 4.2: The "builtinTypes" argument of "ApiPlatform\Metadata\ApiProperty" is deprecated, use "nativeType" instead.');
×
39
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
40
        $apiProperty = new ApiProperty(builtinTypes: [new LegacyType(builtinType: 'object', nullable: true, class: IntEnumAsIdentifier::class)]);
×
41
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
42
        $decorated->expects($this->once())->method('create')->with(DummyWithEnum::class, 'intEnumAsIdentifier')->willReturn($apiProperty);
×
43
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
44
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithEnum::class, 'intEnumAsIdentifier');
×
45
        $this->assertEquals(['type' => ['integer', 'null'], 'enum' => [1, 2, null]], $apiProperty->getSchema());
×
46
    }
47

48
    public function testEnum(): void
49
    {
50
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
51
        $apiProperty = new ApiProperty(nativeType: Type::nullable(Type::enum(IntEnumAsIdentifier::class)));
×
52
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
53
        $decorated->expects($this->once())->method('create')->with(DummyWithEnum::class, 'intEnumAsIdentifier')->willReturn($apiProperty);
×
54
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
55
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithEnum::class, 'intEnumAsIdentifier');
×
56
        $this->assertEquals(['type' => ['integer', 'null'], 'enum' => [1, 2, null]], $apiProperty->getSchema());
×
57
    }
58

59
    #[IgnoreDeprecations]
60
    public function testWithCustomOpenApiContextLegacy(): void
61
    {
NEW
62
        if (!class_exists(LegacyType::class)) {
×
NEW
63
            $this->markTestSkipped();
×
64
        }
65
        $this->expectUserDeprecationMessage('Since api_platform/metadata 4.2: The "builtinTypes" argument of "ApiPlatform\Metadata\ApiProperty" is deprecated, use "nativeType" instead.');
×
66
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
67
        $apiProperty = new ApiProperty(
×
68
            builtinTypes: [new LegacyType(builtinType: 'object', nullable: true, class: IntEnumAsIdentifier::class)],
×
69
            openapiContext: ['type' => 'object', 'properties' => ['alpha' => ['type' => 'integer']]],
×
70
        );
×
71
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
72
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'acme')->willReturn($apiProperty);
×
73
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
74
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'acme');
×
75
        $this->assertEquals([], $apiProperty->getSchema());
×
76
    }
77

78
    public function testWithCustomOpenApiContext(): void
79
    {
80
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
81
        $apiProperty = new ApiProperty(
×
82
            nativeType: Type::nullable(Type::enum(IntEnumAsIdentifier::class)),
×
83
            openapiContext: ['type' => 'object', 'properties' => ['alpha' => ['type' => 'integer']]],
×
84
        );
×
85
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
86
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'acme')->willReturn($apiProperty);
×
87
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
88
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'acme');
×
89
        $this->assertEquals([], $apiProperty->getSchema());
×
90
    }
91

92
    #[IgnoreDeprecations]
93
    public function testWithCustomOpenApiContextWithoutTypeDefinitionLegacy(): void
94
    {
NEW
95
        if (!class_exists(LegacyType::class)) {
×
NEW
96
            $this->markTestSkipped();
×
97
        }
98
        $this->expectUserDeprecationMessage('Since api_platform/metadata 4.2: The "builtinTypes" argument of "ApiPlatform\Metadata\ApiProperty" is deprecated, use "nativeType" instead.');
×
99
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
100
        $apiProperty = new ApiProperty(
×
101
            openapiContext: ['description' => 'My description'],
×
102
            builtinTypes: [new LegacyType(builtinType: 'bool')],
×
103
        );
×
104
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
105
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'foo')->willReturn($apiProperty);
×
106
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
107
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'foo');
×
108
        $this->assertEquals([
×
109
            'type' => 'boolean',
×
110
        ], $apiProperty->getSchema());
×
111

112
        $apiProperty = new ApiProperty(
×
113
            openapiContext: ['iris' => 'https://schema.org/Date'],
×
114
            builtinTypes: [new LegacyType(builtinType: 'object', class: \DateTimeImmutable::class)],
×
115
        );
×
116
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
117
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'bar')->willReturn($apiProperty);
×
118
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
119
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'bar');
×
120
        $this->assertEquals([
×
121
            'type' => 'string',
×
122
            'format' => 'date-time',
×
123
        ], $apiProperty->getSchema());
×
124
    }
125

126
    public function testWithCustomOpenApiContextWithoutTypeDefinition(): void
127
    {
128
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
129
        $apiProperty =
×
130
            new ApiProperty(
×
131
                openapiContext: ['description' => 'My description'],
×
132
                nativeType: Type::bool(),
×
133
            );
×
134
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
135
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'foo')->willReturn($apiProperty);
×
136
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
137
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'foo');
×
138
        $this->assertEquals([
×
139
            'type' => 'boolean',
×
140
        ], $apiProperty->getSchema());
×
141

142
        $apiProperty =
×
143
            new ApiProperty(
×
144
                openapiContext: ['iris' => 'https://schema.org/Date'],
×
145
                nativeType: Type::object(\DateTimeImmutable::class),
×
146
            );
×
147
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
148
        $decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'bar')->willReturn($apiProperty);
×
149
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
150
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'bar');
×
151
        $this->assertEquals([
×
152
            'type' => 'string',
×
153
            'format' => 'date-time',
×
154
        ], $apiProperty->getSchema());
×
155
    }
156

157
    public function testUnionTypeAnyOfIsArray(): void
158
    {
159
        if (!method_exists(PropertyInfoExtractor::class, 'getType')) { // @phpstan-ignore-line symfony/property-info 6.4 is still allowed and this may be true
×
160
            $this->markTestSkipped('This test only supports type-info component');
×
161
        }
162

163
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
164
        $apiProperty = new ApiProperty(nativeType: Type::union(Type::string(), Type::int()));
×
165
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
166
        $decorated->expects($this->once())->method('create')->with(DummyWithUnionTypeProperty::class, 'unionProperty')->willReturn($apiProperty);
×
167

168
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
169
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithUnionTypeProperty::class, 'unionProperty');
×
170

171
        $expectedSchema = [
×
172
            'anyOf' => [
×
173
                ['type' => 'integer'],
×
174
                ['type' => 'string'],
×
175
            ],
×
176
        ];
×
177

178
        $this->assertEquals($expectedSchema, $apiProperty->getSchema());
×
179
    }
180

181
    public function testMixed(): void
182
    {
183
        if (!method_exists(PropertyInfoExtractor::class, 'getType')) { // @phpstan-ignore-line symfony/property-info 6.4 is still allowed and this may be true
×
184
            $this->markTestSkipped('This test only supports type-info component');
×
185
        }
186

187
        $resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
×
188
        $apiProperty = new ApiProperty(nativeType: Type::mixed());
×
189
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
190
        $decorated->expects($this->once())->method('create')->with(DummyWithMixed::class, 'mixedProperty')->willReturn($apiProperty);
×
191

192
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
193
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithMixed::class, 'mixedProperty');
×
194

195
        $this->assertEquals([
×
196
            'type' => ['string', 'null'],
×
197
        ], $apiProperty->getSchema());
×
198

199
        $apiProperty = new ApiProperty(nativeType: Type::array(Type::mixed()));
×
200
        $decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
×
201
        $decorated->expects($this->once())->method('create')->with(DummyWithMixed::class, 'mixedArrayProperty')->willReturn($apiProperty);
×
202

203
        $schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
×
204
        $apiProperty = $schemaPropertyMetadataFactory->create(DummyWithMixed::class, 'mixedArrayProperty');
×
205

206
        $this->assertEquals([
×
207
            'type' => 'array',
×
208
            'items' => [
×
209
                'type' => ['string', 'null'],
×
210
            ],
×
211
        ], $apiProperty->getSchema());
×
212
    }
213
}
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

© 2026 Coveralls, Inc