3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.org //
10 // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
12 // This program is free software; you can redistribute it and/or modify //
13 // it under the terms of the GNU General Public License as published by //
14 // the Free Software Foundation; either version 2 of the License, or //
15 // (at your option) any later version. //
17 // This program is distributed in the hope that it will be useful, //
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
20 // GNU General Public License for more details: //
22 // http://www.gnu.org/copyleft/gpl.html //
24 ///////////////////////////////////////////////////////////////////////////
27 * Unit tests for ../portfoliolib.php.
29 * @author nicolasconnault@gmail.com
30 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
34 if (!defined('MOODLE_INTERNAL')) {
35 die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
38 require_once("$CFG->libdir/portfoliolib.php");
39 require_once("$CFG->libdir/portfolio/exporter.php");
40 require_once("$CFG->libdir/portfolio/plugin.php");
41 require_once("$CFG->dirroot/$CFG->admin/generator.php");
43 class portfolio_plugin_test extends portfolio_plugin_push_base {
44 public function expected_time($callertime){
48 public function prepare_package() {
52 public function send_package() {
56 public function get_interactive_continue_url() {
60 public static function get_name() {
65 class portfolio_caller_test extends portfolio_caller_base {
68 public function __construct($content) {
69 $this->content = $content;
72 public function expected_time() {
73 return PORTFOLIO_TIME_LOW;
76 public function get_navigation() {
77 $extranav = array('name' => 'Test caller class', 'link' => $this->get_return_url());
78 return array($extranav, 'test');
81 public function get_sha1(){
82 return sha1($this->content);
85 public function prepare_package() {
89 public function get_return_url() {
93 public function check_permissions() {
97 public static function display_name() {
98 return "Test caller subclass";
101 public function load_data() {
105 public static function expected_callbackargs() {
108 public static function base_supported_formats() {
109 return array(PORTFOLIO_FORMAT_RICH, PORTFOLIO_FORMAT_FILE);
111 public function set_context($PAGE) {
112 $PAGE->set_context(get_system_context());
116 class portfolio_exporter_test extends portfolio_exporter {
119 public function write_new_file($content, $name) {
120 if (empty($this->files)) {
121 $this->files = array();
123 $this->files[] = new portfolio_fake_file($content, $name);
126 public function copy_existing_file($oldfile) {
127 throw new portfolio_exception('notimplemented', 'portfolio', 'files api test');
130 public function get_tempfiles() {
134 public function zip_tempfiles() {
135 return new portfolio_fake_file('fake content zipfile', 'portfolio-export.zip');
140 * this should be REMOVED when we have proper faking of the files api
142 class portfolio_fake_file {
149 public function __construct($content, $name) {
150 $this->content = $content;
152 $this->hash = sha1($content);
153 $this->size = strlen($content);
156 public function get_contenthash() {
160 public function get_filename() {
164 public function get_filesize() {
170 * The following two classes are full mocks: none of their methods do anything, including their constructor.
171 * They can be instantiated directly with no params (new portfolio_caller_test())
173 Mock::generate('portfolio_caller_test', 'mock_caller');
174 Mock::generate('portfolio_plugin_test', 'mock_plugin');
177 * Partial mocks work as normal except the methods listed in the 3rd param, which are mocked.
178 * They are instantiated by passing $this to the constructor within the test case class.
180 Mock::generatePartial('portfolio_plugin_test', 'partialmock_plugin', array('send_package'));
181 Mock::generatePartial('portfolio_exporter_test', 'partialmock_exporter', array('process_stage_confirm',
182 'process_stage_cleanup',
188 // Generate a mock class for each plugin subclass present
189 $portfolio_plugins = get_list_of_plugins('portfolio');
190 foreach ($portfolio_plugins as $plugin) {
191 require_once($CFG->dirroot . "/portfolio/$plugin/lib.php");
192 Mock::generatePartial("portfolio_plugin_$plugin", "partialmock_plugin_$plugin", array('send_package'));
195 class portfoliolib_test extends UnitTestCaseUsingDatabase {
202 // It is necessary to store $USER object because some subclasses use generator
203 // stuff which breaks $USER
204 $this->olduser = $USER;
207 function tearDown() {
209 $USER = $this->olduser;
213 function test_construct_dupe_instance() {
214 $gotexception = false;
216 $plugin1 = portfolio_plugin_base::create_instance('download', 'download1', array());
217 $plugin2 = portfolio_plugin_base::create_instance('download', 'download2', array());
218 $test1 = new portfolio_plugin_download($plugin1->get('id'));
219 } catch (portfolio_exception $e) {
220 $this->assertEqual('multipleinstancesdisallowed', $e->errorcode);
221 $gotexception = true;
223 $this->assertTrue($gotexception);
227 * does everything we need to set up a new caller
228 * so each subclass doesn't have to implement this
230 * @param string $class name of caller class to generate (this class def must be already loaded)
231 * @param array $callbackargs the arguments to pass the constructor of the caller
232 * @param int $userid a userid the subclass has generated
234 * @return portfolio_caller_base subclass
236 protected function setup_caller($class, $callbackargs, $user=null) {
238 $caller = new $class($callbackargs);
239 $caller->set('exporter', new partialmock_exporter($this));
240 if (is_numeric($user)) {
241 $user = $DB->get_record('user', array('id' => $user));
243 if (is_object($user)) {
244 $caller->set('user', $user);
246 $caller->load_data();
248 $caller->get('exporter')->set('format', array_shift($caller->supported_formats()));
252 public function test_caller_with_plugins() {
253 if (!empty($this->caller)) {
254 $plugins = get_list_of_plugins('portfolio');
256 foreach ($plugins as $plugin) {
257 // Instantiate a fake plugin instance
258 $plugin_class = "partialmock_plugin_$plugin";
259 $plugin = new $plugin_class($this);
261 // figure out our format intersection and test all of them.
262 $formats = portfolio_supported_formats_intersect($this->caller->supported_formats(), $plugin->supported_formats());
263 if (count($formats) == 0) {
264 // bail. no common formats.
268 foreach ($formats as $format) {
269 // Create a new fake exporter
270 $exporter =& $this->caller->get('exporter'); // new partialmock_exporter(&$this);
271 $exporter->set('caller', $this->caller);
272 $exporter->set('instance', $plugin);
273 $exporter->set('format', $format);
274 $this->caller->set_export_config(array('format' => $format));
275 $plugin->set_export_config(array('format' => $format));
276 $exporter->set('user', $this->caller->get('user'));
280 $exporter->process_stage_package();
281 } catch (Exception $e) {
282 $exception = $e->getMessage();
285 $this->assertFalse($exception, "Unwanted exception: $exception");