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

api-platform / core / 18089937549

29 Sep 2025 07:56AM UTC coverage: 21.764% (-0.3%) from 22.093%
18089937549

Pull #7416

github

web-flow
Merge 061bcc790 into abe0438be
Pull Request #7416: fix(laravel): serializer attributes on Eloquent methods

0 of 151 new or added lines in 11 files covered. (0.0%)

5028 existing lines in 173 files now uncovered.

11889 of 54626 relevant lines covered (21.76%)

25.32 hits per line

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

0.0
/src/GraphQl/Tests/Type/TypeBuilderTest.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\GraphQl\Tests\Type;
15

16
use ApiPlatform\GraphQl\Serializer\ItemNormalizer;
17
use ApiPlatform\GraphQl\Tests\Fixtures\ApiResource\Dummy;
18
use ApiPlatform\GraphQl\Tests\Fixtures\Enum\GamePlayMode;
19
use ApiPlatform\GraphQl\Type\FieldsBuilderEnumInterface;
20
use ApiPlatform\GraphQl\Type\TypeBuilder;
21
use ApiPlatform\GraphQl\Type\TypesContainerInterface;
22
use ApiPlatform\Metadata\ApiProperty;
23
use ApiPlatform\Metadata\ApiResource;
24
use ApiPlatform\Metadata\GraphQl\Mutation;
25
use ApiPlatform\Metadata\GraphQl\Operation;
26
use ApiPlatform\Metadata\GraphQl\Query;
27
use ApiPlatform\Metadata\GraphQl\QueryCollection;
28
use ApiPlatform\Metadata\GraphQl\Subscription;
29
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
30
use ApiPlatform\State\Pagination\Pagination;
31
use GraphQL\Type\Definition\EnumType;
32
use GraphQL\Type\Definition\InputObjectType;
33
use GraphQL\Type\Definition\InterfaceType;
34
use GraphQL\Type\Definition\ListOfType;
35
use GraphQL\Type\Definition\NonNull;
36
use GraphQL\Type\Definition\ObjectType;
37
use GraphQL\Type\Definition\ResolveInfo;
38
use GraphQL\Type\Definition\Type as GraphQLType;
39
use PHPUnit\Framework\Attributes\DataProvider;
40
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
41
use PHPUnit\Framework\TestCase;
42
use Prophecy\Argument;
43
use Prophecy\PhpUnit\ProphecyTrait;
44
use Prophecy\Prophecy\ObjectProphecy;
45
use Psr\Container\ContainerInterface;
46
use Symfony\Component\PropertyInfo\Type as LegacyType;
47
use Symfony\Component\TypeInfo\Type;
48

49
/**
50
 * @author Alan Poulain <contact@alanpoulain.eu>
51
 */
52
class TypeBuilderTest extends TestCase
53
{
54
    use ProphecyTrait;
55

56
    private ObjectProphecy $typesContainerProphecy;
57
    /** @var callable */
58
    private $defaultFieldResolver;
59
    private ObjectProphecy $fieldsBuilderLocatorProphecy;
60
    private TypeBuilder $typeBuilder;
61

62
    /**
63
     * {@inheritdoc}
64
     */
65
    protected function setUp(): void
66
    {
67
        $this->typesContainerProphecy = $this->prophesize(TypesContainerInterface::class);
×
68
        $this->defaultFieldResolver = static function (): void {
×
69
        };
×
70
        $this->fieldsBuilderLocatorProphecy = $this->prophesize(ContainerInterface::class);
×
71
        $this->typeBuilder = new TypeBuilder(
×
72
            $this->typesContainerProphecy->reveal(),
×
73
            $this->defaultFieldResolver,
×
UNCOV
74
            $this->fieldsBuilderLocatorProphecy->reveal(),
×
UNCOV
75
            new Pagination()
×
UNCOV
76
        );
×
77
    }
78

79
    public function testGetResourceObjectType(): void
80
    {
81
        $resourceMetadataCollection = new ResourceMetadataCollection(\stdClass::class, [
×
82
            (new ApiResource())->withGraphQlOperations(['collection_query' => new QueryCollection()]),
×
83
        ]);
×
84
        $this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
×
UNCOV
85
        $this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
86
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
87
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
88

89
        $operation = (new Query())->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
90
        /** @var ObjectType $resourceObjectType */
91
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadataCollection, $operation, null, ['input' => false]);
×
92
        $this->assertSame('shortName', $resourceObjectType->name);
×
93
        $this->assertSame('description', $resourceObjectType->description);
×
94
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
UNCOV
95
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
96
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
97

98
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
99
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, false, 0, null)->shouldBeCalled();
×
UNCOV
100
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
UNCOV
101
        $resourceObjectType->config['fields']();
