# Path: librouteros/api.py
# class Api:
# 
#     def __init__(self, protocol: ApiProtocol):
#         self.protocol = protocol
# 
#     def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
#         """
#         Call Api with given command.
#         Yield each row.
# 
#         :param cmd: Command word. eg. /ip/address/print
#         :param kwargs: Dictionary with optional arguments.
#         """
#         words = (compose_word(key, value) for key, value in kwargs.items())
#         self.protocol.writeSentence(cmd, *words)
#         yield from self.readResponse()
# 
#     def rawCmd(self, cmd: str, *words: str) -> ResponseIter:
#         """
#         Call Api with given command and raw words.
#         End user is responsible to properly format each api word argument.
#         :param cmd: Command word. eg. /ip/address/print
#         :param args: Iterable with optional plain api arguments.
#         """
#         self.protocol.writeSentence(cmd, *words)
#         yield from self.readResponse()
# 
#     def readSentence(self) -> typing.Tuple[str, ReplyDict]:
#         """
#         Read one sentence and parse words.
# 
#         :returns: Reply word, dict with attribute words.
#         """
#         reply_word, words = self.protocol.readSentence()
#         return reply_word, dict(parse_word(word) for word in words)
# 
#     def readResponse(self) -> Response:
#         """
#         Yield each sentence untill !done is received.
# 
#         :throws TrapError: If one !trap is received.
#         :throws MultiTrapError: If > 1 !trap is received.
#         """
#         traps = []
#         reply_word = None
#         response = []
#         while reply_word != '!done':
#             reply_word, words = self.readSentence()
#             if reply_word == '!trap':
#                 traps.append(TrapError(**words))
#             elif reply_word in ('!re', '!done') and words:
#                 response.append(words)
# 
#         if len(traps) > 1:
#             raise MultiTrapError(*traps)
#         if len(traps) == 1:
#             raise traps[0]
#         return response
# 
#     def close(self) -> None:
#         self.protocol.close()
# 
#     def path(self, *path: str):
#         return Path(
#             path='',
#             api=self,
#         ).join(*path)
# 
# class Path:
#     """Represents absolute command path."""
# 
#     def __init__(self, path: str, api: Api):
#         self.path = path
#         self.api = api
# 
#     def select(self, key: query.Key, *other: query.Key) -> query.Query:
#         keys = (key, ) + other
#         return query.Query(path=self, keys=keys, api=self.api)
# 
#     def __str__(self) -> str:
#         return self.path
# 
#     def __repr__(self) -> str:
#         return f"<{self.__class__.__name__} {self}>"
# 
#     def __iter__(self) -> ResponseIter:
#         yield from self('print')
# 
#     def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
#         yield from self.api(
#             self.join(cmd).path,
#             **kwargs,
#         )
# 
#     def join(self, *path: str):
#         """Join current path with one or more path strings."""
#         return Path(
#             api=self.api,
#             path=pjoin('/', self.path, *path).rstrip('/'),
#         )
# 
#     def remove(self, *ids: str) -> None:
#         joined = ','.join(ids)
#         tuple(self(
#             'remove',
#             **{'.id': joined},
#         ))
# 
#     def add(self, **kwargs: typing.Any) -> str:
#         ret = self(
#             'add',
#             **kwargs,
#         )
#         return tuple(ret)[0]['ret']
# 
#     def update(self, **kwargs: typing.Any) -> None:
#         tuple(self(
#             'set',
#             **kwargs,
#         ))
# 
# Path: librouteros/query.py
# class Query:
# 
#     def __init__(self, path, keys: typing.Sequence[Key], api):
#         self.path = path
#         self.keys = keys
#         self.api = api
#         self.query: typing.Tuple[str, ...] = tuple()
# 
#     def where(self, *args: str):
#         self.query = tuple(chain.from_iterable(args))
#         return self
# 
#     def __iter__(self) -> ResponseIter:
#         keys = ','.join(str(key) for key in self.keys)
#         keys = f'=.proplist={keys}'
#         cmd = str(self.path.join('print'))
#         return iter(self.api.rawCmd(cmd, keys, *self.query))


from unittest.mock import (
    MagicMock,
)
from librouteros.api import (
    Api,
    Path,
)
from librouteros.query import Query
def test_api_path_returns_Path():
    api = Api(protocol=MagicMock())
    new = api.path('ip', 'address')
    assert new.path == '/ip/address'
    assert new.api == api
    assert isinstance(new, Path)


class Test_Path:

    def setup(self):
        self.path = Path(
            path='/interface',
            api=MagicMock(),
        )

    def test_path_str(self):
        assert str(self.path) == self.path.path

    def test_join_single_param(self):
        assert self.path.join('ethernet').path == self.path.path + '/ethernet'

    def test_join_multi_param(self):
        assert self.path.join('ethernet', 'print').path == self.path.path + '/ethernet/print'

    def test_join_rstrips_slash(self):
        assert self.path.join('ethernet', 'print/').path == self.path.path + '/ethernet/print'

    def test_select_returns_Query(self):
        new = self.path.select('disabled', 'name')

