ContentObjectRendererTest::stdWrap_numRows()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 13
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Frontend\Tests\Unit\ContentObject;
19
20
use PHPUnit\Framework\Exception;
21
use PHPUnit\Framework\MockObject\MockObject;
22
use Prophecy\Argument;
23
use Prophecy\PhpUnit\ProphecyTrait;
24
use Prophecy\Prophecy\ObjectProphecy;
25
use Psr\Container\ContainerInterface;
26
use Psr\Http\Message\ServerRequestInterface;
27
use Psr\Log\NullLogger;
28
use TYPO3\CMS\Core\Cache\CacheManager;
29
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface as CacheFrontendInterface;
30
use TYPO3\CMS\Core\Cache\Frontend\NullFrontend;
31
use TYPO3\CMS\Core\Configuration\SiteConfiguration;
32
use TYPO3\CMS\Core\Context\Context;
33
use TYPO3\CMS\Core\Context\UserAspect;
34
use TYPO3\CMS\Core\Context\WorkspaceAspect;
35
use TYPO3\CMS\Core\Core\ApplicationContext;
36
use TYPO3\CMS\Core\Core\Environment;
37
use TYPO3\CMS\Core\Crypto\Random;
38
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
39
use TYPO3\CMS\Core\ExpressionLanguage\ProviderConfigurationLoader;
40
use TYPO3\CMS\Core\LinkHandling\LinkService;
41
use TYPO3\CMS\Core\Log\Logger;
42
use TYPO3\CMS\Core\Package\PackageManager;
43
use TYPO3\CMS\Core\Resource\Exception\InvalidPathException;
44
use TYPO3\CMS\Core\Resource\File;
45
use TYPO3\CMS\Core\Resource\ResourceFactory;
46
use TYPO3\CMS\Core\Resource\ResourceStorage;
47
use TYPO3\CMS\Core\Service\DependencyOrderingService;
48
use TYPO3\CMS\Core\Site\Entity\Site;
49
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
50
use TYPO3\CMS\Core\TypoScript\TemplateService;
51
use TYPO3\CMS\Core\Utility\DebugUtility;
52
use TYPO3\CMS\Core\Utility\GeneralUtility;
53
use TYPO3\CMS\Core\Utility\StringUtility;
54
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
55
use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
56
use TYPO3\CMS\Frontend\ContentObject\CaseContentObject;
57
use TYPO3\CMS\Frontend\ContentObject\ContentContentObject;
58
use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
59
use TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayContentObject;
60
use TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayInternalContentObject;
61
use TYPO3\CMS\Frontend\ContentObject\ContentObjectGetImageResourceHookInterface;
62
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
63
use TYPO3\CMS\Frontend\ContentObject\ContentObjectStdWrapHookInterface;
64
use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
65
use TYPO3\CMS\Frontend\ContentObject\Exception\ProductionExceptionHandler;
66
use TYPO3\CMS\Frontend\ContentObject\FilesContentObject;
67
use TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject;
68
use TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject;
69
use TYPO3\CMS\Frontend\ContentObject\ImageContentObject;
70
use TYPO3\CMS\Frontend\ContentObject\ImageResourceContentObject;
71
use TYPO3\CMS\Frontend\ContentObject\LoadRegisterContentObject;
72
use TYPO3\CMS\Frontend\ContentObject\RecordsContentObject;
73
use TYPO3\CMS\Frontend\ContentObject\RestoreRegisterContentObject;
74
use TYPO3\CMS\Frontend\ContentObject\ScalableVectorGraphicsContentObject;
75
use TYPO3\CMS\Frontend\ContentObject\TextContentObject;
76
use TYPO3\CMS\Frontend\ContentObject\UserContentObject;
77
use TYPO3\CMS\Frontend\ContentObject\UserInternalContentObject;
78
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
79
use TYPO3\CMS\Frontend\Typolink\LinkResultInterface;
80
use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
81
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
82
83
/**
84
 * Test case
85
 */
86
class ContentObjectRendererTest extends UnitTestCase
87
{
88
    use ProphecyTrait;
89
    use ContentObjectRendererTestTrait;
90
91
    /**
92
     * @var bool Reset singletons created by subject
93
     */
94
    protected bool $resetSingletonInstances = true;
95
96
    /**
97
     * @var MockObject|AccessibleObjectInterface|ContentObjectRenderer
98
     */
99
    protected MockObject $subject;
100
101
    /**
102
     * @var MockObject|TypoScriptFrontendController|AccessibleObjectInterface
103
     */
104
    protected MockObject $frontendControllerMock;
105
106
    /**
107
     * @var MockObject|TemplateService
108
     */
109
    protected $templateServiceMock;
110
111
    /**
112
     * Default content object name -> class name map, shipped with TYPO3 CMS
113
     *
114
     * @var array
115
     */
116
    protected array $contentObjectMap = [
117
        'TEXT' => TextContentObject::class,
118
        'CASE' => CaseContentObject::class,
119
        'COBJ_ARRAY' => ContentObjectArrayContentObject::class,
120
        'COA' => ContentObjectArrayContentObject::class,
121
        'COA_INT' => ContentObjectArrayInternalContentObject::class,
122
        'USER' => UserContentObject::class,
123
        'USER_INT' => UserInternalContentObject::class,
124
        'FILES' => FilesContentObject::class,
125
        'IMAGE' => ImageContentObject::class,
126
        'IMG_RESOURCE' => ImageResourceContentObject::class,
127
        'CONTENT' => ContentContentObject::class,
128
        'RECORDS' => RecordsContentObject::class,
129
        'HMENU' => HierarchicalMenuContentObject::class,
130
        'CASEFUNC' => CaseContentObject::class,
131
        'LOAD_REGISTER' => LoadRegisterContentObject::class,
132
        'RESTORE_REGISTER' => RestoreRegisterContentObject::class,
133
        'FLUIDTEMPLATE' => FluidTemplateContentObject::class,
134
        'SVG' => ScalableVectorGraphicsContentObject::class,
135
    ];
136
137
    /**
138
     * @var \Prophecy\Prophecy\ObjectProphecy|CacheManager
139
     */
140
    protected ObjectProphecy $cacheManager;
141
142
    protected bool $backupEnvironment = true;
143
144
    /**
145
     * Set up
146
     */
147
    protected function setUp(): void
148
    {
149
        parent::setUp();
150
151
        $site = $this->createSiteWithLanguage([
152
            'base' => '/',
153
            'languageId' => 2,
154
            'locale' => 'en_UK',
155
            'typo3Language' => 'default',
156
        ]);
157
158
        $GLOBALS['SIM_ACCESS_TIME'] = 1534278180;
159
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
160
            ->disableOriginalConstructor()
161
            ->getMock();
162
        $this->templateServiceMock =
163
            $this->getMockBuilder(TemplateService::class)
164
                ->setConstructorArgs([null, $packageManagerMock])
165
                ->addMethods(['linkData'])
166
                ->getMock();
167
        $pageRepositoryMock =
168
            $this->getAccessibleMock(PageRepository::class, ['getRawRecord', 'getMountPointInfo']);
169
        $this->frontendControllerMock =
170
            $this->getAccessibleMock(
171
                TypoScriptFrontendController::class,
172
                ['sL'],
173
                [],
174
                '',
175
                false
176
            );
177
        $this->frontendControllerMock->_set('context', GeneralUtility::makeInstance(Context::class));
178
        $this->frontendControllerMock->tmpl = $this->templateServiceMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
179
        $this->frontendControllerMock->config = [];
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
180
        $this->frontendControllerMock->page = [];
0 ignored issues
show
Bug introduced by
Accessing page on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
181
        $this->frontendControllerMock->sys_page = $pageRepositoryMock;
0 ignored issues
show
Bug introduced by
Accessing sys_page on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
182
        $this->frontendControllerMock->_set('language', $site->getLanguageById(2));
183
        $GLOBALS['TSFE'] = $this->frontendControllerMock;
184
185
        $this->cacheManager = $this->prophesize(CacheManager::class);
186
        GeneralUtility::setSingletonInstance(CacheManager::class, $this->cacheManager->reveal());
187
188
        $this->subject = $this->getAccessibleMock(
189
            ContentObjectRenderer::class,
190
            ['getResourceFactory', 'getEnvironmentVariable'],
191
            [$this->frontendControllerMock]
192
        );
193
194
        $logger = $this->prophesize(Logger::class);
195
        $this->subject->setLogger($logger->reveal());
196
        $request = $this->prophesize(ServerRequestInterface::class);
197
        $this->subject->setRequest($request->reveal());
198
        $this->subject->setContentObjectClassMap($this->contentObjectMap);
199
        $this->subject->start([], 'tt_content');
200
    }
201
202
    //////////////////////
203
    // Utility functions
204
    //////////////////////
205
206
    /**
207
     * @return TypoScriptFrontendController
208
     */
209
    protected function getFrontendController(): TypoScriptFrontendController
210
    {
211
        return $GLOBALS['TSFE'];
212
    }
213
214
    /**
215
     * Converts the subject and the expected result into utf-8.
216
     *
217
     * @param string $subject the subject, will be modified
218
     * @param string $expected the expected result, will be modified
219
     */
220
    protected function handleCharset(string &$subject, string &$expected): void
221
    {
222
        $subject = mb_convert_encoding($subject, 'utf-8', 'iso-8859-1');
223
        $expected = mb_convert_encoding($expected, 'utf-8', 'iso-8859-1');
224
    }
225
226
    /////////////////////////////////////////////
227
    // Tests concerning the getImgResource hook
228
    /////////////////////////////////////////////
229
    /**
230
     * @test
231
     */
232
    public function getImgResourceCallsGetImgResourcePostProcessHook(): void
233
    {
234
        $cacheManagerProphecy = $this->prophesize(CacheManager::class);
235
        $cacheProphecy = $this->prophesize(CacheFrontendInterface::class);
236
        $cacheManagerProphecy->getCache('imagesizes')->willReturn($cacheProphecy->reveal());
237
        $cacheProphecy->get(Argument::cetera())->willReturn(false);
238
        $cacheProphecy->set(Argument::cetera(), null)->willReturn(false);
239
        GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
240
241
        $resourceFactory = $this->createMock(ResourceFactory::class);
242
        $this->subject->method('getResourceFactory')->willReturn($resourceFactory);
243
244
        $className = StringUtility::getUniqueId('tx_coretest');
245
        $getImgResourceHookMock = $this->getMockBuilder(ContentObjectGetImageResourceHookInterface::class)
246
            ->onlyMethods(['getImgResourcePostProcess'])
247
            ->setMockClassName($className)
248
            ->getMock();
249
        $getImgResourceHookMock
250
            ->expects(self::once())
251
            ->method('getImgResourcePostProcess')
252
            ->willReturnCallback([$this, 'isGetImgResourceHookCalledCallback']);
253
        $getImgResourceHookObjects = [$getImgResourceHookMock];
254
        $this->subject->_set('getImgResourceHookObjects', $getImgResourceHookObjects);
255
        $this->subject->getImgResource('typo3/sysext/core/Tests/Unit/Utility/Fixtures/clear.gif', []);
256
    }
257
258
    /**
259
     * Handles the arguments that have been sent to the getImgResource hook.
260
     *
261
     * @param string $file
262
     * @param array $fileArray
263
     * @param $imageResource
264
     * @param ContentObjectRenderer $parent
265
     * @return array
266
     * @see getImgResourceHookGetsCalled
267
     */
268
    public function isGetImgResourceHookCalledCallback(
269
        string $file,
270
        array $fileArray,
271
        $imageResource,
272
        ContentObjectRenderer $parent
273
    ): array {
274
        self::assertEquals('typo3/sysext/core/Tests/Unit/Utility/Fixtures/clear.gif', $file);
275
        self::assertEquals('typo3/sysext/core/Tests/Unit/Utility/Fixtures/clear.gif', $imageResource['origFile']);
276
        self::assertIsArray($fileArray);
277
        self::assertInstanceOf(ContentObjectRenderer::class, $parent);
278
        return $imageResource;
279
    }
280
281
    //////////////////////////////////////
282
    // Tests related to getContentObject
283
    //////////////////////////////////////
284
285
    /**
286
     * Show registration of a class for a TypoScript object name and getting
287
     * the registered content object is working.
288
     *
289
     * Prove is done by successfully creating an object based on the mapping.
290
     * Note two conditions in contrast to other tests, where the creation
291
     * fails.
292
     *
293
     * 1. The type must be of AbstractContentObject.
294
     * 2. Registration can only be done by public methods.
295
     *
296
     * @test
297
     */
298
    public function canRegisterAContentObjectClassForATypoScriptName(): void
299
    {
300
        $className = TextContentObject::class;
301
        $contentObjectName = 'TEST_TEXT';
302
        $this->subject->registerContentObjectClass(
303
            $className,
304
            $contentObjectName
305
        );
306
        $object = $this->subject->getContentObject($contentObjectName);
307
        self::assertInstanceOf($className, $object);
308
    }
309
310
    /**
311
     * Show that setting of the class map and getting a registered content
312
     * object is working.
313
     *
314
     * @see ContentObjectRendererTest::canRegisterAContentObjectClassForATypoScriptName
315
     * @test
316
     */
317
    public function canSetTheContentObjectClassMapAndGetARegisteredContentObject(): void
318
    {
319
        $className = TextContentObject::class;
320
        $contentObjectName = 'TEST_TEXT';
321
        $classMap = [$contentObjectName => $className];
322
        $this->subject->setContentObjectClassMap($classMap);
323
        $object = $this->subject->getContentObject($contentObjectName);
324
        self::assertInstanceOf($className, $object);
325
    }
326
327
    /**
328
     * Show that the map is not set as an externally accessible reference.
329
     *
330
     * Prove is done by missing success when trying to use it this way.
331
     *
332
     * @see ContentObjectRendererTest::canRegisterAContentObjectClassForATypoScriptName
333
     * @test
334
     */
335
    public function canNotAccessInternalContentObjectMapByReference(): void
336
    {
337
        $className = TextContentObject::class;
338
        $contentObjectName = 'TEST_TEXT';
339
        $classMap = [];
340
        $this->subject->setContentObjectClassMap($classMap);
341
        $classMap[$contentObjectName] = $className;
342
        $object = $this->subject->getContentObject($contentObjectName);
343
        self::assertNull($object);
344
    }
345
346
    /**
347
     * @see ContentObjectRendererTest::canRegisterAContentObjectClassForATypoScriptName
348
     * @test
349
     */
350
    public function willReturnNullForUnregisteredObject(): void
351
    {
352
        $object = $this->subject->getContentObject('FOO');
353
        self::assertNull($object);
354
    }
355
356
    /**
357
     * @see ContentObjectRendererTest::canRegisterAContentObjectClassForATypoScriptName
358
     * @test
359
     */
360
    public function willThrowAnExceptionForARegisteredNonContentObject(): void
361
    {
362
        $this->expectException(ContentRenderingException::class);
363
        $this->subject->registerContentObjectClass(
364
            \stdClass::class,
365
            'STDCLASS'
366
        );
367
        $this->subject->getContentObject('STDCLASS');
368
    }
369
370
    /**
371
     * @return string[][] [[$name, $fullClassName],]
372
     */
373
    public function registersAllDefaultContentObjectsDataProvider(): array
374
    {
375
        $dataProvider = [];
376
        foreach ($this->contentObjectMap as $name => $className) {
377
            $dataProvider[] = [$name, $className];
378
        }
379
        return $dataProvider;
380
    }
381
382
    /**
383
     * Prove that all content objects are registered and a class is available
384
     * for each of them.
385
     *
386
     * @test
387
     * @dataProvider registersAllDefaultContentObjectsDataProvider
388
     * @param string $objectName TypoScript name of content object
389
     * @param string $className Expected class name
390
     */
391
    public function registersAllDefaultContentObjects(
392
        string $objectName,
393
        string $className
394
    ): void {
395
        self::assertTrue(
396
            is_subclass_of($className, AbstractContentObject::class)
397
        );
398
        if ($objectName === 'FLUIDTEMPLATE') {
399
            GeneralUtility::addInstance(ContentDataProcessor::class, new ContentDataProcessor($this->prophesize(ContainerInterface::class)->reveal()));
400
        }
401
        $object = $this->subject->getContentObject($objectName);
402
        self::assertInstanceOf($className, $object);
403
    }
404
405
    /////////////////////////////////////////
406
    // Tests concerning getQueryArguments()
407
    /////////////////////////////////////////
408
    /**
409
     * @test
410
     */
411
    public function getQueryArgumentsExcludesParameters(): void
412
    {
413
        $_GET = [
414
            'key1' => 'value1',
415
            'key2' => 'value2',
416
            'key3' => [
417
                'key31' => 'value31',
418
                'key32' => [
419
                    'key321' => 'value321',
420
                    'key322' => 'value322',
421
                ],
422
            ],
423
        ];
424
        $getQueryArgumentsConfiguration = [];
425
        $getQueryArgumentsConfiguration['exclude'] = [];
426
        $getQueryArgumentsConfiguration['exclude'][] = 'key1';
427
        $getQueryArgumentsConfiguration['exclude'][] = 'key3[key31]';
428
        $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key321]';
429
        $getQueryArgumentsConfiguration['exclude'] = implode(',', $getQueryArgumentsConfiguration['exclude']);
430
        $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key2=value2&key3[key32][key322]=value322');
431
        $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration);
432
        self::assertEquals($expectedResult, $actualResult);
433
    }
434
435
    /**
436
     * Encodes square brackets in URL.
437
     *
438
     * @param string $string
439
     * @return string
440
     */
441
    private function rawUrlEncodeSquareBracketsInUrl(string $string): string
442
    {
443
        return str_replace(['[', ']'], ['%5B', '%5D'], $string);
444
    }
445
446
    //////////////////////////
447
    // Tests concerning crop
448
    //////////////////////////
449
    /**
450
     * @test
451
     */
452
    public function cropIsMultibyteSafe(): void
453
    {
454
        self::assertEquals('бла', $this->subject->crop('бла', '3|...'));
455
    }
456
457
    //////////////////////////////
458
459
    //////////////////////////////
460
    // Tests concerning cropHTML
461
    //////////////////////////////
462
463
    /**
464
     * Data provider for cropHTML.
465
     *
466
     * Provides combinations of text type and configuration.
467
     *
468
     * @return array [$expect, $conf, $content]
469
     */
470
    public function cropHTMLDataProvider(): array
471
    {
472
        $plainText = 'Kasper Sk' . chr(229) . 'rh' . chr(248)
473
            . 'j implemented the original version of the crop function.';
474
        $textWithMarkup = '<strong><a href="mailto:[email protected]">Kasper Sk'
475
            . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong> the '
476
            . 'original version of the crop function.';
477
        $textWithEntities = 'Kasper Sk&aring;rh&oslash;j implemented the; '
478
            . 'original version of the crop function.';
479
        $textWithLinebreaks = "Lorem ipsum dolor sit amet,\n"
480
            . "consetetur sadipscing elitr,\n"
481
            . 'sed diam nonumy eirmod tempor invidunt ut labore e'
482
            . 't dolore magna aliquyam';
483
        $textWith2000Chars = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ips &amp;. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vesti&amp;';
484
        $textWith1000AmpHtmlEntity = str_repeat('&amp;', 1000);
485
        $textWith2000AmpHtmlEntity = str_repeat('&amp;', 2000);
486
487
        return [
488
            'plain text; 11|...' => [
489
                'Kasper Sk' . chr(229) . 'r...',
490
                $plainText,
491
                '11|...',
492
            ],
493
            'plain text; -58|...' => [
494
                '...h' . chr(248) . 'j implemented the original version of '
495
                . 'the crop function.',
496
                $plainText,
497
                '-58|...',
498
            ],
499
            'plain text; 4|...|1' => [
500
                'Kasp...',
501
                $plainText,
502
                '4|...|1',
503
            ],
504
            'plain text; 20|...|1' => [
505
                'Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j...',
506
                $plainText,
507
                '20|...|1',
508
            ],
509
            'plain text; -5|...|1' => [
510
                '...tion.',
511
                $plainText,
512
                '-5|...|1',
513
            ],
514
            'plain text; -49|...|1' => [
515
                '...the original version of the crop function.',
516
                $plainText,
517
                '-49|...|1',
518
            ],
519
            'text with markup; 11|...' => [
520
                '<strong><a href="mailto:[email protected]">Kasper Sk'
521
                . chr(229) . 'r...</a></strong>',
522
                $textWithMarkup,
523
                '11|...',
524
            ],
525
            'text with markup; 13|...' => [
526
                '<strong><a href="mailto:[email protected]">Kasper Sk'
527
                . chr(229) . 'rh' . chr(248) . '...</a></strong>',
528
                $textWithMarkup,
529
                '13|...',
530
            ],
531
            'text with markup; 14|...' => [
532
                '<strong><a href="mailto:[email protected]">Kasper Sk'
533
                . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
534
                $textWithMarkup,
535
                '14|...',
536
            ],
537
            'text with markup; 15|...' => [
538
                '<strong><a href="mailto:[email protected]">Kasper Sk'
539
                . chr(229) . 'rh' . chr(248) . 'j</a> ...</strong>',
540
                $textWithMarkup,
541
                '15|...',
542
            ],
543
            'text with markup; 29|...' => [
544
                '<strong><a href="mailto:[email protected]">Kasper Sk'
545
                . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong> '
546
                . 'th...',
547
                $textWithMarkup,
548
                '29|...',
549
            ],
550
            'text with markup; -58|...' => [
551
                '<strong><a href="mailto:[email protected]">...h' . chr(248)
552
                . 'j</a> implemented</strong> the original version of the crop '
553
                . 'function.',
554
                $textWithMarkup,
555
                '-58|...',
556
            ],
557
            'text with markup 4|...|1' => [
558
                '<strong><a href="mailto:[email protected]">Kasp...</a>'
559
                . '</strong>',
560
                $textWithMarkup,
561
                '4|...|1',
562
            ],
563
            'text with markup; 11|...|1' => [
564
                '<strong><a href="mailto:[email protected]">Kasper...</a>'
565
                . '</strong>',
566
                $textWithMarkup,
567
                '11|...|1',
568
            ],
569
            'text with markup; 13|...|1' => [
570
                '<strong><a href="mailto:[email protected]">Kasper...</a>'
571
                . '</strong>',
572
                $textWithMarkup,
573
                '13|...|1',
574
            ],
575
            'text with markup; 14|...|1' => [
576
                '<strong><a href="mailto:[email protected]">Kasper Sk'
577
                . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
578
                $textWithMarkup,
579
                '14|...|1',
580
            ],
581
            'text with markup; 15|...|1' => [
582
                '<strong><a href="mailto:[email protected]">Kasper Sk'
583
                . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
584
                $textWithMarkup,
585
                '15|...|1',
586
            ],
587
            'text with markup; 29|...|1' => [
588
                '<strong><a href="mailto:[email protected]">Kasper Sk'
589
                . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong>...',
590
                $textWithMarkup,
591
                '29|...|1',
592
            ],
593
            'text with markup; -66|...|1' => [
594
                '<strong><a href="mailto:[email protected]">...Sk' . chr(229)
595
                . 'rh' . chr(248) . 'j</a> implemented</strong> the original v'
596
                . 'ersion of the crop function.',
597
                $textWithMarkup,
598
                '-66|...|1',
599
            ],
600
            'text with entities 9|...' => [
601
                'Kasper Sk...',
602
                $textWithEntities,
603
                '9|...',
604
            ],
605
            'text with entities 10|...' => [
606
                'Kasper Sk&aring;...',
607
                $textWithEntities,
608
                '10|...',
609
            ],
610
            'text with entities 11|...' => [
611
                'Kasper Sk&aring;r...',
612
                $textWithEntities,
613
                '11|...',
614
            ],
615
            'text with entities 13|...' => [
616
                'Kasper Sk&aring;rh&oslash;...',
617
                $textWithEntities,
618
                '13|...',
619
            ],
620
            'text with entities 14|...' => [
621
                'Kasper Sk&aring;rh&oslash;j...',
622
                $textWithEntities,
623
                '14|...',
624
            ],
625
            'text with entities 15|...' => [
626
                'Kasper Sk&aring;rh&oslash;j ...',
627
                $textWithEntities,
628
                '15|...',
629
            ],
630
            'text with entities 16|...' => [
631
                'Kasper Sk&aring;rh&oslash;j i...',
632
                $textWithEntities,
633
                '16|...',
634
            ],
635
            'text with entities -57|...' => [
636
                '...j implemented the; original version of the crop function.',
637
                $textWithEntities,
638
                '-57|...',
639
            ],
640
            'text with entities -58|...' => [
641
                '...&oslash;j implemented the; original version of the crop '
642
                . 'function.',
643
                $textWithEntities,
644
                '-58|...',
645
            ],
646
            'text with entities -59|...' => [
647
                '...h&oslash;j implemented the; original version of the crop '
648
                . 'function.',
649
                $textWithEntities,
650
                '-59|...',
651
            ],
652
            'text with entities 4|...|1' => [
653
                'Kasp...',
654
                $textWithEntities,
655
                '4|...|1',
656
            ],
657
            'text with entities 9|...|1' => [
658
                'Kasper...',
659
                $textWithEntities,
660
                '9|...|1',
661
            ],
662
            'text with entities 10|...|1' => [
663
                'Kasper...',
664
                $textWithEntities,
665
                '10|...|1',
666
            ],
667
            'text with entities 11|...|1' => [
668
                'Kasper...',
669
                $textWithEntities,
670
                '11|...|1',
671
            ],
672
            'text with entities 13|...|1' => [
673
                'Kasper...',
674
                $textWithEntities,
675
                '13|...|1',
676
            ],
677
            'text with entities 14|...|1' => [
678
                'Kasper Sk&aring;rh&oslash;j...',
679
                $textWithEntities,
680
                '14|...|1',
681
            ],
682
            'text with entities 15|...|1' => [
683
                'Kasper Sk&aring;rh&oslash;j...',
684
                $textWithEntities,
685
                '15|...|1',
686
            ],
687
            'text with entities 16|...|1' => [
688
                'Kasper Sk&aring;rh&oslash;j...',
689
                $textWithEntities,
690
                '16|...|1',
691
            ],
692
            'text with entities -57|...|1' => [
693
                '...implemented the; original version of the crop function.',
694
                $textWithEntities,
695
                '-57|...|1',
696
            ],
697
            'text with entities -58|...|1' => [
698
                '...implemented the; original version of the crop function.',
699
                $textWithEntities,
700
                '-58|...|1',
701
            ],
702
            'text with entities -59|...|1' => [
703
                '...implemented the; original version of the crop function.',
704
                $textWithEntities,
705
                '-59|...|1',
706
            ],
707
            'text with dash in html-element 28|...|1' => [
708
                'Some text with a link to <link [email protected] - '
709
                . 'mail "Open email window">my...</link>',
710
                'Some text with a link to <link [email protected] - m'
711
                . 'ail "Open email window">my [email protected]<'
712
                . '/link> and text after it',
713
                '28|...|1',
714
            ],
715
            'html elements with dashes in attributes' => [
716
                '<em data-foo="x">foobar</em>foo',
717
                '<em data-foo="x">foobar</em>foobaz',
718
                '9',
719
            ],
720
            'html elements with iframe embedded 24|...|1' => [
721
                'Text with iframe <iframe src="//what.ever/"></iframe> and...',
722
                'Text with iframe <iframe src="//what.ever/">'
723
                . '</iframe> and text after it',
724
                '24|...|1',
725
            ],
726
            'html elements with script tag embedded 24|...|1' => [
727
                'Text with script <script>alert(\'foo\');</script> and...',
728
                'Text with script <script>alert(\'foo\');</script> '
729
                . 'and text after it',
730
                '24|...|1',
731
            ],
732
            'text with linebreaks' => [
733
                "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\ns"
734
                . 'ed diam nonumy eirmod tempor invidunt ut labore e'
735
                . 't dolore magna',
736
                $textWithLinebreaks,
737
                '121',
738
            ],
739
            'long text under the crop limit' => [
740
                'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit' . ' ...',
741
                $textWith2000Chars,
742
                '962|...',
743
            ],
744
            'long text above the crop limit' => [
745
                'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ips &amp;. N' . '...',
746
                $textWith2000Chars,
747
                '1000|...',
748
            ],
749
            'long text above the crop limit #2' => [
750
                'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ips &amp;. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vesti&amp;' . '...',
751
                $textWith2000Chars . $textWith2000Chars,
752
                '2000|...',
753
            ],
754
            // ensure that large number of html entities do not break the the regexp splittin
755
            'long text with large number of html entities' => [
756
                $textWith1000AmpHtmlEntity . '...',
757
                $textWith2000AmpHtmlEntity,
758
                '1000|...',
759
            ],
760
        ];
761
    }
762
763
    /**
764
     * Check if cropHTML works properly.
765
     *
766
     * @test
767
     * @dataProvider cropHTMLDataProvider
768
     * @param string $expect The expected cropped output.
769
     * @param string $content The given input.
770
     * @param string $conf The given configuration.
771
     */
772
    public function cropHTML(string $expect, string $content, string $conf): void
773
    {
774
        $this->handleCharset($content, $expect);
775
        self::assertSame(
776
            $expect,
777
            $this->subject->cropHTML($content, $conf)
778
        );
779
    }
780
781
    /**
782
     * Data provider for round
783
     *
784
     * @return array [$expect, $content, $conf]
785
     */
786
    public function roundDataProvider(): array
787
    {
788
        return [
789
            // floats
790
            'down' => [1.0, 1.11, []],
791
            'up' => [2.0, 1.51, []],
792
            'rounds up from x.50' => [2.0, 1.50, []],
793
            'down with decimals' => [0.12, 0.1231, ['decimals' => 2]],
794
            'up with decimals' => [0.13, 0.1251, ['decimals' => 2]],
795
            'ceil' => [1.0, 0.11, ['roundType' => 'ceil']],
796
            'ceil does not accept decimals' => [
797
                1.0,
798
                0.111,
799
                [
800
                    'roundType' => 'ceil',
801
                    'decimals' => 2,
802
                ],
803
            ],
804
            'floor' => [2.0, 2.99, ['roundType' => 'floor']],
805
            'floor does not accept decimals' => [
806
                2.0,
807
                2.999,
808
                [
809
                    'roundType' => 'floor',
810
                    'decimals' => 2,
811
                ],
812
            ],
813
            'round, down' => [1.0, 1.11, ['roundType' => 'round']],
814
            'round, up' => [2.0, 1.55, ['roundType' => 'round']],
815
            'round does accept decimals' => [
816
                5.56,
817
                5.5555,
818
                [
819
                    'roundType' => 'round',
820
                    'decimals' => 2,
821
                ],
822
            ],
823
            // strings
824
            'emtpy string' => [0.0, '', []],
825
            'word string' => [0.0, 'word', []],
826
            'float string' => [1.0, '1.123456789', []],
827
            // other types
828
            'null' => [0.0, null, []],
829
            'false' => [0.0, false, []],
830
            'true' => [1.0, true, []],
831
        ];
832
    }
833
834
    /**
835
     * Check if round works properly
836
     *
837
     * Show:
838
     *
839
     *  - Different types of input are casted to float.
840
     *  - Configuration ceil rounds like ceil().
841
     *  - Configuration floor rounds like floor().
842
     *  - Otherwise rounds like round() and decimals can be applied.
843
     *  - Always returns float.
844
     *
845
     * @param float $expect The expected output.
846
     * @param mixed $content The given content.
847
     * @param array $conf The given configuration of 'round.'.
848
     * @dataProvider roundDataProvider
849
     * @test
850
     */
851
    public function round(float $expect, $content, array $conf): void
852
    {
853
        self::assertSame(
854
            $expect,
855
            $this->subject->_call('round', $content, $conf)
856
        );
857
    }
858
859
    /**
860
     * @test
861
     */
862
    public function recursiveStdWrapProperlyRendersBasicString(): void
863
    {
864
        $stdWrapConfiguration = [
865
            'noTrimWrap' => '|| 123|',
866
            'stdWrap.' => [
867
                'wrap' => '<b>|</b>',
868
            ],
869
        ];
870
        self::assertSame(
871
            '<b>Test</b> 123',
872
            $this->subject->stdWrap('Test', $stdWrapConfiguration)
873
        );
874
    }
875
876
    /**
877
     * @test
878
     */
879
    public function recursiveStdWrapIsOnlyCalledOnce(): void
880
    {
881
        $stdWrapConfiguration = [
882
            'append' => 'TEXT',
883
            'append.' => [
884
                'data' => 'register:Counter',
885
            ],
886
            'stdWrap.' => [
887
                'append' => 'LOAD_REGISTER',
888
                'append.' => [
889
                    'Counter.' => [
890
                        'prioriCalc' => 'intval',
891
                        'cObject' => 'TEXT',
892
                        'cObject.' => [
893
                            'data' => 'register:Counter',
894
                            'wrap' => '|+1',
895
                        ],
896
                    ],
897
                ],
898
            ],
899
        ];
900
        self::assertSame(
901
            'Counter:1',
902
            $this->subject->stdWrap('Counter:', $stdWrapConfiguration)
903
        );
904
    }
905
906
    /**
907
     * Data provider for numberFormat.
908
     *
909
     * @return array [$expect, $content, $conf]
910
     */
911
    public function numberFormatDataProvider(): array
912
    {
913
        return [
914
            'testing decimals' => [
915
                '0.80',
916
                0.8,
917
                ['decimals' => 2],
918
            ],
919
            'testing decimals with input as string' => [
920
                '0.80',
921
                '0.8',
922
                ['decimals' => 2],
923
            ],
924
            'testing dec_point' => [
925
                '0,8',
926
                0.8,
927
                ['decimals' => 1, 'dec_point' => ','],
928
            ],
929
            'testing thousands_sep' => [
930
                '1.000',
931
                999.99,
932
                [
933
                    'decimals' => 0,
934
                    'thousands_sep.' => ['char' => 46],
935
                ],
936
            ],
937
            'testing mixture' => [
938
                '1.281.731,5',
939
                1281731.45,
940
                [
941
                    'decimals' => 1,
942
                    'dec_point.' => ['char' => 44],
943
                    'thousands_sep.' => ['char' => 46],
944
                ],
945
            ],
946
        ];
947
    }
948
949
    /**
950
     * Check if numberFormat works properly.
951
     *
952
     * @dataProvider numberFormatDataProvider
953
     * @test
954
     * @param string $expects
955
     * @param mixed $content
956
     * @param array $conf
957
     */
958
    public function numberFormat(string $expects, $content, array $conf): void
959
    {
960
        self::assertSame(
961
            $expects,
962
            $this->subject->numberFormat($content, $conf)
963
        );
964
    }
965
966
    /**
967
     * Data provider replacement
968
     *
969
     * @return array [$expect, $content, $conf]
970
     */
971
    public function replacementDataProvider(): array
