1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8require_once(__DIR__ . '/../../language/Exception.php');
9require_once(__DIR__ . '/../../language/WriteFile.php');
10
11use org\bovigo\vfs\vfsStream;
12use org\bovigo\vfs\vfsStreamFile;
13
14class Language_WriteFileTest extends TikiTestCase
15{
16	protected $obj;
17
18	protected function setUp()
19	{
20		// setup a mock filesystem
21		$lang = vfsStream::setup('lang');
22		$this->langFile = new vfsStreamFile('language.php');
23		$lang->addChild($this->langFile);
24
25		$this->parseFile = $this->getMockBuilder('Language_File')
26								->setMethods(['getTranslations'])
27								->setConstructorArgs([vfsStream::url('lang/language.php')])
28								->getMock();
29
30		$this->filePath = vfsStream::url('lang/language.php');
31
32		$this->obj = new Language_WriteFile($this->parseFile);
33	}
34
35	public function testConstruct_shouldRaiseExceptionIfFileIsNotWritable()
36	{
37		$this->langFile->chmod(0444);
38		$this->setExpectedException('Language_Exception');
39		new Language_WriteFile($this->parseFile);
40	}
41
42	public function testWriteStringsToFile_shouldReturnFalseIfEmptyParam()
43	{
44		$this->assertFalse($this->obj->writeStringsToFile([]));
45	}
46
47	public function testWriteStringsToFile_shouldWriteSimpleStrings()
48	{
49		$this->parseFile->expects($this->once())->method('getTranslations')->will($this->returnValue([]));
50
51		$obj = $this->getMockBuilder('Language_WriteFile')
52					->setMethods(['fileHeader'])
53					->setConstructorArgs([$this->parseFile])
54					->getMock();
55
56		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
57
58		$strings = [
59			'First string' => ['name' => 'First string'],
60			'Second string' => ['name' => 'Second string'],
61			'etc' => ['name' => 'etc'],
62		];
63
64		$obj->writeStringsToFile($strings);
65
66		// check if a backup of old language file (in this case an empty file) was created
67		$this->assertTrue(file_exists($this->filePath . '.old'));
68
69		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_simple.php'), file_get_contents($this->filePath));
70	}
71
72	public function writeStringsToFile_provider()
73	{
74		$strings = [
75			'First string' => ['name' => 'First string', 'files' => ['file1', 'file3']],
76			'Second string' => ['name' => 'Second string', 'files' => ['file2']],
77			'Used string' => ['name' => 'Used string', 'files' => ['file3']],
78			'Translation is the same as English string' => ['name' => 'Translation is the same as English string', 'files' => ['file5', 'file1']],
79			'etc' => ['name' => 'etc', 'files' => ['file4']],
80		];
81
82		return [[$strings]];
83	}
84
85	/**
86	 * @dataProvider writeStringsToFile_provider
87	 */
88	public function testWriteStringsToFile_shouldKeepTranslationsEvenIfTheyAreEqualToEnglishString($strings)
89	{
90		$this->parseFile->expects($this->exactly(1))->method('getTranslations')->will(
91			$this->returnValue(
92				[
93					'Unused string' => 'Some translation',
94					'Used string' => 'Another translation',
95					'Translation is the same as English string' => 'Translation is the same as English string',
96				]
97			)
98		);
99
100		$obj = $this->getMockBuilder('Language_WriteFile')
101					->setMethods(['fileHeader'])
102					->setConstructorArgs([$this->parseFile])
103					->getMock();
104
105		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
106
107		$obj->writeStringsToFile($strings);
108
109		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_with_translations.php'), file_get_contents($this->filePath));
110	}
111
112	/**
113	 * @dataProvider writeStringsToFile_provider
114	 */
115	public function testWriteStringsToFile_shouldIgnoreUnusedStrings($strings)
116	{
117		$this->parseFile->expects($this->exactly(1))->method('getTranslations')->will(
118			$this->returnValue(
119				[
120					'Unused string' => 'Some translation',
121					'Used string' => 'Another translation',
122					'Translation is the same as English string' => 'Translation is the same as English string',
123				]
124			)
125		);
126
127		$obj = $this->getMockBuilder('Language_WriteFile')
128				->setMethods(['fileHeader'])
129				->setConstructorArgs([$this->parseFile])
130				->getMock();
131
132		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
133
134		$obj->writeStringsToFile($strings);
135
136		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_with_translations.php'), file_get_contents($this->filePath));
137	}
138
139	/**
140	 * @dataProvider writeStringsToFile_provider
141	 */
142	public function testWriteStringsToFile_shouldOutputFileWhereStringsWasFound($strings)
143	{
144		$this->parseFile->expects($this->exactly(1))->method('getTranslations')->will(
145			$this->returnValue(
146				[
147					'Unused string' => 'Some translation',
148					'Used string' => 'Another translation',
149					'Translation is the same as English string' => 'Translation is the same as English string',
150				]
151			)
152		);
153
154		$obj = $this->getMockBuilder('Language_WriteFile')
155					->setMethods(['fileHeader'])
156					->setConstructorArgs([$this->parseFile])
157					->getMock();
158
159		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
160
161		$obj->writeStringsToFile($strings, true);
162
163		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_with_translations_and_file_paths.php'), file_get_contents($this->filePath));
164	}
165
166	/**
167	 * @dataProvider writeStringsToFile_provider
168	 */
169	public function testWriteStringsToFile_shouldConsiderStringsWithPunctuationInEndASpecialCase($strings)
170	{
171		$this->parseFile->expects($this->exactly(1))->method('getTranslations')->will(
172			$this->returnValue(
173				[
174					'Unused string' => 'Some translation',
175					'Used string' => 'Another translation',
176					'Translation is the same as English string' => 'Translation is the same as English string',
177					'Login' => 'Another translation',
178					'Add user:' => 'Translation',
179				]
180			)
181		);
182
183		$obj = $this->getMockBuilder('Language_WriteFile')
184					->setMethods(['fileHeader'])
185					->setConstructorArgs([$this->parseFile])
186					->getMock();
187
188		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
189
190		$strings['Login:'] = ['name' => 'Login:'];
191		$strings['Add user:'] = ['name' => 'Add user:'];
192		$strings['All users:'] = ['name' => 'All users:'];
193
194		$obj->writeStringsToFile($strings);
195
196		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_punctuations.php'), file_get_contents($this->filePath));
197	}
198
199	/**
200	 * @dataProvider writeStringsToFile_provider
201	 */
202	public function testWriteStringsToFile_shouldProperlyHandleSpecialCharactersInsideStrings($strings)
203	{
204		$this->parseFile->expects($this->exactly(1))->method('getTranslations')->will(
205			$this->returnValue(
206				[
207					'Unused string' => 'Some translation',
208					'Used string' => 'Another translation',
209					'Translation is the same as English string' => 'Translation is the same as English string',
210					"Congratulations!\n\nYour server can send emails.\n\n" => "Gratulation!\n\nDein Server kann Emails senden.\n\n",
211				]
212			)
213		);
214
215		$obj = $this->getMockBuilder('Language_WriteFile')
216					->setMethods(['fileHeader'])
217					->setConstructorArgs([$this->parseFile])
218					->getMock();
219
220		$obj->expects($this->once())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
221
222		$strings["Congratulations!\n\nYour server can send emails.\n\n"] = ['name' => "Congratulations!\n\nYour server can send emails.\n\n"];
223		$strings['Handling actions of plugin "%s" failed'] = ['name' => 'Handling actions of plugin "%s" failed'];
224
225		$obj->writeStringsToFile($strings);
226
227		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_escape_special_characters.php'), file_get_contents($this->filePath));
228	}
229
230	public function testWriteStringsToFile_shouldNotKeepTranslationsWithPunctuationOnSuccessiveCalls()
231	{
232		$this->parseFile->expects($this->at(0))
233						->method('getTranslations')->will($this->returnValue(['Errors' => 'Ошибки',]));
234
235		$obj = $this->getMockBuilder('Language_WriteFile')
236					->setMethods(['fileHeader'])
237					->setConstructorArgs([$this->parseFile])
238					->getMock();
239
240		$obj->expects($this->any())->method('fileHeader')->will($this->returnValue("// File header\n\n"));
241
242		$strings = [
243			'Errors' => ['name' => 'Errors'],
244			'Errors:' => ['name' => 'Errors:'],
245		];
246
247		$obj->writeStringsToFile($strings);
248
249		$this->parseFile->expects($this->at(0))
250						->method('getTranslations')->will($this->returnValue(['Errors:' => 'خطاها:',]));
251
252		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_writestringstofile_first_call.php'), file_get_contents($this->filePath));
253
254		$obj->writeStringsToFile($strings);
255
256		$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/language_writestringstofile_second_call.php'), file_get_contents($this->filePath));
257	}
258}
259