class TestAttacking(unittest.TestCase):

    def setUp(self):
        self.character = Character()
        self.opponent = Character()
        self.opponent.damage = MagicMock()

    @patch("evercraft.roll", return_value=5)
    def test_attacking_rolls_a_d20(self,roll):
        self.character.attack(self.opponent)
        self.assertEqual(roll.call_count, 1)

    @patch("evercraft.roll", return_value=19)
    def test_hits_when_rolling_at_or_over_target_ac(self, roll):
        self.character.attack(self.opponent)
        self.assertEqual(self.opponent.damage.call_count, 1)

    @patch("evercraft.roll", return_value=19)
    def test_hits_doing_default_damage(self, roll):
        self.character.attack(self.opponent)
        self.opponent.damage.assert_called_once_with(DEFAULT_DAMAGE)

    @patch("evercraft.roll", return_value=2)
    def test_miss_when_rolling_below_target_ac(self, roll):
        self.character.attack(self.opponent)
        self.assertEqual(self.opponent.damage.call_count, 0)

    @patch("evercraft.roll", return_value=20)
    def test_critical_hit_does_double_damage(self,roll):
        self.character.attack(self.opponent)
        self.opponent.damage.assert_called_once_with(DEFAULT_DAMAGE * 2)
class TestModifiersModifying(DefaultCharacter):

    def test_dex_adds_armor(self):
        for score in range(1,20):
            self.character.stat("dex",score)
            self.assertEqual(self.character.armor_class(),
                    DEFAULT_ARMOR_CLASS + self.character.stat_mod("dex"))

    @patch("evercraft.roll", return_value=10)
    def test_roll_str_modifier(self, __):
        for score in range(1,20):
            result = self.character.roll_stat("str")
            self.assertEqual(result, 10 + self.character.stat_mod("str"))

    @patch("evercraft.roll", return_value=19)
    def test_str_adds_damage(self, __):
        self.character.stat("str",20)
        self.opponent = Character()
        self.character.attack(self.opponent)
        self.assertEqual(self.opponent.hit_points(), 
                DEFAULT_HIT_POINTS - (DEFAULT_DAMAGE + 5))

    def test_con_adds_hit_points(self):
        for score in range(1,20):
            self.assertEqual(self.character.hit_points(),
                DEFAULT_HIT_POINTS + self.character.stat_mod("con"))
 def test_calculate_level(self):
     cases = [(0,1), (999,1), (1000, 2), (1001, 2), (2000, 3), (3000, 4)]
     for xp, expected_level in cases:
       self.character = Character()
       self.character.add_experience(xp)
       self.assertEqual(self.character.level(), expected_level, 
                        "%s %s"%(xp, self.character.level()))
class TestCharacter(TestCase):

    def setUp(self):
        self.subject = Character()

    def test_name_has_expected_default_value(self):
        self.assertEqual(self.subject.name, '')

    def test_name_can_be_changed(self):
        self.subject.name = 'Bob the Destroyer'
        self.assertEqual(self.subject.name, 'Bob the Destroyer')

    def test_alignment_has_expected_default_value(self):
        self.assertEqual(self.subject.alignment, Alignment.NEUTRAL)

    def test_alignment_can_be_changed_to_good(self):
        self.subject.alignment = Alignment.GOOD
        self.assertEqual(self.subject.alignment, Alignment.GOOD)

    def test_alignment_can_be_changed_to_evil(self):
        self.subject.alignment = Alignment.EVIL
        self.assertEqual(self.subject.alignment, Alignment.EVIL)

    def test_armor_class_has_expected_default(self):
        self.assertEqual(self.subject.armor_class, 10)

    def test_hit_points_has_expected_default(self):
        self.assertEqual(self.subject.hit_points, 5)

    def test_is_alive_when_undamaged(self):
        self.assertTrue(self.subject.alive)

    def test_is_alive_when_damaged(self):
        self.subject.damage(3)
        self.assertTrue(self.subject.alive)

    def test_is_dead_when_out_of_hit_points(self):
        self.subject.damage(5)
        self.assertFalse(self.subject.alive)
class TestExperience(unittest.TestCase):

    def setUp(self):
        self.character = Character()
        self.opponent = Character()

    @patch("evercraft.roll", return_value=20)
    def test_xp_gain_on_hit(self, __):
        self.character.attack(self.opponent)
        self.assertEqual(self.character.experience_points(), XP_PER_HIT)

    @patch("evercraft.roll", return_value=2)
    def test_xp_gain_on_miss(self, __):
        self.character.attack(self.opponent)
        self.assertEqual(self.character.experience_points(), 0)

    def test_calculate_level(self):
        cases = [(0,1), (999,1), (1000, 2), (1001, 2), (2000, 3), (3000, 4)]
        for xp, expected_level in cases:
          self.character = Character()
          self.character.add_experience(xp)
          self.assertEqual(self.character.level(), expected_level, 
                           "%s %s"%(xp, self.character.level()))
 def setUp(self):
     self.character = Character()
     self.opponent = Character()
     self.opponent.damage = MagicMock()
 def setUp(self):
     self.character = Character()
     self.opponent = Character()
 def test_str_adds_damage(self, __):
     self.character.stat("str",20)
     self.opponent = Character()
     self.character.attack(self.opponent)
     self.assertEqual(self.opponent.hit_points(), 
             DEFAULT_HIT_POINTS - (DEFAULT_DAMAGE + 5))
 def setUp(self):
     self.subject = Character()