972
    {
973
        return [
974
            'multiple replacements, including regex' => [
975
                'There is an animal, an animal and an animal around the block! Yeah!',
976
                'There_is_a_cat,_a_dog_and_a_tiger_in_da_hood!_Yeah!',
977
                [
978
                    '20.' => [
979
                        'search' => '_',
980
                        'replace.' => ['char' => '32'],
981
                    ],
982
                    '120.' => [
983
                        'search' => 'in da hood',
984
                        'replace' => 'around the block',
985
                    ],
986
                    '130.' => [
987
                        'search' => '#a (Cat|Dog|Tiger)#i',
988
                        'replace' => 'an animal',
989
                        'useRegExp' => '1',
990
                    ],
991
                ],
992
            ],
993
            'replacement with optionSplit, normal pattern' => [
994
                'There1is2a3cat,3a3dog3and3a3tiger3in3da3hood!3Yeah!',
995
                'There_is_a_cat,_a_dog_and_a_tiger_in_da_hood!_Yeah!',
996
                [
997
                    '10.' => [
998
                        'search' => '_',
999
                        'replace' => '1 || 2 || 3',
1000
                        'useOptionSplitReplace' => '1',
1001
                        'useRegExp' => '0',
1002
                    ],
1003
                ],
1004
            ],
1005
            'replacement with optionSplit, using regex' => [
1006
                'There is a tiny cat, a midsized dog and a big tiger in da hood! Yeah!',
1007
                'There is a cat, a dog and a tiger in da hood! Yeah!',
1008
                [
1009
                    '10.' => [
1010
                        'search' => '#(a) (Cat|Dog|Tiger)#i',
1011
                        'replace' => '${1} tiny ${2} || ${1} midsized ${2} || ${1} big ${2}',
1012
                        'useOptionSplitReplace' => '1',
1013
                        'useRegExp' => '1',
1014
                    ],
1015
                ],
1016
            ],
1017
        ];
1018
    }
1019
1020
    /**
1021
     * Check if stdWrap.replacement and all of its properties work properly
1022
     *
1023
     * @test
1024
     * @dataProvider replacementDataProvider
1025
     * @param string $content The given input.
1026
     * @param string $expects The expected result.
1027
     * @param array $conf The given configuration.
1028
     */
1029
    public function replacement(string $expects, string $content, array $conf): void
1030
    {
1031
        self::assertSame(
1032
            $expects,
1033
            $this->subject->_call('replacement', $content, $conf)
1034
        );
1035
    }
1036
1037
    /**
1038
     * Data provider for calcAge.
1039
     *
1040
     * @return array [$expect, $timestamp, $labels]
1041
     */
1042
    public function calcAgeDataProvider(): array
1043
    {
1044
        return [
1045
            'minutes' => [
1046
                '2 min',
1047
                120,
1048
                ' min| hrs| days| yrs',
1049
            ],
1050
            'hours' => [
1051
                '2 hrs',
1052
                7200,
1053
                ' min| hrs| days| yrs',
1054
            ],
1055
            'days' => [
1056
                '7 days',
1057
                604800,
1058
                ' min| hrs| days| yrs',
1059
            ],
1060
            'day with provided singular labels' => [
1061
                '1 day',
1062
                86400,
1063
                ' min| hrs| days| yrs| min| hour| day| year',
1064
            ],
1065
            'years' => [
1066
                '45 yrs',
1067
                1417997800,
1068
                ' min| hrs| days| yrs',
1069
            ],
1070
            'different labels' => [
1071
                '2 Minutes',
1072
                120,
1073
                ' Minutes| Hrs| Days| Yrs',
1074
            ],
1075
            'negative values' => [
1076
                '-7 days',
1077
                -604800,
1078
                ' min| hrs| days| yrs',
1079
            ],
1080
            'default label values for wrong label input' => [
1081
                '2 min',
1082
                121,
1083
                '10',
1084
            ],
1085
            'default singular label values for wrong label input' => [
1086
                '1 year',
1087
                31536000,
1088
                '10',
1089
            ],
1090
        ];
1091
    }
1092
1093
    /**
1094
     * Check if calcAge works properly.
1095
     *
1096
     * @test
1097
     * @dataProvider calcAgeDataProvider
1098
     * @param string $expect
1099
     * @param int $timestamp
1100
     * @param string $labels
1101
     */
1102
    public function calcAge(string $expect, int $timestamp, string $labels): void
1103
    {
1104
        self::assertSame(
1105
            $expect,
1106
            $this->subject->calcAge($timestamp, $labels)
1107
        );
1108
    }
1109
1110
    /**
1111
     * @return array
1112
     */
1113
    public function stdWrapReturnsExpectationDataProvider(): array
1114
    {
1115
        return [
1116
            'Prevent silent bool conversion' => [
1117
                '1+1',
1118
                [
1119
                    'prioriCalc.' => [
1120
                        'wrap' => '|',
1121
                    ],
1122
                ],
1123
                '1+1',
1124
            ],
1125
        ];
1126
    }
1127
1128
    /**
1129
     * @param string $content
1130
     * @param array $configuration
1131
     * @param string $expectation
1132
     * @dataProvider stdWrapReturnsExpectationDataProvider
1133
     * @test
1134
     */
1135
    public function stdWrapReturnsExpectation(string $content, array $configuration, string $expectation): void
1136
    {
1137
        self::assertSame($expectation, $this->subject->stdWrap($content, $configuration));
1138
    }
1139
1140
    /**
1141
     * Data provider for substring
1142
     *
1143
     * @return array [$expect, $content, $conf]
1144
     */
1145
    public function substringDataProvider(): array
1146
    {
1147
        return [
1148
            'sub -1' => ['g', 'substring', '-1'],
1149
            'sub -1,0' => ['g', 'substring', '-1,0'],
1150
            'sub -1,-1' => ['', 'substring', '-1,-1'],
1151
            'sub -1,1' => ['g', 'substring', '-1,1'],
1152
            'sub 0' => ['substring', 'substring', '0'],
1153
            'sub 0,0' => ['substring', 'substring', '0,0'],
1154
            'sub 0,-1' => ['substrin', 'substring', '0,-1'],
1155
            'sub 0,1' => ['s', 'substring', '0,1'],
1156
            'sub 1' => ['ubstring', 'substring', '1'],
1157
            'sub 1,0' => ['ubstring', 'substring', '1,0'],
1158
            'sub 1,-1' => ['ubstrin', 'substring', '1,-1'],
1159
            'sub 1,1' => ['u', 'substring', '1,1'],
1160
            'sub' => ['substring', 'substring', ''],
1161
        ];
1162
    }
1163
1164
    /**
1165
     * Check if substring works properly.
1166
     *
1167
     * @test
1168
     * @dataProvider substringDataProvider
1169
     * @param string $expect The expected output.
1170
     * @param string $content The given input.
1171
     * @param string $conf The given configuration.
1172
     */
1173
    public function substring(string $expect, string $content, string $conf): void
1174
    {
1175
        self::assertSame($expect, $this->subject->substring($content, $conf));
1176
    }
1177
1178
    ///////////////////////////////
1179
    // Tests concerning getData()
1180
    ///////////////////////////////
1181
1182
    /**
1183
     * @return array
1184
     */
1185
    public function getDataWithTypeGpDataProvider(): array
1186
    {
1187
        return [
1188
            'Value in get-data' => ['onlyInGet', 'GetValue'],
1189
            'Value in post-data' => ['onlyInPost', 'PostValue'],
1190
            'Value in post-data overriding get-data' => ['inGetAndPost', 'ValueInPost'],
1191
        ];
1192
    }
1193
1194
    /**
1195
     * Checks if getData() works with type "gp"
1196
     *
1197
     * @test
1198
     * @dataProvider getDataWithTypeGpDataProvider
1199
     * @param string $key
1200
     * @param string $expectedValue
1201
     */
1202
    public function getDataWithTypeGp(string $key, string $expectedValue): void
1203
    {
1204
        $_GET = [
1205
            'onlyInGet' => 'GetValue',
1206
            'inGetAndPost' => 'ValueInGet',
1207
        ];
1208
        $_POST = [
1209
            'onlyInPost' => 'PostValue',
1210
            'inGetAndPost' => 'ValueInPost',
1211
        ];
1212
        self::assertEquals($expectedValue, $this->subject->getData('gp:' . $key));
1213
    }
1214
1215
    /**
1216
     * Checks if getData() works with type "tsfe"
1217
     *
1218
     * @test
1219
     */
1220
    public function getDataWithTypeTsfe(): void
1221
    {
1222
        self::assertEquals($GLOBALS['TSFE']->metaCharset, $this->subject->getData('tsfe:metaCharset'));
1223
    }
1224
1225
    /**
1226
     * Checks if getData() works with type "getenv"
1227
     *
1228
     * @test
1229
     */
1230
    public function getDataWithTypeGetenv(): void
1231
    {
1232
        $envName = StringUtility::getUniqueId('frontendtest');
1233
        $value = StringUtility::getUniqueId('someValue');
1234
        putenv($envName . '=' . $value);
1235
        self::assertEquals($value, $this->subject->getData('getenv:' . $envName));
1236
    }
1237
1238
    /**
1239
     * Checks if getData() works with type "getindpenv"
1240
     *
1241
     * @test
1242
     */
1243
    public function getDataWithTypeGetindpenv(): void
1244
    {
1245
        $this->subject->expects(self::once())->method('getEnvironmentVariable')
1246
            ->with(self::equalTo('SCRIPT_FILENAME'))->willReturn('dummyPath');
1247
        self::assertEquals('dummyPath', $this->subject->getData('getindpenv:SCRIPT_FILENAME'));
1248
    }
1249
1250
    /**
1251
     * Checks if getData() works with type "field"
1252
     *
1253
     * @test
1254
     */
1255
    public function getDataWithTypeField(): void
1256
    {
1257
        $key = 'someKey';
1258
        $value = 'someValue';
1259
        $field = [$key => $value];
1260
1261
        self::assertEquals($value, $this->subject->getData('field:' . $key, $field));
1262
    }
1263
1264
    /**
1265
     * Checks if getData() works with type "field" of the field content
1266
     * is multi-dimensional (e.g. an array)
1267
     *
1268
     * @test
1269
     */
1270
    public function getDataWithTypeFieldAndFieldIsMultiDimensional(): void
1271
    {
1272
        $key = 'somekey|level1|level2';
1273
        $value = 'somevalue';
1274
        $field = ['somekey' => ['level1' => ['level2' => 'somevalue']]];
1275
1276
        self::assertEquals($value, $this->subject->getData('field:' . $key, $field));
1277
    }
1278
1279
    public function getDataWithTypeFileReturnsUidOfFileObjectDataProvider(): array
1280
    {
1281
        return [
1282
            'no whitespace' => [
1283
                'typoScriptPath' => 'file:current:uid',
1284
            ],
1285
            'always whitespace' => [
1286
                'typoScriptPath' => 'file : current : uid',
1287
            ],
1288
            'mixed whitespace' => [
1289
                'typoScriptPath' => 'file:current : uid',
1290
            ],
1291
        ];
1292
    }
1293
1294
    /**
1295
     * Basic check if getData gets the uid of a file object
1296
     *
1297
     * @test
1298
     * @dataProvider getDataWithTypeFileReturnsUidOfFileObjectDataProvider
1299
     */
1300
    public function getDataWithTypeFileReturnsUidOfFileObject(string $typoScriptPath): void
1301
    {
1302
        $uid = StringUtility::getUniqueId();
1303
        $file = $this->createMock(File::class);
1304
        $file->expects(self::once())->method('getUid')->willReturn($uid);
1305
        $this->subject->setCurrentFile($file);
1306
        self::assertEquals($uid, $this->subject->getData($typoScriptPath));
1307
    }
1308
1309
    /**
1310
     * Checks if getData() works with type "parameters"
1311
     *
1312
     * @test
1313
     */
1314
    public function getDataWithTypeParameters(): void
1315
    {
1316
        $key = StringUtility::getUniqueId('someKey');
1317
        $value = StringUtility::getUniqueId('someValue');
1318
        $this->subject->parameters[$key] = $value;
0 ignored issues
show
Bug introduced by
Accessing parameters on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1319
1320
        self::assertEquals($value, $this->subject->getData('parameters:' . $key));
1321
    }
1322
1323
    /**
1324
     * Checks if getData() works with type "register"
1325
     *
1326
     * @test
1327
     */
1328
    public function getDataWithTypeRegister(): void
1329
    {
1330
        $key = StringUtility::getUniqueId('someKey');
1331
        $value = StringUtility::getUniqueId('someValue');
1332
        $GLOBALS['TSFE']->register[$key] = $value;
1333
1334
        self::assertEquals($value, $this->subject->getData('register:' . $key));
1335
    }
1336
1337
    /**
1338
     * Checks if getData() works with type "session"
1339
     *
1340
     * @test
1341
     */
1342
    public function getDataWithTypeSession(): void
1343
    {
1344
        $frontendUser = $this->getMockBuilder(FrontendUserAuthentication::class)
1345
            ->onlyMethods(['getSessionData'])
1346
            ->getMock();
1347
        $frontendUser->expects(self::once())->method('getSessionData')->with('myext')->willReturn([
1348
            'mydata' => [
1349
                'someValue' => 42,
1350
            ],
1351
        ]);
1352
        $GLOBALS['TSFE']->fe_user = $frontendUser;
1353
1354
        self::assertEquals(42, $this->subject->getData('session:myext|mydata|someValue'));
1355
    }
1356
1357
    /**
1358
     * Checks if getData() works with type "level"
1359
     *
1360
     * @test
1361
     */
1362
    public function getDataWithTypeLevel(): void
1363
    {
1364
        $rootline = [
1365
            0 => ['uid' => 1, 'title' => 'title1'],
1366
            1 => ['uid' => 2, 'title' => 'title2'],
1367
            2 => ['uid' => 3, 'title' => 'title3'],
1368
        ];
1369
1370
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1371
        self::assertEquals(2, $this->subject->getData('level'));
1372
    }
1373
1374
    /**
1375
     * Checks if getData() works with type "global"
1376
     *
1377
     * @test
1378
     */
1379
    public function getDataWithTypeGlobal(): void
1380
    {
1381
        self::assertEquals($GLOBALS['TSFE']->metaCharset, $this->subject->getData('global:TSFE|metaCharset'));
1382
    }
1383
1384
    /**
1385
     * Checks if getData() works with type "leveltitle"
1386
     *
1387
     * @test
1388
     */
1389
    public function getDataWithTypeLeveltitle(): void
1390
    {
1391
        $rootline = [
1392
            0 => ['uid' => 1, 'title' => 'title1'],
1393
            1 => ['uid' => 2, 'title' => 'title2'],
1394
            2 => ['uid' => 3, 'title' => ''],
1395
        ];
1396
1397
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1398
        self::assertEquals('', $this->subject->getData('leveltitle:-1'));
1399
        // since "title3" is not set, it will slide to "title2"
1400
        self::assertEquals('title2', $this->subject->getData('leveltitle:-1,slide'));
1401
    }
1402
1403
    /**
1404
     * Checks if getData() works with type "levelmedia"
1405
     *
1406
     * @test
1407
     */
1408
    public function getDataWithTypeLevelmedia(): void
1409
    {
1410
        $rootline = [
1411
            0 => ['uid' => 1, 'title' => 'title1', 'media' => 'media1'],
1412
            1 => ['uid' => 2, 'title' => 'title2', 'media' => 'media2'],
1413
            2 => ['uid' => 3, 'title' => 'title3', 'media' => ''],
1414
        ];
1415
1416
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1417
        self::assertEquals('', $this->subject->getData('levelmedia:-1'));
1418
        // since "title3" is not set, it will slide to "title2"
1419
        self::assertEquals('media2', $this->subject->getData('levelmedia:-1,slide'));
1420
    }
1421
1422
    /**
1423
     * Checks if getData() works with type "leveluid"
1424
     *
1425
     * @test
1426
     */
1427
    public function getDataWithTypeLeveluid(): void
1428
    {
1429
        $rootline = [
1430
            0 => ['uid' => 1, 'title' => 'title1'],
1431
            1 => ['uid' => 2, 'title' => 'title2'],
1432
            2 => ['uid' => 3, 'title' => 'title3'],
1433
        ];
1434
1435
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1436
        self::assertEquals(3, $this->subject->getData('leveluid:-1'));
1437
        // every element will have a uid - so adding slide doesn't really make sense, just for completeness
1438
        self::assertEquals(3, $this->subject->getData('leveluid:-1,slide'));
1439
    }
1440
1441
    /**
1442
     * Checks if getData() works with type "levelfield"
1443
     *
1444
     * @test
1445
     */
1446
    public function getDataWithTypeLevelfield(): void
1447
    {
1448
        $rootline = [
1449
            0 => ['uid' => 1, 'title' => 'title1', 'testfield' => 'field1'],
1450
            1 => ['uid' => 2, 'title' => 'title2', 'testfield' => 'field2'],
1451
            2 => ['uid' => 3, 'title' => 'title3', 'testfield' => ''],
1452
        ];
1453
1454
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1455
        self::assertEquals('', $this->subject->getData('levelfield:-1,testfield'));
1456
        self::assertEquals('field2', $this->subject->getData('levelfield:-1,testfield,slide'));
1457
    }
1458
1459
    /**
1460
     * Checks if getData() works with type "fullrootline"
1461
     *
1462
     * @test
1463
     */
1464
    public function getDataWithTypeFullrootline(): void
1465
    {
1466
        $rootline1 = [
1467
            0 => ['uid' => 1, 'title' => 'title1', 'testfield' => 'field1'],
1468
        ];
1469
        $rootline2 = [
1470
            0 => ['uid' => 1, 'title' => 'title1', 'testfield' => 'field1'],
1471
            1 => ['uid' => 2, 'title' => 'title2', 'testfield' => 'field2'],
1472
            2 => ['uid' => 3, 'title' => 'title3', 'testfield' => 'field3'],
1473
        ];
1474
1475
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline1;
1476
        $GLOBALS['TSFE']->rootLine = $rootline2;
1477
        self::assertEquals('field2', $this->subject->getData('fullrootline:-1,testfield'));
1478
    }
1479
1480
    /**
1481
     * Checks if getData() works with type "date"
1482
     *
1483
     * @test
1484
     */
1485
    public function getDataWithTypeDate(): void
1486
    {
1487
        $format = 'Y-M-D';
1488
        $defaultFormat = 'd/m Y';
1489
1490
        self::assertEquals(date($format, $GLOBALS['EXEC_TIME']), $this->subject->getData('date:' . $format));
1491
        self::assertEquals(date($defaultFormat, $GLOBALS['EXEC_TIME']), $this->subject->getData('date'));
1492
    }
1493
1494
    /**
1495
     * Checks if getData() works with type "page"
1496
     *
1497
     * @test
1498
     */
1499
    public function getDataWithTypePage(): void
1500
    {
1501
        $uid = random_int(0, mt_getrandmax());
1502
        $GLOBALS['TSFE']->page['uid'] = $uid;
1503
        self::assertEquals($uid, $this->subject->getData('page:uid'));
1504
    }
1505
1506
    /**
1507
     * Checks if getData() works with type "current"
1508
     *
1509
     * @test
1510
     */
1511
    public function getDataWithTypeCurrent(): void
1512
    {
1513
        $key = StringUtility::getUniqueId('someKey');
1514
        $value = StringUtility::getUniqueId('someValue');
1515
        $this->subject->data[$key] = $value;
0 ignored issues
show
Bug introduced by
Accessing data on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1516
        $this->subject->currentValKey = $key;
0 ignored issues
show
Bug introduced by
Accessing currentValKey on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1517
        self::assertEquals($value, $this->subject->getData('current'));
1518
    }
1519
1520
    /**
1521
     * Checks if getData() works with type "db"
1522
     *
1523
     * @test
1524
     */
1525
    public function getDataWithTypeDb(): void
1526
    {
1527
        $dummyRecord = ['uid' => 5, 'title' => 'someTitle'];
1528
1529
        $GLOBALS['TSFE']->sys_page->expects(self::atLeastOnce())->method('getRawRecord')->with(
1530
            'tt_content',
1531
            '106'
1532
        )->willReturn($dummyRecord);
1533
        self::assertEquals($dummyRecord['title'], $this->subject->getData('db:tt_content:106:title'));
1534
    }
1535
1536
    /**
1537
     * Checks if getData() works with type "lll"
1538
     *
1539
     * @test
1540
     */
1541
    public function getDataWithTypeLll(): void
1542
    {
1543
        $key = StringUtility::getUniqueId('someKey');
1544
        $value = StringUtility::getUniqueId('someValue');
1545
        $GLOBALS['TSFE']->expects(self::once())->method('sL')->with('LLL:' . $key)->willReturn($value);
1546
        self::assertEquals($value, $this->subject->getData('lll:' . $key));
1547
    }
1548
1549
    /**
1550
     * Checks if getData() works with type "path"
1551
     *
1552
     * @test
1553
     */
1554
    public function getDataWithTypePath(): void
1555
    {
1556
        $filenameIn = 'typo3/sysext/frontend/Public/Icons/Extension.svg';
1557
        self::assertEquals($filenameIn, $this->subject->getData('path:' . $filenameIn));
1558
    }
1559
1560
    /**
1561
     * Checks if getData() works with type "context"
1562
     *
1563
     * @test
1564
     */
1565
    public function getDataWithTypeContext(): void
1566
    {
1567
        $context = new Context([
1568
            'workspace' => new WorkspaceAspect(3),
1569
            'frontend.user' => new UserAspect(new FrontendUserAuthentication(), [0, -1]),
1570
        ]);
1571
        GeneralUtility::setSingletonInstance(Context::class, $context);
1572
        self::assertEquals(3, $this->subject->getData('context:workspace:id'));
1573
        self::assertEquals('0,-1', $this->subject->getData('context:frontend.user:groupIds'));
1574
        self::assertFalse($this->subject->getData('context:frontend.user:isLoggedIn'));
1575
        self::assertSame('', $this->subject->getData('context:frontend.user:foozball'));
1576
    }
1577
1578
    /**
1579
     * Checks if getData() works with type "site"
1580
     *
1581
     * @test
1582
     */
1583
    public function getDataWithTypeSite(): void
1584
    {
1585
        $site = new Site('my-site', 123, [
1586
            'base' => 'http://example.com',
1587
            'custom' => [
1588
                'config' => [
1589
                    'nested' => 'yeah',
1590
                ],
1591
            ],
1592
        ]);
1593
        $this->frontendControllerMock->_set('site', $site);
1594
        self::assertEquals('http://example.com', $this->subject->getData('site:base'));
1595
        self::assertEquals('yeah', $this->subject->getData('site:custom.config.nested'));
1596
    }
1597
1598
    /**
1599
     * Checks if getData() works with type "site" and base variants
1600
     *
1601
     * @test
1602
     */
1603
    public function getDataWithTypeSiteWithBaseVariants(): void
1604
    {
1605
        $packageManager = new PackageManager(new DependencyOrderingService());
1606
        GeneralUtility::addInstance(ProviderConfigurationLoader::class, new ProviderConfigurationLoader(
1607
            $packageManager,
1608
            new NullFrontend('core'),
1609
            'ExpressionLanguageProviders'
1610
        ));
1611
        putenv('LOCAL_DEVELOPMENT=1');
1612
1613
        $site = new Site('my-site', 123, [
1614
            'base' => 'http://prod.com',
1615
            'baseVariants' => [
1616
                [
1617
                    'base' => 'http://staging.com',
1618
                    'condition' => 'applicationContext == "Production/Staging"',
1619
                ],
1620
                [
1621
                    'base' => 'http://dev.com',
1622
                    'condition' => 'getenv("LOCAL_DEVELOPMENT") == 1',
1623
                ],
1624
            ],
1625
        ]);
1626
1627
        $this->frontendControllerMock->_set('site', $site);
1628
        self::assertEquals('http://dev.com', $this->subject->getData('site:base'));
1629
    }
1630
1631
    /**
1632
     * Checks if getData() works with type "siteLanguage"
1633
     *
1634
     * @test
1635
     */
1636
    public function getDataWithTypeSiteLanguage(): void
1637
    {
1638
        $site = $this->createSiteWithLanguage([
1639
            'base' => '/',
1640
            'languageId' => 1,
1641
            'locale' => 'de_DE',
1642
            'title' => 'languageTitle',
1643
            'navigationTitle' => 'German',
1644
        ]);
1645
        $language = $site->getLanguageById(1);
1646
        $this->frontendControllerMock->_set('language', $language);
1647
        self::assertEquals('German', $this->subject->getData('siteLanguage:navigationTitle'));
1648
    }
1649
1650
    /**
1651
     * Checks if getData() works with type "parentRecordNumber"
1652
     *
1653
     * @test
1654
     */
1655
    public function getDataWithTypeParentRecordNumber(): void
1656
    {
1657
        $recordNumber = random_int(0, mt_getrandmax());
1658
        $this->subject->parentRecordNumber = $recordNumber;
0 ignored issues
show
Bug introduced by
Accessing parentRecordNumber on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1659
        self::assertEquals($recordNumber, $this->subject->getData('cobj:parentRecordNumber'));
1660
    }
1661
1662
    /**
1663
     * Checks if getData() works with type "debug:rootLine"
1664
     *
1665
     * @test
1666
     */
1667
    public function getDataWithTypeDebugRootline(): void
1668
    {
1669
        $rootline = [
1670
            0 => ['uid' => 1, 'title' => 'title1'],
1671
            1 => ['uid' => 2, 'title' => 'title2'],
1672
            2 => ['uid' => 3, 'title' => ''],
1673
        ];
1674
        $expectedResult = 'array(3items)0=>array(2items)uid=>1(integer)title=>"title1"(6chars)1=>array(2items)uid=>2(integer)title=>"title2"(6chars)2=>array(2items)uid=>3(integer)title=>""(0chars)';
1675
        $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1676
1677
        DebugUtility::useAnsiColor(false);
1678
        $result = $this->subject->getData('debug:rootLine');
1679
        $cleanedResult = str_replace(["\r", "\n", "\t", ' '], '', $result);
1680
1681
        self::assertEquals($expectedResult, $cleanedResult);
1682
    }
1683
1684
    /**
1685
     * Checks if getData() works with type "debug:fullRootLine"
1686
     *
1687
     * @test
1688
     */
1689
    public function getDataWithTypeDebugFullRootline(): void
1690
    {
1691
        $rootline = [
1692
            0 => ['uid' => 1, 'title' => 'title1'],
1693
            1 => ['uid' => 2, 'title' => 'title2'],
1694
            2 => ['uid' => 3, 'title' => ''],
1695
        ];
1696
        $expectedResult = 'array(3items)0=>array(2items)uid=>1(integer)title=>"title1"(6chars)1=>array(2items)uid=>2(integer)title=>"title2"(6chars)2=>array(2items)uid=>3(integer)title=>""(0chars)';
1697
        $GLOBALS['TSFE']->rootLine = $rootline;
1698
1699
        DebugUtility::useAnsiColor(false);
1700
        $result = $this->subject->getData('debug:fullRootLine');
1701
        $cleanedResult = str_replace(["\r", "\n", "\t", ' '], '', $result);
1702
1703
        self::assertEquals($expectedResult, $cleanedResult);
1704
    }
1705
1706
    /**
1707
     * Checks if getData() works with type "debug:data"
1708
     *
1709
     * @test
1710
     */
1711
    public function getDataWithTypeDebugData(): void
1712
    {
1713
        $key = StringUtility::getUniqueId('someKey');
1714
        $value = StringUtility::getUniqueId('someValue');
1715
        $this->subject->data = [$key => $value];
0 ignored issues
show
Bug introduced by
Accessing data on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1716
1717
        $expectedResult = 'array(1item)' . $key . '=>"' . $value . '"(' . strlen($value) . 'chars)';
1718
1719
        DebugUtility::useAnsiColor(false);
1720
        $result = $this->subject->getData('debug:data');
1721
        $cleanedResult = str_replace(["\r", "\n", "\t", ' '], '', $result);
1722
1723
        self::assertEquals($expectedResult, $cleanedResult);
1724
    }
1725
1726
    /**
1727
     * Checks if getData() works with type "debug:register"
1728
     *
1729
     * @test
1730
     */
1731
    public function getDataWithTypeDebugRegister(): void
1732
    {
1733
        $key = StringUtility::getUniqueId('someKey');
1734
        $value = StringUtility::getUniqueId('someValue');
1735
        $GLOBALS['TSFE']->register = [$key => $value];
1736
1737
        $expectedResult = 'array(1item)' . $key . '=>"' . $value . '"(' . strlen($value) . 'chars)';
1738
1739
        DebugUtility::useAnsiColor(false);
1740
        $result = $this->subject->getData('debug:register');
1741
        $cleanedResult = str_replace(["\r", "\n", "\t", ' '], '', $result);
1742
1743
        self::assertEquals($expectedResult, $cleanedResult);
1744
    }
1745
1746
    /**
1747
     * Checks if getData() works with type "data:page"
1748
     *
1749
     * @test
1750
     */
1751
    public function getDataWithTypeDebugPage(): void
1752
    {
1753
        $uid = random_int(0, mt_getrandmax());
1754
        $GLOBALS['TSFE']->page = ['uid' => $uid];
1755
1756
        $expectedResult = 'array(1item)uid=>' . $uid . '(integer)';
1757
1758
        DebugUtility::useAnsiColor(false);
1759
        $result = $this->subject->getData('debug:page');
1760
        $cleanedResult = str_replace(["\r", "\n", "\t", ' '], '', $result);
1761
1762
        self::assertEquals($expectedResult, $cleanedResult);
1763
    }
1764
1765
    /**
1766
     * @test
1767
     */
1768
    public function aTagParamsHasLeadingSpaceIfNotEmpty(): void
1769
    {
1770
        $aTagParams = $this->subject->getATagParams(['ATagParams' => 'data-test="testdata"']);
1771
        self::assertEquals(' data-test="testdata"', $aTagParams);
1772
    }
1773
1774
    /**
1775
     * @test
1776
     */
1777
    public function aTagParamsHaveSpaceBetweenLocalAndGlobalParams(): void
1778
    {
1779
        $GLOBALS['TSFE']->config['config']['ATagParams'] = 'data-global="dataglobal"';
1780
        $aTagParams = $this->subject->getATagParams(['ATagParams' => 'data-test="testdata"']);
1781
        self::assertEquals(' data-global="dataglobal" data-test="testdata"', $aTagParams);
1782
    }
1783
1784
    /**
1785
     * @test
1786
     */
1787
    public function aTagParamsHasNoLeadingSpaceIfEmpty(): void
1788
    {
1789
        // make sure global ATagParams are empty
1790
        $GLOBALS['TSFE']->config['config']['ATagParams'] = '';
1791
        $aTagParams = $this->subject->getATagParams(['ATagParams' => '']);
1792
        self::assertEquals('', $aTagParams);
1793
    }
1794
1795
    /**
1796
     * @test
1797
     */
1798
    public function renderingContentObjectThrowsException(): void
1799
    {
1800
        $this->expectException(\LogicException::class);
1801
        $this->expectExceptionCode(1414513947);
1802
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture(false);
1803
        $this->subject->render($contentObjectFixture, []);
1804
    }
1805
1806
    /**
1807
     * @test
1808
     */
1809
    public function exceptionHandlerIsEnabledByDefaultInProductionContext(): void
1810
    {
1811
        Environment::initialize(
1812
            new ApplicationContext('Production'),
1813
            true,
1814
            false,
1815
            Environment::getProjectPath(),
1816
            Environment::getPublicPath(),
1817
            Environment::getVarPath(),
1818
            Environment::getConfigPath(),
1819
            Environment::getBackendPath() . '/index.php',
1820
            Environment::isWindows() ? 'WINDOWS' : 'UNIX'
1821
        );
1822
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1823
        $this->subject->render($contentObjectFixture, []);
1824
    }
1825
1826
    /**
1827
     * @test
1828
     */
1829
    public function renderingContentObjectDoesNotThrowExceptionIfExceptionHandlerIsConfiguredLocally(): void
1830
    {
1831
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1832
1833
        $configuration = [
1834
            'exceptionHandler' => '1',
1835
        ];
1836
        $this->subject->render($contentObjectFixture, $configuration);
1837
    }
1838
1839
    /**
1840
     * @test
1841
     */
1842
    public function renderingContentObjectDoesNotThrowExceptionIfExceptionHandlerIsConfiguredGlobally(): void
1843
    {
1844
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1845
1846
        $this->frontendControllerMock->config['config']['contentObjectExceptionHandler'] = '1';
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1847
        $this->subject->render($contentObjectFixture, []);
1848
    }
1849
1850
    /**
1851
     * @test
1852
     */
1853
    public function globalExceptionHandlerConfigurationCanBeOverriddenByLocalConfiguration(): void
1854
    {
1855
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture(false);
1856
        $this->expectException(\LogicException::class);
1857
        $this->expectExceptionCode(1414513947);
1858
        $this->frontendControllerMock->config['config']['contentObjectExceptionHandler'] = '1';
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1859
        $configuration = [
1860
            'exceptionHandler' => '0',
1861
        ];
1862
        $this->subject->render($contentObjectFixture, $configuration);
1863
    }
1864
1865
    /**
1866
     * @test
1867
     */
1868
    public function renderedErrorMessageCanBeCustomized(): void
1869
    {
1870
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1871
1872
        $configuration = [
1873
            'exceptionHandler' => '1',
1874
            'exceptionHandler.' => [
1875
                'errorMessage' => 'New message for testing',
1876
            ],
1877
        ];
1878
1879
        self::assertSame('New message for testing', $this->subject->render($contentObjectFixture, $configuration));
1880
    }
1881
1882
    /**
1883
     * @test
1884
     */
1885
    public function localConfigurationOverridesGlobalConfiguration(): void
1886
    {
1887
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1888
1889
        $this->frontendControllerMock
1890
            ->config['config']['contentObjectExceptionHandler.'] = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
1891
            'errorMessage' => 'Global message for testing',
1892
        ];
1893
        $configuration = [
1894
            'exceptionHandler' => '1',
1895
            'exceptionHandler.' => [
1896
                'errorMessage' => 'New message for testing',
1897
            ],
1898
        ];
1899
1900
        self::assertSame('New message for testing', $this->subject->render($contentObjectFixture, $configuration));
1901
    }
1902
1903
    /**
1904
     * @test
1905
     */
1906
    public function specificExceptionsCanBeIgnoredByExceptionHandler(): void
1907
    {
1908
        $contentObjectFixture = $this->createContentObjectThrowingExceptionFixture();
1909
1910
        $configuration = [
1911
            'exceptionHandler' => '1',
1912
            'exceptionHandler.' => [
1913
                'ignoreCodes.' => ['10.' => '1414513947'],
1914
            ],
1915
        ];
1916
        $this->expectException(\LogicException::class);
1917
        $this->expectExceptionCode(1414513947);
1918
        $this->subject->render($contentObjectFixture, $configuration);
1919
    }
1920
1921
    /**
1922
     * @return MockObject|AbstractContentObject
1923
     */
1924
    protected function createContentObjectThrowingExceptionFixture(bool $addProductionExceptionHandlerInstance = true)
