from itertools import *
from math import pow

def fibonacci():
    a, b = 0, 1
    for i in range (10):
        yield a
        a, b = b, a + b

squares = [i * i for i in range (10)]

chars = 'thequickbrownfoxjumpsoverthelazydog'
        
def run (autoTester):
    autoTester.check ('islice count', list (islice (count (10, 2), 4, 40, 3)))
    autoTester.check ('islice cycle', list (islice (cycle (fibonacci ()), 15)))
    autoTester.check ('repeat', list (repeat (3.14, 15)))
    autoTester.check ('islice repeat', list (islice (repeat (2.74), 15)))
    autoTester.check ('accumulate', list (accumulate (range (5))))

    def add (total, element):
        return total + element
    
    autoTester.check ('accumulate', list (accumulate (['alamak', 'mirach', 'sirrah'], add)))
    
    autoTester.check ('chain', list (chain (fibonacci (), squares, chars)))
    autoTester.check ('chain.from_iterable', list (chain.from_iterable (['ape', 'node', 'mice', 'vim', 'sus', 'jet'])))
    
    selectors = [True, True, False, True, False, False, True, True, False, True]
    
    autoTester.check ('compress', list (compress (
        ['{}{}'.format (('take' if selector else 'leave'), index) for index, selector in enumerate (selectors)],
        selectors
    )))
    
    autoTester.check ('dropwhile', list (dropwhile (lambda x: x < 5, [1, 4, 6, 4, 1])))
    autoTester.check ('filterfalse', list (filterfalse (lambda x: x % 2, range (10))))
    
    things = [('animal', 'bear'), ('animal', 'duck'), ('plant', 'cactus'), ('vehicle', 'speed boat'), ('vehicle', 'school bus')]

    for key, group in groupby (things, lambda x: x [0]):
        for thing in group:
            autoTester.check ('A {} is a {}.' .format (thing[1], key))
        autoTester.check (' ')
        
    autoTester.check ('islice', list (islice ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 9, 2)))
        
    autoTester.check ('starmap', [int (x) for x in starmap (pow, [(2, 5), (3, 2), (10, 3)])])
    autoTester.check ('takewhile', list (takewhile (lambda x: x < 5, [1, 4, 6, 4, 1])))
    
    i1, i2 = tee (islice (count (), 5))
    autoTester.check ('tee', list (i1), list (i1), list (i2))
    
    autoTester.check ('product', list (product ('ABCD', 'xy')), list (product (range (2), repeat = 3)))

    autoTester.check ('permutations', list (permutations ('ABCD')), list (permutations ('ABCD', 2)))
    
    autoTester.check ('combinations',
        list (combinations ('ABCD', 2)),
        list (combinations ([1, 2, 3, 4, 5], 3)),
        list (combinations (islice (count (), 6), 4))
    )
    
    autoTester.check ('combinations_with_replacement',
        list (combinations_with_replacement ('ABCD', 2)),
        list (combinations_with_replacement ([1, 2, 3, 4, 5], 3)),
        list (combinations_with_replacement (islice (count (), 6), 4))
    )
    