summaryrefslogtreecommitdiff
blob: 6f70e23712efddcddb8591b6ec8d69a88bca967c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
<?php
declare( strict_types = 1 );

namespace MediaWiki\Extension\Translate\PageTranslation;

use MediaWiki\Extension\Translate\Utilities\ParsingPlaceholderFactory;
use MediaWikiUnitTestCase;

/**
 * @author Niklas Laxström
 * @license GPL-2.0-or-later
 * @covers \MediaWiki\Extension\Translate\PageTranslation\TranslatablePageParser
 */
class TranslatablePageParserTest extends MediaWikiUnitTestCase {
	/** @dataProvider provideTestContainsMarkup */
	public function testContainsMarkup( string $input, bool $expected ) {
		 $parser = new TranslatablePageParser( new ParsingPlaceholderFactory() );
		 $this->assertSame( $expected, $parser->containsMarkup( $input ) );
	}

	public function provideTestContainsMarkup() {
		yield [ 'Plain page', false ];

		yield [ '<languages/>', false ];

		yield [ '<translate>Board, Run!</translate>', true ];

		yield [ '<translate nowrap>Board, Run!</translate>', true ];

		yield [ '<translate unknown="attributes">Board, Run!</translate>', true ];

		yield [ '</translate>', true ];

		yield [ '<nowiki><translate></nowiki>', false ];
	}

	/** @dataProvider provideTestCleanupTags */
	public function testCleanupTags( string $input, string $expected ) {
		$parser = new TranslatablePageParser( new ParsingPlaceholderFactory() );
		$this->assertSame( $expected, $parser->cleanupTags( $input ) );
	}

	public function provideTestCleanupTags() {
		yield 'Unbalanced tag in a section preview' => [
			"== Hello ==\n</translate>",
			'== Hello ==',
		];

		yield 'Unbalanced tags, no whitespace' => [
			"</translate><translate>",
			'',
		];

		yield 'Balanced tags, non-removable whitespace' => [
			"1\n2<translate>3\n4</translate>5\n6",
			"1\n23\n45\n6",
		];

		yield 'Balanced tags, removable whitespace' => [
			"1<translate>\n\n</translate>2",
			'12',
		];

		yield 'Old style translation variable tag is collapsed' => [
			'[[<tvar|wmf>Special:MyLanguage/Wikimedia Foundation</>|Wikimedia Foundation]].',
			'[[Special:MyLanguage/Wikimedia Foundation|Wikimedia Foundation]].',
		];

		yield 'Translation variable tag is collapsed' => [
			'[[<tvar name=wmf>Special:MyLanguage/Wikimedia Foundation</tvar>|Wikimedia Foundation]].',
			'[[Special:MyLanguage/Wikimedia Foundation|Wikimedia Foundation]].',
		];

		yield 'Tag inside a nowiki is retained' => [
			'You can use the <nowiki><translate></nowiki> tag.',
			'You can use the <nowiki><translate></nowiki> tag.',
		];

		yield 'Broken tag is retained' => [
			'What if I <translate and </translate>.',
			'What if I <translate and .',
		];

		yield 'Tag with nowrap is removed' => [
			'<abbr title="<translate nowrap>Careful unselfish true engineer</translate>">CUTE</abbr>',
			'<abbr title="Careful unselfish true engineer">CUTE</abbr>',
		];

		yield 'No content to remove' => [
			'Plain page',
			'Plain page',
		];

		yield 'Language tag should not be removed by this method' => [
			'<languages/>',
			'<languages/>',
		];

		yield 'Unclosed tag is removed' => [
			'<translate>No worries, I will try to remember to close this tag',
			'No worries, I will try to remember to close this tag',

		];

		yield 'Complex old translation variable syntax is parsed and replaced with contents' => [
			'<translate nowrap>I have <tvar|!><:D></></translate>!',
			'I have <:D>!',
		];

		yield 'Complex translation variable syntax is parsed and replaced with contents' => [
			'<translate nowrap>I have <tvar name="--$"><:D></tvar></translate>!',
			'I have <:D>!',
		];

		yield 'No extra newlines is added' => [
			'A<translate>B<translate>C</translate>D</translate>E',
			'ABCDE',
		];

		yield 'Reasonable amount of newlines is stripped' => [
			"A\n<translate>\n\nB</translate>\nC\n<translate>D\n\n\n\n</translate>E",
			"A\n\nB\nC\nD\n\n\nE",

		];

		yield 'Section markers are removed from headings' => [
			"<translate>\n== Head of the header == <!--T:1-->\n</translate>",
			"== Head of the header ==",
		];

		yield 'Section markers are removed, but not other text' => [
			' <!--T:10--> text <!--T:11--> more text <!--T:12--> even more',
			' text more text even more',
		];
	}