×
102
    }
103

104
    public function testGetResourceObjectTypeOutputClass(): void
105
    {
106
        $resourceMetadataCollection = new ResourceMetadataCollection(\stdClass::class, [
×
107
            (new ApiResource())->withGraphQlOperations(['collection_query' => new QueryCollection()]),
×
108
        ]);
×
109
        $this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
×
110
        $this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
111
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
112
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
113

UNCOV
114
        $operation = (new Query())->withShortName('shortName')->withDescription('description')->withOutput(['class' => 'outputClass']);
×
115
        /** @var ObjectType $resourceObjectType */
116
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadataCollection, $operation, null, ['input' => false]);
×
117
        $this->assertSame('shortName', $resourceObjectType->name);
×
118
        $this->assertSame('description', $resourceObjectType->description);
×
119
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
120
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
UNCOV
121
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
122

123
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
124
        $fieldsBuilderProphecy->getResourceObjectTypeFields('outputClass', $operation, false, 0, ['class' => 'outputClass'])->shouldBeCalled();
×
125
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
UNCOV
126
        $resourceObjectType->config['fields']();
×
127
    }
128

129
    #[DataProvider('resourceObjectTypeQuerySerializationGroupsProvider')]
130
    public function testGetResourceObjectTypeQuerySerializationGroups(string $itemSerializationGroup, string $collectionSerializationGroup, Operation $operation, string $shortName): void
131
    {
132
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([
×
133
            'item_query' => (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => [$itemSerializationGroup]]),
×
134
            'collection_query' => (new QueryCollection())->withShortName('shortName')->withNormalizationContext(['groups' => [$collectionSerializationGroup]]),
×
135
        ])]);
×
136
        $this->typesContainerProphecy->has($shortName)->shouldBeCalled()->willReturn(false);
×
137
        $this->typesContainerProphecy->set($shortName, Argument::type(ObjectType::class))->shouldBeCalled();
×
138
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
139
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
140

141
        /** @var ObjectType $resourceObjectType */
142
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false]);
×
UNCOV
143
        $this->assertSame($shortName, $resourceObjectType->name);
×
144
    }
145

146
    public static function resourceObjectTypeQuerySerializationGroupsProvider(): array
147
    {
148
        return [
×
149
            'same serialization groups for item_query and collection_query' => [
×
150
                'group',
×
151
                'group',
×
152
                (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => ['group']]),
×
153
                'shortName',
×
154
            ],
×
155
            'different serialization groups for item_query and collection_query when using item_query' => [
×
156
                'item_group',
×
157
                'collection_group',
×
158
                (new Query())->withShortName('shortName')->withNormalizationContext(['groups' => ['item_group']]),
×
159
                'shortNameItem',
×
160
            ],
×
161
            'different serialization groups for item_query and collection_query when using collection_query' => [
×
162
                'item_group',
×
163
                'collection_group',
×
164
                (new QueryCollection())->withName('collection_query')->withShortName('shortName')->withNormalizationContext(['groups' => ['collection_group']]),
×
165
                'shortNameCollection',
×
166
            ],
×
UNCOV
167
        ];
×
168
    }
169

170
    public function testGetResourceObjectTypeInput(): void
171
    {
172
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, []);
×
173
        $this->typesContainerProphecy->has('customShortNameInput')->shouldBeCalled()->willReturn(false);
×
174
        $this->typesContainerProphecy->set('customShortNameInput', Argument::type(InputObjectType::class))->shouldBeCalled();
×
175
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
176
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
177

178
        $operation = (new Mutation())->withName('custom')->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
179
        /** @var NonNull $resourceObjectType */
180
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => true]);
×
181
        /** @var InputObjectType $wrappedType */
182
        $wrappedType = $resourceObjectType->getWrappedType();
×
183
        $this->assertInstanceOf(InputObjectType::class, $wrappedType);
×
184
        $this->assertSame('customShortNameInput', $wrappedType->name);
×
185
        $this->assertSame('description', $wrappedType->description);
×
186
        $this->assertArrayHasKey('fields', $wrappedType->config);
×
187

188
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
189
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, true, 0, null)->shouldBeCalled();
×
190
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
191
        $wrappedType->config['fields']();
×
192
    }
193

194
    public function testGetResourceObjectTypeNestedInput(): void
195
    {
196
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, []);
×
197
        $this->typesContainerProphecy->has('customShortNameNestedInput')->shouldBeCalled()->willReturn(false);
×
198
        $this->typesContainerProphecy->set('customShortNameNestedInput', Argument::type(InputObjectType::class))->shouldBeCalled();
×
199
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
200
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
201

UNCOV
202
        $operation = (new Mutation())->withName('custom')->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
