MOCK
====

Mocks are what we are talking about here:
objects pre-programmed with expectations which form a
specification of the calls they are expected to receive.

    >>> from ludibrio import Mock

    >>> with Mock() as greetings:
    ...     greetings.excuse_me() >> 'Com licença'
    ...     greetings.hello('Gustavo') >> 'Ola, Gustavo'
    ...     greetings.see_you_soon >> 'Até logo'
    ...     greetings.see_you_soon >> 'Até logo, denovo'
    >>> print greetings.excuse_me()
    Com licença
    >>> print greetings.hello('Gustavo')
    Ola, Gustavo
    >>> print greetings.see_you_soon
    Até logo
    >>> print greetings.see_you_soon
    Até logo, denovo
    >>> print greetings.see_you_soon
    Traceback (most recent call last):
    ...
    AssertionError: Object's mocks are not pre-programmed with expectations


    >>> with Mock() as greetings:
    ...     greetings.excuse_me() >> 'Com licença'
    ...     greetings.see_you_soon >> 'Até logo'
    >>> print greetings.excuse_me()
    Com licença
    >>> print greetings.hello('Gustavo Rezende')
    Traceback (most recent call last):
    ...
    AssertionError: Object's mocks are not pre-programmed with expectations.
    Got:
    hello
    Expected:
    see_you_soon

    >>> with Mock() as greetings:
    ...     greetings.excuse_me(name='gustavo') >> 'Com licença'
    >>> greetings.excuse_me(name='Diego Manhaes')
    Traceback (most recent call last):
    ...
    AssertionError: Object's mocks are not pre-programmed with expectations.
    Got:
    excuse_me(name='Diego Manhaes')
    Expected:
    excuse_me(name='gustavo')

    >>> with Mock() as listing:
    ...     listing[1] >> 'um'
    ...     listing[1:4] >> ['dois', 'tres', 'quatro']
    ...     listing['quatro'] >> 4
    >>> print listing[1]
    um
    >>> print listing[1:4]
    ['dois', 'tres', 'quatro']
    >>> print listing['quatro']
    4

    >>> with Mock() as callable:
    ...     callable(two=2) >> 2
    >>> callable(two=2)
    2

    >>> with Mock() as operator:
    ...     operator * 4 >> 4
    ...     operator + 4 >> 5
    ...     operator ** 4 >> 1
    >>> operator * 4
    4
    >>> operator + 4
    5
    >>> operator ** 4
    1

    >>> with Mock() as Greetings:
    ...     greetings = Greetings(tree=3)
    >>> greetings
    Mock Object

    >>> with Mock() as MySQLdb:
    ...     con = MySQLdb.connect('servidor', ' usuario', 'senha')
    ...     con.select_db('banco de dados') >> None
    ...     cursor = con.cursor()
    ...     cursor.execute('ALGUM SQL') >> None
    ...     cursor.fetchall() >> [1,2,3,4,5]
    >>> con = MySQLdb.connect('servidor', ' usuario', 'senha')
    >>> con.select_db('banco de dados')
    >>> cursor = con.cursor()
    >>> cursor.execute('ALGUM SQL')
    >>> cursor.fetchall()
    [1, 2, 3, 4, 5]

    >>> with Mock() as testeError:
    ...     testeError.foo('bar') >> ArithmeticError('teste error')
    >>> testeError.foo('bar')
    Traceback (most recent call last):
    ...
    ArithmeticError: teste error

    >>> with Mock() as teste:
    ...     teste.called() << 1
    ...     teste.notcalled() << 2
    >>> teste.called()
    1
    >>> teste.validate()
    Traceback (most recent call last):
    ...
    AssertionError: Object's mocks are not pre-programmed with expectations



    >>> with Mock() as count:
    ...     count() >> 1
    ...     count() >> 2
    ...     count() >> 3
    >>> count()
    1
    >>> count()
    2
    >>> count()
    3


    >>> with Mock() as clock:
    ...     from time import clock
    ...     clock() >> 171

    >>> from time import clock
    >>> clock()
    171

    >>> class MaquinaDeSaque(object):
    ...     @staticmethod
    ...     def transferir(valor, conta1, conta2):
    ...         if conta2.pegar_saldo() >= valor:
    ...             conta2.sacar(valor)
    ...             conta1.depositar(valor)
    >>> with Mock() as conta1:
    ...     conta1.depositar(100) << None
    >>> with Mock() as conta2:
    ...     conta2.pegar_saldo() << 200
    ...     conta2.sacar(100) << None
    >>> MaquinaDeSaque.transferir(100, conta1, conta2)

