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

api-platform / core / 14516256486

17 Apr 2025 01:00PM UTC coverage: 6.974% (-1.6%) from 8.532%
14516256486

push

github

web-flow
feat(hydra): use `TypeInfo`'s `Type` (#7099)

Co-authored-by: Mathias Arlaud <mathias.arlaud@gmail.com>

40 of 95 new or added lines in 2 files covered. (42.11%)

399 existing lines in 8 files now uncovered.

11059 of 158579 relevant lines covered (6.97%)

6.2 hits per line

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

0.0
/tests/Hal/Serializer/ItemNormalizerTest.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\Tests\Hal\Serializer;
15

16
use ApiPlatform\Hal\Serializer\ItemNormalizer;
17
use ApiPlatform\Metadata\ApiProperty;
18
use ApiPlatform\Metadata\IriConverterInterface;
19
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
20
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
21
use ApiPlatform\Metadata\Property\PropertyNameCollection;
22
use ApiPlatform\Metadata\ResourceClassResolverInterface;
23
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\ActivableInterface;
24
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\Author;
25
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\Book;
26
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\Library;
27
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue5452\TimestampableInterface;
28
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
29
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\MaxDepthDummy;
30
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
31
use PHPUnit\Framework\TestCase;
32
use Prophecy\Argument;
33
use Prophecy\PhpUnit\ProphecyTrait;
34
use Symfony\Component\Serializer\Exception\LogicException;
35
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
36
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
37
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
38
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
39
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
40
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
41
use Symfony\Component\Serializer\Serializer;
42
use Symfony\Component\Serializer\SerializerInterface;
43
use Symfony\Component\TypeInfo\Type;
44

45
/**
46
 * @author Kévin Dunglas <dunglas@gmail.com>
47
 */
48
class ItemNormalizerTest extends TestCase
49
{
50
    use ProphecyTrait;
51

52
    public function testDoesNotSupportDenormalization(): void
53
    {
54
        $this->expectException(LogicException::class);
×
55
        $this->expectExceptionMessage('jsonhal is a read-only format.');
×
56

57
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
58
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
59
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
60
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
61
        $nameConverter = $this->prophesize(NameConverterInterface::class);
×
62

63
        $normalizer = new ItemNormalizer(
×
64
            $propertyNameCollectionFactoryProphecy->reveal(),
×
65
            $propertyMetadataFactoryProphecy->reveal(),
×
66
            $iriConverterProphecy->reveal(),
×
67
            $resourceClassResolverProphecy->reveal(),
×
68
            null,
×
69
            $nameConverter->reveal()
×
70
        );
×
71

72
        $this->assertFalse($normalizer->supportsDenormalization('foo', ItemNormalizer::FORMAT));
×
73
        $normalizer->denormalize(['foo'], 'Foo');
×
74
    }
75

76
    #[\PHPUnit\Framework\Attributes\Group('legacy')]
77
    public function testSupportsNormalization(): void
78
    {
79
        $std = new \stdClass();
×
80
        $dummy = new Dummy();
×
81
        $dummy->setDescription('hello');
×
82

83
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
84
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
85
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
86

87
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
88
        $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
×
89
        $resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false);
×
90

91
        $nameConverter = $this->prophesize(NameConverterInterface::class);
×
92

93
        $normalizer = new ItemNormalizer(
×
94
            $propertyNameCollectionFactoryProphecy->reveal(),
×
95
            $propertyMetadataFactoryProphecy->reveal(),
×
96
            $iriConverterProphecy->reveal(),
×
97
            $resourceClassResolverProphecy->reveal(),
×
98
            null,
×
99
            $nameConverter->reveal()
×
100
        );
×
101

102
        $this->assertTrue($normalizer->supportsNormalization($dummy, $normalizer::FORMAT));
×
103
        $this->assertFalse($normalizer->supportsNormalization($dummy, 'xml'));
×
104
        $this->assertFalse($normalizer->supportsNormalization($std, $normalizer::FORMAT));
×
105
        $this->assertEmpty($normalizer->getSupportedTypes('xml'));
×
106
        $this->assertSame(['object' => true], $normalizer->getSupportedTypes($normalizer::FORMAT));
×
107
    }
108

109
    public function testNormalize(): void
110
    {
111
        $relatedDummy = new RelatedDummy();
×
112
        $dummy = new Dummy();
×
113
        $dummy->setName('hello');
×
114
        $dummy->setRelatedDummy($relatedDummy);
×
115

116
        $propertyNameCollection = new PropertyNameCollection(['name', 'relatedDummy']);
×
117
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
118
        $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection);
×
119

120
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
121
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn(
×
122
            (new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)
×
123
        );
