FrontMatterExtensionTest.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. declare(strict_types=1);
  3. namespace League\CommonMark\Tests\Functional\Extension\FrontMatterExtension;
  4. use League\CommonMark\Environment\Environment;
  5. use League\CommonMark\Environment\EnvironmentInterface;
  6. use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
  7. use League\CommonMark\Extension\FrontMatter\Data\FrontMatterDataParserInterface;
  8. use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
  9. use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
  10. use League\CommonMark\Extension\FrontMatter\Exception\InvalidFrontMatterException;
  11. use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
  12. use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
  13. use League\CommonMark\MarkdownConverter;
  14. use League\CommonMark\Output\RenderedContentInterface;
  15. use League\CommonMark\Parser\MarkdownParser;
  16. use League\CommonMark\Xml\XmlRenderer;
  17. use PHPUnit\Framework\TestCase;
  18. final class FrontMatterExtensionTest extends TestCase
  19. {
  20. /**
  21. * @return array{array{FrontMatterDataParserInterface, bool}}
  22. */
  23. public function parserProvider(): array
  24. {
  25. return [
  26. [new SymfonyYamlFrontMatterParser(), true],
  27. [new LibYamlFrontMatterParser(), LibYamlFrontMatterParser::capable() !== null],
  28. ];
  29. }
  30. protected function getEnvironment(FrontMatterDataParserInterface $parser): EnvironmentInterface
  31. {
  32. $environment = new Environment();
  33. $environment->addExtension(new CommonMarkCoreExtension());
  34. $environment->addExtension(new FrontMatterExtension($parser));
  35. return $environment;
  36. }
  37. private function skipIfParserNotAvailable(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  38. {
  39. if (! $shouldTest) {
  40. $this->markTestSkipped(\sprintf('Cannot test with %s due to missing prerequisites', \get_class($parser)));
  41. }
  42. }
  43. /**
  44. * @dataProvider parserProvider
  45. */
  46. public function testWithSampleData(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  47. {
  48. $this->skipIfParserNotAvailable($parser, $shouldTest);
  49. $markdown = <<<EOT
  50. ---
  51. layout: post
  52. title: Blogging Like a Hacker
  53. redirect_from:
  54. - /blog/my-post
  55. - /blog/2020-04/my-post
  56. ---
  57. # Hello World!
  58. This is my awesome blog post
  59. EOT;
  60. $expectedHtml = <<<EOT
  61. <h1>Hello World!</h1>
  62. <p>This is my awesome blog post</p>
  63. EOT;
  64. $expectedFrontMatter = [
  65. 'layout' => 'post',
  66. 'title' => 'Blogging Like a Hacker',
  67. 'redirect_from' => [
  68. '/blog/my-post',
  69. '/blog/2020-04/my-post',
  70. ],
  71. ];
  72. $converter = new MarkdownConverter($this->getEnvironment($parser));
  73. $result = $converter->convert($markdown);
  74. $this->assertInstanceOf(RenderedContentWithFrontMatter::class, $result);
  75. $this->assertInstanceOf(\Stringable::class, $result);
  76. \assert($result instanceof RenderedContentWithFrontMatter);
  77. $this->assertSame($expectedFrontMatter, $result->getFrontMatter());
  78. $this->assertSame($expectedHtml, (string) $result->getContent());
  79. $this->assertSame($expectedHtml, (string) $result);
  80. $this->assertSame(1, $result->getDocument()->getStartLine());
  81. $this->assertSame(9, $result->getDocument()->firstChild()->getStartLine());
  82. }
  83. /**
  84. * @dataProvider parserProvider
  85. */
  86. public function testWithMultipleYamlDocuments(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  87. {
  88. $this->skipIfParserNotAvailable($parser, $shouldTest);
  89. $markdown = <<<EOT
  90. ---
  91. layout: post
  92. title: Blogging Like a Hacker
  93. redirect_from:
  94. - /blog/my-post
  95. - /blog/2020-04/my-post
  96. ---
  97. ---
  98. more_yaml: true
  99. ---
  100. # Hello World!
  101. EOT;
  102. $expectedHtml = <<<EOT
  103. <hr />
  104. <h2>more_yaml: true</h2>
  105. <h1>Hello World!</h1>
  106. EOT;
  107. $expectedFrontMatter = [
  108. 'layout' => 'post',
  109. 'title' => 'Blogging Like a Hacker',
  110. 'redirect_from' => [
  111. '/blog/my-post',
  112. '/blog/2020-04/my-post',
  113. ],
  114. ];
  115. $converter = new MarkdownConverter($this->getEnvironment($parser));
  116. $result = $converter->convert($markdown);
  117. $this->assertInstanceOf(RenderedContentWithFrontMatter::class, $result);
  118. $this->assertInstanceOf(\Stringable::class, $result);
  119. \assert($result instanceof RenderedContentWithFrontMatter);
  120. $this->assertSame($expectedFrontMatter, $result->getFrontMatter());
  121. $this->assertSame($expectedHtml, (string) $result->getContent());
  122. $this->assertSame($expectedHtml, (string) $result);
  123. $this->assertSame(1, $result->getDocument()->getStartLine());
  124. $this->assertSame(9, $result->getDocument()->firstChild()->getStartLine());
  125. }
  126. /**
  127. * @dataProvider parserProvider
  128. */
  129. public function testWithWindowsLineEndings(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  130. {
  131. $this->skipIfParserNotAvailable($parser, $shouldTest);
  132. $markdown = "---\r\nfoo: bar\r\n---\r\n\r\n# Test";
  133. $expectedHtml = "<h1>Test</h1>\n";
  134. $expectedFrontMatter = ['foo' => 'bar'];
  135. $converter = new MarkdownConverter($this->getEnvironment($parser));
  136. $result = $converter->convertToHtml($markdown);
  137. $this->assertInstanceOf(RenderedContentWithFrontMatter::class, $result);
  138. $this->assertInstanceOf(\Stringable::class, $result);
  139. \assert($result instanceof RenderedContentWithFrontMatter);
  140. $this->assertSame($expectedFrontMatter, $result->getFrontMatter());
  141. $this->assertSame($expectedHtml, (string) $result->getContent());
  142. $this->assertSame($expectedHtml, (string) $result);
  143. $this->assertSame(1, $result->getDocument()->getStartLine());
  144. $this->assertSame(5, $result->getDocument()->firstChild()->getStartLine());
  145. }
  146. /**
  147. * @dataProvider parserProvider
  148. */
  149. public function testWithNoFrontMatter(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  150. {
  151. $this->skipIfParserNotAvailable($parser, $shouldTest);
  152. $markdown = '# Hello World!';
  153. $converter = new MarkdownConverter($this->getEnvironment($parser));
  154. $result = $converter->convert($markdown);
  155. $this->assertInstanceOf(RenderedContentInterface::class, $result);
  156. $this->assertNotInstanceOf(RenderedContentWithFrontMatter::class, $result);
  157. $this->assertInstanceOf(\Stringable::class, $result);
  158. $expectedHtml = "<h1>Hello World!</h1>\n";
  159. $this->assertSame($expectedHtml, $result->getContent());
  160. $this->assertSame($expectedHtml, (string) $result);
  161. $this->assertSame(1, $result->getDocument()->getStartLine());
  162. $this->assertSame(1, $result->getDocument()->firstChild()->getStartLine());
  163. }
  164. /**
  165. * @dataProvider parserProvider
  166. */
  167. public function testWithInvalidYaml(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  168. {
  169. $this->skipIfParserNotAvailable($parser, $shouldTest);
  170. $this->expectException(InvalidFrontMatterException::class);
  171. $markdown = <<<EOT
  172. ---
  173. this: list
  174. is: not
  175. valid:::
  176. ---
  177. # Oh no!
  178. EOT;
  179. $converter = new MarkdownConverter($this->getEnvironment($parser));
  180. $converter->convert($markdown);
  181. }
  182. /**
  183. * @dataProvider parserProvider
  184. */
  185. public function testRenderXml(FrontMatterDataParserInterface $parser, bool $shouldTest): void
  186. {
  187. $this->skipIfParserNotAvailable($parser, $shouldTest);
  188. $markdown = <<<MD
  189. ---
  190. layout: post
  191. title: Blogging Like a Hacker
  192. redirect_from:
  193. - /blog/my-post
  194. - /blog/2020-04/my-post
  195. ---
  196. # Hello World!
  197. This is my awesome blog post
  198. MD;
  199. $expectedXml = <<<XML
  200. <?xml version="1.0" encoding="UTF-8"?>
  201. <document xmlns="http://commonmark.org/xml/1.0">
  202. <heading level="1">
  203. <text>Hello World!</text>
  204. </heading>
  205. <paragraph>
  206. <text>This is my awesome blog post</text>
  207. </paragraph>
  208. </document>
  209. XML;
  210. $environment = $this->getEnvironment($parser);
  211. $document = (new MarkdownParser($environment))->parse($markdown);
  212. $xml = (new XmlRenderer($environment))->renderDocument($document)->getContent();
  213. $this->assertSame($expectedXml, \rtrim($xml));
  214. }
  215. }