1925
    {
1926
        $contentObjectFixture = $this->getMockBuilder(AbstractContentObject::class)
1927
            ->setConstructorArgs([$this->subject])
1928
            ->getMock();
1929
        $contentObjectFixture->expects(self::once())
1930
            ->method('render')
1931
            ->willReturnCallback(static function () {
1932
                throw new \LogicException('Exception during rendering', 1414513947);
1933
            });
1934
        if ($addProductionExceptionHandlerInstance) {
1935
            GeneralUtility::addInstance(
1936
                ProductionExceptionHandler::class,
1937
                new ProductionExceptionHandler(new Context(), new Random(), new NullLogger())
1938
            );
1939
        }
1940
        return $contentObjectFixture;
1941
    }
1942
1943
    /**
1944
     * @return array
1945
     */
1946
    protected function getLibParseFunc(): array
1947
    {
1948
        return [
1949
            'makelinks' => '1',
1950
            'makelinks.' => [
1951
                'http.' => [
1952
                    'keep' => '{$styles.content.links.keep}',
1953
                    'extTarget' => '',
1954
                    'mailto.' => [
1955
                        'keep' => 'path',
1956
                    ],
1957
                ],
1958
            ],
1959
            'tags' => [
1960
                'link' => 'TEXT',
1961
                'link.' => [
1962
                    'current' => '1',
1963
                    'typolink.' => [
1964
                        'parameter.' => [
1965
                            'data' => 'parameters : allParams',
1966
                        ],
1967
                    ],
1968
                    'parseFunc.' => [
1969
                        'constants' => '1',
1970
                    ],
1971
                ],
1972
            ],
1973
1974
            'allowTags' => 'a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var',
1975
            'denyTags' => '*',
1976
            'sword' => '<span class="csc-sword">|</span>',
1977
            'constants' => '1',
1978
            'nonTypoTagStdWrap.' => [
1979
                'HTMLparser' => '1',
1980
                'HTMLparser.' => [
1981
                    'keepNonMatchedTags' => '1',
1982
                    'htmlSpecialChars' => '2',
1983
                ],
1984
            ],
1985
        ];
1986
    }
1987
1988
    /**
1989
     * @return array
1990
     */
1991
    public function typolinkReturnsCorrectLinksForEmailsAndUrlsDataProvider(): array
1992
    {
1993
        return [
1994
            'Link to url' => [
1995
                'TYPO3',
1996
                [
1997
                    'directImageLink' => false,
1998
                    'parameter' => 'http://typo3.org',
1999
                ],
2000
                '<a href="http://typo3.org">TYPO3</a>',
2001
            ],
2002
            'Link to url without schema' => [
2003
                'TYPO3',
2004
                [
2005
                    'directImageLink' => false,
2006
                    'parameter' => 'typo3.org',
2007
                ],
2008
                '<a href="http://typo3.org">TYPO3</a>',
2009
            ],
2010
            'Link to url without link text' => [
2011
                '',
2012
                [
2013
                    'directImageLink' => false,
2014
                    'parameter' => 'http://typo3.org',
2015
                ],
2016
                '<a href="http://typo3.org">http://typo3.org</a>',
2017
            ],
2018
            'Link to url with attributes' => [
2019
                'TYPO3',
2020
                [
2021
                    'parameter' => 'http://typo3.org',
2022
                    'ATagParams' => 'class="url-class"',
2023
                    'extTarget' => '_blank',
2024
                    'title' => 'Open new window',
2025
                ],
2026
                '<a href="http://typo3.org" title="Open new window" target="_blank" class="url-class" rel="noreferrer">TYPO3</a>',
2027
            ],
2028
            'Link to url with attributes and custom target name' => [
2029
                'TYPO3',
2030
                [
2031
                    'parameter' => 'http://typo3.org',
2032
                    'ATagParams' => 'class="url-class"',
2033
                    'extTarget' => 'someTarget',
2034
                    'title' => 'Open new window',
2035
                ],
2036
                '<a href="http://typo3.org" title="Open new window" target="someTarget" class="url-class" rel="noreferrer">TYPO3</a>',
2037
            ],
2038
            'Link to url with attributes in parameter' => [
2039
                'TYPO3',
2040
                [
2041
                    'parameter' => 'http://typo3.org _blank url-class "Open new window"',
2042
                ],
2043
                '<a href="http://typo3.org" title="Open new window" target="_blank" class="url-class" rel="noreferrer">TYPO3</a>',
2044
            ],
2045
            'Link to url with attributes in parameter and custom target name' => [
2046
                'TYPO3',
2047
                [
2048
                    'parameter' => 'http://typo3.org someTarget url-class "Open new window"',
2049
                ],
2050
                '<a href="http://typo3.org" title="Open new window" target="someTarget" class="url-class" rel="noreferrer">TYPO3</a>',
2051
            ],
2052
            'Link to url with script tag' => [
2053
                '',
2054
                [
2055
                    'directImageLink' => false,
2056
                    'parameter' => 'http://typo3.org<script>alert(123)</script>',
2057
                ],
2058
                '<a href="http://typo3.org&lt;script&gt;alert(123)&lt;/script&gt;">http://typo3.org&lt;script&gt;alert(123)&lt;/script&gt;</a>',
2059
            ],
2060
            'Link to email address' => [
2061
                'Email address',
2062
                [
2063
                    'parameter' => '[email protected]',
2064
                ],
2065
                '<a href="mailto:[email protected]">Email address</a>',
2066
            ],
2067
            'Link to email address without link text' => [
2068
                '',
2069
                [
2070
                    'parameter' => '[email protected]',
2071
                ],
2072
                '<a href="mailto:[email protected]">[email protected]</a>',
2073
            ],
2074
            'Link to email with attributes' => [
2075
                'Email address',
2076
                [
2077
                    'parameter' => '[email protected]',
2078
                    'ATagParams' => 'class="email-class"',
2079
                    'title' => 'Write an email',
2080
                ],
2081
                '<a href="mailto:[email protected]" title="Write an email" class="email-class">Email address</a>',
2082
            ],
2083
            'Link to email with attributes in parameter' => [
2084
                'Email address',
2085
                [
2086
                    'parameter' => '[email protected] - email-class "Write an email"',
2087
                ],
2088
                '<a href="mailto:[email protected]" title="Write an email" class="email-class">Email address</a>',
2089
            ],
2090
        ];
2091
    }
2092
2093
    /**
2094
     * @test
2095
     * @param string $linkText
2096
     * @param array $configuration
2097
     * @param string $expectedResult
2098
     * @dataProvider typolinkReturnsCorrectLinksForEmailsAndUrlsDataProvider
2099
     */
2100
    public function typolinkReturnsCorrectLinksForEmailsAndUrls(string $linkText, array $configuration, string $expectedResult): void
2101
    {
2102
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
2103
            ->disableOriginalConstructor()
2104
            ->getMock();
2105
        $templateServiceObjectMock = $this->getMockBuilder(TemplateService::class)
2106
            ->setConstructorArgs([null, $packageManagerMock])
2107
            ->addMethods(['dummy'])
2108
            ->getMock();
2109
        $templateServiceObjectMock->setup = [
0 ignored issues
show
Bug introduced by
Accessing setup on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2110
            'lib.' => [
2111
                'parseFunc.' => $this->getLibParseFunc(),
2112
            ],
2113
        ];
2114
        $typoScriptFrontendControllerMockObject = $this->createMock(TypoScriptFrontendController::class);
2115
        $typoScriptFrontendControllerMockObject->config = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2116
            'config' => [],
2117
        ];
2118
        $typoScriptFrontendControllerMockObject->tmpl = $templateServiceObjectMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2119
        $GLOBALS['TSFE'] = $typoScriptFrontendControllerMockObject;
2120
2121
        $this->cacheManager->getCache('runtime')->willReturn(new NullFrontend('dummy'));
2122
        $this->cacheManager->getCache('core')->willReturn(new NullFrontend('runtime'));
2123
2124
        GeneralUtility::setSingletonInstance(
2125
            SiteConfiguration::class,
2126
            new SiteConfiguration(Environment::getConfigPath() . '/sites', new NullFrontend('dummy'))
2127
        );
2128
2129
        $this->subject->_set('typoScriptFrontendController', $typoScriptFrontendControllerMockObject);
2130
2131
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2132
    }
2133
2134
    /**
2135
     * @param array $settings
2136
     * @param string $linkText
2137
     * @param string $mailAddress
2138
     * @param string $expected
2139
     * @dataProvider typoLinkEncodesMailAddressForSpamProtectionDataProvider
2140
     * @test
2141
     */
2142
    public function typoLinkEncodesMailAddressForSpamProtection(
2143
        array $settings,
2144
        string $linkText,
2145
        string $mailAddress,
2146
        string $expected
2147
    ): void {
2148
        $this->getFrontendController()->spamProtectEmailAddresses = $settings['spamProtectEmailAddresses'];
2149
        $this->getFrontendController()->config['config'] = $settings;
2150
        $typoScript = ['parameter' => $mailAddress];
2151
2152
        self::assertEquals($expected, $this->subject->typoLink($linkText, $typoScript));
2153
    }
2154
2155
    /**
2156
     * @return array
2157
     */
2158
    public function typoLinkEncodesMailAddressForSpamProtectionDataProvider(): array
2159
    {
2160
        return [
2161
            'plain mail without mailto scheme' => [
2162
                [
2163
                    'spamProtectEmailAddresses' => '',
2164
                    'spamProtectEmailAddresses_atSubst' => '',
2165
                    'spamProtectEmailAddresses_lastDotSubst' => '',
2166
                ],
2167
                '[email protected]',
2168
                '[email protected]',
2169
                '<a href="mailto:[email protected]">[email protected]</a>',
2170
            ],
2171
            'plain mail with mailto scheme' => [
2172
                [
2173
                    'spamProtectEmailAddresses' => '',
2174
                    'spamProtectEmailAddresses_atSubst' => '',
2175
                    'spamProtectEmailAddresses_lastDotSubst' => '',
2176
                ],
2177
                '[email protected]',
2178
                'mailto:[email protected]',
2179
                '<a href="mailto:[email protected]">[email protected]</a>',
2180
            ],
2181
            'plain with at and dot substitution' => [
2182
                [
2183
                    'spamProtectEmailAddresses' => '0',
2184
                    'spamProtectEmailAddresses_atSubst' => '(at)',
2185
                    'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
2186
                ],
2187
                '[email protected]',
2188
                'mailto:[email protected]',
2189
                '<a href="mailto:[email protected]">[email protected]</a>',
2190
            ],
2191
            'mono-alphabetic substitution offset +1' => [
2192
                [
2193
                    'spamProtectEmailAddresses' => '1',
2194
                    'spamProtectEmailAddresses_atSubst' => '',
2195
                    'spamProtectEmailAddresses_lastDotSubst' => '',
2196
                ],
2197
                '[email protected]',
2198
                'mailto:[email protected]',
2199
                '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">some.body(at)test.typo3.org</a>',
2200
            ],
2201
            'mono-alphabetic substitution offset +1 with at substitution' => [
2202
                [
2203
                    'spamProtectEmailAddresses' => '1',
2204
                    'spamProtectEmailAddresses_atSubst' => '@',
2205
                    'spamProtectEmailAddresses_lastDotSubst' => '',
2206
                ],
2207
                '[email protected]',
2208
                'mailto:[email protected]',
2209
                '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">[email protected]</a>',
2210
            ],
2211
            'mono-alphabetic substitution offset +1 with at and dot substitution' => [
2212
                [
2213
                    'spamProtectEmailAddresses' => '1',
2214
                    'spamProtectEmailAddresses_atSubst' => '(at)',
2215
                    'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
2216
                ],
2217
                '[email protected]',
2218
                'mailto:[email protected]',
2219
                '<a href="#" data-mailto-token="nbjmup+tpnf/cpezAuftu/uzqp4/psh" data-mailto-vector="1">some.body(at)test.typo3(dot)org</a>',
2220
            ],
2221
            'mono-alphabetic substitution offset -1 with at and dot substitution' => [
2222
                [
2223
                    'spamProtectEmailAddresses' => '-1',
2224
                    'spamProtectEmailAddresses_atSubst' => '(at)',
2225
                    'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
2226
                ],
2227
                '[email protected]',
2228
                'mailto:[email protected]',
2229
                '<a href="#" data-mailto-token="lzhksn9rnld-ancxZsdrs-sxon2-nqf" data-mailto-vector="-1">some.body(at)test.typo3(dot)org</a>',
2230
            ],
2231
            'mono-alphabetic substitution offset 2 with at and dot substitution and encoded subject' => [
2232
                [
2233
                    'spamProtectEmailAddresses' => '2',
2234
                    'spamProtectEmailAddresses_atSubst' => '(at)',
2235
                    'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
2236
                ],
2237
                '[email protected]',
2238
                'mailto:[email protected]?subject=foo%20bar',
2239
                '<a href="#" data-mailto-token="ocknvq,uqog0dqfaBvguv0varq50qti?uwdlgev=hqq%42dct" data-mailto-vector="2">[email protected]</a>',
2240
            ],
2241
            'entity substitution with at and dot substitution' => [
2242
                [
2243
                    'spamProtectEmailAddresses' => 'ascii',
2244
                    'spamProtectEmailAddresses_atSubst' => '',
2245
                    'spamProtectEmailAddresses_lastDotSubst' => '',
2246
                ],
2247
                '[email protected]',
2248
                'mailto:[email protected]',
2249
                '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#111;&#109;&#101;&#46;&#98;&#111;&#100;&#121;&#64;&#116;&#101;&#115;&#116;&#46;&#116;&#121;&#112;&#111;&#51;&#46;&#111;&#114;&#103;">some.body(at)test.typo3.org</a>',
2250
            ],
2251
            'entity substitution with at and dot substitution with at and dot substitution' => [
2252
                [
2253
                    'spamProtectEmailAddresses' => 'ascii',
2254
                    'spamProtectEmailAddresses_atSubst' => '(at)',
2255
                    'spamProtectEmailAddresses_lastDotSubst' => '(dot)',
2256
                ],
2257
                '[email protected]',
2258
                'mailto:[email protected]',
2259
                '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#111;&#109;&#101;&#46;&#98;&#111;&#100;&#121;&#64;&#116;&#101;&#115;&#116;&#46;&#116;&#121;&#112;&#111;&#51;&#46;&#111;&#114;&#103;">some.body(at)test.typo3(dot)org</a>',
2260
            ],
2261
        ];
2262
    }
2263
2264
    /**
2265
     * @return array
2266
     */
2267
    public function typolinkReturnsCorrectLinksFilesDataProvider(): array
2268
    {
2269
        return [
2270
            'Link to file' => [
2271
                'My file',
2272
                [
2273
                    'directImageLink' => false,
2274
                    'parameter' => 'fileadmin/foo.bar',
2275
                ],
2276
                '<a href="fileadmin/foo.bar">My file</a>',
2277
            ],
2278
            'Link to file without link text' => [
2279
                '',
2280
                [
2281
                    'directImageLink' => false,
2282
                    'parameter' => 'fileadmin/foo.bar',
2283
                ],
2284
                '<a href="fileadmin/foo.bar">fileadmin/foo.bar</a>',
2285
            ],
2286
            'Link to file with attributes' => [
2287
                'My file',
2288
                [
2289
                    'parameter' => 'fileadmin/foo.bar',
2290
                    'ATagParams' => 'class="file-class"',
2291
                    'fileTarget' => '_blank',
2292
                    'title' => 'Title of the file',
2293
                ],
2294
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2295
            ],
2296
            'Link to file with attributes and additional href' => [
2297
                'My file',
2298
                [
2299
                    'parameter' => 'fileadmin/foo.bar',
2300
                    'ATagParams' => 'href="foo-bar"',
2301
                    'fileTarget' => '_blank',
2302
                    'title' => 'Title of the file',
2303
                ],
2304
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank">My file</a>',
2305
            ],
2306
            'Link to file with attributes and additional href and class' => [
2307
                'My file',
2308
                [
2309
                    'parameter' => 'fileadmin/foo.bar',
2310
                    'ATagParams' => 'href="foo-bar" class="file-class"',
2311
                    'fileTarget' => '_blank',
2312
                    'title' => 'Title of the file',
2313
                ],
2314
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2315
            ],
2316
            'Link to file with attributes and additional class and href' => [
2317
                'My file',
2318
                [
2319
                    'parameter' => 'fileadmin/foo.bar',
2320
                    'ATagParams' => 'class="file-class" href="foo-bar"',
2321
                    'fileTarget' => '_blank',
2322
                    'title' => 'Title of the file',
2323
                ],
2324
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2325
            ],
2326
            'Link to file with attributes and additional class and href and title' => [
2327
                'My file',
2328
                [
2329
                    'parameter' => 'fileadmin/foo.bar',
2330
                    'ATagParams' => 'class="file-class" href="foo-bar" title="foo-bar"',
2331
                    'fileTarget' => '_blank',
2332
                    'title' => 'Title of the file',
2333
                ],
2334
                '<a href="fileadmin/foo.bar" title="foo-bar" target="_blank" class="file-class">My file</a>',
2335
            ],
2336
            'Link to file with attributes and empty ATagParams' => [
2337
                'My file',
2338
                [
2339
                    'parameter' => 'fileadmin/foo.bar',
2340
                    'ATagParams' => '',
2341
                    'fileTarget' => '_blank',
2342
                    'title' => 'Title of the file',
2343
                ],
2344
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank">My file</a>',
2345
            ],
2346
            'Link to file with attributes in parameter' => [
2347
                'My file',
2348
                [
2349
                    'parameter' => 'fileadmin/foo.bar _blank file-class "Title of the file"',
2350
                ],
2351
                '<a href="fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2352
            ],
2353
            'Link to file with script tag in name' => [
2354
                '',
2355
                [
2356
                    'directImageLink' => false,
2357
                    'parameter' => 'fileadmin/<script>alert(123)</script>',
2358
                ],
2359
                '<a href="fileadmin/&lt;script&gt;alert(123)&lt;/script&gt;">fileadmin/&lt;script&gt;alert(123)&lt;/script&gt;</a>',
2360
            ],
2361
        ];
2362
    }
2363
2364
    /**
2365
     * @test
2366
     * @param string $linkText
2367
     * @param array $configuration
2368
     * @param string $expectedResult
2369
     * @dataProvider typolinkReturnsCorrectLinksFilesDataProvider
2370
     */
2371
    public function typolinkReturnsCorrectLinksFiles(string $linkText, array $configuration, string $expectedResult): void
2372
    {
2373
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
2374
            ->disableOriginalConstructor()
2375
            ->getMock();
2376
        $templateServiceObjectMock = $this->getMockBuilder(TemplateService::class)
2377
            ->setConstructorArgs([null, $packageManagerMock])
2378
            ->addMethods(['dummy'])
2379
            ->getMock();
2380
        $templateServiceObjectMock->setup = [
0 ignored issues
show
Bug introduced by
Accessing setup on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2381
            'lib.' => [
2382
                'parseFunc.' => $this->getLibParseFunc(),
2383
            ],
2384
        ];
2385
        $typoScriptFrontendControllerMockObject = $this->createMock(TypoScriptFrontendController::class);
2386
        $typoScriptFrontendControllerMockObject->config = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2387
            'config' => [],
2388
        ];
2389
        $typoScriptFrontendControllerMockObject->tmpl = $templateServiceObjectMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2390
        $GLOBALS['TSFE'] = $typoScriptFrontendControllerMockObject;
2391
2392
        $resourceFactory = $this->prophesize(ResourceFactory::class);
2393
        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
2394
2395
        $this->subject->_set('typoScriptFrontendController', $typoScriptFrontendControllerMockObject);
2396
2397
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2398
    }
2399
2400
    /**
2401
     * @return array
2402
     */
2403
    public function typolinkReturnsCorrectLinksForFilesWithAbsRefPrefixDataProvider(): array
2404
    {
2405
        return [
2406
            'Link to file' => [
2407
                'My file',
2408
                [
2409
                    'directImageLink' => false,
2410
                    'parameter' => 'fileadmin/foo.bar',
2411
                ],
2412
                '/',
2413
                '<a href="/fileadmin/foo.bar">My file</a>',
2414
            ],
2415
            'Link to file with longer absRefPrefix' => [
2416
                'My file',
2417
                [
2418
                    'directImageLink' => false,
2419
                    'parameter' => 'fileadmin/foo.bar',
2420
                ],
2421
                '/sub/',
2422
                '<a href="/sub/fileadmin/foo.bar">My file</a>',
2423
            ],
2424
            'Link to absolute file' => [
2425
                'My file',
2426
                [
2427
                    'directImageLink' => false,
2428
                    'parameter' => '/images/foo.bar',
2429
                ],
2430
                '/',
2431
                '<a href="/images/foo.bar">My file</a>',
2432
            ],
2433
            'Link to absolute file with longer absRefPrefix' => [
2434
                'My file',
2435
                [
2436
                    'directImageLink' => false,
2437
                    'parameter' => '/images/foo.bar',
2438
                ],
2439
                '/sub/',
2440
                '<a href="/images/foo.bar">My file</a>',
2441
            ],
2442
            'Link to absolute file with identical longer absRefPrefix' => [
2443
                'My file',
2444
                [
2445
                    'directImageLink' => false,
2446
                    'parameter' => '/sub/fileadmin/foo.bar',
2447
                ],
2448
                '/sub/',
2449
                '<a href="/sub/fileadmin/foo.bar">My file</a>',
2450
            ],
2451
            'Link to file with empty absRefPrefix' => [
2452
                'My file',
2453
                [
2454
                    'directImageLink' => false,
2455
                    'parameter' => 'fileadmin/foo.bar',
2456
                ],
2457
                '',
2458
                '<a href="fileadmin/foo.bar">My file</a>',
2459
            ],
2460
            'Link to absolute file with empty absRefPrefix' => [
2461
                'My file',
2462
                [
2463
                    'directImageLink' => false,
2464
                    'parameter' => '/fileadmin/foo.bar',
2465
                ],
2466
                '',
2467
                '<a href="/fileadmin/foo.bar">My file</a>',
2468
            ],
2469
            'Link to file with attributes with absRefPrefix' => [
2470
                'My file',
2471
                [
2472
                    'parameter' => 'fileadmin/foo.bar',
2473
                    'ATagParams' => 'class="file-class"',
2474
                    'fileTarget' => '_blank',
2475
                    'title' => 'Title of the file',
2476
                ],
2477
                '/',
2478
                '<a href="/fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2479
            ],
2480
            'Link to file with attributes with longer absRefPrefix' => [
2481
                'My file',
2482
                [
2483
                    'parameter' => 'fileadmin/foo.bar',
2484
                    'ATagParams' => 'class="file-class"',
2485
                    'fileTarget' => '_blank',
2486
                    'title' => 'Title of the file',
2487
                ],
2488
                '/sub/',
2489
                '<a href="/sub/fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2490
            ],
2491
            'Link to absolute file with attributes with absRefPrefix' => [
2492
                'My file',
2493
                [
2494
                    'parameter' => '/images/foo.bar',
2495
                    'ATagParams' => 'class="file-class"',
2496
                    'fileTarget' => '_blank',
2497
                    'title' => 'Title of the file',
2498
                ],
2499
                '/',
2500
                '<a href="/images/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2501
            ],
2502
            'Link to absolute file with attributes with longer absRefPrefix' => [
2503
                'My file',
2504
                [
2505
                    'parameter' => '/images/foo.bar',
2506
                    'ATagParams' => 'class="file-class"',
2507
                    'fileTarget' => '_blank',
2508
                    'title' => 'Title of the file',
2509
                ],
2510
                '/sub/',
2511
                '<a href="/images/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2512
            ],
2513
            'Link to absolute file with attributes with identical longer absRefPrefix' => [
2514
                'My file',
2515
                [
2516
                    'parameter' => '/sub/fileadmin/foo.bar',
2517
                    'ATagParams' => 'class="file-class"',
2518
                    'fileTarget' => '_blank',
2519
                    'title' => 'Title of the file',
2520
                ],
2521
                '/sub/',
2522
                '<a href="/sub/fileadmin/foo.bar" title="Title of the file" target="_blank" class="file-class">My file</a>',
2523
            ],
2524
        ];
2525
    }
2526
2527
    /**
2528
     * @test
2529
     * @param string $linkText
2530
     * @param array $configuration
2531
     * @param string $absRefPrefix
2532
     * @param string $expectedResult
2533
     * @dataProvider typolinkReturnsCorrectLinksForFilesWithAbsRefPrefixDataProvider
2534
     */
2535
    public function typolinkReturnsCorrectLinksForFilesWithAbsRefPrefix(
2536
        string $linkText,
2537
        array $configuration,
2538
        string $absRefPrefix,
2539
        string $expectedResult
2540
    ): void {
2541
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
2542
            ->disableOriginalConstructor()
2543
            ->getMock();
2544
        $templateServiceObjectMock = $this->getMockBuilder(TemplateService::class)
2545
            ->setConstructorArgs([null, $packageManagerMock])
2546
            ->addMethods(['dummy'])
2547
            ->getMock();
2548
        $templateServiceObjectMock->setup = [
0 ignored issues
show
Bug introduced by
Accessing setup on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2549
            'lib.' => [
2550
                'parseFunc.' => $this->getLibParseFunc(),
2551
            ],
2552
        ];
2553
        $resourceFactory = $this->prophesize(ResourceFactory::class);
2554
        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
2555
2556
        $typoScriptFrontendControllerMockObject = $this->createMock(TypoScriptFrontendController::class);
2557
        $typoScriptFrontendControllerMockObject->config = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2558
            'config' => [],
2559
        ];
2560
        $typoScriptFrontendControllerMockObject->tmpl = $templateServiceObjectMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2561
        $GLOBALS['TSFE'] = $typoScriptFrontendControllerMockObject;
2562
        $GLOBALS['TSFE']->absRefPrefix = $absRefPrefix;
2563
        $this->subject->_set('typoScriptFrontendController', $typoScriptFrontendControllerMockObject);
2564
2565
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2566
    }
2567
2568
    /**
2569
     * @test
2570
     */
2571
    public function typolinkOpensInNewWindow(): void
2572
    {
2573
        $this->cacheManager->getCache('runtime')->willReturn(new NullFrontend('runtime'));
2574
        $this->cacheManager->getCache('core')->willReturn(new NullFrontend('runtime'));
2575
        GeneralUtility::setSingletonInstance(
2576
            SiteConfiguration::class,
2577
            new SiteConfiguration(Environment::getConfigPath() . '/sites', new NullFrontend('dummy'))
2578
        );
2579
        $linkText = 'Nice Text';
2580
        $configuration = [
2581
            'parameter' => 'https://example.com 13x84:target=myexample',
2582
        ];
2583
        $expectedResult = '<a href="https://example.com" target="myexample" data-window-url="https://example.com" data-window-target="myexample" data-window-features="width=13,height=84" rel="noreferrer">Nice Text</a>';
2584
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2585
        $linkText = 'Nice Text with default window name';
2586
        $configuration = [
2587
            'parameter' => 'https://example.com 13x84',
2588
        ];
2589
        $expectedResult = '<a href="https://example.com" target="FEopenLink" data-window-url="https://example.com" data-window-target="FEopenLink" data-window-features="width=13,height=84" rel="noreferrer">Nice Text with default window name</a>';
2590
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2591
2592
        $linkText = 'Nice Text with default window name';
2593
        $configuration = [
2594
            'parameter' => 'https://example.com 13x84',
2595
        ];
2596
        $expectedResult = '<a href="https://example.com" target="FEopenLink" data-window-url="https://example.com" data-window-target="FEopenLink" data-window-features="width=13,height=84" rel="noreferrer">Nice Text with default window name</a>';
2597
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2598
2599
        $GLOBALS['TSFE']->xhtmlDoctype = 'xhtml_strict';
2600
        $linkText = 'Nice Text with default window name';
2601
        $configuration = [
2602
            'parameter' => 'https://example.com 13x84',
2603
        ];
2604
        $expectedResult = '<a href="https://example.com" data-window-url="https://example.com" data-window-target="FEopenLink" data-window-features="width=13,height=84" rel="noreferrer">Nice Text with default window name</a>';
2605
        self::assertEquals($expectedResult, $this->subject->typoLink($linkText, $configuration));
2606
    }
2607
2608
    /**
2609
     * @test
2610
     */
2611
    public function typoLinkReturnsOnlyLinkTextIfNoLinkResolvingIsPossible(): void
2612
    {
2613
        $linkService = $this->prophesize(LinkService::class);
2614
        GeneralUtility::setSingletonInstance(LinkService::class, $linkService->reveal());
2615
        $linkService->resolve('foo')->willThrow(InvalidPathException::class);
2616
2617
        self::assertSame('foo', $this->subject->typoLink('foo', ['parameter' => 'foo']));
2618
    }
2619
2620
    /**
2621
     * @test
2622
     */
2623
    public function typoLinkLogsErrorIfNoLinkResolvingIsPossible(): void
2624
    {
2625
        $linkService = $this->prophesize(LinkService::class);
2626
        GeneralUtility::setSingletonInstance(LinkService::class, $linkService->reveal());
2627
        $linkService->resolve('foo')->willThrow(InvalidPathException::class);
2628
2629
        $logger = $this->prophesize(Logger::class);
2630
        $logger->warning('The link could not be generated', Argument::any())->shouldBeCalled();
2631
        $this->subject->setLogger($logger->reveal());
2632
        $this->subject->typoLink('foo', ['parameter' => 'foo']);
2633
    }
2634
2635
    /**
2636
     * @test
2637
     */
2638
    public function typolinkLinkResult(): void
2639
    {
2640
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
2641
            ->disableOriginalConstructor()
2642
            ->getMock();
2643
        $templateServiceObjectMock = $this->getMockBuilder(TemplateService::class)
2644
            ->setConstructorArgs([null, $packageManagerMock])
2645
            ->addMethods(['dummy'])
2646
            ->getMock();
2647
        $templateServiceObjectMock->setup = [
0 ignored issues
show
Bug introduced by
Accessing setup on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2648
            'lib.' => [
2649
                'parseFunc.' => $this->getLibParseFunc(),
2650
            ],
2651
        ];
2652
        $typoScriptFrontendControllerMockObject = $this->createMock(TypoScriptFrontendController::class);
2653
        $typoScriptFrontendControllerMockObject->config = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2654
            'config' => [],
2655
        ];
2656
        $typoScriptFrontendControllerMockObject->tmpl = $templateServiceObjectMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2657
        $GLOBALS['TSFE'] = $typoScriptFrontendControllerMockObject;
2658
2659
        $resourceFactory = $this->prophesize(ResourceFactory::class);
2660
        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
2661
2662
        $this->cacheManager->getCache('runtime')->willReturn(new NullFrontend('dummy'));
2663
        $this->cacheManager->getCache('core')->willReturn(new NullFrontend('runtime'));
2664
2665
        GeneralUtility::setSingletonInstance(
2666
            SiteConfiguration::class,
2667
            new SiteConfiguration(Environment::getConfigPath() . '/sites', new NullFrontend('dummy'))
2668
        );
2669
2670
        $this->subject->_set('typoScriptFrontendController', $typoScriptFrontendControllerMockObject);
2671
2672
        $linkResult = $this->subject->typoLink('', [
2673
            'parameter' => 'https://example.tld',
2674
            'returnLast' => 'result', ]);
2675
2676
        self::assertTrue(is_a($linkResult, LinkResultInterface::class, true));
2677
        self::assertEquals(json_encode([
2678
            'href' => 'https://example.tld',
2679
            'target' => null,
2680
            'class' => null,
2681
            'title' => null,
2682
            'linkText' => 'https://example.tld',
2683
            'additionalAttributes' => [], ]), json_encode($linkResult));
2684
        self::assertEquals(json_encode([
2685
            'href' => 'https://example.tld',
2686
            'target' => null,
2687
            'class' => null,
2688
            'title' => null,
2689
            'linkText' => 'https://example.tld',
2690
            'additionalAttributes' => [], ]), (string)$linkResult);
2691
    }
2692
2693
    /**
2694
     * @param $linkText
2695
     * @param $configuration
2696
     * @param $expectedResult
2697
     * @dataProvider typoLinkProperlyEncodesLinkResultDataProvider
2698
     * @test
2699
     */
2700
    public function typoLinkProperlyEncodesLinkResult($linkText, $configuration, $expectedResult): void
2701
    {
2702
        $packageManagerMock = $this->getMockBuilder(PackageManager::class)
2703
            ->disableOriginalConstructor()
2704
            ->getMock();
2705
        $templateServiceObjectMock = $this->getMockBuilder(TemplateService::class)
2706
            ->setConstructorArgs([null, $packageManagerMock])
2707
            ->addMethods(['dummy'])
2708
            ->getMock();
2709
        $templateServiceObjectMock->setup = [
0 ignored issues
show
Bug introduced by
Accessing setup on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2710
            'lib.' => [
2711
                'parseFunc.' => $this->getLibParseFunc(),
2712
            ],
2713
        ];
2714
        $typoScriptFrontendControllerMockObject = $this->createMock(TypoScriptFrontendController::class);
2715
        $typoScriptFrontendControllerMockObject->config = [
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2716
            'config' => [],
2717
        ];
2718
        $typoScriptFrontendControllerMockObject->tmpl = $templateServiceObjectMock;
0 ignored issues
show
Bug introduced by
Accessing tmpl on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
2719
        $GLOBALS['TSFE'] = $typoScriptFrontendControllerMockObject;
2720
2721
        $resourceFactory = $this->prophesize(ResourceFactory::class);
2722
        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
2723
2724
        $this->cacheManager->getCache('runtime')->willReturn(new NullFrontend('dummy'));
2725
        $this->cacheManager->getCache('core')->willReturn(new NullFrontend('runtime'));
2726
2727
        GeneralUtility::setSingletonInstance(
2728
            SiteConfiguration::class,
2729
            new SiteConfiguration(Environment::getConfigPath() . '/sites', new NullFrontend('dummy'))
2730
        );
2731
2732
        $this->subject->_set('typoScriptFrontendController', $typoScriptFrontendControllerMockObject);
2733
2734
        self::assertEquals($expectedResult, (string)$this->subject->typoLink($linkText, $configuration));
2735
    }
2736
2737
    /**
2738
     * @return array
2739
     */
2740
    public function typoLinkProperlyEncodesLinkResultDataProvider(): array
