Example #1
0
 def setUp(self):
     app_settings = MagicMock()
     self._temp_dir = TemporaryDirectory()
     url = "sqlite:///" + os.path.join(self._temp_dir.name, "db.sqlite")
     db_map = DiffDatabaseMapping(url, create=True)
     import_object_classes(db_map, ("class1",))
     import_object_parameters(db_map, (("class1", "parameter1"), ("class1", "parameter2")))
     import_objects(db_map, (("class1", "object1"), ("class1", "object2")))
     import_object_parameter_values(
         db_map,
         (
             ("class1", "object1", "parameter1", 1.0),
             ("class1", "object2", "parameter1", 3.0),
             ("class1", "object1", "parameter2", 5.0),
             ("class1", "object2", "parameter2", 7.0),
         ),
     )
     db_map.commit_session("Add test data.")
     db_map.connection.close()
     with patch("spinetoolbox.spine_db_manager.SpineDBManager.thread", new_callable=PropertyMock) as mock_thread:
         mock_thread.return_value = QApplication.instance().thread()
         self._db_mngr = SpineDBManager(app_settings, None)
         with patch.object(SpineDBEditor, "restore_ui"):
             self._editor = SpineDBEditor(self._db_mngr, {url: db_map.codename})
     object_class_index = self._editor.object_tree_model.index(0, 0)
     self._editor.object_tree_model.fetchMore(object_class_index)
     index = self._editor.object_tree_model.index(0, 0, object_class_index)
     self._editor.reload_pivot_table(index)
     self._model = self._editor.pivot_table_model
     self._model.start_fetching()
Example #2
0
 def setUp(self):
     """Overridden method. Runs before each test. Makes instance of SpineDBEditor class."""
     with mock.patch(
             "spinetoolbox.spine_db_manager.QMessageBox"
     ), mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
     ):
         self.mock_db_mngr = mock.MagicMock()
         self.mock_db_mngr.undo_action.__getitem__.side_effect = lambda key: QAction(
         )
         self.mock_db_mngr.redo_action.__getitem__.side_effect = lambda key: QAction(
         )
         self.mock_db_map = mock.MagicMock()
         self.mock_db_map.codename = "mock_db"
         self.ds_view_form = SpineDBEditor(self.mock_db_mngr,
                                           self.mock_db_map)
Example #3
0
 def setUp(self):
     """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
     with mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
     ), mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"
     ):
         mock_settings = mock.Mock()
         mock_settings.value.side_effect = lambda *args, **kwards: 0
         self.db_mngr = SpineDBManager(mock_settings, None)
         # TODO: Use a temp file?
         url = "sqlite:///test.sqlite"
         create_new_spine_database(url)
         self.db_mngr.fetch_db_maps_for_listener = lambda *args: None
         self.spine_db_editor = SpineDBEditor(self.db_mngr, {url: "db"})
         self.db_map = self.spine_db_editor.first_db_map
         self.spine_db_editor.pivot_table_model = mock.MagicMock()
 def setUp(self):
     """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
     self._temp_dir = TemporaryDirectory()
     url = "sqlite:///" + os.path.join(self._temp_dir.name, "test.sqlite")
     with mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
     ), mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"
     ):
         mock_settings = mock.Mock()
         mock_settings.value.side_effect = lambda *args, **kwards: 0
         self.db_mngr = SpineDBManager(mock_settings, None)
         logger = mock.MagicMock()
         self.db_map = self.db_mngr.get_db_map(url,
                                               logger,
                                               codename="db",
                                               create=True)
         self.spine_db_editor = SpineDBEditor(self.db_mngr, {url: "db"})
         self.spine_db_editor.pivot_table_model = mock.MagicMock()
    def setUp(self):
        """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
        with mock.patch("spinetoolbox.spine_db_manager.DiffDatabaseMapping") as mock_DiffDBMapping, mock.patch(
            "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
        ), mock.patch("spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"):
            mock_settings = mock.Mock()
            mock_settings.value.side_effect = lambda *args, **kwards: 0
            self.db_mngr = SpineDBManager(mock_settings, None)
            self.db_mngr.fetch_db_maps_for_listener = lambda *args: None

            def DiffDBMapping_side_effect(url, codename=None, upgrade=False, create=False):
                mock_db_map = mock.MagicMock()
                mock_db_map.db_url = url
                mock_db_map.codename = codename
                return mock_db_map

            mock_DiffDBMapping.side_effect = DiffDBMapping_side_effect
            self.spine_db_editor = SpineDBEditor(self.db_mngr, {"mock_url": "mock_db"})
            self.mock_db_map = self.spine_db_editor.first_db_map
            self.spine_db_editor.pivot_table_model = mock.MagicMock()
 def setUp(self):
     """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
     self._temp_dir = TemporaryDirectory()
     url = "sqlite:///" + os.path.join(self._temp_dir.name, "test.sqlite")
     create_new_spine_database(url)
     with mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
     ), mock.patch(
             "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"
     ):
         mock_settings = mock.Mock()
         mock_settings.value.side_effect = lambda *args, **kwards: 0
         with mock.patch(
                 "spinetoolbox.spine_db_manager.SpineDBManager.thread",
                 new_callable=mock.PropertyMock) as mock_thread:
             mock_thread.return_value = QApplication.instance().thread()
             self.db_mngr = SpineDBManager(mock_settings, None)
         self.spine_db_editor = SpineDBEditor(self.db_mngr, {url: "db"})
         self.db_map = self.spine_db_editor.first_db_map
         self.spine_db_editor.pivot_table_model = mock.MagicMock()
