Merge branch 'wip-MDL-62796-master' of git://github.com/marinaglancy/moodle
[moodle.git] / lib / tests / tablelib_test.php
blob1e1fe7b331c378d34929b815eebb583dc3db5805
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Test tablelib.
20 * @package core
21 * @category phpunit
22 * @copyright 2013 Damyon Wiese <damyon@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/tablelib.php');
30 require_once($CFG->libdir . '/tests/fixtures/testable_flexible_table.php');
32 /**
33 * Test some of tablelib.
35 * @package core
36 * @category phpunit
37 * @copyright 2013 Damyon Wiese <damyon@moodle.com>
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class core_tablelib_testcase extends basic_testcase {
41 protected function generate_columns($cols) {
42 $columns = array();
43 foreach (range(0, $cols - 1) as $j) {
44 array_push($columns, 'column' . $j);
46 return $columns;
49 protected function generate_headers($cols) {
50 $columns = array();
51 foreach (range(0, $cols - 1) as $j) {
52 array_push($columns, 'Column ' . $j);
54 return $columns;
57 protected function generate_data($rows, $cols) {
58 $data = array();
60 foreach (range(0, $rows - 1) as $i) {
61 $row = array();
62 foreach (range(0, $cols - 1) as $j) {
63 $val = 'row ' . $i . ' col ' . $j;
64 $row['column' . $j] = $val;
66 array_push($data, $row);
68 return $data;
71 /**
72 * Create a table with properties as passed in params, add data and output html.
74 * @param string[] $columns
75 * @param string[] $headers
76 * @param bool $sortable
77 * @param bool $collapsible
78 * @param string[] $suppress
79 * @param string[] $nosorting
80 * @param (array|object)[] $data
81 * @param int $pagesize
83 protected function run_table_test($columns, $headers, $sortable, $collapsible, $suppress, $nosorting, $data, $pagesize) {
84 $table = $this->create_and_setup_table($columns, $headers, $sortable, $collapsible, $suppress, $nosorting);
85 $table->pagesize($pagesize, count($data));
86 foreach ($data as $row) {
87 $table->add_data_keyed($row);
89 $table->finish_output();
92 /**
93 * Create a table with properties as passed in params.
95 * @param string[] $columns
96 * @param string[] $headers
97 * @param bool $sortable
98 * @param bool $collapsible
99 * @param string[] $suppress
100 * @param string[] $nosorting
101 * @return flexible_table
103 protected function create_and_setup_table($columns, $headers, $sortable, $collapsible, $suppress, $nosorting) {
104 $table = new flexible_table('tablelib_test');
106 $table->define_columns($columns);
107 $table->define_headers($headers);
108 $table->define_baseurl('/invalid.php');
110 $table->sortable($sortable);
111 $table->collapsible($collapsible);
112 foreach ($suppress as $column) {
113 $table->column_suppress($column);
116 foreach ($nosorting as $column) {
117 $table->no_sorting($column);
120 $table->setup();
121 return $table;
124 public function test_empty_table() {
125 $this->expectOutputRegex('/' . get_string('nothingtodisplay') . '/');
126 $this->run_table_test(
127 array('column1', 'column2'), // Columns.
128 array('Column 1', 'Column 2'), // Headers.
129 true, // Sortable.
130 false, // Collapsible.
131 array(), // Suppress columns.
132 array(), // No sorting.
133 array(), // Data.
134 10 // Page size.
138 public function test_has_next_pagination() {
140 $data = $this->generate_data(11, 2);
141 $columns = $this->generate_columns(2);
142 $headers = $this->generate_headers(2);
144 // Search for pagination controls containing '1.*2</a>.*Next</a>'.
145 $this->expectOutputRegex('/1.*2<\/a>.*' . get_string('next') . '<\/a>/');
147 $this->run_table_test(
148 $columns,
149 $headers,
150 true,
151 false,
152 array(),
153 array(),
154 $data,
159 public function test_has_hide() {
161 $data = $this->generate_data(11, 2);
162 $columns = $this->generate_columns(2);
163 $headers = $this->generate_headers(2);
165 // Search for 'hide' links in the column headers.
166 $this->expectOutputRegex('/' . get_string('hide') . '/');
168 $this->run_table_test(
169 $columns,
170 $headers,
171 true,
172 true,
173 array(),
174 array(),
175 $data,
180 public function test_has_not_hide() {
182 $data = $this->generate_data(11, 2);
183 $columns = $this->generate_columns(2);
184 $headers = $this->generate_headers(2);
186 // Make sure there are no 'hide' links in the headers.
188 ob_start();
189 $this->run_table_test(
190 $columns,
191 $headers,
192 true,
193 false,
194 array(),
195 array(),
196 $data,
199 $output = ob_get_contents();
200 ob_end_clean();
201 $this->assertNotContains(get_string('hide'), $output);
204 public function test_has_sort() {
206 $data = $this->generate_data(11, 2);
207 $columns = $this->generate_columns(2);
208 $headers = $this->generate_headers(2);
210 // Search for pagination controls containing '1.*2</a>.*Next</a>'.
211 $this->expectOutputRegex('/' . get_string('sortby') . '/');
213 $this->run_table_test(
214 $columns,
215 $headers,
216 true,
217 false,
218 array(),
219 array(),
220 $data,
225 public function test_has_not_sort() {
227 $data = $this->generate_data(11, 2);
228 $columns = $this->generate_columns(2);
229 $headers = $this->generate_headers(2);
231 // Make sure there are no 'Sort by' links in the headers.
233 ob_start();
234 $this->run_table_test(
235 $columns,
236 $headers,
237 false,
238 false,
239 array(),
240 array(),
241 $data,
244 $output = ob_get_contents();
245 ob_end_clean();
246 $this->assertNotContains(get_string('sortby'), $output);
249 public function test_has_not_next_pagination() {
251 $data = $this->generate_data(10, 2);
252 $columns = $this->generate_columns(2);
253 $headers = $this->generate_headers(2);
255 // Make sure there are no 'Next' links in the pagination.
257 ob_start();
258 $this->run_table_test(
259 $columns,
260 $headers,
261 true,
262 false,
263 array(),
264 array(),
265 $data,
269 $output = ob_get_contents();
270 ob_end_clean();
271 $this->assertNotContains(get_string('next'), $output);
274 public function test_1_col() {
276 $data = $this->generate_data(100, 1);
277 $columns = $this->generate_columns(1);
278 $headers = $this->generate_headers(1);
280 $this->expectOutputRegex('/row 0 col 0/');
282 $this->run_table_test(
283 $columns,
284 $headers,
285 true,
286 false,
287 array(),
288 array(),
289 $data,
294 public function test_empty_rows() {
296 $data = $this->generate_data(1, 5);
297 $columns = $this->generate_columns(5);
298 $headers = $this->generate_headers(5);
300 // Test that we have at least 5 columns generated for each empty row.
301 $this->expectOutputRegex('/emptyrow.*r9_c4/');
303 $this->run_table_test(
304 $columns,
305 $headers,
306 true,
307 false,
308 array(),
309 array(),
310 $data,
315 public function test_5_cols() {
317 $data = $this->generate_data(100, 5);
318 $columns = $this->generate_columns(5);
319 $headers = $this->generate_headers(5);
321 $this->expectOutputRegex('/row 0 col 0/');
323 $this->run_table_test(
324 $columns,
325 $headers,
326 true,
327 false,
328 array(),
329 array(),
330 $data,
335 public function test_50_cols() {
337 $data = $this->generate_data(100, 50);
338 $columns = $this->generate_columns(50);
339 $headers = $this->generate_headers(50);
341 $this->expectOutputRegex('/row 0 col 0/');
343 $this->run_table_test(
344 $columns,
345 $headers,
346 true,
347 false,
348 array(),
349 array(),
350 $data,
355 public function test_get_row_html() {
356 $data = $this->generate_data(1, 5);
357 $columns = $this->generate_columns(5);
358 $headers = $this->generate_headers(5);
359 $data = array_keys(array_flip($data[0]));
361 $table = new flexible_table('tablelib_test');
362 $table->define_columns($columns);
363 $table->define_headers($headers);
364 $table->define_baseurl('/invalid.php');
366 $row = $table->get_row_html($data);
367 $this->assertRegExp('/row 0 col 0/', $row);
368 $this->assertRegExp('/<tr class=""/', $row);
369 $this->assertRegExp('/<td class="cell c0"/', $row);
372 public function test_persistent_table() {
373 global $SESSION;
375 $data = $this->generate_data(5, 5);
376 $columns = $this->generate_columns(5);
377 $headers = $this->generate_headers(5);
379 // Testing without persistence first to verify that the results are different.
380 $table1 = new flexible_table('tablelib_test');
381 $table1->define_columns($columns);
382 $table1->define_headers($headers);
383 $table1->define_baseurl('/invalid.php');
385 $table1->sortable(true);
386 $table1->collapsible(true);
388 $table1->is_persistent(false);
389 $_GET['thide'] = 'column0';
390 $_GET['tsort'] = 'column1';
391 $_GET['tifirst'] = 'A';
392 $_GET['tilast'] = 'Z';
394 foreach ($data as $row) {
395 $table1->add_data_keyed($row);
397 $table1->setup();
399 // Clear session data between each new table.
400 unset($SESSION->flextable);
402 $table2 = new flexible_table('tablelib_test');
403 $table2->define_columns($columns);
404 $table2->define_headers($headers);
405 $table2->define_baseurl('/invalid.php');
407 $table2->sortable(true);
408 $table2->collapsible(true);
410 $table2->is_persistent(false);
411 unset($_GET);
413 foreach ($data as $row) {
414 $table2->add_data_keyed($row);
416 $table2->setup();
418 $this->assertNotEquals($table1, $table2);
420 unset($SESSION->flextable);
422 // Now testing with persistence to check that the tables are the same.
423 $table3 = new flexible_table('tablelib_test');
424 $table3->define_columns($columns);
425 $table3->define_headers($headers);
426 $table3->define_baseurl('/invalid.php');
428 $table3->sortable(true);
429 $table3->collapsible(true);
431 $table3->is_persistent(true);
432 $_GET['thide'] = 'column0';
433 $_GET['tsort'] = 'column1';
434 $_GET['tifirst'] = 'A';
435 $_GET['tilast'] = 'Z';
437 foreach ($data as $row) {
438 $table3->add_data_keyed($row);
440 $table3->setup();
442 unset($SESSION->flextable);
444 $table4 = new flexible_table('tablelib_test');
445 $table4->define_columns($columns);
446 $table4->define_headers($headers);
447 $table4->define_baseurl('/invalid.php');
449 $table4->sortable(true);
450 $table4->collapsible(true);
452 $table4->is_persistent(true);
453 unset($_GET);
455 foreach ($data as $row) {
456 $table4->add_data_keyed($row);
458 $table4->setup();
460 $this->assertEquals($table3, $table4);
462 unset($SESSION->flextable);
464 // Finally, another test with no persistence, but without clearing the session data.
465 $table5 = new flexible_table('tablelib_test');
466 $table5->define_columns($columns);
467 $table5->define_headers($headers);
468 $table5->define_baseurl('/invalid.php');
470 $table5->sortable(true);
471 $table5->collapsible(true);
473 $table5->is_persistent(true);
474 $_GET['thide'] = 'column0';
475 $_GET['tsort'] = 'column1';
476 $_GET['tifirst'] = 'A';
477 $_GET['tilast'] = 'Z';
479 foreach ($data as $row) {
480 $table5->add_data_keyed($row);
482 $table5->setup();
484 $table6 = new flexible_table('tablelib_test');
485 $table6->define_columns($columns);
486 $table6->define_headers($headers);
487 $table6->define_baseurl('/invalid.php');
489 $table6->sortable(true);
490 $table6->collapsible(true);
492 $table6->is_persistent(true);
493 unset($_GET);
495 foreach ($data as $row) {
496 $table6->add_data_keyed($row);
498 $table6->setup();
500 $this->assertEquals($table5, $table6);
504 * Helper method for preparing tables instances in {@link self::test_can_be_reset()}.
506 * @param string $tableid
507 * @return testable_flexible_table
509 protected function prepare_table_for_reset_test($tableid) {
510 global $SESSION;
512 unset($SESSION->flextable[$tableid]);
514 $data = $this->generate_data(25, 3);
515 $columns = array('column0', 'column1', 'column2');
516 $headers = $this->generate_headers(3);
518 $table = new testable_flexible_table($tableid);
519 $table->define_baseurl('/invalid.php');
520 $table->define_columns($columns);
521 $table->define_headers($headers);
522 $table->collapsible(true);
523 $table->is_persistent(false);
525 return $table;
528 public function test_can_be_reset() {
530 // Table in its default state (as if seen for the first time), nothing to reset.
531 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
532 $table->setup();
533 $this->assertFalse($table->can_be_reset());
535 // Table in its default state with default sorting defined, nothing to reset.
536 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
537 $table->sortable(true, 'column1', SORT_DESC);
538 $table->setup();
539 $this->assertFalse($table->can_be_reset());
541 // Table explicitly sorted by the default column (reverses the order), can be reset.
542 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
543 $table->sortable(true, 'column1', SORT_DESC);
544 $_GET['tsort'] = 'column1';
545 $table->setup();
546 unset($_GET['tsort']);
547 $this->assertTrue($table->can_be_reset());
549 // Table explicitly sorted twice by the default column (puts back to default order), nothing to reset.
550 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
551 $table->sortable(true, 'column1', SORT_DESC);
552 $_GET['tsort'] = 'column1';
553 $table->setup();
554 $table->setup(); // Set up again to simulate the second page request.
555 unset($_GET['tsort']);
556 $this->assertFalse($table->can_be_reset());
558 // Table sorted by other than default column, can be reset.
559 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
560 $table->sortable(true, 'column1', SORT_DESC);
561 $_GET['tsort'] = 'column2';
562 $table->setup();
563 unset($_GET['tsort']);
564 $this->assertTrue($table->can_be_reset());
566 // Table sorted by the default column after another sorting previously selected.
567 // This leads to different ORDER BY than just having a single sort defined, can be reset.
568 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
569 $table->sortable(true, 'column1', SORT_DESC);
570 $_GET['tsort'] = 'column0';
571 $table->setup();
572 $_GET['tsort'] = 'column1';
573 $table->setup();
574 unset($_GET['tsort']);
575 $this->assertTrue($table->can_be_reset());
577 // Table having some column collapsed, can be reset.
578 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
579 $_GET['thide'] = 'column2';
580 $table->setup();
581 unset($_GET['thide']);
582 $this->assertTrue($table->can_be_reset());
584 // Table having some column explicitly expanded, nothing to reset.
585 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
586 $_GET['tshow'] = 'column2';
587 $table->setup();
588 unset($_GET['tshow']);
589 $this->assertFalse($table->can_be_reset());
591 // Table after expanding a collapsed column, nothing to reset.
592 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
593 $_GET['thide'] = 'column0';
594 $table->setup();
595 $_GET['tshow'] = 'column0';
596 $table->setup();
597 unset($_GET['thide']);
598 unset($_GET['tshow']);
599 $this->assertFalse($table->can_be_reset());
601 // Table with some name filtering enabled, can be reset.
602 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_'));
603 $_GET['tifirst'] = 'A';
604 $table->setup();
605 unset($_GET['tifirst']);
606 $this->assertTrue($table->can_be_reset());