MDL-42084 Unit tests: Remove unnecessary 'clear time limit change' lines
[moodle.git] / backup / util / progress / tests / progress_test.php
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.
13 //
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.
19  *
20  * @package core_backup
21  * @category phpunit
22  * @copyright 2013 The Open University
23  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 // Include all the needed stuff.
29 global $CFG;
30 require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
32 /**
33  * Progress tests.
34  */
35 class backup_progress_testcase extends basic_testcase {
37     /**
38      * Tests for basic use with simple numeric progress.
39      */
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
47         // gets called.
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());
82     }
84     /**
85      * Tests progress that is nested and/or indeterminate.
86      */
87     public function test_nested() {
88         // Outer progress goes from 0 to 10.
89         $progress = new core_backup_mock_progress();
90         $progress->start_progress('hello', 10);
92         // Get up to 4, check position.
93         $progress->step_time();
94         $progress->progress(4);
95         $this->assert_min_max(0.4, 0.4, $progress);
96         $this->assertEquals('hello', $progress->get_current_description());
98         // Now start indeterminate progress.
99         $progress->start_progress('world');
100         $this->assert_min_max(0.4, 0.5, $progress);
101         $this->assertEquals('world', $progress->get_current_description());
103         // Do some indeterminate progress and count it (once per second).
104         $progress->step_time();
105         $progress->progress();
106         $this->assertEquals(2, $progress->get_progress_count());
107         $progress->progress();
108         $this->assertEquals(2, $progress->get_progress_count());
109         $progress->step_time();
110         $progress->progress();
111         $this->assertEquals(3, $progress->get_progress_count());
112         $this->assert_min_max(0.4, 0.5, $progress);
114         // Exit the indeterminate section.
115         $progress->end_progress();
116         $this->assert_min_max(0.5, 0.5, $progress);
118         $progress->step_time();
119         $progress->progress(7);
120         $this->assert_min_max(0.7, 0.7, $progress);
122         // Enter a numbered section (this time with a range of 5).
123         $progress->start_progress('frogs', 5);
124         $this->assert_min_max(0.7, 0.7, $progress);
125         $progress->step_time();
126         $progress->progress(1);
127         $this->assert_min_max(0.72, 0.72, $progress);
128         $progress->step_time();
129         $progress->progress(3);
130         $this->assert_min_max(0.76, 0.76, $progress);
132         // Now enter another indeterminate section.
133         $progress->start_progress('and');
134         $this->assert_min_max(0.76, 0.78, $progress);
136         // Make some progress, should increment indeterminate count.
137         $progress->step_time();
138         $progress->progress();
139         $this->assertEquals(7, $progress->get_progress_count());
141         // Enter numbered section, won't make any difference to values.
142         $progress->start_progress('zombies', 2);
143         $progress->step_time();
144         $progress->progress(1);
145         $this->assert_min_max(0.76, 0.78, $progress);
146         $this->assertEquals(8, $progress->get_progress_count());
148         // Leaving it will make no difference too.
149         $progress->end_progress();
151         // Leaving the indeterminate section will though.
152         $progress->end_progress();
153         $this->assert_min_max(0.78, 0.78, $progress);
155         // Leave the two numbered sections.
156         $progress->end_progress();
157         $this->assert_min_max(0.8, 0.8, $progress);
158         $progress->end_progress();
159         $this->assertFalse($progress->is_in_progress_section());
160     }
162     /**
163      * Tests the feature for 'weighting' nested progress.
164      */
165     public function test_nested_weighted() {
166         $progress = new core_backup_mock_progress();
167         $progress->start_progress('', 10);
169         // First nested child has 2 units of its own and is worth 1 unit.
170         $progress->start_progress('', 2);
171         $progress->step_time();
172         $progress->progress(1);
173         $this->assert_min_max(0.05, 0.05, $progress);
174         $progress->end_progress();
175         $this->assert_min_max(0.1, 0.1, $progress);
177         // Next child has 2 units of its own but is worth 3 units.
178         $progress->start_progress('weighted', 2, 3);
179         $progress->step_time();
180         $progress->progress(1);
181         $this->assert_min_max(0.25, 0.25, $progress);
182         $progress->end_progress();
183         $this->assert_min_max(0.4, 0.4, $progress);
185         // Next indeterminate child is worth 6 units.
186         $progress->start_progress('', core_backup_progress::INDETERMINATE, 6);
187         $progress->step_time();
188         $progress->progress();
189         $this->assert_min_max(0.4, 1.0, $progress);
190         $progress->end_progress();
191         $this->assert_min_max(1.0, 1.0, $progress);
192     }
194     /**
195      * I had some issues with real use in backup/restore, this test is intended
196      * to be similar.
197      */
198     public function test_realistic() {
199         $progress = new core_backup_mock_progress();
200         $progress->start_progress('parent', 100);
201         $progress->start_progress('child', 1);
202         $progress->progress(1);
203         $this->assert_min_max(0.01, 0.01, $progress);
204         $progress->end_progress();
205         $this->assert_min_max(0.01, 0.01, $progress);
206     }
208     /**
209      * To avoid causing problems, progress needs to work for sections that have
210      * zero entries.
211      */
212     public function test_zero() {
213         $progress = new core_backup_mock_progress();
214         $progress->start_progress('parent', 100);
215         $progress->progress(1);
216         $this->assert_min_max(0.01, 0.01, $progress);
217         $progress->start_progress('child', 0);
219         // For 'zero' progress, the progress section as immediately complete
220         // within the parent count, so it moves up to 2%.
221         $this->assert_min_max(0.02, 0.02, $progress);
222         $progress->progress(0);
223         $this->assert_min_max(0.02, 0.02, $progress);
224         $progress->end_progress();
225         $this->assert_min_max(0.02, 0.02, $progress);
226     }
228     /**
229      * Tests for any exceptions due to invalid calls.
230      */
231     public function test_exceptions() {
232         $progress = new core_backup_mock_progress();
234         // Check errors when empty.
235         try {
236             $progress->progress();
237             $this->fail();
238         } catch (coding_exception $e) {
239             $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
240         }
241         try {
242             $progress->end_progress();
243             $this->fail();
244         } catch (coding_exception $e) {
245             $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
246         }
247         try {
248             $progress->get_current_description();
249             $this->fail();
250         } catch (coding_exception $e) {
251             $this->assertEquals(1, preg_match('~Not inside progress~', $e->getMessage()));
252         }
253         try {
254             $progress->start_progress('', 1, 7);
255             $this->fail();
256         } catch (coding_exception $e) {
257             $this->assertEquals(1, preg_match('~must be 1~', $e->getMessage()));
258         }
260         // Check invalid start (-2).
261         try {
262             $progress->start_progress('hello', -2);
263             $this->fail();
264         } catch (coding_exception $e) {
265             $this->assertEquals(1, preg_match('~cannot be negative~', $e->getMessage()));
266         }
268         // Indeterminate when value expected.
269         $progress->start_progress('hello', 10);
270         try {
271             $progress->progress(core_backup_progress::INDETERMINATE);
272             $this->fail();
273         } catch (coding_exception $e) {
274             $this->assertEquals(1, preg_match('~expecting value~', $e->getMessage()));
275         }
277         // Value when indeterminate expected.
278         $progress->start_progress('hello');
279         try {
280             $progress->progress(4);
281             $this->fail();
282         } catch (coding_exception $e) {
283             $this->assertEquals(1, preg_match('~expecting INDETERMINATE~', $e->getMessage()));
284         }
286         // Illegal values.
287         $progress->start_progress('hello', 10);
288         try {
289             $progress->progress(-2);
290             $this->fail();
291         } catch (coding_exception $e) {
292             $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
293         }
294         try {
295             $progress->progress(11);
296             $this->fail();
297         } catch (coding_exception $e) {
298             $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
299         }
301         // You are allowed two with the same value...
302         $progress->progress(4);
303         $progress->step_time();
304         $progress->progress(4);
305         $progress->step_time();
307         // ...but not to go backwards.
308         try {
309             $progress->progress(3);
310             $this->fail();
311         } catch (coding_exception $e) {
312             $this->assertEquals(1, preg_match('~backwards~', $e->getMessage()));
313         }
315         // When you go forward, you can't go further than there is room.
316         try {
317             $progress->start_progress('', 1, 7);
318             $this->fail();
319         } catch (coding_exception $e) {
320             $this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
321         }
322     }
324     /**
325      * Checks the current progress values are as expected.
326      *
327      * @param number $min Expected min progress
328      * @param number $max Expected max progress
329      * @param core_backup_mock_progress $progress
330      */
331     private function assert_min_max($min, $max, core_backup_mock_progress $progress) {
332         $this->assertEquals(array($min, $max),
333                 $progress->get_progress_proportion_range());
334     }
337 /**
338  * Helper class that records when update_progress is called and allows time
339  * stepping.
340  */
341 class core_backup_mock_progress extends core_backup_progress {
342     private $updatecalled = false;
343     private $time = 1;
345     /**
346      * Checks if update was called since the last call to this function.
347      *
348      * @return boolean True if update was called
349      */
350     public function was_update_called() {
351         if ($this->updatecalled) {
352             $this->updatecalled = false;
353             return true;
354         }
355         return false;
356     }
358     /**
359      * Steps the current time by 1 second.
360      */
361     public function step_time() {
362         $this->time++;
363     }
365     protected function update_progress() {
366         $this->updatecalled = true;
367     }
369     protected function get_time() {
370         return $this->time;
371     }