# Path: flap/latex/commons.py
# class Stream:
#     """
#     A stream of characters, on which we can peek.
# 
#     One can equip a stream with an event handler that gets triggered
#     every times the stream moves forward, that is every time the take
#     method is called, directly or indirectly.
#     """
# 
#     def __init__(self, iterable, handler=lambda x: None):
#         assert hasattr(iterable, "__iter__"), \
#             "Stream requires an iterable, but found an '%s'!" % (
#                 type(iterable))
#         self._characters = iter(iterable)
#         assert callable(handler), \
#             "Stream expect a callable hanlder, but found a '%s" % (
#                 type(handler))
#         self._handler = handler
#         self._cache = []
# 
#     def look_ahead(self):
#         next_item = self._take()
#         if next_item:
#             self._cache.append(next_item)
#         return next_item
# 
#     @property
#     def is_empty(self):
#         return self.look_ahead() is None
# 
#     def _take(self):
#         if self._cache:
#             return self._cache.pop()
#         try:
#             return next(self._characters)
#         except StopIteration:
#             return None
# 
#     def take(self):
#         element = self._take()
#         # logger.debug("Taking %s", str(element))
#         self._handler(element)
#         return element
# 
#     def take_while(self, match):
#         buffer = []
#         while self.look_ahead() and match(self.look_ahead()):
#             buffer.append(self.take())
#         return buffer
# 
#     def take_all(self):
#         return self.take_while(lambda e: e is not None)
# 
#     def push(self, items):
#         if isinstance(items, list):
#             assert not any(i is None for i in items), \
#                 "Cannot push None!"
#             self._cache.extend(reversed(items))
#         else:
#             assert items is not None, \
#                 "Cannot push None"
#             self._cache.append(items)
#         logger.debug(f"Pushing! New cache size: {str(len(self._cache))}")
#         # self.debug()
# 
#     def debug(self):
#         logger.debug("View of the stack ...")
#         for index in range(len(self._cache)):
#             item = self._cache[-(index+1)]
#             text = str(item) if isinstance(item, str) else item.as_text
#             logger.debug(f"  - {index}: {item}")
# 
# class Position:
# 
#     UNKNOWN = "Unknown source file"
#     REPRESENTATION = "{source} @({line}, {column})"
# 
#     def __init__(self, line, column, source=None):
#         self._source = source or self.UNKNOWN
#         self._line = line
#         self._column = column
# 
#     @property
#     def source(self):
#         return self._source
# 
#     @property
#     def line(self):
#         return self._line
# 
#     @property
#     def column(self):
#         return self._column
# 
#     def next_line(self):
#         return Position(self._line + 1, 0, self._source)
# 
#     def next_character(self):
#         return Position(self._line, self._column + 1, self._source)
# 
#     def __eq__(self, other):
#         if not isinstance(other, Position):
#             return False
#         return self._line == other._line and \
#             self._column == other._column
# 
#     def __repr__(self):
#         return self.REPRESENTATION.format(
#             source=self._source, line=self._line, column=self._column)


from unittest import TestCase, main
from unittest.mock import MagicMock
from flap.latex.commons import Stream, Position
        self._handler.assert_not_called()


class ListStreamTest(TestCase):

    def setUp(self):
        self._text = "sample text"
        self._handler = MagicMock()
        self._stream = Stream([c for c in self._text], self._handler)

    def test_returns_all_characters(self):
        self._verify_stream_content_is(self._text)

    def test_push(self):
        self._stream.push("abcdef")
        self._verify_stream_content_is( "abcdef" + self._text)

    def _verify_stream_content_is(self, expected):
        self.assertEqual(expected, "".join(self._stream.take_all()))


class PositionTest(TestCase):

    def setUp(self):
        self._line = 1
        self._column = 4
        self._position = self._at(self._line, self._column)

    @staticmethod
    def _at(line, column):

