1<?php 2 3namespace dokuwiki\plugin\dw2pdf\test; 4 5use dokuwiki\plugin\dw2pdf\src\BookCreatorLiveSelectionCollector; 6use dokuwiki\plugin\dw2pdf\src\Cache; 7use dokuwiki\plugin\dw2pdf\src\Config; 8use dokuwiki\plugin\dw2pdf\src\ExportException; 9use dokuwiki\plugin\dw2pdf\src\PdfExportService; 10use dokuwiki\test\mock\AuthPlugin; 11use DokuWikiTest; 12 13/** 14 * Tests the feedback given when an export yields no usable pages 15 * 16 * @group plugin_dw2pdf 17 * @group plugins 18 */ 19class ExportFeedbackTest extends DokuWikiTest 20{ 21 /** @var string[] Plugins to enable for these tests */ 22 protected $pluginsEnabled = ['dw2pdf']; 23 24 /** @var array|null Saved ACL rules to restore after each test */ 25 protected $oldAuthAcl; 26 27 public function setUp(): void 28 { 29 parent::setUp(); 30 $_REQUEST = []; 31 32 global $AUTH_ACL, $auth; 33 $this->oldAuthAcl = $AUTH_ACL; 34 $auth = new AuthPlugin(); 35 } 36 37 public function tearDown(): void 38 { 39 global $AUTH_ACL; 40 $AUTH_ACL = $this->oldAuthAcl; 41 parent::tearDown(); 42 } 43 44 /** 45 * Deny read access to everybody 46 */ 47 protected function denyAll(): void 48 { 49 global $conf, $AUTH_ACL; 50 $conf['useacl'] = 1; 51 $AUTH_ACL = ['* @ALL 0']; 52 } 53 54 /** 55 * When every selected page is unreadable, they are dropped from the export but remembered. 56 */ 57 public function testForbiddenPagesArePartitioned(): void 58 { 59 global $INPUT; 60 $pageA = 'playground:secret:a'; 61 $pageB = 'playground:secret:b'; 62 saveWikiText($pageA, 'A', 'create'); 63 saveWikiText($pageB, 'B', 'create'); 64 65 $this->denyAll(); 66 $INPUT->set('selection', json_encode([$pageA, $pageB])); 67 68 $collector = new BookCreatorLiveSelectionCollector(new Config()); 69 $this->assertSame([], $collector->getPages()); 70 $this->assertSame([$pageA, $pageB], $collector->getSkippedPages()); 71 } 72 73 /** 74 * Readable pages are kept while forbidden ones are skipped (always-skip behavior). 75 */ 76 public function testMixedAccessKeepsReadablePages(): void 77 { 78 global $INPUT, $conf, $AUTH_ACL; 79 $readable = 'playground:public:a'; 80 $secret = 'playground:secret:b'; 81 saveWikiText($readable, 'A', 'create'); 82 saveWikiText($secret, 'B', 'create'); 83 84 $conf['useacl'] = 1; 85 $AUTH_ACL = [ 86 '* @ALL 8', 87 'playground:secret:* @ALL 0', 88 ]; 89 $INPUT->set('selection', json_encode([$readable, $secret])); 90 91 $collector = new BookCreatorLiveSelectionCollector(new Config()); 92 $this->assertSame([$readable], $collector->getPages()); 93 $this->assertSame([$secret], $collector->getSkippedPages()); 94 } 95 96 /** 97 * An export where every page is forbidden reports only how many pages were skipped. 98 */ 99 public function testServiceThrowsForbiddenWhenAllSkipped(): void 100 { 101 $pageA = 'playground:secret:a'; 102 saveWikiText($pageA, 'A', 'create'); 103 $this->denyAll(); 104 105 $service = $this->makeService([$pageA]); 106 107 try { 108 $service->getDebugHtml(); 109 $this->fail('Expected ExportException was not thrown'); 110 } catch (ExportException $e) { 111 $this->assertSame('forbidden', $e->getMessage()); 112 $this->assertSame([], $e->getArgs(), 'No details about the skipped pages should be exposed'); 113 } 114 } 115 116 /** 117 * An export with no selection at all reports an empty selection. 118 */ 119 public function testServiceThrowsEmptyWhenNothingSelected(): void 120 { 121 $service = $this->makeService([]); 122 123 $this->expectException(ExportException::class); 124 $this->expectExceptionMessage('empty'); 125 $service->getDebugHtml(); 126 } 127 128 /** 129 * Build a debug PdfExportService for a live book selection. 130 * 131 * @param string[] $selection Page ids to export 132 * @return PdfExportService 133 */ 134 protected function makeService(array $selection): PdfExportService 135 { 136 $config = new Config(['debug' => 1, 'liveselection' => json_encode($selection)]); 137 $collector = new BookCreatorLiveSelectionCollector($config); 138 $cache = new Cache($config, $collector); 139 return new PdfExportService($config, $collector, $cache, 'Contents', 'tester'); 140 } 141} 142