×
124
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn(
×
125
            (new ApiProperty())->withNativeType(Type::object(RelatedDummy::class))->withDescription('')->withReadable(true)->withWritable(false)->withWritableLink(false)
×
126
        );
×
127

128
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
129
        $iriConverterProphecy->getIriFromResource($dummy, Argument::cetera())->willReturn('/dummies/1');
×
130
        $iriConverterProphecy->getIriFromResource($relatedDummy, Argument::cetera())->willReturn('/related-dummies/2');
×
131

132
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
133
        $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true);
×
134
        $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
×
135
        $resourceClassResolverProphecy->getResourceClass($dummy, null)->willReturn(Dummy::class);
×
136
        $resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
×
137
        $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class);
×
138
        $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class)->willReturn(RelatedDummy::class);
×
139

140
        $serializerProphecy = $this->prophesize(SerializerInterface::class);
×
141
        $serializerProphecy->willImplement(NormalizerInterface::class);
×
142
        $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello');
×
143

144
        $nameConverter = $this->prophesize(NameConverterInterface::class);
×
145
        $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->willReturn('name');
×
146
        $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->willReturn('related_dummy');
×
147

148
        $normalizer = new ItemNormalizer(
×
149
            $propertyNameCollectionFactoryProphecy->reveal(),
×
150
            $propertyMetadataFactoryProphecy->reveal(),
×
151
            $iriConverterProphecy->reveal(),
×
152
            $resourceClassResolverProphecy->reveal(),
×
153
            null,
×
154
            $nameConverter->reveal()
×
155
        );
×
156
        $normalizer->setSerializer($serializerProphecy->reveal());
×
157

158
        $expected = [
×
159
            '_links' => [
×
160
                'self' => [
×
161
                    'href' => '/dummies/1',
×
162
                ],
×
163
                'related_dummy' => [
×
164
                    'href' => '/related-dummies/2',
×
165
                ],
×
166
            ],
×
167
            'name' => 'hello',
×
168
        ];
×
169
        $this->assertEquals($expected, $normalizer->normalize($dummy));
×
170
    }
171

172
    public function testNormalizeWithUnionIntersectTypes(): void
173
    {
174
        $author = new Author(id: 2, name: 'Isaac Asimov');
×
175
        $library = new Library(id: 3, name: 'Le Bâteau Livre');
×
176
        $book = new Book();
×
177
        $book->author = $author;
×
178
        $book->library = $library;
×
179

180
        $propertyNameCollection = new PropertyNameCollection(['author', 'library']);
×
181
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
182
        $propertyNameCollectionFactoryProphecy->create(Book::class, [])->willReturn($propertyNameCollection);
×
183

184
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
185
        $propertyMetadataFactoryProphecy->create(Book::class, 'author', [])->willReturn(
×
186
            (new ApiProperty())->withNativeType(Type::intersection(Type::object(ActivableInterface::class), Type::object(TimestampableInterface::class)))->withReadable(true)
×
187
        );
×
188
        $propertyMetadataFactoryProphecy->create(Book::class, 'library', [])->willReturn(
×
189
            (new ApiProperty())->withNativeType(Type::intersection(Type::object(ActivableInterface::class), Type::object(TimestampableInterface::class)))->withReadable(true)
×
190
        );
×
191

192
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
193
        $iriConverterProphecy->getIriFromResource($book, Argument::cetera())->willReturn('/books/1');
×
194

195
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
196
        $resourceClassResolverProphecy->isResourceClass(Book::class)->willReturn(true);
×
UNCOV
197
        $resourceClassResolverProphecy->isResourceClass(ActivableInterface::class)->willReturn(false);
×
198
        $resourceClassResolverProphecy->isResourceClass(TimestampableInterface::class)->willReturn(false);
×
199
        $resourceClassResolverProphecy->getResourceClass($book, null)->willReturn(Book::class);
×
UNCOV
200
        $resourceClassResolverProphecy->getResourceClass(null, Book::class)->willReturn(Book::class);
×
201

202
        $serializerProphecy = $this->prophesize(SerializerInterface::class);
×
203
        $serializerProphecy->willImplement(NormalizerInterface::class);
×
204

205
        $nameConverter = $this->prophesize(NameConverterInterface::class);
×
206
        $nameConverter->normalize('author', Argument::any(), Argument::any(), Argument::any())->willReturn('author');
×
UNCOV
207
        $nameConverter->normalize('library', Argument::any(), Argument::any(), Argument::any())->willReturn('library');
×
208

209
        $normalizer = new ItemNormalizer(
×
UNCOV
210
            $propertyNameCollectionFactoryProphecy->reveal(),
×
211
            $propertyMetadataFactoryProphecy->reveal(),
×
212
            $iriConverterProphecy->reveal(),
×
213
            $resourceClassResolverProphecy->reveal(),
×
UNCOV
214
            null,
×
215
            $nameConverter->reveal()
×
216
        );
×
217
        $normalizer->setSerializer($serializerProphecy->reveal());
×
218

219
        $expected = [
×
220
            '_links' => [
×
221
                'self' => [
×
222
                    'href' => '/books/1',
×
223
                ],
×
UNCOV
224
            ],
×
225
            'author' => null,
×
226
            'library' => null,
×
227
        ];
×
228
        $this->assertEquals($expected, $normalizer->normalize($book));
×
229
    }
