# Path: paco/times.py
# @decorate
# def times(coro, limit=1, raise_exception=False, return_value=None):
#     """
#     Wraps a given coroutine function to be executed only a certain amount
#     of times.
# 
#     If the execution limit is exceeded, the last execution return value will
#     be returned as result.
# 
#     You can optionally define a custom return value on exceeded via
#     `return_value` param.
# 
#     This function can be used as decorator.
# 
#     arguments:
#         coro (coroutinefunction): coroutine function to wrap.
#         limit (int): max limit of coroutine executions.
#         raise_exception (bool): raise exception if execution times exceeded.
#         return_value (mixed): value to return when execution times exceeded.
# 
#     Raises:
#         TypeError: if coro argument is not a coroutine function.
#         RuntimeError: if max execution excedeed (optional).
# 
#     Returns:
#         coroutinefunction
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         timed = paco.times(mul_2, 3)
#         await timed(2)
#         # => 4
#         await timed(3)
#         # => 6
#         await timed(4)
#         # => 8
#         await timed(5)  # ignored!
#         # => 8
#     """
#     assert_corofunction(coro=coro)
# 
#     # Store call times
#     limit = max(limit, 1)
#     times = limit
# 
#     # Store result from last execution
#     result = None
# 
#     @asyncio.coroutine
#     def wrapper(*args, **kw):
#         nonlocal limit
#         nonlocal result
# 
#         # Check execution limit
#         if limit == 0:
#             if raise_exception:
#                 raise RuntimeError(ExceptionMessage.format(times))
#             if return_value:
#                 return return_value
#             return result
# 
#         # Decreases counter
#         limit -= 1
# 
#         # If return_value is present, do not memoize result
#         if return_value:
#             return (yield from coro(*args, **kw))
# 
#         # Schedule coroutine and memoize result
#         result = yield from coro(*args, **kw)
#         return result
# 
#     return wrapper
# 
# Path: tests/helpers.py
# def run_in_loop(coro, *args, **kw):
#     loop = asyncio.get_event_loop()
#     if asyncio.iscoroutinefunction(coro) or isfunction(coro):
#         coro = coro(*args, **kw)
#     return loop.run_until_complete(coro)


import pytest
import asyncio
from paco import times
from .helpers import run_in_loop
# -*- coding: utf-8 -*-


@asyncio.coroutine
def coro(*args, **kw):
    return args, kw


def test_times():
    task = times(coro, 2)

    args, kw = run_in_loop(task, 1, 2, foo='bar')
    assert args == (1, 2)
    assert kw == {'foo': 'bar'}

    args, kw = run_in_loop(task, 3, 4, foo='baz')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}

    # Memoized result
    args, kw = run_in_loop(task, 5, 6, foo='foo')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}

    args, kw = run_in_loop(task, 7, 8, foo='foo')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}


def test_times_return_value():

# Path: paco/times.py
# @decorate
# def times(coro, limit=1, raise_exception=False, return_value=None):
#     """
#     Wraps a given coroutine function to be executed only a certain amount
#     of times.
# 
#     If the execution limit is exceeded, the last execution return value will
#     be returned as result.
# 
#     You can optionally define a custom return value on exceeded via
#     `return_value` param.
# 
#     This function can be used as decorator.
# 
#     arguments:
#         coro (coroutinefunction): coroutine function to wrap.
#         limit (int): max limit of coroutine executions.
#         raise_exception (bool): raise exception if execution times exceeded.
#         return_value (mixed): value to return when execution times exceeded.
# 
#     Raises:
#         TypeError: if coro argument is not a coroutine function.
#         RuntimeError: if max execution excedeed (optional).
# 
#     Returns:
#         coroutinefunction
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         timed = paco.times(mul_2, 3)
#         await timed(2)
#         # => 4
#         await timed(3)
#         # => 6
#         await timed(4)
#         # => 8
#         await timed(5)  # ignored!
#         # => 8
#     """
#     assert_corofunction(coro=coro)
# 
#     # Store call times
#     limit = max(limit, 1)
#     times = limit
# 
#     # Store result from last execution
#     result = None
# 
#     @asyncio.coroutine
#     def wrapper(*args, **kw):
#         nonlocal limit
#         nonlocal result
# 
#         # Check execution limit
#         if limit == 0:
#             if raise_exception:
#                 raise RuntimeError(ExceptionMessage.format(times))
#             if return_value:
#                 return return_value
#             return result
# 
#         # Decreases counter
#         limit -= 1
# 
#         # If return_value is present, do not memoize result
#         if return_value:
#             return (yield from coro(*args, **kw))
# 
#         # Schedule coroutine and memoize result
#         result = yield from coro(*args, **kw)
#         return result
# 
#     return wrapper
# 
# Path: tests/helpers.py
# def run_in_loop(coro, *args, **kw):
#     loop = asyncio.get_event_loop()
#     if asyncio.iscoroutinefunction(coro) or isfunction(coro):
#         coro = coro(*args, **kw)
#     return loop.run_until_complete(coro)


# Path: tests/times_test.py
import pytest
import asyncio
from paco import times
from .helpers import run_in_loop

# -*- coding: utf-8 -*-


@asyncio.coroutine
def coro(*args, **kw):
    return args, kw


def test_times():
    task = times(coro, 2)

    args, kw = run_in_loop(task, 1, 2, foo='bar')
    assert args == (1, 2)
    assert kw == {'foo': 'bar'}

    args, kw = run_in_loop(task, 3, 4, foo='baz')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}

    # Memoized result
    args, kw = run_in_loop(task, 5, 6, foo='foo')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}

    args, kw = run_in_loop(task, 7, 8, foo='foo')
    assert args == (3, 4)
    assert kw == {'foo': 'baz'}


def test_times_return_value():

    task = times(coro, 1, return_value='ignored')