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