230

231
    public function testNormalizeWithoutCache(): void
232
    {
233
        $relatedDummy = new RelatedDummy();
×
234
        $dummy = new Dummy();
×
UNCOV
235
        $dummy->setName('hello');
×
UNCOV
236
        $dummy->setRelatedDummy($relatedDummy);
×
237

UNCOV
238
        $propertyNameCollection = new PropertyNameCollection(['name', 'relatedDummy']);
×
239
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
240
        $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection);
×
241

242
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
UNCOV
243
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn(
×
244
            (new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)
×
245
        );
×
246
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn(
×
UNCOV
247
            (new ApiProperty())->withNativeType(Type::object(RelatedDummy::class))->withDescription('')->withReadable(true)->withWritable(false)->withReadableLink(false)
×
248
        );
×
249

250
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
251
        $iriConverterProphecy->getIriFromResource($dummy, Argument::cetera())->willReturn('/dummies/1');
×
252
        $iriConverterProphecy->getIriFromResource($relatedDummy, Argument::cetera())->willReturn('/related-dummies/2');
×
253

254
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
UNCOV
255
        $resourceClassResolverProphecy->getResourceClass($dummy, null)->willReturn(Dummy::class);
×
256
        $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class);
×
257
        $resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
×
258
        $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class)->willReturn(RelatedDummy::class);
×
UNCOV
259
        $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true);
×
260
        $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
×
261

262
        $serializerProphecy = $this->prophesize(SerializerInterface::class);
×
263
        $serializerProphecy->willImplement(NormalizerInterface::class);
×
264
        $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello');
×
265

266
        $nameConverter = $this->prophesize(NameConverterInterface::class);
×
UNCOV
267
        $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->willReturn('name');
×
268
        $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->willReturn('related_dummy');
×
269

270
        $normalizer = new ItemNormalizer(
×
UNCOV
271
            $propertyNameCollectionFactoryProphecy->reveal(),
×
272
            $propertyMetadataFactoryProphecy->reveal(),
×
273
            $iriConverterProphecy->reveal(),
×
274
            $resourceClassResolverProphecy->reveal(),
×
UNCOV
275
            null,
×
276
            $nameConverter->reveal()
×
277
        );
×
278
        $normalizer->setSerializer($serializerProphecy->reveal());
×
279

280
        $expected = [
×
281
            '_links' => [
×
282
                'self' => [
×
283
                    'href' => '/dummies/1',
×
284
                ],
×
UNCOV
285
                'related_dummy' => [
×
286
                    'href' => '/related-dummies/2',
×
287
                ],
×
288
            ],
×
289
            'name' => 'hello',
×
290
        ];
×
291
        $this->assertEquals($expected, $normalizer->normalize($dummy, null, ['not_serializable' => function (): void {}]));
×
292
    }
293

294
    public function testMaxDepth(): void
295
    {
296
        $setId = function (MaxDepthDummy $dummy, int $id): void {
×
297
            $prop = new \ReflectionProperty($dummy, 'id');
×
UNCOV
298
            $prop->setAccessible(true);
×
UNCOV
299
            $prop->setValue($dummy, $id);
×
UNCOV
300
        };
×
301

302
        $level1 = new MaxDepthDummy();
×
303
        $setId($level1, 1);
×
304
        $level1->name = 'level 1';
×
305

306
        $level2 = new MaxDepthDummy();
×
UNCOV
307
        $setId($level2, 2);
×
308
        $level2->name = 'level 2';
×
309
        $level1->child = $level2;
×
310

UNCOV
311
        $level3 = new MaxDepthDummy();
×
312
        $setId($level3, 3);
×
313
        $level3->name = 'level 3';
×
314
        $level2->child = $level3;
×
315

UNCOV
316
        $propertyNameCollection = new PropertyNameCollection(['id', 'name', 'child']);
×
317
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
318
        $propertyNameCollectionFactoryProphecy->create(MaxDepthDummy::class, [])->willReturn($propertyNameCollection);
×
319

320
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
UNCOV
321
        $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'id', [])->willReturn(
×
322
            (new ApiProperty())->withNativeType(Type::int())->withDescription('')->withReadable(true)
×
323
        );
×
324
        $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'name', [])->willReturn(
×
UNCOV
325
            (new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)
×
326
        );
