# Copyright (C) 2015-2018  The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information

import unittest

from swh.core import utils


class UtilsLib(unittest.TestCase):
    def test_grouper(self):
        # given
        actual_data = utils.grouper((i for i in range(0, 9)), 2)

        out = []
        for d in actual_data:
            out.append(list(d))  # force generator resolution for checks

        self.assertEqual(out, [[0, 1], [2, 3], [4, 5], [6, 7], [8]])

        # given
        actual_data = utils.grouper((i for i in range(9, 0, -1)), 4)

        out = []
        for d in actual_data:
            out.append(list(d))  # force generator resolution for checks

        self.assertEqual(out, [[9, 8, 7, 6], [5, 4, 3, 2], [1]])

    def test_grouper_with_stop_value(self):
        # given
        actual_data = utils.grouper(((i, i + 1) for i in range(0, 9)), 2)

        out = []
        for d in actual_data:
            out.append(list(d))  # force generator resolution for checks

        self.assertEqual(
            out,
            [
                [(0, 1), (1, 2)],
                [(2, 3), (3, 4)],
                [(4, 5), (5, 6)],
                [(6, 7), (7, 8)],
                [(8, 9)],
            ],
        )

        # given
        actual_data = utils.grouper((i for i in range(9, 0, -1)), 4)

        out = []
        for d in actual_data:
            out.append(list(d))  # force generator resolution for checks

        self.assertEqual(out, [[9, 8, 7, 6], [5, 4, 3, 2], [1]])

    def test_backslashescape_errors(self):
        raw_data_err = b"abcd\x80"
        with self.assertRaises(UnicodeDecodeError):
            raw_data_err.decode("utf-8", "strict")

        self.assertEqual(
            raw_data_err.decode("utf-8", "backslashescape"), "abcd\\x80",
        )

        raw_data_ok = b"abcd\xc3\xa9"
        self.assertEqual(
            raw_data_ok.decode("utf-8", "backslashescape"),
            raw_data_ok.decode("utf-8", "strict"),
        )

        unicode_data = "abcdef\u00a3"
        self.assertEqual(
            unicode_data.encode("ascii", "backslashescape"), b"abcdef\\xa3",
        )

    def test_encode_with_unescape(self):
        valid_data = "\\x01020304\\x00"
        valid_data_encoded = b"\x01020304\x00"

        self.assertEqual(valid_data_encoded, utils.encode_with_unescape(valid_data))

    def test_encode_with_unescape_invalid_escape(self):
        invalid_data = "test\\abcd"

        with self.assertRaises(ValueError) as exc:
            utils.encode_with_unescape(invalid_data)

        self.assertIn("invalid escape", exc.exception.args[0])
        self.assertIn("position 4", exc.exception.args[0])

    def test_decode_with_escape(self):
        backslashes = b"foo\\bar\\\\baz"
        backslashes_escaped = "foo\\\\bar\\\\\\\\baz"

        self.assertEqual(
            backslashes_escaped, utils.decode_with_escape(backslashes),
        )

        valid_utf8 = b"foo\xc3\xa2"
        valid_utf8_escaped = "foo\u00e2"

        self.assertEqual(
            valid_utf8_escaped, utils.decode_with_escape(valid_utf8),
        )

        invalid_utf8 = b"foo\xa2"
        invalid_utf8_escaped = "foo\\xa2"

        self.assertEqual(
            invalid_utf8_escaped, utils.decode_with_escape(invalid_utf8),
        )

        valid_utf8_nul = b"foo\xc3\xa2\x00"
        valid_utf8_nul_escaped = "foo\u00e2\\x00"

        self.assertEqual(
            valid_utf8_nul_escaped, utils.decode_with_escape(valid_utf8_nul),
        )

    def test_commonname(self):
        # when
        actual_commonname = utils.commonname("/some/where/to/", "/some/where/to/go/to")
        # then
        self.assertEqual("go/to", actual_commonname)

        # when
        actual_commonname2 = utils.commonname(
            b"/some/where/to/", b"/some/where/to/go/to"
        )
        # then
        self.assertEqual(b"go/to", actual_commonname2)
