def _build_units(self, **kwargs):
        self.log.info("Building units")

        unit_model = UnitModel(db=self.db)
        unit_models = unit_model.get_units()

        item_collection = kwargs["item_collection"]
        effect_collection = kwargs["effect_collection"]
        dialogue_collection = kwargs["dialogue_collection"]
        unit_effects_map = kwargs["unit_effects_map"]
        unit_dialogue_map = kwargs["unit_dialogue_map"]
        unit_items_map = kwargs["unit_items_map"]

        unit_builder = UnitBuilder()
        unit_collection = UnitCollection()
        units = \
            unit_builder.build_units(unit_models=unit_models,
                                     item_collection=item_collection,
                                     effect_collection=effect_collection,
                                     dialogue_collection=dialogue_collection,
                                     unit_effects_map=unit_effects_map,
                                     unit_items_map=unit_items_map,
                                     unit_dialogue_map=unit_dialogue_map,
                                     log=self.log)

        for unit in units:
            unit_collection.add(unit)

        return {
            "unit_collection": unit_collection,
            "unit_model": unit_model
        }
    def get_combatants(self):
        """
        Create units, with an item of each type
        """
        item_collection = ItemCollection()
        unit_models = []
        unit_items_list = []
        expected_units = []

        item_types = ("rock", "paper", "scissors", "lizard", "spock")
        for item_type in item_types:
            item = self._make_item(item_type=item_type)
            item_collection.add(item)

        for j in range(0, 2):
            unit_model = self._get_unit_model()
            unit_id = unit_model["id"]

            for c_item in item_collection.items:
                unit_items_list.append({"item_id": c_item.id,
                                        "unit_id": unit_id})
                unit_model["items"].append(c_item)

            with LogCapture():
                logger = logging.getLogger()
                unit = Unit(unit=unit_model, log=logger)

            expected_units.append(unit)
            unit_models.append(unit_model)

        """
        Although we added more items, the collection should
        never add duplicates
        """
        total_items = len(item_types)
        self.assertEqual(len(item_collection.items), total_items)

        """
        There two units with five items each, so unit_items_map
        should have ten items total
        """
        unit_items_list_length = len(unit_items_list)
        self.assertEqual(unit_items_list_length, 10)

        builder = UnitBuilder()
        unit_items_model = UnitItems(db="quux")
        unit_items_map = unit_items_model._get_unit_items_map(unit_items_list)

        with LogCapture():
            logger = logging.getLogger()
            actual_units = builder.build_units(unit_models=unit_models,
                                               unit_items_map=unit_items_map,
                                               item_collection=item_collection,
                                               effect_collection="quux",
                                               dialogue_collection="quux",
                                               unit_effects_map={},
                                               unit_dialogue_map={},
                                               log=logger)

        self.assertEqual(len(expected_units), len(actual_units))

        """
        Ensure that each unit has the expected item set
        """
        unit_items = [uitem for uitem in item_collection.items]

        for unit in actual_units:
            # Ensure that each of the new units have full HP
            self.assertEqual(unit.get_hp(), unit.calculate_hp())
            self.assertEqual(unit.items, unit_items)

        return actual_units
    def test_create_units(self):
        """
        The item collection is populated by models
        """
        item_collection = ItemCollection()
        effect_collection = EffectCollection()
        dialogue_collection = UnitDialogueCollection()

        """
        Prepare unit model collection
        """
        unit_models = []
        expected_units = []
        unit_items = []
        unit_effects = []
        unit_dialogue = []
        unit_items_model = UnitItems(db="quux")
        unit_effects_model = UnitEffects(db="quux")
        unit_dialogue_model = UnitDialogueModel(db="quux")

        total_units = 25
        item_types = ("rock", "paper", "scissors", "paper", "spock")
        total_items_per_unit = len(item_types)
        total_effects_per_unit = 5
        total_dialogue_per_unit = 5

        for j in range(0, total_units):
            """
            Add items for each unit
            """
            items = []
            effects = []
            dialogue = []
            unit_model = self._get_unit_model()
            unit_id = unit_model["id"]
            unit_type_id = unit_model["unit_type_id"]

            for it in item_types:
                item = self._make_item(item_type=it,
                                       unit_type_id=unit_type_id)
                items.append(item)
                item_collection.add(item)
                unit_items.append({"item_id": item.id, "unit_id": unit_id})

            unit_model["items"] = items

            """
            Base items
            """
            unit_model["base_items"] = \
                item_collection.get_base_items_by_unit_type_id(unit_type_id)

            """
            Add effects
            """
            for k in range(0, total_effects_per_unit):
                effect = self._make_effect()
                effects.append(effect)
                effect_collection.add(effect)
                unit_effects.append(
                    {"effect_id": effect.id, "unit_id": unit_id})

            unit_model["effects"] = effects

            """
            Add dialogue
            """
            for q in range(0, total_dialogue_per_unit):
                a_dialogue = self._make_dialogue()
                dialogue.append(a_dialogue)
                dialogue_collection.add(a_dialogue)
                unit_dialogue.append(
                    {"dialogue_id": a_dialogue.id, "unit_id": unit_id})

            unit_model["dialogue"] = dialogue

            """
            Add completed unit to expected
            """
            unit_models.append(unit_model)

            with LogCapture():
                logger = logging.getLogger()
                unit = Unit(unit=unit_model, log=logger)

            expected_units.append(unit)

        unit_items_map = unit_items_model._get_unit_items_map(unit_items)
        unit_effects_map = unit_effects_model._get_unit_effects_map(
            unit_effects)
        unit_dialogue_map = unit_dialogue_model._get_unit_dialogue_map(
            unit_dialogue)

        builder = UnitBuilder()
        with LogCapture():
            logger = logging.getLogger()
            actual_units = builder.build_units(unit_models=unit_models,
                                               unit_items_map=unit_items_map,
                                               item_collection=item_collection,
                                               effect_collection=effect_collection,
                                               unit_effects_map=unit_effects_map,
                                               dialogue_collection=dialogue_collection,
                                               unit_dialogue_map=unit_dialogue_map,
                                               log=logger)

        expected_unit_ids = [unit.id for e_unit in expected_units]
        actual_unit_ids = [unit.id for a_unit in actual_units]

        self.assertEqual(expected_unit_ids, actual_unit_ids)

        """
        Test that the actual units contain the expected items
        and effects
        """
        self.assertEqual(len(actual_units), len(expected_units))

        for e_unit in expected_units:
            self.assertEqual(len(e_unit.items), total_items_per_unit)
            self.assertEqual(len(e_unit.effects), total_effects_per_unit)
            self.assertEqual(len(e_unit.dialogue), total_dialogue_per_unit)

        for a_unit in actual_units:
            self.assertEqual(len(a_unit.items), total_items_per_unit)
            self.assertEqual(len(a_unit.effects), total_effects_per_unit)
            self.assertEqual(len(a_unit.dialogue), total_dialogue_per_unit)

            """
            Ensure each item either has no unit type requirement (0)
            or it matches the unit in question
            """
            for a_item in a_unit.items:
                self.assertIn(a_item.unit_type_id, (0, a_unit.unit_type_id))
    def test_build_world(self):
        """
        Utilize models to build the world.

        1. Get dungeons
        2. Get effects
        3. Get item effects
        4. Get items
        5. Get unit items
        6. Get units
        """

        """ Dungeons """
        dungeon_model = DungeonModel(db=self.db)
        dungeon_models = dungeon_model.get_dungeons()

        self.assertIsInstance(dungeon_models, list)
        self.assertTrue(dungeon_models)

        """ Effects """
        effects_model = EffectModel(db=self.db)
        effects_models = effects_model.get_effects()

        self.assertIsInstance(effects_models, list)
        self.assertTrue(effects_models)

        """ Unit effects map """
        unit_effects_model = UnitEffects(db=self.db)
        unit_effects = unit_effects_model.get_unit_effects()
        unit_effects_map = unit_effects_model._get_unit_effects_map(unit_effects)

        self.assertIsInstance(unit_effects_map, dict)
        self.assertTrue(unit_effects_map)

        """ Unit dialogue map """
        unit_dialogue_model = UnitDialogueModel(db=self.db)
        unit_dialogue = unit_dialogue_model.get_unit_dialogue()
        unit_dialogue_map = unit_dialogue_model._get_unit_dialogue_map(unit_dialogue)

        self.assertIsInstance(unit_dialogue, list)
        self.assertIsInstance(unit_dialogue_map, dict)
        self.assertTrue(unit_dialogue_map)

        """ Item effects map """
        item_effects_model = ItemEffects(db=self.db)
        item_effects = item_effects_model.get_item_effects()
        item_effects_map = item_effects_model._get_item_effects_map(item_effects)

        self.assertIsInstance(item_effects, list)
        self.assertIsInstance(item_effects_map, dict)
        self.assertTrue(item_effects_map)
        self.assertTrue(item_effects)

        """ Items """
        item_model = ItemModel(db=self.db)
        item_models = item_model.get_items()

        self.assertIsInstance(item_models, list)
        self.assertTrue(item_models)

        """ Unit items map """
        unit_items_model = UnitItems(db=self.db)
        unit_item_models = unit_items_model.get_unit_items()
        unit_items_map = unit_items_model._get_unit_items_map(unit_item_models)

        self.assertIsInstance(unit_item_models, list)
        self.assertIsInstance(unit_items_map, dict)
        self.assertTrue(unit_items_map)
        self.assertTrue(unit_item_models)

        """ Units """
        unit_model = UnitModel(db=self.db)
        unit_models = unit_model.get_units()

        self.assertIsInstance(unit_models, list)
        self.assertTrue(unit_models)

        """ Assemble collections using models """
        item_collection = ItemCollection()
        effect_collection = EffectCollection()
        dialogue_collection = UnitDialogueCollection()

        for effect_model in effects_models:
            effect = Effect(effect=effect_model)
            effect_collection.add(effect)

        self.assertTrue(effect_collection.effects)

        item_builder = ItemBuilder()
        items = item_builder.build_items(item_models=item_models,
                                         item_effects_map=item_effects_map,
                                         effect_collection=effect_collection)
        self.assertIsInstance(items, list)
        self.assertTrue(items)

        for item in items:
            item_collection.add(item)

        self.assertTrue(item_collection.items)

        for ud in unit_dialogue:
            dialogue = UnitDialogue(dialogue=ud)
            dialogue_collection.add(dialogue)

        """ Build units using assembled collections """
        unit_builder = UnitBuilder()

        with LogCapture() as l:
            logger = logging.getLogger()
            units = unit_builder.build_units(unit_models=unit_models,
                                             effect_collection=effect_collection,
                                             item_collection=item_collection,
                                             dialogue_collection=dialogue_collection,
                                             unit_items_map=unit_items_map,
                                             unit_effects_map=unit_effects_map,
                                             unit_dialogue_map=unit_dialogue_map,
                                             log=logger)

        self.assertIsInstance(units, list)
        self.assertTrue(units)

        num_players = 0

        for unit in units:
            self.assertIsInstance(unit, Unit)

            if unit.is_player:
                num_players += 1

        self.assertTrue(num_players > 0)

        """
        Populate collections
        """
        unit_collection = UnitCollection()

        for unit in units:
            unit_collection.add(unit)

        self.assertEqual(len(unit_collection.units), len(unit_models))