Issues (130)

tests/phpunit/Unit/ElementTest.php (1 issue)

1
<?php
2
/**
3
 * This file is part of the MediaWiki extension Lingo.
4
 *
5
 * @copyright 2011 - 2018, Stephan Gambke
6
 * @license GPL-2.0-or-later
7
 *
8
 * The Lingo extension is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by the Free
10
 * Software Foundation; either version 2 of the License, or (at your option) any
11
 * later version.
12
 *
13
 * The Lingo extension is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16
 * details.
17
 *
18
 * You should have received a copy of the GNU General Public License along
19
 * with this program. If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 * @author Stephan Gambke
22
 * @since 2.0
23
 * @file
24
 * @ingroup Lingo
25
 */
26
27
namespace Lingo\Tests\Unit;
28
29
use Lingo\Element;
30
31
/**
32
 * @group extensions-lingo
33
 * @group extensions-lingo-unit
34
 * @group mediawiki-databaseless
35
 *
36
 * @coversDefaultClass \Lingo\Element
37
 *
38
 * @ingroup Lingo
39
 * @ingroup Test
40
 */
41
class ElementTest extends \PHPUnit\Framework\TestCase {
0 ignored issues
show
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
43
	/** @var Element */
44
	protected $element;
45
	protected $doc;
46
47
	protected function setUp() {
48
		$this->doc = new \DOMDocument();
49
	}
50
51
	/**
52
	 * @covers ::__construct
53
	 */
54
	public function testCanConstruct() {
55
		$term = 'someTerm';
56
		$definition = [];
57
		$element = new Element( $term, $definition );
58
59
		$this->assertInstanceOf( '\Lingo\Element', $element );
60
	}
61
62
	/**
63
	 * Tests
64
	 * - if $wgexLingoDisplayOnce = false, the first and second occurrence of a term is correctly marked up as tooltip anchor
65
	 */
66
	public function testGetFormattedTerm_1() {
67
		// Setup
68
		$term = 'someTerm';
69
		$definition = [
70
			Element::ELEMENT_TERM       => $term,
71
			Element::ELEMENT_DEFINITION => 'someDefinition',
72
			Element::ELEMENT_LINK       => uniqid(), // just some fake page name that does not exist on the wiki
73
			Element::ELEMENT_SOURCE     => null,
74
			Element::ELEMENT_STYLE      => null,
75
		];
76
		$element = new Element( $term, $definition );
77
78
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
79
80
		$expectedAttributes = [ 'class' => [ 'mw-lingo-term' ], 'data-lingo-term-id' => '8ade40e10f35a32fbb1e06a4b54751d0' ];
81
82
		// Run
83
		$node = $element->getFormattedTerm( $this->doc );
84
85
		// Check
86
		$this->checkTermIsDomElement( $node, 'span', $term, $expectedAttributes );
87
88
		// Run
89
		$node = $element->getFormattedTerm( $this->doc );
90
91
		// Check
92
		$this->checkTermIsDomElement( $node, 'span', $term, $expectedAttributes );
93
	}
94
95
	/**
96
	 * Tests
97
	 * - if $wgexLingoDisplayOnce = true, the first occurrence of a term is correctly marked up as tooltip anchor
98
	 * - if $wgexLingoDisplayOnce = true, the second occurrence of a term is not marked up
99
	 */
100
	public function testGetFormattedTerm_2() {
101
		// Setup
102
		$term = 'someTerm';
103
		$definition = [];
104
		$element = new Element( $term, $definition );
105
106
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = true;
107
108
		$expectedAttributes = [ 'class' => 'mw-lingo-term', 'data-lingo-term-id' => '8ade40e10f35a32fbb1e06a4b54751d0' ];
109
110
		// Run
111
		$node = $element->getFormattedTerm( $this->doc );
112
113
		// Check
114
		$this->checkTermIsDomElement( $node, 'span', $term, $expectedAttributes );
115
116
		// Run
117
		$node = $element->getFormattedTerm( $this->doc );
118
119
		// Check
120
		$this->assertInstanceOf( 'DOMText', $node );
121
		$this->assertEquals( $term, $node->wholeText );
122
	}
123
124
	/**
125
	 * Tests
126
	 * - if there is only one definition and its text is empty and it has a link, the term is marked up as link
127
	 * - if the link is not a URL and does not point to an existing page, the term is marked up as "new" link
128
	 * - if $wgexLingoDisplayOnce = false, the first and second occurrence of of term are marked up as link
129
	 */
130
	public function testGetFormattedTerm_3() {
131
		// Setup
132
		$term = 'someTerm';
133
		$title = uniqid();
134
135
		$definition = [
136
			Element::ELEMENT_TERM       => $term,
137
			Element::ELEMENT_DEFINITION => null,
138
			Element::ELEMENT_LINK       => $title, // just some fake page name that does not exist on the wiki
139
			Element::ELEMENT_SOURCE     => null,
140
			Element::ELEMENT_STYLE      => null,
141
		];
142
143
		$element = new Element( $term, $definition );
144
145
		$expectedAttributes = [ 'class' => [ 'mw-lingo-term', 'new' ],  'title' => wfMessage( 'red-link-title', $title )->text() ];
146
147
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
148
149
		// Run
150
		$node = $element->getFormattedTerm( $this->doc );
151
152
		// Check
153
		$this->checkTermIsDomElement( $node, 'a', $term, $expectedAttributes );
154
155
		// Run
156
		$node = $element->getFormattedTerm( $this->doc );
157
158
		// Check
159
		$this->checkTermIsDomElement( $node, 'a', $term, $expectedAttributes );
160
	}
161
162
	/**
163
	 * Tests
164
	 * - if the link is not a URL and points to an existing page, the term is marked up with that title
165
	 */
166
	public function testGetFormattedTerm_4() {
167
		// Setup
168
		$term = 'someTerm';
169
170
		$page = \Title::newFromId( 1 );
171
		$this->assertTrue( $page->exists() );
172
		$title = $page->getText();
173
174
		$definition = [
175
			Element::ELEMENT_TERM       => $term,
176
			Element::ELEMENT_DEFINITION => null,
177
			Element::ELEMENT_LINK       => $title,
178
			Element::ELEMENT_SOURCE     => null,
179
			Element::ELEMENT_STYLE      => null,
180
		];
181
182
		$element = new Element( $term, $definition );
183
184
		$expectedAttributes = [ 'class' => [ 'mw-lingo-term' ],  'title' => $title ];
185
186
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
187
188
		// Run
189
		$node = $element->getFormattedTerm( $this->doc );
190
191
		// Check
192
		$this->checkTermIsDomElement( $node, 'a', $term, $expectedAttributes );
193
	}
194
195
	/**
196
	 * Tests
197
	 * - if there is only one definition and its text is empty and it has a link and $wgexLingoDisplayOnce = true, the first occurrence of a term is correctly marked up as link
198
	 * - if there is only one definition and its text is empty and it has a link and $wgexLingoDisplayOnce = true, the second occurrence of a term is not marked up
199
	 * - if a style is set in the definition, the link is marked up with that style
200
	 * - if the link is a valid URL, the term is marked up as external link
201
	 */
202
	public function testGetFormattedTerm_5() {
203
		// Setup
204
		$term = 'someTerm';
205
206
		$definition = [
207
			Element::ELEMENT_TERM       => $term,
208
			Element::ELEMENT_DEFINITION => null,
209
			Element::ELEMENT_LINK       => 'http://foo.com',
210
			Element::ELEMENT_SOURCE     => null,
211
			Element::ELEMENT_STYLE      => 'some-style',
212
		];
213
214
		$element = new Element( $term, $definition );
215
216
		$expectedAttributes = [ 'class' => [ 'mw-lingo-term', 'ext', 'some-style' ], 'title' => $term ];
217
218
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = true;
219
220
		// Run
221
		$node = $element->getFormattedTerm( $this->doc );
222
223
		// Check
224
		$this->checkTermIsDomElement( $node, 'a', $term, $expectedAttributes );
225
226
		// Run
227
		$node = $element->getFormattedTerm( $this->doc );
228
229
		// Check
230
		$this->assertInstanceOf( 'DOMText', $node );
231
		$this->assertEquals( $term, $node->wholeText );
232
	}
233
234
	/**
235
	 * Tests
236
	 * - if there is only one definition and its text is empty and it has an invalid link, the term is marked up as tooltip
237
	 * - if the term contains HTML-special characters, it is handled without raising an exception
238
	 */
239
	public function testGetFormattedTerm_6() {
240
		// Setup
241
		$term = 'some&Term';
242
243
		$definition = [
244
			Element::ELEMENT_TERM       => $term,
245
			Element::ELEMENT_DEFINITION => null,
246
			Element::ELEMENT_LINK       => 'foo[]bar',
247
			Element::ELEMENT_SOURCE     => null,
248
			Element::ELEMENT_STYLE      => null,
249
		];
250
251
		$element = new Element( $term, $definition );
252
253
		$expectedAttributes = [ 'class' => 'mw-lingo-term', 'data-lingo-term-id' => 'a8057b0494da505d2f7ac2e96e17083f' ];
254
255
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
256
257
		// Run
258
		$node = $element->getFormattedTerm( $this->doc );
259
260
		// Check
261
		$this->checkTermIsDomElement( $node, 'span', $term, $expectedAttributes );
262
	}
263
264
	/**
265
	 * Tests
266
	 * - if there is only one definition and its text is empty and it has an anchor link, the term is marked up as link without title attribute
267
	 */
268
	public function testGetFormattedTerm_7() {
269
		// Setup
270
		$term = 'some&Term';
271
272
		$definition = [
273
			Element::ELEMENT_TERM       => $term,
274
			Element::ELEMENT_DEFINITION => null,
275
			Element::ELEMENT_LINK       => '#someAnchor',
276
			Element::ELEMENT_SOURCE     => null,
277
			Element::ELEMENT_STYLE      => null,
278
		];
279
280
		$element = new Element( $term, $definition );
281
282
		$expectedAttributes = [ 'class' => 'mw-lingo-term' ];
283
		$unexpectedAttributes = [ 'title' ];
284
285
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
286
287
		// Run
288
		$node = $element->getFormattedTerm( $this->doc );
289
290
		// Check
291
		$this->checkTermIsDomElement( $node, 'a', $term, $expectedAttributes, $unexpectedAttributes );
292
	}
293
294
	/**
295
	 * Tests
296
	 * - correct html is produced
297
	 * - correct order of definitions
298
	 * - user-defined class is applied to definition
299
	 */
300
	public function testGetFormattedDefinitions_1() {
301
		// Setup
302
		$term = 'some&Term';
303
304
		$definition1 = [
305
			Element::ELEMENT_TERM       => $term,
306
			Element::ELEMENT_DEFINITION => 'someDefinition1',
307
			Element::ELEMENT_LINK       => 'someInternalLink1',
308
			Element::ELEMENT_SOURCE     => null,
309
			Element::ELEMENT_STYLE      => null,
310
		];
311
312
		$url1 = \Title::newFromText( $definition1[ Element::ELEMENT_LINK ] )->getFullURL();
313
314
		$definition2 = [
315
			Element::ELEMENT_TERM       => $term,
316
			Element::ELEMENT_DEFINITION => 'someDefinition2',
317
			Element::ELEMENT_LINK       => 'someInternalLink2',
318
			Element::ELEMENT_SOURCE     => null,
319
			Element::ELEMENT_STYLE      => 'some-style-2',
320
		];
321
322
		$url2 = \Title::newFromText( $definition2[ Element::ELEMENT_LINK ] )->getFullURL();
323
324
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
325
326
		$element = new Element( $term, $definition1 );
327
		$element->addDefinition( $definition2 );
328
		$node = $element->getFormattedTerm( $this->doc );
329
330
		// Run
331
		$definitions = $element->getFormattedDefinitions();
332
333
		$this->assertEquals(
334
			"<div class='mw-lingo-tooltip' id='a8057b0494da505d2f7ac2e96e17083f'>" .
335
			"<div class='mw-lingo-definition '>" .
336
			"<div class='mw-lingo-definition-text'>\n" .
337
			"someDefinition1\n" .
338
			"</div>" .
339
			"<div class='mw-lingo-definition-link'>" .
340
			"[" . $url1 . " <nowiki/>]" .
341
			"</div></div>" .
342
			"<div class='mw-lingo-definition some-style-2'>" .
343
			"<div class='mw-lingo-definition-text'>\n" .
344
			"someDefinition2\n" .
345
			"</div>" .
346
			"<div class='mw-lingo-definition-link'>" .
347
			"[" . $url2 . " <nowiki/>]" .
348
			"</div></div>\n" .
349
			"</div>",
350
			$definitions
351
		);
352
	}
353
354
	/**
355
	 * Tests
356
	 * - if there is no link defined, no link is added to the list of definitions
357
	 * - if there is an invalid link, an error message is attached to the list of definitions and the link is omitted
358
	 */
359
	public function testGetFormattedDefinitions_2() {
360
		// Setup
361
		$term = 'some&Term';
362
363
		$definition1 = [
364
			Element::ELEMENT_TERM       => $term,
365
			Element::ELEMENT_DEFINITION => 'someDefinition1',
366
			Element::ELEMENT_LINK       => null,
367
			Element::ELEMENT_SOURCE     => null,
368
			Element::ELEMENT_STYLE      => null,
369
		];
370
371
		// $url1 = \Title::newFromText( $definition1[ Element::ELEMENT_LINK ] )->getFullURL();
372
373
		$definition2 = [
374
			Element::ELEMENT_TERM       => $term,
375
			Element::ELEMENT_DEFINITION => 'someDefinition2',
376
			Element::ELEMENT_LINK       => 'some[]InvalidLink2',
377
			Element::ELEMENT_SOURCE     => null,
378
			Element::ELEMENT_STYLE      => 'some-style-2',
379
		];
380
381
		// $url2 = \Title::newFromText( $definition2[ Element::ELEMENT_LINK ] )->getFullURL();
382
383
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
384
385
		$element = new Element( $term, $definition1 );
386
		$element->addDefinition( $definition2 );
387
		$node = $element->getFormattedTerm( $this->doc );
388
389
		// Run
390
		$definitions = $element->getFormattedDefinitions();
391
392
		$this->assertEquals(
393
			"<div class='mw-lingo-tooltip' id='a8057b0494da505d2f7ac2e96e17083f'>" .
394
			"<div class='mw-lingo-definition '>" .
395
			"<div class='mw-lingo-definition-text'>\n" .
396
			"someDefinition1\n" .
397
			"</div>" .
398
			"</div>" .
399
			"<div class='mw-lingo-definition some-style-2'>" .
400
			"<div class='mw-lingo-definition-text'>\n" .
401
			"someDefinition2\n" .
402
			"</div></div>" .
403
			"<div class='mw-lingo-definition invalid-link-target'>" .
404
			"<div class='mw-lingo-definition-text'>\n" .
405
			"Invalid link target for term \"some&Term\": some[]InvalidLink2\n" .
406
			"</div></div>\n" .
407
			"</div>",
408
			$definitions
409
		);
410
	}
411
412
	/**
413
	 * Tests
414
	 * - if there is only one definition and its text is empty and it has a link, no definitions are produced
415
	 */
416
	public function testGetFormattedDefinitions_3() {
417
		// Setup
418
		$term = 'someTerm';
419
420
		$definition = [
421
			Element::ELEMENT_TERM       => $term,
422
			Element::ELEMENT_DEFINITION => null,
423
			Element::ELEMENT_LINK       => 'someLink',
424
			Element::ELEMENT_SOURCE     => null,
425
			Element::ELEMENT_STYLE      => null,
426
		];
427
428
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
429
430
		$element = new Element( $term, $definition );
431
		$node = $element->getFormattedTerm( $this->doc );
432
433
		// Run
434
		$definitions = $element->getFormattedDefinitions();
435
436
		$this->assertEquals( '', $definitions );
437
	}
438
439
	/**
440
	 * Tests
441
	 * - if there is only one definition and its text is empty and it has an invalid link, the error message shows as tooltip
442
	 * - class 'invalid-link-target' is correctly applied to error message
443
	 * - if the term contains HTML-special characters, it is handled without raising an exception
444
	 */
445
	public function testGetFormattedDefinitions_4() {
446
		// Setup
447
		$term = 'some&Term';
448
449
		$definition = [
450
			Element::ELEMENT_TERM       => $term,
451
			Element::ELEMENT_DEFINITION => null,
452
			Element::ELEMENT_LINK       => 'foo[]bar',
453
			Element::ELEMENT_SOURCE     => null,
454
			Element::ELEMENT_STYLE      => null,
455
		];
456
457
		$GLOBALS[ 'wgexLingoDisplayOnce' ] = false;
458
459
		$element = new Element( $term, $definition );
460
		$node = $element->getFormattedTerm( $this->doc );
461
462
		// Run
463
		$definitions = $element->getFormattedDefinitions();
464
465
		$this->assertEquals(
466
			"<div class='mw-lingo-tooltip' id='a8057b0494da505d2f7ac2e96e17083f'>" .
467
			"<div class='mw-lingo-definition invalid-link-target'>" .
468
			"<div class='mw-lingo-definition-text'>\n" .
469
			"Invalid link target for term \"some&Term\": foo[]bar\n" .
470
			"</div></div>\n</div>",
471
			$definitions
472
		);
473
	}
474
475
	/**
476
	 * @param \DOMElement $node
477
	 * @param string $tagName
478
	 * @param string $text
479
	 * @param string[] $expectedAttributes
480
	 * @param array $unexpectedAttributes
481
	 */
482
	protected function checkTermIsDomElement( $node, $tagName, $text, $expectedAttributes = [], $unexpectedAttributes = [] ) {
483
		$nodeText = $this->doc->saveHTML( $node );
484
485
		$this->assertInstanceOf( 'DOMElement', $node );
486
		$this->assertEquals( $tagName, $node->tagName );
487
		$this->assertEquals( $text, $node->textContent );
488
489
		if ( array_key_exists( 'class', $expectedAttributes ) ) {
490
491
			$classes = array_flip( array_filter( explode( ' ', $node->getAttribute( 'class' ) ) ) );
492
493
			foreach ( (array)$expectedAttributes[ 'class' ] as $expectedClass ) {
494
				$this->assertTrue( array_key_exists( $expectedClass, $classes ) );
495
			}
496
497
			unset( $expectedAttributes[ 'class' ] );
498
		}
499
500
		foreach ( $expectedAttributes as $attribute => $value ) {
501
			$this->assertEquals( $value, $node->getAttribute( $attribute ) );
502
		}
503
504
		foreach ( $unexpectedAttributes as $attribute ) {
505
			$this->assertFalse( $node->hasAttribute( $attribute ) );
506
		}
507
	}
508
}
509