1c4bcbc2eSAndreas Gohr<?php 2c4bcbc2eSAndreas Gohr 3c4bcbc2eSAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode; 4c4bcbc2eSAndreas Gohr 5c4bcbc2eSAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmEmphasis; 6c4bcbc2eSAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmLinebreak; 7c4bcbc2eSAndreas Gohr 8c4bcbc2eSAndreas Gohr/** 9c4bcbc2eSAndreas Gohr * Tests for the GFM hard-line-break mode. 10c4bcbc2eSAndreas Gohr */ 11c4bcbc2eSAndreas Gohrclass GfmLinebreakTest extends ParserTestBase 12c4bcbc2eSAndreas Gohr{ 13c4bcbc2eSAndreas Gohr public function setUp(): void 14c4bcbc2eSAndreas Gohr { 15c4bcbc2eSAndreas Gohr parent::setUp(); 16*47a02a10SAndreas Gohr $this->setSyntax('md'); 17c4bcbc2eSAndreas Gohr } 18c4bcbc2eSAndreas Gohr 19c4bcbc2eSAndreas Gohr function testTwoTrailingSpacesProduceLinebreak() 20c4bcbc2eSAndreas Gohr { 21c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 22c4bcbc2eSAndreas Gohr $this->P->parse("foo \nbar"); 23c4bcbc2eSAndreas Gohr 24c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 25c4bcbc2eSAndreas Gohr $this->assertContains('linebreak', $names, 26c4bcbc2eSAndreas Gohr 'Two trailing spaces before a newline must produce a linebreak call'); 27c4bcbc2eSAndreas Gohr } 28c4bcbc2eSAndreas Gohr 29c4bcbc2eSAndreas Gohr function testManyTrailingSpacesProduceLinebreak() 30c4bcbc2eSAndreas Gohr { 31c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 32c4bcbc2eSAndreas Gohr $this->P->parse("foo \nbar"); 33c4bcbc2eSAndreas Gohr 34c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 35c4bcbc2eSAndreas Gohr $this->assertContains('linebreak', $names, 36c4bcbc2eSAndreas Gohr '7+ trailing spaces before a newline must produce a linebreak call'); 37c4bcbc2eSAndreas Gohr } 38c4bcbc2eSAndreas Gohr 39c4bcbc2eSAndreas Gohr function testBackslashNewlineProducesLinebreak() 40c4bcbc2eSAndreas Gohr { 41c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 42c4bcbc2eSAndreas Gohr $this->P->parse("foo\\\nbar"); 43c4bcbc2eSAndreas Gohr 44c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 45c4bcbc2eSAndreas Gohr $this->assertContains('linebreak', $names, 46c4bcbc2eSAndreas Gohr 'A single backslash before a newline must produce a linebreak call'); 47c4bcbc2eSAndreas Gohr } 48c4bcbc2eSAndreas Gohr 49c4bcbc2eSAndreas Gohr function testLeadingWhitespaceOnNextLineConsumed() 50c4bcbc2eSAndreas Gohr { 51c4bcbc2eSAndreas Gohr // Spec example 656 / 657: leading spaces at the beginning of the 52c4bcbc2eSAndreas Gohr // next line are dropped — the rendered HTML must not carry them. 53c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 54c4bcbc2eSAndreas Gohr $this->P->parse("foo \n bar"); 55c4bcbc2eSAndreas Gohr 56c4bcbc2eSAndreas Gohr $cdata = array_filter($this->H->calls, static fn($c) => $c[0] === 'cdata'); 57c4bcbc2eSAndreas Gohr $joined = implode('', array_map(static fn($c) => $c[1][0], $cdata)); 58c4bcbc2eSAndreas Gohr 59c4bcbc2eSAndreas Gohr $this->assertSame("\nfoobar", $joined, 60c4bcbc2eSAndreas Gohr 'Leading whitespace on the line after a hard break must be consumed'); 61c4bcbc2eSAndreas Gohr } 62c4bcbc2eSAndreas Gohr 63c4bcbc2eSAndreas Gohr function testNoLinebreakAtParagraphBreak() 64c4bcbc2eSAndreas Gohr { 65c4bcbc2eSAndreas Gohr // Spec example 665 (analogue): trailing spaces immediately before 66c4bcbc2eSAndreas Gohr // a paragraph break are not a hard break — the lookahead rejects. 67c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 68c4bcbc2eSAndreas Gohr $this->P->parse("foo \n\nbar"); 69c4bcbc2eSAndreas Gohr 70c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 71c4bcbc2eSAndreas Gohr $this->assertNotContains('linebreak', $names, 72c4bcbc2eSAndreas Gohr 'Trailing spaces before a blank line must not produce a hard break'); 73c4bcbc2eSAndreas Gohr } 74c4bcbc2eSAndreas Gohr 75c4bcbc2eSAndreas Gohr function testNoLinebreakAtEof() 76c4bcbc2eSAndreas Gohr { 77c4bcbc2eSAndreas Gohr // Spec example 665: trailing spaces at end of document are not a 78c4bcbc2eSAndreas Gohr // hard break. The parser appends `\n`, so the lookahead's `\z` arm 79c4bcbc2eSAndreas Gohr // catches this case. 80c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 81c4bcbc2eSAndreas Gohr $this->P->parse('foo '); 82c4bcbc2eSAndreas Gohr 83c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 84c4bcbc2eSAndreas Gohr $this->assertNotContains('linebreak', $names, 85c4bcbc2eSAndreas Gohr 'Trailing spaces at EOF must not produce a hard break'); 86c4bcbc2eSAndreas Gohr } 87c4bcbc2eSAndreas Gohr 88c4bcbc2eSAndreas Gohr function testBackslashAtEofStaysLiteral() 89c4bcbc2eSAndreas Gohr { 90c4bcbc2eSAndreas Gohr // Spec example 664: a single trailing backslash at end of document 91c4bcbc2eSAndreas Gohr // is not a hard break — same paragraph-end rule. 92c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 93c4bcbc2eSAndreas Gohr $this->P->parse('foo\\'); 94c4bcbc2eSAndreas Gohr 95c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 96c4bcbc2eSAndreas Gohr $this->assertNotContains('linebreak', $names, 97c4bcbc2eSAndreas Gohr 'A trailing backslash at EOF must stay literal, not produce a break'); 98c4bcbc2eSAndreas Gohr 99c4bcbc2eSAndreas Gohr $cdata = array_filter($this->H->calls, static fn($c) => $c[0] === 'cdata'); 100c4bcbc2eSAndreas Gohr $joined = implode('', array_map(static fn($c) => $c[1][0], $cdata)); 101c4bcbc2eSAndreas Gohr $this->assertStringContainsString('\\', $joined, 102c4bcbc2eSAndreas Gohr 'The literal backslash must survive in cdata when no break fires'); 103c4bcbc2eSAndreas Gohr } 104c4bcbc2eSAndreas Gohr 105c4bcbc2eSAndreas Gohr function testWorksInsideEmphasis() 106c4bcbc2eSAndreas Gohr { 107c4bcbc2eSAndreas Gohr // Spec example 658: hard breaks fire inside inline containers. 108d331a839SAndreas Gohr // GfmLinebreak is SUBSTITUTION, GfmEmphasis allows SUBSTITUTION via 109c4bcbc2eSAndreas Gohr // its allowedModes — so the break appears between the open and 110c4bcbc2eSAndreas Gohr // close emphasis calls. 111c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 112c4bcbc2eSAndreas Gohr $this->P->addMode('gfm_linebreak', new GfmLinebreak()); 113c4bcbc2eSAndreas Gohr $this->P->parse("*foo \nbar*"); 114c4bcbc2eSAndreas Gohr 115c4bcbc2eSAndreas Gohr $names = array_column($this->H->calls, 0); 116c4bcbc2eSAndreas Gohr $emOpen = array_search('emphasis_open', $names, true); 117c4bcbc2eSAndreas Gohr $break = array_search('linebreak', $names, true); 118c4bcbc2eSAndreas Gohr $emClose = array_search('emphasis_close', $names, true); 119c4bcbc2eSAndreas Gohr 120c4bcbc2eSAndreas Gohr $this->assertNotFalse($emOpen, 'emphasis_open must fire'); 121c4bcbc2eSAndreas Gohr $this->assertNotFalse($break, 'linebreak must fire inside emphasis'); 122c4bcbc2eSAndreas Gohr $this->assertNotFalse($emClose, 'emphasis_close must fire'); 123c4bcbc2eSAndreas Gohr $this->assertLessThan($break, $emOpen, 124c4bcbc2eSAndreas Gohr 'linebreak must come after the emphasis opener'); 125c4bcbc2eSAndreas Gohr $this->assertLessThan($emClose, $break, 126c4bcbc2eSAndreas Gohr 'linebreak must come before the emphasis closer'); 127c4bcbc2eSAndreas Gohr } 128c4bcbc2eSAndreas Gohr 129c4bcbc2eSAndreas Gohr function testGetSortValue() 130c4bcbc2eSAndreas Gohr { 131c4bcbc2eSAndreas Gohr $mode = new GfmLinebreak(); 132c4bcbc2eSAndreas Gohr $this->assertSame(140, $mode->getSort()); 133c4bcbc2eSAndreas Gohr } 134c4bcbc2eSAndreas Gohr} 135