import unittest
from gradescope_utils.autograder_utils.decorators import number, weight
import subprocess

class TestDiff(unittest.TestCase):
    def setUp(self):
        pass 

    # Associated test number within Gradescope
    @number("0")
    # Associated point value within Gradescope
    @weight(5)
    def test_Compile(self):
        # Title used by Gradescope 
        """Clean Compile"""

        # Create a subprocess to run the students make file to ensure it compiles
        test = subprocess.Popen(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stderr.read().strip().decode('utf-8')
        test.kill()

        # Standard unit test case with an associated error message
        self.assertTrue(output == "", msg=output)
        test.terminate()
        
    # Associated test number within Gradescope
    @number("1")
    # Associated point value within Gradescope
    @weight(10)
    def test_IntroOutput(self):
        # Title used by Gradescope 
        """Check that the intro block is printed once"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/1b2a3O3o2a1B.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Array of expected lines of output, line by line in expected order
        expected = ['There are 3 jars containing fruit. Each jar is labeled incorrectly.', 'See if you can determine the correct labels!', '1. oranges', '2. both', '3. apples']
        # Concatenated string of expected output, for display as unformatted expected output in error messages
        expectedUnformatted = ''
        for line in expected:
            expectedUnformatted = expectedUnformatted + line + '\n'
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted after "3. apples"
        try:
            index = linesPrinted.index('3. apples') + 1
        except ValueError:
            index = None
        if index != None:
            del linesPrinted[index:]
            # Check for correct number of lines in output (to help narrow down test failures for students)
            if len(linesPrinted) < len(expected):
                # If too few lines, set test failure status and update message appropriately
                correct = False
                # Format the split linesPrinted array as unformatted output for student comparison
                linesPrintedUnformatted = ''
                for line in linesPrinted:
                    if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                    elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                    elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                    else:
                        linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                msg = ['Your program\'s output has fewer lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            elif len(linesPrinted) > len(expected):
                # If too many lines, set test failure status and update message appropriately
                correct = False
                # Format the split linesPrinted array as unformatted output for student comparison
                linesPrintedUnformatted = ''
                for line in linesPrinted:
                    if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                    elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                    elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                    else:
                        linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                msg = ['Your program\'s output has more lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            else:
                # If correct number of lines, check content of each line
                currentLine = 0
                for line in linesPrinted:
                    # Compare each line of expected array to current line from output
                    if expected[currentLine] not in line:
                        # When output does not match expected, set test failure status
                        correct = False
                    currentLine += 1
                # Format the split linesPrinted array as unformatted output for student comparison
                linesPrintedUnformatted = ''
                for line in linesPrinted:
                    if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                    elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                    elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                        linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                    else:
                        linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                # Update message appropriately
                msg = ['Your program\'s output does not match the expected output. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it is missing the line "3. apples\n". Check the lab instructions for the intro text that should be printed.']    
            
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()
        
    # Associated test number within Gradescope
    @number("2")
    # Associated point value within Gradescope
    @weight(10)
    def test_LetsTryAgainOutput(self):
        # Title used by Gradescope 
        """Check that "Let's try again!" block is printed once"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/1b2a3O3o2a1B.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Array of expected lines of output, line by line in expected order
        expected = ['Let\'s try again!', '1. apples', '2. oranges', '3. both']
        # Concatenated string of expected output, for display as unformatted expected output in error messages
        expectedUnformatted = ''
        for line in expected:
            expectedUnformatted = expectedUnformatted + line + '\n'
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted before "Let's try again!"
        try:
            index = linesPrinted.index('Let\'s try again!')
        except ValueError:
            index = None
        if index != None:
            del linesPrinted[:index]
            # Delete all lines in linesPrinted after "3. both"
            try:
                index = linesPrinted.index('3. both') + 1
            except ValueError:
                index = None
            if index != None:
                del linesPrinted[index:]
                # Check for correct number of lines in output (to help narrow down test failures for students)
                if len(linesPrinted) < len(expected):
                    # If too few lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has fewer lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                elif len(linesPrinted) > len(expected):
                    # If too many lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has more lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                else:
                    # If correct number of lines, check content of each line
                    currentLine = 0
                    for line in linesPrinted:
                        # Compare each line of expected array to current line from output
                        if expected[currentLine] not in line:
                            # When output does not match expected, set test failure status
                            correct = False
                        currentLine += 1
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    # Update message appropriately
                    msg = ['Your program\'s output does not match the expected output. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            else:
                correct = False
                msg = ['The autograder could not split your program\'s output correctly because it is missing the line "3. both\n". Check the lab instructions for the block of text starting with "Let\'s try again" that should be printed.']    
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it is missing the line "Let\'s try again!\n". Check the lab instructions for the block of text starting with "Let\'s try again" that should be printed.']    
            
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()
    
    # Associated test number within Gradescope
    @number("3")
    # Associated point value within Gradescope
    @weight(5)
    def test_InputPromptOutput(self):
        # Title used by Gradescope 
        """Check that input prompts are correct"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/1b2a3O3o2a1B.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted before "Which one would you like to look in first? (choose 1, 2, or 3): "
        try:
            firstIndex = linesPrinted.index('Which one would you like to look in first? (choose 1, 2, or 3): The first fruit in jar 1 is: a')
        except ValueError:
            firstIndex = None
        if firstIndex != None:
            del linesPrinted[:firstIndex]
            # Delete all lines in linesPrinted between "Which one would you like to look in first? (choose 1, 2, or 3): " and "Which one would you like to look in next? (1, 2, or 3): "
            try:
                secondIndex = linesPrinted.index('Which one would you like to look in next? (1, 2, or 3): The first fruit in jar 2 is: a')
            except ValueError:
                secondIndex = None
            if firstIndex != None and secondIndex != None:
                del linesPrinted[firstIndex + 1:secondIndex]
                # Delete all lines in linesPrinted after "What do you think this jar really contains? (a, o, or b): "
                try:
                    thirdIndex = linesPrinted.index('What do you think this jar really contains? (a, o, or b): That\'s correct! Good job!') + 1
                except ValueError:
                    thirdIndex = None
                if thirdIndex != None:
                    msg = ''
                else:
                    correct = False
                    msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'What do you think this jar really contains? (a, o, or b): \', \'That\'s correct! Good job!\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
            else:
                correct = False
                msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'Which one would you like to look in next? (1, 2, or 3): \', \'The first fruit in jar 2 is: a\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'Which one would you like to look in first? (choose 1, 2, or 3): \', \'The first fruit in jar 1 is: a\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
        
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()

    # Associated test number within Gradescope
    @number("4")
    # Associated point value within Gradescope
    @weight(20)
    def test_CorrectInput(self):
        # Title used by Gradescope 
        """Check that input sequence "1, b, 2, a, 3, O, 3, o, 2, a, 1, B" results in correct output"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/1b2a3O3o2a1B.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Array of expected lines of output, line by line in expected order
        expected = ['The first fruit in jar 1 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 1 is: a', 'That\'s correct! Good job!']
        # Concatenated string of expected output, for display as unformatted expected output in error messages
        expectedUnformatted = ''
        for line in expected:
            expectedUnformatted = expectedUnformatted + line + '\n'
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted before "The first fruit in jar 1 is: a"
        try:
            index = linesPrinted.index('Which one would you like to look in first? (choose 1, 2, or 3): The first fruit in jar 1 is: a')
        except ValueError:
            index = None
        if index != None:
            del linesPrinted[:index]
            # Delete all lines in linesPrinted between "Let's try again!" and "3. both" (inclusive)
            try:
                startIndex = linesPrinted.index('Let\'s try again!')
                stopIndex = linesPrinted.index('3. both') + 1
            except ValueError:
                startIndex = None
                stopIndex = None
            if startIndex != None and stopIndex != None:
                del linesPrinted[startIndex:stopIndex]
                # Check for correct number of lines in output (to help narrow down test failures for students)
                if len(linesPrinted) < len(expected):
                    # If too few lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has fewer lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                elif len(linesPrinted) > len(expected):
                    # If too many lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has more lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                else:
                    # If correct number of lines, check content of each line
                    currentLine = 0
                    for line in linesPrinted:
                        # Compare each line of expected array to current line from output
                        if expected[currentLine] not in line:
                            # When output does not match expected, set test failure status
                            correct = False
                        currentLine += 1
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    # Update message appropriately
                    msg = ['Your program\'s output does not match the expected output. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            else:
                correct = False
                msg = ['The autograder could not split your program\'s output correctly because it cannot remove the "Let\'s try again!" block. Make sure Test #2 is passing before attempting to troubleshoot this test.']    
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'Which one would you like to look in first? (choose 1, 2, or 3): \', \'The first fruit in jar 1 is: a\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
        
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()

    # Associated test number within Gradescope
    @number("5")
    # Associated point value within Gradescope
    @weight(20)
    def test_IncorrectInput(self):
        # Title used by Gradescope 
        """Check that input sequence "3, b, 3, o, 1, A, 1, b, 2, o, 2, b, 2, a, 2, a, 3, a, 3, B, 3, O, 1, a, 1, b" results in correct output"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/3b3o1A1b2o2b2a2a3a3B3O1a1b.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Array of expected lines of output, line by line in expected order
        expected = ['The first fruit in jar 3 is: o', 'Sorry, that is incorrect.', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'The first fruit in jar 1 is: a', 'Sorry, that is incorrect.', 'The first fruit in jar 1 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 2 is: a', 'Sorry, that is incorrect.', 'The first fruit in jar 2 is: a', 'Sorry, that is incorrect.', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 3 is: o', 'Sorry, that is incorrect.', 'The first fruit in jar 3 is: o', 'Sorry, that is incorrect.', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'The first fruit in jar 1 is: a', 'Sorry, that is incorrect.', 'The first fruit in jar 1 is: a', 'That\'s correct! Good job!']
        # Concatenated string of expected output, for display as unformatted expected output in error messages
        expectedUnformatted = ''
        for line in expected:
            expectedUnformatted = expectedUnformatted + line + '\n'
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted before "The first fruit in jar 1 is: o"
        try:
            index = linesPrinted.index('Which one would you like to look in first? (choose 1, 2, or 3): The first fruit in jar 3 is: o')
        except ValueError:
            index = None
        if index != None:
            del linesPrinted[:index]
            # Delete all lines in linesPrinted between "Let's try again!" and "3. both" (inclusive)
            try:
                startIndex = linesPrinted.index('Let\'s try again!')
                stopIndex = linesPrinted.index('3. both') + 1
            except ValueError:
                startIndex = None
                stopIndex = None
            if startIndex != None and stopIndex != None:
                del linesPrinted[startIndex:stopIndex]
                # Check for correct number of lines in output (to help narrow down test failures for students)
                if len(linesPrinted) < len(expected):
                    # If too few lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has fewer lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                elif len(linesPrinted) > len(expected):
                    # If too many lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has more lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                else:
                    # If correct number of lines, check content of each line
                    currentLine = 0
                    for line in linesPrinted:
                        # Compare each line of expected array to current line from output
                        if expected[currentLine] not in line:
                            # When output does not match expected, set test failure status
                            correct = False
                        currentLine += 1
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    # Update message appropriately
                    msg = ['Your program\'s output does not match the expected output. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            else:
                correct = False
                msg = ['The autograder could not split your program\'s output correctly because it cannot remove the "Let\'s try again!" block. Make sure Test #2 is passing before attempting to troubleshoot this test.']    
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'Which one would you like to look in first? (choose 1, 2, or 3): \', \'The first fruit in jar 3 is: o\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
        
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()

    # Associated test number within Gradescope
    @number("6")
    # Associated point value within Gradescope
    @weight(20)
    def test_AlreadyGuessed(self):
        # Title used by Gradescope 
        """Check that input sequence "1, b, 1, 2, a, 2, 3, o, 3, o, 3, 1, b, 2, a" results in correct output"""

        # Create a subprocess to run the students code to obtain an output
        cat = subprocess.Popen(["cat", "input/1b12a23o3o31b2a.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        test = subprocess.Popen(["./PA1.out"], stdin=cat.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output = test.stdout.read().strip().decode('utf-8')
        test.kill()
        
        # Boolean to hold value for test pass/fail (updated procedurally)
        correct = True
        
        # Array of expected lines of output, line by line in expected order
        expected = ['The first fruit in jar 1 is: a', 'That\'s correct! Good job!', 'You already correctly guessed this jar!', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!', 'You already correctly guessed this jar!', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'The first fruit in jar 3 is: o', 'That\'s correct! Good job!', 'You already correctly guessed this jar!', 'The first fruit in jar 1 is: a', 'That\'s correct! Good job!', 'The first fruit in jar 2 is: a', 'That\'s correct! Good job!']
        # Concatenated string of expected output, for display as unformatted expected output in error messages
        expectedUnformatted = ''
        for line in expected:
            expectedUnformatted = expectedUnformatted + line + '\n'
        
        # Create array of lines of submission output by splitting at new lines
        linesPrinted = output.split("\n")
        # Strip all lines containing nothing but the new line character
        linesPrinted = [line for line in linesPrinted if line != '\n']
        
        # Delete all lines in linesPrinted before "The first fruit in jar 1 is: a"
        try:
            index = linesPrinted.index('Which one would you like to look in first? (choose 1, 2, or 3): The first fruit in jar 1 is: a')
        except ValueError:
            index = None
        if index != None:
            del linesPrinted[:index]
            # Delete all lines in linesPrinted between "Let's try again!" and "3. both" (inclusive)
            try:
                startIndex = linesPrinted.index('Let\'s try again!')
                stopIndex = linesPrinted.index('3. both') + 1
            except ValueError:
                startIndex = None
                stopIndex = None
            if startIndex != None and stopIndex != None:
                del linesPrinted[startIndex:stopIndex]
                # Check for correct number of lines in output (to help narrow down test failures for students)
                if len(linesPrinted) < len(expected):
                    # If too few lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has fewer lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                elif len(linesPrinted) > len(expected):
                    # If too many lines, set test failure status and update message appropriately
                    correct = False
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    msg = ['Your program\'s output has more lines than expected. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
                else:
                    # If correct number of lines, check content of each line
                    currentLine = 0
                    for line in linesPrinted:
                        # Compare each line of expected array to current line from output
                        if expected[currentLine] not in line:
                            # When output does not match expected, set test failure status
                            correct = False
                        currentLine += 1
                    # Format the split linesPrinted array as unformatted output for student comparison
                    linesPrintedUnformatted = ''
                    for line in linesPrinted:
                        if 'Which one would you like to look in first? (choose 1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in first? (choose 1, 2, or 3): ', '') + '\n'
                        elif 'Which one would you like to look in next? (1, 2, or 3): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('Which one would you like to look in next? (1, 2, or 3): ', '') + '\n'
                        elif 'What do you think this jar really contains? (a, o, or b): ' in line:
                            linesPrintedUnformatted = linesPrintedUnformatted + line.replace('What do you think this jar really contains? (a, o, or b): ', '') + '\n'
                        else:
                            linesPrintedUnformatted = linesPrintedUnformatted + line + '\n'
                    # Update message appropriately
                    msg = ['Your program\'s output does not match the expected output. Check the lab instructions or copy your program\'s output and the expected output into https://diffchecker.com.', f'Your output (unformatted): {linesPrintedUnformatted}', f'Expected output (unformatted): {expectedUnformatted}']
            else:
                correct = False
                msg = ['The autograder could not split your program\'s output correctly because it cannot remove the "Let\'s try again!" block. Make sure Test #2 is passing before attempting to troubleshoot this test.']    
        else:
            correct = False
            msg = ['The autograder could not split your program\'s output correctly because it could not find the following: [\'Which one would you like to look in first? (choose 1, 2, or 3): \', \'The first fruit in jar 1 is: a\n\']. Check the lab instructions for the correct spelling, capitalization, spacing, or punctuation.']    
        
        # Pass test pass/fail status and message to test run output
        self.assertTrue(correct, msg)
        test.terminate()