xref: /plugin/struct/_test/AggregationResultsTest.php (revision c0f1a2d1add0af94d83a1f75f04bdfd9ba698611)
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            $accessSerial = MockAccessTableAlias::getSerialAccess('schema1', "test$i");
57            $accessSerial->saveData($data);
58            $accessPage = MockAccessTableAlias::getPageAccess('schema1', "test$i");
59            $accessPage->saveData($data);
60        }
61    }
62
63    /**
64     * Test whether serial syntax produces a table of serial data limited to current page
65     */
66    public function test_pid()
67    {
68        // \syntax_plugin_struct_serial accesses the global $ID
69        $id = 'test1';
70        $schema = 'schema1';
71        $result = $this->fetchNonPageResults($schema, $id);
72
73        $this->assertCount(1, $result);
74        $this->assertEquals('test1', $result[0][0]->getValue());
75        // skip %rowid% column and test saved values
76        $this->assertEquals('foo1', $result[0][2]->getValue());
77        $this->assertEquals(['green', 'blue'], $result[0][3]->getValue());
78        $this->assertEquals('foobar1', $result[0][4]->getValue());
79        $this->assertEquals('barfoo1', $result[0][5]->getValue());
80    }
81
82    /**
83     * Test simple text filter
84     */
85    public function test_filter_text()
86    {
87        $schema = 'schema1';
88        $result = $this->fetchNonPageResults($schema, 'test0');
89        $this->assertCount(1, $result);
90
91        $result = $this->fetchNonPageResults($schema, 'test0', ['first', '=', 'foo0', 'AND']);
92        $this->assertCount(1, $result);
93
94        $result = $this->fetchNonPageResults($schema, 'test0', ['first', '!=', 'foo0', 'AND']);
95        $this->assertCount(0, $result);
96    }
97
98    /** @noinspection PhpUnreachableStatementInspection */
99    public function test_filter_multi()
100    {
101        $schema = 'schema1';
102        $result = $this->fetchAllResults($schema, '');
103        $this->assertCount(6, $result);
104
105        $result = $this->fetchAllResults($schema, '', ['second', '=', 'green', 'AND']);
106        $this->assertCount(4, $result);
107
108        $this->markTestIncomplete('negative filters currently do not work on multi fields. See #512');
109
110        $result = $this->fetchAllResults($schema, '', ['second', '!~', 'green', 'AND']);
111        $this->assertCount(2, $result);
112    }
113
114    /**
115     * Test filtering on a page field, with 'usetitles' set to true and false
116     */
117    public function test_filter_page()
118    {
119        $this->prepareLookup();
120        $schema = 'pageschema';
121        $result = $this->fetchNonPageResults($schema);
122        $this->assertCount(3, $result);
123
124        // 'usetitles' = true
125        $result = $this->fetchNonPageResults($schema, '', ['singletitle', '*~', 'another', 'AND']);
126        $this->assertCount(1, $result);
127
128        // 'usetitles' = false
129        $result = $this->fetchNonPageResults($schema, '', ['singlepage', '*~', 'this', 'AND']);
130        $this->assertCount(0, $result);
131    }
132
133    /**
134     * Test filtering on a DateTime field
135     */
136    public function test_filter_datetime()
137    {
138        $this->prepareDatetime();
139        $schema = 'datetime';
140        $result = $this->fetchNonPageResults($schema);
141        $this->assertCount(3, $result);
142
143        $result = $this->fetchNonPageResults($schema, '', ['field', '<', '2023-01-02', 'AND']);
144        $this->assertCount(1, $result);
145
146        $result = $this->fetchNonPageResults($schema, '', ['field', '<', '2023-01-01 11:00', 'AND']);
147        $this->assertCount(0, $result);
148    }
149
150    /**
151     * Test whether aggregation tables respect revoking of schema assignments
152     */
153    public function test_assignments()
154    {
155        $result = $this->fetchAllResults('schema1');
156        $this->assertCount(6, $result);
157
158        // revoke assignment
159        $assignments = mock\Assignments::getInstance();
160        $assignments->deassignPageSchema('test0', 'schema1');
161
162        $result = $this->fetchAllResults('schema1');
163        $this->assertCount(5, $result);
164    }
165
166
167    /**
168     * Initialize a table from syntax and return the result from its internal search.
169     *
170     * @param string $schema
171     * @param string $id
172     * @param array $filters
173     * @return \dokuwiki\plugin\struct\meta\Value[][]
174     */
175    protected function fetchAllResults($schema, $id = '', $filters = [])
176    {
177        $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *'];
178        $configParser = new ConfigParser($syntaxConfig);
179        $config = $configParser->getConfig();
180
181        if ($filters) $config['filter'][] = $filters;
182        $search = new MockSearchConfigAlias($config);
183
184        $table = new MockAggregationTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search);
185        return $table->getResult();
186    }
187
188    /**
189     * Initialize a lookup table from syntax and return the result from its internal search.
190     *
191     * @param string $schema
192     * @param string $id
193     * @param array $filters
194     * @return \dokuwiki\plugin\struct\meta\Value[][]
195     */
196    protected function fetchNonPageResults($schema, $id = '', $filters = [])
197    {
198        $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *'];
199        $configParser = new ConfigParser($syntaxConfig);
200        $config = $configParser->getConfig();
201
202        // simulate addYypeFilter() from \syntax_plugin_struct_serial and \syntax_plugin_struct_lookup
203        if ($id) {
204            $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND'];
205            $config['filter'][] = ['%pageid%', '=', $id, 'AND'];
206        } else {
207            $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND'];
208            $config['filter'][] = ['%pageid%', '=*', '^(?![\s\S])', 'AND'];
209        }
210
211        if ($filters) $config['filter'][] = $filters;
212        $search = new MockSearchConfigAlias($config);
213
214        $table = new MockAggregationEditorTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search);
215        return $table->getResult();
216    }
217
218    protected function prepareLookup()
219    {
220        saveWikiText('title1', 'test', 'test');
221        $pageMeta = new PageMeta('title1');
222        $pageMeta->setTitle('This is a title');
223
224        saveWikiText('title2', 'test', 'test');
225        $pageMeta = new PageMeta('title2');
226        $pageMeta->setTitle('This is a 2nd title');
227
228        saveWikiText('title3', 'test', 'test');
229        $pageMeta = new PageMeta('title3');
230        $pageMeta->setTitle('Another Title');
231
232        $this->loadSchemaJSON('pageschema');
233        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
234        $access->saveData(
235            [
236                'singlepage' => 'title1',
237                'multipage' => ['title1'],
238                'singletitle' => 'title1',
239                'multititle' => ['title1'],
240            ]
241        );
242        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
243        $access->saveData(
244            [
245                'singlepage' => 'title2',
246                'multipage' => ['title2'],
247                'singletitle' => 'title2',
248                'multititle' => ['title2'],
249            ]
250        );
251        $access = MockAccessTableAlias::getGlobalAccess('pageschema');
252        $access->saveData(
253            [
254                'singlepage' => 'title3',
255                'multipage' => ['title3'],
256                'singletitle' => 'title3',
257                'multititle' => ['title3'],
258            ]
259        );
260    }
261
262    protected function prepareDatetime()
263    {
264        $this->loadSchemaJSON('datetime');
265        $access = MockAccessTableAlias::getGlobalAccess('datetime');
266        $access->saveData(['field' => '2023-01-01 12:00']);
267        $access = MockAccessTableAlias::getGlobalAccess('datetime');
268        $access->saveData(['field' => '2023-01-02 00:00']);
269        $access = MockAccessTableAlias::getGlobalAccess('datetime');
270        $access->saveData(['field' => '2023-01-02 12:00']);
271    }
272}
273