1from io import BytesIO
2
3from pytest import mark, raises
4
5from translate.convert import po2php, test_convert
6from translate.storage import po
7
8
9class TestPO2Php:
10    def po2php(self, posource):
11        """helper that converts po source to .php source without requiring files"""
12        inputfile = BytesIO(posource.encode())
13        inputpo = po.pofile(inputfile)
14        convertor = po2php.po2php()
15        return convertor.convertstore(inputpo)
16
17    def merge2php(self, phpsource, posource):
18        """helper that merges po translations to .php source without requiring files"""
19        inputfile = BytesIO(posource.encode())
20        inputpo = po.pofile(inputfile)
21        templatefile = BytesIO(phpsource.encode())
22        # templatephp = php.phpfile(templatefile)
23        convertor = po2php.rephp(templatefile, inputpo)
24        outputphp = convertor.convertstore().decode()
25        print(outputphp)
26        return outputphp
27
28    def test_convertphp(self):
29        """test convertphp helper"""
30        posource = """#: $lang['name']
31msgid "value"
32msgstr "waarde"
33"""
34        phptemplate = """$lang['name'] = 'value';
35"""
36        phpexpected = b"""<?php
37$lang['name'] = 'waarde';
38"""
39        inputfile = BytesIO(posource.encode())
40        templatefile = BytesIO(phptemplate.encode())
41        outputfile = BytesIO()
42        assert po2php.convertphp(inputfile, outputfile, templatefile) == 1
43        assert outputfile.getvalue() == phpexpected
44
45    def test_convertphp_notemplate(self):
46        """test convertphp helper without template"""
47        posource = """#: $lang['name']
48msgid "value"
49msgstr "waarde"
50"""
51        inputfile = BytesIO(posource.encode())
52        outputfile = BytesIO()
53        with raises(ValueError):
54            po2php.convertphp(inputfile, outputfile, None)
55
56    def test_convertphp_empty_template(self):
57        """test convertphp helper with empty translation"""
58        posource = """#: $lang['name']
59msgid "value"
60msgstr ""
61"""
62        inputfile = BytesIO(posource.encode())
63        templatefile = BytesIO(b"")
64        outputfile = BytesIO()
65        assert (
66            po2php.convertphp(inputfile, outputfile, templatefile, False, 100) is False
67        )
68        assert outputfile.getvalue() == b""
69
70    def test_merging_simple(self):
71        """check the simplest case of merging a translation"""
72        posource = """#: $lang['name']
73msgid "value"
74msgstr "waarde"
75"""
76        phptemplate = """<?php
77$lang['name'] = 'value';
78"""
79        phpexpected = """<?php
80$lang['name'] = 'waarde';
81"""
82        phpfile = self.merge2php(phptemplate, posource)
83        print(phpfile)
84        assert phpfile == phpexpected
85
86    def test_space_preservation(self):
87        """check that we preserve any spacing in php files when merging"""
88        posource = """#: $lang['name']
89msgid "value"
90msgstr "waarde"
91"""
92        phptemplate = """<?php
93$lang['name']  =  'value';
94"""
95        phpexpected = """<?php
96$lang['name'] = 'waarde';
97"""
98        phpfile = self.merge2php(phptemplate, posource)
99        print(phpfile)
100        assert phpfile == phpexpected
101
102    def test_preserve_unused_statement(self):
103        """check that we preserve any unused statements in php files when merging"""
104        posource = """#: $lang['name']
105msgid "value"
106msgstr "waarde"
107"""
108        phptemplate = """<?php
109error_reporting(E_ALL);
110$lang['name']  =  'value';
111"""
112        phpexpected = """<?php
113$lang['name'] = 'waarde';
114"""
115        phpfile = self.merge2php(phptemplate, posource)
116        assert phpfile == phpexpected
117
118    def test_not_translated_multiline(self):
119        """check that we preserve not translated multiline strings in php files when merging"""
120        posource = """#: $lang['name']
121msgid "value"
122msgstr "waarde"
123"""
124        phptemplate = """<?php
125$lang['name']  =  'value';
126$lang['second']  = "
127value";
128"""
129        phpexpected = """<?php
130$lang['name'] = 'waarde';
131$lang['second'] = "
132value";
133"""
134        phpfile = self.merge2php(phptemplate, posource)
135        assert phpfile == phpexpected
136
137    def test_merging_blank_entries(self):
138        """check that we can correctly merge entries that are blank in the template"""
139        posource = r'''#: accesskey-accept
140msgid ""
141"_: accesskey-accept\n"
142""
143msgstr ""'''
144        phptemplate = """<?php
145$lang['accesskey-accept'] = '';
146"""
147        phpexpected = """<?php
148$lang['accesskey-accept'] = '';
149"""
150        phpfile = self.merge2php(phptemplate, posource)
151        print(phpfile)
152        assert phpfile == phpexpected
153
154    def test_merging_fuzzy(self):
155        """check merging a fuzzy translation"""
156        posource = """#: %24lang%5B+%27name%27+%5D
157#, fuzzy
158msgid "value"
159msgstr "waarde"
160"""
161        phptemplate = """<?php
162$lang['name']  =  'value';
163"""
164        phpexpected = """<?php
165$lang['name'] = 'value';
166"""
167        phpfile = self.merge2php(phptemplate, posource)
168        print(phpfile)
169        assert phpfile == phpexpected
170
171    def test_locations_with_spaces(self):
172        """check that a location with spaces in php but spaces removed in PO is used correctly"""
173        posource = """#: %24lang%5B+%27name%27+%5D
174msgid "value"
175msgstr "waarde"\n"""
176        phptemplate = """<?php
177$lang[ 'name' ]  =  'value';
178"""
179        phpexpected = """<?php
180$lang[ 'name' ] = 'waarde';
181"""
182        phpfile = self.merge2php(phptemplate, posource)
183        print(phpfile)
184        assert phpfile == phpexpected
185
186    def test_inline_comments(self):
187        """check that we include inline comments from the template.  Bug 590"""
188        posource = """#: %24lang%5B+%27name%27+%5D
189msgid "value"
190msgstr "waarde"
191"""
192        phptemplate = """<?php
193$lang[ 'name' ]  =  'value'; //inline comment
194"""
195        phpexpected = """<?php
196//inline comment
197$lang[ 'name' ] = 'waarde';
198"""
199        phpfile = self.merge2php(phptemplate, posource)
200        print(phpfile)
201        assert phpfile == phpexpected
202
203    def test_block_comments(self):
204        """check that we include block comments from the template"""
205        posource = """#: %24lang%5B+%27name%27+%5D
206msgid "value"
207msgstr "waarde"
208"""
209        phptemplate = """<?php
210/* some comment */
211$lang[ 'name' ] = 'value';
212"""
213        phpexpected = """<?php
214/* some comment */
215$lang[ 'name' ] = 'waarde';
216"""
217        phpfile = self.merge2php(phptemplate, posource)
218        assert phpfile == phpexpected
219
220    def test_named_variables(self):
221        """check that we convert correctly if using named variables."""
222        posource = """#: $dictYear
223msgid "Year"
224msgstr "Jaar"
225"""
226        phptemplate = """<?php
227$dictYear = 'Year';
228"""
229        phpexpected = """<?php
230$dictYear = 'Jaar';
231"""
232        phpfile = self.merge2php(phptemplate, posource)
233        print(phpfile)
234        assert phpfile == phpexpected
235
236    def test_multiline(self):
237        """
238        Check that we convert multiline strings correctly.
239
240        Bug 1296.
241        """
242        posource = r"""#: $string['upgradesure']
243msgid ""
244"Your Moodle files have been changed, and you are\n"
245"about to automatically upgrade your server to this version:\n"
246"<p><b>$a</b></p>\n"
247"<p>Once you do this you can not go back again.</p>\n"
248"<p>Are you sure you want to upgrade this server to this version?</p>"
249msgstr ""
250"""
251        phptemplate = """<?php
252$string['upgradesure'] = 'Your Moodle files have been changed, and you are
253about to automatically upgrade your server to this version:
254<p><b>$a</b></p>
255<p>Once you do this you can not go back again.</p>
256<p>Are you sure you want to upgrade this server to this version?</p>';\n"""
257        phpfile = self.merge2php(phptemplate, posource)
258        print(phpfile)
259        assert phpfile == phptemplate
260
261    def test_hash_comment(self):
262        """check that we convert # comments correctly."""
263        posource = """#: $variable
264msgid "stringy"
265msgstr "stringetjie"
266"""
267        phptemplate = """<?php
268# inside alt= stuffies
269$variable = 'stringy';
270"""
271        phpexpected = """<?php
272# inside alt= stuffies
273$variable = 'stringetjie';
274"""
275        phpfile = self.merge2php(phptemplate, posource)
276        print(phpfile)
277        assert phpfile == phpexpected
278
279    def test_arrays(self):
280        """check that we can handle arrays"""
281        posource = """#: $lang->'name'
282msgid "value"
283msgstr "waarde"
284"""
285        phptemplate = """<?php
286$lang = array(
287    'name' => 'value',
288);
289"""
290        phpexpected = """<?php
291$lang = array(
292    'name' => 'waarde',
293);
294"""
295        phpfile = self.merge2php(phptemplate, posource)
296        print(phpfile)
297        assert phpfile == phpexpected
298
299    def test_named_nested_array(self):
300        """check that we can handle nested arrays"""
301        posource = """#: $lang->'codes'->'name'
302msgid "value"
303msgstr "waarde"
304"""
305        phptemplate = """<?php
306$lang = array(
307    'codes' => array(
308        'name' => 'value',
309    ),
310);
311"""
312        phpexpected = """<?php
313$lang = array(
314    'codes' => array(
315        'name' => 'waarde',
316    ),
317);
318"""
319        phpfile = self.merge2php(phptemplate, posource)
320        print(phpfile)
321        assert phpfile == phpexpected
322
323    def test_unnamed_nested_arrays(self):
324        posource = """
325#: return->'name1'
326msgid "source1"
327msgstr "target1"
328
329#: return->'list1'->'l1'
330msgid "source_l1_1"
331msgstr "target_l1_1"
332
333#: return->'list1'->'list2'->'l1'
334msgid "source_l1_l2_l1"
335msgstr "target_l1_l2_l1"
336
337#: return->'list1'->'l3'
338msgid "source_l1_3"
339msgstr "target_l1_3"
340
341#: return->'name2'
342msgid "source2"
343msgstr "target2"
344"""
345        phptemplate = """<?php
346return array(
347    'name1' => 'source1',
348    'list1' => array(
349        'l1' => 'source_l1_1',
350        'list2' => array(
351            'l1' => 'source_l1_l2_l1',
352        ),
353        'l3' => 'source_l1_3',
354    ),
355    'name2' => 'source2',
356);"""
357        phpexpected = """<?php
358return array(
359    'name1' => 'target1',
360    'list1' => array(
361        'l1' => 'target_l1_1',
362        'list2' => array(
363            'l1' => 'target_l1_l2_l1',
364        ),
365        'l3' => 'target_l1_3',
366    ),
367    'name2' => 'target2',
368);\n"""
369        phpfile = self.merge2php(phptemplate, posource)
370        print(phpfile)
371        assert phpfile == phpexpected
372
373    @mark.xfail(reason="Need to review if we want this behaviour")
374    def test_merging_propertyless_template(self):
375        """check that when merging with a template with no property values that we copy the template"""
376        posource = ""
377        proptemplate = "# A comment\n"
378        propexpected = proptemplate
379        propfile = self.merge2prop(proptemplate, posource)
380        print(propfile)
381        assert propfile == [propexpected]
382
383
384class TestPO2PhpCommand(test_convert.TestConvertCommand, TestPO2Php):
385    """Tests running actual po2php commands on files"""
386
387    convertmodule = po2php
388    defaultoptions = {"progress": "none"}
389
390    def test_help(self, capsys):
391        """tests getting help"""
392        options = super().test_help(capsys)
393        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
394        options = self.help_check(options, "--threshold=PERCENT")
395        options = self.help_check(options, "--fuzzy")
396        options = self.help_check(options, "--nofuzzy", last=True)
397