예제 #1
0
class TestDataStore(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 ToolboxUI class.
        """
        # # Set logging level to Error to silence "Logging level: All messages" print
        logging.disable(level=logging.ERROR)  # Disable logging
        self.toolbox = ToolboxUI()
        self.toolbox.create_project("UnitTest Project", "")
        logging.disable(level=logging.NOTSET)  # Enable logging

    def tearDown(self):
        """Overridden method. Runs after each test.
        Use this to free resources after a test if needed.
        """
        shutil.rmtree(self.toolbox.project().project_dir)
        try:
            os.remove(self.toolbox.project().path)
        except OSError:
            pass
        self.toolbox = None

    def test_create_new_spine_database(self):
        """Test that a new Spine database is created when clicking on Spine-icon tool button.
        """
        with mock.patch("data_store.QFileDialog") as mock_file_dialog:
            data_store = DataStore(self.toolbox, "DS", "", dict(), 0, 0)
            file_path = os.path.join(data_store.data_dir, "mock_db.sqlite")
            mock_file_dialog.getSaveFileName.return_value = [file_path]
            data_store.activate()
            self.toolbox.ui.toolButton_new_spine.click()
            self.assertTrue(os.path.isfile(file_path), "mock_db.sqlite file not found.")
            sqlite_file = self.toolbox.ui.lineEdit_SQLite_file.text()
            self.assertEqual(sqlite_file, file_path)
            database = self.toolbox.ui.lineEdit_database.text()
            basename = os.path.basename(file_path)
            self.assertEqual(database, basename)

    def test_load_reference(self):
        """Test that reference is loaded into selections on Data Store creation,
        and then shown in the ui when Data Store is activated.
        """
        # FIXME: For now it only tests sqlite references
        file_path = os.path.join(self.toolbox.project().project_dir, "mock_db.sqlite")
        if not os.path.exists(file_path):
            with open(file_path, 'w'): pass
        url = "sqlite:///" + file_path
        create_new_spine_database(url)
        reference = dict(database="foo", username="******", url=url)
        data_store = DataStore(self.toolbox, "DS", "", reference, 0, 0)
        data_store.activate()
        dialect = self.toolbox.ui.comboBox_dialect.currentText()
        database = self.toolbox.ui.lineEdit_database.text()
        username = self.toolbox.ui.lineEdit_username.text()
        self.assertEqual(dialect, 'sqlite')
        self.assertEqual(database, 'foo')
        self.assertEqual(username, 'bar')

    def test_save_and_restore_selections(self):
        """Test that selections are saved and restored when deactivating a Data Store and activating it again.
        """
        # FIXME: For now it only tests the mysql dialect
        data_store = DataStore(self.toolbox, "DS", "", dict(), 0, 0)
        data_store.activate()
        self.toolbox.ui.comboBox_dialect.setCurrentText('mysql')
        self.toolbox.ui.lineEdit_host.setText('localhost')
        self.toolbox.ui.lineEdit_port.setText('8080')
        self.toolbox.ui.lineEdit_database.setText('foo')
        self.toolbox.ui.lineEdit_username.setText('bar')
        data_store.deactivate()
        data_store.activate()
        dialect = self.toolbox.ui.comboBox_dialect.currentText()
        host = self.toolbox.ui.lineEdit_host.text()
        port = self.toolbox.ui.lineEdit_port.text()
        database = self.toolbox.ui.lineEdit_database.text()
        username = self.toolbox.ui.lineEdit_username.text()
        self.assertEqual(dialect, 'mysql')
        self.assertEqual(host, 'localhost')
        self.assertEqual(port, '8080')
        self.assertEqual(database, 'foo')
        self.assertEqual(username, 'bar')

    def test_copy_db_url_to_clipboard(self):
        """Test that the database url from current selections is copied to clipboard.
        """
        # First create a DS with an sqlite db reference
        file_path = os.path.join(self.toolbox.project().project_dir, "mock_db.sqlite")
        if not os.path.exists(file_path):
            with open(file_path, 'w'): pass
        url = "sqlite:///" + file_path
        create_new_spine_database(url)
        reference = dict(database="foo", username="******", url=url)
        data_store = DataStore(self.toolbox, "DS", "", reference, 0, 0)
        data_store.activate()
        self.toolbox.ui.toolButton_copy_db_url.click()
        clipboard_text = QApplication.clipboard().text()
        self.assertEqual(clipboard_text, url)
예제 #2
0
class TestToolboxUI(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 an instance of ToolboxUI class.
        We want the ToolboxUI to start with the default settings and without a project so
        we need to mock CONFIGURATION_FILE to prevent loading user's own configs from settings.conf.
        """
        with mock.patch("ui_main.CONFIGURATION_FILE") as mocked_file_path, \
                mock.patch("os.path.split") as mock_split, \
                mock.patch("configuration.create_dir") as mock_create_dir:
            # # Set logging level to Error to silence "Logging level: All messages" print
            logging.disable(level=logging.ERROR)  # Disable logging
            self.mw = ToolboxUI()
            logging.disable(level=logging.NOTSET)  # Enable logging

    def tearDown(self):
        """Overridden method. Runs after each test.
        Use this to free resources after a test if needed.
        """
        self.mw = None

    def test_init_project_item_model_without_project(self):
        """Test that a new project item model contains 4 items (Data Stores, Data Connections, Tools, and Views).
        Note: This test is done without a project open.
        """
        self.assertIsNone(
            self.mw.project())  # Make sure that there is no project open
        self.mw.init_project_item_model()
        self.check_init_project_item_model()

    def test_init_project_item_model_with_project(self):
        """Test that a new project item model contains 4 items (Data Stores, Data Connections, Tools, and Views).
        Note: This test is done with a project.
        Mock save_project() and create_dir() so that .proj file and project directory (and work directory) are
        not actually created. Looks like CONFIGURATION_FILE needs to be mocked as well because it only stays
        mocked for the duration of with statement.
        """
        with mock.patch("ui_main.ToolboxUI.save_project") as mock_save_project, \
                mock.patch("project.create_dir") as mock_create_dir, \
                mock.patch("ui_main.CONFIGURATION_FILE") as mock_confs:
            self.mw.create_project("Unit Test Project",
                                   "Project for unit tests.")
        self.assertIsInstance(
            self.mw.project(),
            SpineToolboxProject)  # Check that a project is open
        self.mw.init_project_item_model()
        self.check_init_project_item_model()

    def check_init_project_item_model(self):
        n = self.mw.project_item_model.rowCount()
        self.assertEqual(n, 4)
        # Check that there's only one column
        self.assertEqual(self.mw.project_item_model.columnCount(), 1)
        # Check that the items DisplayRoles are (In this particular order)
        item1 = self.mw.project_item_model.root().child(0)
        self.assertTrue(item1.name == "Data Stores",
                        "Item on row 0 is not 'Data Stores'")
        self.assertTrue(
            item1.parent().is_root,
            "Parent item of category item on row 0 should be root")
        item2 = self.mw.project_item_model.root().child(1)
        self.assertTrue(item2.name == "Data Connections",
                        "Item on row 1 is not 'Data Connections'")
        self.assertTrue(
            item2.parent().is_root,
            "Parent item of category item on row 1 should be root")
        item3 = self.mw.project_item_model.root().child(2)
        self.assertTrue(item3.name == "Tools", "Item on row 2 is not 'Tools'")
        self.assertTrue(
            item3.parent().is_root,
            "Parent item of category item on row 2 should be root")
        item4 = self.mw.project_item_model.root().child(3)
        self.assertTrue(item4.name == "Views", "Item on row 3 is not 'Views'")
        self.assertTrue(
            item4.parent().is_root,
            "Parent item of category item on row 3 should be root")

    def test_init_tool_template_model(self):
        """Check that tool template model has no items after init and that
        signals are connected just once.
        """
        self.assertIsNone(
            self.mw.project())  # Make sure that there is no project open
        self.mw.init_tool_template_model(list())
        self.assertEqual(self.mw.tool_template_model.rowCount(), 0)
        # Test that QLisView signals are connected only once.
        n_dbl_clicked_recv = self.mw.ui.listView_tool_templates.receivers(
            SIGNAL("doubleClicked(QModelIndex)"))
        self.assertEqual(n_dbl_clicked_recv, 1)
        n_context_menu_recv = self.mw.ui.listView_tool_templates.receivers(
            SIGNAL("customContextMenuRequested(QPoint)"))
        self.assertEqual(n_context_menu_recv, 1)
        # Initialize ToolTemplateModel again and see that the signals are connected only once
        self.mw.init_tool_template_model(list())
        # Test that QLisView signals are connected only once.
        n_dbl_clicked_recv = self.mw.ui.listView_tool_templates.receivers(
            SIGNAL("doubleClicked(QModelIndex)"))
        self.assertEqual(n_dbl_clicked_recv, 1)
        n_context_menu_recv = self.mw.ui.listView_tool_templates.receivers(
            SIGNAL("customContextMenuRequested(QPoint)"))
        self.assertEqual(n_context_menu_recv, 1)
        # Check that there's still no items in the model
        self.assertEqual(self.mw.tool_template_model.rowCount(), 0)

    def test_init_connection_model(self):
        """Test that ConnectionModel is empty when initialized."""
        self.assertIsNone(
            self.mw.project())  # Make sure that there is no project open
        self.mw.init_connection_model()
        rows = self.mw.connection_model.rowCount()
        columns = self.mw.connection_model.columnCount()
        self.assertEqual(rows, 0)
        self.assertEqual(columns, 0)

    def test_create_project(self):
        """Test that method makes a SpineToolboxProject instance.
        Skips creating a .proj file and creating directories.
        """
        with mock.patch("ui_main.ToolboxUI.save_project") as mock_save_project, \
                mock.patch("project.create_dir") as mock_create_dir, \
                mock.patch("ui_main.CONFIGURATION_FILE") as mock_confs:
            self.mw.create_project("Unit Test Project",
                                   "Project for unit tests.")
        self.assertIsInstance(
            self.mw.project(),
            SpineToolboxProject)  # Check that a project is open

    @unittest.skip("TODO")
    def test_remove_item(self):
        self.fail()

    @unittest.skip("TODO")
    def test_add_tool_template(self):
        self.fail()

    @unittest.skip("TODO")
    def test_remove_tool_template(self):
        self.fail()
class TestSpineToolboxProject(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Runs once before any tests in this class."""
        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):
        """Runs before each test. Makes an instance of ToolboxUI class.
        We want the ToolboxUI to start with the default settings and without a project so
        we need to mock CONFIGURATION_FILE to prevent loading user's own configs from settings.conf.
        """
        with mock.patch("ui_main.ToolboxUI.save_project") as mock_save_project, \
                mock.patch("project.create_dir") as mock_create_dir, \
                mock.patch("ui_main.CONFIGURATION_FILE") as mock_confs, \
                mock.patch("os.path.split") as mock_split, \
                mock.patch("configuration.create_dir") as mock_create_dir2:
            # logging.disable(level=logging.ERROR)  # Disable logging
            self.toolbox = ToolboxUI()
            self.toolbox.create_project("UnitTest Project", "")
            # logging.disable(level=logging.NOTSET)  # Enable logging

    def tearDown(self):
        """Runs after each test. Use this to free resources after a test if needed."""
        self.toolbox = None

    def test_add_data_store(self):
        """Test adding a Data Store to project."""
        name = self.add_ds()
        # Check that an item with the created name is found from project item model
        found_index = self.toolbox.project_item_model.find_item(name)
        found_item = self.toolbox.project_item_model.project_item(found_index)
        self.assertEqual(found_item.name, name)
        # Check that the created item is a Data Store
        self.assertEqual(found_item.item_type, "Data Store")
        # Check that connection model has been updated
        self.assertEqual(self.toolbox.connection_model.rowCount(), 1)
        self.assertEqual(self.toolbox.connection_model.columnCount(), 1)
        self.assertEqual(
            self.toolbox.connection_model.find_index_in_header(name), 0)

    def test_add_data_connection(self):
        """Test adding a Data Connection to project."""
        name = self.add_dc()
        # Check that an item with the created name is found from project item model
        found_index = self.toolbox.project_item_model.find_item(name)
        found_item = self.toolbox.project_item_model.project_item(found_index)
        self.assertEqual(found_item.name, name)
        # Check that the created item is a Data Connection
        self.assertEqual(found_item.item_type, "Data Connection")
        # Check that connection model has been updated
        self.assertEqual(self.toolbox.connection_model.rowCount(), 1)
        self.assertEqual(self.toolbox.connection_model.columnCount(), 1)
        self.assertEqual(
            self.toolbox.connection_model.find_index_in_header(name), 0)

    def test_add_tool(self):
        """Test adding a Tool to project."""
        name = self.add_tool()
        # Check that an item with the created name is found from project item model
        found_index = self.toolbox.project_item_model.find_item(name)
        found_item = self.toolbox.project_item_model.project_item(found_index)
        self.assertEqual(found_item.name, name)
        # Check that the created item is a Tool
        self.assertEqual(found_item.item_type, "Tool")
        # Check that connection model has been updated
        self.assertEqual(self.toolbox.connection_model.rowCount(), 1)
        self.assertEqual(self.toolbox.connection_model.columnCount(), 1)
        self.assertEqual(
            self.toolbox.connection_model.find_index_in_header(name), 0)

    def test_add_view(self):
        """Test adding a View to project."""
        name = self.add_view()
        # Check that an item with the created name is found from project item model
        found_index = self.toolbox.project_item_model.find_item(name)
        found_item = self.toolbox.project_item_model.project_item(found_index)
        self.assertEqual(found_item.name, name)
        # Check that the created item is a View
        self.assertEqual(found_item.item_type, "View")
        # Check that connection model has been updated
        self.assertEqual(self.toolbox.connection_model.rowCount(), 1)
        self.assertEqual(self.toolbox.connection_model.columnCount(), 1)
        self.assertEqual(
            self.toolbox.connection_model.find_index_in_header(name), 0)

    def test_add_four_items(self):
        """Test that adding multiple item works as expected. Four items are added in order DS->DC->Tool->View."""

        # Add items
        ds_name = self.add_ds()
        dc_name = self.add_dc()
        tool_name = self.add_tool()
        view_name = self.add_view()
        # Check that the items are found from project item model
        ds = self.toolbox.project_item_model.project_item(
            self.toolbox.project_item_model.find_item(ds_name))
        self.assertEqual(ds.name, ds_name)
        dc = self.toolbox.project_item_model.project_item(
            self.toolbox.project_item_model.find_item(dc_name))
        self.assertEqual(dc.name, dc_name)
        tool = self.toolbox.project_item_model.project_item(
            self.toolbox.project_item_model.find_item(tool_name))
        self.assertEqual(tool.name, tool_name)
        view = self.toolbox.project_item_model.project_item(
            self.toolbox.project_item_model.find_item(view_name))
        self.assertEqual(view.name, view_name)
        # Connection model should now have four rows and four columns
        self.assertEqual(self.toolbox.connection_model.rowCount(), 4)
        self.assertEqual(self.toolbox.connection_model.columnCount(), 4)
        # Check that the names match in connection model
        self.assertEqual(
            self.toolbox.connection_model.find_index_in_header(ds_name), 0)

        # # Add Data Connection item
        # dc_name = "DC"
        # with mock.patch("data_connection.create_dir") as mock_create_dir:
        #     dc_item = DataConnection(self.mw, dc_name, "", references=None, x=0, y=0)
        # retval = self.mw.add_item_to_model("Data Connections", dc_name, dc_item)
        # self.assertTrue(retval)
        # # Check that new item is found from project_item_model
        # found_item = self.mw.project_item_model.find_item(dc_name, Qt.MatchExactly | Qt.MatchRecursive)
        # self.assertEqual(found_item.data(Qt.UserRole), dc_item)
        # # Check that connection model has been updated
        # self.assertEqual(self.mw.connection_model.rowCount(), 2)
        # self.assertEqual(self.mw.connection_model.columnCount(), 2)
        # self.assertEqual(self.mw.connection_model.find_index_in_header(dc_name), 1)
        #
        # # Add Tool item
        # tool_name = "Tool"
        # with mock.patch("tool.create_dir") as mock_create_dir:
        #     tool_item = Tool(self.mw, tool_name, "", tool_template=None, x=0, y=0)
        # retval = self.mw.add_item_to_model("Tools", tool_name, tool_item)
        # self.assertTrue(retval)
        # # Check that new item is found from project_item_model
        # found_item = self.mw.project_item_model.find_item(tool_name, Qt.MatchExactly | Qt.MatchRecursive)
        # self.assertEqual(found_item.data(Qt.UserRole), tool_item)
        # # Check that connection model has been updated
        # self.assertEqual(self.mw.connection_model.rowCount(), 3)
        # self.assertEqual(self.mw.connection_model.columnCount(), 3)
        # self.assertEqual(self.mw.connection_model.find_index_in_header(tool_name), 2)
        #
        # # Add View item
        # view_name = "View"
        # view_item = View(self.mw, view_name, "", 0, 0)
        # retval = self.mw.add_item_to_model("Views", view_name, view_item)
        # self.assertTrue(retval)
        # # Check that new item is found from project_item_model
        # found_item = self.mw.project_item_model.find_item(view_name, Qt.MatchExactly | Qt.MatchRecursive)
        # self.assertEqual(found_item.data(Qt.UserRole), view_item)
        # # Check that connection model has been updated
        # self.assertEqual(self.mw.connection_model.rowCount(), 4)
        # self.assertEqual(self.mw.connection_model.columnCount(), 4)
        # self.assertEqual(self.mw.connection_model.find_index_in_header(view_name), 3)
        # # There should now be 4 items in the model
        # self.assertEqual(self.mw.project_item_model.n_items("all"), 4)

    # def test_add_item_to_model_in_random_order(self):
    #     """Add items to model in order DC->View->Tool->DS and check that it still works."""
    #     self.fail()
    #
    # def test_change_name(self):
    #     self.fail()
    #
    # def test_set_description(self):
    #     self.fail()
    #
    # def test_change_filename(self):
    #     self.fail()
    #
    # def test_change_work_dir(self):
    #     self.fail()
    #
    # def test_rename_project(self):
    #     self.fail()
    #
    # def test_save(self):
    #     self.fail()
    #
    # def test_load(self):
    #     self.fail()
    #
    # def test_load_tool_template_from_file(self):
    #     self.fail()
    #
    # def test_load_tool_template_from_dict(self):
    #     self.fail()
    #
    # def test_append_connection_model(self):
    #     self.fail()
    #
    # def test_set_item_selected(self):
    #     self.fail()

    def add_ds(self):
        """Helper method to add Data Store. Returns created items name."""
        with mock.patch("data_store.create_dir") as mock_create_dir:
            self.toolbox.project().add_data_store("DS", "", reference=None)
        return "DS"

    def add_dc(self):
        """Helper method to add Data Connection. Returns created items name."""
        with mock.patch("data_connection.create_dir") as mock_create_dir:
            self.toolbox.project().add_data_connection("DC",
                                                       "",
                                                       references=list())
        return "DC"

    def add_tool(self):
        """Helper method to add Tool. Returns created items name."""
        with mock.patch("tool.create_dir") as mock_create_dir:
            self.toolbox.project().add_tool("tool", "", tool_template=None)
        return "tool"

    def add_view(self):
        """Helper method to add View. Returns created items name."""
        with mock.patch("view.create_dir") as mock_create_dir:
            self.toolbox.project().add_view("view", "")
        return "view"