1import os
2import warnings
3from io import BytesIO
4
5from pytest import mark
6
7from translate.convert import oo2po, po2oo, test_convert
8from translate.storage import po
9
10
11class TestPO2OO:
12    def setup_method(self, method):
13        warnings.resetwarnings()
14
15    def teardown_method(self, method):
16        warnings.resetwarnings()
17
18    def convertoo(self, posource, ootemplate, language="en-US"):
19        """helper to exercise the command line function"""
20        inputfile = BytesIO(posource.encode())
21        outputfile = BytesIO()
22        templatefile = BytesIO(ootemplate.encode())
23        assert po2oo.convertoo(
24            inputfile, outputfile, templatefile, targetlanguage=language, timestamp=0
25        )
26        return outputfile.getvalue()
27
28    def roundtripstring(self, entitystring):
29        oointro, oooutro = (
30            r"svx	source\dialog\numpages.src	0	string	RID_SVXPAGE_NUM_OPTIONS	STR_BULLET			0	en-US	",
31            "				2002-02-02 02:02:02" + "\r\n",
32        )
33        oosource = oointro + entitystring + oooutro
34        ooinputfile = BytesIO(oosource.encode())
35        ooinputfile2 = BytesIO(oosource.encode())
36        pooutputfile = BytesIO()
37        oo2po.convertoo(ooinputfile, pooutputfile, ooinputfile2, targetlanguage="en-US")
38        posource = pooutputfile.getvalue()
39        poinputfile = BytesIO(posource)
40        ootemplatefile = BytesIO(oosource.encode())
41        oooutputfile = BytesIO()
42        po2oo.convertoo(
43            poinputfile, oooutputfile, ootemplatefile, targetlanguage="en-US"
44        )
45        ooresult = oooutputfile.getvalue().decode("utf-8")
46        print(
47            "original oo:\n",
48            oosource,
49            "po version:\n",
50            posource,
51            "output oo:\n",
52            ooresult,
53        )
54        assert ooresult.startswith(oointro) and ooresult.endswith(oooutro)
55        return ooresult[len(oointro) : -len(oooutro)]
56
57    def check_roundtrip(self, oosource):
58        """Checks that the round-tripped string is the same as the original"""
59        assert self.roundtripstring(oosource) == oosource
60
61    @mark.skipif(os.name == "nt", reason="test or storage broken on Windows")
62    def test_convertoo(self):
63        """checks that the convertoo function is working"""
64        oobase = (
65            r"svx	source\dialog\numpages.src	0	string	RID_SVXPAGE_NUM_OPTIONS	STR_BULLET			0	%s	%s				20050924 09:13:58"
66            + "\r\n"
67        )
68        posource = """#: numpages.src#RID_SVXPAGE_NUM_OPTIONS.STR_BULLET.string.text\nmsgid "Simple String"\nmsgstr "Dimpled Ring"\n"""
69        ootemplate = oobase % ("en-US", "Simple String")
70        ooexpected = oobase % ("zu", "Dimpled Ring")
71        newoo = self.convertoo(posource, ootemplate, language="zu")
72        assert newoo.decode("utf-8") == ootemplate + ooexpected
73
74    def test_pofilter(self):
75        """Tests integration with pofilter"""
76        # Some bad po with a few errors:
77        posource = b'#: sourcefile.bla#ID_NUMBER.txet.gnirts\nmsgid "<tag cow=\\"3\\">Mistake."\nmsgstr "  <etiket koei=\\"3\\">(fout) "'
78        filter = po2oo.filter
79        pofile = po.pofile()
80        pofile.parse(posource)
81        assert not filter.validelement(pofile.units[0], "dummyname.po", "exclude-all")
82
83    def test_roundtrip_simple(self):
84        """checks that simple strings make it through a oo->po->oo roundtrip"""
85        self.check_roundtrip("Hello")
86        self.check_roundtrip('"Hello"')
87        self.check_roundtrip('"Hello Everybody"')
88
89    def test_roundtrip_escape(self):
90        """checks that escapes in strings make it through a oo->po->oo roundtrip"""
91        self.check_roundtrip(r'"Simple Escape \ \n \\ \: \t \r "')
92        self.check_roundtrip(r'"More escapes \\n \\t \\r \\: "')
93        self.check_roundtrip(r'"More escapes \\\n \\\t \\\r \\\: "')
94        self.check_roundtrip(r'"More escapes \\\\n \\\\t \\\\r \\\\: "')
95        self.check_roundtrip(r'"End Line Escape \"')
96        self.check_roundtrip(r'"\\rangle \\langle')
97        self.check_roundtrip(r"\\\\<")
98        self.check_roundtrip(r"\\\<")
99        self.check_roundtrip(r"\\<")
100        self.check_roundtrip(r"\<")
101
102    def test_roundtrip_quotes(self):
103        """checks that (escaped) quotes in strings make it through a oo->po->oo roundtrip"""
104        self.check_roundtrip(r"""'Quote Escape "" '""")
105        self.check_roundtrip(r'''"Single-Quote ' "''')
106        self.check_roundtrip(r'''"Single-Quote Escape \' "''')
107        self.check_roundtrip(r"""'Both Quotes "" '' '""")
108
109    def test_roundtrip_spaces(self):
110        # FIXME: this test fails because the resultant PO file returns as po.isempty since .isblank returns true
111        # which is caused by isblankmsgtr returning True.  Its a complete mess which would mean unravelling lots
112        # of yuch in pypo.  Until we have time to do that unravelling we're diabling this test.  You can reenable
113        # once we've fixed that.
114        """checks that (escaped) quotes in strings make it through a oo->po->oo roundtrip"""
115        self.check_roundtrip(" ")
116        self.check_roundtrip("\u00a0")
117
118    def test_default_timestamp(self):
119        """test to ensure that we revert to the default timestamp"""
120        oointro, oooutro = (
121            r"svx	source\dialog\numpages.src	0	string	RID_SVXPAGE_NUM_OPTIONS	STR_BULLET			0	en-US	Text				",
122            "\r\n",
123        )
124        posource = """#: numpages.src#RID_SVXPAGE_NUM_OPTIONS.STR_BULLET.string.text\nmsgid "Text"\nmsgstr "Text"\n"""
125        inputfile = BytesIO(posource.encode())
126        outputfile = BytesIO()
127        templatefile = BytesIO((oointro + "20050924 09:13:58" + oooutro).encode())
128        assert po2oo.convertoo(
129            inputfile, outputfile, templatefile, targetlanguage="en-US"
130        )
131        assert (
132            outputfile.getvalue().decode("utf-8")
133            == oointro + "2002-02-02 02:02:02" + oooutro
134        )
135
136    def test_escape_conversion(self):
137        """test to ensure that we convert escapes correctly"""
138        oosource = (
139            r"svx	source\dialog\numpages.src	0	string	RID_SVXPAGE_NUM_OPTIONS	STR_BULLET			0	en-US	Column1\tColumn2\r\n				2002-02-02 02:02:02"
140            + "\r\n"
141        )
142        posource = """#: numpages.src#RID_SVXPAGE_NUM_OPTIONS.STR_BULLET.string.text\nmsgid "Column1\\tColumn2\\r\\n"\nmsgstr "Kolom1\\tKolom2\\r\\n"\n"""
143        inputfile = BytesIO(posource.encode())
144        outputfile = BytesIO()
145        templatefile = BytesIO(oosource.encode())
146        assert po2oo.convertoo(
147            inputfile, outputfile, templatefile, targetlanguage="af-ZA"
148        )
149        assert b"\tKolom1\\tKolom2\\r\\n\t" in outputfile.getvalue()
150
151    def test_helpcontent_escapes(self):
152        """test to ensure that we convert helpcontent escapes correctly"""
153        # Note how this test specifically uses incorrect spacing in the
154        # translation. The extra space before 'hid' and an extra space before
155        # the closing tag should not confuse us.
156        oosource = (
157            r"helpcontent2	source\text\shared\3dsettings_toolbar.xhp	0	help	par_idN1056A				0	en-US	\<ahelp hid=\".\"\>The 3D-Settings toolbar controls properties of selected 3D objects.\</ahelp\>				2002-02-02 02:02:02"
158            + "\r\n"
159        )
160        posource = r"""#: 3dsettings_toolbar.xhp#par_idN1056A.help.text
161msgid ""
162"<ahelp hid=\".\">The 3D-Settings toolbar controls properties of selected 3D "
163"ob jects.</ahelp>"
164msgstr ""
165"<ahelp  hid=\".\" >Zeee 3DDDD-Settings toolbar controls properties of selected 3D "
166"objects.</ahelp>"
167"""
168        inputfile = BytesIO(posource.encode())
169        outputfile = BytesIO()
170        templatefile = BytesIO(oosource.encode())
171        assert po2oo.convertoo(
172            inputfile, outputfile, templatefile, targetlanguage="af-ZA"
173        )
174        assert (
175            br"\<ahelp  hid=\".\" \>Zeee 3DDDD-Settings toolbar controls properties of selected 3D objects.\</ahelp\>"
176            in outputfile.getvalue()
177        )
178
179    def test_helpcontent_escapes2(self):
180        """test to ensure that we convert helpcontent escapes correctly"""
181        oosource = (
182            r"helpcontent2	source\text\scalc\05\empty_cells.xhp	0	help	par_id2629474				0	en-US	A1: <empty>				2002-02-02 02:02:02"
183            + "\r\n"
184        )
185        posource = r"""#: empty_cells.xhp#par_id2629474.help.text
186msgid "A1: <empty>"
187msgstr "Aa1: <empty>"
188"""
189        inputfile = BytesIO(posource.encode())
190        outputfile = BytesIO()
191        templatefile = BytesIO(oosource.encode())
192        assert po2oo.convertoo(
193            inputfile, outputfile, templatefile, targetlanguage="af-ZA"
194        )
195        assert b"Aa1: <empty>" in outputfile.getvalue()
196
197
198class TestPO2OOCommand(test_convert.TestConvertCommand, TestPO2OO):
199    """Tests running actual po2oo commands on files"""
200
201    convertmodule = po2oo
202
203    def test_help(self, capsys):
204        """tests getting help"""
205        options = super().test_help(capsys)
206        options = self.help_check(options, "--source-language=LANG")
207        options = self.help_check(options, "--language=LANG")
208        options = self.help_check(options, "-T, --keeptimestamp")
209        options = self.help_check(options, "--nonrecursiveoutput")
210        options = self.help_check(options, "--nonrecursivetemplate")
211        options = self.help_check(options, "--filteraction")
212        options = self.help_check(options, "--skipsource")
213        options = self.help_check(options, "--threshold=PERCENT")
214        options = self.help_check(options, "--fuzzy")
215        options = self.help_check(options, "--nofuzzy")
216        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
217        options = self.help_check(options, "--multifile=MULTIFILESTYLE", last=True)
218
219    def convertoo(self, posource, ootemplate, language="en-US"):
220        """helper to exercise the command line function"""
221        self.create_testfile(
222            os.path.join("input", "svx", "source", "dialog.po"), posource
223        )
224        self.create_testfile("input.oo", ootemplate)
225        self.run_command(
226            "input",
227            "output.oo",
228            template="input.oo",
229            language=language,
230            keeptimestamp=True,
231        )
232        return self.read_testfile("output.oo")
233