203
        /** @var NonNull $resourceObjectType */
UNCOV
204
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => true, 'wrapped' => false, 'depth' => 1]);
×
205
        /** @var InputObjectType $wrappedType */
UNCOV
206
        $wrappedType = $resourceObjectType->getWrappedType();
×
207
        $this->assertInstanceOf(InputObjectType::class, $wrappedType);
×
208
        $this->assertSame('customShortNameNestedInput', $wrappedType->name);
×
209
        $this->assertSame('description', $wrappedType->description);
×
210
        $this->assertArrayHasKey('fields', $wrappedType->config);
×
211

UNCOV
212
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
213
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, true, 1, null)->shouldBeCalled();
×
214
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
215
        $wrappedType->config['fields']();
×
216
    }
217

218
    public function testGetResourceObjectTypeNestedInputNullable(): void
219
    {
UNCOV
220
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, []);
×
221
        $this->typesContainerProphecy->has('customShortNameNullableNestedInput')->shouldBeCalled()->willReturn(false);
×
222
        $this->typesContainerProphecy->set('customShortNameNullableNestedInput', Argument::type(InputObjectType::class))->shouldBeCalled();
×
223
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
224
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
225

UNCOV
226
        $operation = (new Mutation())->withName('custom')->withShortName('shortNameNullable')->withDescription('description nullable')->withClass(\stdClass::class);
×
UNCOV
227
        $propertyMetadata = (new ApiProperty())->withRequired(false);
×
228
        /** @var InputObjectType $resourceObjectType */
UNCOV
229
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, $propertyMetadata, [
×
230
            'input' => true,
×
UNCOV
231
            'wrapped' => false,
×
232
            'depth' => 1,
×
233
        ]);
×
234

235
        $this->assertInstanceOf(InputObjectType::class, $resourceObjectType);
×
236
        $this->assertSame('customShortNameNullableNestedInput', $resourceObjectType->name);
×
UNCOV
237
        $this->assertSame('description nullable', $resourceObjectType->description);
×
238
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
239

240
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
241
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, true, 1, null)->shouldBeCalled();
×
UNCOV
242
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
243
        $resourceObjectType->config['fields']();
×
244
    }
245

246
    public function testGetResourceObjectTypeCustomMutationInputArgs(): void
247
    {
UNCOV
248
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, []);
×
UNCOV
249
        $this->typesContainerProphecy->has('customShortNameInput')->shouldBeCalled()->willReturn(false);
×
UNCOV
250
        $this->typesContainerProphecy->set('customShortNameInput', Argument::type(InputObjectType::class))->shouldBeCalled();
×
251
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
252
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
253

254
        $operation = (new Mutation())->withArgs([])->withName('custom')->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
255
        /** @var NonNull $resourceObjectType */
UNCOV
256
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => true]);
×
257
        /** @var InputObjectType $wrappedType */
258
        $wrappedType = $resourceObjectType->getWrappedType();
×
UNCOV
259
        $this->assertInstanceOf(InputObjectType::class, $wrappedType);
×
260
        $this->assertSame('customShortNameInput', $wrappedType->name);
×
UNCOV
261
        $this->assertSame('description', $wrappedType->description);
×
262
        $this->assertArrayHasKey('fields', $wrappedType->config);
×
263

264
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
265
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, true, 0, null)
×
266
            ->shouldBeCalled()->willReturn(['clientMutationId' => GraphQLType::string()]);
×
UNCOV
267
        $fieldsBuilderProphecy->resolveResourceArgs([], $operation)->shouldBeCalled();
×
268
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
269
        $wrappedType->config['fields']();
×
270
    }
271

272
    public function testGetResourceObjectTypeMutation(): void
273
    {
UNCOV
274
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([
×
UNCOV
275
            'create' => (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description'),
×
UNCOV
276
            'item_query' => (new Query())->withShortName('shortName')->withDescription('description'),
×
UNCOV
277
            'collection_query' => new QueryCollection(),
×
278
        ])]);
×
279
        $this->typesContainerProphecy->has('createShortNamePayload')->shouldBeCalled()->willReturn(false);
×
280
        $this->typesContainerProphecy->set('createShortNamePayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
281
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
282
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
283

284
        $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
285
        /** @var ObjectType $resourceObjectType */
286
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false]);
×
UNCOV
287
        $this->assertSame('createShortNamePayload', $resourceObjectType->name);
×
UNCOV
288
        $this->assertSame('description', $resourceObjectType->description);
×
289
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
UNCOV
290
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
291
        $this->assertEquals([], $resourceObjectType->config['interfaces']);
×
292
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
293

294
        // Recursive call (not using wrapped type)
295
        $this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
×
296
        $this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
×
297

UNCOV
298
        $fieldsType = $resourceObjectType->config['fields']();
