009b74ce8a7f02d1941f99eb7bd34da83903f510
[moodle.git] / lib / simpletest / testoutputlib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
19 /**
20  * Unit tests for (some of) ../outputlib.php.
21  *
22  * @package   moodlecore
23  * @copyright 2009 Tim Hunt
24  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later (5)
25  */
27 if (!defined('MOODLE_INTERNAL')) {
28     die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
29 }
30 require_once($CFG->libdir . '/outputlib.php');
32 //TODO: MDL-21361
33 return;
35 $e = <<<EOT
37 /**
38  * Subclass of renderer_factory_base for testing. Implement abstract method and
39  * count calls, so we can test caching behaviour.
40  *
41  * @copyright 2009 Tim Hunt
42  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  */
44 class testable_renderer_factory extends renderer_factory_base {
45     public $createcalls = array();
47     public function __construct() {
48         parent::__construct(null);
49     }
51     public function get_renderer($module, $page, $subtype=null) {
52         if (!in_array(array($module, $subtype), $this->createcalls)) {
53             $this->createcalls[] = array($module, $subtype);
54         }
55         return new core_renderer($page);
56     }
58     public function standard_renderer_class_for_plugin($module, $subtype=null) {
59         return parent::standard_renderer_class_for_plugin($module, $subtype);
60     }
61 }
64 /**
65  * Renderer class for testing.
66  *
67  * @copyright 2009 Tim Hunt
68  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
69  */
70 class mod_test_renderer extends core_renderer {
71     public function __construct($containerstack, $page) {
72         parent::__construct($containerstack, $page, null);
73     }
75     public function greeting($name = 'world') {
76         return '<h1>Hello ' . $name . '!</h1>';
77     }
79     public function box($content, $id = '') {
80         return box_start($id) . $content . box_end();
81     }
83     public function box_start($id = '') {
84         if ($id) {
85             $id = ' id="' . $id . '"';
86         }
87         $this->containerstack->push('box', '</div>');
88         return '<div' . $id . '>';
89     }
91     public function box_end() {
92         return $this->containerstack->pop('box');
93     }
94 }
97 /**
98  * Renderer class for testing subrendering feature
99  *
100  * @copyright 2009 David Mudrak
101  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
102  */
103 class mod_test_subtype_renderer extends core_renderer {
104     public function __construct($containerstack, $page) {
105         parent::__construct($containerstack, $page, null);
106     }
108     public function signature($user = 'Administrator') {
109         return '<div class="signature">Best regards, ' . $user . '</div>';
110     }
114 /**
115  * Unit tests for the requriement_base base class.
116  *
117  * @copyright 2009 Tim Hunt
118  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
119  */
120 class renderer_factory_base_test extends UnitTestCase {
122     public static $includecoverage = array('lib/outputlib.php');
124     public function test_get_calls_create() {
125         // Set up.
126         $factory = new testable_renderer_factory();
127         // Exercise SUT.
128         $renderer    = $factory->get_renderer('modulename', new moodle_page);
129         $subrenderer = $factory->get_renderer('modulename', new moodle_page, 'subtype');
130         $cached      = $factory->get_renderer('modulename', new moodle_page);
131         // Verify outcome
132         $this->assertEqual(array(array('modulename', null), array('modulename', 'subtype')), $factory->createcalls);
134     }
136     public function test_standard_renderer_class_for_plugin_core() {
137         // Set up.
138         $factory = new testable_renderer_factory();
139         // Exercise SUT.
140         $classname = $factory->standard_renderer_class_for_plugin('core');
141         // Verify outcome
142         $this->assertEqual('core_renderer', $classname);
143     }
145     public function test_standard_renderer_class_for_plugin_test() {
146         // Set up.
147         $factory = new testable_renderer_factory();
148         // Exercise SUT.
149         $classname = $factory->standard_renderer_class_for_plugin('mod_test');
150         // Verify outcome
151         $this->assertEqual('mod_test_renderer', $classname);
152     }
154     public function test_standard_renderer_class_for_plugin_test_with_subtype() {
155         // Set up.
156         $factory = new testable_renderer_factory();
157         // Exercise SUT.
158         $classname = $factory->standard_renderer_class_for_plugin('mod_test', 'subtype');
159         // Verify outcome
160         $this->assertEqual('mod_test_subtype_renderer', $classname);
161     }
163     public function test_standard_renderer_class_for_plugin_unknown() {
164         // Set up.
165         $factory = new testable_renderer_factory();
166         $this->expectException();
167         // Exercise SUT.
168         $classname = $factory->standard_renderer_class_for_plugin('something_that_does_not_exist');
169     }
173 /**
174  * Unit tests for the standard_renderer_factory class.
175  *
176  * @copyright 2009 Tim Hunt
177  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
178  */
179 class standard_renderer_factory_test extends UnitTestCase {
181     public static $includecoverage = array('lib/outputrenderers.php', 'lib/outputcomponents.php');
182     protected $factory;
184     public function setUp() {
185         parent::setUp();
186         $this->factory = new standard_renderer_factory(null, null);
187     }
189     public function tearDown() {
190         $this->factory = null;
191         parent::tearDown();
192     }
194     public function test_get_core_renderer() {
195         $renderer = $this->factory->get_renderer('core', new moodle_page);
196         $this->assertIsA($renderer, 'core_renderer');
197     }
199     public function test_get_test_renderer() {
200         $renderer = $this->factory->get_renderer('mod_test', new moodle_page);
201         $this->assertIsA($renderer, 'mod_test_renderer');
202     }
204     public function test_get_test_subtype_renderer() {
205         $renderer = $this->factory->get_renderer('mod_test', new moodle_page, 'subtype');
206         $this->assertIsA($renderer, 'mod_test_subtype_renderer');
207     }
211 /**
212  * Test-specific subclass that implements a getter for $prefixes.
213  *
214  * @copyright 2009 Tim Hunt
215  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
216  */
217 class testable_theme_overridden_renderer_factory extends theme_overridden_renderer_factory {
219     public static $includecoverage = array('lib/outputlib.php');
220     public function get_prefixes() {
221         return $this->prefixes;
222     }
226 /**
227  * Unit tests for the theme_overridden_renderer_factory class.
228  *
229  * @copyright 2009 Tim Hunt
230  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
231  */
232 /*class theme_overridden_renderer_factory_test extends UnitTestCase { // TODO: MDL-21138 rewrite theme unit tests
234     public static $includecoverage = array('lib/outputlib.php');
235     protected $originalcfgthemedir;
236     protected $workspace;
237     protected $page;
238     protected $foldertocleanup = null;
240     public function setUp() {
241         global $CFG;
242         parent::setUp();
244         $this->originalcfgthemedir = $CFG->themedir;
246         $this->workspace = 'temp/theme_overridden_renderer_factory_fixtures';
247         make_upload_directory($this->workspace);
248         $CFG->themedir = $CFG->dataroot . '/' . $this->workspace;
249         $this->foldertocleanup = $CFG->themedir;
251         $this->page = new stdClass;
252     }
254     public function tearDown() {
255         global $CFG;
256         if (!empty($this->foldertocleanup)) {
257             fulldelete($this->foldertocleanup);
258             $this->foldertocleanup = null;
259         }
260         $CFG->themedir = $this->originalcfgthemedir;
261         parent::tearDown();
262     }
264     protected function make_theme($name) {
265         global $CFG;
266         $theme = new stdClass;
267         $theme->name = $name;
268         $theme->dir = $CFG->themedir . '/' . $name;
269         make_upload_directory($this->workspace . '/' . $name);
270         return $theme;
271     }
273     protected function write_renderers_file($theme, $code) {
274         $filename = $theme->dir . '/lib.php';
275         file_put_contents($filename, "<?php\n" . $code);
276     }
278     public function test_constructor_theme_with_renderes() {
279         // Set up.
280         $theme = $this->make_theme('mytheme');
281         $this->write_renderers_file($theme, '');
283         // Exercise SUT.
284         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
286         // Verify outcome
287         $this->assertEqual(array('mytheme_'), $factory->get_prefixes());
288     }
290     public function test_constructor_theme_without_renderes() {
291         // Set up.
292         $theme = $this->make_theme('mytheme');
294         // Exercise SUT.
295         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
297         // Verify outcome
298         $this->assertEqual(array(), $factory->get_prefixes());
299     }
301     public function test_constructor_theme_with_parent() {
302         // Set up.
303         $theme = $this->make_theme('mytheme');
304         $theme->parent = 'parenttheme';
305         $parenttheme = $this->make_theme('parenttheme');
306         $this->write_renderers_file($parenttheme, '');
308         // Exercise SUT.
309         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
311         // Verify outcome
312         $this->assertEqual(array('parenttheme_'), $factory->get_prefixes());
313     }
315     public function test_get_renderer_not_overridden() {
316         // Set up.
317         $theme = $this->make_theme('mytheme');
318         $this->write_renderers_file($theme, '');
319         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
321         // Exercise SUT.
322         $renderer    = $factory->get_renderer('mod_test', new moodle_page);
323         $subrenderer = $factory->get_renderer('mod_test', new moodle_page, 'subtype');
325         // Verify outcome
326         $this->assertIsA($renderer, 'mod_test_renderer');
327         $this->assertIsA($subrenderer, 'mod_test_subtype_renderer');
328     }
330     public function test_get_renderer_overridden() {
331         // Set up - be very careful because the class under test uses require-once. Pick a unique theme name.
332         $theme = $this->make_theme('testrenderertheme');
333         $this->write_renderers_file($theme, '
334         class testrenderertheme_mod_test_renderer extends mod_test_renderer {
335         }');
336         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
338         // Exercise SUT.
339         $renderer    = $factory->get_renderer('mod_test', new moodle_page);
340         $subrenderer = $factory->get_renderer('mod_test', new moodle_page, 'subtype');
342         // Verify outcome
343         $this->assertIsA($renderer, 'testrenderertheme_mod_test_renderer');
344         $this->assertIsA($subrenderer, 'mod_test_subtype_renderer');
345     }
347     public function test_get_renderer_overridden_in_parent() {
348         // Set up.
349         $theme = $this->make_theme('childtheme');
350         $theme->parent = 'parentrenderertheme';
351         $parenttheme = $this->make_theme('parentrenderertheme');
352         $this->write_renderers_file($theme, '');
353         $this->write_renderers_file($parenttheme, '
354         class parentrenderertheme_core_renderer extends core_renderer {
355         }');
356         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
358         // Exercise SUT.
359         $renderer = $factory->get_renderer('core', new moodle_page);
361         // Verify outcome
362         $this->assertIsA($renderer, 'parentrenderertheme_core_renderer');
363     }
365     public function test_get_renderer_overridden_in_both() {
366         // Set up.
367         $theme = $this->make_theme('ctheme');
368         $theme->parent = 'ptheme';
369         $parenttheme = $this->make_theme('ptheme');
370         $this->write_renderers_file($theme, '
371         class ctheme_core_renderer extends core_renderer {
372         }');
373         $this->write_renderers_file($parenttheme, '
374         class ptheme_core_renderer extends core_renderer {
375         }');
376         $factory = new testable_theme_overridden_renderer_factory($theme, $this->page);
378         // Exercise SUT.
379         $renderer = $factory->get_renderer('core', new moodle_page);
381         // Verify outcome
382         $this->assertIsA($renderer, 'ctheme_core_renderer');
383     }
384 }*/
386 /**
387  * Unit tests for the xhtml_container_stack class.
388  *
389  * These tests assume that developer debug mode is on, which, at the time of
390  * writing, is true. admin/report/unittest/index.php forces it on.
391  *
392  * @copyright 2009 Tim Hunt
393  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
394  */
395 class xhtml_container_stack_test extends UnitTestCase {
397     public static $includecoverage = array('lib/outputlib.php');
398     protected function start_capture() {
399         ob_start();
400     }
402     protected function end_capture() {
403         $result = ob_get_contents();
404         ob_end_clean();
405         return $result;
406     }
408     public function test_push_then_pop() {
409         // Set up.
410         $stack = new xhtml_container_stack();
411         // Exercise SUT.
412         $this->start_capture();
413         $stack->push('testtype', '</div>');
414         $html = $stack->pop('testtype');
415         $errors = $this->end_capture();
416         // Verify outcome
417         $this->assertEqual('</div>', $html);
418         $this->assertEqual('', $errors);
419     }
421     public function test_mismatched_pop_prints_warning() {
422         // Set up.
423         $stack = new xhtml_container_stack();
424         $stack->push('testtype', '</div>');
425         // Exercise SUT.
426         $this->start_capture();
427         $html = $stack->pop('mismatch');
428         $errors = $this->end_capture();
429         // Verify outcome
430         $this->assertEqual('</div>', $html);
431         $this->assertNotEqual('', $errors);
432     }
434     public function test_pop_when_empty_prints_warning() {
435         // Set up.
436         $stack = new xhtml_container_stack();
437         // Exercise SUT.
438         $this->start_capture();
439         $html = $stack->pop('testtype');
440         $errors = $this->end_capture();
441         // Verify outcome
442         $this->assertEqual('', $html);
443         $this->assertNotEqual('', $errors);
444     }
446     public function test_correct_nesting() {
447         // Set up.
448         $stack = new xhtml_container_stack();
449         // Exercise SUT.
450         $this->start_capture();
451         $stack->push('testdiv', '</div>');
452         $stack->push('testp', '</p>');
453         $html2 = $stack->pop('testp');
454         $html1 = $stack->pop('testdiv');
455         $errors = $this->end_capture();
456         // Verify outcome
457         $this->assertEqual('</p>', $html2);
458         $this->assertEqual('</div>', $html1);
459         $this->assertEqual('', $errors);
460     }
462     public function test_pop_all_but_last() {
463         // Set up.
464         $stack = new xhtml_container_stack();
465         $stack->push('test1', '</h1>');
466         $stack->push('test2', '</h2>');
467         $stack->push('test3', '</h3>');
468         // Exercise SUT.
469         $this->start_capture();
470         $html = $stack->pop_all_but_last();
471         $errors = $this->end_capture();
472         // Verify outcome
473         $this->assertEqual('</h3></h2>', $html);
474         $this->assertEqual('', $errors);
475         // Tear down.
476         $stack->discard();
477     }
479     public function test_pop_all_but_last_only_one() {
480         // Set up.
481         $stack = new xhtml_container_stack();
482         $stack->push('test1', '</h1>');
483         // Exercise SUT.
484         $this->start_capture();
485         $html = $stack->pop_all_but_last();
486         $errors = $this->end_capture();
487         // Verify outcome
488         $this->assertEqual('', $html);
489         $this->assertEqual('', $errors);
490         // Tear down.
491         $stack->discard();
492     }
494     public function test_pop_all_but_last_empty() {
495         // Set up.
496         $stack = new xhtml_container_stack();
497         // Exercise SUT.
498         $this->start_capture();
499         $html = $stack->pop_all_but_last();
500         $errors = $this->end_capture();
501         // Verify outcome
502         $this->assertEqual('', $html);
503         $this->assertEqual('', $errors);
504     }
506     public function test_destruct() {
507         // Set up.
508         $stack = new xhtml_container_stack();
509         $stack->push('test1', '</somethingdistinctive>');
510         // Exercise SUT.
511         $this->start_capture();
512         $stack = null;
513         $errors = $this->end_capture();
514         // Verify outcome
515         $this->assertPattern('/<\/somethingdistinctive>/', $errors);
516     }
518     public function test_destruct_empty() {
519         // Set up.
520         $stack = new xhtml_container_stack();
521         // Exercise SUT.
522         $this->start_capture();
523         $stack = null;
524         $errors = $this->end_capture();
525         // Verify outcome
526         $this->assertEqual('', $errors);
527     }
529     public function test_discard() {
530         // Set up.
531         $stack = new xhtml_container_stack();
532         $stack->push('test1', '</somethingdistinctive>');
533         $stack->discard();
534         // Exercise SUT.
535         $this->start_capture();
536         $stack = null;
537         $errors = $this->end_capture();
538         // Verify outcome
539         $this->assertEqual('', $errors);
540     }
543 /**
544  * Unit tests for the core_renderer class.
545  *
546  * @copyright 2009 Tim Hunt
547  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
548  */
549 class core_renderer_test extends UnitTestCase {
551     public static $includecoverage = array('lib/outputrenderers.php', 'lib/outputcomponents.php');
552     protected $renderer;
554     public function setUp() {
555         parent::setUp();
556         $this->renderer = new core_renderer(new moodle_page);
557     }
559     public function test_error_text() {
560         $html = $this->renderer->error_text('message');
561         $this->assert(new ContainsTagWithContents('span', 'message'), $html);
562         $this->assert(new ContainsTagWithAttribute('span', 'class', 'error'), $html);
563     }
565     public function test_error_text_blank() {
566         $html = $this->renderer->error_text('');
567         $this->assertEqual('', $html);
568     }
570     public function test_userpicture() {
571         global $CFG;
572         // Set up the user with the required fields
573         $user = new stdClass();
574         $user->firstname = 'Test';
575         $user->lastname = 'User';
576         $user->picture = false;
577         $user->imagealt = false;
578         $user->id = 1;
579         $userpic = new user_picture();
580         $userpic->user = $user;
581         $userpic->courseid = 1;
582         $userpic->url = true;
583         // Setting popup to true adds JS for the link to open in a popup
584         $userpic->popup = true;
585         $html = $this->renderer->user_picture($userpic);
586         $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Test User', 'href' => $CFG->wwwroot.'/user/view.php?id=1&course=1')), $html);
587     }
589     public function test_heading_with_help() {
590         $originalicon = new help_icon();
591         $originalicon->page = 'myhelppage';
592         $originalicon->text = 'Cool help text';
594         $helpicon = clone($originalicon);
595         $html = $this->renderer->heading_with_help($helpicon);
596         $this->assert(new ContainsTagWithAttribute('div', 'class', 'heading-with-help'), $html);
597         $this->assert(new ContainsTagWithAttribute('span', 'class', 'helplink'), $html);
598         $this->assert(new ContainsTagWithAttribute('h2', 'class', 'main help'), $html);
599         $this->assert(new ContainsTagWithAttributes('img', array('class' => 'iconhelp image', 'src' => $this->renderer->pix_url('help'))), $html);
600         $this->assert(new ContainsTagWithContents('h2', 'Cool help text'), $html);
602         $helpicon = clone($originalicon);
603         $helpicon->image = false;
605         $html = $this->renderer->heading_with_help($helpicon);
606         $this->assert(new ContainsTagWithAttribute('div', 'class', 'heading-with-help'), $html);
607         $this->assert(new ContainsTagWithAttribute('span', 'class', 'helplink'), $html);
608         $this->assert(new ContainsTagWithAttribute('h2', 'class', 'main help'), $html);
609         $this->assert(new ContainsTagWithAttributes('img', array('class' => 'iconhelp image', 'src' => $this->renderer->pix_url('help'))), $html);
610         $this->assert(new ContainsTagWithContents('h2', 'Cool help text'), $html);
611     }
614 EOT;