Skip to content

Commit 0940691

Browse files
committed
test(svg): refactor factory tests with data providers
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 8e35cde commit 0940691

1 file changed

Lines changed: 104 additions & 167 deletions

File tree

tests/Unit/Pdf/Svg/SvgPdfXObjectFactoryTest.php

Lines changed: 104 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,18 @@ public function testCreateSupportsPolygonAndRectElements(): void
6464
self::assertStringContainsString('20.000000 0.000000 l', $xObject->stream);
6565
}
6666

67-
public function testCreateRejectsInvalidSvgPayloads(): void
68-
{
69-
$factory = new SvgPdfXObjectFactory();
70-
71-
$this->expectException(InvalidArgumentException::class);
72-
$this->expectExceptionMessage('Unable to parse SVG source "/tmp/invalid.svg".');
73-
74-
$factory->create('<html></html>', '/tmp/invalid.svg');
75-
}
76-
77-
public function testCreateRejectsMalformedSvgRootEvenWhenSvgTagExists(): void
78-
{
67+
#[DataProvider('provideInvalidSvgSources')]
68+
public function testCreateRejectsInvalidSvgSources(
69+
string $svg,
70+
string $sourcePath,
71+
string $expectedMessage,
72+
): void {
7973
$factory = new SvgPdfXObjectFactory();
8074

8175
$this->expectException(InvalidArgumentException::class);
82-
$this->expectExceptionMessage('Unable to parse SVG source "/tmp/malformed-root.svg".');
76+
$this->expectExceptionMessage($expectedMessage);
8377

84-
$factory->create('<svg xmlns="http://www.w3.org/2000/svg"><g>', '/tmp/malformed-root.svg');
78+
$factory->create($svg, $sourcePath);
8579
}
8680

8781
#[DataProvider('provideInvalidViewportScenarios')]
@@ -286,26 +280,6 @@ public function testCreateSkipsUnrecognizedShapeElementsGracefully(): void
286280
self::assertStringContainsString('1 0 0 rg', $xObject->stream);
287281
}
288282

289-
public function testCreateWithEmptySvgStringThrows(): void
290-
{
291-
$factory = new SvgPdfXObjectFactory();
292-
293-
$this->expectException(InvalidArgumentException::class);
294-
$this->expectExceptionMessage('Unable to parse SVG source "/tmp/empty.svg".');
295-
296-
$factory->create('', '/tmp/empty.svg');
297-
}
298-
299-
public function testCreateWithNonSvgRootElementThrows(): void
300-
{
301-
$factory = new SvgPdfXObjectFactory();
302-
303-
$this->expectException(InvalidArgumentException::class);
304-
$this->expectExceptionMessage('Unable to parse SVG source "/tmp/wrong-root.svg".');
305-
306-
$factory->create('<?xml version="1.0"?><root></root>', '/tmp/wrong-root.svg');
307-
}
308-
309283
public function testCreateAcceptsUppercaseSvgRootElementName(): void
310284
{
311285
$factory = new SvgPdfXObjectFactory();
@@ -414,142 +388,19 @@ public function testCreateParsesWidthAndHeightWithSurroundingWhitespace(): void
414388
self::assertSame([0.0, 0.0, 12.5, 7.25], $xObject->dictionary['BBox']);
415389
}
416390

