6 require_once 'application/Utils.php';
7 require_once 'application/Languages.php';
8 require_once 'tests/utils/ReferenceSessionIdHashes.php';
10 // Initialize reference data before PHPUnit starts a session
11 ReferenceSessionIdHashes
::genAllHashes();
15 * Unitary tests for Shaarli utilities
17 class UtilsTest
extends PHPUnit_Framework_TestCase
20 protected static $sidHashes = null;
23 protected static $testLogFile = 'tests.log';
25 // Expected log date format
26 protected static $dateFormat = 'Y/m/d H:i:s';
29 * @var string Save the current timezone.
31 protected static $defaultTimeZone;
35 * Assign reference data
37 public static function setUpBeforeClass()
39 self
::$sidHashes = ReferenceSessionIdHashes
::getHashes();
40 self
::$defaultTimeZone = date_default_timezone_get();
41 // Timezone without DST for test consistency
42 date_default_timezone_set('Africa/Nairobi');
48 public static function tearDownAfterClass()
50 date_default_timezone_set(self
::$defaultTimeZone);
54 * Resets test data before each test
56 protected function setUp()
58 if (file_exists(self
::$testLogFile)) {
59 unlink(self
::$testLogFile);
64 * Returns a list of the elements from the last logged entry
66 * @return list (date, ip address, message)
68 protected function getLastLogEntry()
70 $logFile = file(self
::$testLogFile);
71 return explode(' - ', trim(array_pop($logFile), PHP_EOL
));
75 * Log a message to a file - IPv4 client address
77 public function testLogmIp4()
79 $logMessage = 'IPv4 client connected';
80 logm(self
::$testLogFile, '127.0.0.1', $logMessage);
81 list($date, $ip, $message) = $this->getLastLogEntry();
83 $this->assertInstanceOf(
85 DateTime
::createFromFormat(self
::$dateFormat, $date)
88 filter_var($ip, FILTER_VALIDATE_IP
, FILTER_FLAG_IPV4
) !== false
90 $this->assertEquals($logMessage, $message);
94 * Log a message to a file - IPv6 client address
96 public function testLogmIp6()
98 $logMessage = 'IPv6 client connected';
99 logm(self
::$testLogFile, '2001:db8::ff00:42:8329', $logMessage);
100 list($date, $ip, $message) = $this->getLastLogEntry();
102 $this->assertInstanceOf(
104 DateTime
::createFromFormat(self
::$dateFormat, $date)
107 filter_var($ip, FILTER_VALIDATE_IP
, FILTER_FLAG_IPV6
) !== false
109 $this->assertEquals($logMessage, $message);
113 * Represent a link by its hash
115 public function testSmallHash()
117 $this->assertEquals('CyAAJw', smallHash('http://test.io'));
118 $this->assertEquals(6, strlen(smallHash('https://github.com')));
122 * Look for a substring at the beginning of a string
124 public function testStartsWithCaseInsensitive()
126 $this->assertTrue(startsWith('Lorem ipsum', 'lorem', false));
127 $this->assertTrue(startsWith('Lorem ipsum', 'LoReM i', false));
131 * Look for a substring at the beginning of a string (case-sensitive)
133 public function testStartsWithCaseSensitive()
135 $this->assertTrue(startsWith('Lorem ipsum', 'Lorem', true));
136 $this->assertFalse(startsWith('Lorem ipsum', 'lorem', true));
137 $this->assertFalse(startsWith('Lorem ipsum', 'LoReM i', true));
141 * Look for a substring at the beginning of a string (Unicode)
143 public function testStartsWithSpecialChars()
145 $this->assertTrue(startsWith('å!ùµ', 'å!', false));
146 $this->assertTrue(startsWith('µ$åù', 'µ$', true));
150 * Look for a substring at the end of a string
152 public function testEndsWithCaseInsensitive()
154 $this->assertTrue(endsWith('Lorem ipsum
', 'ipsum
', false));
155 $this->assertTrue(endsWith('Lorem ipsum
', 'm IpsUM
', false));
159 * Look for a substring at the end of a string (case-sensitive)
161 public function testEndsWithCaseSensitive()
163 $this->assertTrue(endsWith('lorem Ipsum
', 'Ipsum
', true));
164 $this->assertFalse(endsWith('lorem Ipsum
', 'ipsum
', true));
165 $this->assertFalse(endsWith('lorem Ipsum
', 'M IPsuM
', true));
169 * Look for a substring at the end of a string (Unicode)
171 public function testEndsWithSpecialChars()
173 $this->assertTrue(endsWith('å
!ùµ
', 'ùµ
', false));
174 $this->assertTrue(endsWith('µ$åù
', 'åù
', true));
178 * Check valid date strings, according to a DateTime format
180 public function testCheckValidDateFormat()
182 $this->assertTrue(checkDateFormat('Ymd
', '20150627'));
183 $this->assertTrue(checkDateFormat('Y
-m
-d
', '2015-06-27'));
187 * Check erroneous date strings, according to a DateTime format
189 public function testCheckInvalidDateFormat()
191 $this->assertFalse(checkDateFormat('Ymd
', '2015'));
192 $this->assertFalse(checkDateFormat('Y
-m
-d
', '2015-06'));
193 $this->assertFalse(checkDateFormat('Ymd
', 'DeLorean
'));
197 * Test generate location with valid data.
199 public function testGenerateLocation() {
200 $ref = 'http
://localhost/?test';
201 $this->assertEquals($ref, generateLocation($ref, 'localhost'));
202 $ref = 'http://localhost:8080/?test';
203 $this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
204 $ref = '?localreferer#hash';
205 $this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
209 * Test generate location - anti loop.
211 public function testGenerateLocationLoop() {
212 $ref = 'http://localhost/?test';
213 $this->assertEquals('?', generateLocation($ref, 'localhost', array('test')));
217 * Test generate location - from other domain.
219 public function testGenerateLocationOut() {
220 $ref = 'http://somewebsite.com/?test';
221 $this->assertEquals('?', generateLocation($ref, 'localhost'));
225 * Test is_session_id_valid with a valid ID - TEST ALL THE HASHES!
227 * This tests extensively covers all hash algorithms / bit representations
229 public function testIsAnyHashSessionIdValid()
231 foreach (self
::$sidHashes as $algo => $bpcs) {
232 foreach ($bpcs as $bpc => $hash) {
233 $this->assertTrue(is_session_id_valid($hash));
239 * Test is_session_id_valid with a valid ID - SHA-1 hashes
241 public function testIsSha1SessionIdValid()
243 $this->assertTrue(is_session_id_valid(sha1('shaarli')));
247 * Test is_session_id_valid with a valid ID - SHA-256 hashes
249 public function testIsSha256SessionIdValid()
251 $this->assertTrue(is_session_id_valid(hash('sha256', 'shaarli')));
255 * Test is_session_id_valid with a valid ID - SHA-512 hashes
257 public function testIsSha512SessionIdValid()
259 $this->assertTrue(is_session_id_valid(hash('sha512', 'shaarli')));
263 * Test is_session_id_valid with invalid IDs.
265 public function testIsSessionIdInvalid()
267 $this->assertFalse(is_session_id_valid(''));
268 $this->assertFalse(is_session_id_valid(array()));
270 is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
275 * Test generateSecretApi.
277 public function testGenerateSecretApi()
279 $this->assertEquals(12, strlen(generate_api_secret('foo', 'bar')));
283 * Test generateSecretApi with invalid parameters.
285 public function testGenerateSecretApiInvalid()
287 $this->assertFalse(generate_api_secret('', ''));
288 $this->assertFalse(generate_api_secret(false, false));
292 * Test normalize_spaces.
294 public function testNormalizeSpace()
296 $str = ' foo bar is important ';
297 $this->assertEquals('foo bar is important', normalize_spaces($str));
298 $this->assertEquals('foo', normalize_spaces('foo'));
299 $this->assertEquals('', normalize_spaces(''));
300 $this->assertEquals(null, normalize_spaces(null));
304 * Test arrays_combine
306 public function testCartesianProductGenerator()
308 $arr = [['ab', 'cd'], ['ef', 'gh'], ['ij', 'kl'], ['m']];
310 ['ab', 'ef', 'ij', 'm'],
311 ['ab', 'ef', 'kl', 'm'],
312 ['ab', 'gh', 'ij', 'm'],
313 ['ab', 'gh', 'kl', 'm'],
314 ['cd', 'ef', 'ij', 'm'],
315 ['cd', 'ef', 'kl', 'm'],
316 ['cd', 'gh', 'ij', 'm'],
317 ['cd', 'gh', 'kl', 'm'],
319 $this->assertEquals($expected, iterator_to_array(cartesian_product_generator($arr)));
323 * Test date_format() with invalid parameter.
325 public function testDateFormatInvalid()
327 $this->assertFalse(format_date([]));
328 $this->assertFalse(format_date(null));
332 * Test is_integer_mixed with valid values
334 public function testIsIntegerMixedValid()
336 $this->assertTrue(is_integer_mixed(12));
337 $this->assertTrue(is_integer_mixed('12'));
338 $this->assertTrue(is_integer_mixed(-12));
339 $this->assertTrue(is_integer_mixed('-12'));
340 $this->assertTrue(is_integer_mixed(0));
341 $this->assertTrue(is_integer_mixed('0'));
342 $this->assertTrue(is_integer_mixed(0x0a));
346 * Test is_integer_mixed with invalid values
348 public function testIsIntegerMixedInvalid()
350 $this->assertFalse(is_integer_mixed(true));
351 $this->assertFalse(is_integer_mixed(false));
352 $this->assertFalse(is_integer_mixed([]));
353 $this->assertFalse(is_integer_mixed(['test']));
354 $this->assertFalse(is_integer_mixed([12]));
355 $this->assertFalse(is_integer_mixed(new DateTime()));
356 $this->assertFalse(is_integer_mixed('0x0a'));
357 $this->assertFalse(is_integer_mixed('12k'));
358 $this->assertFalse(is_integer_mixed('k12'));
359 $this->assertFalse(is_integer_mixed(''));
365 public function testReturnBytes()
367 $this->assertEquals(2 * 1024, return_bytes('2k'));
368 $this->assertEquals(2 * 1024, return_bytes('2K'));
369 $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2m'));
370 $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2M'));
371 $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2g'));
372 $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2G'));
373 $this->assertEquals(374, return_bytes('374'));
374 $this->assertEquals(374, return_bytes(374));
375 $this->assertEquals(0, return_bytes('0'));
376 $this->assertEquals(0, return_bytes(0));
377 $this->assertEquals(-1, return_bytes('-1'));
378 $this->assertEquals(-1, return_bytes(-1));
379 $this->assertEquals('', return_bytes(''));
385 public function testHumanBytes()
387 $this->assertEquals('2kiB', human_bytes(2 * 1024));
388 $this->assertEquals('2kiB', human_bytes(strval(2 * 1024)));
389 $this->assertEquals('2MiB', human_bytes(2 * (pow(1024, 2))));
390 $this->assertEquals('2MiB', human_bytes(strval(2 * (pow(1024, 2)))));
391 $this->assertEquals('2GiB', human_bytes(2 * (pow(1024, 3))));
392 $this->assertEquals('2GiB', human_bytes(strval(2 * (pow(1024, 3)))));
393 $this->assertEquals('374B', human_bytes(374));
394 $this->assertEquals('374B', human_bytes('374'));
395 $this->assertEquals('232kiB', human_bytes(237481));
396 $this->assertEquals('Unlimited', human_bytes('0'));
397 $this->assertEquals('Unlimited', human_bytes(0));
398 $this->assertEquals('Setting not set', human_bytes(''));
402 * Test get_max_upload_size with formatting
404 public function testGetMaxUploadSize()
406 $this->assertEquals('1MiB', get_max_upload_size(2097152, '1024k'));
407 $this->assertEquals('1MiB', get_max_upload_size('1m', '2m'));
408 $this->assertEquals('100B', get_max_upload_size(100, 100));
412 * Test get_max_upload_size without formatting
414 public function testGetMaxUploadSizeRaw()
416 $this->assertEquals('1048576', get_max_upload_size(2097152, '1024k', false));
417 $this->assertEquals('1048576', get_max_upload_size('1m', '2m', false));
418 $this->assertEquals('100', get_max_upload_size(100, 100, false));
422 * Test alphabetical_sort by value, not reversed, with php-intl.
424 public function testAlphabeticalSortByValue()
445 alphabetical_sort($arr);
446 $this->assertEquals($expected, $arr);
450 * Test alphabetical_sort by value, reversed, with php-intl.
452 public function testAlphabeticalSortByValueReversed()
473 alphabetical_sort($arr, true);
474 $this->assertEquals($expected, $arr);
478 * Test alphabetical_sort by keys, not reversed, with php-intl.
480 public function testAlphabeticalSortByKeys()
501 alphabetical_sort($arr, true, true);
502 $this->assertEquals($expected, $arr);
506 * Test alphabetical_sort by keys, reversed, with php-intl.
508 public function testAlphabeticalSortByKeysReversed()
529 alphabetical_sort($arr, true, true);
530 $this->assertEquals($expected, $arr);