Merge branch 'MDL-70422-310' of https://github.com/paulholden/moodle into MOODLE_310_...
[moodle.git] / search / tests / skip_future_documents_iterator_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  * Test iterator that skips future documents
19  *
20  * @package core_search
21  * @category test
22  * @copyright 2017 The Open University
23  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace core_search;
28 defined('MOODLE_INTERNAL') || die();
30 /**
31  * Test iterator that skips future documents
32  *
33  * @package core_search
34  * @category test
35  * @copyright 2017 The Open University
36  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class skip_future_documents_iterator_testcase extends \basic_testcase {
40     /**
41      * Test normal case with all documents in the past.
42      */
43     public function test_iterator_all_in_past() {
44         $past = strtotime('2017-11-01');
45         $documents = [
46             self::make_doc($past, 1),
47             self::make_doc($past + 1, 2),
48             self::make_doc($past + 2, 3)
49         ];
50         $this->assertEquals('mod_x-frog-1.mod_x-frog-2.mod_x-frog-3.',
51                 self::do_iterator($documents));
52     }
54     /**
55      * Confirm that the iterator does not call its parent iterator current() function too many
56      * times.
57      */
58     public function test_iterator_performance() {
59         $counter = new test_counting_iterator();
60         $iterator = new skip_future_documents_iterator($counter);
61         $items = 0;
62         foreach ($iterator as $value) {
63             $this->assertEquals(false, $value);
64             $items++;
65         }
66         $this->assertEquals(3, $items);
67         $this->assertEquals(3, $counter->get_count());
68     }
70     /**
71      * Test with no documents at all.
72      */
73     public function test_iterator_empty() {
74         $this->assertEquals('', self::do_iterator([]));
75     }
77     /**
78      * Test if some documents are in the future.
79      */
80     public function test_iterator_some_in_future() {
81         $past = strtotime('2017-11-01');
82         $future = time() + 1000;
83         $documents = [
84             self::make_doc($past, 1),
85             self::make_doc($past + 1, 2),
86             self::make_doc($future, 3)
87         ];
88         $this->assertEquals('mod_x-frog-1.mod_x-frog-2.',
89                 self::do_iterator($documents));
90     }
92     /**
93      * Test if all documents are in the future.
94      */
95     public function test_iterator_all_in_future() {
96         $future = time() + 1000;
97         $documents = [
98             self::make_doc($future, 1),
99             self::make_doc($future + 1, 2),
100             self::make_doc($future + 2, 3)
101         ];
102         $this->assertEquals('', self::do_iterator($documents));
103     }
105     /**
106      * Test when some documents return error.
107      */
108     public function test_iterator_some_false() {
109         $past = strtotime('2017-11-01');
110         $documents = [
111             self::make_doc($past, 1),
112             false,
113             self::make_doc($past + 2, 3)
114         ];
115         $this->assertEquals('mod_x-frog-1.false.mod_x-frog-3.',
116                 self::do_iterator($documents));
117     }
119     /**
120      * Test when all documents return error.
121      */
122     public function test_iterator_all_false() {
123         $documents = [
124             false,
125             false,
126             false
127         ];
128         $this->assertEquals('false.false.false.',
129                 self::do_iterator($documents));
130     }
132     /**
133      * Test iterator with all cases.
134      */
135     public function test_iterator_past_false_and_future() {
136         $past = strtotime('2017-11-01');
137         $future = time() + 1000;
138         $documents = [
139             false,
140             self::make_doc($past, 1),
141             false,
142             self::make_doc($past + 1, 2),
143             false,
144             self::make_doc($future, 3),
145             false
146         ];
147         $this->assertEquals('false.mod_x-frog-1.false.mod_x-frog-2.false.',
148                 self::do_iterator($documents));
149     }
151     /**
152      * Helper function to create a search document.
153      *
154      * @param int $time Modified time
155      * @param int $index Item id
156      * @return document Search document
157      */
158     protected static function make_doc($time, $index) {
159         $doc = new document($index, 'mod_x', 'frog');
160         $doc->set('modified', $time);
161         return $doc;
162     }
164     /**
165      * Puts documents through the iterator and returns result as a string for easy testing.
166      *
167      * @param document[] $documents Array of documents
168      * @return string Documents converted to string
169      */
170     protected static function do_iterator(array $documents) {
171         $parent = new \ArrayIterator($documents);
172         $iterator = new skip_future_documents_iterator($parent);
173         $result = '';
174         foreach ($iterator as $rec) {
175             if (!$rec) {
176                 $result .= 'false.';
177             } else {
178                 $result .= $rec->get('id') . '.';
179             }
180         }
181         return $result;
182     }
185 /**
186  * Fake iterator just for counting how many times current() is called. It returns 'false' 3 times.
187  *
188  * @package core_search
189  * @category test
190  * @copyright 2017 The Open University
191  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
192  */
193 class test_counting_iterator implements \Iterator {
195     /** @var int Current position in iterator */
196     protected $pos = 0;
197     /** @var int Number of calls to current() function */
198     protected $count = 0;
200     /**
201      * Returns the current element.
202      *
203      * @return mixed Can return any type.
204      */
205     public function current() {
206         $this->count++;
207         return false;
208     }
210     /**
211      * Counts iterator usage.
212      *
213      * @return int Number of times current() was called
214      */
215     public function get_count() {
216         return $this->count;
217     }
219     /**
220      * Goes on to the next element.
221      */
222     public function next() {
223         $this->pos++;
224     }
226     /**
227      * Gets the key (not supported)
228      *
229      * @throws \coding_exception Always
230      */
231     public function key() {
232         throw new \coding_exception('Unsupported');
233     }
235     /**
236      * Checks if iterato is valid (still has entries).
237      *
238      * @return bool True if still valid
239      */
240     public function valid() {
241         return $this->pos < 3;
242     }
244     /**
245      * Rewinds the iterator.
246      */
247     public function rewind() {
248         $this->pos = 0;
249     }