# Path: paco/once.py
# @decorate
# def once(coro, raise_exception=False, return_value=None):
#     """
#     Wrap a given coroutine function that is restricted to one execution.
# 
#     Repeated calls to the coroutine function will return the value of the first
#     invocation.
# 
#     This function can be used as decorator.
# 
#     arguments:
#         coro (coroutinefunction): coroutine function to wrap.
#         raise_exception (bool): raise exception if execution times exceeded.
#         return_value (mixed): value to return when execution times exceeded,
#             instead of the memoized one from last invocation.
# 
#     Raises:
#         TypeError: if coro argument is not a coroutine function.
# 
#     Returns:
#         coroutinefunction
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         once = paco.once(mul_2)
#         await once(2)
#         # => 4
#         await once(3)
#         # => 4
# 
#         once = paco.once(mul_2, return_value='exceeded')
#         await once(2)
#         # => 4
#         await once(3)
#         # => 'exceeded'
# 
#     """
#     return times(coro,
#                  limit=1,
#                  return_value=return_value,
#                  raise_exception=raise_exception)
# 
# 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 once
from .helpers import run_in_loop
@asyncio.coroutine
def coro(*args, **kw):
    return args, kw


def test_once():
    task = once(coro)

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

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

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


def test_once_return_value():
    task = once(coro, return_value='ignored')

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

    # Ignored calls

# Path: paco/once.py
# @decorate
# def once(coro, raise_exception=False, return_value=None):
#     """
#     Wrap a given coroutine function that is restricted to one execution.
# 
#     Repeated calls to the coroutine function will return the value of the first
#     invocation.
# 
#     This function can be used as decorator.
# 
#     arguments:
#         coro (coroutinefunction): coroutine function to wrap.
#         raise_exception (bool): raise exception if execution times exceeded.
#         return_value (mixed): value to return when execution times exceeded,
#             instead of the memoized one from last invocation.
# 
#     Raises:
#         TypeError: if coro argument is not a coroutine function.
# 
#     Returns:
#         coroutinefunction
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         once = paco.once(mul_2)
#         await once(2)
#         # => 4
#         await once(3)
#         # => 4
# 
#         once = paco.once(mul_2, return_value='exceeded')
#         await once(2)
#         # => 4
#         await once(3)
#         # => 'exceeded'
# 
#     """
#     return times(coro,
#                  limit=1,
#                  return_value=return_value,
#                  raise_exception=raise_exception)
# 
# 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/once_test.py
import pytest
import asyncio
from paco import once
from .helpers import run_in_loop

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


def test_once():
    task = once(coro)

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

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

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


def test_once_return_value():
    task = once(coro, return_value='ignored')

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

    # Ignored calls

    assert run_in_loop(task, 3, foo='foo') == 'ignored'