[!!!][FEATURE] Add IP locking for IPv6
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Utility / StringUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\StringUtility;
18 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
19
20 /**
21 * Testcase for class \TYPO3\CMS\Core\Utility\StringUtility
22 */
23 class StringUtilityTest extends UnitTestCase
24 {
25
26 /**
27 * Data provider for endsWithReturnsTrueForMatchingFirstPart
28 *
29 * @return array
30 */
31 public function endsWithReturnsTrueForMatchingLastPartDataProvider()
32 {
33 return [
34 'match last part of string' => ['hello world', 'world'],
35 'match last char of string' => ['hellod world', 'd'],
36 'match whole string' => ['hello', 'hello'],
37 'integer is part of string with same number' => ['24', 24],
38 'string is part of integer with same number' => [24, '24'],
39 'integer is part of string ending with same number' => ['please gimme beer, 24', 24]
40 ];
41 }
42
43 /**
44 * @test
45 * @dataProvider endsWithReturnsTrueForMatchingLastPartDataProvider
46 */
47 public function endsWithReturnsTrueForMatchingLastPart($string, $part)
48 {
49 $this->assertTrue(StringUtility::endsWith($string, $part));
50 }
51
52 /**
53 * Data provider for check endsWithReturnsFalseForNotMatchingLastPart
54 *
55 * @return array
56 */
57 public function endsWithReturnsFalseForNotMatchingLastPartDataProvider()
58 {
59 return [
60 'no string match' => ['hello', 'bye'],
61 'no case sensitive string match' => ['hello world', 'World'],
62 'string is part but not last part' => ['hello world', 'worl'],
63 'integer is not part of empty string' => ['', 0],
64 'longer string is not part of shorter string' => ['a', 'aa'],
65 ];
66 }
67
68 /**
69 * @test
70 * @dataProvider endsWithReturnsFalseForNotMatchingLastPartDataProvider
71 */
72 public function endsWithReturnsFalseForNotMatchingLastPart($string, $part)
73 {
74 $this->assertFalse(StringUtility::endsWith($string, $part));
75 }
76
77 /**
78 * Data provider for endsWithReturnsThrowsExceptionWithInvalidArguments
79 *
80 * @return array
81 */
82 public function endsWithReturnsThrowsExceptionWithInvalidArgumentsDataProvider()
83 {
84 return [
85 'array is not part of string' => ['string', [], 1347135545],
86 'NULL is not part of string' => ['string', null, 1347135545],
87 'empty string is not part of string' => ['string', '', 1347135545],
88 'string is not part of array' => [[], 'string', 1347135544],
89 'NULL is not part of array' => [[], null, 1347135544],
90 'string is not part of NULL' => [null, 'string', 1347135544],
91 'array is not part of NULL' => [null, [], 1347135544],
92 'integer is not part of NULL' => [null, 0, 1347135544],
93 'empty string is not part of NULL' => [null, '', 1347135544],
94 'NULL is not part of empty string' => ['', null, 1347135545],
95 'FALSE is not part of empty string' => ['', false, 1347135545],
96 'empty string is not part of FALSE' => [false, '', 1347135545],
97 'empty string is not part of integer' => [0, '', 1347135545],
98 'string is not part of object' => [new \stdClass(), 'foo', 1347135544],
99 'object is not part of string' => ['foo', new \stdClass(), 1347135545],
100 ];
101 }
102
103 /**
104 * @test
105 * @dataProvider endsWithReturnsThrowsExceptionWithInvalidArgumentsDataProvider
106 */
107 public function endsWithReturnsThrowsExceptionWithInvalidArguments($string, $part, $expectedException)
108 {
109 $this->expectException(\InvalidArgumentException::class);
110 $this->expectExceptionCode($expectedException);
111
112 StringUtility::endsWith($string, $part);
113 }
114
115 /**
116 * Data provider for beginsWithReturnsTrueForMatchingFirstPart
117 *
118 * @return array
119 */
120 public function beginsWithReturnsTrueForMatchingFirstPartDataProvider()
121 {
122 return [
123 'match first part of string' => ['hello world', 'hello'],
124 'match first char of string' => ['hello world', 'h'],
125 'match whole string' => ['hello', 'hello'],
126 'integer is part of string with same number' => ['24', 24],
127 'string is part of integer with same number' => [24, '24'],
128 'integer is part of string starting with same number' => ['24, please gimme beer', 24],
129 ];
130 }
131
132 /**
133 * @test
134 * @dataProvider beginsWithReturnsTrueForMatchingFirstPartDataProvider
135 */
136 public function beginsWithReturnsTrueForMatchingFirstPart($string, $part)
137 {
138 $this->assertTrue(StringUtility::beginsWith($string, $part));
139 }
140
141 /**
142 * Data provider for check beginsWithReturnsFalseForNotMatchingFirstPart
143 *
144 * @return array
145 */
146 public function beginsWithReturnsFalseForNotMatchingFirstPartDataProvider()
147 {
148 return [
149 'no string match' => ['hello', 'bye'],
150 'no case sensitive string match' => ['hello world', 'Hello'],
151 'string in empty string' => ['', 'foo']
152 ];
153 }
154
155 /**
156 * @test
157 * @dataProvider beginsWithReturnsFalseForNotMatchingFirstPartDataProvider
158 */
159 public function beginsWithReturnsFalseForNotMatchingFirstPart($string, $part)
160 {
161 $this->assertFalse(StringUtility::beginsWith($string, $part));
162 }
163
164 /**
165 * Data provider for beginsWithReturnsThrowsExceptionWithInvalidArguments
166 *
167 * @return array
168 */
169 public function beginsWithReturnsInvalidArgumentDataProvider()
170 {
171 return [
172 'array is not part of string' => ['string', [], 1347135547],
173 'NULL is not part of string' => ['string', null, 1347135547],
174 'empty string is not part of string' => ['string', '', 1347135547],
175 'string is not part of array' => [[], 'string', 1347135546],
176 'NULL is not part of array' => [[], null, 1347135546],
177 'string is not part of NULL' => [null, 'string', 1347135546],
178 'array is not part of NULL' => [null, [], 1347135546],
179 'integer is not part of NULL' => [null, 0, 1347135546],
180 'empty string is not part of NULL' => [null, '', 1347135546],
181 'NULL is not part of empty string' => ['', null, 1347135547],
182 'FALSE is not part of empty string' => ['', false, 1347135547],
183 'empty string is not part of FALSE' => [false, '', 1347135547],
184 'empty string is not part of integer' => [0, '', 1347135547],
185 'string is not part of object' => [new \stdClass(), 'foo', 1347135546],
186 'object is not part of string' => ['foo', new \stdClass(), 1347135547],
187 ];
188 }
189
190 /**
191 * @test
192 * @dataProvider beginsWithReturnsInvalidArgumentDataProvider
193 *
194 * @param mixed $string
195 * @param mixed $part
196 * @param int $expectedException
197 */
198 public function beginsWithReturnsThrowsExceptionWithInvalidArguments($string, $part, $expectedException)
199 {
200 $this->expectException(\InvalidArgumentException::class);
201 $this->expectExceptionCode($expectedException);
202
203 StringUtility::beginsWith($string, $part);
204 }
205
206 /**
207 * @test
208 */
209 public function getUniqueIdReturnsIdWithPrefix()
210 {
211 $id = StringUtility::getUniqueId('NEW');
212 $this->assertEquals('NEW', substr($id, 0, 3));
213 }
214
215 /**
216 * @test
217 */
218 public function getUniqueIdReturnsIdWithoutDot()
219 {
220 $this->assertStringNotContainsString('.', StringUtility::getUniqueId());
221 }
222
223 /**
224 * @test
225 * @param string $selector
226 * @param string $expectedValue
227 * @dataProvider escapeCssSelectorDataProvider
228 */
229 public function escapeCssSelector(string $selector, string $expectedValue)
230 {
231 $this->assertEquals($expectedValue, StringUtility::escapeCssSelector($selector));
232 }
233
234 /**
235 * @return array
236 */
237 public function escapeCssSelectorDataProvider(): array
238 {
239 return [
240 ['data.field', 'data\\.field'],
241 ['#theId', '\\#theId'],
242 ['.theId:hover', '\\.theId\\:hover'],
243 ['.theId:hover', '\\.theId\\:hover'],
244 ['input[name=foo]', 'input\\[name\\=foo\\]'],
245 ];
246 }
247
248 /**
249 * @param string $input
250 * @param string $expectedValue
251 * @test
252 * @dataProvider removeByteOrderMarkDataProvider
253 */
254 public function removeByteOrderMark(string $input, string $expectedValue): void
255 {
256 // assertContains is necessary as one test contains non-string characters
257 $this->assertSame($expectedValue, StringUtility::removeByteOrderMark(hex2bin($input)));
258 }
259
260 /**
261 * @return array
262 */
263 public function removeByteOrderMarkDataProvider(): array
264 {
265 return [
266 'BOM gets removed' => [
267 'efbbbf424f4d2061742074686520626567696e6e696e6720676574732072656d6f766564',
268 'BOM at the beginning gets removed'
269 ],
270 'No BOM available' => [
271 '4e6f20424f4d20617661696c61626c65',
272 'No BOM available',
273 ],
274 ];
275 }
276
277 /**
278 * @param $haystack
279 * @param $needle
280 * @param $result
281 * @test
282 * @dataProvider searchStringWildcardDataProvider
283 */
284 public function searchStringWildcard($haystack, $needle, $result)
285 {
286 $this->assertSame($result, StringUtility::searchStringWildcard($haystack, $needle));
287 }
288
289 /**
290 * @return array
291 */
292 public function searchStringWildcardDataProvider(): array
293 {
294 return [
295 'Simple wildard single character with *' => [
296 'TYPO3',
297 'TY*O3',
298 true
299 ],
300 'Simple wildard multiple character with *' => [
301 'TYPO3',
302 'T*P*3',
303 true
304 ],
305 'Simple wildard multiple character for one placeholder with *' => [
306 'TYPO3',
307 'T*3',
308 true
309 ],
310 'Simple wildard single character with ?' => [
311 'TYPO3',
312 'TY?O3',
313 true
314 ],
315 'Simple wildard multiple character with ?' => [
316 'TYPO3',
317 'T?P?3',
318 true
319 ],
320 'Simple wildard multiple character for one placeholder with ?' => [
321 'TYPO3',
322 'T?3',
323 false
324 ],
325 'RegExp' => [
326 'TYPO3',
327 '/^TYPO(\d)$/',
328 true
329 ],
330 ];
331 }
332 }