# Debian requirements:
# $ sudo aptitude install python-hypothesis python-pytest python-pytest-cov
#
# $ python ./factorial.py
# $ pytest factorial.py
# $ pytest --hypothesis-show-statistics factorial.py 
# $ pytest --cov=. factorial.py
# $ python-coverage run factorial.py
# $ python-coverage html

def fact(n):
    f = n
    # {{{
    if n < 0:
        raise ValueError
    if n == 0:
        return 1
    # }}}
    while n > 1:
        n = n-1
        f = f*n
    return f

if __name__ == "__main__":
    for i in range(4):
        print('Factorial %d = %d.' % (i,fact(i)))

def test_zero():
    assert fact(0)==1

def test_one():
    assert fact(1)==1

def test_two():
    assert fact(2)==2

def test_three():
    assert fact(3)==6

# {{{

from pytest import raises

def test_negative():
    with raises(ValueError):
        fact(-1)

# }}}

from hypothesis import given, assume
from hypothesis.strategies import integers, lists

# A first test using the integers generator with default settings.
@given(integers())
def test_demo(i):
    assert i+i == 2*i

# A test on positive integers only, using assume to rule out some values.
# This can also be achieved by using integers(1) i.e. passing min_value=1,
# or simply by taking i = abs(i) at the beginning of the test.
@given(integers())
def test_positive(i):
    assume(i>0)
    assert 2*i > i

# For this test we need to rule out negative integers but also too large
# integers (for which computing the factorial would be slow). We do it
# by tweaking the integers generator, specifying both min_value and max_value.
# Using assume would rule out too many generated values, which defeats the
# purpose of the test, and would cause an error from hypothesis.
@given(integers(1,1000))
def test_equation(i):
    assume(i>0)
    assert fact(i) == i * fact(i-1)
