class TestExceptions(unittest.TestCase):
    def setUp(self):
        self.mi = get_test_mi(debug=DEBUG, lookup=False)
        self.lexer = MacroCommandTokenizer(debug=DEBUG)
        self.parser = MacroParser(lexer_obj=self.lexer, debug=DEBUG)
        return

    # Lex/parse to trigger exceptions
    def macro_test(self, macro, correct=()):
        obj = self.parser.lex_and_parse_macro(macro)
        int_obj = self.mi.interpret_macro(macro)

    def test_UserInputError(self):
        macro = """"""
        try:
            self.macro_test(macro)
            self.fail("Did not raise UserInputError")
        except UserInputError, instance:
            out = str(instance)
            if DEBUG:
                logging.debug(out)
 def setUp(self):
     lexer = MacroCommandTokenizer(debug=DEBUG)
     self.parser = MacroParser(lexer_obj=lexer,
                               debug=DEBUG)
class TestParser(unittest.TestCase):
    def setUp(self):
        lexer = MacroCommandTokenizer(debug=DEBUG)
        self.parser = MacroParser(lexer_obj=lexer,
                                  debug=DEBUG)

    
    # Helpers to reduce repeated code
    def macro_parse(self, macro):
        if DEBUG: logger.debug(macro)
        macro_debug = []
        for i in range(len(macro)):
            macro_debug.append(str(i) + ": " + macro[i])
        if DEBUG: logger.debug(' '.join(macro_debug))

        # Parse it.
        obj = self.parser.lex_and_parse_macro(macro)

        # If we're updating, output the test code.
        if UPDATE: logger.debug("\n        macro = u\"\"\"" + macro + "\"\"\"\n        " + \
                                "objs = self.macro_parse(macro)\n        " + \
                                "correct = " + str(obj) + "\n        " + \
                                "self.macro_check(correct, objs)\n\n")

        if DEBUG:
            logger.warning("\n\n%s\n\n" % get_tree_str(obj, " "))
        return obj

    def macro_check(self, correct, obj):
        # Quickie debug helper.
        def equal(a, b):
            if a != b:
                if DEBUG:    logger.error("%s not equal to %s" % (a,b))
                elif UPDATE: logger.warning("Need to update test.")
                else:        self.assertEqual(a, b)     

        # Quickie helper traverse comparison
        def traverse(a, b):
            if DEBUG:
                logger.debug(a)
                logger.debug(b)

            # Translate tokens.
            if isinstance(a, MacroToken): a = a.get_list()
            if isinstance(b, MacroToken): b = b.get_list()
                
            equal(type(a), type(b))
            if type(a) is list or type(a) is tuple:
                equal(len(a), len(b))
                for i in range(len(a)):
                    traverse(a[i], b[i])
            else:
                equal(a, b)

        if DEBUG: logger.warning("correct: %s" % str(correct))
        if DEBUG: logger.warning("obj: %s" % str(obj))
        if not UPDATE: traverse(correct, obj)

    # Testing broken %t command--command can't expand it.
    def test_broken_insecure_with_no_curr_target(self):
        macro = '''/tell %t Hello!"'''
        self.assertRaises(ParseErrorInsecureVerbNoCurrentTarget, self.macro_parse, macro)

    # Testing insecure verbs that req targets but dont get them.
    def test_broken_insecure_req_target(self):
        macro = '''/tell "Hello!"'''
        self.assertRaises(LexErrorNoMatchingRules, self.macro_parse, macro)

    # Testing insecure verbs with targets
    def test_insecure_with_target(self):
        macro = '''/tell Fitz Hello!"'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/tell', 0, 5, True], [(None, [((None, None, [['TARGET_OBJ', 1, 'Fitz', 6, 10, True]]), None)], None, [(None, ['PARAMETER', 2, 'Hello!"', 11, 18, False])])])
        self.macro_check(correct, objs)

    # Testing insecure verbs with targets
    def test_insecure_glare(self):
        macro = '''/glare'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/glare', 0, 6, False], [(None, [((None, None, []), None)], None, None)])
        self.macro_check(correct, objs)

    # From a comment--CRITICAL CRASH
    def test_critical_crash(self):
        macro = '''/cast [target=focus,target=target]'''
        self.assertRaises(ParseErrorMultiTargetCondition, self.macro_parse, macro)

    # From forums
    def test_group_option_raid(self):
        macro = '''/cast [group:raid] Test'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [(None, (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 2, 'group', 7, 12, False], ['IS', 3, ':', 12, 13, False], [['OPTION_ARG', 4, 'raid', 13, 17, False]])], ['ENDIF', 5, ']', 17, 18, False]))], None, [(None, ['PARAMETER', 6, 'Test', 19, 23, False])])])
        self.macro_check(correct, objs)
        
    def test_assist_empty_obj(self):
        macro ="""/assist Fitzcairn;"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/assist', 0, 7, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Fitzcairn', 8, 17, False])]), (['ELSE', 2, ';', 17, 18, False], None, None, None)])
        self.macro_check(correct, objs)


    def test_assist_unit(self):
        macro ="""/assist Fitzcairn"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/assist', 0, 7, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Fitzcairn', 8, 17, False])])])
        self.macro_check(correct, objs)


    def test_bad_else_command(self):
        macro ="""/cast Spell; [combat] Spell2;"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Spell', 6, 11, False])]), (['ELSE', 2, ';', 11, 12, False], [(None, (['IF', 3, '[', 13, 14, False], [(None, ['OPTION_WORD', 4, 'combat', 14, 20, False], None, None)], ['ENDIF', 5, ']', 20, 21, False]))], None, [(None, ['PARAMETER', 6, 'Spell2', 22, 28, False])]), (['ELSE', 7, ';', 28, 29, False], None, None, None)])
        self.macro_check(correct, objs)


    # Test new changes for 3.2
    def test_broken_targeting(self):
        macro ="""/petattack [target=Fire Resistance Totem]"""
        self.assertRaises(LexErrorNoMatchingRules, self.macro_parse, macro)


    def test_empty_command_obj(self):
        macro ="""/cast [combat] Spell 1;"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [(None, (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 2, 'combat', 7, 13, False], None, None)], ['ENDIF', 3, ']', 13, 14, False]))], None, [(None, ['PARAMETER', 4, 'Spell 1', 15, 22, False])]), (['ELSE', 5, ';', 22, 23, False], None, None, None)])
        self.macro_check(correct, objs)


    def test_empty_conditions(self):
        macro ="""/cast [target=mouseover, help] [ ] Flash of Light"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'mouseover', 14, 23, False]]), (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 6, 'help', 25, 29, False], None, None)], ['ENDIF', 7, ']', 29, 30, False])), (None, (['IF', 8, '[', 31, 32, False], None, ['ENDIF', 9, ']', 33, 34, False]))], None, [(None, ['PARAMETER', 10, 'Flash of Light', 35, 49, False])])])
        self.macro_check(correct, objs)


    def test_empty_multiline(self):
        macro ="""/cast [target=mouseover, harm] Blind; [target=targettarget] Kidney Shot
            




"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'mouseover', 14, 23, False]]), (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 6, 'harm', 25, 29, False], None, None)], ['ENDIF', 7, ']', 29, 30, False]))], None, [(None, ['PARAMETER', 8, 'Blind', 31, 36, False])]), (['ELSE', 9, ';', 36, 37, False], [((['TARGET', 11, 'target', 39, 45, False], ['GETS', 12, '=', 45, 46, False], [['TARGET_OBJ', 13, 'target', 46, 52, False], ['TARGET_OBJ', 14, 'target', 52, 58, False]]), (['IF', 10, '[', 38, 39, False], None, ['ENDIF', 15, ']', 58, 59, False]))], None, [(None, ['PARAMETER', 16, 'Kidney Shot', 60, 71, False])])])
        self.macro_check(correct, objs)


    def test_empty_rank(self):
        macro ="""/cast Faerie Fire (Feral)()"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Faerie Fire (Feral)()', 6, 27, False])])])
        self.macro_check(correct, objs)


    def test_equipslot_command(self):
        macro ="""/equipslot [combat] 14 Phat Dagger; [nocombat] 16 Poop Dagger"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/equipslot', 0, 10, True], [(None, [(None, (['IF', 1, '[', 11, 12, False], [(None, ['OPTION_WORD', 2, 'combat', 12, 18, False], None, None)], ['ENDIF', 3, ']', 18, 19, False]))], None, [(None, ['PARAMETER', 4, '14', 20, 22, True]), (None, ['PARAMETER', 5, 'Phat Dagger', 23, 34, False])]), (['ELSE', 6, ';', 34, 35, False], [(None, (['IF', 7, '[', 36, 37, False], [(['NOT', 8, 'no', 37, 39, False], ['OPTION_WORD', 9, 'combat', 39, 45, False], None, None)], ['ENDIF', 10, ']', 45, 46, False]))], None, [(None, ['PARAMETER', 11, '16', 47, 49, True]), (None, ['PARAMETER', 12, 'Poop Dagger', 50, 61, False])])])
        self.macro_check(correct, objs)


    def test_insecure_command(self):
        macro = '/party [combat] !"Oh crap!"'
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/party', 0, 6, True], [(None, None, None, [(None, ['PARAMETER', 1, '[combat] !"Oh crap!"', 7, 27, False])])])
        self.macro_check(correct, objs)


    def test_metacommands(self):
        macro ="""#show Stealth"""
        objs = self.macro_parse(macro)
        correct = (['META_COMMAND_VERB', 0, '#show', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Stealth', 6, 13, False])])])
        self.macro_check(correct, objs)


    def test_multiple_conditions(self):
        macro ="""/cast [help] [target=targettarget, help] [target=player] Flash Heal"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [(None, (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 2, 'help', 7, 11, False], None, None)], ['ENDIF', 3, ']', 11, 12, False])), ((['TARGET', 5, 'target', 14, 20, False], ['GETS', 6, '=', 20, 21, False], [['TARGET_OBJ', 7, 'target', 21, 27, False], ['TARGET_OBJ', 8, 'target', 27, 33, False]]), (['IF', 4, '[', 13, 14, False], [(None, ['OPTION_WORD', 10, 'help', 35, 39, False], None, None)], ['ENDIF', 11, ']', 39, 40, False])), ((['TARGET', 13, 'target', 42, 48, False], ['GETS', 14, '=', 48, 49, False], [['TARGET_OBJ', 15, 'player', 49, 55, False]]), (['IF', 12, '[', 41, 42, False], None, ['ENDIF', 16, ']', 55, 56, False]))], None, [(None, ['PARAMETER', 17, 'Flash Heal', 57, 67, False])])])
        self.macro_check(correct, objs)


    def test_non_param_command(self):
        macro ="""/targetfriend [combat] [nocombat]"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/targetfriend', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'combat', 15, 21, False], None, None)], ['ENDIF', 3, ']', 21, 22, False])), (None, (['IF', 4, '[', 23, 24, False], [(['NOT', 5, 'no', 24, 26, False], ['OPTION_WORD', 6, 'combat', 26, 32, False], None, None)], ['ENDIF', 7, ']', 32, 33, False]))], None, None)])
        self.macro_check(correct, objs)


    def test_non_param_command_multi_objs(self):
        macro ="""/targetfriend [combat]; [nocombat]"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/targetfriend', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'combat', 15, 21, False], None, None)], ['ENDIF', 3, ']', 21, 22, False]))], None, None), (['ELSE', 4, ';', 22, 23, False], [(None, (['IF', 5, '[', 24, 25, False], [(['NOT', 6, 'no', 25, 27, False], ['OPTION_WORD', 7, 'combat', 27, 33, False], None, None)], ['ENDIF', 8, ']', 33, 34, False]))], None, None)])
        self.macro_check(correct, objs)


    def test_reset_after_conditions(self):
        macro ="""/castsequence [combat] reset=target Curse of Agony, Immolate, Corruption"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'combat', 15, 21, False], None, None)], ['ENDIF', 3, ']', 21, 22, False]))], (['MODIFIER', 4, 'reset', 23, 28, False], ['GETS', 5, '=', 28, 29, False], [['OPTION_ARG', 6, 'target', 29, 35, True]]), [(None, ['PARAMETER', 7, 'Curse of Agony', 36, 50, False]), (None, ['PARAMETER', 9, 'Immolate', 52, 60, False]), (None, ['PARAMETER', 11, 'Corruption', 62, 72, False])])])
        self.macro_check(correct, objs)


    def test_secure_with_no_conditions(self):
        macro ="""/targetlastenemy"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/targetlastenemy', 0, 16, False], [(None, None, None, None)])
        self.macro_check(correct, objs)


    def test_simple(self):
        macro ="""/cast Spell"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Spell', 6, 11, False])])])
        self.macro_check(correct, objs)


    def test_simple_equipslot_command(self):
        macro ="""/equipslot [combat] 14 Phat Dagger"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/equipslot', 0, 10, True], [(None, [(None, (['IF', 1, '[', 11, 12, False], [(None, ['OPTION_WORD', 2, 'combat', 12, 18, False], None, None)], ['ENDIF', 3, ']', 18, 19, False]))], None, [(None, ['PARAMETER', 4, '14', 20, 22, True]), (None, ['PARAMETER', 5, 'Phat Dagger', 23, 34, False])])])
        self.macro_check(correct, objs)


    def test_swapactionbar_num_args(self):
        macro ="""/swapactionbar 1 2"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/swapactionbar', 0, 14, True], [(None, None, None, [(None, ['PARAMETER', 1, '1', 15, 16, True]), (None, ['PARAMETER', 2, '2', 17, 18, False])])])
        self.macro_check(correct, objs)


    def test_target_args(self):
        macro ="""/cast [target=raidpet2] [] Spell 1"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'raidpet', 14, 21, False], ['OPTION_ARG', 5, '2', 21, 22, False]]), (['IF', 1, '[', 6, 7, False], None, ['ENDIF', 6, ']', 22, 23, False])), (None, (['IF', 7, '[', 24, 25, False], None, ['ENDIF', 8, ']', 25, 26, False]))], None, [(None, ['PARAMETER', 9, 'Spell 1', 27, 34, False])])])
        self.macro_check(correct, objs)


    def test_target_args_chain(self):
        macro ="""/cast [] [target=party2targettargettarget] Spell 1"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [(None, (['IF', 1, '[', 6, 7, False], None, ['ENDIF', 2, ']', 7, 8, False])), ((['TARGET', 4, 'target', 10, 16, False], ['GETS', 5, '=', 16, 17, False], [['TARGET_OBJ', 6, 'party', 17, 22, False], ['OPTION_ARG', 7, '2', 22, 23, False], ['TARGET_OBJ', 8, 'target', 23, 29, False], ['TARGET_OBJ', 9, 'target', 29, 35, False], ['TARGET_OBJ', 10, 'target', 35, 41, False]]), (['IF', 3, '[', 9, 10, False], None, ['ENDIF', 11, ']', 41, 42, False]))], None, [(None, ['PARAMETER', 12, 'Spell 1', 43, 50, False])])])
        self.macro_check(correct, objs)


    def test_target_chain(self):
        macro ="""/cast [target=playertargettargettarget] Spell 1"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'player', 14, 20, False], ['TARGET_OBJ', 5, 'target', 20, 26, False], ['TARGET_OBJ', 6, 'target', 26, 32, False], ['TARGET_OBJ', 7, 'target', 32, 38, False]]), (['IF', 1, '[', 6, 7, False], None, ['ENDIF', 8, ']', 38, 39, False]))], None, [(None, ['PARAMETER', 9, 'Spell 1', 40, 47, False])])])
        self.macro_check(correct, objs)


    def test_targetlastenemy(self):
        macro ="""/targetlastenemy [combat]"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/targetlastenemy', 0, 16, True], [(None, [(None, (['IF', 1, '[', 17, 18, False], [(None, ['OPTION_WORD', 2, 'combat', 18, 24, False], None, None)], ['ENDIF', 3, ']', 24, 25, False]))], None, None)])
        self.macro_check(correct, objs)


    def test_three_params(self):
        macro ="""/cast [target=mouseover,harm] Smite; [target=mouseover, help] Greater Heal; [] Greater Heal"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'mouseover', 14, 23, False]]), (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 6, 'harm', 24, 28, False], None, None)], ['ENDIF', 7, ']', 28, 29, False]))], None, [(None, ['PARAMETER', 8, 'Smite', 30, 35, False])]), (['ELSE', 9, ';', 35, 36, False], [((['TARGET', 11, 'target', 38, 44, False], ['GETS', 12, '=', 44, 45, False], [['TARGET_OBJ', 13, 'mouseover', 45, 54, False]]), (['IF', 10, '[', 37, 38, False], [(None, ['OPTION_WORD', 15, 'help', 56, 60, False], None, None)], ['ENDIF', 16, ']', 60, 61, False]))], None, [(None, ['PARAMETER', 17, 'Greater Heal', 62, 74, False])]), (['ELSE', 18, ';', 74, 75, False], [(None, (['IF', 19, '[', 76, 77, False], None, ['ENDIF', 20, ']', 77, 78, False]))], None, [(None, ['PARAMETER', 21, 'Greater Heal', 79, 91, False])])])
        self.macro_check(correct, objs)


    def test_use_with_bag(self):
        macro ="""/use 13 14"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/use', 0, 4, True], [(None, None, None, [(None, ['PARAMETER', 1, '13', 5, 7, True]), (None, ['PARAMETER', 2, '14', 8, 10, False])])])
        self.macro_check(correct, objs)


    def test_use_with_item(self):
        macro ="""/use Swift Dagger"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/use', 0, 4, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Swift Dagger', 5, 17, False])])])
        self.macro_check(correct, objs)


    def test_use_with_slot(self):
        macro ="""/use 13"""
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/use', 0, 4, True], [(None, None, None, [(None, ['PARAMETER', 1, '13', 5, 7, False])])])
        self.macro_check(correct, objs)


    def test_option_args(self): 
        macro = '''/castsequence [] reset=10/20/harm Battlestrider, Swift Green Mechanostrider'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], None, ['ENDIF', 2, ']', 15, 16, False]))], (['MODIFIER', 3, 'reset', 17, 22, False], ['GETS', 4, '=', 22, 23, False], [['OPTION_ARG', 5, '10', 23, 25, False], ['OPTION_ARG', 7, '20', 26, 28, False], ['OPTION_ARG', 9, 'harm', 29, 33, True]]), [(None, ['PARAMETER', 10, 'Battlestrider', 34, 47, False]), (None, ['PARAMETER', 12, 'Swift Green Mechanostrider', 49, 75, False])])])
        self.macro_check(correct, objs)


    def test_reset(self): 
        macro = '''/castsequence reset=10/harm [target=mouseover,harm,nobutton:1/2] Spell 1, Other Spell, Some Item; [] Test, Test2'''
        self.assertRaises(ParseErrorResetBeforeConditions, self.macro_parse, macro)


    def test_toggled_list(self): 
        macro = '''/castsequence [combat] reset=120 Spell 1, !Spell 2, !Spell 3'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'combat', 15, 21, False], None, None)], ['ENDIF', 3, ']', 21, 22, False]))], (['MODIFIER', 4, 'reset', 23, 28, False], ['GETS', 5, '=', 28, 29, False], [['OPTION_ARG', 6, '120', 29, 32, True]]), [(None, ['PARAMETER', 7, 'Spell 1', 33, 40, False]), (['TOGGLE', 9, '!', 42, 43, False], ['PARAMETER', 10, 'Spell 2', 43, 50, False]), (['TOGGLE', 12, '!', 52, 53, False], ['PARAMETER', 13, 'Spell 3', 53, 60, False])])])
        self.macro_check(correct, objs)


    # Testing to make sure a broken command actually breaks.
    def test_broken_equipslot(self):
        macro = '/equipslot [combat] dagger'
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)


    # Test to make sure we break on bad slot/bag commands
    def test_broken_use(self):
        macro = '/use 13 Dagger'
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)
        macro = '/use 13 14 Dagger'
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)
        macro = '/use'
        self.assertRaises(ParseErrorParamRequired, self.macro_parse, macro)

    # Test to make sure we break on bad options.
    def test_broken_options(self):
        macro = '/cast [actionbar] Spell'
        self.assertRaises(ParseErrorReqArgsForOption, self.macro_parse, macro)
        macro = '/cast [equipped] Spell'
        self.assertRaises(ParseErrorReqArgsForOption, self.macro_parse, macro)
        macro = '/cast [button] Spell'
        self.assertRaises(ParseErrorReqArgsForOption, self.macro_parse, macro)

    # Test an else
    def test_bad_else_command(self):
        macro ="/cast Spell; [combat] Spell2;"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Spell', 6, 11, False])]), (['ELSE', 2, ';', 11, 12, False], [(None, (['IF', 3, '[', 13, 14, False], [(None, ['OPTION_WORD', 4, 'combat', 14, 20, False], None, None)], ['ENDIF', 5, ']', 20, 21, False]))], None, [(None, ['PARAMETER', 6, 'Spell2', 22, 28, False])]), (['ELSE', 7, ';', 28, 29, False], None, None, None)])
        self.macro_check(correct, objs)


    # Test that we can handle extra verbs.
    def test_extra_verb(self):
        macro ="/cast Spell; /cast [combat] Spell2;"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Spell', 6, 11, False])]), (['ELSE', 2, ';', 11, 12, False], [(None, (['IF', 4, '[', 19, 20, False], [(None, ['OPTION_WORD', 5, 'combat', 20, 26, False], None, None)], ['ENDIF', 6, ']', 26, 27, False]))], None, [(None, ['PARAMETER', 7, 'Spell2', 28, 34, False])]), (['ELSE', 8, ';', 34, 35, False], None, None, None)])
        self.macro_check(correct, objs)
        macro = '/cast Spell; /cancelaura [combat] Spell'
        self.assertRaises(ParseErrorMultipleVerbs, self.macro_parse, macro)
        

    def test_fail_empty_commands(self):
        macro ="/castsequence;"
        self.assertRaises(ParseErrorParamRequired, self.macro_parse, macro)

    # Test a command with space issues, as well as default targets
    def test_spaces_in_targets(self):
        macro ="/focus  [ mod : shift , no mod : ctrl ]  none ; [ target = focus , harm , no dead ]  focus ; [ harm , no dead ]  ; none"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/focus', 0, 6, True], [(None, [(None, (['IF', 1, '[', 7, 8, False], [(None, ['OPTION_WORD', 2, 'mod', 9, 12, False], ['IS', 3, ':', 13, 14, False], [['OPTION_ARG', 4, 'shift', 15, 20, False]]), (['NOT', 6, 'no', 23, 25, False], ['OPTION_WORD', 7, 'mod', 26, 29, False], ['IS', 8, ':', 30, 31, False], [['OPTION_ARG', 9, 'ctrl', 32, 36, False]])], ['ENDIF', 10, ']', 37, 38, False]))], None, [(None, ['PARAMETER', 11, 'none', 39, 43, False])]), (['ELSE', 12, ';', 44, 45, False], [((['TARGET', 14, 'target', 48, 54, False], ['GETS', 15, '=', 55, 56, False], [['TARGET_OBJ', 16, 'focus', 57, 62, False]]), (['IF', 13, '[', 46, 47, False], [(None, ['OPTION_WORD', 18, 'harm', 65, 69, False], None, None), (['NOT', 20, 'no', 72, 74, False], ['OPTION_WORD', 21, 'dead', 75, 79, False], None, None)], ['ENDIF', 22, ']', 80, 81, False]))], None, [(None, ['PARAMETER', 23, 'focus', 82, 87, False])]), (['ELSE', 24, ';', 88, 89, False], [(None, (['IF', 25, '[', 90, 91, False], [(None, ['OPTION_WORD', 26, 'harm', 92, 96, False], None, None), (['NOT', 28, 'no', 99, 101, False], ['OPTION_WORD', 29, 'dead', 102, 106, False], None, None)], ['ENDIF', 30, ']', 107, 108, False]))], None, None), (['ELSE', 31, ';', 109, 110, False], None, None, [(None, ['PARAMETER', 32, 'none', 111, 115, False])])])
        self.macro_check(correct, objs)

    # Reset always follows conditions.
    def test_reset_before_conditions(self):
        macro ="/castsequence [combat] reset=target Curse of Agony, Immolate, Corruption"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'combat', 15, 21, False], None, None)], ['ENDIF', 3, ']', 21, 22, False]))], (['MODIFIER', 4, 'reset', 23, 28, False], ['GETS', 5, '=', 28, 29, False], [['OPTION_ARG', 6, 'target', 29, 35, True]]), [(None, ['PARAMETER', 7, 'Curse of Agony', 36, 50, False]), (None, ['PARAMETER', 9, 'Immolate', 52, 60, False]), (None, ['PARAMETER', 11, 'Corruption', 62, 72, False])])])
        self.macro_check(correct, objs)


    # Test equipslot with bags
    def test_bag_equipslot(self):
        macro ="/equipslot 16 0 12"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/equipslot', 0, 10, True], [(None, None, None, [(None, ['PARAMETER', 1, '16', 11, 13, True]), (None, ['PARAMETER', 2, '0', 14, 15, True]), (None, ['PARAMETER', 3, '12', 16, 18, False])])])
        self.macro_check(correct, objs)

    # Test equip with bags
    def test_bag_equip(self):
        macro ="/equip 0 12"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/equip', 0, 6, True], [(None, None, None, [(None, ['PARAMETER', 1, '0', 7, 8, True]), (None, ['PARAMETER', 2, '12', 9, 11, False])])])
        self.macro_check(correct, objs)

     
    # Test special click commands
    def test_click_cmds(self):
        macro ="/click PetActionButton5 LeftButton"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/click', 0, 6, True], [(None, None, None, [(None, ['PARAMETER', 1, 'PetActionButton', 7, 22, False]), (None, ['PARAMETER', 2, '5', 22, 23, True]), (None, ['PARAMETER', 3, 'LeftButton', 24, 34, False])])])
        self.macro_check(correct, objs)
        macro ="/click PetActionButton5"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/click', 0, 6, True], [(None, None, None, [(None, ['PARAMETER', 1, 'PetActionButton', 7, 22, False]), (None, ['PARAMETER', 2, '5', 22, 23, False])])])
        self.macro_check(correct, objs)

    # Test broken click command
    def test_click_broken_cmds(self):
        macro ="/click Garbarage124Button4"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/click', 0, 6, True], [(None, None, None, [(None, ['PARAMETER', 1, 'Garbarage124Button4', 7, 26, False])])])
        self.macro_check(correct, objs)


    # Test broken actionbar commands
    def test_swapactionbar_fail(self):
        macro ="/swapactionbar [combat] 2 3 4"
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)
        macro ="/swapactionbar [combat] 2"
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)
        macro ="/swapactionbar [combat]"
        self.assertRaises(ParseErrorParamRequired, self.macro_parse, macro)

    def test_changeactionbar_fail(self):
        macro ="/changeactionbar [combat]"
        self.assertRaises(ParseErrorParamRequired, self.macro_parse, macro)
        macro ="/changeactionbar [combat] 2 3"
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)        


    # Test broken harden command
    def test_helpme(self):
        macro ="/helpme"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/helpme', 0, 7, False], [(None, None, None, None)])
        self.macro_check(correct, objs)

    # Another broken harden command.
    def test_equipslot_wrong_params(self):
        macro ="""/equipslot [button:2] Z X Y"""
        self.assertRaises(ParseErrorWrongParams, self.macro_parse, macro)


    # Test out the new lexer rules for @target 3.3 changes.
    def test_target_alias(self):
        macro = '''/cast [@focus] Test'''    
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, '@', 7, 8, False], None, [['TARGET_OBJ', 3, 'focus', 8, 13, False]]), (['IF', 1, '[', 6, 7, False], None, ['ENDIF', 4, ']', 13, 14, False]))], None, [(None, ['PARAMETER', 5, 'Test', 15, 19, False])])])
        self.macro_check(correct, objs)

    # Test to make sure insecure commands that require params
    # trigger the exception.
    def test_insecure_param_required(self):
        macro ="""/master"""
        self.assertRaises(ParseErrorParamRequired, self.macro_parse, macro)

    # Another test that seems to be causing problems
    def test_broken_cast_target_pet(self):
        macro = '''/cast [combat,modifier:alt,harm,target=pettarget] [] Shadow Bolt'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 10, 'target', 32, 38, False], ['GETS', 11, '=', 38, 39, False], [['TARGET_OBJ', 12, 'pet', 39, 42, False], ['TARGET_OBJ', 13, 'target', 42, 48, False]]), (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 2, 'combat', 7, 13, False], None, None), (None, ['OPTION_WORD', 4, 'modifier', 14, 22, False], ['IS', 5, ':', 22, 23, False], [['OPTION_ARG', 6, 'alt', 23, 26, False]]), (None, ['OPTION_WORD', 8, 'harm', 27, 31, False], None, None)], ['ENDIF', 14, ']', 48, 49, False])), (None, (['IF', 15, '[', 50, 51, False], None, ['ENDIF', 16, ']', 51, 52, False]))], None, [(None, ['PARAMETER', 17, 'Shadow Bolt', 53, 64, False])])])
        self.macro_check(correct, objs)

    def test_sequence_w_empties(self):    
        macro = '''/castsequence reset=combat ,,Potion of Wild Magic,'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, None, (['MODIFIER', 1, 'reset', 14, 19, False], ['GETS', 2, '=', 19, 20, False], [['OPTION_ARG', 3, 'combat', 20, 26, True]]), [(None, ['PARAMETER', 4, '', 27, 27, False]), (None, ['PARAMETER', 6, '', 28, 28, False]), (None, ['PARAMETER', 8, 'Potion of Wild Magic', 29, 49, False]), (None, ['PARAMETER', 10, '', 50, 50, False])])])
        self.macro_check(correct, objs)

    # This broke some things.
    def test_ors_with_options(self):
        macro = '''/castsequence [modifier:alt,nogroup,pet:Voidwalker/pet:Felhunter] Searing Pain, Shadow Bolt, Shadow Bolt'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/castsequence', 0, 13, True], [(None, [(None, (['IF', 1, '[', 14, 15, False], [(None, ['OPTION_WORD', 2, 'modifier', 15, 23, False], ['IS', 3, ':', 23, 24, False], [['OPTION_ARG', 4, 'alt', 24, 27, False]]), (['NOT', 6, 'no', 28, 30, False], ['OPTION_WORD', 7, 'group', 30, 35, False], None, None), (None, ['OPTION_WORD', 9, 'pet', 36, 39, False], ['IS', 10, ':', 39, 40, False], [['OPTION_ARG', 11, 'Voidwalker', 40, 50, False], ['OPTION_ARG', 15, 'Felhunter', 55, 64, False]])], ['ENDIF', 16, ']', 64, 65, False]))], None, [(None, ['PARAMETER', 17, 'Searing Pain', 66, 78, False]), (None, ['PARAMETER', 19, 'Shadow Bolt', 80, 91, False]), (None, ['PARAMETER', 21, 'Shadow Bolt', 93, 104, False])])])
        self.macro_check(correct, objs)

    # Ensure this breaks.
    def test_ors_with_options_broken(self):
        macro = '''/castsequence [modifier:alt,nogroup,pet:Voidwalker/nopet:Felhunter] Searing Pain, Shadow Bolt, Shadow Bolt'''
        self.assertRaises(ParseErrorNonMatchingNegs, self.macro_parse, macro)
        macro = '''/castsequence [modifier:alt,nogroup,pet:Voidwalker/stance:1] Searing Pain, Shadow Bolt, Shadow Bolt'''
        self.assertRaises(ParseErrorNonMatchingOptionWords, self.macro_parse, macro)

    # Another broken macro
    def test_broken_click(self):
        macro = '''/click [nomod] ORLOpen OPieRaidSymbols;'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/click', 0, 6, True], [(None, [(None, (['IF', 1, '[', 7, 8, False], [(['NOT', 2, 'no', 8, 10, False], ['OPTION_WORD', 3, 'mod', 10, 13, False], None, None)], ['ENDIF', 4, ']', 13, 14, False]))], None, [(None, ['PARAMETER', 5, 'ORLOpen OPieRaidSymbols', 15, 38, False])]), (['ELSE', 6, ';', 38, 39, False], None, None, None)])
        self.macro_check(correct, objs)

    # Another broken macro
    def test_broken_equip_macro(self):
        macro = '''/equip [noequipped: Fishing Pole,nomod:shift] Fishing Pole;'''
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/equip', 0, 6, True], [(None, [(None, (['IF', 1, '[', 7, 8, False], [(['NOT', 2, 'no', 8, 10, False], ['OPTION_WORD', 3, 'equipped', 10, 18, False], ['IS', 4, ':', 18, 19, False], [['OPTION_ARG', 5, 'Fishing Pole', 20, 32, False]]), (['NOT', 7, 'no', 33, 35, False], ['OPTION_WORD', 8, 'mod', 35, 38, False], ['IS', 9, ':', 38, 39, False], [['OPTION_ARG', 10, 'shift', 39, 44, False]])], ['ENDIF', 11, ']', 44, 45, False]))], None, [(None, ['PARAMETER', 12, 'Fishing Pole', 46, 58, False])]), (['ELSE', 13, ';', 58, 59, False], None, None, None)])
        self.macro_check(correct, objs)

    # Test commenting
    def test_commenting(self):
        macro = "--/use 14"
        objs = self.macro_parse(macro)
        correct = (['COMMENTED_LINE', 0, '--/use 14', 0, 9, False], [(None, None, None, None)])
        self.macro_check(correct, objs)

    # Test follow-on targeting
    def test_option_targeting_follow1(self):
        macro = "/cast [target=Fitz-target-target-focus]Mark of the Wild"
        self.assertRaises(ParseErrorInvalidTargetToken, self.macro_parse, macro)

    # Test follow-on targeting
    def test_option_targeting_follow2(self):
        macro = "/cast [target=Fitz-target-target]Mark of the Wild"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'Fitz-', 14, 19, False], ['TARGET_OBJ', 5, 'target-', 19, 26, False], ['TARGET_OBJ', 6, 'target', 26, 32, False]]), (['IF', 1, '[', 6, 7, False], None, ['ENDIF', 7, ']', 32, 33, False]))], None, [(None, ['PARAMETER', 8, 'Mark of the Wild', 33, 49, False])])])
        self.macro_check(correct, objs)


    # Test parsing for option args that modify targeting
    def test_target_option_args(self):
        macro = "/cast [target=player,mod:FOCUSCAST]Spell"
        objs = self.macro_parse(macro)
        correct = (['COMMAND_VERB', 0, '/cast', 0, 5, True], [(None, [((['TARGET', 2, 'target', 7, 13, False], ['GETS', 3, '=', 13, 14, False], [['TARGET_OBJ', 4, 'player', 14, 20, False]]), (['IF', 1, '[', 6, 7, False], [(None, ['OPTION_WORD', 6, 'mod', 21, 24, False], ['IS', 7, ':', 24, 25, False], [['OPTION_ARG', 8, 'FOCUSCAST', 25, 34, False]])], ['ENDIF', 9, ']', 34, 35, False]))], None, [(None, ['PARAMETER', 10, 'Spell', 35, 40, False])])])
        self.macro_check(correct, objs)
 def setUp(self):
     self.mi = get_test_mi(debug=DEBUG, lookup=False)
     self.lexer = MacroCommandTokenizer(debug=DEBUG)
     self.parser = MacroParser(lexer_obj=self.lexer, debug=DEBUG)
     return