#! /usr/bin/env python

import unittest

import factorial

data = (
    ( 0 , 1 ) ,
    ( 1 , 1 ) ,
    ( 2 , 2 ) ,
    ( 3 , 6 ) ,
    ( 4 , 24 ) ,
    ( 5 , 120 ) ,
    ( 6 , 720 ) ,
    ( 7 , 5040 ) ,
    ( 8 , 40320 ) ,
    ( 9 , 362880 ) ,
    ( 10 , 3628800 ) ,
    ( 11 , 39916800 ) ,
    ( 12 , 479001600 ) ,
    ( 13 , 6227020800 ) ,
    ( 14 , 87178291200 ) ,
    ( 20 , 2432902008176640000 ) ,
    ( 30 , 265252859812191058636308480000000 ) ,
    ( 40 , 815915283247897734345611269596115894272000000000 )
    )

class TestFactorial ( unittest.TestCase ) :

    def fromArrayTest ( self , function ) :
        for datum in data : self.assertEqual ( function ( datum[0] ) , datum[1] )
        
    def testFromArrayIterative ( self ) : self.fromArrayTest ( factorial.iterative )
    def testFromArrayRecursive ( self ) :self.fromArrayTest ( factorial.recursive )
    def testFromArrayTailRecursive ( self ) :self.fromArrayTest ( factorial.tailRecursive )

    def negativeTest ( self , function ) :
        for index in range ( -20 , -1 ) : self.assertRaises ( ValueError , function , index )
        
    def testNegativeIterative ( self ) : self.negativeTest ( factorial.iterative )
    def testNegativeRecursive ( self ) : self.negativeTest ( factorial.recursive )
    def testNegativeTailRecursive ( self ) : self.negativeTest ( factorial.tailRecursive )
        
    def floatingPointTest ( self , function) :
        for number in range ( -12 , 12 ) : self.assertRaises ( ValueError , function , number + 0.5 )

    def testFloatingPointIterative ( self ) : self.floatingPointTest ( factorial.iterative )
    def testFloatingPointRecursive ( self ) : self.floatingPointTest ( factorial.recursive )
    def testFloatingPointTailRecursive ( self ) : self.floatingPointTest ( factorial.tailRecursive )

    def testIterativeEnormousSucceeds ( self ) : factorial.iterative ( 2000 )
    def testRecursiveStackFail ( self ) : self.assertRaises ( RuntimeError , factorial.recursive , 2000 )
    def testTailRecursiveStackFail ( self ) : self.assertRaises ( RuntimeError , factorial.tailRecursive , 2000 )

if __name__ == '__main__' :
    unittest.main ( )
