1<?php 2 3namespace dokuwiki\test\ChangeLog; 4 5use dokuwiki\ChangeLog\PageChangeLog; 6 7/** 8 * Tests for dokuwiki\ChangeLog\PageChangeLog. 9 */ 10class PageChangeLogTest extends \DokuWikiTest 11{ 12 /** 13 * A page deleted through DokuWiki is recorded as its own revision, newer than the 14 * last revision that still had content. getRelativeRevision() must walk back from 15 * that deletion entry to the last content revision (issue #4635). 16 */ 17 public function testRevisionBeforeNormalDeletion() 18 { 19 $page = 'changelog_deleted'; 20 saveWikiText($page, 'first content', 'create', false); 21 $this->waitForTick(true); 22 saveWikiText($page, 'second content longer', 'edit', false); 23 $this->waitForTick(true); 24 25 $editRev = (new PageChangeLog($page))->currentRevision(); 26 27 saveWikiText($page, '', 'delete', false); 28 clearstatcache(); 29 30 $changelog = new PageChangeLog($page); 31 $delRev = $changelog->currentRevision(); 32 33 $this->assertNotEquals($editRev, $delRev, 'deletion should get its own revision'); 34 $this->assertEquals( 35 DOKU_CHANGE_TYPE_DELETE, 36 $changelog->getRevisionInfo($delRev)['type'], 37 'current revision should be the deletion' 38 ); 39 $this->assertEquals( 40 $editRev, 41 $changelog->getRelativeRevision($delRev, -1), 42 'the revision before the deletion should be the last edit' 43 ); 44 } 45 46 /** 47 * An external deletion is detected and persisted on first read as its own revision 48 * with an unknown exact date, newer than the last content revision. 49 * getRelativeRevision() must walk back from it to that last content revision 50 * (issue #4635). 51 */ 52 public function testRevisionBeforeExternalDeletion() 53 { 54 $page = 'changelog_extdeleted'; 55 saveWikiText($page, 'first content', 'create', false); 56 $this->waitForTick(true); 57 saveWikiText($page, 'second content longer', 'edit', false); 58 $this->waitForTick(true); 59 60 $editRev = (new PageChangeLog($page))->currentRevision(); 61 62 // delete the page file externally, bypassing DokuWiki 63 unlink(wikiFN($page)); 64 clearstatcache(); 65 66 // first read detects and persists the external deletion 67 $changelog = new PageChangeLog($page); 68 $delRev = $changelog->currentRevision(); 69 $delInfo = $changelog->getRevisionInfo($delRev); 70 71 $this->assertNotEquals($editRev, $delRev, 'external deletion should get its own revision'); 72 $this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $delInfo['type'], 'current revision should be the deletion'); 73 $this->assertFalse($delInfo['timestamp'], 'external deletion has an unknown exact date'); 74 $this->assertEquals( 75 $editRev, 76 $changelog->getRelativeRevision($delRev, -1), 77 'the revision before the external deletion should be the last edit' 78 ); 79 } 80 81 /** 82 * A current revision's file can have its modification time bumped without any content 83 * change (a backup restore, a git checkout, ...). That must not be recorded as an 84 * external edit: the content is compared against the last revision and, when identical, 85 * the file mtime is reset to the recorded revision date instead (issue #4634). 86 */ 87 public function testTouchedFileWithUnchangedContentIsNotExternalEdit() 88 { 89 $page = 'changelog_touched'; 90 saveWikiText($page, 'first content', 'create', false); 91 92 $changelog = new PageChangeLog($page); 93 $lastRev = $changelog->currentRevision(); 94 95 // bump the file mtime forward without changing the content 96 touch(wikiFN($page), $lastRev + 1000); 97 clearstatcache(); 98 99 $changelog = new PageChangeLog($page); 100 $currentRev = $changelog->currentRevision(); 101 $currentInfo = $changelog->getRevisionInfo($currentRev); 102 103 $this->assertEquals($lastRev, $currentRev, 'unchanged content must not create an external revision'); 104 $this->assertArrayNotHasKey('timestamp', $currentInfo, 'should not be a synthesized external edit'); 105 $this->assertCount(1, $changelog->getRevisions(-1, 200), 'no external edit entry should be added'); 106 107 clearstatcache(); 108 $this->assertEquals($lastRev, filemtime(wikiFN($page)), 'file mtime should be reset to the changelog date'); 109 } 110} 111