# Copyright 2021 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

from portage import _shell_quote
from portage.tests import TestCase


class ShellQuoteTestCase(TestCase):
    def testShellQuote(self):
        test_data = [
            # String contains no special characters, should be preserved.
            ("abc", "abc"),
            # String contains whitespace, should be double-quoted to prevent word splitting.
            ("abc xyz", '"abc xyz"'),
            ("abc  xyz", '"abc  xyz"'),
            (" abcxyz ", '" abcxyz "'),
            ("abc\txyz", '"abc\txyz"'),
            ("abc\t\txyz", '"abc\t\txyz"'),
            ("\tabcxyz\t", '"\tabcxyz\t"'),
            ("abc\nxyz", '"abc\nxyz"'),
            ("abc\n\nxyz", '"abc\n\nxyz"'),
            ("\nabcxyz\n", '"\nabcxyz\n"'),
            # String contains > or <, should be double-quoted to prevent redirection.
            ("abc>xyz", '"abc>xyz"'),
            ("abc>>xyz", '"abc>>xyz"'),
            (">abcxyz>", '">abcxyz>"'),
            ("abc<xyz", '"abc<xyz"'),
            ("abc<<xyz", '"abc<<xyz"'),
            ("<abcxyz<", '"<abcxyz<"'),
            # String contains =, should be double-quoted to prevent assignment.
            ("abc=xyz", '"abc=xyz"'),
            ("abc==xyz", '"abc==xyz"'),
            ("=abcxyz=", '"=abcxyz="'),
            # String contains *, should be double-quoted to prevent globbing.
            ("abc*xyz", '"abc*xyz"'),
            ("abc**xyz", '"abc**xyz"'),
            ("*abcxyz*", '"*abcxyz*"'),
            # String contains $, should be escaped to prevent parameter expansion.
            # Also double-quoted, though not strictly needed.
            ("abc$xyz", '"abc\\$xyz"'),
            ("abc$$xyz", '"abc\\$\\$xyz"'),
            ("$abcxyz$", '"\\$abcxyz\\$"'),
            # String contains `, should be escaped to prevent command substitution.
            # Also double-quoted, though not strictly needed.
            ("abc`xyz", '"abc\\`xyz"'),
            ("abc``xyz", '"abc\\`\\`xyz"'),
            ("`abc`", '"\\`abc\\`"'),
            # String contains \, should be escaped to prevent it from escaping
            # the next character. Also double-quoted, though not strictly needed.
            ("abc\\xyz", '"abc\\\\xyz"'),
            ("abc\\\\xyz", '"abc\\\\\\\\xyz"'),
            ("\\abcxyz\\", '"\\\\abcxyz\\\\"'),
            # String contains ", should be escaped to prevent it from unexpectedly
            # ending a previous double-quote or starting a new double-quote. Also
            # double-quoted, though not strictly needed.
            ('abc"xyz', '"abc\\"xyz"'),
            ('abc""xyz', '"abc\\"\\"xyz"'),
            ('"abcxyz"', '"\\"abcxyz\\""'),
            # String contains ', should be double-quoted to prevent it from unexpectedly
            # ending a previous single-quote or starting a new single-quote.
            ("abc'xyz", '"abc\'xyz"'),
            ("abc''xyz", "\"abc''xyz\""),
            ("'abcxyz'", "\"'abcxyz'\""),
            # String contains ;, should be double-quoted to prevent command separation.
            ("abc;xyz", '"abc;xyz"'),
            ("abc;;xyz", '"abc;;xyz"'),
            (";abcxyz;", '";abcxyz;"'),
            # String contains &, should be double-quoted to prevent job control.
            ("abc&xyz", '"abc&xyz"'),
            ("abc&&xyz", '"abc&&xyz"'),
            ("&abcxyz&", '"&abcxyz&"'),
            # String contains |, should be double-quoted to prevent piping.
            ("abc|xyz", '"abc|xyz"'),
            ("abc||xyz", '"abc||xyz"'),
            ("|abcxyz|", '"|abcxyz|"'),
            # String contains (), should be double-quoted to prevent
            # command group / array initialization.
            ("abc()xyz", '"abc()xyz"'),
            ("abc(())xyz", '"abc(())xyz"'),
            ("((abcxyz))", '"((abcxyz))"'),
            # String contains {}. Parameter expansion of the form ${} is already
            # rendered safe by escaping the $, but {} could also occur on its own,
            # for example in a brace expansion such as filename.{ext1,ext2},
            # so the string should be double-quoted.
            ("abc{}xyz", '"abc{}xyz"'),
            ("abc{{}}xyz", '"abc{{}}xyz"'),
            ("{{abcxyz}}", '"{{abcxyz}}"'),
            # String contains [], should be double-quoted to prevent testing
            ("abc[]xyz", '"abc[]xyz"'),
            ("abc[[]]xyz", '"abc[[]]xyz"'),
            ("[[abcxyz]]", '"[[abcxyz]]"'),
            # String contains #, should be double-quoted to prevent comment.
            ("#abc", '"#abc"'),
            # String contains !, should be double-quoted to prevent e.g. history substitution.
            ("!abc", '"!abc"'),
            # String contains ~, should be double-quoted to prevent home directory expansion.
            ("~abc", '"~abc"'),
            # String contains ?, should be double-quoted to prevent globbing.
            ("abc?xyz", '"abc?xyz"'),
            ("abc??xyz", '"abc??xyz"'),
            ("?abcxyz?", '"?abcxyz?"'),
        ]

        for data, expected_result in test_data:
            result = _shell_quote(data)
            self.assertEqual(result, expected_result)