	/** @dataProvider provideTestParse */
	public function testParse(
		string $input,
		string $expectedTranslationTemplate,
		string $expectedSourceTemplate,
		array $expectedUnits
	) {
		$parser = new TranslatablePageParser( new TestingParsingPlaceholderFactory() );
		$output = $parser->parse( $input );
		$this->assertSame( $expectedTranslationTemplate, $output->translationPageTemplate() );
		$this->assertSame( $expectedSourceTemplate, $output->sourcePageTemplate() );
		$this->assertEquals( $expectedUnits, $output->units() );
	}

	public function provideTestParse() {
		// Test case 1 //
		$s1 = new TranslationUnit( '== Unit tests ==' );
		$s2 = new TranslationUnit( 'Introduction to unit tests.' );
		$s3 = new TranslationUnit( 'They are fun.' );

		$s4 = new TranslationUnit( 'Smilie' );
		$s4->setCanWrap( false );
		$s4->setIsInline( true );

		yield [
			<<<INPUT
<languages/>
<translate>
== Unit tests ==

Introduction to unit tests.

They are fun.
</translate>

<abbr title="<translate nowrap>Smilie</translate>">:)</abbr>
INPUT
			, <<<TRANSLATION_TEMPLATE
<languages/>
<1>

<2>

<3>

<abbr title="<5>">:)</abbr>
TRANSLATION_TEMPLATE
			, <<<SOURCE_TEMPLATE
<languages/>
<translate>
<1>

<2>

<3>
</translate>

<abbr title="<translate nowrap><5></translate>">:)</abbr>
SOURCE_TEMPLATE
			,
			[
				'<1>' => $s1,
				'<2>' => $s2,
				'<3>' => $s3,
				'<5>' => $s4,
			]
		];

		// Test case 2 //
		$s1 = new TranslationUnit( '== Unit tests ==', '11' );
		$s2 = new TranslationUnit( 'Introduction to unit tests.', '22' );
		$s3 = new TranslationUnit( 'They are fun.', '33' );

		$s4 = new TranslationUnit( 'Smilie', '44' );
		$s4->setCanWrap( false );
		$s4->setIsInline( true );

		yield [
			<<<INPUT
<languages/>
<translate>
== Unit tests == <!--T:11-->

<!--T:22-->
Introduction to unit tests.

<!--T:33-->
They are fun.
</translate>

<abbr title="<translate nowrap><!--T:44--> Smilie</translate>">:)</abbr>
INPUT
			, <<<TRANSLATION_TEMPLATE
<languages/>
<1>

<2>

<3>

<abbr title="<5>">:)</abbr>
TRANSLATION_TEMPLATE
			, <<<SOURCE_TEMPLATE
<languages/>
<translate>
<1>

<2>

<3>
</translate>

<abbr title="<translate nowrap><5></translate>">:)</abbr>
SOURCE_TEMPLATE
			,
			[
				'<1>' => $s1,
				'<2>' => $s2,
				'<3>' => $s3,
				'<5>' => $s4,
			]
		];
	}

	/** @dataProvider provideTestParseSection */
	public function testParseSection(
		string $input,
		string $expectedTemplate,
		array $expectedUnits,
		string $comment
	) {
		$parser = new TranslatablePageParser( new TestingParsingPlaceholderFactory() );
		$canWrap = true;
		$result = $parser->parseSection( $input, $canWrap );
		$this->assertSame( $expectedTemplate, $result['template'], $comment );
		$this->assertEquals( $expectedUnits, $result['sections'], $comment );
	}

	public static function provideTestParseSection() {
		$u = new TranslationUnit( 'Hello' );
		$u->setIsInline( true );
		yield [
			'Hello',
			'<0>',
			[ '<0>' => $u ],
			'No surrounding whitespace',
		];

		$u = new TranslationUnit( 'Hello' );
		yield [
			"\nHello",
			"\n<0>",
			[ '<0>' => $u ],
			'With surrounding whitespace',
		];

		$u0 = new TranslationUnit( 'Hello world' );
		$u1 = new TranslationUnit( 'Bunny' );
		yield [
			"\nHello world\n\nBunny\n",
			"\n<0>\n\n<1>\n",
			[ '<0>' => $u0, '<1>' => $u1 ],
			'Splitting at one empty line',
		];

		$u0 = new TranslationUnit( 'First' );
		$u1 = new TranslationUnit( 'Second' );
		$u2 = new TranslationUnit( 'Third' );
		yield [
			"First\n\n\n\n\nSecond\n\nThird",
			"<0>\n\n\n\n\n<1>\n\n<2>",
			[ '<0>' => $u0, '<1>' => $u1, '<2>' => $u2 ],
			'Splitting with multiple empty lines',
		];
	}
}