×
UNCOV
299
        $this->assertArrayHasKey('shortName', $fieldsType);
×
300
        $this->assertArrayHasKey('clientMutationId', $fieldsType);
×
301
        $this->assertSame(GraphQLType::string(), $fieldsType['clientMutationId']);
×
302
    }
303

304
    public function testGetResourceObjectTypeMutationWrappedType(): void
305
    {
306
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([
×
UNCOV
307
            'item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['item_query']])->withClass(\stdClass::class),
×
UNCOV
308
            'create' => (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['create']])->withClass(\stdClass::class),
×
UNCOV
309
        ])]);
×
UNCOV
310
        $this->typesContainerProphecy->has('createShortNamePayload')->shouldBeCalled()->willReturn(false);
×
311
        $this->typesContainerProphecy->set('createShortNamePayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
312
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
313
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
314

315
        $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['create']])->withClass(\stdClass::class);
×
316
        /** @var ObjectType $resourceObjectType */
317
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false]);
×
318
        $this->assertSame('createShortNamePayload', $resourceObjectType->name);
×
UNCOV
319
        $this->assertSame('description', $resourceObjectType->description);
×
UNCOV
320
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
321
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
UNCOV
322
        $this->assertEquals([], $resourceObjectType->config['interfaces']);
×
323
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
324

325
        // Recursive call (using wrapped type)
326
        $this->typesContainerProphecy->has('createShortNamePayloadData')->shouldBeCalled()->willReturn(false);
×
327
        $this->typesContainerProphecy->set('createShortNamePayloadData', Argument::type(ObjectType::class))->shouldBeCalled();
×
328

329
        $fieldsType = $resourceObjectType->config['fields']();
×
UNCOV
330
        $this->assertArrayHasKey('shortName', $fieldsType);
×
UNCOV
331
        $this->assertArrayHasKey('clientMutationId', $fieldsType);
×
332
        $this->assertSame(GraphQLType::string(), $fieldsType['clientMutationId']);
×
333

334
        /** @var ObjectType $wrappedType */
335
        $wrappedType = $fieldsType['shortName'];
×
336
        $this->assertSame('createShortNamePayloadData', $wrappedType->name);
×
337
        $this->assertSame('description', $wrappedType->description);
×
338
        $this->assertSame($this->defaultFieldResolver, $wrappedType->resolveFieldFn);
×
UNCOV
339
        $this->assertArrayHasKey('interfaces', $wrappedType->config);
×
UNCOV
340
        $this->assertArrayHasKey('fields', $wrappedType->config);
×
341

342
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
343
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, false, 0, null)->shouldBeCalled();
×
344
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
345
        $wrappedType->config['fields']();
×
346
    }
347

348
    public function testGetResourceObjectTypeMutationNested(): void
349
    {
350
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, []);
×
351
        $this->typesContainerProphecy->has('createShortNameNestedPayload')->shouldBeCalled()->willReturn(false);
×
UNCOV
352
        $this->typesContainerProphecy->set('createShortNameNestedPayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
353
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
354
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
355

356
        $operation = (new Mutation())->withName('create')->withShortName('shortName')->withDescription('description')->withClass(\stdClass::class);
×
357
        /** @var ObjectType $resourceObjectType */
358
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false, 'wrapped' => false, 'depth' => 1]);
×
359
        $this->assertSame('createShortNameNestedPayload', $resourceObjectType->name);
×
360
        $this->assertSame('description', $resourceObjectType->description);
×
UNCOV
361
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
UNCOV
362
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
363
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
364

365
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
366
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, false, 1, null)->shouldBeCalled();
×
367
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
368
        $resourceObjectType->config['fields']();
×
369
    }
370

371
    public function testGetResourceObjectTypeSubscription(): void
372
    {
373
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([
×
374
            'update' => (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true),
×
375
            'item_query' => (new Query())->withShortName('shortName')->withDescription('description'),
×
UNCOV
376
            'collection_query' => new QueryCollection(),
×
UNCOV
377
        ])]);
×
UNCOV
378
        $this->typesContainerProphecy->has('updateShortNameSubscriptionPayload')->shouldBeCalled()->willReturn(false);
×
UNCOV
379
        $this->typesContainerProphecy->set('updateShortNameSubscriptionPayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
380
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
381
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
382

383
        $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true)->withClass(\stdClass::class);
×
384
        /** @var ObjectType $resourceObjectType */
385
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false]);
×
386
        $this->assertSame('updateShortNameSubscriptionPayload', $resourceObjectType->name);
×
387
        $this->assertSame('description', $resourceObjectType->description);
×
388
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
UNCOV
389
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
UNCOV
390
        $this->assertEquals([], $resourceObjectType->config['interfaces']);
