# -*- coding: utf-8 -*-
# :-
# SPDX-FileCopyrightText: © 2025 Franz Glasner
# SPDX-License-Identifier: BSD-3-Clause
# :-
r"""Unit tests for :mod:`cutils.util.glob`

"""

from __future__ import absolute_import, print_function

import _test_setup    # noqa: F401 imported but unused

import sys
import unittest

from cutils.util import PY2
from cutils.util.glob import CharIter, glob_to_regexp


class TestCharIter(unittest.TestCase):

    def test_transitive_iter(self):
        it = CharIter("1234")
        self.assertIs(iter(it), it)

    def test_native_str(self):
        it = CharIter("1234")
        chars = []
        for c in it:
            chars.append(c)
        self.assertEqual("1234", "".join(chars))

    def test_unicode_str(self):
        it = CharIter(u"1234")
        chars = []
        for c in it:
            chars.append(c)
        self.assertEqual(u"1234", "".join(chars))

    def test_byte_str(self):
        it = CharIter(b"1234")
        chars = []
        for c in it:
            chars.append(c)
        self.assertEqual(b"1234", b"".join(chars))

    def test_peek_exhausted(self):
        it = CharIter("1234")
        for _ in it:
            pass
        self.assertIsNone(it.peek())

    def test_peek_first(self):
        it = CharIter("1234")
        self.assertEqual("1", it.peek())
        chars = "".join(it)
        self.assertEqual("1234", chars)
        self.assertIsNone(it.peek())

    def test_peek_from_second(self):
        it = CharIter("1234")
        self.assertEqual("1", it.peek())
        self.assertEqual("1", next(it))
        self.assertEqual("2", it.peek())
        chars = "".join(it)
        self.assertEqual("234", chars)
        self.assertIsNone(it.peek())

    def test_peek_from_second_with_bytes(self):
        it = CharIter(b"1234")
        self.assertEqual(b"1", it.peek())
        self.assertEqual(b"1", next(it))
        self.assertEqual(b"2", it.peek())
        self.assertEqual(b"2", it.peek())        # a second peek is idempotent
        chars = b"".join(it)
        self.assertEqual(b"234", chars)
        self.assertIsNone(it.peek())


class TestGlobToRegexp(unittest.TestCase):

    def test_empty(self):
        self.assertEqual("", glob_to_regexp(""))

    def test_question_mark(self):
        self.assertEqual(".", glob_to_regexp("?"))

    def test_single_star(self):
        self.assertEqual("[^/]*", glob_to_regexp("*"))

    def test_double_star(self):
        self.assertEqual(".*", glob_to_regexp("**"))

    def test_double_star_slash(self):
        self.assertEqual("(?:.*/)?", glob_to_regexp("**/"))

    def test_double_star_in_between(self):
        if PY2:
            # Python 2 escapes all alnum characters in re.escape()
            self.assertEqual("part1\\/(?:.*/)?part2",
                             glob_to_regexp("part1/**/part2"))
        else:

            self.assertEqual("part1/(?:.*/)?part2",
                             glob_to_regexp("part1/**/part2"))

    def test_double_start_in_between2(self):
        if PY2:
            # Python 2 escapes all alnum characters in re.escape()
            self.assertEqual("part1\\/.*\\.py", glob_to_regexp("part1/**.py"))
        else:
            self.assertEqual("part1/.*\\.py", glob_to_regexp("part1/**.py"))

    def test_bracket_simple(self):
        self.assertEqual("[abc]", glob_to_regexp("[abc]"))

    def test_bracket_simple_range(self):
        self.assertEqual("[a-c]", glob_to_regexp("[a-c]"))

    def test_bracket_with_special_chars(self):
        self.assertEqual("[x*?!^]", glob_to_regexp("[x*?!^]"))

    def test_bracket_simple_range_with_escape(self):
        self.assertEqual("[\\\\-c]", glob_to_regexp("[\\-c]"))

    def test_bracket_not_closed(self):
        self.assertEqual("\\[a", glob_to_regexp("[a"))

    def test_bracket_not_closed_escapes(self):
        self.assertEqual("\\[a\\*\\?", glob_to_regexp("[a*?"))

    def test_bracket_with_dash_as_first_character(self):
        self.assertEqual("[\\-a]", glob_to_regexp("[-a]"))

    def test_bracket_with_dash_as_last_character(self):
        self.assertEqual("[a\\-]", glob_to_regexp("[a-]"))

    def test_bracket_with_closing_bracket(self):
        self.assertEqual("[\\]a]", glob_to_regexp("[]a]"))

    def test_bracket_with_caret_as_first_character(self):
        self.assertEqual("[\\^a]", glob_to_regexp("[^a]"))

    def test_bracket_negating_with_dash_as_first_character(self):
        self.assertEqual("[^\\-a]", glob_to_regexp("[!-a]"))

    def test_bracket_negating_with_dash_as_last_character(self):
        self.assertEqual("[^a\\-]", glob_to_regexp("[!a-]"))

    def test_bracket_negating_with_closing_bracket(self):
        self.assertEqual("[^\\]a]", glob_to_regexp("[!]a]"))

    def test_bracket_negating_with_caret_as_first_character(self):
        self.assertEqual("[^^a]", glob_to_regexp("[!^a]"))

    def test_simple_escapes(self):
        for c in "\\()[]{}*.?":
            self.assertEqual("\\"+c, glob_to_regexp("\\"+c))

    def test_simple_escapes_last_backslash(self):
        self.assertEqual("\\\\", glob_to_regexp("\\"))

    def test_auto_escapes(self):
        for c in "*.?":
            self.assertEqual("\\"+c, glob_to_regexp("\\"+c))

    def test_group_simple(self):
        self.assertEqual("(?:abc|def)", glob_to_regexp("{abc,def}"))

    def test_group_complex_nested(self):
        self.assertEqual("(?:abc|(?:[ABQ-Z]|[^A][^/]*))",
                         glob_to_regexp("{abc,{[ABQ-Z],[!A]*}}"))


if __name__ == "__main__":
    sys.exit(unittest.main())
