1from io import BytesIO
2
3import pytest
4
5from translate.convert import ical2po, test_convert
6
7
8class TestIcal2PO:
9
10    ConverterClass = ical2po.ical2po
11
12    def _convert(
13        self,
14        input_string,
15        template_string=None,
16        blank_msgstr=False,
17        duplicate_style="msgctxt",
18        success_expected=True,
19    ):
20        """Helper that converts to target format without using files."""
21        input_file = BytesIO(input_string.encode())
22        output_file = BytesIO()
23        template_file = None
24        if template_string:
25            template_file = BytesIO(template_string.encode())
26        expected_result = 1 if success_expected else 0
27        converter = self.ConverterClass(
28            input_file, output_file, template_file, blank_msgstr, duplicate_style
29        )
30        assert converter.run() == expected_result
31        return converter.target_store, output_file
32
33    def _convert_to_string(self, *args, **kwargs):
34        """Helper that converts to target format string without using files."""
35        return self._convert(*args, **kwargs)[1].getvalue().decode("utf-8")
36
37    def test_convert_empty_file(self):
38        """Check converting empty iCalendar returns no output."""
39        with pytest.raises(StopIteration):
40            self._convert_to_string("", success_expected=False)
41
42    def test_no_translations(self):
43        """Check that iCalendar with no translations returns correct result."""
44        input_string = """
45BEGIN:VCALENDAR
46VERSION:2.0
47PRODID:-//hacksw/handcal//NONSGML v1.0//EN
48BEGIN:VEVENT
49END:VEVENT
50END:VCALENDAR
51""".replace(
52            "\n", "\r\n"
53        )
54        output = self._convert_to_string(input_string, success_expected=False)
55        assert output == ""
56
57    def test_summary(self):
58        """Check that iCalendar SUMMARY converts valid PO output."""
59        input_string = """
60BEGIN:VCALENDAR
61VERSION:2.0
62PRODID:-//hacksw/handcal//NONSGML v1.0//EN
63BEGIN:VEVENT
64UID:uid1@example.com
65DTSTART:19970714T170000Z
66DTEND:19970715T035959Z
67DTSTAMP:19970714T170000Z
68ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
69SUMMARY:Value
70END:VEVENT
71END:VCALENDAR
72""".replace(
73            "\n", "\r\n"
74        )
75        expected_output = """
76#. Start date: 1997-07-14 17:00:00+00:00
77#: [uid1@example.com]SUMMARY
78msgid "Value"
79msgstr ""
80"""
81        output = self._convert_to_string(input_string)
82        assert expected_output in output
83        assert "extracted from " in output
84
85    def test_description(self):
86        """Check that iCalendar DESCRIPTION converts valid PO output."""
87        input_string = """
88BEGIN:VCALENDAR
89VERSION:2.0
90PRODID:-//hacksw/handcal//NONSGML v1.0//EN
91BEGIN:VEVENT
92UID:uid1@example.com
93DTSTART:19970714T170000Z
94DTEND:19970715T035959Z
95DESCRIPTION:Value
96DTSTAMP:19970714T170000Z
97ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
98END:VEVENT
99END:VCALENDAR
100""".replace(
101            "\n", "\r\n"
102        )
103        expected_output = """
104#. Start date: 1997-07-14 17:00:00+00:00
105#: [uid1@example.com]DESCRIPTION
106msgid "Value"
107msgstr ""
108"""
109        output = self._convert_to_string(input_string)
110        assert expected_output in output
111        assert "extracted from " in output
112
113    def test_location(self):
114        """Check that iCalendar LOCATION converts valid PO output."""
115        input_string = """
116BEGIN:VCALENDAR
117VERSION:2.0
118PRODID:-//hacksw/handcal//NONSGML v1.0//EN
119BEGIN:VEVENT
120UID:uid1@example.com
121DTSTART:19970714T170000Z
122DTEND:19970715T035959Z
123DTSTAMP:19970714T170000Z
124LOCATION:Value
125ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
126END:VEVENT
127END:VCALENDAR
128""".replace(
129            "\n", "\r\n"
130        )
131        expected_output = """
132#. Start date: 1997-07-14 17:00:00+00:00
133#: [uid1@example.com]LOCATION
134msgid "Value"
135msgstr ""
136"""
137        output = self._convert_to_string(input_string)
138        assert expected_output in output
139        assert "extracted from " in output
140
141    def test_comment(self):
142        """Check that iCalendar COMMENT converts valid PO output."""
143        input_string = """
144BEGIN:VCALENDAR
145VERSION:2.0
146PRODID:-//hacksw/handcal//NONSGML v1.0//EN
147BEGIN:VEVENT
148UID:uid1@example.com
149DTSTART:19970714T170000Z
150DTEND:19970715T035959Z
151COMMENT:Value
152DTSTAMP:19970714T170000Z
153ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
154END:VEVENT
155END:VCALENDAR
156""".replace(
157            "\n", "\r\n"
158        )
159        expected_output = """
160#. Start date: 1997-07-14 17:00:00+00:00
161#: [uid1@example.com]COMMENT
162msgid "Value"
163msgstr ""
164"""
165        output = self._convert_to_string(input_string)
166        assert expected_output in output
167        assert "extracted from " in output
168
169    def test_no_template_duplicate_style(self):
170        """Check that iCalendar extracts conforming duplicate style."""
171        input_string = """
172BEGIN:VCALENDAR
173VERSION:2.0
174PRODID:-//hacksw/handcal//NONSGML v1.0//EN
175BEGIN:VEVENT
176UID:uid1@example.com
177DTSTART:19970714T170000Z
178DTEND:19970715T035959Z
179DTSTAMP:19970714T170000Z
180ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
181SUMMARY:Value
182END:VEVENT
183BEGIN:VEVENT
184UID:uid2@example.com
185DTSTART:19970715T170000Z
186DTEND:19970716T035959Z
187DTSTAMP:19970715T170000Z
188ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
189SUMMARY:Value
190END:VEVENT
191END:VCALENDAR
192""".replace(
193            "\n", "\r\n"
194        )
195        expected_output = """
196#. Start date: 1997-07-14 17:00:00+00:00
197#: [uid1@example.com]SUMMARY
198msgctxt "[uid1@example.com]SUMMARY"
199msgid "Value"
200msgstr ""
201
202#. Start date: 1997-07-15 17:00:00+00:00
203#: [uid2@example.com]SUMMARY
204msgctxt "[uid2@example.com]SUMMARY"
205msgid "Value"
206msgstr ""
207"""
208        output = self._convert_to_string(input_string)
209        assert expected_output in output
210        assert "extracted from " in output
211
212        output = self._convert_to_string(input_string, duplicate_style="msgctxt")
213        assert expected_output in output
214        assert "extracted from " in output
215
216        expected_output = """
217#. Start date: 1997-07-14 17:00:00+00:00
218#. Start date: 1997-07-15 17:00:00+00:00
219#: [uid1@example.com]SUMMARY
220#: [uid2@example.com]SUMMARY
221msgid "Value"
222msgstr ""
223"""
224        output = self._convert_to_string(input_string, duplicate_style="merge")
225        assert expected_output in output
226        assert "extracted from " in output
227
228    def test_merge(self):
229        """Check merging two iCalendar files converts to valid PO output."""
230        input_string = """
231BEGIN:VCALENDAR
232VERSION:2.0
233PRODID:-//hacksw/handcal//NONSGML v1.0//EN
234BEGIN:VEVENT
235UID:uid1@example.com
236DTSTART:19970714T170000Z
237DTEND:19970715T035959Z
238DTSTAMP:19970714T170000Z
239ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
240SUMMARY:Valor
241END:VEVENT
242END:VCALENDAR
243""".replace(
244            "\n", "\r\n"
245        )
246        template_string = """
247BEGIN:VCALENDAR
248VERSION:2.0
249PRODID:-//hacksw/handcal//NONSGML v1.0//EN
250BEGIN:VEVENT
251UID:uid1@example.com
252DTSTART:19970718T170000Z
253DTEND:19970719T035959Z
254DTSTAMP:19970718T170000Z
255ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
256SUMMARY:Value
257END:VEVENT
258END:VCALENDAR
259""".replace(
260            "\n", "\r\n"
261        )
262        expected_output = """
263#. Start date: 1997-07-18 17:00:00+00:00
264#: [uid1@example.com]SUMMARY
265msgid "Value"
266msgstr "Valor"
267"""
268        output = self._convert_to_string(input_string, template_string)
269        assert expected_output in output
270        assert "extracted from " in output
271
272    def test_merge_misaligned_files(self):
273        """Check merging two iCalendar files that are not aligned."""
274        input_string = """
275BEGIN:VCALENDAR
276VERSION:2.0
277PRODID:-//hacksw/handcal//NONSGML v1.0//EN
278BEGIN:VEVENT
279UID:uid3@example.com
280DTSTART:19970713T170000Z
281DTEND:19970717T035959Z
282DTSTAMP:19970713T170000Z
283ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
284SUMMARY:Valor
285END:VEVENT
286END:VCALENDAR
287""".replace(
288            "\n", "\r\n"
289        )
290        template_string = """
291BEGIN:VCALENDAR
292VERSION:2.0
293PRODID:-//hacksw/handcal//NONSGML v1.0//EN
294BEGIN:VEVENT
295UID:uid1@example.com
296DTSTART:19970718T170000Z
297DTEND:19970719T035959Z
298DTSTAMP:19970718T170000Z
299ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
300SUMMARY:Value
301END:VEVENT
302END:VCALENDAR
303""".replace(
304            "\n", "\r\n"
305        )
306        expected_output = """
307#. Start date: 1997-07-18 17:00:00+00:00
308#: [uid1@example.com]SUMMARY
309msgid "Value"
310msgstr ""
311"""
312        output = self._convert_to_string(input_string, template_string)
313        assert expected_output in output
314        assert "extracted from " in output
315
316    def test_merge_blank_msgstr(self):
317        """Check merging two iCalendar files converts to valid POT output."""
318        input_string = """
319BEGIN:VCALENDAR
320VERSION:2.0
321PRODID:-//hacksw/handcal//NONSGML v1.0//EN
322BEGIN:VEVENT
323UID:uid1@example.com
324DTSTART:19970714T170000Z
325DTEND:19970715T035959Z
326DTSTAMP:19970714T170000Z
327ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
328SUMMARY:Valor
329END:VEVENT
330END:VCALENDAR
331""".replace(
332            "\n", "\r\n"
333        )
334        template_string = """
335BEGIN:VCALENDAR
336VERSION:2.0
337PRODID:-//hacksw/handcal//NONSGML v1.0//EN
338BEGIN:VEVENT
339UID:uid1@example.com
340DTSTART:19970718T170000Z
341DTEND:19970719T035959Z
342DTSTAMP:19970718T170000Z
343ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
344SUMMARY:Value
345END:VEVENT
346END:VCALENDAR
347""".replace(
348            "\n", "\r\n"
349        )
350        expected_output = """
351#. Start date: 1997-07-18 17:00:00+00:00
352#: [uid1@example.com]SUMMARY
353msgid "Value"
354msgstr ""
355"""
356        output = self._convert_to_string(
357            input_string, template_string, blank_msgstr=True
358        )
359        assert expected_output in output
360        assert "extracted from " in output
361
362    def test_merge_duplicate_style(self):
363        """Check two iCalendar files convert conforming duplicate style."""
364        input_string = """
365BEGIN:VCALENDAR
366VERSION:2.0
367PRODID:-//hacksw/handcal//NONSGML v1.0//EN
368BEGIN:VEVENT
369UID:uid1@example.com
370DTSTART:19970714T170000Z
371DTEND:19970715T035959Z
372DTSTAMP:19970714T170000Z
373ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
374SUMMARY:Valor
375END:VEVENT
376BEGIN:VEVENT
377UID:uid2@example.com
378DTSTART:19970715T170000Z
379DTEND:19970716T035959Z
380DTSTAMP:19970715T170000Z
381ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
382SUMMARY:Valioso
383END:VEVENT
384END:VCALENDAR
385""".replace(
386            "\n", "\r\n"
387        )
388        template_string = """
389BEGIN:VCALENDAR
390VERSION:2.0
391PRODID:-//hacksw/handcal//NONSGML v1.0//EN
392BEGIN:VEVENT
393UID:uid1@example.com
394DTSTART:19970714T170000Z
395DTEND:19970715T035959Z
396DTSTAMP:19970714T170000Z
397ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
398SUMMARY:Value
399END:VEVENT
400BEGIN:VEVENT
401UID:uid2@example.com
402DTSTART:19970715T170000Z
403DTEND:19970716T035959Z
404DTSTAMP:19970715T170000Z
405ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
406SUMMARY:Value
407END:VEVENT
408END:VCALENDAR
409""".replace(
410            "\n", "\r\n"
411        )
412        expected_output = """
413#. Start date: 1997-07-14 17:00:00+00:00
414#: [uid1@example.com]SUMMARY
415msgctxt "[uid1@example.com]SUMMARY"
416msgid "Value"
417msgstr "Valor"
418
419#. Start date: 1997-07-15 17:00:00+00:00
420#: [uid2@example.com]SUMMARY
421msgctxt "[uid2@example.com]SUMMARY"
422msgid "Value"
423msgstr "Valioso"
424"""
425        output = self._convert_to_string(input_string, template_string)
426        assert expected_output in output
427        assert "extracted from " in output
428
429        output = self._convert_to_string(
430            input_string, template_string, duplicate_style="msgctxt"
431        )
432        assert expected_output in output
433        assert "extracted from " in output
434
435        expected_output = """
436#. Start date: 1997-07-14 17:00:00+00:00
437#. Start date: 1997-07-15 17:00:00+00:00
438#: [uid1@example.com]SUMMARY
439#: [uid2@example.com]SUMMARY
440#, fuzzy
441msgid "Value"
442msgstr "Valor"
443"""
444        output = self._convert_to_string(
445            input_string, template_string, duplicate_style="merge"
446        )
447        assert expected_output in output
448        assert "extracted from " in output
449
450
451class TestIcal2POCommand(test_convert.TestConvertCommand, TestIcal2PO):
452    """Tests running actual ical2po commands on files"""
453
454    convertmodule = ical2po
455    defaultoptions = {"progress": "none"}
456
457    def test_help(self, capsys):
458        """tests getting help"""
459        options = super().test_help(capsys)
460        options = self.help_check(options, "-P, --pot")
461        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
462