1<?php
2
3namespace dokuwiki\test\Treebuilder;
4
5use dokuwiki\TreeBuilder\PageTreeBuilder;
6use DokuWikiTest;
7
8class PageTreeBuilderTest extends DokuWikiTest
9{
10    protected $originalDataDir;
11
12    public static function setUpBeforeClass(): void
13    {
14        parent::setUpBeforeClass();
15
16        // Create a test page hierarchy
17        saveWikiText('namespace:start', 'This is the start page', 'test');
18        saveWikiText('namespace:page1', 'This is page 1', 'test');
19        saveWikiText('namespace:page2', 'This is page 2', 'test');
20        saveWikiText('namespace:subns:start', 'This is the subns start page', 'test');
21        saveWikiText('namespace:subns:page3', 'This is page 3 in subns', 'test');
22        saveWikiText('namespace:subns:deeper:start', 'This is the deeper start page', 'test');
23        saveWikiText('namespace:subns:deeper:page4', 'This is page 4 in deeper', 'test');
24    }
25
26    public function setUp(): void
27    {
28        parent::setUp();
29        global $conf;
30        $this->originalDataDir = $conf['datadir'];
31    }
32
33    public function tearDown(): void
34    {
35        global $conf;
36        $conf['datadir'] = $this->originalDataDir;
37        parent::tearDown();
38    }
39
40    public function treeConfigProvider()
41    {
42        return [
43            'Default configuration' => [
44                'namespace' => 'namespace',
45                'depth' => -1,
46                'flags' => 0,
47                'expected' => [
48                    '+namespace:start',
49                    '+namespace:page1',
50                    '+namespace:page2',
51                    '+namespace:subns',
52                    '++namespace:subns:start',
53                    '++namespace:subns:page3',
54                    '++namespace:subns:deeper',
55                    '+++namespace:subns:deeper:start',
56                    '+++namespace:subns:deeper:page4'
57                ]
58            ],
59            'Depth limit 1' => [
60                'namespace' => 'namespace',
61                'depth' => 1,
62                'flags' => 0,
63                'expected' => [
64                    '+namespace:start',
65                    '+namespace:page1',
66                    '+namespace:page2',
67                    '+namespace:subns',
68                    '++namespace:subns:start',
69                    '++namespace:subns:page3',
70                    '++namespace:subns:deeper'
71                ]
72            ],
73            'Depth limit 1 with NS_AS_STARTPAGE' => [
74                'namespace' => 'namespace',
75                'depth' => 1,
76                'flags' => PageTreeBuilder::FLAG_NS_AS_STARTPAGE,
77                'expected' => [
78                    '+namespace:page1',
79                    '+namespace:page2',
80                    '+namespace:subns:start',
81                    '++namespace:subns:page3',
82                    '++namespace:subns:deeper:start'
83                ]
84            ],
85            'FLAG_NO_NS' => [
86                'namespace' => 'namespace',
87                'depth' => -1,
88                'flags' => PageTreeBuilder::FLAG_NO_NS,
89                'expected' => [
90                    '+namespace:start',
91                    '+namespace:page1',
92                    '+namespace:page2'
93                ]
94            ],
95            'FLAG_NO_PAGES' => [
96                'namespace' => 'namespace',
97                'depth' => -1,
98                'flags' => PageTreeBuilder::FLAG_NO_PAGES,
99                'expected' => [
100                    '+namespace:subns',
101                    '++namespace:subns:deeper'
102                ]
103            ],
104            'FLAG_NS_AS_STARTPAGE' => [
105                'namespace' => 'namespace',
106                'depth' => -1,
107                'flags' => PageTreeBuilder::FLAG_NS_AS_STARTPAGE,
108                'expected' => [
109                    '+namespace:page1',
110                    '+namespace:page2',
111                    '+namespace:subns:start',
112                    '++namespace:subns:page3',
113                    '++namespace:subns:deeper:start',
114                    '+++namespace:subns:deeper:page4'
115                ]
116            ],
117            'Combined FLAG_NO_NS and FLAG_NS_AS_STARTPAGE' => [
118                'namespace' => 'namespace',
119                'depth' => -1,
120                'flags' => PageTreeBuilder::FLAG_NO_NS | PageTreeBuilder::FLAG_NS_AS_STARTPAGE,
121                'expected' => [
122                    '+namespace:page1',
123                    '+namespace:page2'
124                ]
125            ],
126            'FLAG_SELF_TOP' => [
127                'namespace' => 'namespace',
128                'depth' => -1,
129                'flags' => PageTreeBuilder::FLAG_SELF_TOP,
130                'expected' => [
131                    '+namespace',
132                    '++namespace:start',
133                    '++namespace:page1',
134                    '++namespace:page2',
135                    '++namespace:subns',
136                    '+++namespace:subns:start',
137                    '+++namespace:subns:page3',
138                    '+++namespace:subns:deeper',
139                    '++++namespace:subns:deeper:start',
140                    '++++namespace:subns:deeper:page4'
141                ]
142            ],
143        ];
144    }
145
146
147    /**
148     * @dataProvider treeConfigProvider
149     */
150    public function testPageTreeConfigurations(string $namespace, int $depth, int $flags, array $expected)
151    {
152        $tree = new PageTreeBuilder($namespace, $depth);
153        if ($flags) {
154            $tree->addFlag($flags);
155        }
156        $tree->generate();
157
158        $result = explode("\n", (string)$tree);
159        sort($expected);
160        sort($result);
161
162        $this->assertEquals($expected, $result);
163    }
164
165    /**
166     * This is the same test as above, but pretending that our data directory is in our test namespace.
167     *
168     * @dataProvider treeConfigProvider
169     */
170    public function testTopLevelTree(string $namespace, int $depth, int $flags, array $expected)
171    {
172        global $conf;
173        $conf['datadir'] .= '/namespace';
174
175        $expected = array_map(function ($item) use ($namespace) {
176            return preg_replace('/namespace:?/', '', $item);
177        }, $expected);
178
179        $namespace = '';
180        $this->testPageTreeConfigurations($namespace, $depth, $flags, $expected);
181    }
182
183
184    public function testPageTreeLeaves()
185    {
186        $tree = new PageTreeBuilder('namespace');
187        $tree->generate();
188
189        $leaves = $tree->getLeaves();
190        $branches = $tree->getBranches();
191
192        // Test that we have both leaves and branches
193        $this->assertGreaterThan(0, count($leaves), 'Should have leaf pages');
194        $this->assertGreaterThan(0, count($branches), 'Should have branch pages');
195
196        // The total should equal all pages
197        $this->assertEquals(count($tree->getAll()), count($leaves) + count($branches),
198            'Leaves + branches should equal total pages');
199    }
200}
201