# Fall 2019 Final exam skeletons and testing code.
# Lillian Lee and Walker White

"""STUDENTS: Go to the script code at the end of the file and comment/uncomment
   to select which questions you want to work on and have your answers tested.

   Then, fill in the appropriate skeleton.

   Then, run python on this entire file.
"""


import inspect # To get names of calling function automatically
               # (lets you look at the actual call stack!)



###### Q4

NORMAL_MATRIX = -1 # Non-zeroes in both upper and lower triangle
UPPER_TRIANGULAR = 0 # Zeroes only in lower triangle
LOWER_TRIANGULAR = 1 # Zeroes only in upper triangle
PURE_DIAGONAL = 2 # Zeroes only off the diagonal

def checkmatrix(matrix):
    """Returns the value BEST describing the given matrix.
    Value returned is one of NORMAL_MATRIX, UPPER_TRIANGULAR, LOWER_TRIANGULAR,
    or PURE_DIAGONAL. It should return the highest value describing the matrix.
    Precondition: matrix is a non-empty square 2d list of numbers."""
    pass # STUDENTS: IMPLEMENT THIS

def test_q4_checkmatrix():
    print_test_fn_info("start")

    pd = [[1, 0, 0, 0], 
          [0, 6, 0, 0], 
          [0, 0, 11, 0], 
          [0, 0, 0, 16]]

    ut = [[1, 2, 3, 4], 
          [0, 6, 7, 8],
          [0, 0, 11, 12],
          [0, 0, 0, 16]]

    lt = [[1, 0, 0, 0],
          [5, 6, 0, 0],
          [9, 10, 11, 0],
          [13, 14, 15, 16]]

    nm = [[1, 0, 0, 0],
          [5, 6, 0, 0],
          [9, 10, 11, -1],
          [13, 14, 15, 16]]


    # format: (matrix, expected answer, label for matrix (for printing))
    exp_answers = [(pd, PURE_DIAGONAL, "pd"), 
                   (ut, UPPER_TRIANGULAR, "ut"), 
                   (lt, LOWER_TRIANGULAR, "lt"),
                   (nm, NORMAL_MATRIX, "nm")]

    for item in exp_answers:
        inmatrix = item[0]
        expected = item[1]
        label = item[2]

        result = checkmatrix(inmatrix)
        assert result == expected,\
            assert_msg("checkmatrix result for " + label, expected, result)

    print_test_fn_info("end")



##### Q5

def couponify(code):
    """Returns code properly formatted as a coupon code in blocks of 4.

    Each block of a coupon code is composed of upper case letters and numbers.
    Dashes are used to separate the blocks from each other.

    Example:couponify('k97J') returns 'K97J'
            couponify('K97j9876') returns 'K97J-9876'
            couponify('K97JfTRe9876') returns 'K97J-FTRE-9876'
            couponify('K97') returns ''
            couponify('K97J8') returns 'K97J'
            couponify('k97JfTRe9') returns 'K97J-FTRE'
    Preconditions: code is a (possibly empty) string of letters and numbers"""
    pass # STUDENTS: IMPLEMENT THIS

def test_q5_couponify():
    print_test_fn_info("start")

    right_answers={
                    'k97J': 'K97J',
                    'K97j9876': 'K97J-9876',
                    'K97JfTRe9876': 'K97J-FTRE-9876',
                    'K97': '',
                    'K97J8': 'K97J',
                    'k97JfTRe9': 'K97J-FTRE'
                    }
    for code in right_answers:
        expected = right_answers[code]
        result = couponify(code)
        assert result == expected, assert_msg("couponify("+code+")", expected, result)




    print_test_fn_info("end")




# helper
def assert_msg(subject, expected, result):
    return subject + " should be " + repr(expected) + ", but is " + repr(result)



# helper
def print_test_fn_info(kind):
    """If `kind` is the string "start", prints
        Running <name of enclosing function>
       If `kind` is the string "end", prints
        Hurrah, all test cases passed for <name of function>!\n"""

    enclosing_fn_name = inspect.stack()[1][3]

    if kind == "start":
        print("*** Running " + enclosing_fn_name)
    elif kind == "end":
        print("*** Hurrah, all test cases passed for  " + enclosing_fn_name + "!\n")

#####################################
if __name__ == '__main__':
    
    # STUDENTS: comment out the names of test functions you don't want to run.
    # Or, uncomment the names of test functions you DO want to run. 
    tests_to_run = [
        test_q4_checkmatrix,
        test_q5_couponify
    ]

    for testfn in tests_to_run:
        testfn()  # the parentheses mean the function is called