xref: /dokuwiki/_test/tests/ChangeLog/PageChangeLogTest.php (revision 0a245329500f3be55c2a4eb03710ad926803aac6)
12bde879aSAndreas Gohr<?php
22bde879aSAndreas Gohr
32bde879aSAndreas Gohrnamespace dokuwiki\test\ChangeLog;
42bde879aSAndreas Gohr
52bde879aSAndreas Gohruse dokuwiki\ChangeLog\PageChangeLog;
62bde879aSAndreas Gohr
72bde879aSAndreas Gohr/**
82bde879aSAndreas Gohr * Tests for dokuwiki\ChangeLog\PageChangeLog.
92bde879aSAndreas Gohr */
102bde879aSAndreas Gohrclass PageChangeLogTest extends \DokuWikiTest
112bde879aSAndreas Gohr{
122bde879aSAndreas Gohr    /**
132bde879aSAndreas Gohr     * A page deleted through DokuWiki is recorded as its own revision, newer than the
142bde879aSAndreas Gohr     * last revision that still had content. getRelativeRevision() must walk back from
152bde879aSAndreas Gohr     * that deletion entry to the last content revision (issue #4635).
162bde879aSAndreas Gohr     */
172bde879aSAndreas Gohr    public function testRevisionBeforeNormalDeletion()
182bde879aSAndreas Gohr    {
192bde879aSAndreas Gohr        $page = 'changelog_deleted';
202bde879aSAndreas Gohr        saveWikiText($page, 'first content', 'create', false);
212bde879aSAndreas Gohr        $this->waitForTick(true);
222bde879aSAndreas Gohr        saveWikiText($page, 'second content longer', 'edit', false);
232bde879aSAndreas Gohr        $this->waitForTick(true);
242bde879aSAndreas Gohr
252bde879aSAndreas Gohr        $editRev = (new PageChangeLog($page))->currentRevision();
262bde879aSAndreas Gohr
272bde879aSAndreas Gohr        saveWikiText($page, '', 'delete', false);
282bde879aSAndreas Gohr        clearstatcache();
292bde879aSAndreas Gohr
302bde879aSAndreas Gohr        $changelog = new PageChangeLog($page);
312bde879aSAndreas Gohr        $delRev = $changelog->currentRevision();
322bde879aSAndreas Gohr
332bde879aSAndreas Gohr        $this->assertNotEquals($editRev, $delRev, 'deletion should get its own revision');
342bde879aSAndreas Gohr        $this->assertEquals(
352bde879aSAndreas Gohr            DOKU_CHANGE_TYPE_DELETE,
362bde879aSAndreas Gohr            $changelog->getRevisionInfo($delRev)['type'],
372bde879aSAndreas Gohr            'current revision should be the deletion'
382bde879aSAndreas Gohr        );
392bde879aSAndreas Gohr        $this->assertEquals(
402bde879aSAndreas Gohr            $editRev,
412bde879aSAndreas Gohr            $changelog->getRelativeRevision($delRev, -1),
422bde879aSAndreas Gohr            'the revision before the deletion should be the last edit'
432bde879aSAndreas Gohr        );
442bde879aSAndreas Gohr    }
452bde879aSAndreas Gohr
462bde879aSAndreas Gohr    /**
472bde879aSAndreas Gohr     * An external deletion is detected and persisted on first read as its own revision
482bde879aSAndreas Gohr     * with an unknown exact date, newer than the last content revision.
492bde879aSAndreas Gohr     * getRelativeRevision() must walk back from it to that last content revision
502bde879aSAndreas Gohr     * (issue #4635).
512bde879aSAndreas Gohr     */
522bde879aSAndreas Gohr    public function testRevisionBeforeExternalDeletion()
532bde879aSAndreas Gohr    {
542bde879aSAndreas Gohr        $page = 'changelog_extdeleted';
552bde879aSAndreas Gohr        saveWikiText($page, 'first content', 'create', false);
562bde879aSAndreas Gohr        $this->waitForTick(true);
572bde879aSAndreas Gohr        saveWikiText($page, 'second content longer', 'edit', false);
582bde879aSAndreas Gohr        $this->waitForTick(true);
592bde879aSAndreas Gohr
602bde879aSAndreas Gohr        $editRev = (new PageChangeLog($page))->currentRevision();
612bde879aSAndreas Gohr
622bde879aSAndreas Gohr        // delete the page file externally, bypassing DokuWiki
632bde879aSAndreas Gohr        unlink(wikiFN($page));
642bde879aSAndreas Gohr        clearstatcache();
652bde879aSAndreas Gohr
662bde879aSAndreas Gohr        // first read detects and persists the external deletion
672bde879aSAndreas Gohr        $changelog = new PageChangeLog($page);
682bde879aSAndreas Gohr        $delRev = $changelog->currentRevision();
692bde879aSAndreas Gohr        $delInfo = $changelog->getRevisionInfo($delRev);
702bde879aSAndreas Gohr
712bde879aSAndreas Gohr        $this->assertNotEquals($editRev, $delRev, 'external deletion should get its own revision');
722bde879aSAndreas Gohr        $this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $delInfo['type'], 'current revision should be the deletion');
732bde879aSAndreas Gohr        $this->assertFalse($delInfo['timestamp'], 'external deletion has an unknown exact date');
742bde879aSAndreas Gohr        $this->assertEquals(
752bde879aSAndreas Gohr            $editRev,
762bde879aSAndreas Gohr            $changelog->getRelativeRevision($delRev, -1),
772bde879aSAndreas Gohr            'the revision before the external deletion should be the last edit'
782bde879aSAndreas Gohr        );
792bde879aSAndreas Gohr    }
80*0a245329SAndreas Gohr
81*0a245329SAndreas Gohr    /**
82*0a245329SAndreas Gohr     * A current revision's file can have its modification time bumped without any content
83*0a245329SAndreas Gohr     * change (a backup restore, a git checkout, ...). That must not be recorded as an
84*0a245329SAndreas Gohr     * external edit: the content is compared against the last revision and, when identical,
85*0a245329SAndreas Gohr     * the file mtime is reset to the recorded revision date instead (issue #4634).
86*0a245329SAndreas Gohr     */
87*0a245329SAndreas Gohr    public function testTouchedFileWithUnchangedContentIsNotExternalEdit()
88*0a245329SAndreas Gohr    {
89*0a245329SAndreas Gohr        $page = 'changelog_touched';
90*0a245329SAndreas Gohr        saveWikiText($page, 'first content', 'create', false);
91*0a245329SAndreas Gohr
92*0a245329SAndreas Gohr        $changelog = new PageChangeLog($page);
93*0a245329SAndreas Gohr        $lastRev = $changelog->currentRevision();
94*0a245329SAndreas Gohr
95*0a245329SAndreas Gohr        // bump the file mtime forward without changing the content
96*0a245329SAndreas Gohr        touch(wikiFN($page), $lastRev + 1000);
97*0a245329SAndreas Gohr        clearstatcache();
98*0a245329SAndreas Gohr
99*0a245329SAndreas Gohr        $changelog = new PageChangeLog($page);
100*0a245329SAndreas Gohr        $currentRev = $changelog->currentRevision();
101*0a245329SAndreas Gohr        $currentInfo = $changelog->getRevisionInfo($currentRev);
102*0a245329SAndreas Gohr
103*0a245329SAndreas Gohr        $this->assertEquals($lastRev, $currentRev, 'unchanged content must not create an external revision');
104*0a245329SAndreas Gohr        $this->assertArrayNotHasKey('timestamp', $currentInfo, 'should not be a synthesized external edit');
105*0a245329SAndreas Gohr        $this->assertCount(1, $changelog->getRevisions(-1, 200), 'no external edit entry should be added');
106*0a245329SAndreas Gohr
107*0a245329SAndreas Gohr        clearstatcache();
108*0a245329SAndreas Gohr        $this->assertEquals($lastRev, filemtime(wikiFN($page)), 'file mtime should be reset to the changelog date');
109*0a245329SAndreas Gohr    }
1102bde879aSAndreas Gohr}
111