Example #7
0
    def setUp(self):
        """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
        with mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
        ), mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"
        ):
            mock_settings = mock.Mock()
            mock_settings.value.side_effect = lambda *args, **kwards: 0
            self.db_mngr = SpineDBManager(mock_settings, None)
            self.db_mngr.fetch_db_maps_for_listener = lambda *args: None

            logger = mock.MagicMock()
            self.db_mngr.get_db_map("sqlite://",
                                    logger,
                                    codename="database",
                                    create=True)
            self.spine_db_editor = SpineDBEditor(self.db_mngr,
                                                 {"sqlite://": "database"})
            self.mock_db_map = self.spine_db_editor.first_db_map
            self.spine_db_editor.pivot_table_model = mock.MagicMock()
 def setUp(self):
     app_settings = MagicMock()
     logger = MagicMock()
     with unittest.mock.patch(
             "spinetoolbox.spine_db_manager.SpineDBManager.thread",
             new_callable=PropertyMock) as mock_thread:
         mock_thread.return_value = QApplication.instance().thread()
         self._db_mngr = SpineDBManager(app_settings, None)
     self._db_editor = SpineDBEditor(self._db_mngr)
     self._db_map = self._db_mngr.get_db_map("sqlite://",
                                             logger,
                                             codename="test_db",
                                             create=True)
 def setUp(self):
     db_mngr = MagicMock()
     # db_mngr.get_value.side_effect = lambda db_map, item_type, id_, field, role: id_
     db_mngr.get_item.side_effect = lambda db_map, item_type, id_: {
         "name": id_,
         "parameter_name": id_
     }
     db_mngr.get_value_index.side_effect = (
         lambda db_map, item_type, id_, index, role: {
             "value1": {
                 "index1": 5,
                 "index2": -3
             },
             "value2": {
                 "index1": 40,
                 "index2": -24
             },
         }.get(id_, {}).get(index))
     mock_db_map = Mock()
     mock_db_map.codename = "codename"
     db_mngr.undo_action.__getitem__.side_effect = lambda key: QAction()
     db_mngr.redo_action.__getitem__.side_effect = lambda key: QAction()
     with patch.object(SpineDBEditor, "restore_ui"):
         tabular_view = SpineDBEditor(db_mngr, mock_db_map)
     self._model = IndexExpansionPivotTableModel(tabular_view)
     data = {
         ('node1', 'unitA', 'index1', 'parameter1', 'alternative1'):
         'value1',
         ('node1', 'unitB', 'index2', 'parameter1', 'alternative1'):
         'value1',
         ('node2', 'unitA', 'index1', 'parameter1', 'alternative1'):
         'value2',
         ('node2', 'unitB', 'index2', 'parameter1', 'alternative1'):
         'value2',
     }
     tabular_view.load_expanded_parameter_value_data = lambda: data
     object_class_ids = {'node': 1, 'unit': 2}
     self._model.call_reset_model(object_class_ids)
     self._model.start_fetching()
 def setUp(self):
     db_mngr = MagicMock()
     db_mngr.get_value.side_effect = lambda db_map, item_type, id_, field, role: id_
     db_mngr.get_item.side_effect = lambda db_map, item_type, id_: {
         "name": id_,
         "parameter_name": id_
     }
     mock_db_map = Mock()
     mock_db_map.codename = "codename"
     db_mngr.undo_action.__getitem__.side_effect = lambda key: QAction()
     db_mngr.redo_action.__getitem__.side_effect = lambda key: QAction()
     with patch.object(SpineDBEditor, "restore_ui"):
         tabular_view = SpineDBEditor(db_mngr, mock_db_map)
     self._model = ParameterValuePivotTableModel(tabular_view)
     data = {
         ('object1', 'parameter1', 'alternative1'): '1',
         ('object2', 'parameter1', 'alternative1'): '3',
         ('object1', 'parameter2', 'alternative1'): '5',
         ('object2', 'parameter2', 'alternative1'): '7',
     }
     tabular_view.load_parameter_value_data = lambda: data
     object_class_ids = {'object_class': 1}
     self._model.call_reset_model(object_class_ids)
     self._model.start_fetching()
Example #11
0
class TestAddItemsDialog(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Overridden method. Runs once before all tests in this class."""
        try:
            cls.app = QApplication().processEvents()
        except RuntimeError:
            pass
        logging.basicConfig(
            stream=sys.stderr,
            level=logging.DEBUG,
            format='%(asctime)s %(levelname)s: %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
        )

    def setUp(self):
        """Overridden method. Runs before each test. Makes instance of SpineDBEditor class."""
        with mock.patch(
                "spinetoolbox.spine_db_manager.QMessageBox"
        ), mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
        ):
            self.mock_db_mngr = mock.MagicMock()
            self.mock_db_mngr.undo_action.__getitem__.side_effect = lambda key: QAction(
            )
            self.mock_db_mngr.redo_action.__getitem__.side_effect = lambda key: QAction(
            )
            self.mock_db_map = mock.MagicMock()
            self.mock_db_map.codename = "mock_db"
            self.ds_view_form = SpineDBEditor(self.mock_db_mngr,
                                              self.mock_db_map)

    def tearDown(self):
        """Overridden method. Runs after each test.
        Use this to free resources after a test if needed.
        """
        with mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.save_window_state"
        ) as mock_save_w_s:
            self.ds_view_form.close()
            mock_save_w_s.assert_called_once()
        self.ds_view_form.deleteLater()
        self.ds_view_form = None
        try:
            os.remove('mock_db.sqlite')
        except OSError:
            pass

    def test_add_object_classes(self):
        """Test object classes are added through the manager when accepting the dialog."""
        dialog = AddObjectClassesDialog(self.ds_view_form, self.mock_db_mngr,
                                        self.mock_db_map)
        model = dialog.model
        header = model.header
        model.fetchMore()
        self.assertEqual(
            header,
            ['object_class name', 'description', 'display icon', 'databases'])
        indexes = [
            model.index(0, header.index(field))
            for field in ('object_class name', 'databases')
        ]
        values = ['fish', 'mock_db']
        model.batch_set_data(indexes, values)

        def _add_object_classes(db_map_data):
            self.assertTrue(self.mock_db_map in db_map_data)
            data = db_map_data[self.mock_db_map]
            self.assertEqual(len(data), 1)
            item = data[0]
            self.assertTrue("name" in item)
            self.assertEqual(item["name"], "fish")

        self.mock_db_mngr.add_object_classes.side_effect = _add_object_classes
        dialog.accept()
        self.mock_db_mngr.add_object_classes.assert_called_once()

    def test_do_not_add_object_classes_with_invalid_db(self):
        """Test object classes aren't added when the database is not correct."""
        dialog = AddObjectClassesDialog(self.ds_view_form, self.mock_db_mngr,
                                        self.mock_db_map)
        self.ds_view_form.msg_error = mock.NonCallableMagicMock()
        self.ds_view_form.msg_error.attach_mock(mock.MagicMock(), "emit")
        model = dialog.model
        header = model.header
        model.fetchMore()
        self.assertEqual(
            header,
            ['object_class name', 'description', 'display icon', 'databases'])
        indexes = [
            model.index(0, header.index(field))
            for field in ('object_class name', 'databases')
        ]
        values = ['fish', 'gibberish']
        model.batch_set_data(indexes, values)
        dialog.accept()
        self.mock_db_mngr.add_object_classes.assert_not_called()
        self.ds_view_form.msg_error.emit.assert_called_with(
            "Invalid database 'gibberish' at row 1")