×
391
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
392

393
        // Recursive call (not using wrapped type)
394
        $this->typesContainerProphecy->has('shortName')->shouldBeCalled()->willReturn(false);
×
395
        $this->typesContainerProphecy->set('shortName', Argument::type(ObjectType::class))->shouldBeCalled();
×
396

397
        $fieldsType = $resourceObjectType->config['fields']();
×
398
        $this->assertArrayHasKey('shortName', $fieldsType);
×
399
        $this->assertArrayHasKey('clientSubscriptionId', $fieldsType);
×
UNCOV
400
        $this->assertArrayHasKey('mercureUrl', $fieldsType);
×
UNCOV
401
        $this->assertSame(GraphQLType::string(), $fieldsType['clientSubscriptionId']);
×
402
        $this->assertSame(GraphQLType::string(), $fieldsType['mercureUrl']);
×
403
    }
404

405
    public function testGetResourceObjectTypeSubscriptionWrappedType(): void
406
    {
407
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([
×
408
            'item_query' => (new Query())->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['item_query']])->withClass(\stdClass::class),
×
409
            'update' => (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['update']])->withClass(\stdClass::class),
×
410
        ])]);
×
UNCOV
411
        $this->typesContainerProphecy->has('updateShortNameSubscriptionPayload')->shouldBeCalled()->willReturn(false);
×
UNCOV
412
        $this->typesContainerProphecy->set('updateShortNameSubscriptionPayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
413
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
414
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
415

416
        $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withNormalizationContext(['groups' => ['update']])->withClass(\stdClass::class);
×
417
        /** @var ObjectType $resourceObjectType */
418
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false]);
×
419
        $this->assertSame('updateShortNameSubscriptionPayload', $resourceObjectType->name);
×
420
        $this->assertSame('description', $resourceObjectType->description);
×
421
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
422
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
UNCOV
423
        $this->assertEquals([], $resourceObjectType->config['interfaces']);
×
UNCOV
424
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
425

426
        // Recursive call (using wrapped type)
427
        $this->typesContainerProphecy->has('updateShortNameSubscriptionPayloadData')->shouldBeCalled()->willReturn(false);
×
428
        $this->typesContainerProphecy->set('updateShortNameSubscriptionPayloadData', Argument::type(ObjectType::class))->shouldBeCalled();
×
429

430
        $fieldsType = $resourceObjectType->config['fields']();
×
431
        $this->assertArrayHasKey('shortName', $fieldsType);
×
432
        $this->assertArrayHasKey('clientSubscriptionId', $fieldsType);
×
433
        $this->assertArrayNotHasKey('mercureUrl', $fieldsType);
×
UNCOV
434
        $this->assertSame(GraphQLType::string(), $fieldsType['clientSubscriptionId']);
×
435

436
        /** @var ObjectType $wrappedType */
437
        $wrappedType = $fieldsType['shortName'];
×
UNCOV
438
        $this->assertSame('updateShortNameSubscriptionPayloadData', $wrappedType->name);
×
439
        $this->assertSame('description', $wrappedType->description);
×
440
        $this->assertSame($this->defaultFieldResolver, $wrappedType->resolveFieldFn);
×
441
        $this->assertArrayHasKey('interfaces', $wrappedType->config);
×
442
        $this->assertArrayHasKey('fields', $wrappedType->config);
×
443

UNCOV
444
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
UNCOV
445
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, false, 0, null)->shouldBeCalled();
×
446
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
447
        $wrappedType->config['fields']();
×
448
    }
449

450
    public function testGetResourceObjectTypeSubscriptionNested(): void
451
    {
UNCOV
452
        $resourceMetadata = new ResourceMetadataCollection(\stdClass::class, [(new ApiResource())->withGraphQlOperations([])]);
×
453
        $this->typesContainerProphecy->has('updateShortNameSubscriptionNestedPayload')->shouldBeCalled()->willReturn(false);
×
454
        $this->typesContainerProphecy->set('updateShortNameSubscriptionNestedPayload', Argument::type(ObjectType::class))->shouldBeCalled();
×
455
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
456
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
457

UNCOV
458
        $operation = (new Subscription())->withName('update')->withShortName('shortName')->withDescription('description')->withMercure(true)->withClass(\stdClass::class);
×
459
        /** @var ObjectType $resourceObjectType */
UNCOV
460
        $resourceObjectType = $this->typeBuilder->getResourceObjectType($resourceMetadata, $operation, null, ['input' => false, 'wrapped' => false, 'depth' => 1]);
×
461
        $this->assertSame('updateShortNameSubscriptionNestedPayload', $resourceObjectType->name);
×
462
        $this->assertSame('description', $resourceObjectType->description);
×
463
        $this->assertSame($this->defaultFieldResolver, $resourceObjectType->resolveFieldFn);
×
464
        $this->assertArrayHasKey('interfaces', $resourceObjectType->config);
×
465
        $this->assertArrayHasKey('fields', $resourceObjectType->config);
×
466

UNCOV
467
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
468
        $fieldsBuilderProphecy->getResourceObjectTypeFields(\stdClass::class, $operation, false, 1, null)->shouldBeCalled();
×
UNCOV
469
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->shouldBeCalled()->willReturn($fieldsBuilderProphecy->reveal());
×
470
        $resourceObjectType->config['fields']();
×
471
    }
