import os import unittest from gi.repository import Gtk from mock import patch from tests.utils import setup_test_env setup_test_env() from softwarecenter.ui.gtk3.widgets import spinner class SpinnerNotebookTestCase(unittest.TestCase): """The test case for the SpinnerNotebook.""" _fake_timeout_id = object() def setUp(self): # helpers to check the timeout's callbacks self._interval = None self._callback = None self.content = Gtk.Label.new('My test') self.content.show() self.addCleanup(self.content.hide) self.addCleanup(self.content.destroy) self.obj = spinner.SpinnerNotebook(self.content) self.addCleanup(self.obj.hide) self.addCleanup(self.obj.destroy) assert spinner.SOFTWARE_CENTER_DEBUG_TABS not in os.environ self.obj.show() def _fake_timeout_add(self, interval, callback): self._interval = interval self._callback = callback return self._fake_timeout_id def _fake_source_remove(self, event_id): if event_id is self._fake_timeout_id: self._fake_timeout_id = None return True def test_no_borders(self): """The notebook has no borders.""" self.assertFalse(self.obj.get_show_border()) def test_no_tabs(self): """The notebook has no visible tabs.""" self.assertFalse(self.obj.get_show_tabs()) def test_tabs_if_debug_set(self): """The notebook has visible tabs if debug is set.""" with patch.object(spinner, 'SOFTWARE_CENTER_DEBUG_TABS', True): self.obj = spinner.SpinnerNotebook(self.content) self.assertTrue(self.obj.get_show_tabs()) def test_has_two_pages(self): """The notebook has two pages.""" self.assertEqual(self.obj.get_n_pages(), 2) def test_has_content(self): """The notebook has the given content.""" self.assertEqual(self.obj.get_nth_page(self.obj.CONTENT_PAGE), self.content) def test_has_spinner(self): """The notebook has the spinner view.""" self.assertEqual(self.obj.get_nth_page(self.obj.SPINNER_PAGE), self.obj.spinner_view) self.assertTrue(self.obj.spinner_view.get_visible()) def test_show_content_by_default(self): """The content tab is shown by default.""" self.assertEqual(self.obj.get_current_page(), self.obj.CONTENT_PAGE) def test_show_spinner(self): """The spinner is shown only after the timeout occurs.""" assert self._interval is None assert self._callback is None with patch.object(spinner.GLib, 'timeout_add', self._fake_timeout_add): self.obj.show_spinner() # this must hold before the callback is fired self.assertEqual(self.obj.get_current_page(), self.obj.CONTENT_PAGE) self.assertFalse(self.obj.spinner_view.spinner.get_property('active')) self.assertFalse(self.obj.spinner_view.spinner.get_visible()) self.assertEqual(self._interval, 250) self.assertEqual(self._callback, self.obj._unmask_view_spinner) result = self._callback() # fire the timeout # this must hold after the callback is fired self.assertFalse(result, 'The timeout callback should return False.') self.assertTrue(self.obj.spinner_view.spinner.get_property('active')) self.assertTrue(self.obj.spinner_view.spinner.get_visible()) self.assertEqual(self.obj.get_current_page(), self.obj.SPINNER_PAGE) def test_show_spinner_twice(self): """The spinner is not hiden/shown if its already visible.""" with patch.object(self.obj.spinner_view, "stop_and_hide") as m: with patch.object(spinner.GLib, 'timeout_add', lambda t,f: f()): self.obj.show_spinner("meep") self.obj.show_spinner("baap") # ensure that it only called the hide once self.assertEqual(m.call_count, 1) # and that it updated the text self.assertEqual(self.obj.spinner_view.get_text(), "baap") def test_show_spinner_with_msg(self): """The spinner is shown with the given message.""" message = 'Something I want to show' with patch.object(spinner.GLib, 'timeout_add', lambda *a: None): self.obj.show_spinner(msg=message) self.assertEqual(self.obj.spinner_view.get_text(), message) def test_hide_spinner_before_timeout(self): """The spinner is hidden cancelling the timeout.""" with patch.object(spinner.GLib, 'timeout_add', self._fake_timeout_add): self.obj.show_spinner() with patch.object(spinner.GLib, 'source_remove', self._fake_source_remove): self.obj.hide_spinner() # hide_spinner should call source_remove with the proper event id, # which in turn will set the _fake_timeout_id to None self.assertTrue(self._fake_timeout_id is None, 'The timeout should be removed by calling GLib.source_remove') # the content page is shown self.assertEqual(self.obj.get_current_page(), self.obj.CONTENT_PAGE) # the spinner is stoppped and hidden self.assertFalse(self.obj.spinner_view.spinner.get_property('active')) self.assertFalse(self.obj.spinner_view.spinner.get_visible()) def test_hide_spinner_after_timeout(self): """The spinner is hidden without cancelling the timeout.""" with patch.object(spinner.GLib, 'timeout_add', self._fake_timeout_add): self.obj.show_spinner() self._callback() # fake the timeout being fired with patch.object(spinner.GLib, 'source_remove', self._fake_source_remove): self.obj.hide_spinner() self.assertTrue(self._fake_timeout_id is not None, 'GLib.source_remove should not be called if already fired.') # the content page is shown self.assertEqual(self.obj.get_current_page(), self.obj.CONTENT_PAGE) # the spinner is stoppped and hidden self.assertFalse(self.obj.spinner_view.spinner.get_property('active')) self.assertFalse(self.obj.spinner_view.spinner.get_visible()) def test_specify_spinner_size(self): # check small spinner case notebook = spinner.SpinnerNotebook(self.content, "test spinner label", spinner.SpinnerView.SMALL) self.assertEqual(notebook.spinner_view.spinner.get_size_request(), (24, 24)) # check large spinner case (default) notebook = spinner.SpinnerNotebook(self.content, "test spinner label") self.assertEqual(notebook.spinner_view.spinner.get_size_request(), (48, 48)) # check that specifying an invalid spinner_size value raises # an exception with self.assertRaises(ValueError): notebook = spinner.SpinnerNotebook(self.content, "test spinner label", 48) if __name__ == "__main__": unittest.main()