|
10 | 10 | use DOMDocument; |
11 | 11 | use LibreSign\XObjectTemplate\Exception\UnsupportedSubsetException; |
12 | 12 | use LibreSign\XObjectTemplate\Html\SubsetHtmlParser; |
| 13 | +use PHPUnit\Framework\Attributes\DataProvider; |
13 | 14 | use PHPUnit\Framework\TestCase; |
14 | 15 |
|
15 | 16 | final class SubsetHtmlParserTest extends TestCase |
16 | 17 | { |
17 | | - public function testUnsupportedTagThrowsException(): void |
| 18 | + /** |
| 19 | + * @return iterable<string, array{0: string, 1: string}> |
| 20 | + */ |
| 21 | + public static function unsupportedTagProvider(): iterable |
| 22 | + { |
| 23 | + yield 'table is outside the supported subset' => [ |
| 24 | + '<table><tr><td>x</td></tr></table>', |
| 25 | + 'Tag <table> is not supported.', |
| 26 | + ]; |
| 27 | + |
| 28 | + yield 'unordered lists are outside the supported subset' => [ |
| 29 | + '<ul><li>x</li></ul>', |
| 30 | + 'Tag <ul> is not supported.', |
| 31 | + ]; |
| 32 | + |
| 33 | + yield 'semantic strong tags are outside the supported subset' => [ |
| 34 | + '<strong>x</strong>', |
| 35 | + 'Tag <strong> is not supported.', |
| 36 | + ]; |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * @return iterable<string, array{0: string, 1: string, 2: string, 3: string, 4: list<string>}> |
| 41 | + */ |
| 42 | + public static function inheritableStyleProvider(): iterable |
| 43 | + { |
| 44 | + yield 'layout-only styles stay on parent while text styles inherit' => [ |
| 45 | + '<div style="width:58%;height:100%;padding:18 24;font-size:20;color:#123456">' |
| 46 | + . '<div style="font-weight:700">Title</div>' |
| 47 | + . '</div>', |
| 48 | + 'width:58%;height:100%;padding:18 24;font-size:20;color:#123456', |
| 49 | + 'font-size:20;color:#123456;font-weight:700', |
| 50 | + 'font-size:20;color:#123456;font-weight:700', |
| 51 | + ['width:58%', 'height:100%', 'padding:18 24'], |
| 52 | + ]; |
| 53 | + |
| 54 | + yield 'text alignment white-space and color inherit together' => [ |
| 55 | + '<div style="text-align:right;white-space:nowrap;color:#222222;font-size:11">' |
| 56 | + . '<span>Aligned</span>' |
| 57 | + . '</div>', |
| 58 | + 'text-align:right;white-space:nowrap;color:#222222;font-size:11', |
| 59 | + 'text-align:right;white-space:nowrap;color:#222222;font-size:11', |
| 60 | + 'text-align:right;white-space:nowrap;color:#222222;font-size:11', |
| 61 | + [], |
| 62 | + ]; |
| 63 | + |
| 64 | + yield 'malformed declarations preserve last inheritable values and colon values' => [ |
| 65 | + '<div style=" ; COLOR : #fff ; broken ; font-family : Times:Bold ; invalid: ; ' |
| 66 | + . 'white-space : nowrap ; hyphens : auto ; color : #abc ; line-height : 12 ; ">' |
| 67 | + . '<span style="font-weight:bold">Hello</span>' |
| 68 | + . '</div>', |
| 69 | + '; COLOR : #fff ; broken ; font-family : Times:Bold ; invalid: ; white-space : nowrap ; ' |
| 70 | + . 'hyphens : auto ; color : #abc ; line-height : 12 ;', |
| 71 | + 'color:#abc;font-family:Times:Bold;white-space:nowrap;hyphens:auto;line-height:12;font-weight:bold', |
| 72 | + 'color:#abc;font-family:Times:Bold;white-space:nowrap;hyphens:auto;line-height:12;font-weight:bold', |
| 73 | + [], |
| 74 | + ]; |
| 75 | + } |
| 76 | + |
| 77 | + #[DataProvider('unsupportedTagProvider')] |
| 78 | + public function testUnsupportedTagThrowsException(string $html, string $expectedMessage): void |
18 | 79 | { |
19 | 80 | $parser = new SubsetHtmlParser(); |
20 | 81 |
|
21 | 82 | $this->expectException(UnsupportedSubsetException::class); |
22 | | - $this->expectExceptionMessage('Tag <table> is not supported.'); |
23 | | - $parser->parse('<table><tr><td>x</td></tr></table>'); |
| 83 | + $this->expectExceptionMessage($expectedMessage); |
| 84 | + $parser->parse($html); |
24 | 85 | } |
25 | 86 |
|
26 | 87 | public function testParseNormalizesAttributesAndTrimsTextNodes(): void |
@@ -62,31 +123,25 @@ public function testParseMergesInheritedStylesAndKeepsAllowedTags(): void |
62 | 123 | self::assertSame('font-size:10; margin:2', $nodes[0]->children[2]->attributes['style']); |
63 | 124 | } |
64 | 125 |
|
65 | | - public function testParseOnlyInheritsTextualStylesToDescendants(): void |
66 | | - { |
| 126 | + #[DataProvider('inheritableStyleProvider')] |
| 127 | + public function testParseOnlyInheritsTextualStylesToDescendants( |
| 128 | + string $html, |
| 129 | + string $expectedRootStyle, |
| 130 | + string $expectedChildStyle, |
| 131 | + string $expectedTextStyle, |
| 132 | + array $excludedFragments, |
| 133 | + ): void { |
67 | 134 | $parser = new SubsetHtmlParser(); |
68 | 135 |
|
69 | | - $nodes = $parser->parse( |
70 | | - '<div style="width:58%;height:100%;padding:18 24;font-size:20;color:#123456">' |
71 | | - . '<div style="font-weight:700">Title</div>' |
72 | | - . '</div>', |
73 | | - ); |
| 136 | + $nodes = $parser->parse($html); |
74 | 137 |
|
75 | | - self::assertSame( |
76 | | - 'width:58%;height:100%;padding:18 24;font-size:20;color:#123456', |
77 | | - $nodes[0]->attributes['style'], |
78 | | - ); |
79 | | - self::assertSame( |
80 | | - 'font-size:20;color:#123456;font-weight:700', |
81 | | - $nodes[0]->children[0]->attributes['style'], |
82 | | - ); |
83 | | - self::assertSame( |
84 | | - 'font-size:20;color:#123456;font-weight:700', |
85 | | - $nodes[0]->children[0]->children[0]->attributes['style'], |
86 | | - ); |
87 | | - self::assertStringNotContainsString('width:58%', $nodes[0]->children[0]->attributes['style']); |
88 | | - self::assertStringNotContainsString('height:100%', $nodes[0]->children[0]->attributes['style']); |
89 | | - self::assertStringNotContainsString('padding:18 24', $nodes[0]->children[0]->attributes['style']); |
| 138 | + self::assertSame($expectedRootStyle, $nodes[0]->attributes['style']); |
| 139 | + self::assertSame($expectedChildStyle, $nodes[0]->children[0]->attributes['style']); |
| 140 | + self::assertSame($expectedTextStyle, $nodes[0]->children[0]->children[0]->attributes['style']); |
| 141 | + |
| 142 | + foreach ($excludedFragments as $excludedFragment) { |
| 143 | + self::assertStringNotContainsString($excludedFragment, $nodes[0]->children[0]->attributes['style']); |
| 144 | + } |
90 | 145 | } |
91 | 146 |
|
92 | 147 | public function testParseNormalizesTagAndAttributeNamesAndKeepsAllAttributes(): void |
@@ -178,32 +233,6 @@ public function testParseKeepsAllTopLevelNodesInOrder(): void |
178 | 233 | $this->assertSame('Second', $nodes[1]->children[0]->text); |
179 | 234 | } |
180 | 235 |
|
181 | | - public function testParseFiltersInheritedStylesAfterMalformedDeclarationsAndPreservesColonValues(): void |
182 | | - { |
183 | | - $parser = new SubsetHtmlParser(); |
184 | | - |
185 | | - $nodes = $parser->parse( |
186 | | - '<div style=" ; COLOR : #fff ; broken ; font-family : Times:Bold ; invalid: ; ' |
187 | | - . 'white-space : nowrap ; hyphens : auto ; color : #abc ; line-height : 12 ; ">' |
188 | | - . '<span style="font-weight:bold">Hello</span>' |
189 | | - . '</div>', |
190 | | - ); |
191 | | - |
192 | | - $this->assertSame( |
193 | | - '; COLOR : #fff ; broken ; font-family : Times:Bold ; invalid: ; white-space : nowrap ; ' |
194 | | - . 'hyphens : auto ; color : #abc ; line-height : 12 ;', |
195 | | - $nodes[0]->attributes['style'], |
196 | | - ); |
197 | | - $this->assertSame( |
198 | | - 'color:#abc;font-family:Times:Bold;white-space:nowrap;hyphens:auto;line-height:12;font-weight:bold', |
199 | | - $nodes[0]->children[0]->attributes['style'], |
200 | | - ); |
201 | | - $this->assertSame( |
202 | | - 'color:#abc;font-family:Times:Bold;white-space:nowrap;hyphens:auto;line-height:12;font-weight:bold', |
203 | | - $nodes[0]->children[0]->children[0]->attributes['style'], |
204 | | - ); |
205 | | - } |
206 | | - |
207 | 236 | public function testParseClearsPreExistingLibxmlErrorBuffer(): void |
208 | 237 | { |
209 | 238 | $parser = new SubsetHtmlParser(); |
|
0 commit comments