1*0244be5cSAndreas Gohr<?php 2*0244be5cSAndreas Gohr 3*0244be5cSAndreas Gohrnamespace dokuwiki\test\Parsing\ParserMode; 4*0244be5cSAndreas Gohr 5*0244be5cSAndreas Gohruse dokuwiki\Parsing\ModeRegistry; 6*0244be5cSAndreas Gohruse dokuwiki\Parsing\ParserMode\GfmDeleted; 7*0244be5cSAndreas Gohr 8*0244be5cSAndreas Gohr/** 9*0244be5cSAndreas Gohr * Tests for the GFM strikethrough mode (`~~text~~`). 10*0244be5cSAndreas Gohr */ 11*0244be5cSAndreas Gohrclass GfmDeletedTest extends ParserTestBase 12*0244be5cSAndreas Gohr{ 13*0244be5cSAndreas Gohr public function setUp(): void 14*0244be5cSAndreas Gohr { 15*0244be5cSAndreas Gohr parent::setUp(); 16*0244be5cSAndreas Gohr global $conf; 17*0244be5cSAndreas Gohr $conf['syntax'] = 'markdown'; 18*0244be5cSAndreas Gohr ModeRegistry::reset(); 19*0244be5cSAndreas Gohr } 20*0244be5cSAndreas Gohr 21*0244be5cSAndreas Gohr public function tearDown(): void 22*0244be5cSAndreas Gohr { 23*0244be5cSAndreas Gohr ModeRegistry::reset(); 24*0244be5cSAndreas Gohr parent::tearDown(); 25*0244be5cSAndreas Gohr } 26*0244be5cSAndreas Gohr 27*0244be5cSAndreas Gohr function testBasicStrikethrough() 28*0244be5cSAndreas Gohr { 29*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 30*0244be5cSAndreas Gohr $this->P->parse('Foo ~~Bar~~ Baz'); 31*0244be5cSAndreas Gohr $calls = [ 32*0244be5cSAndreas Gohr ['document_start', []], 33*0244be5cSAndreas Gohr ['p_open', []], 34*0244be5cSAndreas Gohr ['cdata', ["\nFoo "]], 35*0244be5cSAndreas Gohr ['deleted_open', []], 36*0244be5cSAndreas Gohr ['cdata', ['Bar']], 37*0244be5cSAndreas Gohr ['deleted_close', []], 38*0244be5cSAndreas Gohr ['cdata', [' Baz']], 39*0244be5cSAndreas Gohr ['p_close', []], 40*0244be5cSAndreas Gohr ['document_end', []], 41*0244be5cSAndreas Gohr ]; 42*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 43*0244be5cSAndreas Gohr } 44*0244be5cSAndreas Gohr 45*0244be5cSAndreas Gohr function testSingleCharacterBody() 46*0244be5cSAndreas Gohr { 47*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 48*0244be5cSAndreas Gohr $this->P->parse('foo ~~b~~ bar'); 49*0244be5cSAndreas Gohr $calls = [ 50*0244be5cSAndreas Gohr ['document_start', []], 51*0244be5cSAndreas Gohr ['p_open', []], 52*0244be5cSAndreas Gohr ['cdata', ["\nfoo "]], 53*0244be5cSAndreas Gohr ['deleted_open', []], 54*0244be5cSAndreas Gohr ['cdata', ['b']], 55*0244be5cSAndreas Gohr ['deleted_close', []], 56*0244be5cSAndreas Gohr ['cdata', [' bar']], 57*0244be5cSAndreas Gohr ['p_close', []], 58*0244be5cSAndreas Gohr ['document_end', []], 59*0244be5cSAndreas Gohr ]; 60*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 61*0244be5cSAndreas Gohr } 62*0244be5cSAndreas Gohr 63*0244be5cSAndreas Gohr function testMultipleWords() 64*0244be5cSAndreas Gohr { 65*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 66*0244be5cSAndreas Gohr $this->P->parse('~~three four five~~'); 67*0244be5cSAndreas Gohr $calls = [ 68*0244be5cSAndreas Gohr ['document_start', []], 69*0244be5cSAndreas Gohr ['p_open', []], 70*0244be5cSAndreas Gohr ['cdata', ["\n"]], 71*0244be5cSAndreas Gohr ['deleted_open', []], 72*0244be5cSAndreas Gohr ['cdata', ['three four five']], 73*0244be5cSAndreas Gohr ['deleted_close', []], 74*0244be5cSAndreas Gohr ['cdata', ['']], 75*0244be5cSAndreas Gohr ['p_close', []], 76*0244be5cSAndreas Gohr ['document_end', []], 77*0244be5cSAndreas Gohr ]; 78*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 79*0244be5cSAndreas Gohr } 80*0244be5cSAndreas Gohr 81*0244be5cSAndreas Gohr function testTwoSeparateStrikethroughsOnOneLine() 82*0244be5cSAndreas Gohr { 83*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 84*0244be5cSAndreas Gohr $this->P->parse('~~one~~ and ~~two~~'); 85*0244be5cSAndreas Gohr $calls = [ 86*0244be5cSAndreas Gohr ['document_start', []], 87*0244be5cSAndreas Gohr ['p_open', []], 88*0244be5cSAndreas Gohr ['cdata', ["\n"]], 89*0244be5cSAndreas Gohr ['deleted_open', []], 90*0244be5cSAndreas Gohr ['cdata', ['one']], 91*0244be5cSAndreas Gohr ['deleted_close', []], 92*0244be5cSAndreas Gohr ['cdata', [' and ']], 93*0244be5cSAndreas Gohr ['deleted_open', []], 94*0244be5cSAndreas Gohr ['cdata', ['two']], 95*0244be5cSAndreas Gohr ['deleted_close', []], 96*0244be5cSAndreas Gohr ['cdata', ['']], 97*0244be5cSAndreas Gohr ['p_close', []], 98*0244be5cSAndreas Gohr ['document_end', []], 99*0244be5cSAndreas Gohr ]; 100*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 101*0244be5cSAndreas Gohr } 102*0244be5cSAndreas Gohr 103*0244be5cSAndreas Gohr function testUnmatchedOpenerDoesNotStrike() 104*0244be5cSAndreas Gohr { 105*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 106*0244be5cSAndreas Gohr $this->P->parse('foo ~~bar with no closer'); 107*0244be5cSAndreas Gohr $calls = [ 108*0244be5cSAndreas Gohr ['document_start', []], 109*0244be5cSAndreas Gohr ['p_open', []], 110*0244be5cSAndreas Gohr ['cdata', ["\nfoo ~~bar with no closer"]], 111*0244be5cSAndreas Gohr ['p_close', []], 112*0244be5cSAndreas Gohr ['document_end', []], 113*0244be5cSAndreas Gohr ]; 114*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 115*0244be5cSAndreas Gohr } 116*0244be5cSAndreas Gohr 117*0244be5cSAndreas Gohr function testOpenerFollowedBySpaceDoesNotStrike() 118*0244be5cSAndreas Gohr { 119*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 120*0244be5cSAndreas Gohr $this->P->parse('foo ~~ bar~~ baz'); 121*0244be5cSAndreas Gohr $calls = [ 122*0244be5cSAndreas Gohr ['document_start', []], 123*0244be5cSAndreas Gohr ['p_open', []], 124*0244be5cSAndreas Gohr ['cdata', ["\nfoo ~~ bar~~ baz"]], 125*0244be5cSAndreas Gohr ['p_close', []], 126*0244be5cSAndreas Gohr ['document_end', []], 127*0244be5cSAndreas Gohr ]; 128*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 129*0244be5cSAndreas Gohr } 130*0244be5cSAndreas Gohr 131*0244be5cSAndreas Gohr function testEmptyDelimiterDoesNotStrike() 132*0244be5cSAndreas Gohr { 133*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 134*0244be5cSAndreas Gohr $this->P->parse('foo ~~~~ bar'); 135*0244be5cSAndreas Gohr $modes = array_column($this->H->calls, 0); 136*0244be5cSAndreas Gohr $this->assertNotContains('deleted_open', $modes, 137*0244be5cSAndreas Gohr 'Empty `~~~~` must stay literal'); 138*0244be5cSAndreas Gohr } 139*0244be5cSAndreas Gohr 140*0244be5cSAndreas Gohr function testTripleTildeDoesNotStrike() 141*0244be5cSAndreas Gohr { 142*0244be5cSAndreas Gohr // `~~~` is the GFM fenced-code-block marker; strikethrough must not 143*0244be5cSAndreas Gohr // consume a run of three or more tildes. 144*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 145*0244be5cSAndreas Gohr $this->P->parse('foo ~~~bar~~~ baz'); 146*0244be5cSAndreas Gohr $modes = array_column($this->H->calls, 0); 147*0244be5cSAndreas Gohr $this->assertNotContains('deleted_open', $modes, 148*0244be5cSAndreas Gohr 'Run of 3+ tildes must not trigger strikethrough'); 149*0244be5cSAndreas Gohr } 150*0244be5cSAndreas Gohr 151*0244be5cSAndreas Gohr function testMultilineStrikethrough() 152*0244be5cSAndreas Gohr { 153*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 154*0244be5cSAndreas Gohr $this->P->parse("~~line\nline\nline~~"); 155*0244be5cSAndreas Gohr $calls = [ 156*0244be5cSAndreas Gohr ['document_start', []], 157*0244be5cSAndreas Gohr ['p_open', []], 158*0244be5cSAndreas Gohr ['cdata', ["\n"]], 159*0244be5cSAndreas Gohr ['deleted_open', []], 160*0244be5cSAndreas Gohr ['cdata', ["line\nline\nline"]], 161*0244be5cSAndreas Gohr ['deleted_close', []], 162*0244be5cSAndreas Gohr ['cdata', ['']], 163*0244be5cSAndreas Gohr ['p_close', []], 164*0244be5cSAndreas Gohr ['document_end', []], 165*0244be5cSAndreas Gohr ]; 166*0244be5cSAndreas Gohr $this->assertCalls($calls, $this->H->calls); 167*0244be5cSAndreas Gohr } 168*0244be5cSAndreas Gohr 169*0244be5cSAndreas Gohr function testDoesNotSpanParagraphBoundary() 170*0244be5cSAndreas Gohr { 171*0244be5cSAndreas Gohr // An unclosed `~~` followed by a blank line must stay literal. 172*0244be5cSAndreas Gohr // Mirrors GFM spec example 492. 173*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 174*0244be5cSAndreas Gohr $this->P->parse("This ~~has a\n\nnew paragraph~~."); 175*0244be5cSAndreas Gohr $modes = array_column($this->H->calls, 0); 176*0244be5cSAndreas Gohr $this->assertNotContains('deleted_open', $modes, 177*0244be5cSAndreas Gohr 'GfmDeleted must not open when the closing `~~` is past a blank line'); 178*0244be5cSAndreas Gohr } 179*0244be5cSAndreas Gohr 180*0244be5cSAndreas Gohr function testAllowsSingleNewline() 181*0244be5cSAndreas Gohr { 182*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 183*0244be5cSAndreas Gohr $this->P->parse("~~open\nclose~~"); 184*0244be5cSAndreas Gohr $modes = array_column($this->H->calls, 0); 185*0244be5cSAndreas Gohr $this->assertContains('deleted_open', $modes, 186*0244be5cSAndreas Gohr 'GfmDeleted must still match across a single newline'); 187*0244be5cSAndreas Gohr } 188*0244be5cSAndreas Gohr 189*0244be5cSAndreas Gohr function testTrailingWhitespaceBeforeCloserDoesNotStrike() 190*0244be5cSAndreas Gohr { 191*0244be5cSAndreas Gohr $this->P->addMode('gfm_deleted', new GfmDeleted()); 192*0244be5cSAndreas Gohr $this->P->parse('~~foo bar ~~'); 193*0244be5cSAndreas Gohr $modes = array_column($this->H->calls, 0); 194*0244be5cSAndreas Gohr $this->assertNotContains('deleted_open', $modes, 195*0244be5cSAndreas Gohr 'Closer preceded by whitespace must not match'); 196*0244be5cSAndreas Gohr } 197*0244be5cSAndreas Gohr 198*0244be5cSAndreas Gohr function testSortValue() 199*0244be5cSAndreas Gohr { 200*0244be5cSAndreas Gohr $mode = new GfmDeleted(); 201*0244be5cSAndreas Gohr $this->assertSame(130, $mode->getSort()); 202*0244be5cSAndreas Gohr } 203*0244be5cSAndreas Gohr} 204