2741
    {
2742
        return [
2743
            'Link to file' => [
2744
                'My file',
2745
                [
2746
                    'directImageLink' => false,
2747
                    'parameter' => '/fileadmin/foo.bar',
2748
                    'returnLast' => 'result',
2749
                ],
2750
                json_encode([
2751
                    'href' => '/fileadmin/foo.bar',
2752
                    'target' => null,
2753
                    'class' => null,
2754
                    'title' => null,
2755
                    'linkText' => 'My file',
2756
                    'additionalAttributes' => [],
2757
                ]),
2758
            ],
2759
            'Link example' => [
2760
                'My example',
2761
                [
2762
                    'directImageLink' => false,
2763
                    'parameter' => 'https://example.tld',
2764
                    'returnLast' => 'result',
2765
                ],
2766
                json_encode([
2767
                    'href' => 'https://example.tld',
2768
                    'target' => null,
2769
                    'class' => null,
2770
                    'title' => null,
2771
                    'linkText' => 'My example',
2772
                    'additionalAttributes' => [],
2773
                ]),
2774
            ],
2775
            'Link to file with attributes' => [
2776
                'My file',
2777
                [
2778
                    'parameter' => '/fileadmin/foo.bar',
2779
                    'fileTarget' => '_blank',
2780
                    'returnLast' => 'result',
2781
                ],
2782
                json_encode([
2783
                    'href' => '/fileadmin/foo.bar',
2784
                    'target' => '_blank',
2785
                    'class' => null,
2786
                    'title' => null,
2787
                    'linkText' => 'My file',
2788
                    'additionalAttributes' => [],
2789
                ]),
2790
            ],
2791
            'Link parsing' => [
2792
                'Url',
2793
                [
2794
                    'parameter' => 'https://example.com _blank css-class "test title"',
2795
                    'returnLast' => 'result',
2796
                ],
2797
                json_encode([
2798
                    'href' => 'https://example.com',
2799
                    'target' => '_blank',
2800
                    'class' => 'css-class',
2801
                    'title' => 'test title',
2802
                    'linkText' => 'Url',
2803
                    'additionalAttributes' => ['rel' => 'noreferrer'],
2804
                ]),
2805
            ],
2806
        ];
2807
    }
2808
2809
    /**
2810
     * @test
2811
     */
2812
    public function stdWrap_splitObjReturnsCount(): void
2813
    {
2814
        $conf = [
2815
            'token' => ',',
2816
            'returnCount' => 1,
2817
        ];
2818
        $expectedResult = 5;
2819
        $amountOfEntries = $this->subject->splitObj('1, 2, 3, 4, 5', $conf);
2820
        self::assertSame(
2821
            $expectedResult,
2822
            $amountOfEntries
2823
        );
2824
    }
2825
2826
    /**
2827
     * Check if calculateCacheKey works properly.
2828
     *
2829
     * @return array Order: expect, conf, times, with, withWrap, will
2830
     */
2831
    public function calculateCacheKeyDataProvider(): array
2832
    {
2833
        $value = StringUtility::getUniqueId('value');
2834
        $wrap = [StringUtility::getUniqueId('wrap')];
2835
        $valueConf = ['key' => $value];
2836
        $wrapConf = ['key.' => $wrap];
2837
        $conf = array_merge($valueConf, $wrapConf);
2838
        $will = StringUtility::getUniqueId('stdWrap');
2839
2840
        return [
2841
            'no conf' => [
2842
                '',
2843
                [],
2844
                0,
2845
                null,
2846
                null,
2847
                null,
2848
            ],
2849
            'value conf only' => [
2850
                $value,
2851
                $valueConf,
2852
                0,
2853
                null,
2854
                null,
2855
                null,
2856
            ],
2857
            'wrap conf only' => [
2858
                $will,
2859
                $wrapConf,
2860
                1,
2861
                '',
2862
                $wrap,
2863
                $will,
2864
            ],
2865
            'full conf' => [
2866
                $will,
2867
                $conf,
2868
                1,
2869
                $value,
2870
                $wrap,
2871
                $will,
2872
            ],
2873
        ];
2874
    }
2875
2876
    /**
2877
     * Check if calculateCacheKey works properly.
2878
     *
2879
     * - takes key from $conf['key']
2880
     * - processes key with stdWrap based on $conf['key.']
2881
     *
2882
     * @test
2883
     * @dataProvider calculateCacheKeyDataProvider
2884
     * @param string $expect Expected result.
2885
     * @param array $conf Properties 'key', 'key.'
2886
     * @param int $times Times called mocked method.
2887
     * @param string|null $with Parameter passed to mocked method.
2888
     * @param array|null $withWrap
2889
     * @param string|null $will Return value of mocked method.
2890
     */
2891
    public function calculateCacheKey(string $expect, array $conf, int $times, ?string $with, ?array $withWrap, ?string $will): void
2892
    {
2893
        $subject = $this->getAccessibleMock(ContentObjectRenderer::class, ['stdWrap']);
2894
        $subject->expects(self::exactly($times))
2895
            ->method('stdWrap')
2896
            ->with($with, $withWrap)
2897
            ->willReturn($will);
2898
2899
        $result = $subject->_call('calculateCacheKey', $conf);
2900
        self::assertSame($expect, $result);
2901
    }
2902
2903
    /**
2904
     * Data provider for getFromCache
2905
     *
2906
     * @return array Order: expect, conf, cacheKey, times, cached.
2907
     */
2908
    public function getFromCacheDataProvider(): array
2909
    {
2910
        $conf = [StringUtility::getUniqueId('conf')];
2911
        return [
2912
            'empty cache key' => [
2913
                false,
2914
                $conf,
2915
                '',
2916
                0,
2917
                null,
2918
            ],
2919
            'non-empty cache key' => [
2920
                'value',
2921
                $conf,
2922
                'non-empty-key',
2923
                1,
2924
                'value',
2925
            ],
2926
        ];
2927
    }
2928
2929
    /**
2930
     * Check if getFromCache works properly.
2931
     *
2932
     * - CalculateCacheKey is called to calc the cache key.
2933
     * - $conf is passed on as parameter
2934
     * - CacheFrontend is created and called if $cacheKey is not empty.
2935
     * - Else false is returned.
2936
     *
2937
     * @test
2938
     * @dataProvider getFromCacheDataProvider
2939
     * @param string|bool $expect Expected result.
2940
     * @param array $conf Configuration to pass to calculateCacheKey mock.
2941
     * @param string $cacheKey Return from calculateCacheKey mock.
2942
     * @param int $times Times the cache is expected to be called (0 or 1).
2943
     * @param string|null $cached Return from cacheFrontend mock.
2944
     */
2945
    public function getFromCache($expect, array $conf, string $cacheKey, int $times, ?string $cached): void
2946
    {
2947
        $subject = $this->getAccessibleMock(
2948
            ContentObjectRenderer::class,
2949
            ['calculateCacheKey']
2950
        );
2951
        $subject
2952
            ->expects(self::once())
2953
            ->method('calculateCacheKey')
2954
            ->with($conf)
2955
            ->willReturn($cacheKey);
2956
        $cacheFrontend = $this->createMock(CacheFrontendInterface::class);
2957
        $cacheFrontend
2958
            ->expects(self::exactly($times))
2959
            ->method('get')
2960
            ->with($cacheKey)
2961
            ->willReturn($cached);
2962
        $cacheManager = $this->createMock(CacheManager::class);
2963
        $cacheManager
2964
            ->method('getCache')
2965
            ->willReturn($cacheFrontend);
2966
        GeneralUtility::setSingletonInstance(
2967
            CacheManager::class,
2968
            $cacheManager
2969
        );
2970
        self::assertSame($expect, $subject->_call('getFromCache', $conf));
2971
    }
2972
2973
    /**
2974
     * Data provider for getFieldVal
2975
     *
2976
     * @return array [$expect, $fields]
2977
     */
2978
    public function getFieldValDataProvider(): array
2979
    {
2980
        return [
2981
            'invalid single key' => [null, 'invalid'],
2982
            'single key of null' => [null, 'null'],
2983
            'single key of empty string' => ['', 'empty'],
2984
            'single key of non-empty string' => ['string 1', 'string1'],
2985
            'single key of boolean false' => [false, 'false'],
2986
            'single key of boolean true' => [true, 'true'],
2987
            'single key of integer 0' => [0, 'zero'],
2988
            'single key of integer 1' => [1, 'one'],
2989
            'single key to be trimmed' => ['string 1', ' string1 '],
2990
2991
            'split nothing' => ['', '//'],
2992
            'split one before' => ['string 1', 'string1//'],
2993
            'split one after' => ['string 1', '//string1'],
2994
            'split two ' => ['string 1', 'string1//string2'],
2995
            'split three ' => ['string 1', 'string1//string2//string3'],
2996
            'split to be trimmed' => ['string 1', ' string1 // string2 '],
2997
            '0 is not empty' => [0, '// zero'],
2998
            '1 is not empty' => [1, '// one'],
2999
            'true is not empty' => [true, '// true'],
3000
            'false is empty' => ['', '// false'],
3001
            'null is empty' => ['', '// null'],
3002
            'empty string is empty' => ['', '// empty'],
3003
            'string is not empty' => ['string 1', '// string1'],
3004
            'first non-empty winns' => [0, 'false//empty//null//zero//one'],
3005
            'empty string is fallback' => ['', 'false // empty // null'],
3006
        ];
3007
    }
3008
3009
    /**
3010
     * Check that getFieldVal works properly.
3011
     *
3012
     * Show:
3013
     *
3014
     * - Returns the field from $this->data.
3015
     * - The keys are trimmed.
3016
     *
3017
     * - For a single key (no //) returns the field as is:
3018
     *
3019
     *   - '' => ''
3020
     *   - null => null
3021
     *   - false => false
3022
     *   - true => true
3023
     *   -  0 => 0
3024
     *   -  1 => 1
3025
     *   - 'string' => 'string'
3026
     *
3027
     * - If '//' is present, explodes key candidates.
3028
     * - Returns the first field, that is not "empty".
3029
     * - "Empty" is checked after type cast to string by comparing to ''.
3030
     * - The winning non-empty value is returned as is.
3031
     * - The fallback, if all evals to empty, is the empty string ''.
3032
     * - '//' with single elements and empty string fallback results in:
3033
     *
3034
     *   - '' => ''
3035
     *   - null => ''
3036
     *   - false => ''
3037
     *   - true => true
3038
     *   -  0 => 0
3039
     *   -  1 => 1
3040
     *   - 'string' => 'string'
3041
     *
3042
     * @test
3043
     * @dataProvider getFieldValDataProvider
3044
     * @param mixed $expect The expected string.
3045
     * @param string $fields Field names divides by //.
3046
     */
3047
    public function getFieldVal($expect, string $fields): void
3048
    {
3049
        $data = [
3050
            'string1' => 'string 1',
3051
            'string2' => 'string 2',
3052
            'string3' => 'string 3',
3053
            'empty' => '',
3054
            'null' => null,
3055
            'false' => false,
3056
            'true' => true,
3057
            'zero' => 0,
3058
            'one' => 1,
3059
        ];
3060
        $this->subject->_set('data', $data);
3061
        self::assertSame($expect, $this->subject->getFieldVal($fields));
3062
    }
3063
3064
    /**
3065
     * Data provider for caseshift.
3066
     *
3067
     * @return array [$expect, $content, $case]
3068
     */
3069
    public function caseshiftDataProvider(): array
3070
    {
3071
        return [
3072
            'lower' => ['x y', 'X Y', 'lower'],
3073
            'upper' => ['X Y', 'x y', 'upper'],
3074
            'capitalize' => ['One Two', 'one two', 'capitalize'],
3075
            'ucfirst' => ['One two', 'one two', 'ucfirst'],
3076
            'lcfirst' => ['oNE TWO', 'ONE TWO', 'lcfirst'],
3077
            'uppercamelcase' => ['CamelCase', 'camel_case', 'uppercamelcase'],
3078
            'lowercamelcase' => ['camelCase', 'camel_case', 'lowercamelcase'],
3079
        ];
3080
    }
3081
3082
    /**
3083
     * Check if caseshift works properly.
3084
     *
3085
     * @test
3086
     * @dataProvider caseshiftDataProvider
3087
     * @param string $expect The expected output.
3088
     * @param string $content The given input.
3089
     * @param string $case The given type of conversion.
3090
     */
3091
    public function caseshift(string $expect, string $content, string $case): void
3092
    {
3093
        self::assertSame(
3094
            $expect,
3095
            $this->subject->caseshift($content, $case)
3096
        );
3097
    }
3098
3099
    /**
3100
     * Data provider for HTMLcaseshift.
3101
     *
3102
     * @return array [$expect, $content, $case, $with, $will]
3103
     */
3104
    public function HTMLcaseshiftDataProvider(): array
3105
    {
3106
        $case = StringUtility::getUniqueId('case');
3107
        return [
3108
            'simple text' => [
3109
                'TEXT',
3110
                'text',
3111
                $case,
3112
                [['text', $case]],
3113
                ['TEXT'],
3114
            ],
3115
            'simple tag' => [
3116
                '<i>TEXT</i>',
3117
                '<i>text</i>',
3118
                $case,
3119
                [['', $case], ['text', $case]],
3120
                ['', 'TEXT'],
3121
            ],
3122
            'multiple nested tags with classes' => [
3123
                '<div class="typo3">'
3124
                . '<p>A <b>BOLD<\b> WORD.</p>'
3125
                . '<p>AN <i>ITALIC<\i> WORD.</p>'
3126
                . '</div>',
3127
                '<div class="typo3">'
3128
                . '<p>A <b>bold<\b> word.</p>'
3129
                . '<p>An <i>italic<\i> word.</p>'
3130
                . '</div>',
3131
                $case,
3132
                [
3133
                    ['', $case],
3134
                    ['', $case],
3135
                    ['A ', $case],
3136
                    ['bold', $case],
3137
                    [' word.', $case],
3138
                    ['', $case],
3139
                    ['An ', $case],
3140
                    ['italic', $case],
3141
                    [' word.', $case],
3142
                    ['', $case],
3143
                ],
3144
                ['', '', 'A ', 'BOLD', ' WORD.', '', 'AN ', 'ITALIC', ' WORD.', ''],
3145
            ],
3146
        ];
3147
    }
3148
3149
    /**
3150
     * Check if HTMLcaseshift works properly.
3151
     *
3152
     * Show:
3153
     *
3154
     * - Only shifts the case of characters not part of tags.
3155
     * - Delegates to the method caseshift.
3156
     *
3157
     * @test
3158
     * @dataProvider HTMLcaseshiftDataProvider
3159
     * @param string $expect The expected output.
3160
     * @param string $content The given input.
3161
     * @param string $case The given type of conversion.
3162
     * @param array $with Consecutive args expected by caseshift.
3163
     * @param array $will Consecutive return values of caseshfit.
3164
     */
3165
    public function HTMLcaseshift(string $expect, string $content, string $case, array $with, array $will): void
3166
    {
3167
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3168
            ->onlyMethods(['caseshift'])->getMock();
3169
        $subject
3170
            ->expects(self::exactly(count($with)))
3171
            ->method('caseshift')
3172
            ->withConsecutive(...$with)
3173
            ->will(self::onConsecutiveCalls(...$will));
3174
        self::assertSame(
3175
            $expect,
3176
            $subject->HTMLcaseshift($content, $case)
3177
        );
3178
    }
3179
3180
    /***************************************************************************
3181
     * General tests for stdWrap_
3182
     ***************************************************************************/
3183
3184
    /**
3185
     * Check that all registered stdWrap processors are callable.
3186
     *
3187
     * Show:
3188
     *
3189
     * - The given invalidProcessor is counted as not callable.
3190
     * - All stdWrap processors are counted as callable.
3191
     * - Their amount is 91.
3192
     *
3193
     * @test
3194
     */
3195
    public function allStdWrapProcessorsAreCallable(): void
3196
    {
3197
        $callable = 0;
3198
        $notCallable = 0;
3199
        $processors = ['invalidProcessor'];
3200
        foreach (array_keys($this->subject->_get('stdWrapOrder')) as $key) {
3201
            $processors[] = strtr($key, ['.' => '']);
3202
        }
3203
        foreach (array_unique($processors) as $processor) {
3204
            $method = [$this->subject, 'stdWrap_' . $processor];
3205
            if (is_callable($method)) {
3206
                ++$callable;
3207
            } else {
3208
                ++$notCallable;
3209
            }
3210
        }
3211
        self::assertSame(1, $notCallable);
3212
        self::assertSame(83, $callable);
3213
    }
3214
3215
    /**
3216
     * Check which stdWrap functions are callable with empty parameters.
3217
     *
3218
     * Show:
3219
     *
3220
     * - Almost all stdWrap_[type] are callable if called with 2 parameters:
3221
     *   - string $content Empty string.
3222
     *   - array $conf ['type' => '', 'type.' => []].
3223
     * - Exceptions: stdWrap_numRows, stdWrap_split
3224
     * - The overall count is 91.
3225
     *
3226
     *  Note:
3227
     *
3228
     *  The two exceptions break, if the configuration is empty. This test just
3229
     *  tracks the different behaviour to gain information. It doesn't mean
3230
     *  that it is an issue.
3231
     *
3232
     * @test
3233
     */
3234
    public function notAllStdWrapProcessorsAreCallableWithEmptyConfiguration(): void
3235
    {
3236
        $timeTrackerProphecy = $this->prophesize(TimeTracker::class);
3237
        GeneralUtility::setSingletonInstance(TimeTracker::class, $timeTrackerProphecy->reveal());
3238
3239
        // `parseFunc` issues deprecation in case `htmlSanitize` is not given
3240
        $expectExceptions = ['numRows', 'parseFunc', 'split', 'bytes'];
3241
        $count = 0;
3242
        $processors = [];
3243
        $exceptions = [];
3244
        foreach (array_keys($this->subject->_get('stdWrapOrder')) as $key) {
3245
            $processors[] = strtr($key, ['.' => '']);
3246
        }
3247
        foreach (array_unique($processors) as $processor) {
3248
            ++$count;
3249
            try {
3250
                $conf = [$processor => '', $processor . '.' => ['table' => 'tt_content']];
3251
                $method = 'stdWrap_' . $processor;
3252
                $this->subject->$method('', $conf);
3253
            } catch (\Exception $e) {
3254
                $exceptions[] = $processor;
3255
            }
3256
        }
3257
        self::assertSame($expectExceptions, $exceptions);
3258
        self::assertSame(83, $count);
3259
    }
3260
3261
    /***************************************************************************
3262
     * End general tests for stdWrap_
3263
     ***************************************************************************/
3264
3265
    /***************************************************************************
3266
     * Tests for stdWrap_ in alphabetical order (all uppercase before lowercase)
3267
     ***************************************************************************/
3268
3269
    /**
3270
     * Data provider for fourTypesOfStdWrapHookObjectProcessors
3271
     *
3272
     * @return array Order: stdWrap, hookObjectCall
3273
     */
3274
    public function fourTypesOfStdWrapHookObjectProcessorsDataProvider(): array
3275
    {
3276
        return [
3277
            'preProcess' => [
3278
                'stdWrap_stdWrapPreProcess',
3279
                'stdWrapPreProcess',
3280
            ],
3281
            'override' => [
3282
                'stdWrap_stdWrapOverride',
3283
                'stdWrapOverride',
3284
            ],
3285
            'process' => [
3286
                'stdWrap_stdWrapProcess',
3287
                'stdWrapProcess',
3288
            ],
3289
            'postProcess' => [
3290
                'stdWrap_stdWrapPostProcess',
3291
                'stdWrapPostProcess',
3292
            ],
3293
        ];
3294
    }
3295
3296
    /**
3297
     * Check if stdWrapHookObject processors work properly.
3298
     *
3299
     * Checks:
3300
     *
3301
     * - stdWrap_stdWrapPreProcess
3302
     * - stdWrap_stdWrapOverride
3303
     * - stdWrap_stdWrapProcess
3304
     * - stdWrap_stdWrapPostProcess
3305
     *
3306
     * @test
3307
     * @dataProvider fourTypesOfStdWrapHookObjectProcessorsDataProvider
3308
     * @param string $stdWrapMethod : The method to cover.
3309
     * @param string $hookObjectCall : The expected hook object call.
3310
     */
3311
    public function fourTypesOfStdWrapHookObjectProcessors(
3312
        string $stdWrapMethod,
3313
        string $hookObjectCall
3314
    ): void {
3315
        $conf = [StringUtility::getUniqueId('conf')];
3316
        $content = StringUtility::getUniqueId('content');
3317
        $processed1 = StringUtility::getUniqueId('processed1');
3318
        $processed2 = StringUtility::getUniqueId('processed2');
3319
        $hookObject1 = $this->createMock(
3320
            ContentObjectStdWrapHookInterface::class
3321
        );
3322
        $hookObject1->expects(self::once())
3323
            ->method($hookObjectCall)
3324
            ->with($content, $conf)
3325
            ->willReturn($processed1);
3326
        $hookObject2 = $this->createMock(
3327
            ContentObjectStdWrapHookInterface::class
3328
        );
3329
        $hookObject2->expects(self::once())
3330
            ->method($hookObjectCall)
3331
            ->with($processed1, $conf)
3332
            ->willReturn($processed2);
3333
        $this->subject->_set(
3334
            'stdWrapHookObjects',
3335
            [$hookObject1, $hookObject2]
3336
        );
3337
        $result = $this->subject->$stdWrapMethod($content, $conf);
3338
        self::assertSame($processed2, $result);
3339
    }
3340
3341
    /**
3342
     * Data provider for stdWrap_HTMLparser
3343
     *
3344
     * @return array [$expect, $content, $conf, $times, $will].
3345
     */
3346
    public function stdWrap_HTMLparserDataProvider(): array
3347
    {
3348
        $content = StringUtility::getUniqueId('content');
3349
        $parsed = StringUtility::getUniqueId('parsed');
3350
        return [
3351
            'no config' => [
3352
                $content,
3353
                $content,
3354
                [],
3355
                0,
3356
                $parsed,
3357
            ],
3358
            'no array' => [
3359
                $content,
3360
                $content,
3361
                ['HTMLparser.' => 1],
3362
                0,
3363
                $parsed,
3364
            ],
3365
            'empty array' => [
3366
                $parsed,
3367
                $content,
3368
                ['HTMLparser.' => []],
3369
                1,
3370
                $parsed,
3371
            ],
3372
            'non-empty array' => [
3373
                $parsed,
3374
                $content,
3375
                ['HTMLparser.' => [true]],
3376
                1,
3377
                $parsed,
3378
            ],
3379
        ];
3380
    }
3381
3382
    /**
3383
     * Check if stdWrap_HTMLparser works properly
3384
     *
3385
     * Show:
3386
     *
3387
     * - Checks if $conf['HTMLparser.'] is an array.
3388
     * - No:
3389
     *   - Returns $content as is.
3390
     * - Yes:
3391
     *   - Delegates to method HTMLparser_TSbridge.
3392
     *   - Parameter 1 is $content.
3393
     *   - Parameter 2 is $conf['HTMLparser'].
3394
     *   - Returns the return value.
3395
     *
3396
     * @test
3397
     * @dataProvider stdWrap_HTMLparserDataProvider
3398
     * @param string $expect The expected output.
3399
     * @param string $content The given content.
3400
     * @param array $conf The given configuration.
3401
     * @param int $times Times HTMLparser_TSbridge is called (0 or 1).
3402
     * @param string $will Return of HTMLparser_TSbridge.
3403
     */
3404
    public function stdWrap_HTMLparser(
3405
        string $expect,
3406
        string $content,
3407
        array $conf,
3408
        int $times,
3409
        string $will
3410
    ): void {
3411
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3412
            ->onlyMethods(['HTMLparser_TSbridge'])->getMock();
3413
        $subject
3414
            ->expects(self::exactly($times))
3415
            ->method('HTMLparser_TSbridge')
3416
            ->with($content, $conf['HTMLparser.'] ?? [])
3417
            ->willReturn($will);
3418
        self::assertSame(
3419
            $expect,
3420
            $subject->stdWrap_HTMLparser($content, $conf)
3421
        );
3422
    }
3423
3424
    /**
3425
     * @return array
3426
     */
3427
    public function stdWrap_addPageCacheTagsAddsPageTagsDataProvider(): array
3428
    {
3429
        return [
3430
            'No Tag' => [
3431
                [],
3432
                ['addPageCacheTags' => ''],
3433
            ],
3434
            'Two expectedTags' => [
3435
                ['tag1', 'tag2'],
3436
                ['addPageCacheTags' => 'tag1,tag2'],
3437
            ],
3438
            'Two expectedTags plus one with stdWrap' => [
3439
                ['tag1', 'tag2', 'tag3'],
3440
                [
3441
                    'addPageCacheTags' => 'tag1,tag2',
3442
                    'addPageCacheTags.' => ['wrap' => '|,tag3'],
3443
                ],
3444
            ],
3445
        ];
3446
    }
3447
3448
    /**
3449
     * @param array $expectedTags
3450
     * @param array $configuration
3451
     * @test
3452
     * @dataProvider stdWrap_addPageCacheTagsAddsPageTagsDataProvider
3453
     */
3454
    public function stdWrap_addPageCacheTagsAddsPageTags(array $expectedTags, array $configuration): void
3455
    {
3456
        $this->subject->stdWrap_addPageCacheTags('', $configuration);
3457
        self::assertEquals($expectedTags, $this->frontendControllerMock->_get('pageCacheTags'));
3458
    }
3459
3460
    /**
3461
     * Check if stdWrap_age works properly.
3462
     *
3463
     * Show:
3464
     *
3465
     * - Delegates to calcAge.
3466
     * - Parameter 1 is the difference between $content and EXEC_TIME.
3467
     * - Parameter 2 is $conf['age'].
3468
     * - Returns the return value.
3469
     *
3470
     * @test
3471
     */
3472
    public function stdWrap_age(): void
3473
    {
3474
        $now = 10;
3475
        $content = '9';
3476
        $conf = ['age' => StringUtility::getUniqueId('age')];
3477
        $return = StringUtility::getUniqueId('return');
3478
        $difference = $now - (int)$content;
3479
        $GLOBALS['EXEC_TIME'] = $now;
3480
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3481
            ->onlyMethods(['calcAge'])->getMock();
3482
        $subject
3483
            ->expects(self::once())
3484
            ->method('calcAge')
3485
            ->with($difference, $conf['age'])
3486
            ->willReturn($return);
3487
        self::assertSame($return, $subject->stdWrap_age($content, $conf));
3488
    }
3489
3490
    /**
3491
     * Check if stdWrap_append works properly.
3492
     *
3493
     * Show:
3494
     *
3495
     * - Delegates to the method cObjGetSingle().
3496
     * - First parameter is $conf['append'].
3497
     * - Second parameter is $conf['append.'].
3498
     * - Third parameter is '/stdWrap/.append'.
3499
     * - Returns the return value appended to $content.
3500
     *
3501
     * @test
3502
     */
3503
    public function stdWrap_append(): void
3504
    {
3505
        $debugKey = '/stdWrap/.append';
3506
        $content = StringUtility::getUniqueId('content');
3507
        $conf = [
3508
            'append' => StringUtility::getUniqueId('append'),
3509
            'append.' => [StringUtility::getUniqueId('append.')],
3510
        ];
3511
        $return = StringUtility::getUniqueId('return');
3512
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3513
            ->onlyMethods(['cObjGetSingle'])->getMock();
3514
        $subject
3515
            ->expects(self::once())
3516
            ->method('cObjGetSingle')
3517
            ->with($conf['append'], $conf['append.'], $debugKey)
3518
            ->willReturn($return);
3519
        self::assertSame(
3520
            $content . $return,
3521
            $subject->stdWrap_append($content, $conf)
3522
        );
3523
    }
3524
3525
    /**
3526
     * Data provider for stdWrap_br
3527
     *
3528
     * @return string[][] Order expected, given, xhtmlDoctype
3529
     */
3530
    public function stdWrapBrDataProvider(): array
3531
    {
3532
        return [
3533
            'no xhtml with LF in between' => [
3534
                'one<br>' . LF . 'two',
3535
                'one' . LF . 'two',
3536
                null,
3537
            ],
3538
            'no xhtml with LF in between and around' => [
3539
                '<br>' . LF . 'one<br>' . LF . 'two<br>' . LF,
3540
                LF . 'one' . LF . 'two' . LF,
3541
                null,
3542
            ],
3543
            'xhtml with LF in between' => [
3544
                'one<br />' . LF . 'two',
3545
                'one' . LF . 'two',
3546
                'xhtml_strict',
3547
            ],
3548
            'xhtml with LF in between and around' => [
3549
                '<br />' . LF . 'one<br />' . LF . 'two<br />' . LF,
3550
                LF . 'one' . LF . 'two' . LF,
3551
                'xhtml_strict',
3552
            ],
3553
        ];
3554
    }
3555
3556
    /**
3557
     * Test that stdWrap_br works as expected.
3558
     *
3559
     * @param string $expected The expected value.
3560
     * @param string $input The input value.
3561
     * @param string|null $xhtmlDoctype Xhtml document type.
3562
     * @test
3563
     * @dataProvider stdWrapBrDataProvider
3564
     */
3565
    public function stdWrap_br(string $expected, string $input, ?string $xhtmlDoctype): void
3566
    {
3567
        $GLOBALS['TSFE']->xhtmlDoctype = $xhtmlDoctype;
3568
        self::assertSame($expected, $this->subject->stdWrap_br($input));
3569
    }
3570
3571
    /**
3572
     * Data provider for stdWrap_brTag
3573
     *
3574
     * @return array
3575
     */
3576
    public function stdWrapBrTagDataProvider(): array
3577
    {
3578
        $noConfig = [];
3579
        $config1 = ['brTag' => '<br/>'];
3580
        $config2 = ['brTag' => '<br>'];
3581
        return [
3582
            'no config: one break at the beginning' => [LF . 'one' . LF . 'two', 'onetwo', $noConfig],
3583
            'no config: multiple breaks at the beginning' => [LF . LF . 'one' . LF . 'two', 'onetwo', $noConfig],
3584
            'no config: one break at the end' => ['one' . LF . 'two' . LF, 'onetwo', $noConfig],
3585
            'no config: multiple breaks at the end' => ['one' . LF . 'two' . LF . LF, 'onetwo', $noConfig],
3586
3587
            'config1: one break at the beginning' => [LF . 'one' . LF . 'two', '<br/>one<br/>two', $config1],
3588
            'config1: multiple breaks at the beginning' => [
3589
                LF . LF . 'one' . LF . 'two',
3590
                '<br/><br/>one<br/>two',
3591
                $config1,
3592
            ],
3593
            'config1: one break at the end' => ['one' . LF . 'two' . LF, 'one<br/>two<br/>', $config1],
3594
            'config1: multiple breaks at the end' => ['one' . LF . 'two' . LF . LF, 'one<br/>two<br/><br/>', $config1],
3595
3596
            'config2: one break at the beginning' => [LF . 'one' . LF . 'two', '<br>one<br>two', $config2],
3597
            'config2: multiple breaks at the beginning' => [
3598
                LF . LF . 'one' . LF . 'two',
3599
                '<br><br>one<br>two',
3600
                $config2,
3601
            ],
3602
            'config2: one break at the end' => ['one' . LF . 'two' . LF, 'one<br>two<br>', $config2],
3603
            'config2: multiple breaks at the end' => ['one' . LF . 'two' . LF . LF, 'one<br>two<br><br>', $config2],
3604
        ];
3605
    }
3606
3607
    /**
3608
     * Check if brTag works properly
3609
     *
3610
     * @test
3611
     * @dataProvider stdWrapBrTagDataProvider
3612
     * @param string $input
3613
     * @param string $expected
3614
     * @param array $config
3615
     */
3616
    public function stdWrap_brTag(string $input, string $expected, array $config): void
3617
    {
3618
        self::assertEquals($expected, $this->subject->stdWrap_brTag($input, $config));
3619
    }
3620
3621
    /**
3622
     * Data provider for stdWrap_bytes.
3623
     *
3624
     * @return array [$expect, $content, $conf]
3625
     */
3626
    public function stdWrap_bytesDataProvider(): array
3627
    {
3628
        return [
3629
            'value 1234 default' => [
3630
                '1.21 Ki',
3631
                '1234',
3632
                ['labels' => '', 'base' => 0],
3633
            ],
3634
            'value 1234 si' => [
3635
                '1.23 k',
3636
                '1234',
3637
                ['labels' => 'si', 'base' => 0],
3638
            ],
3639
            'value 1234 iec' => [
3640
                '1.21 Ki',
3641
                '1234',
3642
                ['labels' => 'iec', 'base' => 0],
3643
            ],
3644
            'value 1234 a-i' => [
3645
                '1.23b',
3646
                '1234',
3647
                ['labels' => 'a|b|c|d|e|f|g|h|i', 'base' => 1000],
3648
            ],
3649
            'value 1234 a-i invalid base' => [
3650
                '1.21b',
3651
                '1234',
3652
                ['labels' => 'a|b|c|d|e|f|g|h|i', 'base' => 54],
3653
            ],
3654
            'value 1234567890 default' => [
3655
                '1.15 Gi',
3656
                '1234567890',
3657
                ['labels' => '', 'base' => 0],
3658
            ],
3659
        ];
3660
    }
3661
3662
    /**
3663
     * Check if stdWrap_bytes works properly.
3664
     *
3665
     * Show:
3666
     *
3667
     * - Delegates to GeneralUtility::formatSize
3668
     * - Parameter 1 is $conf['bytes.'][labels'].
3669
     * - Parameter 2 is $conf['bytes.'][base'].
3670
     * - Returns the return value.
3671
     *
3672
     * Note: As PHPUnit can't mock static methods, the call to
3673
     *       GeneralUtility::formatSize can't be easily intercepted. The test
3674
     *       is done by testing input/output pairs instead. To not duplicate
3675
     *       the testing of formatSize just a few smoke tests are done here.
3676
     *
3677
     * @test
3678
     * @dataProvider stdWrap_bytesDataProvider
3679
     * @param string $expect The expected output.
3680
     * @param string $content The given input.
3681
     * @param array $conf The given configuration for 'bytes.'.
3682
     */
3683
    public function stdWrap_bytes(string $expect, string $content, array $conf): void
3684
    {
3685
        $locale = 'en_US.UTF-8';
3686
        try {
3687
            $this->setLocale(LC_NUMERIC, $locale);
3688
        } catch (Exception $e) {
3689
            self::markTestSkipped('Locale ' . $locale . ' is not available.');
3690
        }
3691
        $conf = ['bytes.' => $conf];
3692
        self::assertSame(
3693
            $expect,
3694
            $this->subject->stdWrap_bytes($content, $conf)
3695
        );
3696
    }
3697
3698
    /**
3699
     * Check if stdWrap_cObject works properly.
3700
     *
3701
     * Show:
3702
     *
3703
     * - Delegates to the method cObjGetSingle().
3704
     * - Parameter 1 is $conf['cObject'].
3705
     * - Parameter 2 is $conf['cObject.'].
3706
     * - Parameter 3 is '/stdWrap/.cObject'.
3707
     * - Returns the return value.
3708
     *
3709
     * @test
3710
     */
3711
    public function stdWrap_cObject(): void