class TestSpineDBEditorWithDBMapping(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Overridden method. Runs once before all tests in this class."""
        try:
            cls.app = QApplication().processEvents()
        except RuntimeError:
            pass
        logging.basicConfig(
            stream=sys.stderr,
            level=logging.DEBUG,
            format='%(asctime)s %(levelname)s: %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
        )

    def setUp(self):
        """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
        self._temp_dir = TemporaryDirectory()
        url = "sqlite:///" + os.path.join(self._temp_dir.name, "test.sqlite")
        with mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
        ), mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"
        ):
            mock_settings = mock.Mock()
            mock_settings.value.side_effect = lambda *args, **kwards: 0
            self.db_mngr = SpineDBManager(mock_settings, None)
            logger = mock.MagicMock()
            self.db_map = self.db_mngr.get_db_map(url,
                                                  logger,
                                                  codename="db",
                                                  create=True)
            self.spine_db_editor = SpineDBEditor(self.db_mngr, {url: "db"})
            self.spine_db_editor.pivot_table_model = mock.MagicMock()

    def tearDown(self):
        """Overridden method. Runs after each test.
        Use this to free resources after a test if needed.
        """
        with mock.patch(
                "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.save_window_state"
        ) as mock_save_w_s, mock.patch(
                "spinetoolbox.spine_db_manager.QMessageBox"):
            self.spine_db_editor.close()
            mock_save_w_s.assert_called_once()
        QApplication.removePostedEvents(
            None)  # Clean up unfinished fetcher signals
        self.db_mngr.close_all_sessions()
        self.db_mngr.clean_up()
        self.db_mngr = None  # Ensure the database file is closed to allow the temporary directory to be removed.
        self.spine_db_editor.deleteLater()
        self.spine_db_editor = None
        self._temp_dir.cleanup()

    def fetch_object_tree_model(self):
        for item in self.spine_db_editor.object_tree_model.visit_all():
            if item.can_fetch_more():
                item.fetch_more()

    def test_duplicate_object_in_object_tree_model(self):
        data = dict()
        data["object_classes"] = ["fish", "dog"]
        data["relationship_classes"] = [("fish__dog", ("fish", "dog"))]
        data["objects"] = [("fish", "nemo"), ("dog", "pluto")]
        data["relationships"] = [("fish__dog", ("nemo", "pluto"))]
        data["object_parameters"] = [("fish", "color")]
        data["object_parameter_values"] = [("fish", "nemo", "color", "orange")]
        with mock.patch(
                "spinetoolbox.spine_db_manager.SpineDBManager.entity_class_icon"
        ) as mock_icon:
            mock_icon.return_value = None
            loop = QEventLoop()
            self.db_mngr.data_imported.connect(loop.quit)
            self.db_mngr.import_data({self.db_map: data})
            loop.exec_()
            loop.deleteLater()
            mock_icon.assert_called()
        self.fetch_object_tree_model()
        root_item = self.spine_db_editor.object_tree_model.root_item
        fish_item = next(
            iter(item for item in root_item.children
                 if item.display_data == "fish"))
        nemo_item = fish_item.child(0)
        with mock.patch(
                "spinetoolbox.spine_db_editor.widgets.tree_view_mixin.QInputDialog"
        ) as mock_input_dialog:
            mock_input_dialog.getText.side_effect = lambda *args, **kwargs: (
                "nemo_copy", True)
            loop = QEventLoop()
            self.db_mngr.data_imported.connect(loop.quit)
            self.spine_db_editor.duplicate_object(nemo_item.index())
            loop.exec_()
            loop.deleteLater()
        nemo_dupe = fish_item.child(1)
        self.assertEqual(nemo_dupe.display_data, "nemo_copy")
