import os import unittest from collections import defaultdict from functools import partial import xapian from mock import Mock from tests.utils import ( FakedCache, get_mock_options, setup_test_env, do_events_with_sleep, ) setup_test_env() from softwarecenter.db import DebFileApplication, DebFileOpenError from softwarecenter.enums import PkgStates, SearchSeparators from softwarecenter.ui.gtk3 import app from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook class ParsePackagesArgsTestCase(unittest.TestCase): """Test suite for the parse_packages_args helper.""" pkg_name = 'foo' def transform_for_test(self, items): """Transform a sequence into a comma separated string.""" return app.SEARCH_PREFIX + SearchSeparators.REGULAR.join(items) def do_check(self, apps, items=None): """Check that the available_pane was shown.""" if items is None: items = self.transform_for_test(apps) search_text, result_app = app.parse_packages_args(items) self.assertEqual(SearchSeparators.REGULAR.join(apps), search_text) self.assertIsNone(result_app) def test_empty(self): """Pass an empty argument, show the 'available' view.""" self.do_check(apps=()) def test_single_empty_item(self): """Pass a single empty item, show the 'available' view.""" self.do_check(apps=('',)) def test_single_item(self): """Pass a single item, show the 'available' view.""" self.do_check(apps=(self.pkg_name,)) def test_two_items(self): """Pass two items, show the 'available' view.""" self.do_check(apps=(self.pkg_name, 'bar')) def test_several_items(self): """Pass several items, show the 'available' view.""" self.do_check(apps=(self.pkg_name, 'firefox', 'software-center')) class ParsePackageArgsAsFileTestCase(unittest.TestCase): def test_item_is_a_file(self): """Pass an item that is an existing file.""" # pass a real deb here fname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "data", "test_debs", "gdebi-test1.deb") assert os.path.exists(fname) # test once as string and as list for items in ( fname, [fname] ): search_text, result_app = app.parse_packages_args(fname) self.assertIsInstance(result_app, DebFileApplication) def test_item_with_file_prefix_one_slash(self): """ Pass an existing filename with a file:/ prefix. """ # pass a real deb here orig_fname = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "data", "test_debs", "gdebi-test1.deb") assert os.path.exists(orig_fname) for prefix in [ "file:/", "file://", "file:///"]: fname = prefix + orig_fname # test once as string and as list for items in ( fname, [fname] ): search_text, result_app = app.parse_packages_args(fname) self.assertIsInstance(result_app, DebFileApplication) def test_item_is_invalid_file(self): """ Pass an invalid file item """ fname = __file__ assert os.path.exists(fname) self.assertRaises(DebFileOpenError, app.parse_packages_args, fname) class ParsePackagesWithAptPrefixTestCase(ParsePackagesArgsTestCase): installed = None def setUp(self): super(ParsePackagesWithAptPrefixTestCase, self).setUp() self.cache = FakedCache() self.db = app.StoreDatabase(cache=self.cache) assert self.pkg_name not in self.cache if self.installed is not None: mock_cache_entry = Mock() mock_cache_entry.website = None mock_cache_entry.license = None mock_cache_entry.installed_files = [] mock_cache_entry.candidate = Mock() mock_cache_entry.candidate.version = '1.0' mock_cache_entry.candidate.description = 'A nonsense app.' mock_cache_entry.candidate.origins = () mock_cache_entry.versions = (Mock(),) mock_cache_entry.versions[0].version = '0.99' mock_cache_entry.versions[0].origins = (Mock(),) mock_cache_entry.versions[0].origins[0].archive = 'test' mock_cache_entry.is_installed = self.installed if self.installed: mock_cache_entry.installed = Mock() mock_cache_entry.installed.version = '0.90' mock_cache_entry.installed.installed_size = 0 else: mock_cache_entry.installed = None self.cache[self.pkg_name] = mock_cache_entry self.addCleanup(self.cache.pop, self.pkg_name) def transform_for_test(self, items): """Do nothing.""" return items def check_package_availability(self, name): """Check whether the package 'name' is available.""" if name not in self.cache: state = PkgStates.NOT_FOUND elif self.cache[name].installed: state = PkgStates.INSTALLED else: state = PkgStates.UNINSTALLED return state def do_check(self, apps, items=None): """Check that the available_pane was shown.""" if items is None: items = self.transform_for_test(apps) search_text, result_app = app.parse_packages_args(items) if apps and len(apps) == 1 and apps[0] and not os.path.isfile(apps[0]): self.assertIsNotNone(result_app) app_details = result_app.get_details(self.db) self.assertEqual(apps[0], app_details.name) state = self.check_package_availability(app_details.name) self.assertEqual(state, app_details.pkg_state) else: self.assertIsNone(result_app) if apps and (len(apps) > 1 or os.path.isfile(apps[0])): self.assertEqual(SearchSeparators.PACKAGE.join(apps), search_text) else: self.assertEqual('', search_text) def test_item_with_prefix(self): """Pass a item with the item prefix.""" for prefix in ('apt:', 'apt://', 'apt:///'): for case in (self.pkg_name, app.PACKAGE_PREFIX + self.pkg_name): self.do_check(apps=(case,), items=(prefix + case,)) class ParsePackagesNotInstalledTestCase(ParsePackagesWithAptPrefixTestCase): """Test suite for parsing/searching/loading package lists.""" installed = False class ParsePackagesInstalledTestCase(ParsePackagesWithAptPrefixTestCase): """Test suite for parsing/searching/loading package lists.""" installed = True class ParsePackagesArgsStringTestCase(ParsePackagesWithAptPrefixTestCase): """Test suite for parsing/loading package lists from strings.""" def transform_for_test(self, items): """Transform a sequence into a comma separated string.""" return SearchSeparators.PACKAGE.join(items) class AppTestCase(unittest.TestCase): """Test suite for the app module.""" def setUp(self): super(AppTestCase, self).setUp() self.called = defaultdict(list) self.addCleanup(self.called.clear) orig = app.SoftwareCenterAppGtk3.START_DBUS self.addCleanup(setattr, app.SoftwareCenterAppGtk3, 'START_DBUS', orig) app.SoftwareCenterAppGtk3.START_DBUS = False orig = app.get_pkg_info self.addCleanup(setattr, app, 'get_pkg_info', orig) app.get_pkg_info = lambda: FakedCache() options = get_mock_options() self.app = app.SoftwareCenterAppGtk3(options) self.addCleanup(self.app.destroy) self.app.cache.open() # connect some signals of interest cid = self.app.installed_pane.connect('installed-pane-created', partial(self.track_calls, 'pane-created')) self.addCleanup(self.app.installed_pane.disconnect, cid) cid = self.app.available_pane.connect('available-pane-created', partial(self.track_calls, 'pane-created')) self.addCleanup(self.app.available_pane.disconnect, cid) def track_calls(self, name, *a, **kw): """Record the callback for 'name' using 'args' and 'kwargs'.""" self.called[name].append((a, kw)) class ShowPackagesTestCase(AppTestCase): """Test suite for parsing/searching/loading package lists.""" def do_check(self, packages, search_text): """Check that the available_pane was shown.""" self.app.show_available_packages(packages=packages) self.assertEqual(self.called, {'pane-created': [((self.app.available_pane,), {})]}) actual = self.app.available_pane.searchentry.get_text() self.assertEqual(search_text, actual, 'Expected search text %r (got %r instead) for packages %r.' % (search_text, actual, packages)) self.assertIsNone(self.app.available_pane.app_details_view.app_details) def test_show_available_packages_search_prefix(self): """Check that the available_pane was shown.""" self.do_check(packages='search:foo,bar baz', search_text='foo bar baz') def test_show_available_packages_apt_prefix(self): """Check that the available_pane was shown.""" for prefix in ('apt:', 'apt://', 'apt:///'): self.do_check(packages=prefix + 'foo,bar,baz', search_text='foo,bar,baz') class ShowPackagesOnePackageTestCase(AppTestCase): """Test suite for parsing/searching/loading package lists.""" pkg_name = 'foo' installed = None def setUp(self): super(ShowPackagesOnePackageTestCase, self).setUp() assert self.pkg_name not in self.app.cache if self.installed is not None: mock_cache_entry = Mock() mock_cache_entry.website = None mock_cache_entry.license = None mock_cache_entry.installed_files = [] mock_cache_entry.candidate = Mock() mock_cache_entry.candidate.version = '1.0' mock_cache_entry.candidate.description = 'A nonsense app.' mock_cache_entry.candidate.origins = () mock_cache_entry.versions = (Mock(),) mock_cache_entry.versions[0].version = '0.99' mock_cache_entry.versions[0].origins = (Mock(),) mock_cache_entry.versions[0].origins[0].archive = 'test' mock_cache_entry.is_installed = self.installed if self.installed: mock_cache_entry.installed = Mock() mock_cache_entry.installed.version = '0.90' mock_cache_entry.installed.installed_size = 0 else: mock_cache_entry.installed = None self.app.cache[self.pkg_name] = mock_cache_entry self.addCleanup(self.app.cache.pop, self.pkg_name) def check_package_availability(self, name): """Check whether the package 'name' is available.""" pane = self.app.available_pane if name not in self.app.cache: state = PkgStates.NOT_FOUND elif self.app.cache[name].installed: state = PkgStates.INSTALLED pane = self.app.installed_pane else: state = PkgStates.UNINSTALLED self.assertEqual(state, pane.app_details_view.app_details.pkg_state) return pane def test_show_available_packages(self): """Check that the available_pane was shown.""" self.app.show_available_packages(packages=self.pkg_name) expected_pane = self.check_package_availability(self.pkg_name) name = expected_pane.app_details_view.app_details.name self.assertEqual(self.pkg_name, name) self.assertEqual('', self.app.available_pane.searchentry.get_text()) self.assertEqual(self.called, {'pane-created': [((expected_pane,), {})]}) class ShowPackagesNotInstalledTestCase(ShowPackagesOnePackageTestCase): """Test suite for parsing/searching/loading package lists.""" installed = False class ShowPackagesInstalledTestCase(ShowPackagesOnePackageTestCase): """Test suite for parsing/searching/loading package lists.""" installed = True class MenuTestCase(AppTestCase): """ Test case for the menus """ def test_reinstall_previous_purchases_lp1011522(self): # pretend we have the available_for_me data (much quicker # than to do a real s-c-agent query for this) self.app.available_for_me_query = xapian.Query() self.app.on_menuitem_reinstall_purchases_activate(None) do_events_with_sleep() self.assertEqual( self.app.available_pane.spinner_notebook.get_current_page(), SpinnerNotebook.CONTENT_PAGE) if __name__ == "__main__": # avoid spawning recommender-agent, reviews, software-center-agent etc, # cuts ~5s or so os.environ["SOFTWARE_CENTER_DISABLE_SPAWN_HELPER"] = "1" unittest.main()