예제 #1
0
 def setUp(self):
     FitTestCase.setUp(self)
     self.holder = ModuleHigh(type_id=None)
     self.holder.attributes = {}
     self.charge = Charge(type_id=None)
     self.charge.attributes = {}
     self.holder.charge = self.charge
예제 #2
0
 def setUp(self):
     super().setUp()
     self.holder = ModuleHigh(type_id=None)
     self.holder.attributes = {}
     self.charge = Charge(type_id=None)
     self.charge.attributes = {}
     self.holder.charge = self.charge
예제 #3
0
class TestHolderMixinChargedCycles(FitTestCase):

    def setUp(self):
        FitTestCase.setUp(self)
        self.holder = ModuleHigh(type_id=None)
        self.holder.item = Mock()
        self.holder.item.attributes = {}
        self.holder.attributes = {}
        self.charge = Charge(type_id=None)
        self.charge.item = Mock()
        self.charge.item.attributes = {}
        self.charge.attributes = {}
        self.holder.charge = self.charge

    def test_ammo_generic(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertEqual(self.holder.fully_charged_cycles, 25)
        self.assertEqual(self.holder.fully_charged_cycles_max, 25)

    def test_ammo_override(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.charge_quantity = 40
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertEqual(self.holder.fully_charged_cycles, 20)
        self.assertEqual(self.holder.fully_charged_cycles_max, 25)

    def test_ammo_round_down(self):
        self.holder.attributes[Attribute.capacity] = 22.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 4.0
        self.assertEqual(self.holder.fully_charged_cycles, 2)
        self.assertEqual(self.holder.fully_charged_cycles_max, 2)

    def test_ammo_no_quantity(self):
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 4.0
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_laser_combat(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertEqual(self.holder.fully_charged_cycles, 4400)
        self.assertEqual(self.holder.fully_charged_cycles_max, 4400)

    def test_laser_mining(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.mining_laser
        self.assertEqual(self.holder.fully_charged_cycles, 4400)
        self.assertEqual(self.holder.fully_charged_cycles_max, 4400)

    def test_laser_not_damageable(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_laser_no_hp(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_laser_no_chance(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_laser_no_damage(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_laser_override(self):
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.charge_quantity = 3
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertEqual(self.holder.fully_charged_cycles, 6600)
        self.assertEqual(self.holder.fully_charged_cycles_max, 4400)

    def test_no_item(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item = None
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_no_default_effect(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item.default_effect = None
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertIsNone(self.holder.fully_charged_cycles)
        self.assertIsNone(self.holder.fully_charged_cycles_max)

    def test_cache(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertEqual(self.holder.fully_charged_cycles, 25)
        self.assertEqual(self.holder.fully_charged_cycles_max, 25)
        del self.holder.item.attributes[Attribute.charge_rate]
        del self.holder.attributes[Attribute.charge_rate]
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item._effect_ids = (Effect.target_attack,)
        self.assertEqual(self.holder.fully_charged_cycles, 25)
        self.assertEqual(self.holder.fully_charged_cycles_max, 25)

    def test_cache_volatility(self):
        self.holder.attributes[Attribute.capacity] = 100.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.item.attributes[Attribute.charge_rate] = 1.0
        self.holder.attributes[Attribute.charge_rate] = 2.0
        self.assertEqual(self.holder.fully_charged_cycles, 25)
        self.assertEqual(self.holder.fully_charged_cycles_max, 25)
        self.holder._clear_volatile_attrs()
        del self.holder.item.attributes[Attribute.charge_rate]
        del self.holder.attributes[Attribute.charge_rate]
        self.holder.attributes[Attribute.capacity] = 4.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.charge.attributes[Attribute.crystals_get_damaged] = 1.0
        self.charge.attributes[Attribute.hp] = 2.2
        self.charge.attributes[Attribute.crystal_volatility_chance] = 0.1
        self.charge.attributes[Attribute.crystal_volatility_damage] = 0.01
        self.holder.item.default_effect.id = Effect.target_attack
        self.assertEqual(self.holder.fully_charged_cycles, 4400)
        self.assertEqual(self.holder.fully_charged_cycles_max, 4400)
예제 #4
0
class TestHolderMixinChargeQuantity(FitTestCase):

    def setUp(self):
        FitTestCase.setUp(self)
        self.holder = ModuleHigh(type_id=None)
        self.holder.attributes = {}
        self.charge = Charge(type_id=None)
        self.charge.attributes = {}
        self.holder.charge = self.charge

    def make_fit(self, *args, **kwargs):
        fit = super().make_fit(*args, **kwargs)
        fit.container = HolderSet(fit, ModuleHigh)
        return fit

    def test_generic(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)

    def test_float_error(self):
        self.holder.attributes[Attribute.capacity] = 2.3
        self.charge.attributes[Attribute.volume] = 0.1
        self.assertEqual(self.holder.charge_quantity_max, 23)
        self.assertEqual(self.holder.charge_quantity, 23)

    def test_round_down(self):
        self.holder.attributes[Attribute.capacity] = 19.7
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 9)
        self.assertEqual(self.holder.charge_quantity, 9)

    def test_no_volume(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_no_capacity(self):
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_no_charge(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.charge = None
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_cache(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)
        self.holder.attributes[Attribute.capacity] = 200.0
        self.charge.attributes[Attribute.volume] = 1.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)

    def test_volatility(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)
        self.holder._clear_volatile_attrs()
        self.holder.attributes[Attribute.capacity] = 200.0
        self.charge.attributes[Attribute.volume] = 1.0
        self.assertEqual(self.holder.charge_quantity_max, 200)
        self.assertEqual(self.holder.charge_quantity, 200)

    def test_override_set_int(self):
        eos = Mock()
        fit = self.make_fit(eos=eos)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        holder.charge_quantity = 26
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 1)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 1)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 1)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 26)

    def test_override_set_other(self):
        eos = Mock()
        fit = self.make_fit(eos=eos)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        self.assertRaises(TypeError, holder.__setattr__, 'charge_quantity', 26.0)
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 0)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 0)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 0)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)

    def test_override_del(self):
        eos = Mock()
        fit = self.make_fit(eos=eos)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        holder.charge_quantity = 26
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        del holder.charge_quantity
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 1)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 1)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 1)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)
예제 #5
0
 def test_state_higher(self):
     item = self.ch.type_(type_id=1)
     item.max_state = State.active
     holder = Mock(state=State.overload, item=item, _domain=Domain.character, spec_set=ModuleHigh(1))
     self.track_holder(holder)
     restriction_error = self.get_restriction_error(holder, Restriction.state)
     self.assertIsNotNone(restriction_error)
     self.assertEqual(restriction_error.current_state, State.overload)
     self.assertCountEqual(restriction_error.allowed_states, (State.offline, State.online, State.active))
     self.untrack_holder(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_restriction_buffers_empty()
예제 #6
0
 def test_state_equal(self):
     item = self.ch.type_(type_id=1)
     item.max_state = State.active
     holder = Mock(state=State.active, item=item, _domain=Domain.character, spec_set=ModuleHigh(1))
     self.track_holder(holder)
     restriction_error = self.get_restriction_error(holder, Restriction.state)
     self.assertIsNone(restriction_error)
     self.untrack_holder(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_restriction_buffers_empty()
예제 #7
0
 def test_mix_excess_original(self):
     # Check that original item attributes are used
     item1 = self.ch.type_(type_id=1, group=61, attributes={Attribute.max_group_fitted: 1})
     holder1 = Mock(state=State.offline, item=item1, _domain=Domain.ship, spec_set=ModuleHigh(1))
     holder1.attributes = {Attribute.max_group_fitted: 2}
     self.track_holder(holder1)
     item2 = self.ch.type_(type_id=2, group=61, attributes={Attribute.max_group_fitted: 2})
     holder2 = Mock(state=State.offline, item=item2, _domain=Domain.ship, spec_set=ModuleHigh(1))
     holder2.attributes = {Attribute.max_group_fitted: 1}
     self.track_holder(holder2)
     restriction_error1 = self.get_restriction_error(holder1, Restriction.max_group_fitted)
     self.assertIsNotNone(restriction_error1)
     self.assertEqual(restriction_error1.max_group, 1)
     self.assertEqual(restriction_error1.holder_group, 61)
     self.assertEqual(restriction_error1.group_holders, 2)
     restriction_error2 = self.get_restriction_error(holder2, Restriction.max_group_fitted)
     self.assertIsNone(restriction_error2)
     self.untrack_holder(holder1)
     self.untrack_holder(holder2)
     self.assertEqual(len(self.log), 0)
     self.assert_restriction_buffers_empty()
예제 #8
0
 def test_mix_excess_one(self):
     # Make sure error is raised for just holders which excess
     # restriction, even if both are from the same group
     item1 = self.ch.type_(type_id=1, group=92, attributes={Attribute.max_group_fitted: 1})
     holder1 = Mock(state=State.offline, item=item1, _domain=Domain.ship, spec_set=ModuleHigh(1))
     self.track_holder(holder1)
     item2 = self.ch.type_(type_id=2, group=92, attributes={Attribute.max_group_fitted: 2})
     holder2 = Mock(state=State.offline, item=item2, _domain=Domain.ship, spec_set=ModuleHigh(1))
     self.track_holder(holder2)
     restriction_error1 = self.get_restriction_error(holder1, Restriction.max_group_fitted)
     self.assertIsNotNone(restriction_error1)
     self.assertEqual(restriction_error1.max_group, 1)
     self.assertEqual(restriction_error1.holder_group, 92)
     self.assertEqual(restriction_error1.group_holders, 2)
     restriction_error2 = self.get_restriction_error(holder2, Restriction.max_group_fitted)
     self.assertIsNone(restriction_error2)
     self.untrack_holder(holder1)
     self.untrack_holder(holder2)
     self.assertEqual(len(self.log), 0)
     self.assert_restriction_buffers_empty()
예제 #9
0
class TestHolderMixinChargeQuantity(FitTestCase):

    def setUp(self):
        super().setUp()
        self.holder = ModuleHigh(type_id=None)
        self.holder.attributes = {}
        self.charge = Charge(type_id=None)
        self.charge.attributes = {}
        self.holder.charge = self.charge

    def make_fit(self, *args, **kwargs):
        fit = super().make_fit(*args, **kwargs)
        fit.container = HolderSet(fit, ModuleHigh)
        return fit

    def test_generic(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)

    def test_float_error(self):
        self.holder.attributes[Attribute.capacity] = 2.3
        self.charge.attributes[Attribute.volume] = 0.1
        self.assertEqual(self.holder.charge_quantity_max, 23)
        self.assertEqual(self.holder.charge_quantity, 23)

    def test_round_down(self):
        self.holder.attributes[Attribute.capacity] = 19.7
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 9)
        self.assertEqual(self.holder.charge_quantity, 9)

    def test_no_volume(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_no_capacity(self):
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_no_charge(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.holder.charge = None
        self.assertIsNone(self.holder.charge_quantity_max)
        self.assertIsNone(self.holder.charge_quantity)

    def test_cache(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)
        self.holder.attributes[Attribute.capacity] = 200.0
        self.charge.attributes[Attribute.volume] = 1.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)

    def test_volatility(self):
        self.holder.attributes[Attribute.capacity] = 20.0
        self.charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(self.holder.charge_quantity_max, 10)
        self.assertEqual(self.holder.charge_quantity, 10)
        self.holder._clear_volatile_attrs()
        self.holder.attributes[Attribute.capacity] = 200.0
        self.charge.attributes[Attribute.volume] = 1.0
        self.assertEqual(self.holder.charge_quantity_max, 200)
        self.assertEqual(self.holder.charge_quantity, 200)

    def test_override_set_int(self):
        source = Mock(spec_set=Source)
        fit = self.make_fit(source=source)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        holder.charge_quantity = 26
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 1)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 1)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 1)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 26)

    def test_override_set_other(self):
        source = Mock(spec_set=Source)
        fit = self.make_fit(source=source)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        self.assertRaises(TypeError, holder.__setattr__, 'charge_quantity', 26.0)
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 0)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 0)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 0)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)

    def test_override_del(self):
        source = Mock(spec_set=Source)
        fit = self.make_fit(source=source)
        holder = self.holder
        charge = self.charge
        holder._clear_volatile_attrs = Mock()
        charge._clear_volatile_attrs = Mock()
        fit.container.add(holder)
        holder.attributes[Attribute.capacity] = 20.0
        charge.attributes[Attribute.volume] = 2.0
        holder.charge_quantity = 26
        st_cleans_before = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_before = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_before = len(charge._clear_volatile_attrs.mock_calls)
        del holder.charge_quantity
        st_cleans_after = len(fit.stats._clear_volatile_attrs.mock_calls)
        holder_cleans_after = len(holder._clear_volatile_attrs.mock_calls)
        charge_cleans_after = len(charge._clear_volatile_attrs.mock_calls)
        self.assertEqual(st_cleans_after - st_cleans_before, 1)
        self.assertEqual(holder_cleans_after - holder_cleans_before, 1)
        self.assertEqual(charge_cleans_after - charge_cleans_before, 1)
        self.assertEqual(holder.charge_quantity_max, 10)
        self.assertEqual(holder.charge_quantity, 10)