xref: /plugin/struct/_test/AggregationResultsTest.php (revision 299ca8cc642c152679238a0fa0ee3d839791f6b6)
1<?php
2
3namespace dokuwiki\plugin\struct\test;
4
5use dokuwiki\plugin\struct\meta\AccessTablePage;
6use dokuwiki\plugin\struct\meta\ConfigParser;
7use dokuwiki\plugin\struct\meta\PageMeta;
8use dokuwiki\plugin\struct\test\mock\AccessTable as MockAccessTableAlias;
9use dokuwiki\plugin\struct\test\mock\AggregationEditorTable as MockAggregationEditorTableAlias;
10use dokuwiki\plugin\struct\test\mock\AggregationTable as MockAggregationTableAlias;
11use dokuwiki\plugin\struct\test\mock\SearchConfig as MockSearchConfigAlias;
12
13/**
14 * Testing serial data
15 *
16 * @group plugin_struct
17 * @group plugins
18 */
19class AggregationResultsTest extends StructTest
20{
21    protected $sqlite;
22
23    public function setUp(): void
24    {
25        parent::setUp();
26
27        $sqlite = plugin_load('helper', 'struct_db');
28        $this->sqlite = $sqlite->getDB();
29
30        $this->loadSchemaJSON('schema1');
31
32        $assignments = mock\Assignments::getInstance();
33        $assignments->clear(true);
34
35        // different values for each entry
36        $second = [
37            ['green', 'red'],
38            ['green', 'blue'],
39            ['blue', 'yellow']
40        ];
41
42        for ($i = 0; $i < 3; $i++) {
43            // assign a schema
44            $assignments->assignPageSchema("test$i", 'schema1');
45
46            // save wiki pages
47            saveWikiText("test$i", "test$i", "test$i");
48
49            // save serial data
50            $data = [
51                'first' => "foo$i",
52                'second' => $second[$i],
53                'third' => "foobar$i",
54                'fourth' => "barfoo$i",
55            ];
56            $access = MockAccessTableAlias::getSerialAccess('schema1', "test$i");
57            $access->saveData($data);
58        }
59    }
60
61    /**
62     * Test whether serial syntax produces a table of serial data limited to current page
63     */
64    public function test_pid()
65    {
66        // \syntax_plugin_struct_serial accesses the global $ID
67        $id = 'test1';
68        $schema = 'schema1';
69        $result = $this->fetchResult($schema, $id);
70
71        $this->assertCount(1, $result);
72        $this->assertEquals('test1', $result[0][0]->getValue());
73        // skip %rowid% column and test saved values
74        $this->assertEquals('foo1', $result[0][2]->getValue());
75        $this->assertEquals(['green', 'blue'], $result[0][3]->getValue());
76        $this->assertEquals('foobar1', $result[0][4]->getValue());
77        $this->assertEquals('barfoo1', $result[0][5]->getValue());
78    }
79
80    /**
81     * Test simple text filter
82     */
83    public function test_filter_text()
84    {
85        $schema = 'schema1';
86        $result = $this->fetchResult($schema, 'test0');
87        $this->assertCount(1, $result);
88
89        $result = $this->fetchResult($schema, 'test0', ['first', '=', 'foo0', 'AND']);
90        $this->assertCount(1, $result);
91
92        $result = $this->fetchResult($schema, 'test0', ['first', '!=', 'foo0', 'AND']);
93        $this->assertCount(0, $result);
94    }
95
96    /** @noinspection PhpUnreachableStatementInspection */
97    public function test_filter_multi()
98    {
99        $schema = 'schema1';
100        $result = $this->fetchPagesResult($schema, '');
101        $this->assertCount(3, $result);
102
103        $result = $this->fetchPagesResult($schema, '', ['second', '=', 'green', 'AND']);
104        $this->assertCount(2, $result);
105
106        $this->markTestIncomplete('negative filters currently do not work on multi fields. See #512');
107
108        $result = $this->fetchPagesResult($schema, '', ['second', '!~', 'green', 'AND']);
109        $this->assertCount(1, $result);
110    }
111
112    /**
113     * Test filtering on a page field, with 'usetitles' set to true and false
114     */
115    public function test_filter_page()
116    {
117        $this->prepareLookup();
118        $schema = 'pageschema';
119        $result = $this->fetchResult($schema);
120        $this->assertCount(3, $result);
121
122        // 'usetitles' = true
123        $result = $this->fetchResult($schema, '', ['singletitle', '*~', 'another', 'AND']);
124        $this->assertCount(1, $result);
125
126        // 'usetitles' = false
127        $result = $this->fetchResult($schema, '', ['singlepage', '*~', 'this', 'AND']);
128        $this->assertCount(0, $result);
129    }
130
131    /**
132     * Test filtering on a DateTime field
133     */
134    public function test_filter_datetime()
135    {
136        $this->prepareDatetime();
137        $schema = 'datetime';
138        $result = $this->fetchResult($schema);
139        $this->assertCount(3, $result);
140
141        $result = $this->fetchResult($schema, '', ['field', '<', '2023-01-02', 'AND']);
142        $this->assertCount(1, $result);
143
144        $result = $this->fetchResult($schema, '', ['field', '<', '2023-01-01 11:00', 'AND']);
145        $this->assertCount(0, $result);
146    }
147
148    /**
149     * Test whether aggregation tables respect revoking of schema assignments
150     */
151    public function test_assignments()
152    {
153        $result = $this->fetchPagesResult('schema1');
154        $this->assertCount(3, $result);
155
156        // revoke assignment
157        $assignments = mock\Assignments::getInstance();
158        $assignments->deassignPageSchema('test0', 'schema1');
159
160        $result = $this->fetchPagesResult('schema1');
161        $this->assertCount(2, $result);
162    }
163
164
165    /**
166     * Initialize a lookup table from syntax and return the result from its internal search.
167     *
168     * @param string $schema
169     * @param string $id
170     * @param array $filters
171     * @return \dokuwiki\plugin\struct\meta\Value[][]
172     */
173    protected function fetchPagesResult($schema, $id = '', $filters = [])
174    {
175        $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *'];
176        $configParser = new ConfigParser($syntaxConfig);
177        $config = $configParser->getConfig();
178
179        if ($filters) $config['filter'][] = $filters;
180        $search = new MockSearchConfigAlias($config);
181
182        $table = new MockAggregationTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search);
183        return $table->getResult();
184    }
185
186    /**
187     * Initialize a lookup table from syntax and return the result from its internal search.
188     *
189     * @param string $schema
190     * @param string $id
191     * @param array $filters
192     * @return \dokuwiki\plugin\struct\meta\Value[][]
193     */
194    protected function fetchResult($schema, $id = '', $filters = [])
195    {
196        $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *'];
197        $configParser = new ConfigParser($syntaxConfig);
198        $config = $configParser->getConfig();
199
200        // FIXME simulate addYypeFilter() from \syntax_plugin_struct_serial or \syntax_plugin_struct_lookup
201        if ($id) {
202            $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND'];
203            $config['filter'][] = ['%pageid%', '=', $id, 'AND'];
204        } else {
205            $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND'];
206            $config['filter'][] = ['%pageid%', '=*', '^(?![\s\S])', 'AND'];
207        }
208
209        if ($filters) $config['filter'][] = $filters;
210        $search = new MockSearchConfigAlias($config);
211
212        $table = new MockAggregationEditorTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search);
213        return $table->getResult();
214    }
215
216    protected function prepareLookup()
217    {
218        saveWikiText('title1', 'test', 'test');
219        $pageMeta = new PageMeta('title1');
220        $pageMeta->setTitle('This is a title');
221
222        saveWikiText('title2', 'test', 'test');
223        $pageMeta = new PageMeta('title2');
224        $pageMeta->setTitle('This is a 2nd title');
225
226        saveWikiText('title3', 'test', 'test');
227        $pageMeta = new PageMeta('title3');
228        $pageMeta->setTitle('Another Title');
229
230        $this->loadSchemaJSON('pageschema');
231        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
232        $access->saveData(
233            [
234                'singlepage' => 'title1',
235                'multipage' => ['title1'],
236                'singletitle' => 'title1',
237                'multititle' => ['title1'],
238            ]
239        );
240        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
241        $access->saveData(
242            [
243                'singlepage' => 'title2',
244                'multipage' => ['title2'],
245                'singletitle' => 'title2',
246                'multititle' => ['title2'],
247            ]
248        );
249        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
250        $access->saveData(
251            [
252                'singlepage' => 'title3',
253                'multipage' => ['title3'],
254                'singletitle' => 'title3',
255                'multititle' => ['title3'],
256            ]
257        );
258    }
259
260    protected function prepareDatetime()
261    {
262        $this->loadSchemaJSON('datetime');
263        $access = MockAccessTableAlias::getGlobalAccess('datetime');
264        $access->saveData(['field' => '2023-01-01 12:00']);
265        $access = MockAccessTableAlias::getGlobalAccess('datetime');
266        $access->saveData(['field' => '2023-01-02 00:00']);
267        $access = MockAccessTableAlias::getGlobalAccess('datetime');
268        $access->saveData(['field' => '2023-01-02 12:00']);
269    }
270}
271