×
327
        $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'child', [])->willReturn(
×
328
            (new ApiProperty())->withNativeType(Type::object(MaxDepthDummy::class))->withDescription('')->withReadable(true)->withWritable(false)->withReadableLink(true)
×
329
        );
×
330

331
        $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
×
332
        $iriConverterProphecy->getIriFromResource($level1, Argument::cetera())->willReturn('/max_depth_dummies/1');
×
333
        $iriConverterProphecy->getIriFromResource($level2, Argument::cetera())->willReturn('/max_depth_dummies/2');
×
334
        $iriConverterProphecy->getIriFromResource($level3, Argument::cetera())->willReturn('/max_depth_dummies/3');
×
335

UNCOV
336
        $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
×
337
        $resourceClassResolverProphecy->getResourceClass($level1, null)->willReturn(MaxDepthDummy::class);
×
338
        $resourceClassResolverProphecy->getResourceClass($level1, MaxDepthDummy::class)->willReturn(MaxDepthDummy::class);
×
339
        $resourceClassResolverProphecy->getResourceClass($level2, MaxDepthDummy::class)->willReturn(MaxDepthDummy::class);
×
340
        $resourceClassResolverProphecy->getResourceClass($level3, MaxDepthDummy::class)->willReturn(MaxDepthDummy::class);
×
UNCOV
341
        $resourceClassResolverProphecy->getResourceClass(null, MaxDepthDummy::class)->willReturn(MaxDepthDummy::class);
×
342
        $resourceClassResolverProphecy->isResourceClass(MaxDepthDummy::class)->willReturn(true);
×
343

344
        $normalizer = new ItemNormalizer(
×
345
            $propertyNameCollectionFactoryProphecy->reveal(),
×
346
            $propertyMetadataFactoryProphecy->reveal(),
×
347
            $iriConverterProphecy->reveal(),
×
348
            $resourceClassResolverProphecy->reveal(),
×
UNCOV
349
            null,
×
350
            null,
×
351
            new ClassMetadataFactory(class_exists(AttributeLoader::class) ? new AttributeLoader() : new AnnotationLoader())
×
352
        );
×
353
        $serializer = new Serializer([$normalizer]);
×
354
        $normalizer->setSerializer($serializer);
×
355

356
        $expected = [
×
357
            '_links' => [
×
358
                'self' => [
×
359
                    'href' => '/max_depth_dummies/1',
×
360
                ],
×
UNCOV
361
                'child' => [
×
362
                    'href' => '/max_depth_dummies/2',
×
363
                ],
×
364
            ],
×
365
            '_embedded' => [
×
366
                'child' => [
×
367
                    '_links' => [
×
368
                        'self' => [
×
369
                            'href' => '/max_depth_dummies/2',
×
370
                        ],
×
371
                        'child' => [
×
372
                            'href' => '/max_depth_dummies/3',
×
373
                        ],
×
374
                    ],
×
375
                    '_embedded' => [
×
376
                        'child' => [
×
377
                            '_links' => [
×
378
                                'self' => [
×
379
                                    'href' => '/max_depth_dummies/3',
×
380
                                ],
×
381
                            ],
×
382
                            'id' => 3,
×
383
                            'name' => 'level 3',
×
384
                        ],
×
385
                    ],
×
386
                    'id' => 2,
×
387
                    'name' => 'level 2',
×
388
                ],
×
389
            ],
×
390
            'id' => 1,
×
391
            'name' => 'level 1',
×
392
        ];
×
393

394
        $this->assertEquals($expected, $normalizer->normalize($level1, ItemNormalizer::FORMAT));
×
395
        $this->assertEquals($expected, $normalizer->normalize($level1, ItemNormalizer::FORMAT, [ObjectNormalizer::ENABLE_MAX_DEPTH => false]));
×
396

397
        $expected = [
×
398
            '_links' => [
×
UNCOV
399
                'self' => [
×
400
                    'href' => '/max_depth_dummies/1',
×
401
                ],
×
UNCOV
402
                'child' => [
×
403
                    'href' => '/max_depth_dummies/2',
×
404
                ],
×
405
            ],
×
406
            '_embedded' => [
×
407
                'child' => [
×
408
                    '_links' => [
×
409
                        'self' => [
×
410
                            'href' => '/max_depth_dummies/2',
×
411
                        ],
×
412
                    ],
×
413
                    'id' => 2,
×
414
                    'name' => 'level 2',
×
415
                ],
×
416
            ],
×
417
            'id' => 1,
×
418
            'name' => 'level 1',
×
419
        ];
×
420

421
        $this->assertEquals($expected, $normalizer->normalize($level1, ItemNormalizer::FORMAT, [ObjectNormalizer::ENABLE_MAX_DEPTH => true]));
×
422
    }
423
}
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