1from io import BytesIO
2
3from translate.convert import csv2po, po2csv, test_convert
4from translate.storage import csvl10n, po
5from translate.storage.test_base import first_translatable, headerless_len
6
7
8class TestPO2CSV:
9    def po2csv(self, posource):
10        """helper that converts po source to csv source without requiring files"""
11        inputfile = BytesIO(posource.encode())
12        inputpo = po.pofile(inputfile)
13        convertor = po2csv.po2csv()
14        return convertor.convertstore(inputpo)
15
16    def csv2po(self, csvsource, template=None):
17        """helper that converts csv source to po source without requiring files"""
18        inputfile = BytesIO(csvsource)
19        inputcsv = csvl10n.csvfile(inputfile)
20        if template:
21            templatefile = BytesIO(template.encode())
22            inputpot = po.pofile(templatefile)
23        else:
24            inputpot = None
25        convertor = csv2po.csv2po(templatepo=inputpot)
26        return convertor.convertstore(inputcsv)
27
28    def singleelement(self, storage):
29        """checks that the pofile contains a single non-header element, and returns it"""
30        assert headerless_len(storage.units) == 1
31        return first_translatable(storage)
32
33    def test_simpleentity(self):
34        """checks that a simple csv entry definition converts properly to a po entry"""
35        minipo = r'''#: term.cpp
36msgid "Term"
37msgstr "asdf"'''
38        csvfile = self.po2csv(minipo)
39        unit = self.singleelement(csvfile)
40        assert unit.location == "term.cpp"
41        assert unit.source == "Term"
42        assert unit.target == "asdf"
43
44    def test_multiline(self):
45        """tests multiline po entries"""
46        minipo = r'''msgid "First part "
47"and extra"
48msgstr "Eerste deel "
49"en ekstra"'''
50        csvfile = self.po2csv(minipo)
51        unit = self.singleelement(csvfile)
52        assert unit.source == "First part and extra"
53        assert unit.target == "Eerste deel en ekstra"
54
55    def test_escapednewlines(self):
56        """Test the escaping of newlines"""
57        minipo = r"""msgid "First line\nSecond line"
58msgstr "Eerste lyn\nTweede lyn"
59"""
60        csvfile = self.po2csv(minipo)
61        unit = self.singleelement(csvfile)
62        assert unit.source == "First line\nSecond line"
63        assert unit.target == "Eerste lyn\nTweede lyn"
64        pofile = self.csv2po(bytes(csvfile))
65        unit = self.singleelement(pofile)
66        assert unit.source == "First line\nSecond line"
67        assert unit.target == "Eerste lyn\nTweede lyn"
68
69    def test_escapedtabs(self):
70        """Test the escaping of tabs"""
71        minipo = r"""msgid "First column\tSecond column"
72msgstr "Eerste kolom\tTweede kolom"
73"""
74        csvfile = self.po2csv(minipo)
75        unit = self.singleelement(csvfile)
76        assert unit.source == "First column\tSecond column"
77        assert unit.target == "Eerste kolom\tTweede kolom"
78        assert (
79            csvfile.findunit("First column\tSecond column").target
80            == "Eerste kolom\tTweede kolom"
81        )
82
83    def test_escapedquotes(self):
84        """Test the escaping of quotes (and slash)"""
85        minipo = r"""msgid "Hello \"Everyone\""
86msgstr "Good day \"All\""
87
88msgid "Use \\\"."
89msgstr "Gebruik \\\"."
90"""
91        csvfile = self.po2csv(minipo)
92        assert csvfile.findunit('Hello "Everyone"').target == 'Good day "All"'
93        assert csvfile.findunit('Use \\".').target == 'Gebruik \\".'
94
95    def test_escapedescape(self):
96        """Test the escaping of pure escapes is unaffected"""
97        minipo = r"""msgid "Find\\Options"
98msgstr "Vind\\Opsies"
99"""
100        csvfile = self.po2csv(minipo)
101        print(minipo)
102        print(csvfile)
103        assert csvfile.findunit(r"Find\Options").target == r"Vind\Opsies"
104
105    def test_singlequotes(self):
106        """Tests that single quotes are preserved correctly"""
107        minipo = """msgid "source 'source'"\nmsgstr "target 'target'"\n"""
108        csvfile = self.po2csv(minipo)
109        print(bytes(csvfile))
110        assert csvfile.findunit("source 'source'").target == "target 'target'"
111        # Make sure we don't mess with start quotes until writing
112        minipo = """msgid "'source'"\nmsgstr "'target'"\n"""
113        csvfile = self.po2csv(minipo)
114        print(bytes(csvfile))
115        assert csvfile.findunit(r"'source'").target == r"'target'"
116        # TODO check that we escape on writing not in the internal representation
117
118    def test_empties(self):
119        """Tests that things keep working with empty entries"""
120        minipo = 'msgid "Source"\nmsgstr ""\n\nmsgid ""\nmsgstr ""'
121        csvfile = self.po2csv(minipo)
122        assert csvfile.findunit("Source") is not None
123        assert csvfile.findunit("Source").target == ""
124        assert headerless_len(csvfile.units) == 1
125
126    def test_kdecomments(self):
127        """test that we don't carry KDE comments to CSV"""
128        minipo = '#: simple.c\nmsgid "_: KDE comment\\n"\n"Same"\nmsgstr "Same"\n'
129        csvfile = self.po2csv(minipo)
130        unit = self.singleelement(csvfile)
131        assert unit.source == "Same"
132        assert unit.target == "Same"
133
134
135class TestPO2CSVCommand(test_convert.TestConvertCommand, TestPO2CSV):
136    """Tests running actual po2csv commands on files"""
137
138    convertmodule = po2csv
139
140    def test_help(self, capsys):
141        """tests getting help"""
142        options = super().test_help(capsys)
143        options = self.help_check(options, "--columnorder=COLUMNORDER", last=True)
144
145    def test_columnorder(self):
146        pocontent = '#: simple.c\nmsgid "Same"\nmsgstr "Target"\n'
147        self.create_testfile("test.po", pocontent)
148
149        self.run_command("test.po", "test.csv")
150        content = self.open_testfile("test.csv", "r").read()
151        assert (
152            content
153            == """"location","source","target"
154"simple.c","Same","Target"
155"""
156        )
157
158        self.run_command("test.po", "test.csv", columnorder="target,source")
159        content = self.open_testfile("test.csv", "r").read()
160        assert (
161            content
162            == """"target","source"
163"Target","Same"
164"""
165        )
166