# Brett Terpstra
# bt19ex@brocku.ca 6920201


# functional version of the code to test against
def workingProcessString(input_str):
    output_str = ""
    for char in input_str:
        if char.isupper():
            output_str += char.lower()
        elif char.isnumeric():
            output_str += char
        else:
            output_str += char.upper()
    return output_str

# the failing version of the code
def processString(input_str):
    output_str = ""
    for char in input_str:
        if char.isupper():
            output_str += char.lower()
        elif char.isnumeric():
            output_str += char * 2
        else:
            output_str += char.upper()
    return output_str

# function to test an input string
def processTest(input):
    # fancy output.
    print(f"-------------------[ {input} ]-------------------")
    parts_to_test = []
    failing_strings = []
    passing_strings = []
    # simple recursion emulation with a while loop
    parts_to_test.append(input)
    while parts_to_test:
        # process the front of the queue
        s = parts_to_test[0]
        o1 = workingProcessString(s)
        o2 = processString(s)
        # only make substrings that make sense, recursion base case. Append these to the queue
        if len(s) > 1:
            h1, h2 = s[:len(s)//2], s[len(s)//2:]
            parts_to_test.append(h1)
            parts_to_test.append(h2)
        # remove the front element from the queue
        parts_to_test.pop(0)
        # append to the tracking lists for later printing and sorting
        if o1 != o2:
            failing_strings.append(s)
        else:
            passing_strings.append(s)
    # sort the failures in order of largest to smallest
    sorted_failings = sorted(failing_strings, key=lambda x: -len(x))
    # I don't know what kind of output you were looking for so I printed every bit of information I have
    if len(passing_strings) > 0:
        print(f"For input {input} we found {len(passing_strings)} passing strings:")
        for p in passing_strings:
            print(f"\t{p}")
        print()

    if len(sorted_failings) > 0:
        print(f"For input {input} we found {len(sorted_failings)} failing strings:")
        for f in sorted_failings:
            print(f"\t{f}")
        print()

        # printing the smallest is probably the most important
        # since it'll tell us the place of the bug
        smallest = len(sorted_failings[len(sorted_failings)-1])
        print(f"For input {input} the smallest erroring strings are:")
        for f in sorted_failings:
            if len(f) == smallest:
                print(f"\t{f}")
        print()
    else:
            print("No failing strings found!")

processTest("abcdefG1")
print()
processTest("CCDDEExy")
print()
processTest("1234567b")
print()
processTest("8665")