class TestSpineDBEditor(
    TestSpineDBEditorAddMixin,
    TestSpineDBEditorUpdateMixin,
    TestSpineDBEditorRemoveMixin,
    TestSpineDBEditorFilterMixin,
    unittest.TestCase,
):
    @staticmethod
    def _object_class(*args):
        return dict(zip(["id", "name", "description", "display_order", "display_icon"], args))

    @staticmethod
    def _object(*args):
        return dict(zip(["id", "class_id", "name", "description"], args))

    @staticmethod
    def _relationship_class(*args):
        return dict(zip(["id", "name", "object_class_id_list", "object_class_name_list"], args))

    @staticmethod
    def _relationship(*args):
        return dict(
            zip(
                ["id", "class_id", "name", "class_name", "object_class_id_list", "object_id_list", "object_name_list"],
                args,
            )
        )

    @staticmethod
    def _object_parameter_definition(*args):
        d = dict(zip(["id", "object_class_id", "object_class_name", "parameter_name"], args))
        return d

    @staticmethod
    def _relationship_parameter_definition(*args):
        d = dict(
            zip(
                [
                    "id",
                    "relationship_class_id",
                    "relationship_class_name",
                    "object_class_id_list",
                    "object_class_name_list",
                    "parameter_name",
                ],
                args,
            )
        )
        return d

    @staticmethod
    def _object_parameter_value(*args):
        d = dict(
            zip(
                [
                    "id",
                    "object_class_id",
                    "object_class_name",
                    "object_id",
                    "object_name",
                    "parameter_id",
                    "parameter_name",
                    "value",
                ],
                args,
            )
        )
        d["entity_id"] = d["object_id"]
        return d

    @staticmethod
    def _relationship_parameter_value(*args):
        d = dict(
            zip(
                [
                    "id",
                    "relationship_class_id",
                    "relationship_class_name",
                    "object_class_id_list",
                    "object_class_name_list",
                    "relationship_id",
                    "object_id_list",
                    "object_name_list",
                    "parameter_id",
                    "parameter_name",
                    "value",
                ],
                args,
            )
        )
        d["entity_id"] = d["relationship_id"]
        return d

    @classmethod
    def setUpClass(cls):
        """Overridden method. Runs once before all tests in this class."""
        try:
            cls.app = QApplication().processEvents()
        except RuntimeError:
            pass
        logging.basicConfig(
            stream=sys.stderr,
            level=logging.DEBUG,
            format='%(asctime)s %(levelname)s: %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
        )
        cls.create_mock_dataset()

    @classmethod
    def create_mock_dataset(cls):
        cls.fish_class = cls._object_class(1, "fish", "A fish.", 1, None)
        cls.dog_class = cls._object_class(2, "dog", "A dog.", 3, None)
        cls.fish_dog_class = cls._relationship_class(
            3,
            "fish__dog",
            str(cls.fish_class["id"]) + "," + str(cls.dog_class["id"]),
            cls.fish_class["name"] + "," + cls.dog_class["name"],
        )
        cls.dog_fish_class = cls._relationship_class(
            4,
            "dog__fish",
            str(cls.dog_class["id"]) + "," + str(cls.fish_class["id"]),
            cls.dog_class["name"] + "," + cls.fish_class["name"],
        )
        cls.nemo_object = cls._object(1, cls.fish_class["id"], 'nemo', 'The lost one.')
        cls.pluto_object = cls._object(2, cls.dog_class["id"], 'pluto', "Mickey's.")
        cls.scooby_object = cls._object(3, cls.dog_class["id"], 'scooby', 'Scooby-Dooby-Doo.')
        cls.pluto_nemo_rel = cls._relationship(
            4,
            cls.dog_fish_class["id"],
            "dog__fish_pluto__nemo",
            cls.dog_fish_class["name"],
            str(cls.dog_class["id"]) + "," + str(cls.fish_class["id"]),
            str(cls.pluto_object["id"]) + "," + str(cls.nemo_object["id"]),
            cls.pluto_object["name"] + "," + cls.nemo_object["name"],
        )
        cls.nemo_pluto_rel = cls._relationship(
            5,
            cls.fish_dog_class["id"],
            "fish__dog_nemo__pluto",
            cls.fish_dog_class["name"],
            str(cls.fish_class["id"]) + "," + str(cls.dog_class["id"]),
            str(cls.nemo_object["id"]) + "," + str(cls.pluto_object["id"]),
            cls.nemo_object["name"] + "," + cls.pluto_object["name"],
        )
        cls.nemo_scooby_rel = cls._relationship(
            6,
            cls.fish_dog_class["id"],
            "fish__dog_nemo__scooby",
            cls.fish_dog_class["name"],
            str(cls.fish_class["id"]) + "," + str(cls.dog_class["id"]),
            str(cls.nemo_object["id"]) + "," + str(cls.scooby_object["id"]),
            cls.nemo_object["name"] + "," + cls.scooby_object["name"],
        )
        cls.water_parameter = cls._object_parameter_definition(1, cls.fish_class["id"], cls.fish_class["name"], "water")
        cls.breed_parameter = cls._object_parameter_definition(2, cls.dog_class["id"], cls.dog_class["name"], "breed")
        cls.relative_speed_parameter = cls._relationship_parameter_definition(
            3,
            cls.fish_dog_class["id"],
            cls.fish_dog_class["name"],
            cls.fish_dog_class["object_class_id_list"],
            cls.fish_dog_class["object_class_name_list"],
            "relative_speed",
        )
        cls.combined_mojo_parameter = cls._relationship_parameter_definition(
            4,
            cls.dog_fish_class["id"],
            cls.dog_fish_class["name"],
            cls.dog_fish_class["object_class_id_list"],
            cls.dog_fish_class["object_class_name_list"],
            "combined_mojo",
        )
        cls.nemo_water = cls._object_parameter_value(
            1,
            cls.water_parameter["object_class_id"],
            cls.water_parameter["object_class_name"],
            cls.nemo_object["id"],
            cls.nemo_object["name"],
            cls.water_parameter["id"],
            cls.water_parameter["parameter_name"],
            '"salt"',
        )
        cls.pluto_breed = cls._object_parameter_value(
            2,
            cls.breed_parameter["object_class_id"],
            cls.breed_parameter["object_class_name"],
            cls.pluto_object["id"],
            cls.pluto_object["name"],
            cls.breed_parameter["id"],
            cls.breed_parameter["parameter_name"],
            '"bloodhound"',
        )
        cls.scooby_breed = cls._object_parameter_value(
            3,
            cls.breed_parameter["object_class_id"],
            cls.breed_parameter["object_class_name"],
            cls.scooby_object["id"],
            cls.scooby_object["name"],
            cls.breed_parameter["id"],
            cls.breed_parameter["parameter_name"],
            '"great dane"',
        )
        cls.nemo_pluto_relative_speed = cls._relationship_parameter_value(
            4,
            cls.relative_speed_parameter["relationship_class_id"],
            cls.relative_speed_parameter["relationship_class_name"],
            cls.relative_speed_parameter["object_class_id_list"],
            cls.relative_speed_parameter["object_class_name_list"],
            cls.nemo_pluto_rel["id"],
            cls.nemo_pluto_rel["object_id_list"],
            cls.nemo_pluto_rel["object_name_list"],
            cls.relative_speed_parameter["id"],
            cls.relative_speed_parameter["parameter_name"],
            "-1",
        )
        cls.nemo_scooby_relative_speed = cls._relationship_parameter_value(
            5,
            cls.relative_speed_parameter["relationship_class_id"],
            cls.relative_speed_parameter["relationship_class_name"],
            cls.relative_speed_parameter["object_class_id_list"],
            cls.relative_speed_parameter["object_class_name_list"],
            cls.nemo_scooby_rel["id"],
            cls.nemo_scooby_rel["object_id_list"],
            cls.nemo_scooby_rel["object_name_list"],
            cls.relative_speed_parameter["id"],
            cls.relative_speed_parameter["parameter_name"],
            "5",
        )
        cls.pluto_nemo_combined_mojo = cls._relationship_parameter_value(
            6,
            cls.combined_mojo_parameter["relationship_class_id"],
            cls.combined_mojo_parameter["relationship_class_name"],
            cls.combined_mojo_parameter["object_class_id_list"],
            cls.combined_mojo_parameter["object_class_name_list"],
            cls.pluto_nemo_rel["id"],
            cls.pluto_nemo_rel["object_id_list"],
            cls.pluto_nemo_rel["object_name_list"],
            cls.combined_mojo_parameter["id"],
            cls.combined_mojo_parameter["parameter_name"],
            "100",
        )

    def setUp(self):
        """Overridden method. Runs before each test. Makes instances of SpineDBEditor classes."""
        with mock.patch("spinetoolbox.spine_db_manager.DiffDatabaseMapping") as mock_DiffDBMapping, mock.patch(
            "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.restore_ui"
        ), mock.patch("spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.show"):
            mock_settings = mock.Mock()
            mock_settings.value.side_effect = lambda *args, **kwards: 0
            self.db_mngr = SpineDBManager(mock_settings, None)
            self.db_mngr.fetch_db_maps_for_listener = lambda *args: None

            def DiffDBMapping_side_effect(url, codename=None, upgrade=False, create=False):
                mock_db_map = mock.MagicMock()
                mock_db_map.db_url = url
                mock_db_map.codename = codename
                return mock_db_map

            mock_DiffDBMapping.side_effect = DiffDBMapping_side_effect
            self.spine_db_editor = SpineDBEditor(self.db_mngr, {"mock_url": "mock_db"})
            self.mock_db_map = self.spine_db_editor.first_db_map
            self.spine_db_editor.pivot_table_model = mock.MagicMock()

    def tearDown(self):
        """Overridden method. Runs after each test.
        Use this to free resources after a test if needed.
        """
        with mock.patch(
            "spinetoolbox.spine_db_editor.widgets.spine_db_editor.SpineDBEditor.save_window_state"
        ) as mock_save_w_s, mock.patch("spinetoolbox.spine_db_manager.QMessageBox"):
            self.spine_db_editor.close()
            mock_save_w_s.assert_called_once()
        self.spine_db_editor.db_mngr.stop_fetchers()
        QApplication.removePostedEvents(None)  # Clean up unfinished fetcher signals
        self.spine_db_editor.deleteLater()
        self.spine_db_editor = None

    def put_mock_object_classes_in_db_mngr(self):
        """Put fish and dog object classes in the db mngr."""
        object_classes = [self.fish_class, self.dog_class]
        self.db_mngr.object_classes_added.emit({self.mock_db_map: object_classes})

    def put_mock_objects_in_db_mngr(self):
        """Put nemo, pluto and scooby objects in the db mngr."""
        objects = [self.nemo_object, self.pluto_object, self.scooby_object]
        self.db_mngr.objects_added.emit({self.mock_db_map: objects})

    def put_mock_relationship_classes_in_db_mngr(self):
        """Put dog__fish and fish__dog relationship classes in the db mngr."""
        relationship_classes = [self.fish_dog_class, self.dog_fish_class]
        self.db_mngr.relationship_classes_added.emit({self.mock_db_map: relationship_classes})

    def put_mock_relationships_in_db_mngr(self):
        """Put pluto_nemo, nemo_pluto and nemo_scooby relationships in the db mngr."""
        relationships = [self.pluto_nemo_rel, self.nemo_pluto_rel, self.nemo_scooby_rel]
        self.db_mngr.relationships_added.emit({self.mock_db_map: relationships})

    def put_mock_object_parameter_definitions_in_db_mngr(self):
        """Put water and breed object parameter definitions in the db mngr."""
        parameter_definitions = [self.water_parameter, self.breed_parameter]
        with mock.patch.object(CompoundParameterModel, "_modify_data_in_filter_menus"):
            self.db_mngr.parameter_definitions_added.emit({self.mock_db_map: parameter_definitions})

    def put_mock_relationship_parameter_definitions_in_db_mngr(self):
        """Put relative speed and combined mojo relationship parameter definitions in the db mngr."""
        parameter_definitions = [self.relative_speed_parameter, self.combined_mojo_parameter]
        with mock.patch.object(CompoundParameterModel, "_modify_data_in_filter_menus"):
            self.db_mngr.parameter_definitions_added.emit({self.mock_db_map: parameter_definitions})

    def put_mock_object_parameter_values_in_db_mngr(self):
        """Put some object parameter values in the db mngr."""
        parameter_values = [self.nemo_water, self.pluto_breed, self.scooby_breed]
        with mock.patch.object(CompoundParameterModel, "_modify_data_in_filter_menus"):
            self.db_mngr.parameter_values_added.emit({self.mock_db_map: parameter_values})

    def put_mock_relationship_parameter_values_in_db_mngr(self):
        """Put some relationship parameter values in the db mngr."""
        parameter_values = [
            self.nemo_pluto_relative_speed,
            self.nemo_scooby_relative_speed,
            self.pluto_nemo_combined_mojo,
        ]
        with mock.patch.object(CompoundParameterModel, "_modify_data_in_filter_menus"):
            self.db_mngr.parameter_values_added.emit({self.mock_db_map: parameter_values})

    def put_mock_dataset_in_db_mngr(self):
        """Put mock dataset in the db mngr."""
        self.put_mock_object_classes_in_db_mngr()
        self.put_mock_objects_in_db_mngr()
        self.put_mock_relationship_classes_in_db_mngr()
        self.put_mock_relationships_in_db_mngr()
        self.put_mock_object_parameter_definitions_in_db_mngr()
        self.put_mock_relationship_parameter_definitions_in_db_mngr()
        self.put_mock_object_parameter_values_in_db_mngr()
        self.put_mock_relationship_parameter_values_in_db_mngr()
        self.fetch_object_tree_model()

    def fetch_object_tree_model(self):
        for item in self.spine_db_editor.object_tree_model.visit_all():
            if item.can_fetch_more():
                item.fetch_more()

    def test_set_object_parameter_definition_defaults(self):
        """Test that defaults are set in object parameter_definition models according the object tree selection."""
        self.spine_db_editor.init_models()
        self.put_mock_object_classes_in_db_mngr()
        self.fetch_object_tree_model()
        # Select fish item in object tree
        root_item = self.spine_db_editor.object_tree_model.root_item
        fish_item = root_item.child(0)
        fish_index = self.spine_db_editor.object_tree_model.index_from_item(fish_item)
        self.spine_db_editor.ui.treeView_object.setCurrentIndex(fish_index)
        self.spine_db_editor.ui.treeView_object.selectionModel().select(fish_index, QItemSelectionModel.Select)
        # Check default in object parameter_definition
        model = self.spine_db_editor.object_parameter_definition_model
        model.empty_model.fetchMore()
        h = model.header.index
        row_data = []
        for row in range(model.rowCount()):
            row_data.append(tuple(model.index(row, h(field)).data() for field in ("object_class_name", "database")))
        self.assertTrue(("fish", "mock_db") in row_data)

    @unittest.skip("TODO")
    def test_set_object_parameter_value_defaults(self):
        """Test that defaults are set in relationship parameter_definition
        models according the object tree selection.
        """
        self.fail()

    @unittest.skip("TODO")
    def test_set_relationship_parameter_definition_defaults(self):
        """Test that defaults are set in relationship parameter_definition
        models according the object tree selection.
        """
        self.fail()

    @unittest.skip("TODO")
    def test_set_relationship_parameter_value_defaults(self):
        """Test that defaults are set in relationship parameter_definition
        models according the object tree selection.
        """
        self.fail()