3712
    {
3713
        $debugKey = '/stdWrap/.cObject';
3714
        $content = StringUtility::getUniqueId('content');
3715
        $conf = [
3716
            'cObject' => StringUtility::getUniqueId('cObject'),
3717
            'cObject.' => [StringUtility::getUniqueId('cObject.')],
3718
        ];
3719
        $return = StringUtility::getUniqueId('return');
3720
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3721
            ->onlyMethods(['cObjGetSingle'])->getMock();
3722
        $subject
3723
            ->expects(self::once())
3724
            ->method('cObjGetSingle')
3725
            ->with($conf['cObject'], $conf['cObject.'], $debugKey)
3726
            ->willReturn($return);
3727
        self::assertSame(
3728
            $return,
3729
            $subject->stdWrap_cObject($content, $conf)
3730
        );
3731
    }
3732
3733
    /**
3734
     * Data provider for stdWrap_orderedStdWrap.
3735
     *
3736
     * @return array [$firstConf, $secondConf, $conf]
3737
     */
3738
    public function stdWrap_orderedStdWrapDataProvider(): array
3739
    {
3740
        $confA = [StringUtility::getUniqueId('conf A')];
3741
        $confB = [StringUtility::getUniqueId('conf B')];
3742
        return [
3743
            'standard case: order 1, 2' => [
3744
                $confA,
3745
                $confB,
3746
                ['1.' => $confA, '2.' => $confB],
3747
            ],
3748
            'inverted: order 2, 1' => [
3749
                $confB,
3750
                $confA,
3751
                ['2.' => $confA, '1.' => $confB],
3752
            ],
3753
            '0 as integer: order 0, 2' => [
3754
                $confA,
3755
                $confB,
3756
                ['0.' => $confA, '2.' => $confB],
3757
            ],
3758
            'negative integers: order 2, -2' => [
3759
                $confB,
3760
                $confA,
3761
                ['2.' => $confA, '-2.' => $confB],
3762
            ],
3763
            'chars are casted to key 0, that is not in the array' => [
3764
                null,
3765
                $confB,
3766
                ['2.' => $confB, 'xxx.' => $confA],
3767
            ],
3768
        ];
3769
    }
3770
3771
    /**
3772
     * Check if stdWrap_orderedStdWrap works properly.
3773
     *
3774
     * Show:
3775
     *
3776
     * - For each entry of $conf['orderedStdWrap.'] stdWrap is applied
3777
     *   to $content.
3778
     * - The order is defined by the keys, after they have been casted
3779
     *   to integers.
3780
     * - Returns the processed $content after all entries have been applied.
3781
     *
3782
     * Each test calls stdWrap two times. First $content is processed to
3783
     * $between, second $between is processed to $expect, the final return
3784
     * value. It is checked, if the expected parameters are given in the right
3785
     * consecutive order to stdWrap.
3786
     *
3787
     * @test
3788
     * @dataProvider stdWrap_orderedStdWrapDataProvider
3789
     * @param array|null $firstConf Parameter 2 expected by first call to stdWrap.
3790
     * @param array $secondConf Parameter 2 expected by second call to stdWrap.
3791
     * @param array $conf The given configuration.
3792
     */
3793
    public function stdWrap_orderedStdWrap(?array $firstConf, array $secondConf, array $conf): void
3794
    {
3795
        $content = StringUtility::getUniqueId('content');
3796
        $between = StringUtility::getUniqueId('between');
3797
        $expect = StringUtility::getUniqueId('expect');
3798
        $conf['orderedStdWrap.'] = $conf;
3799
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
3800
            ->onlyMethods(['stdWrap'])->getMock();
3801
        $subject
3802
            ->expects(self::exactly(2))
3803
            ->method('stdWrap')
3804
            ->withConsecutive([$content, $firstConf], [$between, $secondConf])
3805
            ->will(self::onConsecutiveCalls($between, $expect));
3806
        self::assertSame(
3807
            $expect,
3808
            $subject->stdWrap_orderedStdWrap($content, $conf)
3809
        );
3810
    }
3811
3812
    /**
3813
     * Data provider for stdWrap_cacheRead
3814
     *
3815
     * @return array Order: expect, input, conf, times, with, will
3816
     */
3817
    public function stdWrap_cacheReadDataProvider(): array
3818
    {
3819
        $cacheConf = [StringUtility::getUniqueId('cache.')];
3820
        $conf = ['cache.' => $cacheConf];
3821
        return [
3822
            'no conf' => [
3823
                'content',
3824
                'content',
3825
                [],
3826
                0,
3827
                null,
3828
                null,
3829
            ],
3830
            'no cache. conf' => [
3831
                'content',
3832
                'content',
3833
                ['otherConf' => 1],
3834
                0,
3835
                null,
3836
                null,
3837
            ],
3838
            'non-cached simulation' => [
3839
                'content',
3840
                'content',
3841
                $conf,
3842
                1,
3843
                $cacheConf,
3844
                false,
3845
            ],
3846
            'cached simulation' => [
3847
                'cachedContent',
3848
                'content',
3849
                $conf,
3850
                1,
3851
                $cacheConf,
3852
                'cachedContent',
3853
            ],
3854
        ];
3855
    }
3856
3857
    /**
3858
     * Check if stdWrap_cacheRead works properly.
3859
     *
3860
     * - the method branches correctly
3861
     * - getFromCache is called to fetch from cache
3862
     * - $conf['cache.'] is passed on as parameter
3863
     *
3864
     * @test
3865
     * @dataProvider stdWrap_cacheReadDataProvider
3866
     * @param string $expect Expected result.
3867
     * @param string $input Given input string.
3868
     * @param array $conf Property 'cache.'
3869
     * @param int $times Times called mocked method.
3870
     * @param array|null $with Parameter passed to mocked method.
3871
     * @param string|false $will Return value of mocked method.
3872
     */
3873
    public function stdWrap_cacheRead(
3874
        string $expect,
3875
        string $input,
3876
        array $conf,
3877
        int $times,
3878
        ?array $with,
3879
        $will
3880
    ): void {
3881
        $subject = $this->getAccessibleMock(
3882
            ContentObjectRenderer::class,
3883
            ['getFromCache']
3884
        );
3885
        $subject
3886
            ->expects(self::exactly($times))
3887
            ->method('getFromCache')
3888
            ->with($with)
3889
            ->willReturn($will);
3890
        self::assertSame(
3891
            $expect,
3892
            $subject->stdWrap_cacheRead($input, $conf)
3893
        );
3894
    }
3895
3896
    /**
3897
     * Data provider for stdWrap_cacheStore.
3898
     *
3899
     * @return array [$confCache, $timesCCK, $key, $times]
3900
     */
3901
    public function stdWrap_cacheStoreDataProvider(): array
3902
    {
3903
        $confCache = [StringUtility::getUniqueId('cache.')];
3904
        $key = [StringUtility::getUniqueId('key')];
3905
        return [
3906
            'Return immediate with no conf' => [
3907
                null,
3908
                0,
3909
                null,
3910
                0,
3911
            ],
3912
            'Return immediate with empty key' => [
3913
                $confCache,
3914
                1,
3915
                '0',
3916
                0,
3917
            ],
3918
            'Call all methods' => [
3919
                $confCache,
3920
                1,
3921
                $key,
3922
                1,
3923
            ],
3924
        ];
3925
    }
3926
3927
    /**
3928
     * Check if stdWrap_cacheStore works properly.
3929
     *
3930
     * Show:
3931
     *
3932
     * - Returns $content as is.
3933
     * - Returns immediate if $conf['cache.'] is not set.
3934
     * - Returns immediate if calculateCacheKey returns an empty value.
3935
     * - Calls calculateCacheKey with $conf['cache.'].
3936
     * - Calls calculateCacheTags with $conf['cache.'].
3937
     * - Calls calculateCacheLifetime with $conf['cache.'].
3938
     * - Calls all configured user functions with $params, $this.
3939
     * - Calls set on the cache frontend with $key, $content, $tags, $lifetime.
3940
     *
3941
     * @test
3942
     * @dataProvider stdWrap_cacheStoreDataProvider
3943
     * @param array|null $confCache Configuration of 'cache.'
3944
     * @param int $timesCCK Times calculateCacheKey is called.
3945
     * @param mixed $key The return value of calculateCacheKey.
3946
     * @param int $times Times the other methods are called.
3947
     */
3948
    public function stdWrap_cacheStore(
3949
        ?array $confCache,
3950
        int $timesCCK,
3951
        $key,
3952
        int $times
3953
    ): void {
3954
        $content = StringUtility::getUniqueId('content');
3955
        $conf = [];
3956
        $conf['cache.'] = $confCache;
3957
        $tags = [StringUtility::getUniqueId('tags')];
3958
        $lifetime = StringUtility::getUniqueId('lifetime');
3959
        $params = [
3960
            'key' => $key,
3961
            'content' => $content,
3962
            'lifetime' => $lifetime,
3963
            'tags' => $tags,
3964
        ];
3965
        $subject = $this->getAccessibleMock(
3966
            ContentObjectRenderer::class,
3967
            [
3968
                'calculateCacheKey',
3969
                'calculateCacheTags',
3970
                'calculateCacheLifetime',
3971
            ]
3972
        );
3973
        $subject
3974
            ->expects(self::exactly($timesCCK))
3975
            ->method('calculateCacheKey')
3976
            ->with($confCache)
3977
            ->willReturn($key);
3978
        $subject
3979
            ->expects(self::exactly($times))
3980
            ->method('calculateCacheTags')
3981
            ->with($confCache)
3982
            ->willReturn($tags);
3983
        $subject
3984
            ->expects(self::exactly($times))
3985
            ->method('calculateCacheLifetime')
3986
            ->with($confCache)
3987
            ->willReturn($lifetime);
3988
        $cacheFrontend = $this->createMock(CacheFrontendInterface::class);
3989
        $cacheFrontend
3990
            ->expects(self::exactly($times))
3991
            ->method('set')
3992
            ->with($key, $content, $tags, $lifetime)
3993
            ->willReturn(null);
3994
        $cacheManager = $this->createMock(CacheManager::class);
3995
        $cacheManager
3996
            ->method('getCache')
3997
            ->willReturn($cacheFrontend);
3998
        GeneralUtility::setSingletonInstance(
3999
            CacheManager::class,
4000
            $cacheManager
4001
        );
4002
        [$countCalls, $test] = [0, $this];
4003
        $closure = static function ($par1, $par2) use (
4004
            $test,
4005
            $subject,
4006
            $params,
4007
            &$countCalls
4008
        ) {
4009
            $test->assertSame($params, $par1);
4010
            $test->assertSame($subject, $par2);
4011
            $countCalls++;
4012
        };
4013
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap_cacheStore'] = [
4014
            $closure,
4015
            $closure,
4016
            $closure,
4017
        ];
4018
        self::assertSame(
4019
            $content,
4020
            $subject->stdWrap_cacheStore($content, $conf)
4021
        );
4022
        self::assertSame($times * 3, $countCalls);
4023
    }
4024
4025
    /**
4026
     * Check if stdWrap_case works properly.
4027
     *
4028
     * Show:
4029
     *
4030
     * - Delegates to method HTMLcaseshift.
4031
     * - Parameter 1 is $content.
4032
     * - Parameter 2 is $conf['case'].
4033
     * - Returns the return value.
4034
     *
4035
     * @test
4036
     */
4037
    public function stdWrap_case(): void
4038
    {
4039
        $content = StringUtility::getUniqueId();
4040
        $conf = [
4041
            'case' => StringUtility::getUniqueId('used'),
4042
            'case.' => [StringUtility::getUniqueId('discarded')],
4043
        ];
4044
        $return = StringUtility::getUniqueId();
4045
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4046
            ->onlyMethods(['HTMLcaseshift'])->getMock();
4047
        $subject
4048
            ->expects(self::once())
4049
            ->method('HTMLcaseshift')
4050
            ->with($content, $conf['case'])
4051
            ->willReturn($return);
4052
        self::assertSame(
4053
            $return,
4054
            $subject->stdWrap_case($content, $conf)
4055
        );
4056
    }
4057
4058
    /**
4059
     * Check if stdWrap_char works properly.
4060
     *
4061
     * @test
4062
     */
4063
    public function stdWrap_char(): void
4064
    {
4065
        $input = 'discarded';
4066
        $expected = 'C';
4067
        self::assertEquals($expected, $this->subject->stdWrap_char($input, ['char' => '67']));
4068
    }
4069
4070
    /**
4071
     * Check if stdWrap_crop works properly.
4072
     *
4073
     * Show:
4074
     *
4075
     * - Delegates to method listNum.
4076
     * - Parameter 1 is $content.
4077
     * - Parameter 2 is $conf['crop'].
4078
     * - Returns the return value.
4079
     *
4080
     * @test
4081
     */
4082
    public function stdWrap_crop(): void
4083
    {
4084
        $content = StringUtility::getUniqueId('content');
4085
        $conf = [
4086
            'crop' => StringUtility::getUniqueId('crop'),
4087
            'crop.' => StringUtility::getUniqueId('not used'),
4088
        ];
4089
        $return = StringUtility::getUniqueId('return');
4090
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4091
            ->onlyMethods(['crop'])->getMock();
4092
        $subject
4093
            ->expects(self::once())
4094
            ->method('crop')
4095
            ->with($content, $conf['crop'])
4096
            ->willReturn($return);
4097
        self::assertSame(
4098
            $return,
4099
            $subject->stdWrap_crop($content, $conf)
4100
        );
4101
    }
4102
4103
    /**
4104
     * Check if stdWrap_cropHTML works properly.
4105
     *
4106
     * Show:
4107
     *
4108
     * - Delegates to method cropHTML.
4109
     * - Parameter 1 is $content.
4110
     * - Parameter 2 is $conf['cropHTML'].
4111
     * - Returns the return value.
4112
     *
4113
     * @test
4114
     */
4115
    public function stdWrap_cropHTML(): void
4116
    {
4117
        $content = StringUtility::getUniqueId('content');
4118
        $conf = [
4119
            'cropHTML' => StringUtility::getUniqueId('cropHTML'),
4120
            'cropHTML.' => StringUtility::getUniqueId('not used'),
4121
        ];
4122
        $return = StringUtility::getUniqueId('return');
4123
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4124
            ->onlyMethods(['cropHTML'])->getMock();
4125
        $subject
4126
            ->expects(self::once())
4127
            ->method('cropHTML')
4128
            ->with($content, $conf['cropHTML'])
4129
            ->willReturn($return);
4130
        self::assertSame(
4131
            $return,
4132
            $subject->stdWrap_cropHTML($content, $conf)
4133
        );
4134
    }
4135
4136
    /**
4137
     * Data provider for stdWrap_csConv
4138
     *
4139
     * @return array Order expected, input, conf
4140
     */
4141
    public function stdWrap_csConvDataProvider(): array
4142
    {
4143
        return [
4144
            'empty string from ISO-8859-15' => [
4145
                '',
4146
                mb_convert_encoding('', 'ISO-8859-15', 'UTF-8'),
4147
                ['csConv' => 'ISO-8859-15'],
4148
            ],
4149
            'empty string from BIG-5' => [
4150
                '',
4151
                mb_convert_encoding('', 'BIG-5'),
4152
                ['csConv' => 'BIG-5'],
4153
            ],
4154
            '"0" from ISO-8859-15' => [
4155
                '0',
4156
                mb_convert_encoding('0', 'ISO-8859-15', 'UTF-8'),
4157
                ['csConv' => 'ISO-8859-15'],
4158
            ],
4159
            '"0" from BIG-5' => [
4160
                '0',
4161
                mb_convert_encoding('0', 'BIG-5'),
4162
                ['csConv' => 'BIG-5'],
4163
            ],
4164
            'euro symbol from ISO-88859-15' => [
4165
                '€',
4166
                mb_convert_encoding('€', 'ISO-8859-15', 'UTF-8'),
4167
                ['csConv' => 'ISO-8859-15'],
4168
            ],
4169
            'good morning from BIG-5' => [
4170
                '早安',
4171
                mb_convert_encoding('早安', 'BIG-5'),
4172
                ['csConv' => 'BIG-5'],
4173
            ],
4174
        ];
4175
    }
4176
4177
    /**
4178
     * Check if stdWrap_csConv works properly.
4179
     *
4180
     * @test
4181
     * @dataProvider stdWrap_csConvDataProvider
4182
     * @param string $expected The expected value.
4183
     * @param string $input The input value.
4184
     * @param array $conf Property: csConv
4185
     */
4186
    public function stdWrap_csConv(string $expected, string $input, array $conf): void
4187
    {
4188
        self::assertSame(
4189
            $expected,
4190
            $this->subject->stdWrap_csConv($input, $conf)
4191
        );
4192
    }
4193
4194
    /**
4195
     * Check if stdWrap_current works properly.
4196
     *
4197
     * Show:
4198
     *
4199
     * - current is returned from $this->data
4200
     * - the key is stored in $this->currentValKey
4201
     * - the key defaults to 'currentValue_kidjls9dksoje'
4202
     *
4203
     * @test
4204
     */
4205
    public function stdWrap_current(): void
4206
    {
4207
        $data = [
4208
            'currentValue_kidjls9dksoje' => 'default',
4209
            'currentValue_new' => 'new',
4210
        ];
4211
        $this->subject->_set('data', $data);
4212
        self::assertSame(
4213
            'currentValue_kidjls9dksoje',
4214
            $this->subject->_get('currentValKey')
4215
        );
4216
        self::assertSame(
4217
            'default',
4218
            $this->subject->stdWrap_current('discarded', ['discarded'])
4219
        );
4220
        $this->subject->_set('currentValKey', 'currentValue_new');
4221
        self::assertSame(
4222
            'new',
4223
            $this->subject->stdWrap_current('discarded', ['discarded'])
4224
        );
4225
    }
4226
4227
    /**
4228
     * Data provider for stdWrap_data.
4229
     *
4230
     * @return array [$expect, $data, $alt]
4231
     */
4232
    public function stdWrap_dataDataProvider(): array
4233
    {
4234
        $data = [StringUtility::getUniqueId('data')];
4235
        $alt = [StringUtility::getUniqueId('alternativeData')];
4236
        return [
4237
            'default' => [$data, $data, ''],
4238
            'alt is array' => [$alt, $data, $alt],
4239
            'alt is empty array' => [[], $data, []],
4240
            'alt null' => [$data, $data, null],
4241
            'alt string' => [$data, $data, 'xxx'],
4242
            'alt int' => [$data, $data, 1],
4243
            'alt bool' => [$data, $data, true],
4244
        ];
4245
    }
4246
4247
    /**
4248
     * Checks that stdWrap_data works properly.
4249
     *
4250
     * Show:
4251
     *
4252
     * - Delegates to method getData.
4253
     * - Parameter 1 is $conf['data'].
4254
     * - Parameter 2 is property data by default.
4255
     * - Parameter 2 is property alternativeData, if set as array.
4256
     * - Property alternativeData is always unset to ''.
4257
     * - Returns the return value.
4258
     *
4259
     * @test
4260
     * @dataProvider stdWrap_dataDataProvider
4261
     * @param array $expect Expect either $data or $alternativeData.
4262
     * @param array $data The data.
4263
     * @param mixed $alt The alternativeData.
4264
     */
4265
    public function stdWrap_data(array $expect, array $data, $alt): void
4266
    {
4267
        $conf = ['data' => StringUtility::getUniqueId('conf.data')];
4268
        $return = StringUtility::getUniqueId('return');
4269
        $subject = $this->getAccessibleMock(
4270
            ContentObjectRenderer::class,
4271
            ['getData']
4272
        );
4273
        $subject->_set('data', $data);
4274
        $subject->_set('alternativeData', $alt);
4275
        $subject
4276
            ->expects(self::once())
4277
            ->method('getData')
4278
            ->with($conf['data'], $expect)
4279
            ->willReturn($return);
4280
        self::assertSame($return, $subject->stdWrap_data('discard', $conf));
4281
        self::assertSame('', $subject->_get('alternativeData'));
4282
    }
4283
4284
    /**
4285
     * Check that stdWrap_dataWrap works properly.
4286
     *
4287
     * Show:
4288
     *
4289
     *  - Delegates to method dataWrap.
4290
     *  - Parameter 1 is $content.
4291
     *  - Parameter 2 is $conf['dataWrap'].
4292
     *  - Returns the return value.
4293
     *
4294
     * @test
4295
     */
4296
    public function stdWrap_dataWrap(): void
4297
    {
4298
        $content = StringUtility::getUniqueId('content');
4299
        $conf = [
4300
            'dataWrap' => StringUtility::getUniqueId('dataWrap'),
4301
            'dataWrap.' => [StringUtility::getUniqueId('not used')],
4302
        ];
4303
        $return = StringUtility::getUniqueId('return');
4304
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4305
            ->onlyMethods(['dataWrap'])->getMock();
4306
        $subject
4307
            ->expects(self::once())
4308
            ->method('dataWrap')
4309
            ->with($content, $conf['dataWrap'])
4310
            ->willReturn($return);
4311
        self::assertSame(
4312
            $return,
4313
            $subject->stdWrap_dataWrap($content, $conf)
4314
        );
4315
    }
4316
4317
    /**
4318
     * Data provider for the stdWrap_date test
4319
     *
4320
     * @return array [$expect, $content, $conf, $now]
4321
     */
4322
    public function stdWrap_dateDataProvider(): array
4323
    {
4324
        // Fictive execution time: 2015-10-02 12:00
4325
        $now = 1443780000;
4326
        return [
4327
            'given timestamp' => [
4328
                '02.10.2015',
4329
                $now,
4330
                ['date' => 'd.m.Y'],
4331
                $now,
4332
            ],
4333
            'empty string' => [
4334
                '02.10.2015',
4335
                '',
4336
                ['date' => 'd.m.Y'],
4337
                $now,
4338
            ],
4339
            'testing null' => [
4340
                '02.10.2015',
4341
                null,
4342
                ['date' => 'd.m.Y'],
4343
                $now,
4344
            ],
4345
            'given timestamp return GMT' => [
4346
                '02.10.2015 10:00:00',
4347
                $now,
4348
                [
4349
                    'date' => 'd.m.Y H:i:s',
4350
                    'date.' => ['GMT' => true],
4351
                ],
4352
                $now,
4353
            ],
4354
        ];
4355
    }
4356
4357
    /**
4358
     * Check if stdWrap_date works properly.
4359
     *
4360
     * @test
4361
     * @dataProvider stdWrap_dateDataProvider
4362
     * @param string $expected The expected output.
4363
     * @param mixed $content The given input.
4364
     * @param array $conf The given configuration.
4365
     * @param int $now Fictive execution time.
4366
     */
4367
    public function stdWrap_date(string $expected, $content, array $conf, int $now): void
4368
    {
4369
        $GLOBALS['EXEC_TIME'] = $now;
4370
        self::assertEquals(
4371
            $expected,
4372
            $this->subject->stdWrap_date($content, $conf)
4373
        );
4374
    }
4375
4376
    /**
4377
     * Check if stdWrap_debug works properly.
4378
     *
4379
     * @test
4380
     */
4381
    public function stdWrap_debug(): void
4382
    {
4383
        $expect = '<pre>&lt;p class=&quot;class&quot;&gt;&lt;br/&gt;'
4384
            . '&lt;/p&gt;</pre>';
4385
        $content = '<p class="class"><br/></p>';
4386
        self::assertSame($expect, $this->subject->stdWrap_debug($content));
4387
    }
4388
4389
    /**
4390
     * Check if stdWrap_debug works properly.
4391
     *
4392
     * Show:
4393
     *
4394
     * - Calls the function debug.
4395
     * - Parameter 1 is $this->data.
4396
     * - Parameter 2 is the string '$cObj->data:'.
4397
     * - If $this->alternativeData is an array the same is repeated with:
4398
     * - Parameter 1 is $this->alternativeData.
4399
     * - Parameter 2 is the string '$cObj->alternativeData:'.
4400
     * - Returns $content as is.
4401
     *
4402
     * Note 1:
4403
     *
4404
     *   As PHPUnit can't mock PHP function calls, the call to debug can't be
4405
     *   easily intercepted. The test is done indirectly by catching the
4406
     *   frontend output of debug.
4407
     *
4408
     * Note 2:
4409
     *
4410
     *   The second parameter to the debug function isn't used by the current
4411
     *   implementation at all. It can't even indirectly be tested.
4412
     *
4413
     * @test
4414
     */
4415
    public function stdWrap_debugData(): void
4416
    {
4417
        $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '*';
4418
        $content = StringUtility::getUniqueId('content');
4419
        $key = StringUtility::getUniqueId('key');
4420
        $value = StringUtility::getUniqueId('value');
4421
        $altValue = StringUtility::getUniqueId('value alt');
4422
        $this->subject->data = [$key => $value];
0 ignored issues
show
Bug introduced by
Accessing data on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
4423
        // Without alternative data only data is returned.
4424
        ob_start();
4425
        $result = $this->subject->stdWrap_debugData($content);
4426
        $out = ob_get_clean();
4427
        self::assertSame($result, $content);
4428
        self::assertStringContainsString('$cObj->data', $out);
4429
        self::assertStringContainsString($value, $out);
4430
        self::assertStringNotContainsString($altValue, $out);
4431
        // By adding alternative data both are returned together.
4432
        $this->subject->alternativeData = [$key => $altValue];
0 ignored issues
show
Bug introduced by
Accessing alternativeData on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
4433
        ob_start();
4434
        $this->subject->stdWrap_debugData($content);
4435
        $out = ob_get_clean();
4436
        self::assertStringNotContainsString('$cObj->alternativeData', $out);
4437
        self::assertStringContainsString($value, $out);
4438
        self::assertStringContainsString($altValue, $out);
4439
    }
4440
4441
    /**
4442
     * Data provider for stdWrap_debugFunc.
4443
     *
4444
     * @return array [$expectArray, $confDebugFunc]
4445
     */
4446
    public function stdWrap_debugFuncDataProvider(): array
4447
    {
4448
        return [
4449
            'expect array by string' => [true, '2'],
4450
            'expect array by integer' => [true, 2],
4451
            'do not expect array' => [false, ''],
4452
        ];
4453
    }
4454
4455
    /**
4456
     * Check if stdWrap_debugFunc works properly.
4457
     *
4458
     * Show:
4459
     *
4460
     * - Calls the function debug with one parameter.
4461
     * - The parameter is the given $content string.
4462
     * - The string is casted to array before, if (int)$conf['debugFunc'] is 2.
4463
     * - Returns $content as is.
4464
     *
4465
     * Note 1:
4466
     *
4467
     *   As PHPUnit can't mock PHP function calls, the call to debug can't be
4468
     *   easily intercepted. The test is done indirectly by catching the
4469
     *   frontend output of debug.
4470
     *
4471
     * @test
4472
     * @dataProvider stdWrap_debugFuncDataProvider
4473
     * @param bool $expectArray If cast to array is expected.
4474
     * @param mixed $confDebugFunc The configuration for $conf['debugFunc'].
4475
     */
4476
    public function stdWrap_debugFunc(bool $expectArray, $confDebugFunc): void
4477
    {
4478
        $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '*';
4479
        $content = StringUtility::getUniqueId('content');
4480
        $conf = ['debugFunc' => $confDebugFunc];
4481
        ob_start();
4482
        $result = $this->subject->stdWrap_debugFunc($content, $conf);
4483
        $out = ob_get_clean();
4484
        self::assertSame($result, $content);
4485
        self::assertStringContainsString($content, $out);
4486
        if ($expectArray) {
4487
            self::assertStringContainsString('=>', $out);
4488
        } else {
4489
            self::assertStringNotContainsString('=>', $out);
4490
        }
4491
    }
4492
4493
    /**
4494
     * Data provider for stdWrap_doubleBrTag
4495
     *
4496
     * @return array Order expected, input, config
4497
     */
4498
    public function stdWrapDoubleBrTagDataProvider(): array
4499
    {
4500
        return [
4501
            'no config: void input' => [
4502
                '',
4503
                '',
4504
                [],
4505
            ],
4506
            'no config: single break' => [
4507
                'one' . LF . 'two',
4508
                'one' . LF . 'two',
4509
                [],
4510
            ],
4511
            'no config: double break' => [
4512
                'onetwo',
4513
                'one' . LF . LF . 'two',
4514
                [],
4515
            ],
4516
            'no config: double break with whitespace' => [
4517
                'onetwo',
4518
                'one' . LF . "\t" . ' ' . "\t" . ' ' . LF . 'two',
4519
                [],
4520
            ],
4521
            'no config: single break around' => [
4522
                LF . 'one' . LF,
4523
                LF . 'one' . LF,
4524
                [],
4525
            ],
4526
            'no config: double break around' => [
4527
                'one',
4528
                LF . LF . 'one' . LF . LF,
4529
                [],
4530
            ],
4531
            'empty string: double break around' => [
4532
                'one',
4533
                LF . LF . 'one' . LF . LF,
4534
                ['doubleBrTag' => ''],
4535
            ],
4536
            'br tag: double break' => [
4537
                'one<br/>two',
4538
                'one' . LF . LF . 'two',
4539
                ['doubleBrTag' => '<br/>'],
4540
            ],
4541
            'br tag: double break around' => [
4542
                '<br/>one<br/>',
4543
                LF . LF . 'one' . LF . LF,
4544
                ['doubleBrTag' => '<br/>'],
4545
            ],
4546
            'double br tag: double break around' => [
4547
                '<br/><br/>one<br/><br/>',
4548
                LF . LF . 'one' . LF . LF,
4549
                ['doubleBrTag' => '<br/><br/>'],
4550
            ],
4551
        ];
4552
    }
4553
4554
    /**
4555
     * Check if doubleBrTag works properly
4556
     *
4557
     * @test
4558
     * @dataProvider stdWrapDoubleBrTagDataProvider
4559
     * @param string $expected The expected value.
4560
     * @param string $input The input value.
4561
     * @param array $config The property 'doubleBrTag'.
4562
     */
4563
    public function stdWrap_doubleBrTag(string $expected, string $input, array $config): void
4564
    {
4565
        self::assertEquals($expected, $this->subject->stdWrap_doubleBrTag($input, $config));
4566
    }
4567
4568
    /**
4569
     * Check if stdWrap_encapsLines works properly.
4570
     *
4571
     * Show:
4572
     *
4573
     * - Delegates to method encaps_lineSplit.
4574
     * - Parameter 1 is $content.
4575
     * - Parameter 2 is $conf['encapsLines'].
4576
     * - Returns the return value.
4577
     *
4578
     * @test
4579
     */
4580
    public function stdWrap_encapsLines(): void
4581
    {
4582
        $content = StringUtility::getUniqueId('content');
4583
        $conf = [
4584
            'encapsLines' => [StringUtility::getUniqueId('not used')],
4585
            'encapsLines.' => [StringUtility::getUniqueId('encapsLines.')],
4586
        ];
4587
        $return = StringUtility::getUniqueId('return');
4588
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4589
            ->onlyMethods(['encaps_lineSplit'])->getMock();
4590
        $subject
4591
            ->expects(self::once())
4592
            ->method('encaps_lineSplit')
4593
            ->with($content, $conf['encapsLines.'])
4594
            ->willReturn($return);
4595
        self::assertSame(
4596
            $return,
4597
            $subject->stdWrap_encapsLines($content, $conf)
4598
        );
4599
    }
4600
4601
    /**
4602
     * Check if stdWrap_encapsLines uses self closing tags
4603
     * only for allowed tags according to
4604
     * @see https://www.w3.org/TR/html5/syntax.html#void-elements
4605
     *
4606
     * @test
4607
     * @dataProvider html5SelfClosingTagsDataprovider
4608
     * @param string $input
4609
     * @param string $expected
4610
     */
4611
    public function stdWrap_encapsLines_HTML5SelfClosingTags(string $input, string $expected): void
4612
    {
4613
        $rteParseFunc = $this->getLibParseFunc_RTE();
4614
4615
        $conf = [
4616
            'encapsLines' => $rteParseFunc['parseFunc.']['nonTypoTagStdWrap.']['encapsLines'] ?? null,
4617
            'encapsLines.' => $rteParseFunc['parseFunc.']['nonTypoTagStdWrap.']['encapsLines.'] ?? null,
4618
        ];
4619
        // don't add an &nbsp; to tag without content
4620
        $conf['encapsLines.']['innerStdWrap_all.']['ifBlank'] = '';
4621
        $additionalEncapsTags = ['a', 'b', 'span'];
4622
4623
        // We want to allow any tag to be an encapsulating tag
4624
        // since this is possible and we don't want an additional tag to be wrapped around.
4625
        $conf['encapsLines.']['encapsTagList'] .= ',' . implode(',', $additionalEncapsTags);
4626
        $conf['encapsLines.']['encapsTagList'] .= ',' . implode(',', [$input]);
4627
4628
        // Check if we get a self-closing tag for
4629
        // empty tags where this is allowed according to HTML5
4630
        $content = '<' . $input . ' id="myId" class="bodytext" />';
4631
        $result = $this->subject->stdWrap_encapsLines($content, $conf);
4632
        self::assertSame($expected, $result);
4633
    }
4634
4635
    /**
4636
     * @return array
4637
     */
4638
    public function html5SelfClosingTagsDataprovider(): array
4639
    {
4640
        return [
4641
            'areaTag_selfclosing' => [
4642
                'input' => 'area',
4643
                'expected' => '<area id="myId" class="bodytext" />',
4644
            ],
4645
            'base_selfclosing' => [
4646
                'input' => 'base',
4647
                'expected' => '<base id="myId" class="bodytext" />',
4648
            ],
4649
            'br_selfclosing' => [
4650
                'input' => 'br',
4651
                'expected' => '<br id="myId" class="bodytext" />',
4652
            ],
4653
            'col_selfclosing' => [
4654
                'input' => 'col',
4655
                'expected' => '<col id="myId" class="bodytext" />',
4656
            ],
4657
            'embed_selfclosing' => [
4658
                'input' => 'embed',
4659
                'expected' => '<embed id="myId" class="bodytext" />',
4660
            ],
4661
            'hr_selfclosing' => [
4662
                'input' => 'hr',
4663
                'expected' => '<hr id="myId" class="bodytext" />',
4664
            ],
4665
            'img_selfclosing' => [
4666
                'input' => 'img',
4667
                'expected' => '<img id="myId" class="bodytext" />',
4668
            ],
4669
            'input_selfclosing' => [
4670
                'input' => 'input',
4671
                'expected' => '<input id="myId" class="bodytext" />',
4672
            ],
4673
            'keygen_selfclosing' => [
4674
                'input' => 'keygen',
4675
                'expected' => '<keygen id="myId" class="bodytext" />',
4676
            ],
4677
            'link_selfclosing' => [
4678
                'input' => 'link',
4679
                'expected' => '<link id="myId" class="bodytext" />',
4680
            ],
4681
            'meta_selfclosing' => [
4682
                'input' => 'meta',
4683
                'expected' => '<meta id="myId" class="bodytext" />',
4684
            ],
4685
            'param_selfclosing' => [
4686
                'input' => 'param',
4687
                'expected' => '<param id="myId" class="bodytext" />',
4688
            ],
4689
            'source_selfclosing' => [
4690
                'input' => 'source',
4691
                'expected' => '<source id="myId" class="bodytext" />',
4692
            ],
4693
            'track_selfclosing' => [
4694
                'input' => 'track',
4695
                'expected' => '<track id="myId" class="bodytext" />',
4696
            ],
4697
            'wbr_selfclosing' => [
4698
                'input' => 'wbr',
4699
                'expected' => '<wbr id="myId" class="bodytext" />',
4700
            ],
4701
            'p_notselfclosing' => [
4702
                'input' => 'p',
4703
                'expected' => '<p id="myId" class="bodytext"></p>',
4704
            ],
4705
            'a_notselfclosing' => [
4706
                'input' => 'a',
4707
                'expected' => '<a id="myId" class="bodytext"></a>',
4708
            ],
4709
            'strong_notselfclosing' => [
4710
                'input' => 'strong',
4711
                'expected' => '<strong id="myId" class="bodytext"></strong>',
4712
            ],
4713
            'span_notselfclosing' => [
4714
                'input' => 'span',
4715
                'expected' => '<span id="myId" class="bodytext"></span>',
4716
            ],
4717
        ];
4718
    }
