# Path: microcosm_pubsub/chain/chain.py
# class Chain:
#     """
#     Structure that contains callable functions that shares the same context.
# 
#     """
#     def __init__(self, *args):
#         """
#         Build a chain that can be resolved multiple times
#         :param *args: callable functions, Chain statemnts or other Chains
# 
#         """
#         self.links = list(args)
# 
#     @property
#     def context_decorators(self):
#         """
#         Decorators to apply to the chain links
# 
#         """
#         return [
#             # Order matter - get_from_context should be first
#             get_from_context,
#             temporarily_replace_context_keys,
#             save_to_context,
#             save_to_context_by_func_name,
#         ]
# 
#     @property
#     def context_decorators_assigned(self):
#         """
#         Tuple naming attributes that self.context_decorators attributes should keep
#         It should contain all attributes that set by relevant decorators
#         (such as @extracts)
# 
#         """
#         return DEFAULT_ASSIGNED
# 
#     @property
#     def new_context_type(self):
#         """
#         Context type to create
# 
#         """
#         return SafeContext
# 
#     def __call__(self, context=None, **kwargs):
#         """
#         Resolve the chain and return the last chain function result
#         :param context: use existing context instead of creating a new one
#         :param **kwargs: initialize the context with some values
# 
#         """
#         context = context or self.new_context_type()
#         context.update(kwargs)
# 
#         res = None
# 
#         for link in self.links:
#             func = self.apply_decorators(context, link)
#             res = func()
# 
#         return res
# 
#     def __len__(self):
#         return len(self.links)
# 
#     def apply_decorators(self, context, link):
#         decorated_link = link
#         for decorator in self.context_decorators:
#             decorated_link = decorator(context, decorated_link, self.context_decorators_assigned)
#         return decorated_link
# 
#     @classmethod
#     def make(cls, *args, chain=None, links=None, **kwargs):
#         if chain is not None:
#             return chain
#         elif links is not None:
#             return cls(*links)
#         elif args:
#             return cls(*args)
#         else:
#             raise ValueError("Must define one of 'chain', 'links', or '*args'")
# 
# Path: microcosm_pubsub/chain/decorators.py
# def binds(**binds):
#     """
#     On resolving this function with temporarily_replace_context_keys decorator -
#     temporarily updates the context keys.
# 
#     Note: The decorator just marks the function.
#     :param **binds: (old_context_key, new_context_key) - context keys to rename
# 
#     """
#     def decorate(func):
#         function = to_function(func)
#         setattr(function, BINDS, binds)
#         return function
#     return decorate
# 
# def extracts(*extract):
#     """
#     On resolving this function with get_from_context decorator -
#     updates the context based on the function return value.
# 
#     Note: The decorator just marks the function and don't change the return value.
#     :param *args: key/s of the return value
# 
#     """
#     def decorate(func):
#         function = to_function(func)
#         setattr(function, EXTRACTS, extract)
#         return function
#     return decorate


from hamcrest import assert_that, equal_to, is_
from microcosm_pubsub.chain import Chain
from microcosm_pubsub.chain.decorators import binds, extracts



class TestChain:

    def test_chain_returns_value(self):
        chain = Chain(
            lambda: 100,
            lambda: 200,
        )
        assert_that(
            chain(),
            is_(equal_to(200)),
        )

    def test_chain_functions_can_pass_variables(self):
        chain = Chain(
            lambda arg: arg,
        )
        assert_that(
            chain(arg=200),
            is_(equal_to(200)),
        )

    def test_chain_functions_has_access_to_context(self):

# Path: microcosm_pubsub/chain/chain.py
# class Chain:
#     """
#     Structure that contains callable functions that shares the same context.
# 
#     """
#     def __init__(self, *args):
#         """
#         Build a chain that can be resolved multiple times
#         :param *args: callable functions, Chain statemnts or other Chains
# 
#         """
#         self.links = list(args)
# 
#     @property
#     def context_decorators(self):
#         """
#         Decorators to apply to the chain links
# 
#         """
#         return [
#             # Order matter - get_from_context should be first
#             get_from_context,
#             temporarily_replace_context_keys,
#             save_to_context,
#             save_to_context_by_func_name,
#         ]
# 
#     @property
#     def context_decorators_assigned(self):
#         """
#         Tuple naming attributes that self.context_decorators attributes should keep
#         It should contain all attributes that set by relevant decorators
#         (such as @extracts)
# 
#         """
#         return DEFAULT_ASSIGNED
# 
#     @property
#     def new_context_type(self):
#         """
#         Context type to create
# 
#         """
#         return SafeContext
# 
#     def __call__(self, context=None, **kwargs):
#         """
#         Resolve the chain and return the last chain function result
#         :param context: use existing context instead of creating a new one
#         :param **kwargs: initialize the context with some values
# 
#         """
#         context = context or self.new_context_type()
#         context.update(kwargs)
# 
#         res = None
# 
#         for link in self.links:
#             func = self.apply_decorators(context, link)
#             res = func()
# 
#         return res
# 
#     def __len__(self):
#         return len(self.links)
# 
#     def apply_decorators(self, context, link):
#         decorated_link = link
#         for decorator in self.context_decorators:
#             decorated_link = decorator(context, decorated_link, self.context_decorators_assigned)
#         return decorated_link
# 
#     @classmethod
#     def make(cls, *args, chain=None, links=None, **kwargs):
#         if chain is not None:
#             return chain
#         elif links is not None:
#             return cls(*links)
#         elif args:
#             return cls(*args)
#         else:
#             raise ValueError("Must define one of 'chain', 'links', or '*args'")
# 
# Path: microcosm_pubsub/chain/decorators.py
# def binds(**binds):
#     """
#     On resolving this function with temporarily_replace_context_keys decorator -
#     temporarily updates the context keys.
# 
#     Note: The decorator just marks the function.
#     :param **binds: (old_context_key, new_context_key) - context keys to rename
# 
#     """
#     def decorate(func):
#         function = to_function(func)
#         setattr(function, BINDS, binds)
#         return function
#     return decorate
# 
# def extracts(*extract):
#     """
#     On resolving this function with get_from_context decorator -
#     updates the context based on the function return value.
# 
#     Note: The decorator just marks the function and don't change the return value.
#     :param *args: key/s of the return value
# 
#     """
#     def decorate(func):
#         function = to_function(func)
#         setattr(function, EXTRACTS, extract)
#         return function
#     return decorate


# Path: microcosm_pubsub/tests/chain/test_chain.py
from hamcrest import assert_that, equal_to, is_
from microcosm_pubsub.chain import Chain
from microcosm_pubsub.chain.decorators import binds, extracts




class TestChain:

    def test_chain_returns_value(self):
        chain = Chain(
            lambda: 100,
            lambda: 200,
        )
        assert_that(
            chain(),
            is_(equal_to(200)),
        )

    def test_chain_functions_can_pass_variables(self):
        chain = Chain(
            lambda arg: arg,
        )
        assert_that(
            chain(arg=200),
            is_(equal_to(200)),
        )

    def test_chain_functions_has_access_to_context(self):

        chain = Chain(