Skip to content

Commit c9611dc

Browse files
authored
Merge pull request dokuwiki#4423 from dokuwiki/treebuilder
Add experimental tree builder classes
2 parents e206a49 + a8e9ec0 commit c9611dc

File tree

14 files changed

+1421
-0
lines changed

14 files changed

+1421
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
namespace dokuwiki\test\Treebuilder;
4+
5+
use dokuwiki\TreeBuilder\ControlPageBuilder;
6+
use DokuWikiTest;
7+
8+
class ControlPageBuilderTest extends DokuWikiTest
9+
{
10+
public static function setUpBeforeClass(): void
11+
{
12+
parent::setUpBeforeClass();
13+
saveWikiText('simple', file_get_contents(__DIR__ . '/cp/simple.txt'), 'test');
14+
saveWikiText('foo:complex', file_get_contents(__DIR__ . '/cp/complex.txt'), 'test');
15+
}
16+
17+
public function testSimpleParsing()
18+
{
19+
$control = new ControlPageBuilder('simple');
20+
$control->generate();
21+
22+
$expected = [
23+
'+briefs:start',
24+
'+qhsr:start',
25+
'++qhsr:q',
26+
'++qhsr:cert',
27+
'++qhsr:hse:start',
28+
'++qhsr:engsystems',
29+
'++qhsr:performance',
30+
'++qhsr:competence',
31+
'++qhsr:ashford',
32+
'++qhsr:training',
33+
'+tech:start',
34+
'+https://homepage.company.com'
35+
];
36+
37+
$result = explode("\n", (string)$control);
38+
sort($expected);
39+
sort($result);
40+
41+
$this->assertEquals($expected, $result);
42+
43+
// Additional structure tests
44+
$top = $control->getTop();
45+
$this->assertEquals(4, count($top->getChildren()));
46+
$this->assertEquals(1, count($top->getChildren()[0]->getParents()));
47+
$this->assertEquals(4, count($top->getChildren()[1]->getSiblings()));
48+
$this->assertEquals(8, count($top->getChildren()[1]->getChildren()));
49+
50+
$this->assertEquals(12, count($control->getAll()));
51+
$this->assertEquals(11, count($control->getLeaves()));
52+
$this->assertEquals(1, count($control->getBranches()));
53+
}
54+
55+
/**
56+
* Parse the complex example with different flags
57+
*
58+
* @return array[]
59+
* @see testComplexParsing
60+
*/
61+
public function complexProvider()
62+
{
63+
return [
64+
'No flags' => [
65+
'flags' => 0,
66+
'expected' => [
67+
'+content',
68+
'+foo:this',
69+
'+foo:bar',
70+
'+foo:another_link',
71+
'+https://www.google.com',
72+
'+relativeup',
73+
'+foo2:this',
74+
'++foo2:deeper:item',
75+
'+++foo2:deeper:evendeeper:item',
76+
'+foo:blarg:down',
77+
'+toplevel',
78+
'+foo:link',
79+
]
80+
],
81+
'FLAG_NOEXTERNAL' => [
82+
'flags' => ControlPageBuilder::FLAG_NOEXTERNAL,
83+
'expected' => [
84+
'+content',
85+
'+foo:this',
86+
'+foo:bar',
87+
'+foo:another_link',
88+
'+relativeup',
89+
'+foo2:this',
90+
'++foo2:deeper:item',
91+
'+++foo2:deeper:evendeeper:item',
92+
'+foo:blarg:down',
93+
'+toplevel',
94+
'+foo:link',
95+
]
96+
],
97+
'FLAG_NOINTERNAL' => [
98+
'flags' => ControlPageBuilder::FLAG_NOINTERNAL,
99+
'expected' => [
100+
'+https://www.google.com',
101+
]
102+
],
103+
];
104+
}
105+
106+
/**
107+
* @dataProvider complexProvider
108+
* @param int $flags
109+
* @param array $expected
110+
* @return void
111+
*/
112+
public function testComplexParsing(int $flags, array $expected)
113+
{
114+
$control = new ControlPageBuilder('foo:complex');
115+
$control->addFlag($flags);
116+
$control->generate();
117+
118+
$result = explode("\n", (string)$control);
119+
sort($expected);
120+
sort($result);
121+
122+
$this->assertEquals($expected, $result);
123+
}
124+
125+
public function testNonExisting()
126+
{
127+
$this->expectException(\RuntimeException::class);
128+
$control = new ControlPageBuilder('does:not:exist');
129+
$control->generate();
130+
$foo = $control->getAll();
131+
}
132+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
<?php
2+
3+
namespace dokuwiki\test\Treebuilder;
4+
5+
use dokuwiki\TreeBuilder\PageTreeBuilder;
6+
use DokuWikiTest;
7+
8+
class 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+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
====== this is the Control ======
2+
3+
It has all kinds of [[:content]]. But also Links.
4+
5+
* This is not a link
6+
* [[this]] is
7+
* [[foo:bar]] is also a link
8+
* [[Another Link]]
9+
* [[https://www.google.com|External links]] are not lessons
10+
11+
We have two lists here
12+
13+
* [[foo:bar|duplicates]] will be ignored in the order
14+
* [[..:relativeup]]
15+
* [[foo2:this]]
16+
* [[foo2:deeper:item|Deeper Item]]
17+
* [[foo2:deeper:evendeeper:item|Even Deeper Item]]
18+
* [[.:blarg:down]]
19+
* [[:toplevel]]
20+
21+
Here is more and another [[link]].
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
* [[briefs:start|Briefs]]
2+
* [[qhsr:start|QHSR]]
3+
* [[qhsr:q|Quality]]
4+
* [[qhsr:cert|Certification]]
5+
* [[qhsr:hse:start|HSE]]
6+
* [[qhsr:engsystems|Eng Systems]]
7+
* [[qhsr:performance|Eng Performance]]
8+
* [[qhsr:competence|Eng Competence]]
9+
* [[qhsr:ashford|Ashford DFO]]
10+
* [[qhsr:training|Technical Training]]
11+
* [[tech:start|Tech Info]]
12+
* [[https://homepage.company.com|Company Homepage]]

0 commit comments

Comments
 (0)