Dummy
=====

Dummy Objects are passed around but never validated.


    >>> from ludibrio import Dummy

    >>> Dummy()
    Dummy Object

    >>> Dummy(repr="Objeto Idiota")
    Objeto Idiota


    >>> Dummy(1,2.3,"4",a=5.6, b=7, c="8 ...")
    Dummy Object
    >>> def execute_but_not_validated(x):
    ...     x.write("teste")
    ...     x.close()
    >>> execute_but_not_validated(Dummy())

    >>> dummy = Dummy()
    >>> dummy.executAnythingAndReturnDummyObject()
    Dummy Object
    >>> dummy.foo()
    Dummy Object
    >>> dummy.bar
    Dummy Object
    >>> dummy.one.two.three()
    Dummy Object
    >>> 1 + Dummy()
    Dummy Object
    >>> Dummy() -1
    Dummy Object

    >>> dummy = Dummy()
    >>> dummy ** 22 and dummy / dummy
    Dummy Object
    >>> dummy * 69 or dummy // dummy == "Anything"
    Dummy Object
    >>> list(Dummy())
    [Dummy Object]
    >>> for i in Dummy():print i
    Dummy Object
    >>> Dummy()[4]
    Dummy Object
    >>> Dummy()[2:9]
    Dummy Object
    >>> 8 in Dummy()
    True


    >>> dict(Dummy())
    {Dummy Object: Dummy Object}

    >>> str(Dummy())
    'Dummy Object'
    >>> Dummy() %(1, "Gustavo Rezende", 2.8)
    Dummy Object
    >>> int(Dummy())
    1
    >>> float(Dummy())
    1.0
    >>> bool(Dummy())
    True
    >>> del dummy.anything

    >>> isinstance(Dummy(), str)
    False

    >>> isinstance(Dummy(type=str), str)
    True

    >>> class A(object):
    ...     def teste(self, dummy):return dummy.notshouldbeCalled()
    >>> dummy = Dummy(must_not_be_used_by=A)
    >>> a = A()
    >>> a.teste(dummy)
    Traceback (most recent call last):
    ...
    AttributeError: Dummy Object must not be called
    >>> dummy.shouldbeCalled()
    Dummy Object


Stubs
=====

Stubs provide canned answers to calls made during the test.

    >>> from ludibrio import Stub


    >>> with Stub() as x:
    ...     x + 1 >> 1
    ...     x - 1 >> -1
    >>> x - 1
    -1
    >>> x + 1
    1
    >>> with Stub() as count:
    ...     count() >> 1
    ...     count() >> 2
    ...     count() >> 3
    >>> count()
    1
    >>> count()
    2
    >>> count()
    3
    >>> count()
    1
    >>> count()
    2
    >>> count()
    3


    >>> with Stub(repr='Greetings') as greetings:
    ...     greetings.excuse_me() >> 'Com licença'
    ...     greetings.hello('Gustavo') >> 'Ola, Gustavo'
    ...     greetings.outrohello('Gustavo') >> 'Oi, Gustavo'
    ...     greetings.hello('Gustavo', 'Diego') >> 'Ola, Gustavo e Diego'
    ...     greetings.see_you_soon >> 'Até logo'
    >>> print greetings.hello('Gustavo')
    Ola, Gustavo
    >>> print greetings.excuse_me()
    Com licença
    >>> print greetings.hello('Gustavo')
    Ola, Gustavo
    >>> print greetings.outrohello('Gustavo')
    Oi, Gustavo
    >>> print greetings.outrohello('Gustavo')
    Oi, Gustavo
    >>> print greetings.hello('Gustavo')
    Ola, Gustavo
    >>> print greetings.see_you_soon
    Até logo
    >>> greetings
    Greetings
    >>> print greetings.hello('Gustavo', 'Diego')
    Ola, Gustavo e Diego
    >>> print greetings.hello('Gustavo')
    Ola, Gustavo
    >>> print greetings.executAnythingAndReturnDummyObject()
    Dummy Object
    >>> greetings + 171 - greetings * 22
    Dummy Object



Spy
===

A test spy is similar to a stub, but besides giving clients an instance on which to invoke members, a spy will also record which members were invoked so that unit tests can verify that members were invoked as expected.

    >>> from ludibrio import Spy

    >>> import os
    >>> with Spy(type=os) as os:
    ...     os.times() >> (23.02, 1.29, 0.0, 0.0, 17186198.539999999)

    >>> 'ludibrio' in os.getcwd()
    True
    >>> os.times()
    (23.02, 1.29, 0.0, 0.0, 17186198.539999999)

