diff --git a/pyqso/auxiliary_dialogs.py b/pyqso/auxiliary_dialogs.py index 06e8bc0..bb0b73b 100644 --- a/pyqso/auxiliary_dialogs.py +++ b/pyqso/auxiliary_dialogs.py @@ -28,7 +28,7 @@ def error(parent, message): :arg str message: The message to display to the user. """ logging.error(message) - _handle_gtk_dialog(parent, Gtk.MessageType.ERROR, message, "Error") + handle_gtk_dialog(parent, Gtk.MessageType.ERROR, message, "Error") def info(parent, message): @@ -38,7 +38,7 @@ def info(parent, message): :arg str message: The message to display to the user. """ logging.debug(message) - _handle_gtk_dialog(parent, Gtk.MessageType.INFO, message, "Information") + handle_gtk_dialog(parent, Gtk.MessageType.INFO, message, "Information") def question(parent, message): @@ -49,10 +49,10 @@ def question(parent, message): :returns: The 'yes'/'no' response from the user. :rtype: Gtk.ResponseType """ - return _handle_gtk_dialog(parent, Gtk.MessageType.QUESTION, message, "Question") + return handle_gtk_dialog(parent, Gtk.MessageType.QUESTION, message, "Question") -def _handle_gtk_dialog(parent, msgtype, message, title): +def handle_gtk_dialog(parent, msgtype, message, title): """ Instantiate and present a dialog to the user. diff --git a/pyqso/logbook.py b/pyqso/logbook.py index 14408a4..ceda309 100644 --- a/pyqso/logbook.py +++ b/pyqso/logbook.py @@ -58,7 +58,11 @@ class Logbook: return def new(self, widget=None): - """ Create a new logbook, and open it. """ + """ Create a new logbook, and open it. + + :returns: True if the new logbook is successfully opened, and False otherwise. + :rtype: bool + """ # Get the new file's path from a dialog. dialog = Gtk.FileChooserDialog("Create a New SQLite Database File", @@ -82,13 +86,16 @@ class Logbook: # Clear the contents of the file, in case the file exists already. open(path, 'w').close() # Open the new logbook, ready for use. - self.open(path=path) - return + opened = self.open(path=path) + return opened - def open(self, widget=None, path=None): + def open(self, widget=None, path=None, render=True): """ Open a logbook, and render all the logs within it. :arg str path: An optional argument containing the database file location, if already known. If this is None, a file selection dialog will appear. + :arg bool render: An optional argument to specify whether or not the logs should be rendered in the logbook. By default this is True, but is sometimes set to False for unit testing purposes. + :returns: True if the logbook is successfully opened, and False otherwise. + :rtype: bool """ if(path is None): @@ -106,7 +113,7 @@ class Logbook: if(path is None): # If the Cancel button has been clicked, path will still be None logging.debug("No file path specified.") - return + return False connected = self.db_connect(path) if(connected): @@ -118,46 +125,52 @@ class Logbook: self.logs = self.get_logs() if(self.logs is None): error(parent=self.application.window, message="Could not open logbook. Something went wrong when trying to retrieve the logs. Perhaps the logbook file is encrypted, corrupted, or in the wrong format?") - return + return False else: logging.debug("All logs retrieved successfully.") - logging.debug("Rendering logs...") - # For rendering the logs. One treeview and one treeselection per Log. - self.treeview = [] - self.treeselection = [] - self.sorter = [] - self.filter = [] - self.summary = Summary(self.application) - self.blank = Blank(self.application) + if(render): + logging.debug("Rendering logs...") + # For rendering the logs. One treeview and one treeselection per Log. + self.treeview = [] + self.treeselection = [] + self.sorter = [] + self.filter = [] + self.summary = Summary(self.application) + self.blank = Blank(self.application) - # FIXME: This is an unfortunate work-around. If the area around the "+/New Log" button - # is clicked, PyQSO will change to an empty page. This signal is used to stop this from happening. - self.notebook.connect("switch-page", self.on_switch_page) + # FIXME: This is an unfortunate work-around. If the area around the "+/New Log" button + # is clicked, PyQSO will change to an empty page. This signal is used to stop this from happening. + self.notebook.connect("switch-page", self.on_switch_page) - for i in range(len(self.logs)): - self.render_log(i) - logging.debug("All logs rendered successfully.") + for i in range(len(self.logs)): + self.render_log(i) + logging.debug("All logs rendered successfully.") - self.summary.update() - self.application.toolbox.awards.count(self) + self.summary.update() + self.application.toolbox.awards.count(self) - context_id = self.application.statusbar.get_context_id("Status") - self.application.statusbar.push(context_id, "Logbook: %s" % self.path) - self.application.toolbar.set_logbook_button_sensitive(False) - self.application.menu.set_logbook_item_sensitive(False) - self.application.menu.set_log_items_sensitive(True) - self.application.toolbar.filter_source.set_sensitive(True) + context_id = self.application.statusbar.get_context_id("Status") + self.application.statusbar.push(context_id, "Logbook: %s" % self.path) + self.application.toolbar.set_logbook_button_sensitive(False) + self.application.menu.set_logbook_item_sensitive(False) + self.application.menu.set_log_items_sensitive(True) + self.application.toolbar.filter_source.set_sensitive(True) - self.notebook.show_all() + self.notebook.show_all() else: logging.debug("Not connected to a logbook. No logs were opened.") + return False - return + return True def close(self, widget=None): - """ Close the logbook that is currently open. """ + """ Close the logbook that is currently open. + + :returns: True if the logbook is successfully closed, and False otherwise. + :rtype: bool + """ disconnected = self.db_disconnect() if(disconnected): @@ -176,7 +189,9 @@ class Logbook: self.application.toolbar.filter_source.set_sensitive(False) else: logging.debug("Unable to disconnect from the database. No logs were closed.") - return + return False + + return True def db_connect(self, path): """ Create an SQL database connection to the Logbook's data source. diff --git a/tests/test_logbook.py b/tests/test_logbook.py index d22ac76..1cca54b 100644 --- a/tests/test_logbook.py +++ b/tests/test_logbook.py @@ -32,25 +32,36 @@ class TestLogbook(unittest.TestCase): def setUp(self): """ Set up the Logbook object and connection to the test database needed for the unit tests. """ + self.logbook = Logbook(application=mock.MagicMock()) + + # Open the test database file. path_to_test_database = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, "res/test.db") - success = self.logbook.db_connect(path_to_test_database) - assert(success) - self.logbook.logs = self.logbook.get_logs() - assert(self.logbook.logs is not None) + opened = self.logbook.open(path=path_to_test_database, render=False) + assert(opened) + assert(self.logbook.connection is not None) + # Check that the logs have been retrieved. - temp = [] - for log_name in ["test", "test2"]: - l = Log(self.logbook.connection, log_name) - l.populate() - temp.append(l) - assert(self.logbook.logs[0].name == temp[0].name) - assert(self.logbook.logs[1].name == temp[1].name) + assert(len(self.logbook.logs) == 2) + assert(self.logbook.logs[0].name == "test") + assert(self.logbook.logs[1].name == "test2") def tearDown(self): """ Disconnect from the test database. """ - success = self.logbook.db_disconnect() - assert(success) + self.logbook.notebook.get_n_pages.return_value = 0 + closed = self.logbook.close() + assert(closed) + + @mock.patch('pyqso.auxiliary_dialogs.handle_gtk_dialog') + def test_open_invalid_log(self, mock_handle_gtk_dialog): + """ Open an invalid database file and check that an error occurs. """ + path_to_invalid_database = "Logbook.test_setUp_invalid.txt" + f = open("Logbook.test_setUp_invalid.txt", 'w') + f.write("This is a plain text file. Trying to open this file in PyQSO should case an error, since it is not a valid database file.") + f.close() + opened = self.logbook.open(path=path_to_invalid_database, render=False) + assert(not opened) + assert(self.logbook.logs is None) def test_log_name_exists(self): """ Check that only the log called 'test' exists. """ diff --git a/tests/test_record_dialog.py b/tests/test_record_dialog.py index 162e5fe..ec9ffe7 100644 --- a/tests/test_record_dialog.py +++ b/tests/test_record_dialog.py @@ -57,7 +57,7 @@ class TestRecordDialog(unittest.TestCase): def test_convert_frequency(self): """ Check that a frequency can be successfully converted from one unit to another. """ frequency = "7.140" # In MHz - converted = self.record_dialog.convert_frequency(frequency, from_unit="MHz", to_unit="AHz") # Unknown to_unit. This should return the input unmodified. + converted = self.record_dialog.convert_frequency(frequency, from_unit="MHz", to_unit="AHz") # Unknown to_unit. This should return the input unmodified (and give an error message). assert(converted == frequency) converted = self.record_dialog.convert_frequency(frequency, from_unit="MHz", to_unit="kHz") # Convert from MHz to kHz. assert(float(converted) == 1e3*float(frequency))