2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
18 * Unit tests for the progress classes.
20 * @package core_backup
22 * @copyright 2013 The Open University
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 // Include all the needed stuff.
30 require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
35 class backup_progress_testcase extends basic_testcase {
38 * Tests for basic use with simple numeric progress.
40 public function test_basic() {
41 $progress = new core_backup_mock_progress();
43 // Check values of empty progress things.
44 $this->assertFalse($progress->is_in_progress_section());
46 // Start progress counting, check basic values and check that update
48 $progress->start_progress('hello', 10);
49 $this->assertTrue($progress->was_update_called());
50 $this->assertTrue($progress->is_in_progress_section());
51 $this->assertEquals('hello', $progress->get_current_description());
53 // Check numeric position and indeterminate count.
54 $this->assert_min_max(0.0, 0.0, $progress);
55 $this->assertEquals(0, $progress->get_progress_count());
57 // Make some progress and check that the time limit gets added.
58 $progress->step_time();
59 core_php_time_limit::get_and_clear_unit_test_data();
60 $progress->progress(2);
61 $this->assertTrue($progress->was_update_called());
62 $this->assertEquals(array(core_backup_progress::TIME_LIMIT_WITHOUT_PROGRESS),
63 core_php_time_limit::get_and_clear_unit_test_data());
65 // Check the new value.
66 $this->assert_min_max(0.2, 0.2, $progress);
68 // Do another progress run at same time, it should be ignored.
69 $progress->progress(3);
70 $this->assertFalse($progress->was_update_called());
71 $this->assert_min_max(0.2, 0.2, $progress);
73 // End the section. This should cause an update.
74 $progress->end_progress();
75 $this->assertTrue($progress->was_update_called());
77 // Because there are no sections left open, it thinks we finished.
78 $this->assert_min_max(1.0, 1.0, $progress);
80 // There was 1 progress call.
81 $this->assertEquals(1, $progress->get_progress_count());
83 // Clear the time limit, otherwise phpunit complains.
88 * Tests progress that is nested and/or indeterminate.
90 public function test_nested() {
91 // Outer progress goes from 0 to 10.
92 $progress = new core_backup_mock_progress();
93 $progress->start_progress('hello', 10);
95 // Get up to 4, check position.
96 $progress->step_time();
97 $progress->progress(4);
98 $this->assert_min_max(0.4, 0.4, $progress);
99 $this->assertEquals('hello', $progress->get_current_description());
101 // Now start indeterminate progress.
102 $progress->start_progress('world');
103 $this->assert_min_max(0.4, 0.5, $progress);
104 $this->assertEquals('world', $progress->get_current_description());
106 // Do some indeterminate progress and count it (once per second).
107 $progress->step_time();
108 $progress->progress();
109 $this->assertEquals(2, $progress->get_progress_count());
110 $progress->progress();
111 $this->assertEquals(2, $progress->get_progress_count());
112 $progress->step_time();
113 $progress->progress();
114 $this->assertEquals(3, $progress->get_progress_count());
115 $this->assert_min_max(0.4, 0.5, $progress);
117 // Exit the indeterminate section.
118 $progress->end_progress();
119 $this->assert_min_max(0.5, 0.5, $progress);
121 $progress->step_time();
122 $progress->progress(7);
123 $this->assert_min_max(0.7, 0.7, $progress);
125 // Enter a numbered section (this time with a range of 5).
126 $progress->start_progress('frogs', 5);
127 $this->assert_min_max(0.7, 0.7, $progress);
128 $progress->step_time();
129 $progress->progress(1);
130 $this->assert_min_max(0.72, 0.72, $progress);
131 $progress->step_time();
132 $progress->progress(3);
133 $this->assert_min_max(0.76, 0.76, $progress);
135 // Now enter another indeterminate section.
136 $progress->start_progress('and');
137 $this->assert_min_max(0.76, 0.78, $progress);
139 // Make some progress, should increment indeterminate count.
140 $progress->step_time();
141 $progress->progress();
142 $this->assertEquals(7, $progress->get_progress_count());
144 // Enter numbered section, won't make any difference to values.
145 $progress->start_progress('zombies', 2);
146 $progress->step_time();
147 $progress->progress(1);
148 $this->assert_min_max(0.76, 0.78, $progress);
149 $this->assertEquals(8, $progress->get_progress_count());
151 // Leaving it will make no difference too.
152 $progress->end_progress();
154 // Leaving the indeterminate section will though.
155 $progress->end_progress();
156 $this->assert_min_max(0.78, 0.78, $progress);
158 // Leave the two numbered sections.
159 $progress->end_progress();
160 $this->assert_min_max(0.8, 0.8, $progress);
161 $progress->end_progress();
162 $this->assertFalse($progress->is_in_progress_section());
168 * Tests the feature for 'weighting' nested progress.
170 public function test_nested_weighted() {
171 $progress = new core_backup_mock_progress();
172 $progress->start_progress('', 10);
174 // First nested child has 2 units of its own and is worth 1 unit.
175 $progress->start_progress('', 2);
176 $progress->step_time();
177 $progress->progress(1);
178 $this->assert_min_max(0.05, 0.05, $progress);
179 $progress->end_progress();
180 $this->assert_min_max(0.1, 0.1, $progress);
182 // Next child has 2 units of its own but is worth 3 units.
183 $progress->start_progress('weighted', 2, 3);
184 $progress->step_time();
185 $progress->progress(1);
186 $this->assert_min_max(0.25, 0.25, $progress);
187 $progress->end_progress();
188 $this->assert_min_max(0.4, 0.4, $progress);
190 // Next indeterminate child is worth 6 units.
191 $progress->start_progress('', core_backup_progress::INDETERMINATE, 6);
192 $progress->step_time();
193 $progress->progress();
194 $this->assert_min_max(0.4, 1.0, $progress);
195 $progress->end_progress();
196 $this->assert_min_max(1.0, 1.0, $progress);
202 * I had some issues with real use in backup/restore, this test is intended
205 public function test_realistic() {
206 $progress = new core_backup_mock_progress();
207 $progress->start_progress('parent', 100);
208 $progress->start_progress('child', 1);
209 $progress->progress(1);
210 $this->assert_min_max(0.01, 0.01, $progress);
211 $progress->end_progress();
212 $this->assert_min_max(0.01, 0.01, $progress);
214 // Clear the time limit, otherwise phpunit complains.
219 * To avoid causing problems, progress needs to work for sections that have
222 public function test_zero() {
223 $progress = new core_backup_mock_progress();
224 $progress->start_progress('parent', 100);
225 $progress->progress(1);
226 $this->assert_min_max(0.01, 0.01, $progress);
227 $progress->start_progress('child', 0);
229 // For 'zero' progress, the progress section as immediately complete
230 // within the parent count, so it moves up to 2%.
231 $this->assert_min_max(0.02, 0.02, $progress);
232 $progress->progress(0);
233 $this->assert_min_max(0.02, 0.02, $progress);
234 $progress->end_progress();
235 $this->assert_min_max(0.02, 0.02, $progress);
241 * Tests for any exceptions due to invalid calls.
243 public function test_exceptions() {
244 $progress = new core_backup_mock_progress();
246 // Check errors when empty.
248 $progress->progress();
250 } catch (coding_exception $e) {
251 $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
254 $progress->end_progress();
256 } catch (coding_exception $e) {
257 $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
260 $progress->get_current_description();
262 } catch (coding_exception $e) {
263 $this->assertEquals(1, preg_match('~Not inside progress~', $e->getMessage()));
266 $progress->start_progress('', 1, 7);
268 } catch (coding_exception $e) {
269 $this->assertEquals(1, preg_match('~must be 1~', $e->getMessage()));
272 // Check invalid start (-2).
274 $progress->start_progress('hello', -2);
276 } catch (coding_exception $e) {
277 $this->assertEquals(1, preg_match('~cannot be negative~', $e->getMessage()));
280 // Indeterminate when value expected.
281 $progress->start_progress('hello', 10);
283 $progress->progress(core_backup_progress::INDETERMINATE);
285 } catch (coding_exception $e) {
286 $this->assertEquals(1, preg_match('~expecting value~', $e->getMessage()));
289 // Value when indeterminate expected.
290 $progress->start_progress('hello');
292 $progress->progress(4);
294 } catch (coding_exception $e) {
295 $this->assertEquals(1, preg_match('~expecting INDETERMINATE~', $e->getMessage()));
299 $progress->start_progress('hello', 10);
301 $progress->progress(-2);
303 } catch (coding_exception $e) {
304 $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
307 $progress->progress(11);
309 } catch (coding_exception $e) {
310 $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
313 // You are allowed two with the same value...
314 $progress->progress(4);
315 $progress->step_time();
316 $progress->progress(4);
317 $progress->step_time();
319 // ...but not to go backwards.
321 $progress->progress(3);
323 } catch (coding_exception $e) {
324 $this->assertEquals(1, preg_match('~backwards~', $e->getMessage()));
327 // When you go forward, you can't go further than there is room.
329 $progress->start_progress('', 1, 7);
331 } catch (coding_exception $e) {
332 $this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
335 // Clear the time limit, otherwise phpunit complains.
340 * Checks the current progress values are as expected.
342 * @param number $min Expected min progress
343 * @param number $max Expected max progress
344 * @param core_backup_mock_progress $progress
346 private function assert_min_max($min, $max, core_backup_mock_progress $progress) {
347 $this->assertEquals(array($min, $max),
348 $progress->get_progress_proportion_range());
353 * Helper class that records when update_progress is called and allows time
356 class core_backup_mock_progress extends core_backup_progress {
357 private $updatecalled = false;
361 * Checks if update was called since the last call to this function.
363 * @return boolean True if update was called
365 public function was_update_called() {
366 if ($this->updatecalled) {
367 $this->updatecalled = false;
374 * Steps the current time by 1 second.
376 public function step_time() {
380 protected function update_progress() {
381 $this->updatecalled = true;
384 protected function get_time() {