1bcefb8aeSAndreas Gohr<?php 2bcefb8aeSAndreas Gohr 3bcefb8aeSAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode; 4bcefb8aeSAndreas Gohr 5bcefb8aeSAndreas Gohruse dokuwiki\Parsing\ModeRegistry; 6bcefb8aeSAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmEmphasis; 7bcefb8aeSAndreas Gohr 8bcefb8aeSAndreas Gohr/** 9bcefb8aeSAndreas Gohr * Tests for the GFM asterisk emphasis mode (`*text*`). 10bcefb8aeSAndreas Gohr */ 11bcefb8aeSAndreas Gohrclass GfmEmphasisTest extends ParserTestBase 12bcefb8aeSAndreas Gohr{ 13bcefb8aeSAndreas Gohr public function setUp(): void 14bcefb8aeSAndreas Gohr { 15bcefb8aeSAndreas Gohr parent::setUp(); 16bcefb8aeSAndreas Gohr global $conf; 17bcefb8aeSAndreas Gohr $conf['syntax'] = 'markdown'; 18bcefb8aeSAndreas Gohr ModeRegistry::reset(); 19bcefb8aeSAndreas Gohr } 20bcefb8aeSAndreas Gohr 21bcefb8aeSAndreas Gohr public function tearDown(): void 22bcefb8aeSAndreas Gohr { 23bcefb8aeSAndreas Gohr ModeRegistry::reset(); 24bcefb8aeSAndreas Gohr parent::tearDown(); 25bcefb8aeSAndreas Gohr } 26bcefb8aeSAndreas Gohr 27bcefb8aeSAndreas Gohr function testBasicAsterisk() 28bcefb8aeSAndreas Gohr { 29bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 30bcefb8aeSAndreas Gohr $this->P->parse('Foo *Bar* Baz'); 31bcefb8aeSAndreas Gohr $calls = [ 32bcefb8aeSAndreas Gohr ['document_start', []], 33bcefb8aeSAndreas Gohr ['p_open', []], 34bcefb8aeSAndreas Gohr ['cdata', ["\nFoo "]], 35bcefb8aeSAndreas Gohr ['emphasis_open', []], 36bcefb8aeSAndreas Gohr ['cdata', ['Bar']], 37bcefb8aeSAndreas Gohr ['emphasis_close', []], 38bcefb8aeSAndreas Gohr ['cdata', [' Baz']], 39bcefb8aeSAndreas Gohr ['p_close', []], 40bcefb8aeSAndreas Gohr ['document_end', []], 41bcefb8aeSAndreas Gohr ]; 42bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 43bcefb8aeSAndreas Gohr } 44bcefb8aeSAndreas Gohr 45bcefb8aeSAndreas Gohr function testSingleCharacter() 46bcefb8aeSAndreas Gohr { 47bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 48bcefb8aeSAndreas Gohr $this->P->parse('foo *b* bar'); 49bcefb8aeSAndreas Gohr $calls = [ 50bcefb8aeSAndreas Gohr ['document_start', []], 51bcefb8aeSAndreas Gohr ['p_open', []], 52bcefb8aeSAndreas Gohr ['cdata', ["\nfoo "]], 53bcefb8aeSAndreas Gohr ['emphasis_open', []], 54bcefb8aeSAndreas Gohr ['cdata', ['b']], 55bcefb8aeSAndreas Gohr ['emphasis_close', []], 56bcefb8aeSAndreas Gohr ['cdata', [' bar']], 57bcefb8aeSAndreas Gohr ['p_close', []], 58bcefb8aeSAndreas Gohr ['document_end', []], 59bcefb8aeSAndreas Gohr ]; 60bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 61bcefb8aeSAndreas Gohr } 62bcefb8aeSAndreas Gohr 63bcefb8aeSAndreas Gohr function testMultipleWords() 64bcefb8aeSAndreas Gohr { 65bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 66bcefb8aeSAndreas Gohr $this->P->parse('*three four five*'); 67bcefb8aeSAndreas Gohr $calls = [ 68bcefb8aeSAndreas Gohr ['document_start', []], 69bcefb8aeSAndreas Gohr ['p_open', []], 70bcefb8aeSAndreas Gohr ['cdata', ["\n"]], 71bcefb8aeSAndreas Gohr ['emphasis_open', []], 72bcefb8aeSAndreas Gohr ['cdata', ['three four five']], 73bcefb8aeSAndreas Gohr ['emphasis_close', []], 74bcefb8aeSAndreas Gohr ['cdata', ['']], 75bcefb8aeSAndreas Gohr ['p_close', []], 76bcefb8aeSAndreas Gohr ['document_end', []], 77bcefb8aeSAndreas Gohr ]; 78bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 79bcefb8aeSAndreas Gohr } 80bcefb8aeSAndreas Gohr 81bcefb8aeSAndreas Gohr function testTwoSeparateEmphasisOnOneLine() 82bcefb8aeSAndreas Gohr { 83bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 84bcefb8aeSAndreas Gohr $this->P->parse('*one* and *two*'); 85bcefb8aeSAndreas Gohr $calls = [ 86bcefb8aeSAndreas Gohr ['document_start', []], 87bcefb8aeSAndreas Gohr ['p_open', []], 88bcefb8aeSAndreas Gohr ['cdata', ["\n"]], 89bcefb8aeSAndreas Gohr ['emphasis_open', []], 90bcefb8aeSAndreas Gohr ['cdata', ['one']], 91bcefb8aeSAndreas Gohr ['emphasis_close', []], 92bcefb8aeSAndreas Gohr ['cdata', [' and ']], 93bcefb8aeSAndreas Gohr ['emphasis_open', []], 94bcefb8aeSAndreas Gohr ['cdata', ['two']], 95bcefb8aeSAndreas Gohr ['emphasis_close', []], 96bcefb8aeSAndreas Gohr ['cdata', ['']], 97bcefb8aeSAndreas Gohr ['p_close', []], 98bcefb8aeSAndreas Gohr ['document_end', []], 99bcefb8aeSAndreas Gohr ]; 100bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 101bcefb8aeSAndreas Gohr } 102bcefb8aeSAndreas Gohr 103bcefb8aeSAndreas Gohr function testUnmatchedOpenerDoesNotEmphasise() 104bcefb8aeSAndreas Gohr { 105bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 106bcefb8aeSAndreas Gohr $this->P->parse('foo *bar with no closer'); 107bcefb8aeSAndreas Gohr $calls = [ 108bcefb8aeSAndreas Gohr ['document_start', []], 109bcefb8aeSAndreas Gohr ['p_open', []], 110bcefb8aeSAndreas Gohr ['cdata', ["\nfoo *bar with no closer"]], 111bcefb8aeSAndreas Gohr ['p_close', []], 112bcefb8aeSAndreas Gohr ['document_end', []], 113bcefb8aeSAndreas Gohr ]; 114bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 115bcefb8aeSAndreas Gohr } 116bcefb8aeSAndreas Gohr 117bcefb8aeSAndreas Gohr function testOpenerFollowedBySpaceDoesNotEmphasise() 118bcefb8aeSAndreas Gohr { 119bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 120bcefb8aeSAndreas Gohr $this->P->parse('foo * bar* baz'); 121bcefb8aeSAndreas Gohr $calls = [ 122bcefb8aeSAndreas Gohr ['document_start', []], 123bcefb8aeSAndreas Gohr ['p_open', []], 124bcefb8aeSAndreas Gohr ['cdata', ["\nfoo * bar* baz"]], 125bcefb8aeSAndreas Gohr ['p_close', []], 126bcefb8aeSAndreas Gohr ['document_end', []], 127bcefb8aeSAndreas Gohr ]; 128bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 129bcefb8aeSAndreas Gohr } 130bcefb8aeSAndreas Gohr 131bcefb8aeSAndreas Gohr function testEmptyDelimiterDoesNotEmphasise() 132bcefb8aeSAndreas Gohr { 133bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 134bcefb8aeSAndreas Gohr $this->P->parse('foo ** bar'); 135bcefb8aeSAndreas Gohr $calls = [ 136bcefb8aeSAndreas Gohr ['document_start', []], 137bcefb8aeSAndreas Gohr ['p_open', []], 138bcefb8aeSAndreas Gohr ['cdata', ["\nfoo ** bar"]], 139bcefb8aeSAndreas Gohr ['p_close', []], 140bcefb8aeSAndreas Gohr ['document_end', []], 141bcefb8aeSAndreas Gohr ]; 142bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 143bcefb8aeSAndreas Gohr } 144bcefb8aeSAndreas Gohr 145bcefb8aeSAndreas Gohr function testUnderscoreIsNotEmphasised() 146bcefb8aeSAndreas Gohr { 147bcefb8aeSAndreas Gohr // GfmEmphasis handles `*` only — `_` is reserved to avoid the 148*685560ebSAndreas Gohr // `__underline__` conflict with DokuWiki's underline syntax; 149*685560ebSAndreas Gohr // GfmEmphasisUnderscore handles `_` separately when MD-preferred. 150bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 151bcefb8aeSAndreas Gohr $this->P->parse('foo _bar_ baz'); 152bcefb8aeSAndreas Gohr $calls = [ 153bcefb8aeSAndreas Gohr ['document_start', []], 154bcefb8aeSAndreas Gohr ['p_open', []], 155bcefb8aeSAndreas Gohr ['cdata', ["\nfoo _bar_ baz"]], 156bcefb8aeSAndreas Gohr ['p_close', []], 157bcefb8aeSAndreas Gohr ['document_end', []], 158bcefb8aeSAndreas Gohr ]; 159bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 160bcefb8aeSAndreas Gohr } 161bcefb8aeSAndreas Gohr 162bcefb8aeSAndreas Gohr function testMultilineEmphasis() 163bcefb8aeSAndreas Gohr { 164bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 165bcefb8aeSAndreas Gohr $this->P->parse("*line\nline\nline*"); 166bcefb8aeSAndreas Gohr $calls = [ 167bcefb8aeSAndreas Gohr ['document_start', []], 168bcefb8aeSAndreas Gohr ['p_open', []], 169bcefb8aeSAndreas Gohr ['cdata', ["\n"]], 170bcefb8aeSAndreas Gohr ['emphasis_open', []], 171bcefb8aeSAndreas Gohr ['cdata', ["line\nline\nline"]], 172bcefb8aeSAndreas Gohr ['emphasis_close', []], 173bcefb8aeSAndreas Gohr ['cdata', ['']], 174bcefb8aeSAndreas Gohr ['p_close', []], 175bcefb8aeSAndreas Gohr ['document_end', []], 176bcefb8aeSAndreas Gohr ]; 177bcefb8aeSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 178bcefb8aeSAndreas Gohr } 179bcefb8aeSAndreas Gohr 180bcefb8aeSAndreas Gohr function testModeNameIsDistinctFromInstructionName() 181bcefb8aeSAndreas Gohr { 182bcefb8aeSAndreas Gohr // The lexer mode is registered as 'gfm_emphasis' (to avoid collision 183bcefb8aeSAndreas Gohr // with DW Emphasis), but instructions are 'emphasis_open/close' 184bcefb8aeSAndreas Gohr // so the existing XHTML renderer emits <em>. 185bcefb8aeSAndreas Gohr $mode = new GfmEmphasis(); 186bcefb8aeSAndreas Gohr $this->assertSame(80, $mode->getSort()); 187bcefb8aeSAndreas Gohr } 188bcefb8aeSAndreas Gohr 189bcefb8aeSAndreas Gohr function testDoesNotSpanParagraphBoundary() 190bcefb8aeSAndreas Gohr { 191bcefb8aeSAndreas Gohr // An unclosed `*` followed by a blank line must stay literal — the 192bcefb8aeSAndreas Gohr // entry pattern's lookahead is paragraph-boundary-safe. 193bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 194bcefb8aeSAndreas Gohr $this->P->parse("*open\n\nclose*"); 195bcefb8aeSAndreas Gohr $modes = array_column($this->H->calls, 0); 196bcefb8aeSAndreas Gohr $this->assertNotContains('emphasis_open', $modes, 197bcefb8aeSAndreas Gohr 'GfmEmphasis must not open when the closing `*` is past a blank line'); 198bcefb8aeSAndreas Gohr } 199bcefb8aeSAndreas Gohr 200bcefb8aeSAndreas Gohr function testAllowsSingleNewline() 201bcefb8aeSAndreas Gohr { 202bcefb8aeSAndreas Gohr // Single newlines are fine inside emphasis (multi-line emphasis). 203bcefb8aeSAndreas Gohr $this->P->addMode('gfm_emphasis', new GfmEmphasis()); 204bcefb8aeSAndreas Gohr $this->P->parse("*open\nclose*"); 205bcefb8aeSAndreas Gohr $modes = array_column($this->H->calls, 0); 206bcefb8aeSAndreas Gohr $this->assertContains('emphasis_open', $modes, 207bcefb8aeSAndreas Gohr 'GfmEmphasis must still match across a single newline'); 208bcefb8aeSAndreas Gohr } 209bcefb8aeSAndreas Gohr} 210