1<?php
2
3namespace dokuwiki\plugin\struct\test;
4
5use dokuwiki\plugin\struct\meta;
6
7/**
8 * @group plugin_struct
9 * @group plugins
10 *
11 * @covers action_plugin_struct_revert
12 * @covers action_plugin_struct_edit
13 */
14class edit_struct_test extends StructTest
15{
16
17    public function setUp(): void
18    {
19        parent::setUp();
20
21        $this->loadSchemaJSON('schema1');
22        $this->loadSchemaJSON('schema2', 'schema2int');
23        $this->saveData(
24            'page01',
25            'schema1',
26            array(
27                'first' => 'first data',
28                'second' => array('second data', 'more data', 'even more'),
29                'third' => 'third data',
30                'fourth' => 'fourth data'
31            ),
32            time()
33        );
34    }
35
36    protected function checkField(\phpQueryObject $pq, $schema, $name, $value)
37    {
38        $this->assertEquals(1, $pq->find("span.label:contains('$name')")->length, "Field $schema.$name not found");
39        $this->assertEquals($value, $pq->find("input[name='struct_schema_data[$schema][$name]']")->val(), "Field $schema.$name has wrong value");
40    }
41
42    public function test_createForm_storedData()
43    {
44        $edit = new mock\action_plugin_struct_edit();
45        global $ID;
46        $ID = 'page01';
47        $test_html = $edit->createForm('schema1');
48
49        $pq = \phpQuery::newDocument($test_html);
50        $this->assertEquals('schema1', $pq->find('legend')->text());
51        $this->checkField($pq, 'schema1', 'first', 'first data');
52        $this->checkField($pq, 'schema1', 'second', 'second data, more data, even more');
53        $this->checkField($pq, 'schema1', 'third', 'third data');
54        $this->checkField($pq, 'schema1', 'fourth', 'fourth data');
55    }
56
57    public function test_createForm_emptyData()
58    {
59        $edit = new mock\action_plugin_struct_edit();
60        global $ID;
61        $ID = 'page02';
62        $test_html = $edit->createForm('schema1');
63
64        $pq = \phpQuery::newDocument($test_html);
65        $this->assertEquals('schema1', $pq->find('legend')->text());
66        $this->checkField($pq, 'schema1', 'first', '');
67        $this->checkField($pq, 'schema1', 'second', '');
68        $this->checkField($pq, 'schema1', 'third', '');
69        $this->checkField($pq, 'schema1', 'fourth', '');
70    }
71
72    public function test_createForm_postData()
73    {
74        global $INPUT, $ID;
75        $ID = 'page01';
76        $structdata = array(
77            'schema1' => array(
78                'first' => 'first post data',
79                'second' => array('second post data', 'more post data', 'even more post data'),
80                'third' => 'third post data',
81                'fourth' => 'fourth post data'
82            )
83        );
84        $INPUT->set(mock\action_plugin_struct_edit::getVAR(), $structdata);
85
86        $edit = new mock\action_plugin_struct_edit();
87        $test_html = $edit->createForm('schema1');
88
89        $pq = \phpQuery::newDocument($test_html);
90        $this->assertEquals('schema1', $pq->find('legend')->text());
91        $this->checkField($pq, 'schema1', 'first', 'first post data');
92        $this->checkField($pq, 'schema1', 'second', 'second post data, more post data, even more post data');
93        $this->checkField($pq, 'schema1', 'third', 'third post data');
94        $this->checkField($pq, 'schema1', 'fourth', 'fourth post data');
95    }
96
97    public function test_edit_page_wo_schema()
98    {
99        $page = 'test_edit_page_wo_schema';
100
101        $request = new \TestRequest();
102        $response = $request->get(array('id' => $page, 'do' => 'edit'), '/doku.php');
103        $structElement = $response->queryHTML('.struct_entry_form');
104
105        $this->assertEquals(1, count($structElement));
106        $this->assertEquals($structElement->html(), '');
107    }
108
109    public function test_edit_page_with_schema()
110    {
111        $page = 'test_edit_page_with_schema';
112        $assignment = mock\Assignments::getInstance();
113        $schema = 'schema2';
114        $assignment->addPattern($page, $schema);
115
116        $request = new \TestRequest();
117        $response = $request->get(array('id' => $page, 'do' => 'edit'), '/doku.php');
118        $test_html = trim($response->queryHTML('.struct_entry_form')->html());
119
120        $pq = \phpQuery::newDocument($test_html);
121        $this->assertEquals('schema2', $pq->find('legend')->text());
122        $this->checkField($pq, 'schema2', 'afirst', '');
123        $this->checkField($pq, 'schema2', 'asecond', '');
124        $this->checkField($pq, 'schema2', 'athird', '');
125        $this->checkField($pq, 'schema2', 'afourth', '');
126    }
127
128    public function test_preview_page_invaliddata()
129    {
130        $page = 'test_preview_page_invaliddata';
131        $assignment = mock\Assignments::getInstance();
132        $schema = 'schema2';
133        $assignment->addPattern($page, $schema);
134
135        $request = new \TestRequest();
136        $structData = array(
137            $schema => array(
138                'afirst' => 'foo',
139                'asecond' => 'bar, baz',
140                'athird' => 'foobar',
141                'afourth' => 'Eve'
142            )
143        );
144        $request->setPost('struct_schema_data', $structData);
145        $response = $request->post(array('id' => $page, 'do' => 'preview'), '/doku.php');
146        $expected_errormsg = sprintf($this->getLang('validation_prefix') . $this->getLang('Validation Exception Decimal needed'), 'afourth');
147        $actual_errormsg = $response->queryHTML('.error')->html();
148        $test_html = trim($response->queryHTML('.struct_entry_form')->html());
149
150        $this->assertEquals($expected_errormsg, $actual_errormsg, 'If there is invalid data, then there should be an error message.');
151
152        $pq = \phpQuery::newDocument($test_html);
153        $this->assertEquals('schema2', $pq->find('legend')->text());
154        $this->checkField($pq, 'schema2', 'afirst', 'foo');
155        $this->checkField($pq, 'schema2', 'asecond', 'bar, baz');
156        $this->checkField($pq, 'schema2', 'athird', 'foobar');
157        $this->checkField($pq, 'schema2', 'afourth', 'Eve');
158    }
159
160    public function test_preview_page_validdata()
161    {
162        $page = 'test_preview_page_validdata';
163        $assignment = mock\Assignments::getInstance();
164        $schema = 'schema2';
165        $assignment->addPattern($page, $schema);
166
167        $request = new \TestRequest();
168        $structData = array(
169            $schema => array(
170                'afirst' => 'foo',
171                'asecond' => 'bar, baz',
172                'athird' => 'foobar',
173                'afourth' => '42'
174            )
175        );
176        $request->setPost('struct_schema_data', $structData);
177        $response = $request->post(array('id' => $page, 'do' => 'preview'), '/doku.php');
178        $actual_errormsg = $response->queryHTML('.error')->get();
179        $test_html = trim($response->queryHTML('.struct_entry_form')->html());
180
181        $this->assertEquals($actual_errormsg, array(), "If all data is valid, then there should be no error message.");
182
183        $pq = \phpQuery::newDocument($test_html);
184        $this->assertEquals('schema2', $pq->find('legend')->text());
185        $this->checkField($pq, 'schema2', 'afirst', 'foo');
186        $this->checkField($pq, 'schema2', 'asecond', 'bar, baz');
187        $this->checkField($pq, 'schema2', 'athird', 'foobar');
188        $this->checkField($pq, 'schema2', 'afourth', '42');
189    }
190
191    public function test_fail_saving_empty_page()
192    {
193        $page = 'test_fail_saving_empty_page';
194        $assignment = mock\Assignments::getInstance();
195        $schema = 'schema2';
196        $assignment->addPattern($page, $schema);
197
198        $request = new \TestRequest();
199        $structData = array(
200            $schema => array(
201                'afirst' => 'foo',
202                'asecond' => 'bar, baz',
203                'athird' => 'foobar',
204                'afourth' => '42'
205            )
206        );
207        $request->setPost('struct_schema_data', $structData);
208        $request->setPost('summary', 'only struct data saved');
209        $response = $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
210        $expected_errormsg = $this->getLang('emptypage');
211        $actual_errormsg = $response->queryHTML('.error')->html();
212        $pagelog = new \PageChangelog($page);
213        $revisions = $pagelog->getRevisions(-1, 200);
214
215        $this->assertEquals(0, count($revisions));
216        $this->assertEquals($expected_errormsg, $actual_errormsg, "An empty page should not be saved.");
217    }
218
219    public function test_fail_saveing_page_with_invaliddata()
220    {
221        $page = 'test_fail_saveing_page_with_invaliddata';
222        $assignment = mock\Assignments::getInstance();
223        $schema = 'schema2';
224        $assignment->addPattern($page, $schema);
225
226        $wikitext = 'teststring';
227        $request = new \TestRequest();
228        $structData = array(
229            $schema => array(
230                'afirst' => 'foo',
231                'asecond' => 'bar, baz',
232                'athird' => 'foobar',
233                'afourth' => 'Eve'
234            )
235        );
236        $request->setPost('struct_schema_data', $structData);
237        $request->setPost('wikitext', $wikitext);
238        $request->setPost('summary', 'content and struct data saved');
239        $response = $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
240        $actual_wikitext = trim($response->queryHTML('#wiki__text')->html());
241        $expected_wikitext = $wikitext;
242
243        $actual_errormsg = $response->queryHTML('.error')->html();
244        $expected_errormsg = sprintf($this->getLang('validation_prefix') . $this->getLang('Validation Exception Decimal needed'), 'afourth');
245
246        $test_html = trim($response->queryHTML('.struct_entry_form')->html());
247
248        $pagelog = new \PageChangelog($page);
249        $revisions = $pagelog->getRevisions(-1, 200);
250
251        // assert
252        $this->assertEquals(0, count($revisions));
253        $this->assertEquals($expected_errormsg, $actual_errormsg, 'If there is invalid data, then there should be an error message.');
254        $this->assertEquals($expected_wikitext, $actual_wikitext);
255
256        $pq = \phpQuery::newDocument($test_html);
257        $this->assertEquals('schema2', $pq->find('legend')->text());
258        $this->checkField($pq, 'schema2', 'afirst', 'foo');
259        $this->checkField($pq, 'schema2', 'asecond', 'bar, baz');
260        $this->checkField($pq, 'schema2', 'athird', 'foobar');
261        $this->checkField($pq, 'schema2', 'afourth', 'Eve');
262
263        // todo: assert that no struct data has been saved
264    }
265
266    public function test_save_page()
267    {
268        $page = 'test_save_page';
269        $assignment = mock\Assignments::getInstance();
270        $schema = 'schema2';
271        $assignment->addPattern($page, $schema);
272
273        $request = new \TestRequest();
274        $structData = array(
275            $schema => array(
276                'afirst' => 'foo',
277                'asecond' => 'bar, baz',
278                'athird' => 'foobar',
279                'afourth' => '42'
280            )
281        );
282        $request->setPost('struct_schema_data', $structData);
283        $request->setPost('wikitext', 'teststring');
284        $request->setPost('summary', 'content and struct data saved');
285        $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
286
287        $pagelog = new \PageChangelog($page);
288        $revisions = $pagelog->getRevisions(-1, 200);
289        $revinfo = $pagelog->getRevisionInfo($revisions[0]);
290        $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]);
291        $actual_struct_data = $schemaData->getDataArray();
292        $expected_struct_data = array(
293            'afirst' => 'foo',
294            'asecond' => array('bar', 'baz'),
295            'athird' => 'foobar',
296            'afourth' => 42
297        );
298
299        $this->assertEquals(1, count($revisions));
300        $this->assertEquals('content and struct data saved', $revinfo['sum']);
301        $this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']);
302        $this->assertEquals($expected_struct_data, $actual_struct_data);
303        // todo: assert that pagerevision and struct data have the same timestamp
304    }
305
306    /**
307     * @group slow
308     */
309    public function test_save_page_without_new_text()
310    {
311        $page = 'test_save_page_without_new_text';
312        $assignment = mock\Assignments::getInstance();
313        $schema = 'schema2';
314        $assignment->addPattern($page, $schema);
315        $wikitext = 'teststring';
316
317        // first save;
318        $request = new \TestRequest();
319        $structData = array(
320            $schema => array(
321                'afirst' => 'foo',
322                'asecond' => 'bar, baz',
323                'athird' => 'foobar',
324                'afourth' => '42'
325            )
326        );
327        $request->setPost('struct_schema_data', $structData);
328        $request->setPost('wikitext', $wikitext);
329        $request->setPost('summary', 'content and struct data saved');
330        $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
331
332        $this->waitForTick(true);
333
334        // second save - only struct data
335        $request = new \TestRequest();
336        $structData = array(
337            $schema => array(
338                'afirst' => 'foo2',
339                'asecond' => 'bar2, baz2',
340                'athird' => 'foobar2',
341                'afourth' => '43'
342            )
343        );
344        $request->setPost('struct_schema_data', $structData);
345        $request->setPost('wikitext', $wikitext);
346        $request->setPost('summary', '2nd revision');
347        $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
348
349        // assert
350        $pagelog = new \PageChangelog($page);
351        $revisions = $pagelog->getRevisions(-1, 200);
352        $revinfo = $pagelog->getRevisionInfo($revisions[0]);
353        $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]);
354        $actual_struct_data = $schemaData->getDataArray();
355        $expected_struct_data = array(
356            'afirst' => 'foo2',
357            'asecond' => array('bar2', 'baz2'),
358            'athird' => 'foobar2',
359            'afourth' => 43
360        );
361
362        $this->assertEquals(2, count($revisions), 'there should be 2 (two) revisions');
363        $this->assertEquals('2nd revision', $revinfo['sum']);
364        $this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']);
365        $this->assertEquals($expected_struct_data, $actual_struct_data);
366        // todo: assert that pagerevisions and struct entries have the same timestamps
367    }
368
369    /**
370     * @group slow
371     */
372    public function test_delete_page()
373    {
374        $page = 'test_delete_page';
375        $assignment = mock\Assignments::getInstance();
376        $schema = 'schema2';
377        $assignment->addPattern($page, $schema);
378        $wikitext = 'teststring';
379
380        // first save;
381        $request = new \TestRequest();
382        $structData = array(
383            $schema => array(
384                'afirst' => 'foo',
385                'asecond' => 'bar, baz',
386                'athird' => 'foobar',
387                'afourth' => '42'
388            )
389        );
390        $request->setPost('struct_schema_data', $structData);
391        $request->setPost('wikitext', $wikitext);
392        $request->setPost('summary', 'content and struct data saved');
393        $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
394
395        $this->waitForTick(true);
396
397        // delete
398        $request = new \TestRequest();
399        $structData = array(
400            $schema => array(
401                'afirst' => 'foo2',
402                'asecond' => 'bar2, baz2',
403                'athird' => 'foobar2',
404                'afourth' => '43'
405            )
406        );
407        $request->setPost('struct_schema_data', $structData);
408        $request->setPost('wikitext', '');
409        $request->setPost('summary', 'delete page');
410        $request->post(array('id' => $page, 'do' => 'save'), '/doku.php');
411
412        // assert
413        $pagelog = new \PageChangelog($page);
414        $revisions = $pagelog->getRevisions(-1, 200);
415        $revinfo = $pagelog->getRevisionInfo($revisions[0]);
416        $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]);
417        $actual_struct_data = $schemaData->getDataArray();
418        $expected_struct_data = array(
419            'afirst' => '',
420            'asecond' => array(),
421            'athird' => '',
422            'afourth' => ''
423        );
424
425        $this->assertEquals(2, count($revisions), 'there should be 2 (two) revisions');
426        $this->assertEquals('delete page', $revinfo['sum']);
427        $this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']);
428        $this->assertEquals($expected_struct_data, $actual_struct_data);
429        // todo: timestamps?
430    }
431
432    /**
433     * @group slow
434     */
435    public function test_revert_page()
436    {
437        $page = 'test_revert_page';
438        $assignment = mock\Assignments::getInstance();
439        $schema = 'schema2';
440        $assignment->addPattern($page, $schema);
441        $wikitext = 'teststring';
442
443        global $conf;
444        $conf['useacl'] = 1;
445        $conf['superuser'] = 'admin';
446        $_SERVER['REMOTE_USER'] = 'admin'; //now it's testing as admin
447        global $default_server_vars;
448        $default_server_vars['REMOTE_USER'] = 'admin';  //Hack until Issue #1099 is fixed
449        $USERINFO['grps'] = array('admin', 'user');
450
451        // first save;
452        $request = new \TestRequest();
453        $structData = array(
454            $schema => array(
455                'afirst' => 'foo',
456                'asecond' => 'bar, baz',
457                'athird' => 'foobar',
458                'afourth' => '42'
459            )
460        );
461        $request->setPost('struct_schema_data', $structData);
462        $request->setPost('wikitext', $wikitext);
463        $request->setPost('summary', 'content and struct data saved');
464        $request->post(array('id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()), '/doku.php');
465
466        $this->waitForTick(true);
467
468        // second save
469        $request = new \TestRequest();
470        $structData = array(
471            $schema => array(
472                'afirst' => 'foo2',
473                'asecond' => 'bar2, baz2',
474                'athird' => 'foobar2',
475                'afourth' => '43'
476            )
477        );
478        $request->setPost('struct_schema_data', $structData);
479        $request->setPost('wikitext', $wikitext . $wikitext);
480        $request->setPost('summary', 'delete page');
481        $request->post(array('id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()), '/doku.php');
482
483        $this->waitForTick(true);
484
485        // revert to first save
486        $actpagelog = new \PageChangelog($page);
487        $actrevisions = $actpagelog->getRevisions(0, 200);
488
489        $actrevinfo = $actpagelog->getRevisionInfo($actrevisions[0]);
490        $request = new \TestRequest();
491        $request->setPost('summary', 'revert page');
492        $request->post(array('id' => $page, 'do' => 'revert', 'rev' => $actrevinfo['date'], 'sectok' => getSecurityToken()), '/doku.php');
493
494        // assert
495        $pagelog = new \PageChangelog($page);
496        $revisions = $pagelog->getRevisions(-1, 200);
497        $revinfo = $pagelog->getRevisionInfo($revisions[0]);
498        $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]);
499        $actual_struct_data = $schemaData->getDataArray();
500        $expected_struct_data = array(
501            'afirst' => 'foo',
502            'asecond' => array('bar', 'baz'),
503            'athird' => 'foobar',
504            'afourth' => '42'
505        );
506
507        $this->assertEquals(3, count($revisions), 'there should be 3 (three) revisions');
508        $this->assertContains('restored', $revinfo['sum']);
509        $this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']);
510        $this->assertEquals($expected_struct_data, $actual_struct_data);
511        // todo: timestamps?
512    }
513
514}
515