472

473
    public function testGetNodeInterface(): void
474
    {
475
        $this->typesContainerProphecy->has('Node')->shouldBeCalled()->willReturn(false);
×
UNCOV
476
        $this->typesContainerProphecy->set('Node', Argument::type(InterfaceType::class))->shouldBeCalled();
×
477

478
        $nodeInterface = $this->typeBuilder->getNodeInterface();
×
479
        $this->assertSame('Node', $nodeInterface->name);
×
480
        $this->assertSame('A node, according to the Relay specification.', $nodeInterface->description);
×
UNCOV
481
        $this->assertArrayHasKey('id', $nodeInterface->getFields());
×
482

UNCOV
483
        $this->assertNull($nodeInterface->resolveType([], [], $this->prophesize(ResolveInfo::class)->reveal()));
×
484

485
        $this->typesContainerProphecy->has('Dummy')->shouldBeCalled()->willReturn(false);
×
486
        $resolvedType = $nodeInterface->resolveType([ItemNormalizer::ITEM_RESOURCE_CLASS_KEY => Dummy::class], [], $this->prophesize(ResolveInfo::class)->reveal());
×
UNCOV
487
        $this->assertNull($resolvedType);
×
488

489
        $this->typesContainerProphecy->has('Dummy')->shouldBeCalled()->willReturn(true);
×
490
        $this->typesContainerProphecy->get('Dummy')->shouldBeCalled()->willReturn(GraphQLType::string());
×
491
        $resolvedType = $nodeInterface->resolveType([ItemNormalizer::ITEM_RESOURCE_CLASS_KEY => Dummy::class], [], $this->prophesize(ResolveInfo::class)->reveal());
×
UNCOV
492
        $this->assertSame(GraphQLType::string(), $resolvedType);
×
493
    }
494

495
    public function testCursorBasedGetPaginatedCollectionType(): void