Example #14
0
class TestParameterValuePivotTableModel(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        if not QApplication.instance():
            QApplication()

    def setUp(self):
        app_settings = MagicMock()
        self._temp_dir = TemporaryDirectory()
        url = "sqlite:///" + os.path.join(self._temp_dir.name, "db.sqlite")
        db_map = DiffDatabaseMapping(url, create=True)
        import_object_classes(db_map, ("class1",))
        import_object_parameters(db_map, (("class1", "parameter1"), ("class1", "parameter2")))
        import_objects(db_map, (("class1", "object1"), ("class1", "object2")))
        import_object_parameter_values(
            db_map,
            (
                ("class1", "object1", "parameter1", 1.0),
                ("class1", "object2", "parameter1", 3.0),
                ("class1", "object1", "parameter2", 5.0),
                ("class1", "object2", "parameter2", 7.0),
            ),
        )
        db_map.commit_session("Add test data.")
        db_map.connection.close()
        with patch("spinetoolbox.spine_db_manager.SpineDBManager.thread", new_callable=PropertyMock) as mock_thread:
            mock_thread.return_value = QApplication.instance().thread()
            self._db_mngr = SpineDBManager(app_settings, None)
            with patch.object(SpineDBEditor, "restore_ui"):
                self._editor = SpineDBEditor(self._db_mngr, {url: db_map.codename})
        object_class_index = self._editor.object_tree_model.index(0, 0)
        self._editor.object_tree_model.fetchMore(object_class_index)
        index = self._editor.object_tree_model.index(0, 0, object_class_index)
        self._editor.reload_pivot_table(index)
        self._model = self._editor.pivot_table_model
        self._model.start_fetching()

    def tearDown(self):
        self._db_mngr.close_all_sessions()
        self._db_mngr.clean_up()
        self._temp_dir.cleanup()

    def test_x_flag(self):
        self.assertIsNone(self._model.plot_x_column)
        self._model.set_plot_x_column(1, True)
        self.assertEqual(self._model.plot_x_column, 1)
        self._model.set_plot_x_column(1, False)
        self.assertIsNone(self._model.plot_x_column)

    def test_header_name(self):
        self.assertEqual(self._model.rowCount(), 5)
        self.assertEqual(self._model.columnCount(), 4)
        self.assertEqual(self._model.header_name(self._model.index(2, 0)), 'object1')
        self.assertEqual(self._model.header_name(self._model.index(0, 1)), 'parameter1')
        self.assertEqual(self._model.header_name(self._model.index(3, 0)), 'object2')
        self.assertEqual(self._model.header_name(self._model.index(0, 2)), 'parameter2')

    def test_data(self):
        self.assertEqual(self._model.rowCount(), 5)
        self.assertEqual(self._model.columnCount(), 4)
        self.assertEqual(self._model.index(0, 0).data(), "parameter")
        self.assertEqual(self._model.index(1, 0).data(), "class1")
        self.assertEqual(self._model.index(2, 0).data(), "object1")
        self.assertEqual(self._model.index(3, 0).data(), "object2")
        self.assertEqual(self._model.index(4, 0).data(), None)
        self.assertEqual(self._model.index(0, 1).data(), "parameter1")
        self.assertEqual(self._model.index(1, 1).data(), None)
        self.assertEqual(self._model.index(2, 1).data(), str(1.0))
        self.assertEqual(self._model.index(3, 1).data(), str(3.0))
        self.assertEqual(self._model.index(4, 1).data(), None)
        self.assertEqual(self._model.index(0, 2).data(), "parameter2")
        self.assertEqual(self._model.index(1, 2).data(), None)
        self.assertEqual(self._model.index(2, 2).data(), str(5.0))
        self.assertEqual(self._model.index(3, 2).data(), str(7.0))
        self.assertEqual(self._model.index(4, 2).data(), None)
        self.assertEqual(self._model.index(0, 3).data(), None)
        self.assertEqual(self._model.index(1, 3).data(), None)
        self.assertEqual(self._model.index(2, 3).data(), None)
        self.assertEqual(self._model.index(3, 3).data(), None)
        self.assertEqual(self._model.index(4, 3).data(), None)

    def test_header_row_count(self):
        self.assertEqual(self._model.headerRowCount(), 2)
Example #15
0
class TestIndexExpansionPivotTableModel(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        if not QApplication.instance():
            QApplication()

    def setUp(self):
        app_settings = MagicMock()
        self._temp_dir = TemporaryDirectory()
        url = "sqlite:///" + os.path.join(self._temp_dir.name, "db.sqlite")
        db_map = DiffDatabaseMapping(url, create=True)
        import_object_classes(db_map, ("class1",))
        import_object_parameters(db_map, (("class1", "parameter1"), ("class1", "parameter2")))
        import_objects(db_map, (("class1", "object1"), ("class1", "object2")))
        import_object_parameter_values(
            db_map,
            (
                ("class1", "object1", "parameter1", Map(["A", "B"], [1.1, 2.1])),
                ("class1", "object2", "parameter1", Map(["C", "D"], [1.2, 2.2])),
                ("class1", "object1", "parameter2", Map(["C", "D"], [-1.1, -2.1])),
                ("class1", "object2", "parameter2", Map(["A", "B"], [-1.2, -2.2])),
            ),
        )
        db_map.commit_session("Add test data.")
        db_map.connection.close()
        with patch("spinetoolbox.spine_db_manager.SpineDBManager.thread", new_callable=PropertyMock) as mock_thread:
            mock_thread.return_value = QApplication.instance().thread()
            self._db_mngr = SpineDBManager(app_settings, None)
            with patch.object(SpineDBEditor, "restore_ui"):
                self._editor = SpineDBEditor(self._db_mngr, {url: db_map.codename})
        object_class_index = self._editor.object_tree_model.index(0, 0)
        self._editor.object_tree_model.fetchMore(object_class_index)
        index = self._editor.object_tree_model.index(0, 0, object_class_index)
        for action in self._editor.pivot_action_group.actions():
            if action.text() == self._editor._INDEX_EXPANSION:
                action.trigger()
                break
        self._editor.reload_pivot_table(index)
        self._model = self._editor.pivot_table_model
        self._model.start_fetching()

    def tearDown(self):
        self._db_mngr.close_all_sessions()
        self._db_mngr.clean_up()
        self._temp_dir.cleanup()

    def test_data(self):
        self.assertEqual(self._model.rowCount(), 11)
        self.assertEqual(self._model.columnCount(), 5)
        model_data = list()
        i = self._model.index
        for row in range(11):
            model_data.append(list(i(row, column).data() for column in range(5)))
        expected = [
            [None, "parameter", "parameter1", "parameter2", None],
            ["class1", "index", None, None, None],
            ["object1", "A", str(1.1), None, None],
            ["object1", "B", str(2.1), None, None],
            ["object2", "C", str(1.2), None, None],
            ["object2", "D", str(2.2), None, None],
            ["object1", "C", None, str(-1.1), None],
            ["object1", "D", None, str(-2.1), None],
            ["object2", "A", None, str(-1.2), None],
            ["object2", "B", None, str(-2.2), None],
            [None, None, None, None, None],
        ]
        self.assertEqual(model_data, expected)
Example #16
0
def _make_pivot_proxy_model():
    """Returns a prefilled PivotTableModel."""
    db_mngr = MagicMock()
    db_mngr.get_value.side_effect = lambda db_map, item_type, id_, role: from_database(
        id_)
    mock_db_map = MagicMock()
    mock_db_map.codename = "codename"
    db_mngr.undo_action.__getitem__.side_effect = lambda key: QAction()
    db_mngr.redo_action.__getitem__.side_effect = lambda key: QAction()
    with patch.object(SpineDBEditor,
                      "restore_ui"), patch.object(SpineDBEditor, "show"):
        spine_db_editor = SpineDBEditor(db_mngr, mock_db_map)
    spine_db_editor.create_header_widget = lambda *args, **kwargs: None
    simple_map = Map(["a", "b"], [-1.1, -2.2])
    nested_map = Map(
        ["a", "b"],
        [
            Map([DateTime("2020-11-13T11:00"),
                 DateTime("2020-11-13T12:00")], [-1.1, -2.2]),
            Map([DateTime("2020-11-13T11:00"),
                 DateTime("2020-11-13T12:00")], [-3.3, -4.4]),
        ],
    )
    nested_map_with_time_series = Map(
        ["a", "b"],
        [
            Map(
                [DateTime("2020-11-13T11:00"),
                 DateTime("2020-11-13T12:00")],
                [
                    TimeSeriesVariableResolution(
                        ["2020-11-13T11:00", "2020-11-13T12:00"], [-1.1, -2.2],
                        False, False),
                    TimeSeriesVariableResolution(
                        ["2020-11-13T12:00", "2020-11-13T13:00"], [-3.3, -4.4],
                        False, False),
                ],
            ),
            Map(
                [DateTime("2020-11-13T11:00"),
                 DateTime("2020-11-13T12:00")],
                [
                    TimeSeriesVariableResolution(
                        ["2020-11-13T11:00", "2020-11-13T12:00"], [-5.5, -6.6],
                        False, False),
                    TimeSeriesVariableResolution(
                        ["2020-11-13T12:00", "2020-11-13T13:00"], [-7.7, -8.8],
                        False, False),
                ],
            ),
        ],
    )
    data = {
        ('1', 'int_col', 'base_alternative'):
        '-3',
        ('2', 'int_col', 'base_alternative'):
        '-1',
        ('3', 'int_col', 'base_alternative'):
        '2',
        ('1', 'float_col', 'base_alternative'):
        '1.1',
        ('2', 'float_col', 'base_alternative'):
        '1.2',
        ('3', 'float_col', 'base_alternative'):
        '1.3',
        (
            '1',
            'time_series_col',
            'base_alternative',
        ):
        '{"type": "time_series", "data": {"2019-07-10T13:00": 2.3, "2019-07-10T13:20": 5.0}}',
        (
            '2',
            'time_series_col',
            'base_alternative',
        ):
        '{"type": "time_series", "index": {"start": "2019-07-10T13:00", "resolution": "20 minutes"}, "data": [3.3, 4.0]}',
        (
            '3',
            'time_series_col',
            'base_alternative',
        ):
        '{"type": "time_series", "data": {"2019-07-10T13:00": 4.3, "2019-07-10T13:20": 3.0}}',
        ("1", "map_col", "base_alternative"):
        to_database(simple_map),
        ("2", "map_col", "base_alternative"):
        to_database(nested_map),
        ("3", "map_col", "base_alternative"):
        to_database(nested_map_with_time_series),
    }
    data = {
        tuple((db, k) for k in key) + (db, ): (db, value)
        for key, value in data.items()
    }
    spine_db_editor.load_parameter_value_data = lambda: data
    spine_db_editor.pivot_table_model = model = ParameterValuePivotTableModel(
        spine_db_editor)
    with patch.object(
            SpineDBEditor, "current_object_class_ids",
            new_callable=PropertyMock) as mock_current_object_class_ids:
        mock_current_object_class_ids.return_value = {"object": {db: 1}}
        model.call_reset_model(pivot=(['object'], ['parameter', 'alternative'],
                                      ['database'], (db, )))
    model.start_fetching()
    spine_db_editor.pivot_table_model = model
    spine_db_editor.pivot_table_proxy.setSourceModel(model)
    return spine_db_editor.pivot_table_proxy