# see testQ1, testQ2, testQ3 for test cases.

# If you want to test your own code to see where it might have failed, replace
# the q1, q2, and/or q3 below.  

def q1(n):
    return q1s(n)

def q2(n, listOfStrings):
    return q2s(n, listOfStrings)

def q3(item1, item2):
    return q3s(item1, item2)


#####
# Solutions, named differently so can be used to generate comparison results
# q1s, q2s, q3s

# Q1
def q1s(n):
    if n == 1:
        return [1]
    else:
        return q1s(n-1) + [n*n] + q1s(n-1)

# Q2
def q2s(n, listOfStrings):
    if listOfStrings == []:
        return 0
    elif len(listOfStrings[0]) < n:
        return 1 + q2s(n, listOfStrings[1:])
    else:
        return q2s(n, listOfStrings[1:])

# Q3
#
def q3s(item1, item2):
    if ((type(item1) == int) or (type(item1) == float)) and ((type(item2) == int) or (type(item2) == float)):
        return True
    if type(item1) != type(item2):
        return False
    if type(item1) != list:
        return True
    if len(item1) != len(item2):
        return False
    i = 0
    while (i < len(item1)):
        sItem1 = item1[i]
        sItem2 = item2[i]
        if not q3s(sItem1, sItem2):
            return False
        i = i + 1
    return True

#####

def testQ1():
    print("\nQ1 tests:")
    testCase(1, q1s(1), q1, 1)
    testCase(2, q1s(2), q1, 2)
    testCase(3, q1s(3), q1, 3)
    testCase(4, q1s(18), q1, 18, printExpected=False)
    testCase(5, q1s(19), q1, 19, printExpected=False)

def testQ2():
    print()
    print("\nQ2 tests:")
    testCase(1, q2s(4, ['hi', 'bye', 'goodbye', 'hello']), q2, 4, ['hi', 'bye', 'goodbye', 'hello'])
    testCase(2, q2s(10, ['hi', 'bye', 'goodbye', 'hello']), q2, 10, ['hi', 'bye', 'goodbye', 'hello'])
    testCase(3, q2s(2, ['hi', 'bye', 'goodbye', 'hello']), q2, 2, ['hi', 'bye', 'goodbye', 'hello'])
    testCase(4, q2s(5, ['hello', 'bye']), q2, 5, ['hello', 'bye'])
    testCase(5, q2s(4, ['hello', 'bye']), q2, 4, ['hello', 'bye'])
    testCase(6, q2s(1, ["a", "bb", "ccc", "dddd"]), q2, 1, ["a", "bb", "ccc", "dddd"]) 
    testCase(7, q2s(1, ["", "a", "b"]), q2, 1, ["", "a", "b"])
    testCase(8, q2s(1, ["", "a", ""]), q2, 1, ["", "a", ""])
    
def testQ3():
    print("\nQ3 tests:")
    testCase(1, q3s([],[]), q3, [], [])
    testCase(2, q3s([],[3]), q3, [], [3])
    testCase(3, q3s([3, 2.0, 1],[3, 2, 1]), q3, [3, 2.0, 1],[3, 2, 1])
    testCase(4, q3s([3.0],[3]), q3, [3.0],[3])
    testCase(5, q3s([5],[3]), q3, [5],[3])
    testCase(6, q3s(['c'],[3]), q3, ['c'],[3])
    testCase(7, q3s([5, [2]],[3, [2.0]]), q3, [5, [2]],[3, [2.0]])
    testCase(8, q3s([5, [2, 3, [3, 2]]], [3, [4, 5, [2, 1.0]]]), q3, [5, [2, 3, [3, 2]]], [3, [4, 5, [2, 1.0]]])
    testCase(9, q3s([1,2,['a','b']],[3,4, [1,2,3]]), q3, [1,2,['a','b']],[3,4, [1,2,3]])
    testCase(10, q3s([1,2,['a','b'], 'a'],[3,4, [1,2,3], 'b']), q3, [1,2,['a','b'], 'a'],[3,4, [1,2,3], 'b'])
    testCase(11, q3s([1,2,['a', 'b']],[3, 4, ['c', 'hello']]), q3, [1,2,['a', 'b']],[3, 4, ['c', 'hello']])
    testCase(12, q3s([[[[],[2],[],['hi', [0]]]]], [[[[],[-2.0],[],['bye', [1]]]]]), q3, [[[[],[2],[],['hi', [0]]]]], [[[[],[-2.0],[],['bye', [1]]]]])
    testCase(13, q3s([[[[],[2],[],['hi', [0]]]]], [[[[],[-2],[],['bye', 0]]]]), q3, [[[[],[2],[],['hi', [0]]]]], [[[[],[-2],[],['bye', 0]]]])
    testCase(14, q3s([[[[],[2],[],[[0], 'hi']]]], [[[[],[-2],[],[0, 'bye']]]]), q3, [[[[],[2],[],[[0], 'hi']]]], [[[[],[-2],[],[0, 'bye']]]])
    testCase(15, q3s([1,2,3,[4,5,6],7,8], [1,2,3,[4,'a',6],7,8]), q3, [1,2,3,[4,5,6],7,8], [1,2,3,[4,'a',6],7,8])
    testCase(16, q3s([1,[2,3]], [[1,2],3]), q3, [1,[2,3]],[[1,2],3])
    testCase(17, q3s([None], [False]), q3, [None], [False])


def testCase(i, expectedResult, fn, *args, sortResults=False, printExpected = True):
    try:
        res = fn(*args)
        if sortResults == True:
            res = sorted(res)
        if res == expectedResult:
            print("Test {} okay".format(i))
        else:
            print("***")
            if printExpected == True:
                print("Test {} FAILED. Result: {} Expected Result: {}".format(i, res, expectedResult))
            else:
                
                print("Test {} FAILED. Not printing expect result because it is too large to print nicely in shell.".format(i))
    except Exception as errMsg:
        print("{} Run-time error when testing input: {}.".format(i, args))
        print("Message: ", errMsg)

separatorString = '\n' + 40*'-'