417-
public function testCreateRejectsDimensionWithNonNumericPrefix(): void
418-
{
419-
$factory = new SvgPdfXObjectFactory();
420-
421-
$this->expectException(InvalidArgumentException::class);
422-
$this->expectExceptionMessage(
423-
'SVG source "/tmp/non-numeric-dimension.svg" must define either a valid viewBox or positive width/height.',
424-
);
425-
426-
$factory->create(
427-
'<svg width="abc12" height="10" xmlns="http://www.w3.org/2000/svg">'
428-
. '<path fill="#000" d="M0,0 L1,1"/>'
429-
. '</svg>',
430-
'/tmp/non-numeric-dimension.svg',
431-
);
432-
}
433-
434-
public function testCreateRejectsZeroWidthWhenNoViewBoxIsProvided(): void
435-
{
436-
$factory = new SvgPdfXObjectFactory();
437-
438-
$this->expectException(InvalidArgumentException::class);
439-
$this->expectExceptionMessage(
440-
'SVG source "/tmp/zero-width.svg" must define either a valid viewBox or positive width/height.',
441-
);
442-
443-
$factory->create(
444-
'<svg width="0" height="10" xmlns="http://www.w3.org/2000/svg">'
445-
. '<path fill="#000" d="M0,0 L1,1"/>'
446-
. '</svg>',
447-
'/tmp/zero-width.svg',
448-
);
449-
}
450-
451-
public function testCreateRejectsZeroHeightWhenNoViewBoxIsProvided(): void
452-
{
453-
$factory = new SvgPdfXObjectFactory();
454-
455-
$this->expectException(InvalidArgumentException::class);
456-
$this->expectExceptionMessage(
457-
'SVG source "/tmp/zero-height.svg" must define either a valid viewBox or positive width/height.',
458-
);
459-
460-
$factory->create(
461-
'<svg width="10" height="0" xmlns="http://www.w3.org/2000/svg">'
462-
. '<path fill="#000" d="M0,0 L1,1"/>'
463-
. '</svg>',
464-
'/tmp/zero-height.svg',
465-
);
466-
}
467-
468-
public function testCreateResolvesUppercaseCssFillAndStrokePropertiesFromStyleBlock(): void
469-
{
470-
$factory = new SvgPdfXObjectFactory();
471-
472-
$xObject = $factory->create(
473-
<<<'SVG'
474-
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg">
475-
<style>
476-
.box { FILL: #112233; STROKE: #ff0000; }
477-
</style>
478-
<rect class="box" x="1" y="1" width="10" height="10" style="stroke-width:2"/>
479-
</svg>
480-
SVG,
481-
'/tmp/uppercase-css-style.svg',
482-
);
483-
484-
self::assertStringContainsString('0.0667 0.1333 0.2 rg', $xObject->stream);
485-
self::assertStringContainsString('1 0 0 RG', $xObject->stream);
486-
self::assertStringContainsString('2.000000 w', $xObject->stream);
487-
}
488-
489-
public function testCreateIgnoresEmptyAndNonMatchingStyleBlocksBeforeValidClassRule(): void
490-
{
491-
$factory = new SvgPdfXObjectFactory();
492-
493-
$xObject = $factory->create(
494-
<<<'SVG'
495-
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg">
496-
<style></style>
497-
<style>path { fill: #00ff00; }</style>
498-
<style>.accent { fill: #112233; stroke: #ff0000; }</style>
499-
<rect class="accent" x="1" y="1" width="10" height="10" style="stroke-width:2"/>
500-
</svg>
501-
SVG,
502-
'/tmp/style-continue-coverage.svg',
503-
);
504-
505-
self::assertStringContainsString('0.0667 0.1333 0.2 rg', $xObject->stream);
506-
self::assertStringContainsString('1 0 0 RG', $xObject->stream);
507-
self::assertStringContainsString('2.000000 w', $xObject->stream);
508-
}
509-
510-
public function testCreateWithMissingDimensionsOrViewBoxThrows(): void
511-
{
512-
$factory = new SvgPdfXObjectFactory();
513-
514-
$this->expectException(InvalidArgumentException::class);
515-
$this->expectExceptionMessage(
516-
'SVG source "/tmp/no-viewport.svg" must define either a valid viewBox or positive width/height.',
517-
);
518-
519-
$factory->create(
520-
'<svg xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
521-
'/tmp/no-viewport.svg',
522-
);
523-
}
524-
525-
public function testCreateWithZeroDimensionsThrows(): void
526-
{
527-
$factory = new SvgPdfXObjectFactory();
528-
529-
$this->expectException(InvalidArgumentException::class);
530-
$this->expectExceptionMessage(
531-
'SVG source "/tmp/zero-dims.svg" must define a positive viewBox.',
532-
);
533-
534-
$factory->create(
535-
'<svg viewBox="0 0 0 0" xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
536-
'/tmp/zero-dims.svg',
537-
);
538-
}
539-
540-
public function testCreateWithViewBoxButNegativeHeightThrows(): void
541-
{
391+
#[DataProvider('provideStyleBlockColorExtractionScenarios')]
392+
public function testCreateResolvesClassColorMapsFromStyleBlocks(
393+
string $svg,
394+
string $sourcePath,
395+
array $requiredStreamFragments,
396+
): void {
542397
$factory = new SvgPdfXObjectFactory();
543398

544-
$this->expectException(InvalidArgumentException::class);
545-
$this->expectExceptionMessage(
546-
'SVG source "/tmp/negative-height.svg" must define a positive viewBox.',
547-
);
399+
$xObject = $factory->create($svg, $sourcePath);
548400

549-
$factory->create(
550-
'<svg viewBox="0 0 10 -5" xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
551-
'/tmp/negative-height.svg',
552-
);
401+
foreach ($requiredStreamFragments as $fragment) {
402+
self::assertStringContainsString($fragment, $xObject->stream);
403+
}
553404
}
554405

555406
public function testCreateWithViewBoxAndDimensionsCombination(): void
@@ -686,6 +537,92 @@ public static function provideInvalidViewportScenarios(): iterable
686537
'<svg width="auto" height="" xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
687538
'SVG source "/tmp/invalid-viewport.svg" must define either a valid viewBox or positive width/height.',
688539
];
540+
541+
yield 'missing dimensions and viewbox' => [
542+
'<svg xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
543+
'SVG source "/tmp/invalid-viewport.svg" must define either a valid viewBox or positive width/height.',
544+
];
545+
546+
yield 'zero width without viewbox' => [
547+
'<svg width="0" height="10" xmlns="http://www.w3.org/2000/svg"><path d="M0,0 L1,1"/></svg>',
548+
'SVG source "/tmp/invalid-viewport.svg" must define either a valid viewBox or positive width/height.',
549+
];
550+
551+
yield 'zero height without viewbox' => [
552+
'<svg width="10" height="0" xmlns="http://www.w3.org/2000/svg"><path d="M0,0 L1,1"/></svg>',
553+
'SVG source "/tmp/invalid-viewport.svg" must define either a valid viewBox or positive width/height.',
554+
];
555+
556+
yield 'non numeric dimension prefix' => [
557+
'<svg width="abc12" height="10" xmlns="http://www.w3.org/2000/svg"><path d="M0,0 L1,1"/></svg>',
558+
'SVG source "/tmp/invalid-viewport.svg" must define either a valid viewBox or positive width/height.',
559+
];
560+
561+
yield 'viewbox with zero dimensions' => [
562+
'<svg viewBox="0 0 0 0" xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
563+
'SVG source "/tmp/invalid-viewport.svg" must define a positive viewBox.',
564+
];
565+
566+
yield 'viewbox with negative height' => [
567+
'<svg viewBox="0 0 10 -5" xmlns="http://www.w3.org/2000/svg"><path d="M0,0"/></svg>',
568+
'SVG source "/tmp/invalid-viewport.svg" must define a positive viewBox.',
569+
];
570+
}
571+
572+
public static function provideInvalidSvgSources(): iterable
573+
{
574+
yield 'empty svg string' => [
575+
'',
576+
'/tmp/empty.svg',
577+
'Unable to parse SVG source "/tmp/empty.svg".',
578+
];
579+
580+
yield 'html payload' => [
581+
'<html></html>',
582+
'/tmp/invalid.svg',
583+
'Unable to parse SVG source "/tmp/invalid.svg".',
584+
];
585+
586+
yield 'non svg root element' => [
587+
'<?xml version="1.0"?><root></root>',
588+
'/tmp/wrong-root.svg',
589+
'Unable to parse SVG source "/tmp/wrong-root.svg".',
590+
];
591+
592+
yield 'malformed svg root' => [
593+
'<svg xmlns="http://www.w3.org/2000/svg"><g>',
594+
'/tmp/malformed-root.svg',
595+
'Unable to parse SVG source "/tmp/malformed-root.svg".',
596+
];
597+
}
598+
599+
public static function provideStyleBlockColorExtractionScenarios(): iterable
600+
{
601+
yield 'uppercase fill and stroke properties' => [
602+
<<<'SVG'
603+
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg">
604+
<style>
605+
.box { FILL: #112233; STROKE: #ff0000; }
606+
</style>
607+
<rect class="box" x="1" y="1" width="10" height="10" style="stroke-width:2"/>
608+
</svg>
609+
SVG,
610+
'/tmp/uppercase-css-style.svg',
611+
['0.0667 0.1333 0.2 rg', '1 0 0 RG', '2.000000 w'],
612+
];
613+
614+
yield 'ignore empty and non matching style blocks' => [
615+
<<<'SVG'
616+
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg">
617+
<style></style>
618+
<style>path { fill: #00ff00; }</style>
619+
<style>.accent { fill: #112233; stroke: #ff0000; }</style>
620+
<rect class="accent" x="1" y="1" width="10" height="10" style="stroke-width:2"/>
621+
</svg>
622+
SVG,
623+
'/tmp/style-continue-coverage.svg',
624+
['0.0667 0.1333 0.2 rg', '1 0 0 RG', '2.000000 w'],
625+
];
689626
}
690627

691628
public static function provideDimensionScenarios(): iterable

0 commit comments

Comments
 (0)