Merge branch 'wip-mdl-52007' of https://github.com/rajeshtaneja/moodle
[moodle.git] / lib / tests / progress_test.php
blob5181f4f59d4393daa1350e0afbdd30b9c0eab78e
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 * Unit tests for the progress classes.
20 * @package core_progress
21 * @category phpunit
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 /**
29 * Progress tests.
31 class core_progress_testcase extends basic_testcase {
33 /**
34 * Tests for basic use with simple numeric progress.
36 public function test_basic() {
37 $progress = new core_mock_progress();
39 // Check values of empty progress things.
40 $this->assertFalse($progress->is_in_progress_section());
42 // Start progress counting, check basic values and check that update
43 // gets called.
44 $progress->start_progress('hello', 10);
45 $this->assertTrue($progress->was_update_called());
46 $this->assertTrue($progress->is_in_progress_section());
47 $this->assertEquals('hello', $progress->get_current_description());
49 // Check numeric position and indeterminate count.
50 $this->assert_min_max(0.0, 0.0, $progress);
51 $this->assertEquals(0, $progress->get_progress_count());
53 // Make some progress and check that the time limit gets added.
54 $progress->step_time();
55 core_php_time_limit::get_and_clear_unit_test_data();
56 $progress->progress(2);
57 $this->assertTrue($progress->was_update_called());
58 $this->assertEquals(array(\core\progress\base::TIME_LIMIT_WITHOUT_PROGRESS),
59 core_php_time_limit::get_and_clear_unit_test_data());
61 // Check the new value.
62 $this->assert_min_max(0.2, 0.2, $progress);
64 // Do another progress run at same time, it should be ignored.
65 $progress->progress(3);
66 $this->assertFalse($progress->was_update_called());
67 $this->assert_min_max(0.3, 0.3, $progress);
69 // End the section. This should cause an update.
70 $progress->end_progress();
71 $this->assertTrue($progress->was_update_called());
73 // Because there are no sections left open, it thinks we finished.
74 $this->assert_min_max(1.0, 1.0, $progress);
76 // There was 1 progress call.
77 $this->assertEquals(1, $progress->get_progress_count());
80 /**
81 * Tests progress that is nested and/or indeterminate.
83 public function test_nested() {
84 // Outer progress goes from 0 to 10.
85 $progress = new core_mock_progress();
86 $progress->start_progress('hello', 10);
88 // Get up to 4, check position.
89 $progress->step_time();
90 $progress->progress(4);
91 $this->assert_min_max(0.4, 0.4, $progress);
92 $this->assertEquals('hello', $progress->get_current_description());
94 // Now start indeterminate progress.
95 $progress->start_progress('world');
96 $this->assert_min_max(0.4, 0.5, $progress);
97 $this->assertEquals('world', $progress->get_current_description());
99 // Do some indeterminate progress and count it (once per second).
100 $progress->step_time();
101 $progress->progress();
102 $this->assertEquals(2, $progress->get_progress_count());
103 $progress->progress();
104 $this->assertEquals(2, $progress->get_progress_count());
105 $progress->step_time();
106 $progress->progress();
107 $this->assertEquals(3, $progress->get_progress_count());
108 $this->assert_min_max(0.4, 0.5, $progress);
110 // Exit the indeterminate section.
111 $progress->end_progress();
112 $this->assert_min_max(0.5, 0.5, $progress);
114 $progress->step_time();
115 $progress->progress(7);
116 $this->assert_min_max(0.7, 0.7, $progress);
118 // Enter a numbered section (this time with a range of 5).
119 $progress->start_progress('frogs', 5);
120 $this->assert_min_max(0.7, 0.7, $progress);
121 $progress->step_time();
122 $progress->progress(1);
123 $this->assert_min_max(0.72, 0.72, $progress);
124 $progress->step_time();
125 $progress->progress(3);
126 $this->assert_min_max(0.76, 0.76, $progress);
128 // Now enter another indeterminate section.
129 $progress->start_progress('and');
130 $this->assert_min_max(0.76, 0.78, $progress);
132 // Make some progress, should increment indeterminate count.
133 $progress->step_time();
134 $progress->progress();
135 $this->assertEquals(7, $progress->get_progress_count());
137 // Enter numbered section, won't make any difference to values.
138 $progress->start_progress('zombies', 2);
139 $progress->step_time();
140 $progress->progress(1);
141 $this->assert_min_max(0.76, 0.78, $progress);
142 $this->assertEquals(8, $progress->get_progress_count());
144 // Leaving it will make no difference too.
145 $progress->end_progress();
147 // Leaving the indeterminate section will though.
148 $progress->end_progress();
149 $this->assert_min_max(0.78, 0.78, $progress);
151 // Leave the two numbered sections.
152 $progress->end_progress();
153 $this->assert_min_max(0.8, 0.8, $progress);
154 $progress->end_progress();
155 $this->assertFalse($progress->is_in_progress_section());
159 * Tests the feature for 'weighting' nested progress.
161 public function test_nested_weighted() {
162 $progress = new core_mock_progress();
163 $progress->start_progress('', 10);
165 // First nested child has 2 units of its own and is worth 1 unit.
166 $progress->start_progress('', 2);
167 $progress->step_time();
168 $progress->progress(1);
169 $this->assert_min_max(0.05, 0.05, $progress);
170 $progress->end_progress();
171 $this->assert_min_max(0.1, 0.1, $progress);
173 // Next child has 2 units of its own but is worth 3 units.
174 $progress->start_progress('weighted', 2, 3);
175 $progress->step_time();
176 $progress->progress(1);
177 $this->assert_min_max(0.25, 0.25, $progress);
178 $progress->end_progress();
179 $this->assert_min_max(0.4, 0.4, $progress);
181 // Next indeterminate child is worth 6 units.
182 $progress->start_progress('', \core\progress\base::INDETERMINATE, 6);
183 $progress->step_time();
184 $progress->progress();
185 $this->assert_min_max(0.4, 1.0, $progress);
186 $progress->end_progress();
187 $this->assert_min_max(1.0, 1.0, $progress);
191 * I had some issues with real use in backup/restore, this test is intended
192 * to be similar.
194 public function test_realistic() {
195 $progress = new core_mock_progress();
196 $progress->start_progress('parent', 100);
197 $progress->start_progress('child', 1);
198 $progress->progress(1);
199 $this->assert_min_max(0.01, 0.01, $progress);
200 $progress->end_progress();
201 $this->assert_min_max(0.01, 0.01, $progress);
205 * To avoid causing problems, progress needs to work for sections that have
206 * zero entries.
208 public function test_zero() {
209 $progress = new core_mock_progress();
210 $progress->start_progress('parent', 100);
211 $progress->progress(1);
212 $this->assert_min_max(0.01, 0.01, $progress);
213 $progress->start_progress('child', 0);
215 // For 'zero' progress, the progress section as immediately complete
216 // within the parent count, so it moves up to 2%.
217 $this->assert_min_max(0.02, 0.02, $progress);
218 $progress->progress(0);
219 $this->assert_min_max(0.02, 0.02, $progress);
220 $progress->end_progress();
221 $this->assert_min_max(0.02, 0.02, $progress);
225 * Tests for any exceptions due to invalid calls.
227 public function test_exceptions() {
228 $progress = new core_mock_progress();
230 // Check errors when empty.
231 try {
232 $progress->progress();
233 $this->fail();
234 } catch (coding_exception $e) {
235 $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
237 try {
238 $progress->end_progress();
239 $this->fail();
240 } catch (coding_exception $e) {
241 $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
243 try {
244 $progress->get_current_description();
245 $this->fail();
246 } catch (coding_exception $e) {
247 $this->assertEquals(1, preg_match('~Not inside progress~', $e->getMessage()));
249 try {
250 $progress->start_progress('', 1, 7);
251 $this->fail();
252 } catch (coding_exception $e) {
253 $this->assertEquals(1, preg_match('~must be 1~', $e->getMessage()));
256 // Check invalid start (-2).
257 try {
258 $progress->start_progress('hello', -2);
259 $this->fail();
260 } catch (coding_exception $e) {
261 $this->assertEquals(1, preg_match('~cannot be negative~', $e->getMessage()));
264 // Indeterminate when value expected.
265 $progress->start_progress('hello', 10);
266 try {
267 $progress->progress(\core\progress\base::INDETERMINATE);
268 $this->fail();
269 } catch (coding_exception $e) {
270 $this->assertEquals(1, preg_match('~expecting value~', $e->getMessage()));
273 // Value when indeterminate expected.
274 $progress->start_progress('hello');
275 try {
276 $progress->progress(4);
277 $this->fail();
278 } catch (coding_exception $e) {
279 $this->assertEquals(1, preg_match('~expecting INDETERMINATE~', $e->getMessage()));
282 // Illegal values.
283 $progress->start_progress('hello', 10);
284 try {
285 $progress->progress(-2);
286 $this->fail();
287 } catch (coding_exception $e) {
288 $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
290 try {
291 $progress->progress(11);
292 $this->fail();
293 } catch (coding_exception $e) {
294 $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
297 // You are allowed two with the same value...
298 $progress->progress(4);
299 $progress->step_time();
300 $progress->progress(4);
301 $progress->step_time();
303 // ...but not to go backwards.
304 try {
305 $progress->progress(3);
306 $this->fail();
307 } catch (coding_exception $e) {
308 $this->assertEquals(1, preg_match('~backwards~', $e->getMessage()));
311 // When you go forward, you can't go further than there is room.
312 try {
313 $progress->start_progress('', 1, 7);
314 $this->fail();
315 } catch (coding_exception $e) {
316 $this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
320 public function test_progress_change() {
322 $progress = new core_mock_progress();
324 $progress->start_progress('hello', 50);
327 for ($n = 1; $n <= 10; $n++) {
328 $progress->increment_progress();
331 // Check numeric position and indeterminate count.
332 $this->assert_min_max(0.2, 0.2, $progress);
333 $this->assertEquals(1, $progress->get_progress_count());
335 // Make some progress and check that the time limit gets added.
336 $progress->step_time();
338 for ($n = 1; $n <= 20; $n++) {
339 $progress->increment_progress();
342 $this->assertTrue($progress->was_update_called());
344 // Check the new value.
345 $this->assert_min_max(0.6, 0.6, $progress);
346 $this->assertEquals(2, $progress->get_progress_count());
348 for ($n = 1; $n <= 10; $n++) {
349 $progress->increment_progress();
351 $this->assertFalse($progress->was_update_called());
352 $this->assert_min_max(0.8, 0.8, $progress);
353 $this->assertEquals(2, $progress->get_progress_count());
355 // Do another progress run at same time, it should be ignored.
356 $progress->increment_progress(5);
357 $this->assertFalse($progress->was_update_called());
358 $this->assert_min_max(0.9, 0.9, $progress);
359 $this->assertEquals(2, $progress->get_progress_count());
361 for ($n = 1; $n <= 3; $n++) {
362 $progress->step_time();
363 $progress->increment_progress(1);
365 $this->assertTrue($progress->was_update_called());
366 $this->assert_min_max(0.96, 0.96, $progress);
367 $this->assertEquals(5, $progress->get_progress_count());
370 // End the section. This should cause an update.
371 $progress->end_progress();
372 $this->assertTrue($progress->was_update_called());
373 $this->assertEquals(5, $progress->get_progress_count());
375 // Because there are no sections left open, it thinks we finished.
376 $this->assert_min_max(1.0, 1.0, $progress);
380 * Checks the current progress values are as expected.
382 * @param number $min Expected min progress
383 * @param number $max Expected max progress
384 * @param core_mock_progress $progress
386 private function assert_min_max($min, $max, core_mock_progress $progress) {
387 $this->assertEquals(array($min, $max),
388 $progress->get_progress_proportion_range());
393 * Helper class that records when update_progress is called and allows time
394 * stepping.
396 class core_mock_progress extends \core\progress\base {
397 private $updatecalled = false;
398 private $time = 1;
401 * Checks if update was called since the last call to this function.
403 * @return boolean True if update was called
405 public function was_update_called() {
406 if ($this->updatecalled) {
407 $this->updatecalled = false;
408 return true;
410 return false;
414 * Steps the current time by 1 second.
416 public function step_time() {
417 $this->time++;
420 protected function update_progress() {
421 $this->updatecalled = true;
424 protected function get_time() {
425 return $this->time;