#
# Copyright 2015 Zuza Software Foundation
# Copyright 2015 Sarah Hale
#
# This file is part of translate.
#
# translate is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# translate is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

"""Tests converting Gettext PO localisation files to .Net Resource (.resx) files."""

from io import BytesIO

from translate.convert import po2resx
from translate.storage import po

from . import test_convert


class TestPO2RESX:
    XMLskeleton = """<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  %s
</root>"""

    @staticmethod
    def po2resx(resxsource, po_source):
        """Helper that merges po translations to .resx source without requiring files."""
        po_store = po.pofile(po_source.encode("utf-8"))
        template_file = BytesIO(resxsource.encode())
        convertor = po2resx.po2resx(template_file, po_store)
        output_resx = convertor.convertstore()
        return output_resx.decode("utf-8")

    def test_simpleunit(self) -> None:
        """Checks that a simple po entry definition converts properly to a resx entry."""
        po_source = r'''#: key
msgid "Source Text"
msgstr "Some translated text"'''
        resx_template = (
            self.XMLskeleton
            % """<data name="key" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="key" xml:space="preserve">
    <value>Some translated text</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_basic(self) -> None:
        po_source = r"""# Afrikaans translation of program ABC
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-12-22 23:20+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: ResourceKey
msgid "Applications"
msgstr "Toepassings"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Toepassings</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_multiline(self) -> None:
        """Test multiline po entry."""
        po_source = r'''#: ResourceKey
msgid "First part "
"and extra"
msgstr "Eerste deel "
"en ekstra"'''
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Eerste deel en ekstra</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_escapednewlines(self) -> None:
        """Test the escaping of newlines."""
        po_source = r"""#: ResourceKey
msgid "First line\nSecond line"
msgstr "Eerste lyn\nTweede lyn"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Eerste lyn
Tweede lyn</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_escapedtabs(self) -> None:
        """Test the escaping of tabs."""
        po_source = r"""#: ResourceKey
msgid "First column\tSecond column"
msgstr "Eerste kolom\tTweede kolom"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Eerste kolom\tTweede kolom</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_escapedquotes(self) -> None:
        """Test the escaping of quotes (and slash)."""
        po_source = r"""#: ResourceKey
msgid "Hello \"Everyone\""
msgstr "Good day \"All\""

msgid "Use \\\"."
msgstr "Gebruik \\\"."
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Good day "All"</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_exclusions(self) -> None:
        """Test that empty and fuzzy messages are excluded."""
        po_source = r"""#: ResourceKey
#, fuzzy
msgid "One"
msgstr "Een"

#: ResourceKey2
msgid "Two"
msgstr ""

#: ResourceKey3
msgid ""
msgstr "Drie"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value />
  </data>
  <data name="ResourceKey2" xml:space="preserve">
    <value />
  </data>
  <data name="ResourceKey3" xml:space="preserve">
    <value />
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value />
  </data>
  <data name="ResourceKey2" xml:space="preserve">
    <value />
  </data>
  <data name="ResourceKey3" xml:space="preserve">
    <value />
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_automaticcomments(self) -> None:
        """Tests that automatic comments are imported."""
        po_source = """#. This is a comment
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is a comment</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_automaticcomments_existingcomment(self) -> None:
        """Tests a differing automatic comment is added if there is an existing automatic comment."""
        po_source = """#. This is a new comment
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>This is an existing comment</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment
This is a new comment</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_automaticcomments_existingduplicatecomment(self) -> None:
        """Tests there is no duplication of automatic comments if it already exists and hasn't changed."""
        po_source = """#. This is an existing comment
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>This is an existing comment</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_automaticcomments_existingduplicatecommentwithwhitespace(self) -> None:
        """
        Tests there is no duplication of automatic comments if it already
        exists, hasn't changed but has leading or trailing whitespaces.
        """
        po_source = """#.  This is an existing comment with leading and trailing spaces
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment> This is an existing comment with leading and trailing spaces </comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment with leading and trailing spaces</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_translatorcomments(self) -> None:
        """Tests that translator comments are imported."""
        po_source = """# This is a translator comment : 22.12.14
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>[Translator Comment: This is a translator comment : 22.12.14]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_translatorcomments_existingcomment(self) -> None:
        """Tests a differing translator comment is added if there is an existing translator comment."""
        po_source = """# This is a new translator comment
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>[Translator Comment: This is an existing comment]</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>[Translator Comment: This is an existing comment]
[Translator Comment: This is a new translator comment]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_translatorcomments_existingduplicatecomment(self) -> None:
        """Tests there is no duplication of translator comments if it already exists and hasn't changed."""
        po_source = """# This is an existing translator comment
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>[Translator Comment: This is an existing translator comment]</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>[Translator Comment: This is an existing translator comment]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_combocomments(self) -> None:
        """Tests that translator comments and automatic comments are imported."""
        po_source = """#. This is a developer comment
# This is a translator comment : 22.12.14
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is a developer comment
[Translator Comment: This is a translator comment : 22.12.14]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_combocomments_existingduplicatecomment(self) -> None:
        """
        Tests there is no duplication of automatic comment if it already exists
        and hasn't changed, but still adds the translator comment.
        """
        po_source = """#. This is an existing comment
# This is a translator comment : 22.12.14
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>This is an existing comment</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment
[Translator Comment: This is a translator comment : 22.12.14]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_combocomments_existingcomment(self) -> None:
        """
        Tests a differing automatic comment is added if there is an existing
        automatic comment, but still adds the translator comment.
        """
        po_source = """#. This is a new comment
# This is a translator comment : 22.12.14
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>This is an existing comment</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment
This is a new comment
[Translator Comment: This is a translator comment : 22.12.14]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_existingcomments(self) -> None:
        """Tests that no extra space is added when there are no changes to existing comments."""
        po_source = """#. This is an existing comment
# This is an existing translator comment : 22.12.14
#: ResourceKey
msgid "Bézier curve"
msgstr "Bézier-kurwe"
"""
        resx_template = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value></value>
    <comment>This is an existing comment
[Translator Comment: This is an existing translator comment : 22.12.14]</comment>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="ResourceKey" xml:space="preserve">
    <value>Bézier-kurwe</value>
    <comment>This is an existing comment
[Translator Comment: This is an existing translator comment : 22.12.14]</comment>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_plus_in_resourcekey(self) -> None:
        """Tests that resource keys with + characters work correctly when properly escaped."""
        # When PO files are generated by the toolkit, + is encoded as %2B in locations
        po_source = r'''#: DLG_WORKFLOW%2B101
msgid "Workflow Dialog"
msgstr "Translated Workflow Dialog"'''
        resx_template = (
            self.XMLskeleton
            % """<data name="DLG_WORKFLOW+101" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="DLG_WORKFLOW+101" xml:space="preserve">
    <value>Translated Workflow Dialog</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")

    def test_special_chars_in_resourcekey(self) -> None:
        """Tests that resource keys with various special characters work when properly escaped."""
        # Plus signs are encoded as %2B in PO file locations
        po_source = r'''#: Button%2BOK
msgid "OK"
msgstr "Oké"

#: Label_Info%2BText
msgid "Information"
msgstr "Inligting"

#: Menu.File%2BSave
msgid "Save"
msgstr "Stoor"'''
        resx_template = (
            self.XMLskeleton
            % """<data name="Button+OK" xml:space="preserve">
    <value></value>
  </data>
  <data name="Label_Info+Text" xml:space="preserve">
    <value></value>
  </data>
  <data name="Menu.File+Save" xml:space="preserve">
    <value></value>
  </data>"""
        )
        expected_output = (
            self.XMLskeleton
            % """<data name="Button+OK" xml:space="preserve">
    <value>Oké</value>
  </data>
  <data name="Label_Info+Text" xml:space="preserve">
    <value>Inligting</value>
  </data>
  <data name="Menu.File+Save" xml:space="preserve">
    <value>Stoor</value>
  </data>"""
        )
        resx_file = self.po2resx(resx_template, po_source)
        assert resx_file == expected_output.replace("\n", "\r\n")


class TestPO2RESXCommand(test_convert.TestConvertCommand, TestPO2RESX):
    """Tests running actual po2resx commands on files."""

    convertmodule = po2resx
    expected_options = [
        "-t TEMPLATE, --template=TEMPLATE",
        "--fuzzy",
        "--nofuzzy",
    ]
