MDL-45828 cache: definitions now sorted in the admin UI
[moodle.git] / lib / tests / collator_test.php
CommitLineData
d534708f
PS
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/>.
16
17/**
18 * Collator unit tests.
19 *
20 * @package core
21 * @category phpunit
22 * @copyright 2011 Sam Hemelryk
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28/**
5b59bc29 29 * Unit tests for our utf-8 aware collator which is used for sorting.
d534708f
PS
30 *
31 * @package core
32 * @category phpunit
33 * @copyright 2011 Sam Hemelryk
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 */
78c12cdb 36class core_collator_testcase extends advanced_testcase {
d534708f
PS
37
38 /**
39 * @var string The initial lang, stored because we change it during testing
40 */
41 protected $initiallang = null;
42
43 /**
5b59bc29 44 * @var string The last error that has occurred
d534708f
PS
45 */
46 protected $error = null;
47
48 /**
5b59bc29 49 * Prepares things for this test case.
d534708f
PS
50 */
51 protected function setUp() {
52 global $SESSION;
53 if (isset($SESSION->lang)) {
54 $this->initiallang = $SESSION->lang;
55 }
5b59bc29 56 $SESSION->lang = 'en'; // Make sure we test en language to get consistent results, hopefully all systems have this locale.
d534708f
PS
57 if (extension_loaded('intl')) {
58 $this->error = 'Collation aware sorting not supported';
59 } else {
60 $this->error = 'Collation aware sorting not supported, PHP extension "intl" is not available.';
61 }
62 parent::setUp();
63 }
64
65 /**
5b59bc29 66 * Cleans things up after this test case has run.
d534708f
PS
67 */
68 protected function tearDown() {
69 global $SESSION;
70 parent::tearDown();
71 if ($this->initiallang !== null) {
72 $SESSION->lang = $this->initiallang;
73 $this->initiallang = null;
74 } else {
75 unset($SESSION->lang);
76 }
77 }
78
79 /**
5b59bc29 80 * Tests the static asort method.
d534708f
PS
81 */
82 public function test_asort() {
83 $arr = array('b' => 'ab', 1 => 'aa', 0 => 'cc');
84 $result = core_collator::asort($arr);
5b59bc29
PS
85 $this->assertSame(array('aa', 'ab', 'cc'), array_values($arr));
86 $this->assertSame(array(1, 'b', 0), array_keys($arr));
d534708f
PS
87 $this->assertTrue($result);
88
89 $arr = array('b' => 'ab', 1 => 'aa', 0 => 'cc');
90 $result = core_collator::asort($arr, core_collator::SORT_STRING);
5b59bc29
PS
91 $this->assertSame(array('aa', 'ab', 'cc'), array_values($arr));
92 $this->assertSame(array(1, 'b', 0), array_keys($arr));
d534708f
PS
93 $this->assertTrue($result);
94
95 $arr = array('b' => 'aac', 1 => 'Aac', 0 => 'cc');
96 $result = core_collator::asort($arr, (core_collator::SORT_STRING | core_collator::CASE_SENSITIVE));
5b59bc29
PS
97 $this->assertSame(array('Aac', 'aac', 'cc'), array_values($arr));
98 $this->assertSame(array(1, 'b', 0), array_keys($arr));
d534708f
PS
99 $this->assertTrue($result);
100
101 $arr = array('b' => 'a1', 1 => 'a10', 0 => 'a3b');
102 $result = core_collator::asort($arr);
5b59bc29
PS
103 $this->assertSame(array('a1', 'a10', 'a3b'), array_values($arr));
104 $this->assertSame(array('b', 1, 0), array_keys($arr));
d534708f
PS
105 $this->assertTrue($result);
106
107 $arr = array('b' => 'a1', 1 => 'a10', 0 => 'a3b');
108 $result = core_collator::asort($arr, core_collator::SORT_NATURAL);
5b59bc29
PS
109 $this->assertSame(array('a1', 'a3b', 'a10'), array_values($arr));
110 $this->assertSame(array('b', 0, 1), array_keys($arr));
d534708f
PS
111 $this->assertTrue($result);
112
113 $arr = array('b' => '1.1.1', 1 => '1.2', 0 => '1.20.2');
114 $result = core_collator::asort($arr, core_collator::SORT_NATURAL);
115 $this->assertSame(array_values($arr), array('1.1.1', '1.2', '1.20.2'));
116 $this->assertSame(array_keys($arr), array('b', 1, 0));
117 $this->assertTrue($result);
118
119 $arr = array('b' => '-1', 1 => 1000, 0 => -1.2, 3 => 1, 4 => false);
120 $result = core_collator::asort($arr, core_collator::SORT_NUMERIC);
5b59bc29
PS
121 $this->assertSame(array(-1.2, '-1', false, 1, 1000), array_values($arr));
122 $this->assertSame(array(0, 'b', 4, 3, 1), array_keys($arr));
d534708f
PS
123 $this->assertTrue($result);
124
125 $arr = array('b' => array(1), 1 => array(2, 3), 0 => 1);
126 $result = core_collator::asort($arr, core_collator::SORT_REGULAR);
5b59bc29
PS
127 $this->assertSame(array(1, array(1), array(2, 3)), array_values($arr));
128 $this->assertSame(array(0, 'b', 1), array_keys($arr));
d534708f
PS
129 $this->assertTrue($result);
130
5b59bc29 131 // Test sorting of array of arrays - first element should be used for actual comparison.
d534708f
PS
132 $arr = array(0=>array('bb', 'z'), 1=>array('ab', 'a'), 2=>array('zz', 'x'));
133 $result = core_collator::asort($arr, core_collator::SORT_REGULAR);
5b59bc29 134 $this->assertSame(array(1, 0, 2), array_keys($arr));
d534708f
PS
135 $this->assertTrue($result);
136
5b59bc29 137 $arr = array('a' => 'áb', 'b' => 'ab', 1 => 'aa', 0=>'cc', 'x' => 'Áb');
d534708f 138 $result = core_collator::asort($arr);
5b59bc29
PS
139 $this->assertSame(array('aa', 'ab', 'áb', 'Áb', 'cc'), array_values($arr), $this->error);
140 $this->assertSame(array(1, 'b', 'a', 'x', 0), array_keys($arr), $this->error);
d534708f
PS
141 $this->assertTrue($result);
142
143 $a = array(2=>'b', 1=>'c');
144 $c =& $a;
145 $b =& $a;
146 core_collator::asort($b);
147 $this->assertSame($a, $b);
148 $this->assertSame($c, $b);
149 }
150
151 /**
5b59bc29 152 * Tests the static asort_objects_by_method method.
d534708f
PS
153 */
154 public function test_asort_objects_by_method() {
155 $objects = array(
156 'b' => new string_test_class('ab'),
157 1 => new string_test_class('aa'),
158 0 => new string_test_class('cc')
159 );
160 $result = core_collator::asort_objects_by_method($objects, 'get_protected_name');
5b59bc29
PS
161 $this->assertSame(array(1, 'b', 0), array_keys($objects));
162 $this->assertSame(array('aa', 'ab', 'cc'), $this->get_ordered_names($objects, 'get_protected_name'));
d534708f
PS
163 $this->assertTrue($result);
164
165 $objects = array(
166 'b' => new string_test_class('a20'),
167 1 => new string_test_class('a1'),
168 0 => new string_test_class('a100')
169 );
170 $result = core_collator::asort_objects_by_method($objects, 'get_protected_name', core_collator::SORT_NATURAL);
5b59bc29
PS
171 $this->assertSame(array(1, 'b', 0), array_keys($objects));
172 $this->assertSame(array('a1', 'a20', 'a100'), $this->get_ordered_names($objects, 'get_protected_name'));
d534708f
PS
173 $this->assertTrue($result);
174 }
175
176 /**
5b59bc29 177 * Tests the static asort_objects_by_method method.
d534708f
PS
178 */
179 public function test_asort_objects_by_property() {
180 $objects = array(
181 'b' => new string_test_class('ab'),
182 1 => new string_test_class('aa'),
183 0 => new string_test_class('cc')
184 );
185 $result = core_collator::asort_objects_by_property($objects, 'publicname');
5b59bc29
PS
186 $this->assertSame(array(1, 'b', 0), array_keys($objects));
187 $this->assertSame(array('aa', 'ab', 'cc'), $this->get_ordered_names($objects, 'publicname'));
d534708f
PS
188 $this->assertTrue($result);
189
190 $objects = array(
191 'b' => new string_test_class('a20'),
192 1 => new string_test_class('a1'),
193 0 => new string_test_class('a100')
194 );
195 $result = core_collator::asort_objects_by_property($objects, 'publicname', core_collator::SORT_NATURAL);
5b59bc29
PS
196 $this->assertSame(array(1, 'b', 0), array_keys($objects));
197 $this->assertSame(array('a1', 'a20', 'a100'), $this->get_ordered_names($objects, 'publicname'));
d534708f
PS
198 $this->assertTrue($result);
199 }
200
6e247996
SH
201 /**
202 * Tests the sorting of an array of arrays by key.
203 */
204 public function test_asort_array_of_arrays_by_key() {
205 $array = array(
206 'a' => array('name' => 'bravo'),
207 'b' => array('name' => 'charlie'),
208 'c' => array('name' => 'alpha')
209 );
210 $this->assertSame(array('a', 'b', 'c'), array_keys($array));
211 $this->assertTrue(core_collator::asort_array_of_arrays_by_key($array, 'name'));
212 $this->assertSame(array('c', 'a', 'b'), array_keys($array));
213
214 $array = array(
215 'a' => array('name' => 'b'),
216 'b' => array('name' => 1),
217 'c' => array('name' => 0)
218 );
219 $this->assertSame(array('a', 'b', 'c'), array_keys($array));
220 $this->assertTrue(core_collator::asort_array_of_arrays_by_key($array, 'name'));
221 $this->assertSame(array('c', 'b', 'a'), array_keys($array));
222
223 $array = array(
224 'a' => array('name' => 'áb'),
225 'b' => array('name' => 'ab'),
226 1 => array('name' => 'aa'),
227 'd' => array('name' => 'cc'),
228 0 => array('name' => 'Áb')
229 );
230 $this->assertSame(array('a', 'b', 1, 'd', 0), array_keys($array));
231 $this->assertTrue(core_collator::asort_array_of_arrays_by_key($array, 'name'));
232 $this->assertSame(array(1, 'b', 'a', 0, 'd'), array_keys($array));
233 $this->assertSame(array(
234 1 => array('name' => 'aa'),
235 'b' => array('name' => 'ab'),
236 'a' => array('name' => 'áb'),
237 0 => array('name' => 'Áb'),
238 'd' => array('name' => 'cc')
239 ), $array);
240
241 }
242
d534708f 243 /**
5b59bc29 244 * Returns an array of sorted names.
d534708f
PS
245 * @param array $objects
246 * @param string $methodproperty
5b59bc29 247 * @return array
d534708f
PS
248 */
249 protected function get_ordered_names($objects, $methodproperty = 'get_protected_name') {
250 $return = array();
251 foreach ($objects as $object) {
252 if ($methodproperty == 'publicname') {
253 $return[] = $object->publicname;
254 } else {
255 $return[] = $object->$methodproperty();
256 }
257 }
258 return $return;
259 }
260
261 /**
5b59bc29 262 * Tests the static ksort method.
d534708f
PS
263 */
264 public function test_ksort() {
265 $arr = array('b' => 'ab', 1 => 'aa', 0 => 'cc');
266 $result = core_collator::ksort($arr);
5b59bc29
PS
267 $this->assertSame(array(0, 1, 'b'), array_keys($arr));
268 $this->assertSame(array('cc', 'aa', 'ab'), array_values($arr));
d534708f
PS
269 $this->assertTrue($result);
270
271 $obj = new stdClass();
272 $arr = array('1.1.1'=>array(), '1.2'=>$obj, '1.20.2'=>null);
273 $result = core_collator::ksort($arr, core_collator::SORT_NATURAL);
5b59bc29
PS
274 $this->assertSame(array('1.1.1', '1.2', '1.20.2'), array_keys($arr));
275 $this->assertSame(array(array(), $obj, null), array_values($arr));
d534708f
PS
276 $this->assertTrue($result);
277
278 $a = array(2=>'b', 1=>'c');
279 $c =& $a;
280 $b =& $a;
281 core_collator::ksort($b);
282 $this->assertSame($a, $b);
283 $this->assertSame($c, $b);
284 }
285
286 public function test_legacy_collatorlib() {
287 $arr = array('b' => 'ab', 1 => 'aa', 0 => 'cc');
288 $result = collatorlib::asort($arr);
78c12cdb 289 $this->assertDebuggingCalled(null, null, 'This fails if any other test uses the deprecated collatorlib class.');
5b59bc29
PS
290 $this->assertSame(array('aa', 'ab', 'cc'), array_values($arr));
291 $this->assertSame(array(1, 'b', 0), array_keys($arr));
d534708f
PS
292 $this->assertTrue($result);
293 }
294}
295
296
297/**
298 * Simple class used to work with the unit test.
299 *
300 * @package core
301 * @category phpunit
302 * @copyright 2011 Sam Hemelryk
303 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
304 */
305class string_test_class extends stdClass {
306 /**
307 * @var string A public property
308 */
309 public $publicname;
310 /**
311 * @var string A protected property
312 */
313 protected $protectedname;
314 /**
315 * @var string A private property
316 */
317 private $privatename;
318 /**
5b59bc29 319 * Constructs the test instance.
d534708f
PS
320 * @param string $name
321 */
322 public function __construct($name) {
323 $this->publicname = $name;
324 $this->protectedname = $name;
325 $this->privatename = $name;
326 }
327 /**
5b59bc29 328 * Returns the protected property.
d534708f
PS
329 * @return string
330 */
331 public function get_protected_name() {
332 return $this->protectedname;
333 }
334 /**
5b59bc29 335 * Returns the protected property.
d534708f
PS
336 * @return string
337 */
338 public function get_private_name() {
339 return $this->publicname;
340 }
5b59bc29 341}