public void GetSizeModifier_Large_Plus1()
        {
            // Arrange
            var strength = Mock.Of <IAbilityScore>();

            var mockAbilityScores = new Mock <IAbilityScoreSection>();

            mockAbilityScores.Setup(abs => abs.Strength)
            .Returns(strength);

            var mockCharacter = new Mock <ICharacter>();

            mockCharacter.Setup(c => c.AbilityScores)
            .Returns(mockAbilityScores.Object);
            mockCharacter.Setup(c => c.Size)
            .Returns(SizeCategory.Large);

            CombatManeuverBonus cmb = new CombatManeuverBonus(mockCharacter.Object);

            // Act
            var result = cmb.GetSizeModifier();

            // Assert
            Assert.AreEqual(1, result,
                            "A large character should receive a +1 bonus to CMB.");
        }
        public void GetTotal_Aggregates()
        {
            // Arrange
            var mockBaseAttackBonus = new Mock <IBaseAttackBonus>();

            mockBaseAttackBonus.Setup(bab => bab.GetTotal())
            .Returns(20);

            var mockAttackBonusSection = new Mock <IAttackBonusSection>();

            mockAttackBonusSection.Setup(abs => abs.BaseAttackBonus)
            .Returns(mockBaseAttackBonus.Object);

            var mockAbilityScore = new Mock <IAbilityScore>();

            mockAbilityScore.Setup(ab => ab.GetModifier())
            .Returns(2);

            var mockAbilityScores = new Mock <IAbilityScoreSection>();

            mockAbilityScores.Setup(abs => abs.Strength)
            .Returns(mockAbilityScore.Object);

            var mockCharacter = new Mock <ICharacter>();

            mockCharacter.Setup(c => c.AbilityScores)
            .Returns(mockAbilityScores.Object);
            mockCharacter.Setup(c => c.AttackBonuses)
            .Returns(mockAttackBonusSection.Object);
            mockCharacter.Setup(c => c.Size)
            .Returns(SizeCategory.Large);

            CombatManeuverBonus cmb = new CombatManeuverBonus(mockCharacter.Object);

            cmb.EnhancementBonuses.Add(() => 3);
            cmb.UntypedBonuses.Add(() => 4);
            cmb.Penalties.Add(() => 5);

            // Act
            var result = cmb.GetTotal();

            // Assert
            Assert.AreEqual(25, result,
                            "25 = (20 BAB) + (1 size) + (2 strength) + (3 enhancement) + (4 untyped) - (5 penalty)");
        }
        public void PenaltyTracker_ReadsMeleeAttackBonus()
        {
            // Arrange
            var mockBonusTracker = new Mock <IModifierTracker>();

            mockBonusTracker.Setup(bt => bt.GetTotal())
            .Returns(5);

            var mockUniversalMeleeAttackBonus = new Mock <IUniversalAttackBonus>();

            mockUniversalMeleeAttackBonus.Setup(umab => umab.Penalties)
            .Returns(mockBonusTracker.Object);

            var mockAttackBonusSection = new Mock <IAttackBonusSection>();

            mockAttackBonusSection.Setup(abs => abs.GenericMeleeAttackBonus)
            .Returns(mockUniversalMeleeAttackBonus.Object);

            var mockAbilityScores = new Mock <IAbilityScoreSection>();

            mockAbilityScores.Setup(abs => abs.Strength)
            .Returns(Mock.Of <IAbilityScore>());

            var mockCharacter = new Mock <ICharacter>();

            mockCharacter.Setup(c => c.AbilityScores)
            .Returns(mockAbilityScores.Object);
            mockCharacter.Setup(c => c.AttackBonuses)
            .Returns(mockAttackBonusSection.Object);

            CombatManeuverBonus cmb = new CombatManeuverBonus(mockCharacter.Object);

            // Act
            var result = cmb.Penalties.GetTotal();

            // Assert
            Assert.AreEqual(5, result,
                            "Penalties which apply to all melee attack rolls should also be applied to CMB.");
        }
        public void Default()
        {
            // Arrange
            var strength = Mock.Of <IAbilityScore>();

            var mockAbilityScores = new Mock <IAbilityScoreSection>();

            mockAbilityScores.Setup(abs => abs.Strength)
            .Returns(strength);

            var mockCharacter = new Mock <ICharacter>();

            mockCharacter.Setup(c => c.AbilityScores)
            .Returns(mockAbilityScores.Object);

            CombatManeuverBonus cmb = new CombatManeuverBonus(mockCharacter.Object);

            // Assert
            Assert.AreSame(strength, cmb.KeyAbilityScore, "By default, CMB should be keyed to a character's strength score.");
            Assert.IsInstanceOf <EnhancementBonusTracker>(cmb.EnhancementBonuses);
            Assert.IsInstanceOf <UntypedBonusTracker>(cmb.UntypedBonuses);
            Assert.IsInstanceOf <PenaltyTracker>(cmb.Penalties);
        }
        public void KeyAbilityScore_NullAssignment_Throws()
        {
            // Arrange
            var strength = Mock.Of <IAbilityScore>();

            var mockAbilityScores = new Mock <IAbilityScoreSection>();

            mockAbilityScores.Setup(abs => abs.Strength)
            .Returns(strength);

            var mockCharacter = new Mock <ICharacter>();

            mockCharacter.Setup(c => c.AbilityScores)
            .Returns(mockAbilityScores.Object);

            CombatManeuverBonus cmb = new CombatManeuverBonus(mockCharacter.Object);

            // Act
            TestDelegate assignment = () => cmb.KeyAbilityScore = null;

            // Assert
            Assert.Throws <ArgumentNullException>(assignment,
                                                  "CombatManeuverBonus.KeyAbilityScore should not accept null assignment values.");
        }