# Path: librouteros/api.py
# class Api:
# 
#     def __init__(self, protocol: ApiProtocol):
#         self.protocol = protocol
# 
#     def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
#         """
#         Call Api with given command.
#         Yield each row.
# 
#         :param cmd: Command word. eg. /ip/address/print
#         :param kwargs: Dictionary with optional arguments.
#         """
#         words = (compose_word(key, value) for key, value in kwargs.items())
#         self.protocol.writeSentence(cmd, *words)
#         yield from self.readResponse()
# 
#     def rawCmd(self, cmd: str, *words: str) -> ResponseIter:
#         """
#         Call Api with given command and raw words.
#         End user is responsible to properly format each api word argument.
#         :param cmd: Command word. eg. /ip/address/print
#         :param args: Iterable with optional plain api arguments.
#         """
#         self.protocol.writeSentence(cmd, *words)
#         yield from self.readResponse()
# 
#     def readSentence(self) -> typing.Tuple[str, ReplyDict]:
#         """
#         Read one sentence and parse words.
# 
#         :returns: Reply word, dict with attribute words.
#         """
#         reply_word, words = self.protocol.readSentence()
#         return reply_word, dict(parse_word(word) for word in words)
# 
#     def readResponse(self) -> Response:
#         """
#         Yield each sentence untill !done is received.
# 
#         :throws TrapError: If one !trap is received.
#         :throws MultiTrapError: If > 1 !trap is received.
#         """
#         traps = []
#         reply_word = None
#         response = []
#         while reply_word != '!done':
#             reply_word, words = self.readSentence()
#             if reply_word == '!trap':
#                 traps.append(TrapError(**words))
#             elif reply_word in ('!re', '!done') and words:
#                 response.append(words)
# 
#         if len(traps) > 1:
#             raise MultiTrapError(*traps)
#         if len(traps) == 1:
#             raise traps[0]
#         return response
# 
#     def close(self) -> None:
#         self.protocol.close()
# 
#     def path(self, *path: str):
#         return Path(
#             path='',
#             api=self,
#         ).join(*path)
# 
# class Path:
#     """Represents absolute command path."""
# 
#     def __init__(self, path: str, api: Api):
#         self.path = path
#         self.api = api
# 
#     def select(self, key: query.Key, *other: query.Key) -> query.Query:
#         keys = (key, ) + other
#         return query.Query(path=self, keys=keys, api=self.api)
# 
#     def __str__(self) -> str:
#         return self.path
# 
#     def __repr__(self) -> str:
#         return f"<{self.__class__.__name__} {self}>"
# 
#     def __iter__(self) -> ResponseIter:
#         yield from self('print')
# 
#     def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
#         yield from self.api(
#             self.join(cmd).path,
#             **kwargs,
#         )
# 
#     def join(self, *path: str):
#         """Join current path with one or more path strings."""
#         return Path(
#             api=self.api,
#             path=pjoin('/', self.path, *path).rstrip('/'),
#         )
# 
#     def remove(self, *ids: str) -> None:
#         joined = ','.join(ids)
#         tuple(self(
#             'remove',
#             **{'.id': joined},
#         ))
# 
#     def add(self, **kwargs: typing.Any) -> str:
#         ret = self(
#             'add',
#             **kwargs,
#         )
#         return tuple(ret)[0]['ret']
# 
#     def update(self, **kwargs: typing.Any) -> None:
#         tuple(self(
#             'set',
#             **kwargs,
#         ))
# 
# Path: librouteros/query.py
# class Query:
# 
#     def __init__(self, path, keys: typing.Sequence[Key], api):
#         self.path = path
#         self.keys = keys
#         self.api = api
#         self.query: typing.Tuple[str, ...] = tuple()
# 
#     def where(self, *args: str):
#         self.query = tuple(chain.from_iterable(args))
#         return self
# 
#     def __iter__(self) -> ResponseIter:
#         keys = ','.join(str(key) for key in self.keys)
#         keys = f'=.proplist={keys}'
#         cmd = str(self.path.join('print'))
#         return iter(self.api.rawCmd(cmd, keys, *self.query))


# Path: tests/unit/test_path.py
from unittest.mock import (
    MagicMock,
)
from librouteros.api import (
    Api,
    Path,
)
from librouteros.query import Query

def test_api_path_returns_Path():
    api = Api(protocol=MagicMock())
    new = api.path('ip', 'address')
    assert new.path == '/ip/address'
    assert new.api == api
    assert isinstance(new, Path)


class Test_Path:

    def setup(self):
        self.path = Path(
            path='/interface',
            api=MagicMock(),
        )

    def test_path_str(self):
        assert str(self.path) == self.path.path

    def test_join_single_param(self):
        assert self.path.join('ethernet').path == self.path.path + '/ethernet'

    def test_join_multi_param(self):
        assert self.path.join('ethernet', 'print').path == self.path.path + '/ethernet/print'

    def test_join_rstrips_slash(self):
        assert self.path.join('ethernet', 'print/').path == self.path.path + '/ethernet/print'

    def test_select_returns_Query(self):
        new = self.path.select('disabled', 'name')

        assert type(new) == Query