4719
4720
    /**
4721
     * Data provider for stdWrap_encodeForJavaScriptValue.
4722
     *
4723
     * @return array[]
4724
     */
4725
    public function stdWrap_encodeForJavaScriptValueDataProvider(): array
4726
    {
4727
        return [
4728
            'double quote in string' => [
4729
                '\'double\u0020quote\u0022\'',
4730
                'double quote"',
4731
            ],
4732
            'backslash in string' => [
4733
                '\'backslash\u0020\u005C\'',
4734
                'backslash \\',
4735
            ],
4736
            'exclamation mark' => [
4737
                '\'exclamation\u0021\'',
4738
                'exclamation!',
4739
            ],
4740
            'whitespace tab, newline and carriage return' => [
4741
                '\'white\u0009space\u000As\u000D\'',
4742
                "white\tspace\ns\r",
4743
            ],
4744
            'single quote in string' => [
4745
                '\'single\u0020quote\u0020\u0027\'',
4746
                'single quote \'',
4747
            ],
4748
            'tag' => [
4749
                '\'\u003Ctag\u003E\'',
4750
                '<tag>',
4751
            ],
4752
            'ampersand in string' => [
4753
                '\'amper\u0026sand\'',
4754
                'amper&sand',
4755
            ],
4756
        ];
4757
    }
4758
4759
    /**
4760
     * Check if encodeForJavaScriptValue works properly.
4761
     *
4762
     * @test
4763
     * @dataProvider stdWrap_encodeForJavaScriptValueDataProvider
4764
     * @param string $expect The expected output.
4765
     * @param string $content The given input.
4766
     */
4767
    public function stdWrap_encodeForJavaScriptValue(string $expect, string $content): void
4768
    {
4769
        self::assertSame(
4770
            $expect,
4771
            $this->subject->stdWrap_encodeForJavaScriptValue($content)
4772
        );
4773
    }
4774
4775
    /**
4776
     * Data provider for expandList
4777
     *
4778
     * @return array [$expect, $content]
4779
     */
4780
    public function stdWrap_expandListDataProvider(): array
4781
    {
4782
        return [
4783
            'numbers' => ['1,2,3', '1,2,3'],
4784
            'range' => ['3,4,5', '3-5'],
4785
            'numbers and range' => ['1,3,4,5,7', '1,3-5,7'],
4786
        ];
4787
    }
4788
4789
    /**
4790
     * Test for the stdWrap function "expandList"
4791
     *
4792
     * The method simply delegates to GeneralUtility::expandList. There is no
4793
     * need to repeat the full set of tests of this method here. As PHPUnit
4794
     * can't mock static methods, to prove they are called, all we do here
4795
     * is to provide a few smoke tests.
4796
     *
4797
     * @test
4798
     * @dataProvider stdWrap_expandListDataProvider
4799
     * @param string $expected The expected output.
4800
     * @param string $content The given content.
4801
     */
4802
    public function stdWrap_expandList(string $expected, string $content): void
4803
    {
4804
        self::assertEquals(
4805
            $expected,
4806
            $this->subject->stdWrap_expandList($content)
4807
        );
4808
    }
4809
4810
    /**
4811
     * Check if stdWrap_field works properly.
4812
     *
4813
     * Show:
4814
     *
4815
     * - calls getFieldVal
4816
     * - passes conf['field'] as parameter
4817
     *
4818
     * @test
4819
     */
4820
    public function stdWrap_field(): void
4821
    {
4822
        $expect = StringUtility::getUniqueId('expect');
4823
        $conf = ['field' => StringUtility::getUniqueId('field')];
4824
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
4825
            ->onlyMethods(['getFieldVal'])->getMock();
4826
        $subject
4827
            ->expects(self::once())
4828
            ->method('getFieldVal')
4829
            ->with($conf['field'])
4830
            ->willReturn($expect);
4831
        self::assertSame(
4832
            $expect,
4833
            $subject->stdWrap_field('discarded', $conf)
4834
        );
4835
    }
4836
4837
    /**
4838
     * Data provider for stdWrap_fieldRequired.
4839
     *
4840
     * @return array [$expect, $stop, $content, $conf]
4841
     */
4842
    public function stdWrap_fieldRequiredDataProvider(): array
4843
    {
4844
        $content = StringUtility::getUniqueId('content');
4845
        return [
4846
            // resulting in boolean false
4847
            'false is false' => [
4848
                '',
4849
                true,
4850
                $content,
4851
                ['fieldRequired' => 'false'],
4852
            ],
4853
            'null is false' => [
4854
                '',
4855
                true,
4856
                $content,
4857
                ['fieldRequired' => 'null'],
4858
            ],
4859
            'empty string is false' => [
4860
                '',
4861
                true,
4862
                $content,
4863
                ['fieldRequired' => 'empty'],
4864
            ],
4865
            'whitespace is false' => [
4866
                '',
4867
                true,
4868
                $content,
4869
                ['fieldRequired' => 'whitespace'],
4870
            ],
4871
            'string zero is false' => [
4872
                '',
4873
                true,
4874
                $content,
4875
                ['fieldRequired' => 'stringZero'],
4876
            ],
4877
            'string zero with whitespace is false' => [
4878
                '',
4879
                true,
4880
                $content,
4881
                ['fieldRequired' => 'stringZeroWithWhiteSpace'],
4882
            ],
4883
            'zero is false' => [
4884
                '',
4885
                true,
4886
                $content,
4887
                ['fieldRequired' => 'zero'],
4888
            ],
4889
            // resulting in boolean true
4890
            'true is true' => [
4891
                $content,
4892
                false,
4893
                $content,
4894
                ['fieldRequired' => 'true'],
4895
            ],
4896
            'string is true' => [
4897
                $content,
4898
                false,
4899
                $content,
4900
                ['fieldRequired' => 'string'],
4901
            ],
4902
            'one is true' => [
4903
                $content,
4904
                false,
4905
                $content,
4906
                ['fieldRequired' => 'one'],
4907
            ],
4908
        ];
4909
    }
4910
4911
    /**
4912
     * Check if stdWrap_fieldRequired works properly.
4913
     *
4914
     * Show:
4915
     *
4916
     *  - The value is taken from property array data.
4917
     *  - The key is taken from $conf['fieldRequired'].
4918
     *  - The value is casted to string by trim() and trimmed.
4919
     *  - It is further casted to boolean by if().
4920
     *  - False triggers a stop of further rendering.
4921
     *  - False returns '', true the given content as is.
4922
     *
4923
     * @test
4924
     * @dataProvider stdWrap_fieldRequiredDataProvider
4925
     * @param string $expect The expected output.
4926
     * @param bool $stop Expect stop further rendering.
4927
     * @param string $content The given input.
4928
     * @param array $conf The given configuration.
4929
     */
4930
    public function stdWrap_fieldRequired(string $expect, bool $stop, string $content, array $conf): void
4931
    {
4932
        $data = [
4933
            'null' => null,
4934
            'false' => false,
4935
            'empty' => '',
4936
            'whitespace' => "\t" . ' ',
4937
            'stringZero' => '0',
4938
            'stringZeroWithWhiteSpace' => "\t" . ' 0 ' . "\t",
4939
            'zero' => 0,
4940
            'string' => 'string',
4941
            'true' => true,
4942
            'one' => 1,
4943
        ];
4944
        $subject = $this->subject;
4945
        $subject->_set('data', $data);
4946
        $subject->_set('stdWrapRecursionLevel', 1);
4947
        $subject->_set('stopRendering', [1 => false]);
4948
        self::assertSame(
4949
            $expect,
4950
            $subject->stdWrap_fieldRequired($content, $conf)
4951
        );
4952
        self::assertSame($stop, $subject->_get('stopRendering')[1]);
4953
    }
4954
4955
    /**
4956
     * Data provider for the hash test
4957
     *
4958
     * @return array [$expect, $content, $conf]
4959
     */
4960
    public function hashDataProvider(): array
4961
    {
4962
        return [
4963
            'md5' => [
4964
                'bacb98acf97e0b6112b1d1b650b84971',
4965
                'joh316',
4966
                ['hash' => 'md5'],
4967
            ],
4968
            'sha1' => [
4969
                '063b3d108bed9f88fa618c6046de0dccadcf3158',
4970
                'joh316',
4971
                ['hash' => 'sha1'],
4972
            ],
4973
            'stdWrap capability' => [
4974
                'bacb98acf97e0b6112b1d1b650b84971',
4975
                'joh316',
4976
                [
4977
                    'hash' => '5',
4978
                    'hash.' => ['wrap' => 'md|'],
4979
                ],
4980
            ],
4981
            'non-existing hashing algorithm' => [
4982
                '',
4983
                'joh316',
4984
                ['hash' => 'non-existing'],
4985
            ],
4986
        ];
4987
    }
4988
4989
    /**
4990
     * Check if stdWrap_hash works properly.
4991
     *
4992
     * Show:
4993
     *
4994
     *  - Algorithms: sha1, md5
4995
     *  - Returns '' for invalid algorithm.
4996
     *  - Value can be processed by stdWrap.
4997
     *
4998
     * @test
4999
     * @dataProvider hashDataProvider
5000
     * @param string $expect The expected output.
5001
     * @param string $content The given content.
5002
     * @param array $conf The given configuration.
5003
     */
5004
    public function stdWrap_hash(string $expect, string $content, array $conf): void
5005
    {
5006
        self::assertSame(
5007
            $expect,
5008
            $this->subject->stdWrap_hash($content, $conf)
5009
        );
5010
    }
5011
5012
    /**
5013
     * Data provider for stdWrap_htmlSpecialChars
5014
     *
5015
     * @return array Order: expected, input, conf
5016
     */
5017
    public function stdWrap_htmlSpecialCharsDataProvider(): array
5018
    {
5019
        return [
5020
            'void conf' => [
5021
                '&lt;span&gt;1 &amp;lt; 2&lt;/span&gt;',
5022
                '<span>1 &lt; 2</span>',
5023
                [],
5024
            ],
5025
            'void preserveEntities' => [
5026
                '&lt;span&gt;1 &amp;lt; 2&lt;/span&gt;',
5027
                '<span>1 &lt; 2</span>',
5028
                ['htmlSpecialChars.' => []],
5029
            ],
5030
            'false preserveEntities' => [
5031
                '&lt;span&gt;1 &amp;lt; 2&lt;/span&gt;',
5032
                '<span>1 &lt; 2</span>',
5033
                ['htmlSpecialChars.' => ['preserveEntities' => 0]],
5034
            ],
5035
            'true preserveEntities' => [
5036
                '&lt;span&gt;1 &lt; 2&lt;/span&gt;',
5037
                '<span>1 &lt; 2</span>',
5038
                ['htmlSpecialChars.' => ['preserveEntities' => 1]],
5039
            ],
5040
        ];
5041
    }
5042
5043
    /**
5044
     * Check if stdWrap_htmlSpecialChars works properly
5045
     *
5046
     * @test
5047
     * @dataProvider stdWrap_htmlSpecialCharsDataProvider
5048
     * @param string $expected The expected value.
5049
     * @param string $input The input value.
5050
     * @param array $conf htmlSpecialChars.preserveEntities
5051
     */
5052
    public function stdWrap_htmlSpecialChars(string $expected, string $input, array $conf): void
5053
    {
5054
        self::assertSame(
5055
            $expected,
5056
            $this->subject->stdWrap_htmlSpecialChars($input, $conf)
5057
        );
5058
    }
5059
5060
    /**
5061
     * Data provider for stdWrap_if.
5062
     *
5063
     * @return array [$expect, $stop, $content, $conf, $times, $will]
5064
     */
5065
    public function stdWrap_ifDataProvider(): array
5066
    {
5067
        $content = StringUtility::getUniqueId('content');
5068
        $conf = ['if.' => [StringUtility::getUniqueId('if.')]];
5069
        return [
5070
            // evals to true
5071
            'empty config' => [
5072
                $content,
5073
                false,
5074
                $content,
5075
                [],
5076
                0,
5077
                null,
5078
            ],
5079
            'if. is empty array' => [
5080
                $content,
5081
                false,
5082
                $content,
5083
                ['if.' => []],
5084
                0,
5085
                null,
5086
            ],
5087
            'if. is null' => [
5088
                $content,
5089
                false,
5090
                $content,
5091
                ['if.' => null],
5092
                0,
5093
                null,
5094
            ],
5095
            'if. is false' => [
5096
                $content,
5097
                false,
5098
                $content,
5099
                ['if.' => false],
5100
                0,
5101
                null,
5102
            ],
5103
            'if. is 0' => [
5104
                $content,
5105
                false,
5106
                $content,
5107
                ['if.' => false],
5108
                0,
5109
                null,
5110
            ],
5111
            'if. is "0"' => [
5112
                $content,
5113
                false,
5114
                $content,
5115
                ['if.' => '0'],
5116
                0,
5117
                null,
5118
            ],
5119
            'checkIf returning true' => [
5120
                $content,
5121
                false,
5122
                $content,
5123
                $conf,
5124
                1,
5125
                true,
5126
            ],
5127
            // evals to false
5128
            'checkIf returning false' => [
5129
                '',
5130
                true,
5131
                $content,
5132
                $conf,
5133
                1,
5134
                false,
5135
            ],
5136
        ];
5137
    }
5138
5139
    /**
5140
     * Check if stdWrap_if works properly.
5141
     *
5142
     * Show:
5143
     *
5144
     *  - Delegates to the method checkIf to check for 'true'.
5145
     *  - The parameter to checkIf is $conf['if.'].
5146
     *  - Is also 'true' if $conf['if.'] is empty (PHP method empty).
5147
     *  - 'False' triggers a stop of further rendering.
5148
     *  - Returns the content as is or '' if false.
5149
     *
5150
     * @test
5151
     * @dataProvider stdWrap_ifDataProvider
5152
     * @param string $expect The expected output.
5153
     * @param bool $stop Expect stop further rendering.
5154
     * @param mixed $content The given content.
5155
     * @param array $conf
5156
     * @param int $times Times checkIf is called (0 or 1).
5157
     * @param bool|null $will Return of checkIf (null if not called).
5158
     */
5159
    public function stdWrap_if(string $expect, bool $stop, string $content, array $conf, int $times, ?bool $will): void
5160
    {
5161
        $subject = $this->getAccessibleMock(
5162
            ContentObjectRenderer::class,
5163
            ['checkIf']
5164
        );
5165
        $subject->_set('stdWrapRecursionLevel', 1);
5166
        $subject->_set('stopRendering', [1 => false]);
5167
        $subject
5168
            ->expects(self::exactly($times))
5169
            ->method('checkIf')
5170
            ->with($conf['if.'] ?? null)
5171
            ->willReturn($will);
5172
        self::assertSame($expect, $subject->stdWrap_if($content, $conf));
5173
        self::assertSame($stop, $subject->_get('stopRendering')[1]);
5174
    }
5175
5176
    /**
5177
     * Data provider for checkIf.
5178
     *
5179
     * @return array [$expect, $conf]
5180
     */
5181
    public function checkIfDataProvider(): array
5182
    {
5183
        return [
5184
            'true bitAnd the same' => [true, ['bitAnd' => '4', 'value' => '4']],
5185
            'true bitAnd included' => [true, ['bitAnd' => '6', 'value' => '4']],
5186
            'false bitAnd' => [false, ['bitAnd' => '4', 'value' => '3']],
5187
            'negate true bitAnd the same' => [false, ['bitAnd' => '4', 'value' => '4', 'negate' => '1']],
5188
            'negate true bitAnd included' => [false, ['bitAnd' => '6', 'value' => '4', 'negate' => '1']],
5189
            'negate false bitAnd' => [true, ['bitAnd' => '3', 'value' => '4', 'negate' => '1']],
5190
        ];
5191
    }
5192
5193
    /**
5194
     * Check if checkIf works properly.
5195
     *
5196
     * @test
5197
     * @dataProvider checkIfDataProvider
5198
     * @param bool $expect Whether result should be true or false.
5199
     * @param array $conf TypoScript configuration to pass into checkIf
5200
     */
5201
    public function checkIf(bool $expect, array $conf): void
5202
    {
5203
        $subject = $this->getAccessibleMock(
5204
            ContentObjectRenderer::class,
5205
            ['stdWrap']
5206
        );
5207
        self::assertSame($expect, $subject->checkIf($conf));
5208
    }
5209
5210
    /**
5211
     * Data provider for stdWrap_ifBlank.
5212
     *
5213
     * @return array [$expect, $content, $conf]
5214
     */
5215
    public function stdWrap_ifBlankDataProvider(): array
5216
    {
5217
        $alt = StringUtility::getUniqueId('alternative content');
5218
        $conf = ['ifBlank' => $alt];
5219
        return [
5220
            // blank cases
5221
            'null is blank' => [$alt, null, $conf],
5222
            'false is blank' => [$alt, false, $conf],
5223
            'empty string is blank' => [$alt, '', $conf],
5224
            'whitespace is blank' => [$alt, "\t" . '', $conf],
5225
            // non-blank cases
5226
            'string is not blank' => ['string', 'string', $conf],
5227
            'zero is not blank' => [0, 0, $conf],
5228
            'zero string is not blank' => ['0', '0', $conf],
5229
            'zero float is not blank' => [0.0, 0.0, $conf],
5230
            'true is not blank' => [true, true, $conf],
5231
        ];
5232
    }
5233
5234
    /**
5235
     * Check that stdWrap_ifBlank works properly.
5236
     *
5237
     * Show:
5238
     *
5239
     * - The content is returned if not blank.
5240
     * - Otherwise $conf['ifBlank'] is returned.
5241
     * - The check for blank is done by comparing the trimmed content
5242
     *   with the empty string for equality.
5243
     *
5244
     * @test
5245
     * @dataProvider stdWrap_ifBlankDataProvider
5246
     * @param mixed $expect
5247
     * @param mixed $content The given input.
5248
     * @param array $conf The given configuration.
5249
     */
5250
    public function stdWrap_ifBlank($expect, $content, array $conf): void
5251
    {
5252
        $result = $this->subject->stdWrap_ifBlank($content, $conf);
5253
        self::assertSame($expect, $result);
5254
    }
5255
5256
    /**
5257
     * Data provider for stdWrap_ifEmpty.
5258
     *
5259
     * @return array [$expect, $content, $conf]
5260
     */
5261
    public function stdWrap_ifEmptyDataProvider(): array
5262
    {
5263
        $alt = StringUtility::getUniqueId('alternative content');
5264
        $conf = ['ifEmpty' => $alt];
5265
        return [
5266
            // empty cases
5267
            'null is empty' => [$alt, null, $conf],
5268
            'false is empty' => [$alt, false, $conf],
5269
            'zero is empty' => [$alt, 0, $conf],
5270
            'float zero is empty' => [$alt, 0.0, $conf],
5271
            'whitespace is empty' => [$alt, "\t" . ' ', $conf],
5272
            'empty string is empty' => [$alt, '', $conf],
5273
            'zero string is empty' => [$alt, '0', $conf],
5274
            'zero string is empty with whitespace' => [
5275
                $alt,
5276
                "\t" . ' 0 ' . "\t",
5277
                $conf,
5278
            ],
5279
            // non-empty cases
5280
            'string is not empty' => ['string', 'string', $conf],
5281
            '1 is not empty' => [1, 1, $conf],
5282
            '-1 is not empty' => [-1, -1, $conf],
5283
            '0.1 is not empty' => [0.1, 0.1, $conf],
5284
            '-0.1 is not empty' => [-0.1, -0.1, $conf],
5285
            'true is not empty' => [true, true, $conf],
5286
        ];
5287
    }
5288
5289
    /**
5290
     * Check that stdWrap_ifEmpty works properly.
5291
     *
5292
     * Show:
5293
     *
5294
     * - Returns the content, if not empty.
5295
     * - Otherwise returns $conf['ifEmpty'].
5296
     * - Empty is checked by cast to boolean after trimming.
5297
     *
5298
     * @test
5299
     * @dataProvider stdWrap_ifEmptyDataProvider
5300
     * @param mixed $expect The expected output.
5301
     * @param mixed $content The given content.
5302
     * @param array $conf The given configuration.
5303
     */
5304
    public function stdWrap_ifEmpty($expect, $content, array $conf): void
5305
    {
5306
        $result = $this->subject->stdWrap_ifEmpty($content, $conf);
5307
        self::assertSame($expect, $result);
5308
    }
5309
5310
    /**
5311
     * Data provider for stdWrap_ifNull.
5312
     *
5313
     * @return array [$expect, $content, $conf]
5314
     */
5315
    public function stdWrap_ifNullDataProvider(): array
5316
    {
5317
        $alt = StringUtility::getUniqueId('alternative content');
5318
        $conf = ['ifNull' => $alt];
5319
        return [
5320
            'only null is null' => [$alt, null, $conf],
5321
            'zero is not null' => [0, 0, $conf],
5322
            'float zero is not null' => [0.0, 0.0, $conf],
5323
            'false is not null' => [false, false, $conf],
5324
            'zero string is not null' => ['0', '0', $conf],
5325
            'empty string is not null' => ['', '', $conf],
5326
            'whitespace is not null' => ["\t" . '', "\t" . '', $conf],
5327
        ];
5328
    }
5329
5330
    /**
5331
     * Check that stdWrap_ifNull works properly.
5332
     *
5333
     * Show:
5334
     *
5335
     * - Returns the content, if not null.
5336
     * - Otherwise returns $conf['ifNull'].
5337
     * - Null is strictly checked by identity with null.
5338
     *
5339
     * @test
5340
     * @dataProvider stdWrap_ifNullDataProvider
5341
     * @param mixed $expect
5342
     * @param mixed $content The given input.
5343
     * @param array $conf The given configuration.
5344
     */
5345
    public function stdWrap_ifNull($expect, $content, array $conf): void
5346
    {
5347
        $result = $this->subject->stdWrap_ifNull($content, $conf);
5348
        self::assertSame($expect, $result);
5349
    }
5350
5351
    /**
5352
     * Data provider for stdWrap_innerWrap
5353
     *
5354
     * @return array Order expected, input, conf
5355
     */
5356
    public function stdWrap_innerWrapDataProvider(): array
5357
    {
5358
        return [
5359
            'no conf' => [
5360
                'XXX',
5361
                'XXX',
5362
                [],
5363
            ],
5364
            'simple' => [
5365
                '<wrap>XXX</wrap>',
5366
                'XXX',
5367
                ['innerWrap' => '<wrap>|</wrap>'],
5368
            ],
5369
            'missing pipe puts wrap before' => [
5370
                '<pre>XXX',
5371
                'XXX',
5372
                ['innerWrap' => '<pre>'],
5373
            ],
5374
            'trims whitespace' => [
5375
                '<wrap>XXX</wrap>',
5376
                'XXX',
5377
                ['innerWrap' => '<wrap>' . "\t" . ' | ' . "\t" . '</wrap>'],
5378
            ],
5379
            'split char change is not possible' => [
5380
                '<wrap> # </wrap>XXX',
5381
                'XXX',
5382
                [
5383
                    'innerWrap' => '<wrap> # </wrap>',
5384
                    'innerWrap.' => ['splitChar' => '#'],
5385
                ],
5386
            ],
5387
        ];
5388
    }
5389
5390
    /**
5391
     * Check if stdWrap_innerWrap works properly.
5392
     *
5393
     * @param string $expected The expected value.
5394
     * @param string $input The input value.
5395
     * @param array $conf Property: innerWrap
5396
     * @test
5397
     * @dataProvider stdWrap_innerWrapDataProvider
5398
     */
5399
    public function stdWrap_innerWrap(string $expected, string $input, array $conf): void
5400
    {
5401
        self::assertSame(
5402
            $expected,
5403
            $this->subject->stdWrap_innerWrap($input, $conf)
5404
        );
5405
    }
5406
5407
    /**
5408
     * Data provider for stdWrap_innerWrap2
5409
     *
5410
     * @return array Order expected, input, conf
5411
     */
5412
    public function stdWrap_innerWrap2DataProvider(): array
5413
    {
5414
        return [
5415
            'no conf' => [
5416
                'XXX',
5417
                'XXX',
5418
                [],
5419
            ],
5420
            'simple' => [
5421
                '<wrap>XXX</wrap>',
5422
                'XXX',
5423
                ['innerWrap2' => '<wrap>|</wrap>'],
5424
            ],
5425
            'missing pipe puts wrap before' => [
5426
                '<pre>XXX',
5427
                'XXX',
5428
                ['innerWrap2' => '<pre>'],
5429
            ],
5430
            'trims whitespace' => [
5431
                '<wrap>XXX</wrap>',
5432
                'XXX',
5433
                ['innerWrap2' => '<wrap>' . "\t" . ' | ' . "\t" . '</wrap>'],
5434
            ],
5435
            'split char change is not possible' => [
5436
                '<wrap> # </wrap>XXX',
5437
                'XXX',
5438
                [
5439
                    'innerWrap2' => '<wrap> # </wrap>',
5440
                    'innerWrap2.' => ['splitChar' => '#'],
5441
                ],
5442
            ],
5443
        ];
5444
    }
5445
5446
    /**
5447
     * Check if stdWrap_innerWrap2 works properly.
5448
     *
5449
     * @param string $expected The expected value.
5450
     * @param string $input The input value.
5451
     * @param array $conf Property: innerWrap2
5452
     * @test
5453
     * @dataProvider stdWrap_innerWrap2DataProvider
5454
     */
5455
    public function stdWrap_innerWrap2(string $expected, string $input, array $conf): void
5456
    {
5457
        self::assertSame(
5458
            $expected,
5459
            $this->subject->stdWrap_innerWrap2($input, $conf)
5460
        );
5461
    }
5462
5463
    /**
5464
     * Check if stdWrap_insertData works properly.
5465
     *
5466
     * Show:
5467
     *
5468
     *  - Delegates to method insertData.
5469
     *  - Parameter 1 is $content.
5470
     *  - Returns the return value.
5471
     *
5472
     * @test
5473
     */
5474
    public function stdWrap_insertData(): void
5475
    {
5476
        $content = StringUtility::getUniqueId('content');
5477
        $return = StringUtility::getUniqueId('return');
5478
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
5479
            ->onlyMethods(['insertData'])->getMock();
5480
        $subject->expects(self::once())->method('insertData')
5481
            ->with($content)->willReturn($return);
5482
        self::assertSame(
5483
            $return,
5484
            $subject->stdWrap_insertData($content)
5485
        );
5486
    }
5487
5488
    /**
5489
     * Data provider for stdWrap_insertData
5490
     *
5491
     * @return array [$expect, $content]
5492
     */
5493
    public function stdWrap_insertDataProvider(): array
5494
    {
5495
        return [
5496
            'empty' => ['', ''],
5497
            'notFoundData' => ['any=1', 'any{$string}=1'],
5498
            'queryParameter' => ['any{#string}=1', 'any{#string}=1'],
5499
        ];
5500
    }
5501
5502
    /**
5503
     * Check that stdWrap_insertData works properly with given input.
5504
     *
5505
     * @test
5506
     * @dataProvider stdWrap_insertDataProvider
5507
     * @param mixed $expect The expected output.
5508
     * @param string $content The given input.
5509
     */
5510
    public function stdWrap_insertDataAndInputExamples($expect, string $content): void
5511
    {
5512
        self::assertSame($expect, $this->subject->stdWrap_insertData($content));
5513
    }
5514
5515
    /**
5516
     * Data provider for stdWrap_intval
5517
     *
5518
     * @return array [$expect, $content]
5519
     */
5520
    public function stdWrap_intvalDataProvider(): array
5521
    {
5522
        return [
5523
            // numbers
5524
            'int' => [123, 123],
5525
            'float' => [123, 123.45],
5526
            'float does not round up' => [123, 123.55],
5527
            // negative numbers
5528
            'negative int' => [-123, -123],
5529
            'negative float' => [-123, -123.45],
5530
            'negative float does not round down' => [-123, -123.55],
5531
            // strings
5532
            'word string' => [0, 'string'],
5533
            'empty string' => [0, ''],
5534
            'zero string' => [0, '0'],
5535
            'int string' => [123, '123'],
5536
            'float string' => [123, '123.55'],
5537
            'negative float string' => [-123, '-123.55'],
5538
            // other types
5539
            'null' => [0, null],
5540
            'true' => [1, true],
5541
            'false' => [0, false],
5542
        ];
5543
    }
5544
5545
    /**
5546
     * Check that stdWrap_intval works properly.
5547
     *
5548
     * Show:
5549
     *
5550
     * - It does not round up.
5551
     * - All types of input is casted to int:
5552
     *   - null: 0
5553
     *   - false: 0
5554
     *   - true: 1
5555
     *   -
5556
     *
5557
     *
5558
     *
5559
     * @test
5560
     * @dataProvider stdWrap_intvalDataProvider
5561
     * @param int $expect The expected output.
5562
     * @param mixed $content The given input.
5563
     */
5564
    public function stdWrap_intval(int $expect, $content): void
5565
    {
5566
        self::assertSame($expect, $this->subject->stdWrap_intval($content));
5567
    }
5568
5569
    /**
5570
     * Data provider for stdWrap_keywords
5571
     *
5572
     * @return string[][] Order expected, input
5573
     */
5574
    public function stdWrapKeywordsDataProvider(): array
5575
    {
5576
        return [
5577
            'empty string' => ['', ''],
5578
            'blank' => ['', ' '],
5579
            'tab' => ['', "\t"],
5580
            'single semicolon' => [',', ' ; '],
5581
            'single comma' => [',', ' , '],
5582
            'single nl' => [',', ' ' . PHP_EOL . ' '],
5583
            'double semicolon' => [',,', ' ; ; '],
5584
            'double comma' => [',,', ' , , '],
5585
            'double nl' => [',,', ' ' . PHP_EOL . ' ' . PHP_EOL . ' '],
5586
            'simple word' => ['one', ' one '],
5587
            'simple word trimmed' => ['one', 'one'],
5588
            ', separated' => ['one,two', ' one , two '],
5589
            '; separated' => ['one,two', ' one ; two '],
5590
            'nl separated' => ['one,two', ' one ' . PHP_EOL . ' two '],
5591
            ', typical' => ['one,two,three', 'one, two, three'],
5592
            '; typical' => ['one,two,three', ' one; two; three'],
5593
            'nl typical' => [
5594
                'one,two,three',
5595
                'one' . PHP_EOL . 'two' . PHP_EOL . 'three',
5596
            ],
5597
            ', sourounded' => [',one,two,', ' , one , two , '],
5598
            '; sourounded' => [',one,two,', ' ; one ; two ; '],
5599
            'nl sourounded' => [
5600
                ',one,two,',
5601
                ' ' . PHP_EOL . ' one ' . PHP_EOL . ' two ' . PHP_EOL . ' ',
5602
            ],
5603
            'mixed' => [
5604
                'one,two,three,four',
5605
                ' one, two; three' . PHP_EOL . 'four',
5606
            ],
5607
            'keywods with blanks in words' => [
5608
                'one plus,two minus',
5609
                ' one plus , two minus ',
5610
            ],
5611
        ];
5612
    }
5613
5614
    /**
5615
     * Check if stdWrap_keywords works properly.
5616
     *
5617
     * @param string $expected The expected value.
5618
     * @param string $input The input value.
5619
     * @test
5620
     * @dataProvider stdWrapKeywordsDataProvider
5621
     */
5622
    public function stdWrap_keywords(string $expected, string $input): void
5623
    {
5624
        self::assertSame($expected, $this->subject->stdWrap_keywords($input));
5625
    }
5626
5627
    /**
5628
     * Data provider for stdWrap_lang
5629
     *
5630
     * @return array Order expected, input, conf, language
5631
     */
5632
    public function stdWrap_langDataProvider(): array
5633
    {
5634
        return [
5635
            'empty conf' => [
5636
                'original',
5637
                'original',
5638
                [],
5639
                'de',
5640
            ],
5641
            'translation de' => [
5642
                'Übersetzung',
5643
                'original',
5644
                [
5645
                    'lang.' => [
5646
                        'de' => 'Übersetzung',
5647
                        'it' => 'traduzione',
5648
                    ],
5649
                ],
5650
                'de',
5651
            ],
5652
            'translation it' => [
5653
                'traduzione',
5654
                'original',
5655
                [
5656
                    'lang.' => [
5657
                        'de' => 'Übersetzung',
5658
                        'it' => 'traduzione',
5659
                    ],
5660
                ],
5661
                'it',
5662
            ],
5663
            'no translation' => [
5664
                'original',
5665
                'original',
5666
                [
5667
                    'lang.' => [
5668
                        'de' => 'Übersetzung',
5669
                        'it' => 'traduzione',
5670
                    ],
5671
                ],
5672
                '',
5673
            ],
5674
            'missing label' => [
5675
                'original',
5676
                'original',
5677
                [
5678
                    'lang.' => [
5679
                        'de' => 'Übersetzung',
5680
                        'it' => 'traduzione',
5681
                    ],
5682
                ],
5683
                'fr',
5684
            ],
5685
        ];
5686
    }
5687
5688
    /**
5689
     * Check if stdWrap_lang works properly with site handling.
5690
     *
5691
     * @param string $expected The expected value.
5692
     * @param string $input The input value.
5693
     * @param array $conf Properties: lang.xy.
5694
     * @param string $language For $TSFE->config[config][language].
5695
     * @test
5696
     * @dataProvider stdWrap_langDataProvider
5697
     */
5698
    public function stdWrap_langViaSiteLanguage(string $expected, string $input, array $conf, string $language): void
5699
    {
5700
        $site = $this->createSiteWithLanguage([
5701
            'base' => '/',
5702
            'languageId' => 2,
5703
            'locale' => 'en_UK',
5704
            'typo3Language' => $language,
5705
        ]);
5706
        $this->frontendControllerMock->_set('language', $site->getLanguageById(2));
5707
        self::assertSame(
5708
            $expected,
5709
            $this->subject->stdWrap_lang($input, $conf)
5710
        );
5711
    }
