$options
* @param ConverterInterface[] $converters
*/
private function assertHtmlGivesMarkdown(string $html, string $expectedMarkdown, array $options = [], array $converters = []): void
{
$markdown = new HtmlConverter($options);
foreach ($converters as $converter) {
$markdown->getEnvironment()->addConverter($converter);
}
$result = $markdown->convert($html);
$this->assertSame($expectedMarkdown, $result);
}
public function testEmptyInput(): void
{
$this->assertHtmlGivesMarkdown('', '');
$this->assertHtmlGivesMarkdown(' ', '');
}
public function testPlainText(): void
{
$this->assertHtmlGivesMarkdown('test', 'test');
$this->assertHtmlGivesMarkdown('
text should be preserved as-is - no escaping
$this->assertHtmlGivesMarkdown('
_test_
', '
_test_
');
$this->assertHtmlGivesMarkdown('
*test*
', '
*test*
');
$this->assertHtmlGivesMarkdown('
\ ` * _ { } [ ] ( ) > > # + - . !
', '\\\\ ` \* \_ { } \[ \] ( ) > > # + - . !');
}
public function testLineBreaks(): void
{
$this->assertHtmlGivesMarkdown("test\nanother line", 'test another line');
$this->assertHtmlGivesMarkdown("
test\nanother line
", 'test another line');
$this->assertHtmlGivesMarkdown("
test
\nanother line
", "test \nanother line");
$this->assertHtmlGivesMarkdown("
test
\n another line
", "test \n another line");
$this->assertHtmlGivesMarkdown("
test
\nanother line
", "test \n*another* line");
$this->assertHtmlGivesMarkdown('
test
another line
', "test \nanother line");
$this->assertHtmlGivesMarkdown('
test
another line
', "test \nanother line");
$this->assertHtmlGivesMarkdown('
test
another line
', "test \nanother line");
$this->assertHtmlGivesMarkdown('
test
another line
', "test \nanother line");
$this->assertHtmlGivesMarkdown('
test
another line
', "test\nanother line", ['hard_break' => true]);
$this->assertHtmlGivesMarkdown('
test
another line
', "test\nanother line", ['hard_break' => true]);
$this->assertHtmlGivesMarkdown('
test
another line
', "test\nanother line", ['hard_break' => true]);
$this->assertHtmlGivesMarkdown('
test
another line
', "test\nanother line", ['hard_break' => true]);
$this->assertHtmlGivesMarkdown('
foo
baz
', "foo\n\n
\n\nbaz");
}
public function testHeaders(): void
{
$this->assertHtmlGivesMarkdown('
Test
', "Test\n====");
$this->assertHtmlGivesMarkdown('
Test
', "Test\n----");
$this->assertHtmlGivesMarkdown('
Test
', '> # Test');
$this->assertHtmlGivesMarkdown('
Test
', '> ## Test');
$this->assertHtmlGivesMarkdown('
Test
', '### Test');
$this->assertHtmlGivesMarkdown('
Test
', '#### Test');
$this->assertHtmlGivesMarkdown('
Test
', '##### Test');
$this->assertHtmlGivesMarkdown('
Test
', '###### Test');
$this->assertHtmlGivesMarkdown('
', '');
$this->assertHtmlGivesMarkdown('
', '');
$this->assertHtmlGivesMarkdown('
', '');
$this->assertHtmlGivesMarkdown('
# Test
', "\# Test\n=======");
$this->assertHtmlGivesMarkdown('
# Test #
', "\# Test #\n=========");
$this->assertHtmlGivesMarkdown('
Mismatched Tags', '### Mismatched Tags');
}
public function testSpans(): void
{
$this->assertHtmlGivesMarkdown('Test', '*Test*');
$this->assertHtmlGivesMarkdown('Test', '*Test*');
$this->assertHtmlGivesMarkdown('Test', '**Test**');
$this->assertHtmlGivesMarkdown('Test', '**Test**');
$this->assertHtmlGivesMarkdown('Test', '*Test*', ['italic_style' => '*']);
$this->assertHtmlGivesMarkdown('Italic and a bold', '*Italic* and a __bold__', ['italic_style' => '*', 'bold_style' => '__']);
$this->assertHtmlGivesMarkdown('Test', '_Test_', ['italic_style' => '_']);
$this->assertHtmlGivesMarkdown('Test', '__Test__', ['bold_style' => '__']);
$this->assertHtmlGivesMarkdown('Test', '__Test__', ['bold_style' => '__']);
$this->assertHtmlGivesMarkdown('Test', 'Test');
$this->assertHtmlGivesMarkdown('Bold Italic', '**Bold** *Italic*');
$this->assertHtmlGivesMarkdown('BoldItalic', '**Bold***Italic*');
$this->assertHtmlGivesMarkdown('This is a test', '*This is **a test***');
$this->assertHtmlGivesMarkdown('This is a test', '*This is* **a** test');
$this->assertHtmlGivesMarkdown('Emphasis with no text preserves spaces.', 'Emphasis with no text **preserves** spaces.');
$this->assertHtmlGivesMarkdown("Emphasis discards \nline breaks", 'Emphasis discards line breaks');
$this->assertHtmlGivesMarkdown('Emphasis preserves
HTML breaks', "Emphasis preserves \nHTML breaks");
}
public function testConsecutiveSpans(): void
{
$this->assertHtmlGivesMarkdown('FooBar', '*FooBar*');
$this->assertHtmlGivesMarkdown('FooBar', '*FooBar*');
$this->assertHtmlGivesMarkdown('FooBarFoo', '*FooBarFoo*');
$this->assertHtmlGivesMarkdown('FooBar', '**FooBar**');
$this->assertHtmlGivesMarkdown('FooBar', '**FooBar**');
$this->assertHtmlGivesMarkdown('FooBarFoo', '**FooBarFoo**');
$this->assertHtmlGivesMarkdown('Foo Bar', '*Foo* *Bar*');
$this->assertHtmlGivesMarkdown('Foo Bar', '**Foo** **Bar**');
$this->assertHtmlGivesMarkdown('FooBarFoo', '**FooBar***Foo*');
}
public function testNesting(): void
{
$this->assertHtmlGivesMarkdown('Test', 'Test');
}
public function testScript(): void
{
$this->assertHtmlGivesMarkdown("", "");
}
public function testImage(): void
{
$this->assertHtmlGivesMarkdown('
', '');
}
public function testAnchor(): void
{
$this->assertHtmlGivesMarkdown('http://modernnerd.net', '');
$this->assertHtmlGivesMarkdown('Modern Nerd', '[Modern Nerd](http://modernnerd.net "Title")');
$this->assertHtmlGivesMarkdown('Modern Nerd Modern Nerd', '[Modern Nerd](http://modernnerd.net "Title") [Modern Nerd](http://modernnerd.net "Title")');
$this->assertHtmlGivesMarkdown('Modern Nerd
', '[### Modern Nerd](http://modernnerd.net)');
$this->assertHtmlGivesMarkdown('The Modern Nerd (MN)', 'The [Modern Nerd ](http://modernnerd.net)(MN)');
$this->assertHtmlGivesMarkdown('
', '[](http://modernnerd.net/ "Title")');
$this->assertHtmlGivesMarkdown('
Test', '[ Test](http://modernnerd.net/ "Title")');
// Placeholder links and fragment identifiers
$this->assertHtmlGivesMarkdown('Test', 'Test');
$this->assertHtmlGivesMarkdown('Test', 'Test');
$this->assertHtmlGivesMarkdown('Test', '[Test](#nerd "Title")');
$this->assertHtmlGivesMarkdown('Test', '[Test](#nerd)');
// Strip placeholder links
$this->assertHtmlGivesMarkdown('Test', 'Test', ['strip_placeholder_links' => true]);
$this->assertHtmlGivesMarkdown('Test', 'Test', ['strip_placeholder_links' => true]);
$this->assertHtmlGivesMarkdown('Test', '[Test](#nerd "Title")', ['strip_placeholder_links' => true]);
$this->assertHtmlGivesMarkdown('Test', '[Test](#nerd)', ['strip_placeholder_links' => true]);
// Autolinking
$this->assertHtmlGivesMarkdown('test', '[test](test)');
$this->assertHtmlGivesMarkdown('google.com', '[google.com](google.com)');
$this->assertHtmlGivesMarkdown('https://www.google.com', '');
$this->assertHtmlGivesMarkdown('ftp://files.example.com', '');
$this->assertHtmlGivesMarkdown('test@example.com', '');
$this->assertHtmlGivesMarkdown('test+foo@example.bar-baz.com', '');
// Autolinking can be toggled off
$this->assertHtmlGivesMarkdown('https://www.google.com', '[https://www.google.com](https://www.google.com)', ['use_autolinks' => false]);
$this->assertHtmlGivesMarkdown('Google', '[Google](https://www.google.com)', ['use_autolinks' => false]);
$this->assertHtmlGivesMarkdown('google.com', '[google.com](google.com)', ['use_autolinks' => false]);
}
public function testHorizontalRule(): void
{
$this->assertHtmlGivesMarkdown('
', '---');
$this->assertHtmlGivesMarkdown('
', '---');
$this->assertHtmlGivesMarkdown('
', '---');
$this->assertHtmlGivesMarkdown('
', '---');
$this->assertHtmlGivesMarkdown('Test
', "Test\n\n---");
}
public function testLists(): void
{
$this->assertHtmlGivesMarkdown('', "- Item A\n- Item B\n- Item C");
$this->assertHtmlGivesMarkdown('', "- Item A\n- Item B");
$this->assertHtmlGivesMarkdown('', "- ### Item A\n \n Description\n- Item B");
$this->assertHtmlGivesMarkdown('', "* First\n* Second", ['list_item_style' => '*']);
$this->assertHtmlGivesMarkdown('- Item A
- Item B
', "1. Item A\n2. Item B");
$this->assertHtmlGivesMarkdown("\n - Item A
\n - Item B
\n
", "1. Item A\n2. Item B");
$this->assertHtmlGivesMarkdown('- Item A
- Item B
', "1. Item A\n2. Item B");
$this->assertHtmlGivesMarkdown('-
Item A
Description
- Item B
', "1. ### Item A\n \n Description\n2. Item B");
$this->assertHtmlGivesMarkdown('- Item A
- Item B
', "120. Item A\n121. Item B");
$this->assertHtmlGivesMarkdown('- Item A
- Item B
', "0. Item A\n1. Item B");
$this->assertHtmlGivesMarkdown('- first item of first list
- second item of first list
- first item of second list
', "- first item of first list\n- second item of first list\n\n* first item of second list", ['list_item_style_alternate' => '*']);
}
public function testNestedLists(): void
{
$this->assertHtmlGivesMarkdown('', "- Item A\n- Item B\n - Nested A\n - Nested B\n- Item C");
$this->assertHtmlGivesMarkdown('', "- Item A\n 1. Nested A\n- Item B");
$this->assertHtmlGivesMarkdown('- Item A
- Item B
', "1. Item A\n - Nested A\n2. Item B");
}
public function testComplexNestedLists(): void
{
$this->assertHtmlGivesMarkdown("\n- Item A
\n- Item B\n
\n- Nested A
\n- Nested B\n
\n- Subnested A
\n- Subnested B
\n
\n \n
\n \n- Item C
\n
", "- Item A\n- Item B \n - Nested A\n - Nested B \n - Subnested A\n - Subnested B\n- Item C");
$this->assertHtmlGivesMarkdown("\n- Item A
\nItem B
\nParagraph Item B
\n\n- Nested A
\n- Nested B\n
\n- Subnested A
\n- Subnested B
\n
\n \n
\n \n- Item C
\n
", "* Item A\n* ## Item B\n \n Paragraph Item B\n \n \n * Nested A\n * Nested B \n * Subnested A\n * Subnested B\n* Item C", ['list_item_style' => '*', 'header_style' => 'atx']);
$this->assertHtmlGivesMarkdown("\n- Item A
\nItem B
\nParagraph Item B
\n\n- Nested A
\nNested B
\nParagraph Nested B
\n\n- Subnested A
\n- Subnested B\n
\n- Subsubnested A
\nSubsubnested B
\nParagraph Subsubnested B
\n\n- Subsubsubnested A
\n- Subsubsubnested B
\n
\n \n
\n \n
\n \n
\n \n- Item C
\n
", "* Item A\n* ## Item B\n \n Paragraph Item B\n \n \n * Nested A\n * ## Nested B\n \n Paragraph Nested B\n \n \n * Subnested A\n * Subnested B \n * Subsubnested A\n * ## Subsubnested B\n \n Paragraph Subsubnested B\n \n \n * Subsubsubnested A\n * Subsubsubnested B\n* Item C", ['list_item_style' => '*', 'header_style' => 'atx']);
$this->assertHtmlGivesMarkdown("\n- Item A
\n- Item B\n
\n- Nested A
\n- Nested B\n
\n- Subnested A
\n- Subnested B\n
\n- Subsubnested A
\n- Subsubnested B \n
\n- Subsubsubnested A
\n- Subsubsubnested B
\n
\n \n
\n \n
\n \n
\n \n- Item C
\n
", "* Item A\n* Item B \n * Nested A\n * Nested B \n * Subnested A\n * Subnested B \n * Subsubnested A\n * Subsubnested B \n * Subsubsubnested A\n * Subsubsubnested B\n* Item C", ['list_item_style' => '*', 'header_style' => 'atx']);
}
public function testListLikeThingsWhichArentLists(): void
{
$this->assertHtmlGivesMarkdown('120.
', '120\.');
$this->assertHtmlGivesMarkdown('
120.
', '120\.');
$this->assertHtmlGivesMarkdown('
120.00
', '120.00');
$this->assertHtmlGivesMarkdown('
120.00 USD
', '120.00 USD');
}
public function testTables(): void
{
$opt = [];
$conv = [new TableConverter()];
$this->assertHtmlGivesMarkdown('
', "| A |\n|---|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A | B |\n|---|---|\n| a | b |\n| c | d |", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A | B |\n|---|---|\n| a | `foo` |", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A | B |\n|---|---|\n| a | *foo*bar |", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A | B |\n|---|---|\n| a | foo bar |", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| [link](http://example.com) |\n|---|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|\n| a \\| b |", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|\n| a ][ b |", ['table_pipe_escape' => ']['], $conv);
$this->assertHtmlGivesMarkdown('', "Cap\n| A |\n|---|", ['table_caption_side' => 'top'], $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|\nCap", ['table_caption_side' => 'bottom'], $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|", ['table_caption_side' => null], $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|:--|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|--:|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|:-:|", $opt, $conv);
$this->assertHtmlGivesMarkdown('', "| A |\n|---|", $opt, $conv);
$html = <<<'EOT'
| |
Batman |
Robin |
The Flash |
Kid Flash |
| Skill |
Smarts |
Dex, acrobat |
Super speed |
Super speed |
EOT;
$this->assertHtmlGivesMarkdown($html, "| | Batman | Robin | The Flash | Kid Flash |\n|---|---|---|---|---|\n| Skill | Smarts | Dex, acrobat | Super speed | Super speed |", $opt, $conv);
}
public function testCodeSamples(): void
{
$this->assertHtmlGivesMarkdown('<p>Some sample HTML</p>', '`Some sample HTML
`');
$this->assertHtmlGivesMarkdown("\n<p>Some sample HTML</p>\n<p>And another line</p>\n", '`Some sample HTML
And another line
`');
$this->assertHtmlGivesMarkdown('`', '```');
$this->assertHtmlGivesMarkdown('test', '`test`');
$this->assertHtmlGivesMarkdown('test `` test', '`test `` test`');
$this->assertHtmlGivesMarkdown('test` `test', "```\ntest` `test\n```");
$this->assertHtmlGivesMarkdown("\n<p>Some sample HTML</p>\n<p>And another line</p>\n
Paragraph after code.
", "`Some sample HTML
And another line
`\n\nParagraph after code.");
$this->assertHtmlGivesMarkdown("\n#sidebar h1 {\n font-size: 1.5em;\n font-weight: bold;\n}\n
", '`#sidebar h1 { font-size: 1.5em; font-weight: bold;}`');
$this->assertHtmlGivesMarkdown("#sidebar h1 {\n font-size: 1.5em;\n font-weight: bold;\n}\n
", '`#sidebar h1 { font-size: 1.5em; font-weight: bold;}`');
$this->assertHtmlGivesMarkdown('<p>Some sample HTML</p>
', "```\nSome sample HTML
\n```");
$this->assertHtmlGivesMarkdown('<?php //Some php code ?>
', "```php\n\n```");
$this->assertHtmlGivesMarkdown("<?php //Some multiline php code\n\$myVar = 2; ?>
", "```php\n\n```");
$this->assertHtmlGivesMarkdown("<p>Multiline HTML</p>\n<p>Here's the second line</p>
", "```\nMultiline HTML
\nHere's the second line
\n```");
$this->assertHtmlGivesMarkdown("<p>Multiline HTML</p>\n<p>Here's the second line</p>
\nline
", "```\nMultiline HTML
\nHere's the second line
\n```\n\nline");
}
public function testPreformat(): void
{
$this->assertHtmlGivesMarkdown("test\ntest\r\ntest
", "```\ntest\ntest\ntest\n```");
$this->assertHtmlGivesMarkdown("test\ntest\r\ntest\n
", "```\ntest\ntest\ntest\n```");
$this->assertHtmlGivesMarkdown("test\n\ttab\r\n
", "```\ntest\n\ttab\n```");
$this->assertHtmlGivesMarkdown(' one line with spaces
', "```\n one line with spaces \n```");
$this->assertHtmlGivesMarkdown('', "```\n```");
$this->assertHtmlGivesMarkdown('', "```\n```\n\n```\n```");
$this->assertHtmlGivesMarkdown("\n
", "```\n\n```");
$this->assertHtmlGivesMarkdown("foo\n
", "```\nfoo\n```");
$this->assertHtmlGivesMarkdown("\nfoo
", "```\n\nfoo\n```");
$this->assertHtmlGivesMarkdown("\nfoo\n
", "```\n\nfoo\n```");
$this->assertHtmlGivesMarkdown("\n\n
", "```\n\n\n```");
$this->assertHtmlGivesMarkdown("\n\n\n
", "```\n\n\n\n```");
$this->assertHtmlGivesMarkdown("\n
\n
", "```\n\n```\n\n```\n\n```");
$this->assertHtmlGivesMarkdown("one\ntwo\r\nthree
\nline
", "```\none\ntwo\nthree\n```\n\nline");
$this->assertHtmlGivesMarkdown("test with attributes
", "```\ntest with attributes\n```");
}
public function testBlockquotes(): void
{
$this->assertHtmlGivesMarkdown('Something I said?
', '> Something I said?');
$this->assertHtmlGivesMarkdown('Something I said?
', '> > Something I said?');
$this->assertHtmlGivesMarkdown('Something I said?
Why, yes it was!
', "> Something I said?\n> \n> Why, yes it was!");
}
public function testMalformedHtml(): void
{
$this->assertHtmlGivesMarkdown('Some sample HTML
', '`Some sample HTML
`'); // Invalid HTML, but should still work
$this->assertHtmlGivesMarkdown('Strong italic Regular text', '***Strong italic*** Regular text'); // Missing closing
}
public function testHtml5TagsArePreserved(): void
{
$this->assertHtmlGivesMarkdown('Some stuff', 'Some stuff');
}
public function testStripUnmarkdownable(): void
{
$this->assertHtmlGivesMarkdown('Span', 'Span', ['strip_tags' => true]);
}
public function testStripComments(): void
{
$this->assertHtmlGivesMarkdown('Test
', 'Test');
$this->assertHtmlGivesMarkdown('Test
', 'Test');
$this->assertHtmlGivesMarkdown('Test
', 'Test', ['strip_tags' => true]);
$this->assertHtmlGivesMarkdown('Test
', 'Test', ['strip_tags' => true]);
}
public function testPreserveComments(): void
{
$this->assertHtmlGivesMarkdown('Test
', "Test\n\n", ['preserve_comments' => ['more']]);
$this->assertHtmlGivesMarkdown('Test
', "Test\n\n", ['preserve_comments' => ['more']]);
$this->assertHtmlGivesMarkdown('Test
', "Test\n\n", ['preserve_comments' => true]);
}
public function testPreserveCommentOrder(): void
{
$this->assertHtmlGivesMarkdown('Test
', "Test\n\n", ['preserve_comments' => true]);
}
public function testPreserveWhitespace(): void
{
$this->assertHtmlGivesMarkdown('google.com test', '[google.com](google.com) `test`');
}
public function testDeleteBlankP(): void
{
$this->assertHtmlGivesMarkdown('', '');
$this->assertHtmlGivesMarkdown('', '', ['strip_tags' => true]);
}
public function testDivs(): void
{
$this->assertHtmlGivesMarkdown('Hello
World
', 'Hello
World
');
$this->assertHtmlGivesMarkdown('Hello
World
', "Hello\n\nWorld", ['strip_tags' => true]);
$this->assertHtmlGivesMarkdown("Hello
\nWorld
", "Hello\n\nWorld", ['strip_tags' => true]);
$this->assertHtmlGivesMarkdown('Paragraph
Hello
World
', "Paragraph\n\nHello\n\nWorld", ['strip_tags' => true]);
}
public function testRemoveNodes(): void
{
$this->assertHtmlGivesMarkdown('Hello
World
', '', ['remove_nodes' => 'div']);
$this->assertHtmlGivesMarkdown('Hello
World', '', ['remove_nodes' => 'p span']);
}
public function testHtmlEntities(): void
{
$this->assertHtmlGivesMarkdown('€
', '€');
$this->assertHtmlGivesMarkdown('<p>Some sample HTML</p>', '`Some sample HTML
`');
}
public function testSetOption(): void
{
$markdown = new HtmlConverter();
$markdown->getConfig()->setOption('strip_tags', true);
$result = $markdown->convert('Strip');
$this->assertEquals('Strip', $result);
}
public function testInvoke(): void
{
$markdown = new HtmlConverter();
$markdown->getConfig()->setOption('strip_tags', true);
$result = $markdown('Strip');
$this->assertEquals('Strip', $result);
}
public function testSanitization(): void
{
$html = '<script type = "text/javascript"> function startTimer() { var tim = window.setTimeout("hideMessage()", 5000) } </head> <body>
';
$markdown = '```' . "\n" . '