Completed
Push — master ( 35bd4c...c8e02c )
by
unknown
10:31 queued 10s
created

SetupTest::testHookParserBeforeTidy()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 22
nc 1
nop 0
1
<?php
2
3
namespace BootstrapComponents\Tests\Unit;
4
5
use BootstrapComponents\ParserOutputHelper;
6
use BootstrapComponents\Setup as Setup;
7
use \PHPUnit_Framework_TestCase;
8
9
/**
10
 * @covers  \BootstrapComponents\Setup
11
 *
12
 * @ingroup Test
13
 *
14
 * @group   extension-bootstrap-components
15
 * @group   mediawiki-databaseless
16
 *
17
 * @license GNU GPL v3+
18
 *
19
 * @since   1.0
20
 * @author  Tobias Oetterer
21
 */
22
class SetupTest extends PHPUnit_Framework_TestCase {
23
	/**
24
	 * @throws \ConfigException
25
	 * @throws \MWException
26
	 */
27
	public function testCanConstruct() {
28
29
		$this->assertInstanceOf(
30
			'BootstrapComponents\\Setup',
31
			new Setup( [] )
32
		);
33
	}
34
35
	/**
36
	 * @throws \ConfigException cascading {@see \BootstrapComponents\Setup::onExtensionLoad}
37
	 * @throws \MWException
38
	 */
39
	public function testOnExtensionLoad() {
40
		$this->assertTrue(
41
			Setup::onExtensionLoad( [ 'version' => 'test' ] )
42
		);
43
	}
44
45
	/**
46
	 * @param string[] $hookList
47
	 *
48
	 * @throws \ConfigException
49
	 * @throws \MWException
50
	 *
51
	 * @dataProvider buildHookCallbackListForProvider
52
	 */
53
	public function testCanBuildHookCallbackListFor( $hookList ) {
54
55
		$instance = new Setup( [] );
56
57
		/** @noinspection PhpParamsInspection */
58
		$hookCallbackList = $instance->buildHookCallbackListFor( $hookList );
59
		list ( $expectedHookList, $invertedHookList ) = $this->buildHookListsForCanBuildHookListCheck( $hookList );
60
61
		foreach ( $expectedHookList as $hook ) {
62
			$this->doTestHookIsRegistered( $instance, $hookCallbackList, $hook, false );
63
		}
64
		foreach ( $invertedHookList as $hook ) {
65
			$this->doTestHookIsNotRegistered( $hookCallbackList, $hook );
66
		}
67
	}
68
69
	/**
70
	 * @throws \ConfigException
71
	 * @throws \MWException
72
	 */
73
	public function testCanClear() {
74
75
		$instance = new Setup( [] );
76
		$instance->register(
77
			$instance->buildHookCallbackListFor( Setup::AVAILABLE_HOOKS )
78
		);
79
		foreach ( Setup::AVAILABLE_HOOKS as $hook ) {
80
			$this->assertTrue(
81
				$instance->isRegistered( $hook ),
82
				'Hook ' . $hook . ' is not registered!'
83
			);
84
		}
85
		$instance->clear();
86
		foreach ( [ 'GalleryGetModes', 'ImageBeforeProduceHTML' ] as $hook ) {
87
			$this->assertTrue(
88
				!$instance->isRegistered( $hook ),
89
				'Hook ' . $hook . ' is still registered!'
90
			);
91
		}
92
	}
93
94
	/**
95
	 * @param string[] $listOfConfigSettingsSet
96
	 * @param string[] $expectedHookList
97
	 *
98
	 * @throws \ConfigException
99
	 * @throws \MWException
100
	 *
101
	 * @dataProvider hookRegistryProvider
102
	 */
103
	public function testCanCompileRequestedHooksListFor( $listOfConfigSettingsSet, $expectedHookList ) {
104
		$myConfig = $this->getMockBuilder( 'Config' )
105
			->disableOriginalConstructor()
106
			->getMock();
107
		$myConfig->expects( $this->any() )
108
			->method( 'has' )
109
			->will( $this->returnCallback(
110
				function( $configSetting ) use ( $listOfConfigSettingsSet )
111
				{
112
					return in_array( $configSetting, $listOfConfigSettingsSet );
113
				}
114
			) );
115
		$myConfig->expects( $this->any() )
116
			->method( 'get' )
117
			->will( $this->returnCallback(
118
				function( $configSetting ) use ( $listOfConfigSettingsSet )
119
				{
120
					return in_array( $configSetting, $listOfConfigSettingsSet );
121
				}
122
			) );
123
124
		$instance = new Setup( [] );
125
126
		/** @noinspection PhpParamsInspection */
127
		$compiledHookList = $instance->compileRequestedHooksListFor( $myConfig );
128
129
		$this->assertEquals(
130
			$expectedHookList,
131
			$compiledHookList
132
		);
133
	}
134
135
	/**
136
	 * @throws \ConfigException
137
	 * @throws \MWException
138
	 */
139
	public function testCanGetCompleteHookDefinitionList() {
140
141
		$myConfig = $this->getMockBuilder( 'Config' )
142
			->disableOriginalConstructor()
143
			->getMock();
144
		$componentLibrary = $this->getMockBuilder( 'BootstrapComponents\\ComponentLibrary' )
145
			->disableOriginalConstructor()
146
			->getMock();
147
		$nestingController = $this->getMockBuilder( 'BootstrapComponents\\NestingController' )
148
			->disableOriginalConstructor()
149
			->getMock();
150
151
		$instance = new Setup( [] );
152
153
		/** @noinspection PhpParamsInspection */
154
		$completeHookDefinitionList = $instance->getCompleteHookDefinitionList( $myConfig, $componentLibrary, $nestingController );
155
		$this->assertEquals(
156
			Setup::AVAILABLE_HOOKS,
157
			array_keys( $completeHookDefinitionList )
158
		);
159
160
		foreach ( $completeHookDefinitionList as $callback ) {
161
			$this->assertTrue(
162
				is_callable( $callback )
163
			);
164
		}
165
	}
166
167
	/**
168
	 * @throws \ConfigException
169
	 * @throws \MWException
170
	 */
171
	public function testCanInitializeApplications() {
172
173
		$myConfig = $this->getMockBuilder( 'Config' )
174
			->disableOriginalConstructor()
175
			->getMock();
176
177
		$instance = new Setup( [] );
178
179
		/** @noinspection PhpParamsInspection */
180
		list( $componentLibrary, $nestingController ) = $instance->initializeApplications( $myConfig );
181
182
		$this->assertInstanceOf(
183
			'BootstrapComponents\\ComponentLibrary',
184
			$componentLibrary
185
		);
186
		$this->assertInstanceOf(
187
			'BootstrapComponents\\NestingController',
188
			$nestingController
189
		);
190
	}
191
192
	/**
193
	 * @param array $listOfConfigSettingsSet
194
	 * @param array $expectedRegisteredHooks
195
	 * @param array $expectedNotRegisteredHooks
196
	 *
197
	 * @throws \ConfigException cascading {@see \Config::get}
198
	 * @throws \MWException
199
	 *
200
	 * @dataProvider hookRegistryProvider
201
	 */
202
	public function testHookRegistrationProcess( $listOfConfigSettingsSet, $expectedRegisteredHooks, $expectedNotRegisteredHooks ) {
203
204
		$instance = new Setup( [] );
205
206
		$hookCallbackList = $instance->buildHookCallbackListFor(
207
			$expectedRegisteredHooks
208
		);
209
210
		$this->assertTrue(
211
			is_array( $listOfConfigSettingsSet )
212
		);
213
214
		$this->assertEquals(
215
			count( $expectedRegisteredHooks ),
216
			$instance->register( $hookCallbackList )
217
		);
218
219
		foreach ( $expectedRegisteredHooks as $expectedHook ) {
220
			$this->doTestHookIsRegistered( $instance, $hookCallbackList, $expectedHook );
221
		}
222
223
		foreach ( $expectedNotRegisteredHooks as $notExpectedHook ) {
224
			$this->doTestHookIsNotRegistered( $hookCallbackList, $notExpectedHook );
225
		}
226
	}
227
228
	/**
229
	 * @throws \ConfigException cascading {@see \Config::get}
230
	 * @throws \MWException
231
	 */
232
	public function testCanRun() {
233
234
		$instance = new Setup( [] );
235
236
		$this->assertInternalType(
237
			'integer',
238
			$instance->run()
239
		);
240
	}
241
242
	/*
243
	 * Here end the tests for all the public methods.
244
	 * Following one test per hook function and one test for all the parser hook registrations.
245
	 */
246
247
	/**
248
	 * @throws \ConfigException
249
	 * @throws \MWException
250
	 */
251
	public function testHookGalleryGetModes() {
252
253
		$callback = $this->getCallBackForHook( 'GalleryGetModes' );
254
		$modesForTest = [ 'default' => 'TestGallery' ];
255
256
		$callback( $modesForTest );
257
		$this->assertEquals(
258
			2,
259
			count( $modesForTest )
260
		);
261
		$this->assertArrayHasKey(
262
			'carousel',
263
			$modesForTest
264
		);
265
		$this->assertEquals(
266
			'BootstrapComponents\\CarouselGallery',
267
			$modesForTest['carousel']
268
		);
269
	}
270
271
	/**
272
	 * @throws \ConfigException
273
	 * @throws \MWException
274
	 */
275
	public function testHookImageBeforeProduceHTML() {
276
		$callback = $this->getCallBackForHook( 'ImageBeforeProduceHTML' );
277
		$linker = $title = $file = $frameParams = $handlerParams = $time = $res = false;
278
279
		$this->assertTrue(
280
			$callback( $linker, $title, $file, $frameParams, $handlerParams, $time, $res )
281
		);
282
	}
283
284
	/**
285
	 * @throws \ConfigException
286
	 * @throws \MWException
287
	 */
288
	public function testHookInternalParseBeforeLinks() {
289
		$parserOutput = $this->getMockBuilder( 'ParserOutput' )
290
			->disableOriginalConstructor()
291
			->getMock();
292
		$parserOutput->expects( $this->exactly( 2 ) )
293
			->method( 'setExtensionData' )
294
			->with(
295
				$this->stringContains( 'bsc_no_image_modal' ),
296
				$this->isType( 'boolean' )
297
			);
298
299
		$parser = $this->getMockBuilder( 'Parser' )
300
			->disableOriginalConstructor()
301
			->getMock();
302
		$parser->expects( $this->exactly( 2 ) )
303
			->method( 'getOutput' )
304
			->willReturn( $parserOutput );
305
306
		$callback = $this->getCallBackForHook( 'InternalParseBeforeLinks' );
307
308
		$text = '';
309
		$this->assertTrue(
310
			$callback( $parser, $text )
311
		);
312
		$this->assertEquals(
313
			'',
314
			$text
315
		);
316
		$text = '__NOIMAGEMODAL__';
317
		$this->assertTrue(
318
			$callback( $parser, $text )
319
		);
320
		$this->assertEquals(
321
			'',
322
			$text
323
		);
324
	}
325
326
	/**
327
	 * @throws \ConfigException
328
	 * @throws \MWException
329
	 */
330
	public function testHookOutputPageParserOutput() {
331
		$content = 'CONTENT';
332
		$parser = $this->getMockBuilder( 'Parser' )
333
			->disableOriginalConstructor()
334
			->getMock();
335
		$parserOutput = $this->getMockBuilder( 'ParserOutput' )
336
			->disableOriginalConstructor()
337
			->getMock();
338
		$parserOutput->expects( $this->exactly( 2 ) )
339
			->method( 'getExtensionData' )
340
			->with(
341
				$this->stringContains( 'bsc_deferredContent' )
342
			)
343
			->willReturnOnConsecutiveCalls( [], [ 'call2' ] );
344
		$parserOutput->expects( $this->exactly( 2 ) )
345
			->method( 'getText' )
346
			->will( $this->returnCallback( function() use ( &$content ) {
347
				return $content;
348
			} ) );
349
		$parserOutput->expects( $this->exactly( 2 ) )
350
			->method( 'setText' )
351
			->will( $this->returnCallback( function( $injection ) use ( &$content ) {
352
				$content = $injection;
353
			} ) );
354
		$outputPage = $this->getMockBuilder( 'OutputPage' )
355
			->disableOriginalConstructor()
356
			->getMock();
357
358
		/** @noinspection PhpParamsInspection */
359
		$parserOutputHelper = new ParserOutputHelper( $parser );
360
361
		$callback = $this->getCallBackForHook( 'OutputPageParserOutput' );
362
363
		$this->assertTrue(
364
			$callback( $outputPage, $parserOutput, $parserOutputHelper )
365
		);
366
		$this->assertEquals(
367
			'CONTENT',
368
			$content
369
		);
370
		$this->assertTrue(
371
			$callback( $outputPage, $parserOutput, $parserOutputHelper )
372
		);
373
		$this->assertEquals(
374
			'CONTENT<!-- injected by Extension:BootstrapComponents -->call2<!-- /injected by Extension:BootstrapComponents -->',
375
			$content
376
		);
377
	}
378
379
	/**
380
	 * Note: Hook ParserFirstCallInit is tested in detail in {@see \BootstrapComponents\Tests\Unit\Hooks\ParserFirstCallInitTest}.
381
	 *
382
	 * @throws \ConfigException
383
	 * @throws \MWException
384
	 */
385
	public function testHookParserFirstCallInit() {
386
		$parser = $this->getMockBuilder( 'Parser' )
387
			->disableOriginalConstructor()
388
			->getMock();
389
390
		$callback = $this->getCallBackForHook( 'ParserFirstCallInit' );
391
392
		$this->assertTrue(
393
			$callback( $parser )
394
		);
395
	}
396
397
398
	/**
399
	 * @throws \ConfigException
400
	 * @throws \MWException
401
	 */
402
	public function testHookScribuntoExternalLibraries() {
403
		$callback = $this->getCallBackForHook( 'ScribuntoExternalLibraries' );
404
405
		$libraries = [];
406
		$this->assertTrue(
407
			$callback( '', $libraries )
408
		);
409
		$this->assertEquals(
410
			[],
411
			$libraries
412
		);
413
		$this->assertTrue(
414
			$callback( 'lua', $libraries )
415
		);
416
		$this->assertArrayHasKey(
417
			'mw.bootstrap',
418
			$libraries
419
		);
420
		$this->assertEquals(
421
			'BootstrapComponents\\LuaLibrary',
422
			$libraries['mw.bootstrap']
423
		);
424
	}
425
426
	/**
427
	 * @throws \ConfigException
428
	 * @throws \MWException
429
	 */
430
	public function testHookSetupAfterCache() {
431
		$callback = $this->getCallBackForHook( 'SetupAfterCache' );
432
		$this->assertTrue(
433
			$callback()
434
		);
435
	}
436
437
	/**
438
	 * @return array
439
	 */
440
	public function buildHookCallbackListForProvider() {
441
		return [
442
			'empty'               => [ [] ],
443
			'default'             => [ [ 'ParserBeforeTidy', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries' ] ],
444
			'alsoImageModal'      => [ [ 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', 'ParserBeforeTidy', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries' ] ],
445
			'alsoCarouselGallery' => [ [ 'GalleryGetModes', 'ParserBeforeTidy', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries' ] ],
446
			'all'                 => [ [ 'GalleryGetModes', 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries' ] ],
447
			'invalid'             => [ [ 'nonExistingHook', 'PageContentSave' ] ],
448
		];
449
	}
450
451
	/**
452
	 * @return string[]
453
	 */
454
	public function hookRegistryProvider() {
455
		return [
456
			'onlydefault' => [
457
				[],
458
				[ 'OutputPageParserOutput', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries', ],
459
				[ 'GalleryGetModes', 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', ],
460
			],
461
			'gallery activated' => [
462
				[ 'BootstrapComponentsEnableCarouselGalleryMode' ],
463
				[ 'OutputPageParserOutput', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries', 'GalleryGetModes', ],
464
				[ 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', ],
465
			],
466
			'image replacement activated' => [
467
				[ 'BootstrapComponentsModalReplaceImageTag' ],
468
				[ 'OutputPageParserOutput', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries', 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', ],
469
				[ 'GalleryGetModes', ],
470
			],
471
			'both activated' => [
472
				[ 'BootstrapComponentsEnableCarouselGalleryMode', 'BootstrapComponentsModalReplaceImageTag' ],
473
				[ 'OutputPageParserOutput', 'ParserFirstCallInit', 'SetupAfterCache', 'ScribuntoExternalLibraries', 'GalleryGetModes', 'ImageBeforeProduceHTML', 'InternalParseBeforeLinks', ],
474
				[],
475
			],
476
		];
477
	}
478
479
	/**
480
	 * @param $hookList
481
	 *
482
	 * @return array $expectedHookList, $invertedHookList
483
	 */
484
	private function buildHookListsForCanBuildHookListCheck( $hookList ) {
485
		$expectedHookList = [];
486
		$invertedHookList = [];
487
		foreach ( $hookList as $hook ) {
488
			if ( in_array( $hook, Setup::AVAILABLE_HOOKS ) ) {
489
				$expectedHookList[] = $hook;
490
			}
491
		}
492
		foreach ( Setup::AVAILABLE_HOOKS as $availableHook ) {
493
			if ( !in_array( $availableHook, $hookList ) ) {
494
				$invertedHookList[] = $availableHook;
495
			}
496
		}
497
		return [ $expectedHookList, $invertedHookList ];
498
	}
499
500
	/**
501
	 * @param Setup  $instance
502
	 * @param array  $registeredHooks
503
	 * @param string $expectedHook
504
	 * @param bool   $hardRegisterTest
505
	 */
506
	private function doTestHookIsRegistered( Setup $instance, $registeredHooks, $expectedHook, $hardRegisterTest = true ) {
507
		if ( $hardRegisterTest ) {
508
			$this->assertTrue(
509
				$instance->isRegistered( $expectedHook )
510
			);
511
		}
512
		$this->assertArrayHasKey(
513
			$expectedHook,
514
			$registeredHooks,
515
			'Expected hook "' . $expectedHook . '" to be registered but was not! '
516
		);
517
		$this->assertTrue(
518
			is_callable( $registeredHooks[$expectedHook] )
519
		);
520
	}
521
522
	/**
523
	 * @param array  $registeredHooks
524
	 * @param string $notExpectedHook
525
	 */
526
	private function doTestHookIsNotRegistered( $registeredHooks, $notExpectedHook ) {
527
		$this->assertArrayNotHasKey(
528
			$notExpectedHook,
529
			$registeredHooks,
530
			'Expected hook "' . $notExpectedHook . '" to not be registered but was! '
531
		);
532
	}
533
534
	/**
535
	 * @param string $hook
536
	 *
537
	 * @throws \ConfigException
538
	 * @throws \MWException
539
	 *
540
	 * @return \Closure
541
	 */
542
	private function getCallBackForHook( $hook ) {
543
		$instance = new Setup( [] );
544
		$hookCallbackList = $instance->buildHookCallbackListFor(
545
			[ $hook ]
546
		);
547
		$this->assertArrayHasKey(
548
			$hook,
549
			$hookCallbackList
550
		);
551
		$this->assertTrue(
552
			is_callable( $hookCallbackList[$hook] )
553
		);
554
		return $hookCallbackList[$hook];
555
	}
556
}
557