5712
5713
    /**
5714
     * Check if stdWrap_listNum works properly.
5715
     *
5716
     * Show:
5717
     *
5718
     * - Delegates to method listNum.
5719
     * - Parameter 1 is $content.
5720
     * - Parameter 2 is $conf['listNum'].
5721
     * - Parameter 3 is $conf['listNum.']['splitChar'].
5722
     * - Returns the return value.
5723
     *
5724
     * @test
5725
     */
5726
    public function stdWrap_listNum(): void
5727
    {
5728
        $content = StringUtility::getUniqueId('content');
5729
        $conf = [
5730
            'listNum' => StringUtility::getUniqueId('listNum'),
5731
            'listNum.' => [
5732
                'splitChar' => StringUtility::getUniqueId('splitChar'),
5733
            ],
5734
        ];
5735
        $return = StringUtility::getUniqueId('return');
5736
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
5737
            ->onlyMethods(['listNum'])->getMock();
5738
        $subject
5739
            ->expects(self::once())
5740
            ->method('listNum')
5741
            ->with(
5742
                $content,
5743
                $conf['listNum'],
5744
                $conf['listNum.']['splitChar']
5745
            )
5746
            ->willReturn($return);
5747
        self::assertSame(
5748
            $return,
5749
            $subject->stdWrap_listNum($content, $conf)
5750
        );
5751
    }
5752
5753
    /**
5754
     * Data provider for stdWrap_noTrimWrap.
5755
     *
5756
     * @return array [$expect, $content, $conf]
5757
     */
5758
    public function stdWrap_noTrimWrapDataProvider(): array
5759
    {
5760
        return [
5761
            'Standard case' => [
5762
                ' left middle right ',
5763
                'middle',
5764
                [
5765
                    'noTrimWrap' => '| left | right |',
5766
                ],
5767
            ],
5768
            'Tabs as whitespace' => [
5769
                "\t" . 'left' . "\t" . 'middle' . "\t" . 'right' . "\t",
5770
                'middle',
5771
                [
5772
                    'noTrimWrap' =>
5773
                        '|' . "\t" . 'left' . "\t" . '|' . "\t" . 'right' . "\t" . '|',
5774
                ],
5775
            ],
5776
            'Split char is 0' => [
5777
                ' left middle right ',
5778
                'middle',
5779
                [
5780
                    'noTrimWrap' => '0 left 0 right 0',
5781
                    'noTrimWrap.' => ['splitChar' => '0'],
5782
                ],
5783
            ],
5784
            'Split char is pipe (default)' => [
5785
                ' left middle right ',
5786
                'middle',
5787
                [
5788
                    'noTrimWrap' => '| left | right |',
5789
                    'noTrimWrap.' => ['splitChar' => '|'],
5790
                ],
5791
            ],
5792
            'Split char is a' => [
5793
                ' left middle right ',
5794
                'middle',
5795
                [
5796
                    'noTrimWrap' => 'a left a right a',
5797
                    'noTrimWrap.' => ['splitChar' => 'a'],
5798
                ],
5799
            ],
5800
            'Split char is a word (ab)' => [
5801
                ' left middle right ',
5802
                'middle',
5803
                [
5804
                    'noTrimWrap' => 'ab left ab right ab',
5805
                    'noTrimWrap.' => ['splitChar' => 'ab'],
5806
                ],
5807
            ],
5808
            'Split char accepts stdWrap' => [
5809
                ' left middle right ',
5810
                'middle',
5811
                [
5812
                    'noTrimWrap' => 'abc left abc right abc',
5813
                    'noTrimWrap.' => [
5814
                        'splitChar' => 'b',
5815
                        'splitChar.' => ['wrap' => 'a|c'],
5816
                    ],
5817
                ],
5818
            ],
5819
        ];
5820
    }
5821
5822
    /**
5823
     * Check if stdWrap_noTrimWrap works properly.
5824
     *
5825
     * @test
5826
     * @dataProvider stdWrap_noTrimWrapDataProvider
5827
     * @param string $expect The expected output.
5828
     * @param string $content The given input.
5829
     * @param array $conf The given configuration.
5830
     */
5831
    public function stdWrap_noTrimWrap(string $expect, string $content, array $conf): void
5832
    {
5833
        self::assertSame(
5834
            $expect,
5835
            $this->subject->stdWrap_noTrimWrap($content, $conf)
5836
        );
5837
    }
5838
5839
    /**
5840
     * Check if stdWrap_numRows works properly.
5841
     *
5842
     * Show:
5843
     *
5844
     * - Delegates to method numRows.
5845
     * - Parameter is $conf['numRows.'].
5846
     * - Returns the return value.
5847
     *
5848
     * @test
5849
     */
5850
    public function stdWrap_numRows(): void
5851
    {
5852
        $conf = [
5853
            'numRows' => StringUtility::getUniqueId('numRows'),
5854
            'numRows.' => [StringUtility::getUniqueId('numRows')],
5855
        ];
5856
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
5857
            ->onlyMethods(['numRows'])->getMock();
5858
        $subject->expects(self::once())->method('numRows')
5859
            ->with($conf['numRows.'])->willReturn('return');
5860
        self::assertSame(
5861
            'return',
5862
            $subject->stdWrap_numRows('discard', $conf)
5863
        );
5864
    }
5865
5866
    /**
5867
     * Check if stdWrap_numberFormat works properly.
5868
     *
5869
     * Show:
5870
     *
5871
     * - Delegates to the method numberFormat.
5872
     * - Parameter 1 is $content.
5873
     * - Parameter 2 is $conf['numberFormat.'].
5874
     * - Returns the return value.
5875
     *
5876
     * @test
5877
     */
5878
    public function stdWrap_numberFormat(): void
5879
    {
5880
        $content = StringUtility::getUniqueId('content');
5881
        $conf = [
5882
            'numberFormat' => StringUtility::getUniqueId('not used'),
5883
            'numberFormat.' => [StringUtility::getUniqueId('numberFormat.')],
5884
        ];
5885
        $return = StringUtility::getUniqueId('return');
5886
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
5887
            ->onlyMethods(['numberFormat'])->getMock();
5888
        $subject
5889
            ->expects(self::once())
5890
            ->method('numberFormat')
5891
            ->with((float)$content, $conf['numberFormat.'])
5892
            ->willReturn($return);
5893
        self::assertSame(
5894
            $return,
5895
            $subject->stdWrap_numberFormat($content, $conf)
5896
        );
5897
    }
5898
5899
    /**
5900
     * Data provider for stdWrap_outerWrap
5901
     *
5902
     * @return array Order expected, input, conf
5903
     */
5904
    public function stdWrap_outerWrapDataProvider(): array
5905
    {
5906
        return [
5907
            'no conf' => [
5908
                'XXX',
5909
                'XXX',
5910
                [],
5911
            ],
5912
            'simple' => [
5913
                '<wrap>XXX</wrap>',
5914
                'XXX',
5915
                ['outerWrap' => '<wrap>|</wrap>'],
5916
            ],
5917
            'missing pipe puts wrap before' => [
5918
                '<pre>XXX',
5919
                'XXX',
5920
                ['outerWrap' => '<pre>'],
5921
            ],
5922
            'trims whitespace' => [
5923
                '<wrap>XXX</wrap>',
5924
                'XXX',
5925
                ['outerWrap' => '<wrap>' . "\t" . ' | ' . "\t" . '</wrap>'],
5926
            ],
5927
            'split char change is not possible' => [
5928
                '<wrap> # </wrap>XXX',
5929
                'XXX',
5930
                [
5931
                    'outerWrap' => '<wrap> # </wrap>',
5932
                    'outerWrap.' => ['splitChar' => '#'],
5933
                ],
5934
            ],
5935
        ];
5936
    }
5937
5938
    /**
5939
     * Check if stdWrap_outerWrap works properly.
5940
     *
5941
     * @param string $expected The expected value.
5942
     * @param string $input The input value.
5943
     * @param array $conf Property: outerWrap
5944
     * @test
5945
     * @dataProvider stdWrap_outerWrapDataProvider
5946
     */
5947
    public function stdWrap_outerWrap(string $expected, string $input, array $conf): void
5948
    {
5949
        self::assertSame(
5950
            $expected,
5951
            $this->subject->stdWrap_outerWrap($input, $conf)
5952
        );
5953
    }
5954
5955
    /**
5956
     * Data provider for stdWrap_csConv
5957
     *
5958
     * @return array Order expected, input, conf
5959
     */
5960
    public function stdWrap_overrideDataProvider(): array
5961
    {
5962
        return [
5963
            'standard case' => [
5964
                'override',
5965
                'content',
5966
                ['override' => 'override'],
5967
            ],
5968
            'empty conf does not override' => [
5969
                'content',
5970
                'content',
5971
                [],
5972
            ],
5973
            'empty string does not override' => [
5974
                'content',
5975
                'content',
5976
                ['override' => ''],
5977
            ],
5978
            'whitespace does not override' => [
5979
                'content',
5980
                'content',
5981
                ['override' => ' ' . "\t"],
5982
            ],
5983
            'zero does not override' => [
5984
                'content',
5985
                'content',
5986
                ['override' => 0],
5987
            ],
5988
            'false does not override' => [
5989
                'content',
5990
                'content',
5991
                ['override' => false],
5992
            ],
5993
            'null does not override' => [
5994
                'content',
5995
                'content',
5996
                ['override' => null],
5997
            ],
5998
            'one does override' => [
5999
                1,
6000
                'content',
6001
                ['override' => 1],
6002
            ],
6003
            'minus one does override' => [
6004
                -1,
6005
                'content',
6006
                ['override' => -1],
6007
            ],
6008
            'float does override' => [
6009
                -0.1,
6010
                'content',
6011
                ['override' => -0.1],
6012
            ],
6013
            'true does override' => [
6014
                true,
6015
                'content',
6016
                ['override' => true],
6017
            ],
6018
            'the value is not trimmed' => [
6019
                "\t" . 'override',
6020
                'content',
6021
                ['override' => "\t" . 'override'],
6022
            ],
6023
        ];
6024
    }
6025
6026
    /**
6027
     * Check if stdWrap_override works properly.
6028
     *
6029
     * @test
6030
     * @dataProvider stdWrap_overrideDataProvider
6031
     * @param mixed $expect
6032
     * @param string $content
6033
     * @param array $conf Property: setCurrent
6034
     */
6035
    public function stdWrap_override($expect, string $content, array $conf): void
6036
    {
6037
        self::assertSame(
6038
            $expect,
6039
            $this->subject->stdWrap_override($content, $conf)
6040
        );
6041
    }
6042
6043
    /**
6044
     * Check if stdWrap_parseFunc works properly.
6045
     *
6046
     * Show:
6047
     *
6048
     * - Delegates to method parseFunc.
6049
     * - Parameter 1 is $content.
6050
     * - Parameter 2 is $conf['parseFunc.'].
6051
     * - Parameter 3 is $conf['parseFunc'].
6052
     * - Returns the return.
6053
     *
6054
     * @test
6055
     */
6056
    public function stdWrap_parseFunc(): void
6057
    {
6058
        $content = StringUtility::getUniqueId('content');
6059
        $conf = [
6060
            'parseFunc' => StringUtility::getUniqueId('parseFunc'),
6061
            'parseFunc.' => [StringUtility::getUniqueId('parseFunc.')],
6062
        ];
6063
        $return = StringUtility::getUniqueId('return');
6064
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6065
            ->onlyMethods(['parseFunc'])->getMock();
6066
        $subject
6067
            ->expects(self::once())
6068
            ->method('parseFunc')
6069
            ->with($content, $conf['parseFunc.'], $conf['parseFunc'])
6070
            ->willReturn($return);
6071
        self::assertSame(
6072
            $return,
6073
            $subject->stdWrap_parseFunc($content, $conf)
6074
        );
6075
    }
6076
6077
    /**
6078
     * Check if stdWrap_postCObject works properly.
6079
     *
6080
     * Show:
6081
     *
6082
     * - Delegates to the method cObjGetSingle().
6083
     * - Parameter 1 is $conf['postCObject'].
6084
     * - Parameter 2 is $conf['postCObject.'].
6085
     * - Parameter 3 is '/stdWrap/.postCObject'.
6086
     * - Returns the return value appended by $content.
6087
     *
6088
     * @test
6089
     */
6090
    public function stdWrap_postCObject(): void
6091
    {
6092
        $debugKey = '/stdWrap/.postCObject';
6093
        $content = StringUtility::getUniqueId('content');
6094
        $conf = [
6095
            'postCObject' => StringUtility::getUniqueId('postCObject'),
6096
            'postCObject.' => [StringUtility::getUniqueId('postCObject.')],
6097
        ];
6098
        $return = StringUtility::getUniqueId('return');
6099
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6100
            ->onlyMethods(['cObjGetSingle'])->getMock();
6101
        $subject
6102
            ->expects(self::once())
6103
            ->method('cObjGetSingle')
6104
            ->with($conf['postCObject'], $conf['postCObject.'], $debugKey)
6105
            ->willReturn($return);
6106
        self::assertSame(
6107
            $content . $return,
6108
            $subject->stdWrap_postCObject($content, $conf)
6109
        );
6110
    }
6111
6112
    /**
6113
     * Check that stdWrap_postUserFunc works properly.
6114
     *
6115
     * Show:
6116
     *  - Delegates to method callUserFunction.
6117
     *  - Parameter 1 is $conf['postUserFunc'].
6118
     *  - Parameter 2 is $conf['postUserFunc.'].
6119
     *  - Returns the return value.
6120
     *
6121
     * @test
6122
     */
6123
    public function stdWrap_postUserFunc(): void
6124
    {
6125
        $content = StringUtility::getUniqueId('content');
6126
        $conf = [
6127
            'postUserFunc' => StringUtility::getUniqueId('postUserFunc'),
6128
            'postUserFunc.' => [StringUtility::getUniqueId('postUserFunc.')],
6129
        ];
6130
        $return = StringUtility::getUniqueId('return');
6131
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6132
            ->onlyMethods(['callUserFunction'])->getMock();
6133
        $subject
6134
            ->expects(self::once())
6135
            ->method('callUserFunction')
6136
            ->with($conf['postUserFunc'], $conf['postUserFunc.'])
6137
            ->willReturn($return);
6138
        self::assertSame(
6139
            $return,
6140
            $subject->stdWrap_postUserFunc($content, $conf)
6141
        );
6142
    }
6143
6144
    /**
6145
     * Check if stdWrap_postUserFuncInt works properly.
6146
     *
6147
     * Show:
6148
     *
6149
     * - Calls frontend controller method uniqueHash.
6150
     * - Concatenates "INT_SCRIPT." and the returned hash to $substKey.
6151
     * - Configures the frontend controller for 'INTincScript.$substKey'.
6152
     * - The configuration array contains:
6153
     *   - content: $content
6154
     *   - postUserFunc: $conf['postUserFuncInt']
6155
     *   - conf: $conf['postUserFuncInt.']
6156
     *   - type: 'POSTUSERFUNC'
6157
     *   - cObj: serialized content renderer object
6158
     * - Returns "<!-- $substKey -->".
6159
     *
6160
     * @test
6161
     */
6162
    public function stdWrap_postUserFuncInt(): void
6163
    {
6164
        $uniqueHash = StringUtility::getUniqueId('uniqueHash');
6165
        $substKey = 'INT_SCRIPT.' . $uniqueHash;
6166
        $content = StringUtility::getUniqueId('content');
6167
        $conf = [
6168
            'postUserFuncInt' => StringUtility::getUniqueId('function'),
6169
            'postUserFuncInt.' => [StringUtility::getUniqueId('function array')],
6170
        ];
6171
        $expect = '<!--' . $substKey . '-->';
6172
        $frontend = $this->getMockBuilder(TypoScriptFrontendController::class)
6173
            ->disableOriginalConstructor()->onlyMethods(['uniqueHash'])
6174
            ->getMock();
6175
        $frontend->expects(self::once())->method('uniqueHash')
6176
            ->with()->willReturn($uniqueHash);
6177
        $frontend->config = [];
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
6178
        $subject = $this->getAccessibleMock(
6179
            ContentObjectRenderer::class,
6180
            null,
6181
            [$frontend]
6182
        );
6183
        self::assertSame(
6184
            $expect,
6185
            $subject->stdWrap_postUserFuncInt($content, $conf)
6186
        );
6187
        $array = [
6188
            'content' => $content,
6189
            'postUserFunc' => $conf['postUserFuncInt'],
6190
            'conf' => $conf['postUserFuncInt.'],
6191
            'type' => 'POSTUSERFUNC',
6192
            'cObj' => serialize($subject),
6193
        ];
6194
        self::assertSame(
6195
            $array,
6196
            $frontend->config['INTincScript'][$substKey]
6197
        );
6198
    }
6199
6200
    /**
6201
     * Check if stdWrap_preCObject works properly.
6202
     *
6203
     * Show:
6204
     *
6205
     * - Delegates to the method cObjGetSingle().
6206
     * - Parameter 1 is $conf['preCObject'].
6207
     * - Parameter 2 is $conf['preCObject.'].
6208
     * - Parameter 3 is '/stdWrap/.preCObject'.
6209
     * - Returns the return value appended by $content.
6210
     *
6211
     * @test
6212
     */
6213
    public function stdWrap_preCObject(): void
6214
    {
6215
        $debugKey = '/stdWrap/.preCObject';
6216
        $content = StringUtility::getUniqueId('content');
6217
        $conf = [
6218
            'preCObject' => StringUtility::getUniqueId('preCObject'),
6219
            'preCObject.' => [StringUtility::getUniqueId('preCObject.')],
6220
        ];
6221
        $return = StringUtility::getUniqueId('return');
6222
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6223
            ->onlyMethods(['cObjGetSingle'])->getMock();
6224
        $subject
6225
            ->expects(self::once())
6226
            ->method('cObjGetSingle')
6227
            ->with($conf['preCObject'], $conf['preCObject.'], $debugKey)
6228
            ->willReturn($return);
6229
        self::assertSame(
6230
            $return . $content,
6231
            $subject->stdWrap_preCObject($content, $conf)
6232
        );
6233
    }
6234
6235
    /**
6236
     * Check if stdWrap_preIfEmptyListNum works properly.
6237
     *
6238
     * Show:
6239
     *
6240
     * - Delegates to method listNum.
6241
     * - Parameter 1 is $content.
6242
     * - Parameter 2 is $conf['preIfEmptyListNum'].
6243
     * - Parameter 3 is $conf['preIfEmptyListNum.']['splitChar'].
6244
     * - Returns the return value.
6245
     *
6246
     * @test
6247
     */
6248
    public function stdWrap_preIfEmptyListNum(): void
6249
    {
6250
        $content = StringUtility::getUniqueId('content');
6251
        $conf = [
6252
            'preIfEmptyListNum' => StringUtility::getUniqueId('preIfEmptyListNum'),
6253
            'preIfEmptyListNum.' => [
6254
                'splitChar' => StringUtility::getUniqueId('splitChar'),
6255
            ],
6256
        ];
6257
        $return = StringUtility::getUniqueId('return');
6258
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6259
            ->onlyMethods(['listNum'])->getMock();
6260
        $subject
6261
            ->expects(self::once())
6262
            ->method('listNum')
6263
            ->with(
6264
                $content,
6265
                $conf['preIfEmptyListNum'],
6266
                $conf['preIfEmptyListNum.']['splitChar']
6267
            )
6268
            ->willReturn($return);
6269
        self::assertSame(
6270
            $return,
6271
            $subject->stdWrap_preIfEmptyListNum($content, $conf)
6272
        );
6273
    }
6274
6275
    /**
6276
     * Data provider for stdWrap_prefixComment.
6277
     *
6278
     * @return array [$expect, $content, $conf, $disable, $times, $will]
6279
     */
6280
    public function stdWrap_prefixCommentDataProvider(): array
6281
    {
6282
        $content = StringUtility::getUniqueId('content');
6283
        $will = StringUtility::getUniqueId('will');
6284
        $conf = [];
6285
        $conf['prefixComment'] = StringUtility::getUniqueId('prefixComment');
6286
        $emptyConf1 = [];
6287
        $emptyConf2 = [];
6288
        $emptyConf2['prefixComment'] = '';
6289
        return [
6290
            'standard case' => [$will, $content, $conf, false, 1, $will],
6291
            'emptyConf1' => [$content, $content, $emptyConf1, false, 0, $will],
6292
            'emptyConf2' => [$content, $content, $emptyConf2, false, 0, $will],
6293
            'disabled by bool' => [$content, $content, $conf, true, 0, $will],
6294
            'disabled by int' => [$content, $content, $conf, 1, 0, $will],
6295
        ];
6296
    }
6297
6298
    /**
6299
     * Check that stdWrap_prefixComment works properly.
6300
     *
6301
     * Show:
6302
     *
6303
     *  - Delegates to method prefixComment.
6304
     *  - Parameter 1 is $conf['prefixComment'].
6305
     *  - Parameter 2 is [].
6306
     *  - Parameter 3 is $content.
6307
     *  - Returns the return value.
6308
     *  - Returns $content as is,
6309
     *    - if $conf['prefixComment'] is empty.
6310
     *    - if 'config.disablePrefixComment' is configured by the frontend.
6311
     *
6312
     * @test
6313
     * @dataProvider stdWrap_prefixCommentDataProvider
6314
     * @param string $expect
6315
     * @param string $content
6316
     * @param array $conf
6317
     * @param $disable
6318
     * @param int $times
6319
     * @param string $will
6320
     */
6321
    public function stdWrap_prefixComment(
6322
        string $expect,
6323
        string $content,
6324
        array $conf,
6325
        $disable,
6326
        int $times,
6327
        string $will
6328
    ): void {
6329
        $this->frontendControllerMock
6330
            ->config['config']['disablePrefixComment'] = $disable;
0 ignored issues
show
Bug introduced by
Accessing config on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
6331
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6332
            ->onlyMethods(['prefixComment'])->getMock();
6333
        $subject
6334
            ->expects(self::exactly($times))
6335
            ->method('prefixComment')
6336
            ->with($conf['prefixComment'] ?? null, [], $content)
6337
            ->willReturn($will);
6338
        self::assertSame(
6339
            $expect,
6340
            $subject->stdWrap_prefixComment($content, $conf)
6341
        );
6342
    }
6343
6344
    /**
6345
     * Check if stdWrap_prepend works properly.
6346
     *
6347
     * Show:
6348
     *
6349
     * - Delegates to the method cObjGetSingle().
6350
     * - First parameter is $conf['prepend'].
6351
     * - Second parameter is $conf['prepend.'].
6352
     * - Third parameter is '/stdWrap/.prepend'.
6353
     * - Returns the return value prepended to $content.
6354
     *
6355
     * @test
6356
     */
6357
    public function stdWrap_prepend(): void
6358
    {
6359
        $debugKey = '/stdWrap/.prepend';
6360
        $content = StringUtility::getUniqueId('content');
6361
        $conf = [
6362
            'prepend' => StringUtility::getUniqueId('prepend'),
6363
            'prepend.' => [StringUtility::getUniqueId('prepend.')],
6364
        ];
6365
        $return = StringUtility::getUniqueId('return');
6366
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6367
            ->onlyMethods(['cObjGetSingle'])->getMock();
6368
        $subject
6369
            ->expects(self::once())
6370
            ->method('cObjGetSingle')
6371
            ->with($conf['prepend'], $conf['prepend.'], $debugKey)
6372
            ->willReturn($return);
6373
        self::assertSame(
6374
            $return . $content,
6375
            $subject->stdWrap_prepend($content, $conf)
6376
        );
6377
    }
6378
6379
    /**
6380
     * Data provider for stdWrap_prioriCalc
6381
     *
6382
     * @return array [$expect, $content, $conf]
6383
     */
6384
    public function stdWrap_prioriCalcDataProvider(): array
6385
    {
6386
        return [
6387
            'priority of *' => ['7', '1 + 2 * 3', []],
6388
            'priority of parentheses' => ['9', '(1 + 2) * 3', []],
6389
            'float' => ['1.5', '3/2', []],
6390
            'intval casts to int' => [1, '3/2', ['prioriCalc' => 'intval']],
6391
            'intval does not round' => [2, '2.7', ['prioriCalc' => 'intval']],
6392
        ];
6393
    }
6394
6395
    /**
6396
     * Check if stdWrap_prioriCalc works properly.
6397
     *
6398
     * Show:
6399
     *
6400
     * - If $conf['prioriCalc'] is 'intval' the return is casted to int.
6401
     * - Delegates to MathUtility::calculateWithParentheses.
6402
     *
6403
     * Note: As PHPUnit can't mock static methods, the call to
6404
     *       MathUtility::calculateWithParentheses can't be easily intercepted.
6405
     *       The test is done by testing input/output pairs instead. To not
6406
     *       duplicate the testing of calculateWithParentheses just a few
6407
     *       smoke tests are done here.
6408
     *
6409
     * @test
6410
     * @dataProvider stdWrap_prioriCalcDataProvider
6411
     * @param mixed $expect The expected output.
6412
     * @param string $content The given content.
6413
     * @param array $conf The given configuration.
6414
     */
6415
    public function stdWrap_prioriCalc($expect, string $content, array $conf): void
6416
    {
6417
        $result = $this->subject->stdWrap_prioriCalc($content, $conf);
6418
        self::assertSame($expect, $result);
6419
    }
6420
6421
    /**
6422
     * Check if stdWrap_preUserFunc works properly.
6423
     *
6424
     * Show:
6425
     *
6426
     * - Delegates to method callUserFunction.
6427
     * - Parameter 1 is $conf['preUserFunc'].
6428
     * - Parameter 2 is $conf['preUserFunc.'].
6429
     * - Parameter 3 is $content.
6430
     * - Returns the return value.
6431
     *
6432
     * @test
6433
     */
6434
    public function stdWrap_preUserFunc(): void
6435
    {
6436
        $content = StringUtility::getUniqueId('content');
6437
        $conf = [
6438
            'preUserFunc' => StringUtility::getUniqueId('preUserFunc'),
6439
            'preUserFunc.' => [StringUtility::getUniqueId('preUserFunc.')],
6440
        ];
6441
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6442
            ->onlyMethods(['callUserFunction'])->getMock();
6443
        $subject->expects(self::once())->method('callUserFunction')
6444
            ->with($conf['preUserFunc'], $conf['preUserFunc.'], $content)
6445
            ->willReturn('return');
6446
        self::assertSame(
6447
            'return',
6448
            $subject->stdWrap_preUserFunc($content, $conf)
6449
        );
6450
    }
6451
6452
    /**
6453
     * Data provider for stdWrap_rawUrlEncode
6454
     *
6455
     * @return array [$expect, $content].
6456
     */
6457
    public function stdWrap_rawUrlEncodeDataProvider(): array
6458
    {
6459
        return [
6460
            'https://typo3.org?id=10' => [
6461
                'https%3A%2F%2Ftypo3.org%3Fid%3D10',
6462
                'https://typo3.org?id=10',
6463
            ],
6464
            'https://typo3.org?id=10&foo=bar' => [
6465
                'https%3A%2F%2Ftypo3.org%3Fid%3D10%26foo%3Dbar',
6466
                'https://typo3.org?id=10&foo=bar',
6467
            ],
6468
        ];
6469
    }
6470
6471
    /**
6472
     * Check if rawUrlEncode works properly.
6473
     *
6474
     * @test
6475
     * @dataProvider stdWrap_rawUrlEncodeDataProvider
6476
     * @param string $expect The expected output.
6477
     * @param string $content The given input.
6478
     */
6479
    public function stdWrap_rawUrlEncode(string $expect, string $content): void
6480
    {
6481
        self::assertSame(
6482
            $expect,
6483
            $this->subject->stdWrap_rawUrlEncode($content)
6484
        );
6485
    }
6486
6487
    /**
6488
     * Check if stdWrap_replacement works properly.
6489
     *
6490
     * Show:
6491
     *
6492
     * - Delegates to method replacement.
6493
     * - Parameter 1 is $content.
6494
     * - Parameter 2 is $conf['replacement.'].
6495
     * - Returns the return value.
6496
     *
6497
     * @test
6498
     */
6499
    public function stdWrap_replacement(): void
6500
    {
6501
        $content = StringUtility::getUniqueId('content');
6502
        $conf = [
6503
            'replacement' => StringUtility::getUniqueId('not used'),
6504
            'replacement.' => [StringUtility::getUniqueId('replacement.')],
6505
        ];
6506
        $return = StringUtility::getUniqueId('return');
6507
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6508
            ->onlyMethods(['replacement'])->getMock();
6509
        $subject
6510
            ->expects(self::once())
6511
            ->method('replacement')
6512
            ->with($content, $conf['replacement.'])
6513
            ->willReturn($return);
6514
        self::assertSame(
6515
            $return,
6516
            $subject->stdWrap_replacement($content, $conf)
6517
        );
6518
    }
6519
6520
    /**
6521
     * Data provider for stdWrap_required.
6522
     *
6523
     * @return array [$expect, $stop, $content]
6524
     */
6525
    public function stdWrap_requiredDataProvider(): array
6526
    {
6527
        return [
6528
            // empty content
6529
            'empty string is empty' => ['', true, ''],
6530
            'null is empty' => ['', true, null],
6531
            'false is empty' => ['', true, false],
6532
6533
            // non-empty content
6534
            'blank is not empty' => [' ', false, ' '],
6535
            'tab is not empty' => ["\t", false, "\t"],
6536
            'linebreak is not empty' => [PHP_EOL, false, PHP_EOL],
6537
            '"0" is not empty' => ['0', false, '0'],
6538
            '0 is not empty' => [0, false, 0],
6539
            '1 is not empty' => [1, false, 1],
6540
            'true is not empty' => [true, false, true],
6541
        ];
6542
    }
6543
6544
    /**
6545
     * Check if stdWrap_required works properly.
6546
     *
6547
     * Show:
6548
     *
6549
     *  - Content is empty if it equals '' after cast to string.
6550
     *  - Empty content triggers a stop of further rendering.
6551
     *  - Returns the content as is or '' for empty content.
6552
     *
6553
     * @test
6554
     * @dataProvider stdWrap_requiredDataProvider
6555
     * @param mixed $expect The expected output.
6556
     * @param bool $stop Expect stop further rendering.
6557
     * @param mixed $content The given input.
6558
     */
6559
    public function stdWrap_required($expect, bool $stop, $content): void
6560
    {
6561
        $subject = $this->subject;
6562
        $subject->_set('stdWrapRecursionLevel', 1);
6563
        $subject->_set('stopRendering', [1 => false]);
6564
        self::assertSame($expect, $subject->stdWrap_required($content));
6565
        self::assertSame($stop, $subject->_get('stopRendering')[1]);
6566
    }
6567
6568
    /**
6569
     * Check if stdWrap_round works properly
6570
     *
6571
     * Show:
6572
     *
6573
     * - Delegates to method round.
6574
     * - Parameter 1 is $content.
6575
     * - Parameter 2 is $conf['round.'].
6576
     * - Returns the return value.
6577
     *
6578
     * @test
6579
     */
6580
    public function stdWrap_round(): void
6581
    {
6582
        $content = StringUtility::getUniqueId('content');
6583
        $conf = [
6584
            'round' => StringUtility::getUniqueId('not used'),
6585
            'round.' => [StringUtility::getUniqueId('round.')],
6586
        ];
6587
        $return = StringUtility::getUniqueId('return');
6588
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6589
            ->onlyMethods(['round'])->getMock();
6590
        $subject
6591
            ->expects(self::once())
6592
            ->method('round')
6593
            ->with($content, $conf['round.'])
6594
            ->willReturn($return);
6595
        self::assertSame($return, $subject->stdWrap_round($content, $conf));
6596
    }
6597
6598
    /**
6599
     * Check if stdWrap_setContentToCurrent works properly.
6600
     *
6601
     * @test
6602
     */
6603
    public function stdWrap_setContentToCurrent(): void
6604
    {
6605
        $content = StringUtility::getUniqueId('content');
6606
        self::assertNotSame($content, $this->subject->getData('current'));
6607
        self::assertSame(
6608
            $content,
6609
            $this->subject->stdWrap_setContentToCurrent($content)
6610
        );
6611
        self::assertSame($content, $this->subject->getData('current'));
6612
    }
6613
6614
    /**
6615
     * Data provider for stdWrap_setCurrent
6616
     *
6617
     * @return array Order input, conf
6618
     */
6619
    public function stdWrap_setCurrentDataProvider(): array
6620
    {
6621
        return [
6622
            'no conf' => [
6623
                'content',
6624
                [],
6625
            ],
6626
            'empty string' => [
6627
                'content',
6628
                ['setCurrent' => ''],
6629
            ],
6630
            'non-empty string' => [
6631
                'content',
6632
                ['setCurrent' => 'xxx'],
6633
            ],
6634
            'integer null' => [
6635
                'content',
6636
                ['setCurrent' => 0],
6637
            ],
6638
            'integer not null' => [
6639
                'content',
6640
                ['setCurrent' => 1],
6641
            ],
6642
            'boolean true' => [
6643
                'content',
6644
                ['setCurrent' => true],
6645
            ],
6646
            'boolean false' => [
6647
                'content',
6648
                ['setCurrent' => false],
6649
            ],
6650
        ];
6651
    }
6652
6653
    /**
6654
     * Check if stdWrap_setCurrent works properly.
6655
     *
6656
     * @test
6657
     * @dataProvider stdWrap_setCurrentDataProvider
6658
     * @param string $input The input value.
6659
     * @param array $conf Property: setCurrent
6660
     */
6661
    public function stdWrap_setCurrent(string $input, array $conf): void
6662
    {
6663
        if (isset($conf['setCurrent'])) {
6664
            self::assertNotSame($conf['setCurrent'], $this->subject->getData('current'));
6665
        }
6666
        self::assertSame($input, $this->subject->stdWrap_setCurrent($input, $conf));
6667
        if (isset($conf['setCurrent'])) {
6668
            self::assertSame($conf['setCurrent'], $this->subject->getData('current'));
6669
        }
6670
    }
6671
6672
    /**
6673
     * Check if stdWrap_split works properly.
6674
     *
6675
     * Show:
6676
     *
6677
     * - Delegates to method splitObj.
6678
     * - Parameter 1 is $content.
6679
     * - Parameter 2 is $conf['split.'].
6680
     * - Returns the return value.
6681
     *
6682
     * @test
6683
     */
6684
    public function stdWrap_split(): void
6685
    {
6686
        $content = StringUtility::getUniqueId('content');
6687
        $conf = [
6688
            'split' => StringUtility::getUniqueId('not used'),
6689
            'split.' => [StringUtility::getUniqueId('split.')],
6690
        ];
6691
        $return = StringUtility::getUniqueId('return');
6692
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6693
            ->onlyMethods(['splitObj'])->getMock();
6694
        $subject
6695
            ->expects(self::once())
6696
            ->method('splitObj')
6697
            ->with($content, $conf['split.'])
6698
            ->willReturn($return);
6699
        self::assertSame(
6700
            $return,
6701
            $subject->stdWrap_split($content, $conf)
6702
        );
6703
    }