496
    {
UNCOV
497
        $operation = (new Query())->withPaginationType('cursor');
×
498
        $this->typesContainerProphecy->has('StringCursorConnection')->shouldBeCalled()->willReturn(false);
×
499
        $this->typesContainerProphecy->set('StringCursorConnection', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
500
        $this->typesContainerProphecy->set('StringEdge', Argument::type(ObjectType::class))->shouldBeCalled();
×
501
        $this->typesContainerProphecy->set('StringPageInfo', Argument::type(ObjectType::class))->shouldBeCalled();
×
502

503
        /** @var ObjectType $resourcePaginatedCollectionType */
UNCOV
504
        $resourcePaginatedCollectionType = $this->typeBuilder->getPaginatedCollectionType(GraphQLType::string(), $operation);
×
UNCOV
505
        $this->assertSame('StringCursorConnection', $resourcePaginatedCollectionType->name);
×
UNCOV
506
        $this->assertSame('Cursor connection for String.', $resourcePaginatedCollectionType->description);
×
507

508
        $resourcePaginatedCollectionTypeFields = $resourcePaginatedCollectionType->getFields();
×
509
        $this->assertArrayHasKey('edges', $resourcePaginatedCollectionTypeFields);
×
510
        $this->assertArrayHasKey('pageInfo', $resourcePaginatedCollectionTypeFields);
×
511
        $this->assertArrayHasKey('totalCount', $resourcePaginatedCollectionTypeFields);
×
512

513
        /** @var ListOfType $edgesType */
UNCOV
514
        $edgesType = $resourcePaginatedCollectionTypeFields['edges']->getType();
×
515
        /** @var ObjectType $wrappedType */
516
        $wrappedType = $edgesType->getWrappedType();
×
517
        $this->assertSame('StringEdge', $wrappedType->name);
×
UNCOV
518
        $this->assertSame('Edge of String.', $wrappedType->description);
×
519
        $edgeObjectTypeFields = $wrappedType->getFields();
×
520
        $this->assertArrayHasKey('node', $edgeObjectTypeFields);
×
521
        $this->assertArrayHasKey('cursor', $edgeObjectTypeFields);
×
522
        $this->assertSame(GraphQLType::string(), $edgeObjectTypeFields['node']->getType());
×
UNCOV
523
        $this->assertInstanceOf(NonNull::class, $edgeObjectTypeFields['cursor']->getType());
×
UNCOV
524
        $this->assertSame(GraphQLType::string(), $edgeObjectTypeFields['cursor']->getType()->getWrappedType());
×
525

526
        /** @var NonNull $pageInfoType */
527
        $pageInfoType = $resourcePaginatedCollectionTypeFields['pageInfo']->getType();
×
528
        /** @var ObjectType $wrappedType */
529
        $wrappedType = $pageInfoType->getWrappedType();
×
530
        $this->assertSame('StringPageInfo', $wrappedType->name);
×
531
        $this->assertSame('Information about the current page.', $wrappedType->description);
×
532
        $pageInfoObjectTypeFields = $wrappedType->getFields();
×
533
        $this->assertArrayHasKey('endCursor', $pageInfoObjectTypeFields);
×
534
        $this->assertArrayHasKey('startCursor', $pageInfoObjectTypeFields);
×
535
        $this->assertArrayHasKey('hasNextPage', $pageInfoObjectTypeFields);
×
UNCOV
536
        $this->assertArrayHasKey('hasPreviousPage', $pageInfoObjectTypeFields);
×
UNCOV
537
        $this->assertSame(GraphQLType::string(), $pageInfoObjectTypeFields['endCursor']->getType());
×
538
        $this->assertSame(GraphQLType::string(), $pageInfoObjectTypeFields['startCursor']->getType());
×
UNCOV
539
        $this->assertInstanceOf(NonNull::class, $pageInfoObjectTypeFields['hasNextPage']->getType());
×
540
        $this->assertSame(GraphQLType::boolean(), $pageInfoObjectTypeFields['hasNextPage']->getType()->getWrappedType());
×
541
        $this->assertInstanceOf(NonNull::class, $pageInfoObjectTypeFields['hasPreviousPage']->getType());
×
542
        $this->assertSame(GraphQLType::boolean(), $pageInfoObjectTypeFields['hasPreviousPage']->getType()->getWrappedType());
×
543

544
        /** @var NonNull $totalCountType */
545
        $totalCountType = $resourcePaginatedCollectionTypeFields['totalCount']->getType();
×
546
        $this->assertInstanceOf(NonNull::class, $totalCountType);
×
547
        $this->assertSame(GraphQLType::int(), $totalCountType->getWrappedType());
×
548
    }
549

550
    public function testPageBasedGetPaginatedCollectionType(): void
551
    {
552
        $operation = (new Query())->withPaginationType('page');
×
553
        $this->typesContainerProphecy->has('StringPageConnection')->shouldBeCalled()->willReturn(false);
×
UNCOV
554
        $this->typesContainerProphecy->set('StringPageConnection', Argument::type(ObjectType::class))->shouldBeCalled();
×
UNCOV
555
        $this->typesContainerProphecy->set('StringPaginationInfo', Argument::type(ObjectType::class))->shouldBeCalled();
×
556

557
        /** @var ObjectType $resourcePaginatedCollectionType */
558
        $resourcePaginatedCollectionType = $this->typeBuilder->getPaginatedCollectionType(GraphQLType::string(), $operation);
×
UNCOV
559
        $this->assertSame('StringPageConnection', $resourcePaginatedCollectionType->name);
×
UNCOV
560
        $this->assertSame('Page connection for String.', $resourcePaginatedCollectionType->description);
×
561

UNCOV
562
        $resourcePaginatedCollectionTypeFields = $resourcePaginatedCollectionType->getFields();
×
UNCOV
563
        $this->assertArrayHasKey('collection', $resourcePaginatedCollectionTypeFields);
×
564
        $this->assertArrayHasKey('paginationInfo', $resourcePaginatedCollectionTypeFields);
×
565

566
        /** @var NonNull $paginationInfoType */
567
        $paginationInfoType = $resourcePaginatedCollectionTypeFields['paginationInfo']->getType();
×
568
        /** @var ObjectType $wrappedType */
UNCOV
569
        $wrappedType = $paginationInfoType->getWrappedType();
×
570
        $this->assertSame('StringPaginationInfo', $wrappedType->name);
×
571
        $this->assertSame('Information about the pagination.', $wrappedType->description);
×
572
        $paginationInfoObjectTypeFields = $wrappedType->getFields();
×
UNCOV
573
        $this->assertArrayHasKey('itemsPerPage', $paginationInfoObjectTypeFields);
×
574
        $this->assertArrayHasKey('lastPage', $paginationInfoObjectTypeFields);
×
575
        $this->assertArrayHasKey('totalCount', $paginationInfoObjectTypeFields);
×
576
        $this->assertInstanceOf(NonNull::class, $paginationInfoObjectTypeFields['itemsPerPage']->getType());
×
UNCOV
577
        $this->assertSame(GraphQLType::int(), $paginationInfoObjectTypeFields['itemsPerPage']->getType()->getWrappedType());
×
UNCOV
578
        $this->assertInstanceOf(NonNull::class, $paginationInfoObjectTypeFields['lastPage']->getType());
×
579
        $this->assertSame(GraphQLType::int(), $paginationInfoObjectTypeFields['lastPage']->getType()->getWrappedType());
×
UNCOV
580
        $this->assertInstanceOf(NonNull::class, $paginationInfoObjectTypeFields['totalCount']->getType());
×
581
        $this->assertSame(GraphQLType::int(), $paginationInfoObjectTypeFields['totalCount']->getType()->getWrappedType());
×
582
    }
583

584
    public function testGetEnumType(): void
585
    {
586
        $enumClass = GamePlayMode::class;
×
587
        $enumName = 'GamePlayMode';
×
588
        $enumDescription = 'GamePlayMode description';
×
589
        $operation = (new Operation())
×
590
            ->withClass($enumClass)
×
591
            ->withShortName($enumName)
×
592
            ->withDescription('GamePlayMode description');
×
593

UNCOV
594
        $this->typesContainerProphecy->has('GamePlayMode')->shouldBeCalled()->willReturn(false);
×
UNCOV
595
        $this->typesContainerProphecy->set('GamePlayMode', Argument::type(EnumType::class))->shouldBeCalled();
×
UNCOV
596
        $fieldsBuilderProphecy = $this->prophesize(FieldsBuilderEnumInterface::class);
×
UNCOV
597
        $enumValues = [
×
598
            GamePlayMode::CO_OP->name => ['value' => GamePlayMode::CO_OP->value],
×
599
            GamePlayMode::MULTI_PLAYER->name => ['value' => GamePlayMode::MULTI_PLAYER->value],
×
600
            GamePlayMode::SINGLE_PLAYER->name => ['value' => GamePlayMode::SINGLE_PLAYER->value, 'description' => 'Which is played by a lone player.'],
×
UNCOV
601
        ];
×
602
        $fieldsBuilderProphecy->getEnumFields($enumClass)->willReturn($enumValues);
×
603
        $this->fieldsBuilderLocatorProphecy->get('api_platform.graphql.fields_builder')->willReturn($fieldsBuilderProphecy->reveal());
×
604

605
        self::assertEquals(new EnumType([
×
UNCOV
606
            'name' => 'GamePlayMode',
×
607
            'description' => $enumDescription,
×
608
            'values' => $enumValues,
×
609
        ]), $this->typeBuilder->getEnumType($operation));
×
610
    }
611

612
    #[DataProvider('legacyTypesProvider')]
613
    #[IgnoreDeprecations]
614
    public function testIsCollectionLegacy(LegacyType $type, bool $expectedIsCollection): void
615
    {
616
        $this->expectUserDeprecationMessage('Since api-platform/graphql 4.2: The "ApiPlatform\GraphQl\Type\TypeBuilder::isCollection()" method is deprecated and will be removed.');
×
UNCOV
617
        $this->assertSame($expectedIsCollection, $this->typeBuilder->isCollection($type));
×
618
    }
619

620
    public static function legacyTypesProvider(): array
621
    {
622
        return [
×
UNCOV
623
            [new LegacyType(LegacyType::BUILTIN_TYPE_BOOL), false],
×
UNCOV
624
            [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT), false],
×
UNCOV
625
            [new LegacyType(LegacyType::BUILTIN_TYPE_RESOURCE, false, null, false), false],
×
UNCOV
626
            [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, null, true), false],
×
UNCOV
627
            [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true), false],
×
628
            [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, null, new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT)), false],
×
UNCOV
629
            [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'className', true), false],
×
UNCOV
630
            [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, null, true, null, new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'className')), true],
×
UNCOV
631
            [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, false, null, true, null, new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, 'className')), true],
×
UNCOV
632
        ];
×
633
    }
634

635
    public static function typesProvider(): array
636
    {
637
        return [
×
638
            [Type::bool(), false],
×
639
            [Type::object(), false],
×
640
            [Type::resource(), false],
×
641
            [Type::collection(Type::object(\Stringable::class)), false],
×
642
            [Type::array(), false],
×
643
            [Type::array(Type::object()), false],
×
UNCOV
644
            [Type::collection(Type::object(\Traversable::class), Type::object(\Stringable::class)), true],
×
UNCOV
645
            [Type::array(Type::object(\Stringable::class)), true],
×
UNCOV
646
        ];
×
647
    }
648
}
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