# Path: flap/latex/commons.py
# class Stream:
#     """
#     A stream of characters, on which we can peek.
# 
#     One can equip a stream with an event handler that gets triggered
#     every times the stream moves forward, that is every time the take
#     method is called, directly or indirectly.
#     """
# 
#     def __init__(self, iterable, handler=lambda x: None):
#         assert hasattr(iterable, "__iter__"), \
#             "Stream requires an iterable, but found an '%s'!" % (
#                 type(iterable))
#         self._characters = iter(iterable)
#         assert callable(handler), \
#             "Stream expect a callable hanlder, but found a '%s" % (
#                 type(handler))
#         self._handler = handler
#         self._cache = []
# 
#     def look_ahead(self):
#         next_item = self._take()
#         if next_item:
#             self._cache.append(next_item)
#         return next_item
# 
#     @property
#     def is_empty(self):
#         return self.look_ahead() is None
# 
#     def _take(self):
#         if self._cache:
#             return self._cache.pop()
#         try:
#             return next(self._characters)
#         except StopIteration:
#             return None
# 
#     def take(self):
#         element = self._take()
#         # logger.debug("Taking %s", str(element))
#         self._handler(element)
#         return element
# 
#     def take_while(self, match):
#         buffer = []
#         while self.look_ahead() and match(self.look_ahead()):
#             buffer.append(self.take())
#         return buffer
# 
#     def take_all(self):
#         return self.take_while(lambda e: e is not None)
# 
#     def push(self, items):
#         if isinstance(items, list):
#             assert not any(i is None for i in items), \
#                 "Cannot push None!"
#             self._cache.extend(reversed(items))
#         else:
#             assert items is not None, \
#                 "Cannot push None"
#             self._cache.append(items)
#         logger.debug(f"Pushing! New cache size: {str(len(self._cache))}")
#         # self.debug()
# 
#     def debug(self):
#         logger.debug("View of the stack ...")
#         for index in range(len(self._cache)):
#             item = self._cache[-(index+1)]
#             text = str(item) if isinstance(item, str) else item.as_text
#             logger.debug(f"  - {index}: {item}")
# 
# class Position:
# 
#     UNKNOWN = "Unknown source file"
#     REPRESENTATION = "{source} @({line}, {column})"
# 
#     def __init__(self, line, column, source=None):
#         self._source = source or self.UNKNOWN
#         self._line = line
#         self._column = column
# 
#     @property
#     def source(self):
#         return self._source
# 
#     @property
#     def line(self):
#         return self._line
# 
#     @property
#     def column(self):
#         return self._column
# 
#     def next_line(self):
#         return Position(self._line + 1, 0, self._source)
# 
#     def next_character(self):
#         return Position(self._line, self._column + 1, self._source)
# 
#     def __eq__(self, other):
#         if not isinstance(other, Position):
#             return False
#         return self._line == other._line and \
#             self._column == other._column
# 
#     def __repr__(self):
#         return self.REPRESENTATION.format(
#             source=self._source, line=self._line, column=self._column)


# Path: tests/unit/latex/test_commons.py
from unittest import TestCase, main
from unittest.mock import MagicMock
from flap.latex.commons import Stream, Position

        self._handler.assert_not_called()


class ListStreamTest(TestCase):

    def setUp(self):
        self._text = "sample text"
        self._handler = MagicMock()
        self._stream = Stream([c for c in self._text], self._handler)

    def test_returns_all_characters(self):
        self._verify_stream_content_is(self._text)

    def test_push(self):
        self._stream.push("abcdef")
        self._verify_stream_content_is( "abcdef" + self._text)

    def _verify_stream_content_is(self, expected):
        self.assertEqual(expected, "".join(self._stream.take_all()))


class PositionTest(TestCase):

    def setUp(self):
        self._line = 1
        self._column = 4
        self._position = self._at(self._line, self._column)

    @staticmethod
    def _at(line, column):

        return Position(line, column)