6704
6705
    /**
6706
     * Check that stdWrap_stdWrap works properly.
6707
     *
6708
     * Show:
6709
     *  - Delegates to method stdWrap.
6710
     *  - Parameter 1 is $content.
6711
     *  - Parameter 2 is $conf['stdWrap.'].
6712
     *  - Returns the return value.
6713
     *
6714
     * @test
6715
     */
6716
    public function stdWrap_stdWrap(): void
6717
    {
6718
        $content = StringUtility::getUniqueId('content');
6719
        $conf = [
6720
            'stdWrap' => StringUtility::getUniqueId('not used'),
6721
            'stdWrap.' => [StringUtility::getUniqueId('stdWrap.')],
6722
        ];
6723
        $return = StringUtility::getUniqueId('return');
6724
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
6725
            ->onlyMethods(['stdWrap'])->getMock();
6726
        $subject
6727
            ->expects(self::once())
6728
            ->method('stdWrap')
6729
            ->with($content, $conf['stdWrap.'])
6730
            ->willReturn($return);
6731
        self::assertSame($return, $subject->stdWrap_stdWrap($content, $conf));
6732
    }
6733
6734
    /**
6735
     * Data provider for stdWrap_stdWrapValue test
6736
     *
6737
     * @return array
6738
     */
6739
    public function stdWrap_stdWrapValueDataProvider(): array
6740
    {
6741
        return [
6742
            'only key returns value' => [
6743
                'ifNull',
6744
                [
6745
                    'ifNull' => '1',
6746
                ],
6747
                '',
6748
                '1',
6749
            ],
6750
            'array without key returns empty string' => [
6751
                'ifNull',
6752
                [
6753
                    'ifNull.' => '1',
6754
                ],
6755
                '',
6756
                '',
6757
            ],
6758
            'array without key returns default' => [
6759
                'ifNull',
6760
                [
6761
                    'ifNull.' => '1',
6762
                ],
6763
                'default',
6764
                'default',
6765
            ],
6766
            'non existing key returns default' => [
6767
                'ifNull',
6768
                [
6769
                    'noTrimWrap' => 'test',
6770
                    'noTrimWrap.' => '1',
6771
                ],
6772
                'default',
6773
                'default',
6774
            ],
6775
            'default value null is returned' => [
6776
                'ifNull',
6777
                [],
6778
                null,
6779
                null,
6780
            ],
6781
            'existing key and array returns stdWrap' => [
6782
                'test',
6783
                [
6784
                    'test' => 'value',
6785
                    'test.' => ['case' => 'upper'],
6786
                ],
6787
                'default',
6788
                'VALUE',
6789
            ],
6790
            'the string "0" from stdWrap will be returned' => [
6791
                'test',
6792
                [
6793
                    'test' => '',
6794
                    'test.' => [
6795
                        'wrap' => '|0',
6796
                    ],
6797
                ],
6798
                '100',
6799
                '0',
6800
            ],
6801
        ];
6802
    }
6803
6804
    /**
6805
     * @param string $key
6806
     * @param array $configuration
6807
     * @param string|null $defaultValue
6808
     * @param string|null $expected
6809
     * @dataProvider stdWrap_stdWrapValueDataProvider
6810
     * @test
6811
     */
6812
    public function stdWrap_stdWrapValue(
6813
        string $key,
6814
        array $configuration,
6815
        ?string $defaultValue,
6816
        ?string $expected
6817
    ): void {
6818
        $result = $this->subject->stdWrapValue($key, $configuration, $defaultValue);
6819
        self::assertSame($expected, $result);
6820
    }
6821
6822
    /**
6823
     * Data provider for stdWrap_strPad.
6824
     *
6825
     * @return array [$expect, $content, $conf]
6826
     */
6827
    public function stdWrap_strPadDataProvider(): array
6828
    {
6829
        return [
6830
            'pad string with default settings and length 10' => [
6831
                'Alien     ',
6832
                'Alien',
6833
                [
6834
                    'length' => '10',
6835
                ],
6836
            ],
6837
            'pad string with default settings and length 10 and multibyte character' => [
6838
                'Älien     ',
6839
                'Älien',
6840
                [
6841
                    'length' => '10',
6842
                ],
6843
            ],
6844
            'pad string with padWith -= and type left and length 10' => [
6845
                '-=-=-Alien',
6846
                'Alien',
6847
                [
6848
                    'length' => '10',
6849
                    'padWith' => '-=',
6850
                    'type' => 'left',
6851
                ],
6852
            ],
6853
            'pad string with padWith äö and type left and length 10 and multibyte characters' => [
6854
                'äöäöäÄlien',
6855
                'Älien',
6856
                [
6857
                    'length' => '10',
6858
                    'padWith' => 'äö',
6859
                    'type' => 'left',
6860
                ],
6861
            ],
6862
            'pad string with padWith _ and type both and length 10' => [
6863
                '__Alien___',
6864
                'Alien',
6865
                [
6866
                    'length' => '10',
6867
                    'padWith' => '_',
6868
                    'type' => 'both',
6869
                ],
6870
            ],
6871
            'pad string with padWith 0 and type both and length 10' => [
6872
                '00Alien000',
6873
                'Alien',
6874
                [
6875
                    'length' => '10',
6876
                    'padWith' => '0',
6877
                    'type' => 'both',
6878
                ],
6879
            ],
6880
            'pad string with padWith ___ and type both and length 6' => [
6881
                'Alien_',
6882
                'Alien',
6883
                [
6884
                    'length' => '6',
6885
                    'padWith' => '___',
6886
                    'type' => 'both',
6887
                ],
6888
            ],
6889
            'pad string with padWith _ and type both and length 12, using stdWrap for length' => [
6890
                '___Alien____',
6891
                'Alien',
6892
                [
6893
                    'length' => '1',
6894
                    'length.' => [
6895
                        'wrap' => '|2',
6896
                    ],
6897
                    'padWith' => '_',
6898
                    'type' => 'both',
6899
                ],
6900
            ],
6901
            'pad string with padWith _ and type both and length 12, using stdWrap for padWidth' => [
6902
                '-_=Alien-_=-',
6903
                'Alien',
6904
                [
6905
                    'length' => '12',
6906
                    'padWith' => '_',
6907
                    'padWith.' => [
6908
                        'wrap' => '-|=',
6909
                    ],
6910
                    'type' => 'both',
6911
                ],
6912
            ],
6913
            'pad string with padWith _ and type both and length 12, using stdWrap for type' => [
6914
                '_______Alien',
6915
                'Alien',
6916
                [
6917
                    'length' => '12',
6918
                    'padWith' => '_',
6919
                    'type' => 'both',
6920
                    // make type become "left"
6921
                    'type.' => [
6922
                        'substring' => '2,1',
6923
                        'wrap' => 'lef|',
6924
                    ],
6925
                ],
6926
            ],
6927
        ];
6928
    }
6929
6930
    /**
6931
     * Check if stdWrap_strPad works properly.
6932
     *
6933
     * @test
6934
     * @dataProvider stdWrap_strPadDataProvider
6935
     * @param string $expect The expected output.
6936
     * @param string $content The given input.
6937
     * @param array $conf The configuration of 'strPad.'.
6938
     */
6939
    public function stdWrap_strPad(string $expect, string $content, array $conf): void
6940
    {
6941
        $conf = ['strPad.' => $conf];
6942
        $result = $this->subject->stdWrap_strPad($content, $conf);
6943
        self::assertSame($expect, $result);
6944
    }
6945
6946
    /**
6947
     * Data provider for stdWrap_strftime
6948
     *
6949
     * @return array [$expect, $content, $conf, $now]
6950
     */
6951
    public function stdWrap_strftimeDataProvider(): array
6952
    {
6953
        // Fictive execution time is 2012-09-01 12:00 in UTC/GMT.
6954
        $now = 1346500800;
6955
        return [
6956
            'given timestamp' => [
6957
                '01-09-2012',
6958
                $now,
6959
                ['strftime' => '%d-%m-%Y'],
6960
                $now,
6961
            ],
6962
            'empty string' => [
6963
                '01-09-2012',
6964
                '',
6965
                ['strftime' => '%d-%m-%Y'],
6966
                $now,
6967
            ],
6968
            'testing null' => [
6969
                '01-09-2012',
6970
                null,
6971
                ['strftime' => '%d-%m-%Y'],
6972
                $now,
6973
            ],
6974
        ];
6975
    }
6976
6977
    /**
6978
     * Check if stdWrap_strftime works properly.
6979
     *
6980
     * @test
6981
     * @dataProvider stdWrap_strftimeDataProvider
6982
     * @param string $expect The expected output.
6983
     * @param mixed $content The given input.
6984
     * @param array $conf The given configuration.
6985
     * @param int $now Fictive execution time.
6986
     */
6987
    public function stdWrap_strftime(string $expect, $content, array $conf, int $now): void
6988
    {
6989
        // Save current timezone and set to UTC to make the system under test
6990
        // behave the same in all server timezone settings
6991
        $timezoneBackup = date_default_timezone_get();
6992
        date_default_timezone_set('UTC');
6993
6994
        $GLOBALS['EXEC_TIME'] = $now;
6995
        $result = $this->subject->stdWrap_strftime($content, $conf);
6996
6997
        // Reset timezone
6998
        date_default_timezone_set($timezoneBackup);
6999
7000
        self::assertSame($expect, $result);
7001
    }
7002
7003
    /**
7004
     * Test for the stdWrap_stripHtml
7005
     *
7006
     * @test
7007
     */
7008
    public function stdWrap_stripHtml(): void
7009
    {
7010
        $content = '<html><p>Hello <span class="inline">inline tag<span>!</p><p>Hello!</p></html>';
7011
        $expected = 'Hello inline tag!Hello!';
7012
        self::assertSame($expected, $this->subject->stdWrap_stripHtml($content));
7013
    }
7014
7015
    /**
7016
     * Data provider for the stdWrap_strtotime test
7017
     *
7018
     * @return array [$expect, $content, $conf]
7019
     */
7020
    public function stdWrap_strtotimeDataProvider(): array
7021
    {
7022
        return [
7023
            'date from content' => [
7024
                1417651200,
7025
                '2014-12-04',
7026
                ['strtotime' => '1'],
7027
            ],
7028
            'manipulation of date from content' => [
7029
                1417996800,
7030
                '2014-12-04',
7031
                ['strtotime' => '+ 2 weekdays'],
7032
            ],
7033
            'date from configuration' => [
7034
                1417651200,
7035
                '',
7036
                ['strtotime' => '2014-12-04'],
7037
            ],
7038
            'manipulation of date from configuration' => [
7039
                1417996800,
7040
                '',
7041
                ['strtotime' => '2014-12-04 + 2 weekdays'],
7042
            ],
7043
            'empty input' => [
7044
                false,
7045
                '',
7046
                ['strtotime' => '1'],
7047
            ],
7048
            'date from content and configuration' => [
7049
                false,
7050
                '2014-12-04',
7051
                ['strtotime' => '2014-12-05'],
7052
            ],
7053
        ];
7054
    }
7055
7056
    /**
7057
     * Check if stdWrap_strtotime works properly.
7058
     *
7059
     * @test
7060
     * @dataProvider stdWrap_strtotimeDataProvider
7061
     * @param mixed $expect The expected output.
7062
     * @param string $content The given input.
7063
     * @param array $conf The given configuration.
7064
     */
7065
    public function stdWrap_strtotime($expect, string $content, array $conf): void
7066
    {
7067
        // Set exec_time to a hard timestamp
7068
        $GLOBALS['EXEC_TIME'] = 1417392000;
7069
        // Save current timezone and set to UTC to make the system under test
7070
        // behave the same in all server timezone settings
7071
        $timezoneBackup = date_default_timezone_get();
7072
        date_default_timezone_set('UTC');
7073
7074
        $result = $this->subject->stdWrap_strtotime($content, $conf);
7075
7076
        // Reset timezone
7077
        date_default_timezone_set($timezoneBackup);
7078
7079
        self::assertEquals($expect, $result);
7080
    }
7081
7082
    /**
7083
     * Check if stdWrap_substring works properly.
7084
     *
7085
     * Show:
7086
     *
7087
     * - Delegates to method substring.
7088
     * - Parameter 1 is $content.
7089
     * - Parameter 2 is $conf['substring'].
7090
     * - Returns the return value.
7091
     *
7092
     * @test
7093
     */
7094
    public function stdWrap_substring(): void
7095
    {
7096
        $content = StringUtility::getUniqueId('content');
7097
        $conf = [
7098
            'substring' => StringUtility::getUniqueId('substring'),
7099
            'substring.' => StringUtility::getUniqueId('not used'),
7100
        ];
7101
        $return = StringUtility::getUniqueId('return');
7102
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
7103
            ->onlyMethods(['substring'])->getMock();
7104
        $subject
7105
            ->expects(self::once())
7106
            ->method('substring')
7107
            ->with($content, $conf['substring'])
7108
            ->willReturn($return);
7109
        self::assertSame(
7110
            $return,
7111
            $subject->stdWrap_substring($content, $conf)
7112
        );
7113
    }
7114
7115
    /**
7116
     * Data provider for stdWrap_trim.
7117
     *
7118
     * @return array [$expect, $content]
7119
     */
7120
    public function stdWrap_trimDataProvider(): array
7121
    {
7122
        return [
7123
            // string not trimmed
7124
            'empty string' => ['', ''],
7125
            'string without whitespace' => ['xxx', 'xxx'],
7126
            'string with whitespace inside' => [
7127
                'xx ' . "\t" . ' xx',
7128
                'xx ' . "\t" . ' xx',
7129
            ],
7130
            'string with newlines inside' => [
7131
                'xx ' . PHP_EOL . ' xx',
7132
                'xx ' . PHP_EOL . ' xx',
7133
            ],
7134
            // string trimmed
7135
            'blanks around' => ['xxx', '  xxx  '],
7136
            'tabs around' => ['xxx', "\t" . 'xxx' . "\t"],
7137
            'newlines around' => ['xxx', PHP_EOL . 'xxx' . PHP_EOL],
7138
            'mixed case' => ['xxx', "\t" . ' xxx ' . PHP_EOL],
7139
            // non strings
7140
            'null' => ['', null],
7141
            'false' => ['', false],
7142
            'true' => ['1', true],
7143
            'zero' => ['0', 0],
7144
            'one' => ['1', 1],
7145
            '-1' => ['-1', -1],
7146
            '0.0' => ['0', 0.0],
7147
            '1.0' => ['1', 1.0],
7148
            '-1.0' => ['-1', -1.0],
7149
            '1.1' => ['1.1', 1.1],
7150
        ];
7151
    }
7152
7153
    /**
7154
     * Check that stdWrap_trim works properly.
7155
     *
7156
     * Show:
7157
     *
7158
     *  - the given string is trimmed like PHP trim
7159
     *  - non-strings are casted to strings:
7160
     *    - null => 'null'
7161
     *    - false => ''
7162
     *    - true => '1'
7163
     *    - 0 => '0'
7164
     *    - -1 => '-1'
7165
     *    - 1.0 => '1'
7166
     *    - 1.1 => '1.1'
7167
     *
7168
     * @test
7169
     * @dataProvider stdWrap_trimDataProvider
7170
     * @param string $expect
7171
     * @param mixed $content The given content.
7172
     */
7173
    public function stdWrap_trim(string $expect, $content): void
7174
    {
7175
        $result = $this->subject->stdWrap_trim($content);
7176
        self::assertSame($expect, $result);
7177
    }
7178
7179
    /**
7180
     * Check that stdWrap_typolink works properly.
7181
     *
7182
     * Show:
7183
     *  - Delegates to method typolink.
7184
     *  - Parameter 1 is $content.
7185
     *  - Parameter 2 is $conf['typolink.'].
7186
     *  - Returns the return value.
7187
     *
7188
     * @test
7189
     */
7190
    public function stdWrap_typolink(): void
7191
    {
7192
        $content = StringUtility::getUniqueId('content');
7193
        $conf = [
7194
            'typolink' => StringUtility::getUniqueId('not used'),
7195
            'typolink.' => [StringUtility::getUniqueId('typolink.')],
7196
        ];
7197
        $return = StringUtility::getUniqueId('return');
7198
        $subject = $this->getMockBuilder(ContentObjectRenderer::class)
7199
            ->onlyMethods(['typolink'])->getMock();
7200
        $subject
7201
            ->expects(self::once())
7202
            ->method('typolink')
7203
            ->with($content, $conf['typolink.'])
7204
            ->willReturn($return);
7205
        self::assertSame($return, $subject->stdWrap_typolink($content, $conf));
7206
    }
7207
7208
    /**
7209
     * Data provider for stdWrap_wrap
7210
     *
7211
     * @return array Order expected, input, conf
7212
     */
7213
    public function stdWrap_wrapDataProvider(): array
7214
    {
7215
        return [
7216
            'no conf' => [
7217
                'XXX',
7218
                'XXX',
7219
                [],
7220
            ],
7221
            'simple' => [
7222
                '<wrapper>XXX</wrapper>',
7223
                'XXX',
7224
                ['wrap' => '<wrapper>|</wrapper>'],
7225
            ],
7226
            'trims whitespace' => [
7227
                '<wrapper>XXX</wrapper>',
7228
                'XXX',
7229
                ['wrap' => '<wrapper>' . "\t" . ' | ' . "\t" . '</wrapper>'],
7230
            ],
7231
            'missing pipe puts wrap before' => [
7232
                '<pre>XXX',
7233
                'XXX',
7234
                [
7235
                    'wrap' => '<pre>',
7236
                ],
7237
            ],
7238
            'split char change' => [
7239
                '<wrapper>XXX</wrapper>',
7240
                'XXX',
7241
                [
7242
                    'wrap' => '<wrapper> # </wrapper>',
7243
                    'wrap.' => ['splitChar' => '#'],
7244
                ],
7245
            ],
7246
            'split by pattern' => [
7247
                '<wrapper>XXX</wrapper>',
7248
                'XXX',
7249
                [
7250
                    'wrap' => '<wrapper> ###splitter### </wrapper>',
7251
                    'wrap.' => ['splitChar' => '###splitter###'],
7252
                ],
7253
            ],
7254
        ];
7255
    }
7256
7257
    /**
7258
     * Check if stdWrap_wrap works properly.
7259
     *
7260
     * @param string $expected The expected value.
7261
     * @param string $input The input value.
7262
     * @param array $conf Properties: wrap, wrap.splitChar
7263
     * @test
7264
     * @dataProvider stdWrap_wrapDataProvider
7265
     */
7266
    public function stdWrap_wrap(string $expected, string $input, array $conf): void
7267
    {
7268
        self::assertSame(
7269
            $expected,
7270
            $this->subject->stdWrap_wrap($input, $conf)
7271
        );
7272
    }
7273
7274
    /**
7275
     * Data provider for stdWrap_wrap2
7276
     *
7277
     * @return array Order expected, input, conf
7278
     */
7279
    public function stdWrap_wrap2DataProvider(): array
7280
    {
7281
        return [
7282
            'no conf' => [
7283
                'XXX',
7284
                'XXX',
7285
                [],
7286
            ],
7287
            'simple' => [
7288
                '<wrapper>XXX</wrapper>',
7289
                'XXX',
7290
                ['wrap2' => '<wrapper>|</wrapper>'],
7291
            ],
7292
            'trims whitespace' => [
7293
                '<wrapper>XXX</wrapper>',
7294
                'XXX',
7295
                ['wrap2' => '<wrapper>' . "\t" . ' | ' . "\t" . '</wrapper>'],
7296
            ],
7297
            'missing pipe puts wrap2 before' => [
7298
                '<pre>XXX',
7299
                'XXX',
7300
                [
7301
                    'wrap2' => '<pre>',
7302
                ],
7303
            ],
7304
            'split char change' => [
7305
                '<wrapper>XXX</wrapper>',
7306
                'XXX',
7307
                [
7308
                    'wrap2' => '<wrapper> # </wrapper>',
7309
                    'wrap2.' => ['splitChar' => '#'],
7310
                ],
7311
            ],
7312
            'split by pattern' => [
7313
                '<wrapper>XXX</wrapper>',
7314
                'XXX',
7315
                [
7316
                    'wrap2' => '<wrapper> ###splitter### </wrapper>',
7317
                    'wrap2.' => ['splitChar' => '###splitter###'],
7318
                ],
7319
            ],
7320
        ];
7321
    }
7322
7323
    /**
7324
     * Check if stdWrap_wrap2 works properly.
7325
     *
7326
     * @param string $expected The expected value.
7327
     * @param string $input The input value.
7328
     * @param array $conf Properties: wrap2, wrap2.splitChar
7329
     * @test
7330
     * @dataProvider stdWrap_wrap2DataProvider
7331
     */
7332
    public function stdWrap_wrap2(string $expected, string $input, array $conf): void
7333
    {
7334
        self::assertSame($expected, $this->subject->stdWrap_wrap2($input, $conf));
7335
    }
7336
7337
    /**
7338
     * Data provider for stdWrap_wrap3
7339
     *
7340
     * @return array Order expected, input, conf
7341
     */
7342
    public function stdWrap_wrap3DataProvider(): array
7343
    {
7344
        return [
7345
            'no conf' => [
7346
                'XXX',
7347
                'XXX',
7348
                [],
7349
            ],
7350
            'simple' => [
7351
                '<wrapper>XXX</wrapper>',
7352
                'XXX',
7353
                ['wrap3' => '<wrapper>|</wrapper>'],
7354
            ],
7355
            'trims whitespace' => [
7356
                '<wrapper>XXX</wrapper>',
7357
                'XXX',
7358
                ['wrap3' => '<wrapper>' . "\t" . ' | ' . "\t" . '</wrapper>'],
7359
            ],
7360
            'missing pipe puts wrap3 before' => [
7361
                '<pre>XXX',
7362
                'XXX',
7363
                [
7364
                    'wrap3' => '<pre>',
7365
                ],
7366
            ],
7367
            'split char change' => [
7368
                '<wrapper>XXX</wrapper>',
7369
                'XXX',
7370
                [
7371
                    'wrap3' => '<wrapper> # </wrapper>',
7372
                    'wrap3.' => ['splitChar' => '#'],
7373
                ],
7374
            ],
7375
            'split by pattern' => [
7376
                '<wrapper>XXX</wrapper>',
7377
                'XXX',
7378
                [
7379
                    'wrap3' => '<wrapper> ###splitter### </wrapper>',
7380
                    'wrap3.' => ['splitChar' => '###splitter###'],
7381
                ],
7382
            ],
7383
        ];
7384
    }
7385
7386
    /**
7387
     * Check if stdWrap_wrap3 works properly.
7388
     *
7389
     * @param string $expected The expected value.
7390
     * @param string $input The input value.
7391
     * @param array $conf Properties: wrap3, wrap3.splitChar
7392
     * @test
7393
     * @dataProvider stdWrap_wrap3DataProvider
7394
     */
7395
    public function stdWrap_wrap3(string $expected, string $input, array $conf): void
7396
    {
7397
        self::assertSame($expected, $this->subject->stdWrap_wrap3($input, $conf));
7398
    }
7399
7400
    /**
7401
     * Data provider for stdWrap_wrapAlign.
7402
     *
7403
     * @return array [$expect, $content, $conf]
7404
     */
7405
    public function stdWrap_wrapAlignDataProvider(): array
7406
    {
7407
        $format = '<div style="text-align:%s;">%s</div>';
7408
        $content = StringUtility::getUniqueId('content');
7409
        $wrapAlign = StringUtility::getUniqueId('wrapAlign');
7410
        $expect = sprintf($format, $wrapAlign, $content);
7411
        return [
7412
            'standard case' => [$expect, $content, $wrapAlign],
7413
            'empty conf' => [$content, $content, null],
7414
            'empty string' => [$content, $content, ''],
7415
            'whitespaced zero string' => [$content, $content, ' 0 '],
7416
        ];
7417
    }
7418
7419
    /**
7420
     * Check if stdWrap_wrapAlign works properly.
7421
     *
7422
     * Show:
7423
     *
7424
     * - Wraps $content with div and style attribute.
7425
     * - The style attribute is taken from $conf['wrapAlign'].
7426
     * - Returns the content as is,
7427
     * - if $conf['wrapAlign'] evals to false after being trimmed.
7428
     *
7429
     * @test
7430
     * @dataProvider stdWrap_wrapAlignDataProvider
7431
     * @param string $expect The expected output.
7432
     * @param string $content The given content.
7433
     * @param mixed $wrapAlignConf The given input.
7434
     */
7435
    public function stdWrap_wrapAlign(string $expect, string $content, $wrapAlignConf): void
7436
    {
7437
        $conf = [];
7438
        if ($wrapAlignConf !== null) {
7439
            $conf['wrapAlign'] = $wrapAlignConf;
7440
        }
7441
        self::assertSame(
7442
            $expect,
7443
            $this->subject->stdWrap_wrapAlign($content, $conf)
7444
        );
7445
    }
7446
7447
    /***************************************************************************
7448
     * End of tests of stdWrap in alphabetical order
7449
     ***************************************************************************/
7450
7451
    /***************************************************************************
7452
     * Begin: Mixed tests
7453
     *
7454
     * - Add new tests here that still don't have a better place in this class.
7455
     * - Place tests in alphabetical order.
7456
     * - Place data provider above test method.
7457
     ***************************************************************************/
7458
7459
    /**
7460
     * Check if getCurrentTable works properly.
7461
     *
7462
     * @test
7463
     */
7464
    public function getCurrentTable(): void
7465
    {
7466
        self::assertEquals('tt_content', $this->subject->getCurrentTable());
7467
    }
7468
7469
    /**
7470
     * Data provider for prefixComment.
7471
     *
7472
     * @return array [$expect, $comment, $content]
7473
     */
7474
    public function prefixCommentDataProvider(): array
7475
    {
7476
        $comment = StringUtility::getUniqueId();
7477
        $content = StringUtility::getUniqueId();
7478
        $format = '%s';
7479
        $format .= '%%s<!-- %%s [begin] -->%s';
7480
        $format .= '%%s%s%%s%s';
7481
        $format .= '%%s<!-- %%s [end] -->%s';
7482
        $format .= '%%s%s';
7483
        $format = sprintf($format, LF, LF, "\t", LF, LF, "\t");
7484
        $indent1 = "\t";
7485
        $indent2 = "\t" . "\t";
7486
        return [
7487
            'indent one tab' => [
7488
                sprintf(
7489
                    $format,
7490
                    $indent1,
7491
                    $comment,
7492
                    $indent1,
7493
                    $content,
7494
                    $indent1,
7495
                    $comment,
7496
                    $indent1
7497
                ),
7498
                '1|' . $comment,
7499
                $content,
7500
            ],
7501
            'indent two tabs' => [
7502
                sprintf(
7503
                    $format,
7504
                    $indent2,
7505
                    $comment,
7506
                    $indent2,
7507
                    $content,
7508
                    $indent2,
7509
                    $comment,
7510
                    $indent2
7511
                ),
7512
                '2|' . $comment,
7513
                $content,
7514
            ],
7515
            'htmlspecialchars applies for comment only' => [
7516
                sprintf(
7517
                    $format,
7518
                    $indent1,
7519
                    '&lt;' . $comment . '&gt;',
7520
                    $indent1,
7521
                    '<' . $content . '>',
7522
                    $indent1,
7523
                    '&lt;' . $comment . '&gt;',
7524
                    $indent1
7525
                ),
7526
                '1|<' . $comment . '>',
7527
                '<' . $content . '>',
7528
            ],
7529
        ];
7530
    }
7531
7532
    /**
7533
     * Check if prefixComment works properly.
7534
     *
7535
     * @test
7536
     * @dataProvider prefixCommentDataProvider
7537
     * @param string $expect The expected output.
7538
     * @param string $comment The parameter $comment.
7539
     * @param string $content The parameter $content.
7540
     */
7541
    public function prefixComment(string $expect, string $comment, string $content): void
7542
    {
7543
        // The parameter $conf is never used. Just provide null.
7544
        // Consider to improve the signature and deprecate the old one.
7545
        $result = $this->subject->prefixComment($comment, null, $content);
7546
        self::assertEquals($expect, $result);
7547
    }
7548
7549
    /**
7550
     * Check setter and getter of currentFile work properly.
7551
     *
7552
     * @test
7553
     */
7554
    public function setCurrentFile_getCurrentFile(): void
7555
    {
7556
        $storageMock = $this->createMock(ResourceStorage::class);
7557
        $file = new File(['testfile'], $storageMock);
7558
        $this->subject->setCurrentFile($file);
7559
        self::assertSame($file, $this->subject->getCurrentFile());
7560
    }
7561
7562
    /**
7563
     * Check setter and getter of currentVal work properly.
7564
     *
7565
     * Show it stored to $this->data[$this->currentValKey].
7566
     * (The default value of currentValKey is tested elsewhere.)
7567
     *
7568
     * @test
7569
     * @see stdWrap_current()
7570
     */
7571
    public function setCurrentVal_getCurrentVal(): void
7572
    {
7573
        $key = StringUtility::getUniqueId();
7574
        $value = StringUtility::getUniqueId();
7575
        $this->subject->currentValKey = $key;
0 ignored issues
show
Bug introduced by
Accessing currentValKey on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
7576
        $this->subject->setCurrentVal($value);
7577
        self::assertEquals($value, $this->subject->getCurrentVal());
7578
        self::assertEquals($value, $this->subject->data[$key]);
0 ignored issues
show
Bug introduced by
Accessing data on the interface PHPUnit\Framework\MockObject\MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
7579
    }
7580
7581
    /**
7582
     * Check setter and getter of userObjectType work properly.
7583
     *
7584
     * @test
7585
     */
7586
    public function setUserObjectType_getUserObjectType(): void
7587
    {
7588
        $value = StringUtility::getUniqueId();
7589
        $this->subject->setUserObjectType($value);
7590
        self::assertEquals($value, $this->subject->getUserObjectType());
7591
    }
7592
7593
    /**
7594
     * Data provider for emailSpamProtectionWithTypeAscii
7595
     *
7596
     * @return array [$content, $expect]
7597
     */
7598
    public function emailSpamProtectionWithTypeAsciiDataProvider(): array
7599
    {
7600
        return [
7601
            'Simple email address' => [
7602
                '[email protected]',
7603
                '&#116;&#101;&#115;&#116;&#64;&#101;&#109;&#97;&#105;&#108;&#46;&#116;&#108;&#100;',
7604
            ],
7605
            'Simple email address with unicode characters' => [
7606
                'matthä[email protected]',
7607
                '&#109;&#97;&#116;&#116;&#104;&#228;&#117;&#115;&#64;&#101;&#109;&#97;&#105;&#108;&#46;&#116;&#108;&#100;',
7608
            ],
7609
            'Susceptible email address' => [
7610
                '"><script>alert(\'emailSpamProtection\')</script>',
7611
                '&#34;&#62;&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#101;&#109;&#97;&#105;&#108;&#83;&#112;&#97;&#109;&#80;&#114;&#111;&#116;&#101;&#99;&#116;&#105;&#111;&#110;&#39;&#41;&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;',
7612
7613
            ],
7614
            'Susceptible email address with unicode characters' => [
7615
                '"><script>alert(\'ȅmǡilSpamProtȅction\')</script>',
7616
                '&#34;&#62;&#60;&#115;&#99;&#114;&#105;&#112;&#116;&#62;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#517;&#109;&#481;&#105;&#108;&#83;&#112;&#97;&#109;&#80;&#114;&#111;&#116;&#517;&#99;&#116;&#105;&#111;&#110;&#39;&#41;&#60;&#47;&#115;&#99;&#114;&#105;&#112;&#116;&#62;',
7617
            ],
7618
        ];
7619
    }
7620
7621
    /**
7622
     * Check if email spam protection processes all UTF-8 characters properly
7623
     *
7624
     * @test
7625
     * @dataProvider emailSpamProtectionWithTypeAsciiDataProvider
7626
     * @param string $content The parameter $content.
7627
     * @param string $expected The expected output.
7628
     */
7629
    public function mailSpamProtectionWithTypeAscii(string $content, string $expected): void
7630
    {
7631
        self::assertSame(
7632
            $expected,
7633
            $this->subject->_call('encryptEmail', $content, 'ascii')
7634
        );
7635
    }
7636
7637
    public function getGlobalDataProvider(): array
7638
    {
7639
        return [
7640
            'simple' => [
7641
                'foo',
7642
                'HTTP_SERVER_VARS | something',
7643
                [
7644
                    'HTTP_SERVER_VARS' => [
7645
                        'something' => 'foo',
7646
                    ],
7647
                ],
7648
                null,
7649
            ],
7650
            'simple source fallback' => [
7651
                'foo',
7652
                'HTTP_SERVER_VARS | something',
7653
                null,
7654
                [
7655
                    'HTTP_SERVER_VARS' => [
7656
                        'something' => 'foo',
7657
                    ],
7658
                ],
7659
            ],
7660
            'globals ignored if source given' => [
7661
                '',
7662
                'HTTP_SERVER_VARS | something',
7663
                [
7664
                    'HTTP_SERVER_VARS' => [
7665
                        'something' => 'foo',
7666
                    ],
7667
                ],
7668
                [
7669
                    'HTTP_SERVER_VARS' => [
7670
                        'something-else' => 'foo',
7671
                    ],
7672
                ],
7673
            ],
7674
            'sub array is returned as empty string' => [
7675
                '',
7676
                'HTTP_SERVER_VARS | something',
7677
                [
7678
                    'HTTP_SERVER_VARS' => [
7679
                        'something' => ['foo'],
7680
                    ],
7681
                ],
7682
                null,
7683
            ],
7684
            'does not exist' => [
7685
                '',
7686
                'HTTP_SERVER_VARS | something',
7687
                [
7688
                    'HTTP_SERVER_VARS' => [
7689
                        'something-else' => 'foo',
7690
                    ],
7691
                ],
7692
                null,
7693
            ],
7694
            'does not exist in source' => [
7695
                '',
7696
                'HTTP_SERVER_VARS | something',
7697
                null,
7698
                [
7699
                    'HTTP_SERVER_VARS' => [
7700
                        'something-else' => 'foo',
7701
                    ],
7702
                ],
7703
            ],
7704
        ];
7705
    }
7706
7707
    /**
7708
     * @test
7709
     * @dataProvider getGlobalDataProvider
7710
     * @param mixed $expected
7711
     * @param string $key
7712
     * @param array|null $globals
7713
     * @param array|null $source
7714
     */
7715
    public function getGlobalReturnsExpectedResult($expected, string $key, ?array $globals, ?array $source): void
7716
    {
7717
        if (isset($globals['HTTP_SERVER_VARS'])) {
7718
            // Note we can't simply $GLOBALS = $globals, since phpunit backupGlobals works on existing array keys.
7719
            $GLOBALS['HTTP_SERVER_VARS'] = $globals['HTTP_SERVER_VARS'];
7720
        }
7721
        self::assertSame(
7722
            $expected,
7723
            (new ContentObjectRenderer())->getGlobal($key, $source)
7724
        );
7725
    }
7726
7727
    /***************************************************************************
7728
     * End: Mixed tests
7729
     ***************************************************************************/
7730
}
7731