unity-scopes-shell-0.5.7+16.04.20160317/0000755000015600001650000000000012672635475017657 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/0000755000015600001650000000000012672635475020607 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/api/0000755000015600001650000000000012672635475021360 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/api/api.rst0000644000015600001650000000460112672630457022657 0ustar pbuserpbgroup00000000000000API === Main classes ------------ .. autoclass:: scope_harness.ScopeHarness :members: .. autoclass:: scope_harness.CustomRegistry :members: .. autoclass:: scope_harness.Parameters :members: .. autoclass:: scope_harness.MatchResult :undoc-members: :members: Search results matchers ----------------------- .. autoclass:: scope_harness.Category :undoc-members: :members: .. autoclass:: scope_harness.CategoryListMatcher :members: .. autoclass:: scope_harness.CategoryListMatcherMode :members: .. autoclass:: scope_harness.CategoryMatcher :undoc-members: :members: .. autoclass:: scope_harness.CategoryMatcherMode :members: .. autoclass:: scope_harness.Result :undoc-members: :members: :special-members: .. autoclass:: scope_harness.ResultMatcher :members: .. autoclass:: scope_harness.ResultsView :undoc-members: :members: .. autoclass:: scope_harness.SearchStatus :undoc-members: :members: .. autoclass:: scope_harness.ScopeUri :undoc-members: :members: Department matchers ------------------- .. autoclass:: scope_harness.ChildDepartment :members: .. autoclass:: scope_harness.ChildDepartmentMatcher :undoc-members: :members: .. autoclass:: scope_harness.Department :undoc-members: :members: .. autoclass:: scope_harness.DepartmentMatcher :members: .. autoclass:: scope_harness.DepartmentMatcherMode :members: Preview matchers ---------------- .. autoclass:: scope_harness.PreviewColumnMatcher :members: .. autoclass:: scope_harness.PreviewMatcher :members: .. autoclass:: scope_harness.PreviewView :undoc-members: :members: .. autoclass:: scope_harness.PreviewWidget :undoc-members: :members: .. autoclass:: scope_harness.PreviewWidgetList :undoc-members: :members: .. autoclass:: scope_harness.PreviewWidgetMatcher :members: Settings matchers ----------------- .. autoclass:: scope_harness.SettingsMatcher :members: .. autoclass:: scope_harness.SettingsMatcherMode :members: .. autoclass:: scope_harness.SettingsOption :members: .. autoclass:: scope_harness.SettingsOptionMatcher :undoc-members: :members: .. autoclass:: scope_harness.SettingsOptionType :members: .. autoclass:: scope_harness.SettingsView :undoc-members: :members: Testing module -------------- .. automodule:: scope_harness.testing :members: unity-scopes-shell-0.5.7+16.04.20160317/docs/_static/0000755000015600001650000000000012672635475022235 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/conf.py0000644000015600001650000002005312672630457022101 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Scope Harness documentation build configuration file, created by # sphinx-quickstart on Thu May 21 14:08:23 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Scope Harness' copyright = '2015, Canonical Ltd' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. release = '1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'ScopeHarnessdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'ScopeHarness.tex', 'Scope Harness Documentation', 'Canonical Ltd.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'scopeharness', 'Scope Harness Documentation', ['Canonical Ltd'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'ScopeHarness', 'Scope Harness Documentation', 'Canonical Ltd.', 'ScopeHarness', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False unity-scopes-shell-0.5.7+16.04.20160317/docs/index.rst0000644000015600001650000000071312672630457022444 0ustar pbuserpbgroup00000000000000.. Scope Harness documentation master file, created by sphinx-quickstart on Thu May 21 14:08:23 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to Scope Harness's documentation! ========================================= Contents: .. toctree:: tutorial/tutorial api/api Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` unity-scopes-shell-0.5.7+16.04.20160317/docs/_templates/0000755000015600001650000000000012672635475022744 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/tutorial/0000755000015600001650000000000012672635475022452 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/docs/tutorial/tutorial.rst0000644000015600001650000004754312672630457025057 0ustar pbuserpbgroup00000000000000Writing scope harness tests with Python ####################################### What is scope-harness ===================== Scope-harness is a high-level testing framework for scopes that offers high-level abstractions to interact with scopes and simulate user interactions in order to verify data (categories, results, departments etc.) returned by the scope. It can be used to implement tests executed as a part of the build process of a scope. Scope-harness is available via C++ API and also offers bindings for Python 3. Both C++ and Python APIs offer same functionality. This documentation covers Python API only. About the Python testing framework used ======================================= Scope harness for Python is build upon the standard unittest framework (by inheriting from :class:`~scope_harness.testing.ScopeHarnessTestCase`, based on unittest.TestCase), but there no obligation to use it - the only functionality that ScopeHarnessTestCase provides is a helper assertMatchResult method, that can easily be replaced with a custom implementation. Here is the implementation of assertMatchResult for your reference. .. code-block:: python from unittest import TestCase from scope_harness import MatchResult class ScopeHarnessTestCase(TestCase): """ A class whose instances are single test cases. This class extends unittest.TestCase with helper methods relevant for testing of Unity scopes. """ def assertMatchResult(self, match_result): """ Assert for MatchResult object that fails if match wasn't successful and prints conditions which were not met by the matcher. """ self.assertIsInstance(match_result, MatchResult, msg='match_result must be an instance of MatchResult') self.assertTrue(match_result.success, msg=match_result.concat_failures) Getting started =============== The main "entry point" for every scope harness test cases is an instance of :class:`~ScopeHarness` object. This object encapsulates various aspects of configuration of scopes runtime, including an instance of scoperegistry - the central process which maintains the list of known scopes, separate from the scoperegistry instance and scopes normally installed on your system. When creating this object via one of its factory methods, you have to decide whether you want to run your tests against scoperegistry and scopes already installed on the system (see :meth:`~scope_harness.ScopeHarness.new_from_system`), scopesregistry executed against an existing configuration file (see :meth:`~scope_harness.ScopeHarness.new_from_pre_existing_config`) or a custom scope registry instance which only knows about scopes provided by your test (:meth:`~scope_harness.ScopeHarness.new_from_scope_list`). The latter is the most common use case. Consider the following example of test setUpClass method which assumes two "dummy" scopes have been installed into your test directory, and TEST_DATA_DIR points to it. .. code-block:: python from scope_harness import * from scope_harness.testing import ScopeHarnessTestCase import unittest class MyTest(ScopeHarnessTestCase): @classmethod def setUpClass(cls): cls.harness = ScopeHarness.new_from_scope_list( Parameters([ TEST_DATA_DIR + "/myscope1/myscope1.ini", TEST_DATA_DIR + "/myscope2/myscope2.ini" ]) ) Once ScopeHarness instance has been created, it provides the results_view property (a :class:`~scope_harness.ResultsView` instance) which corresponds to a scope page in the unity8 dash; you can set curently active scope, its current search query, change active department, inspect the returned categories and their results etc. Consider the following simple test: .. code-block:: python :linenos: class MyTest(ScopeHarnessTestCase): @classmethod def setUpClass(cls): cls.harness = ScopeHarness.new_from_scope_list(Parameters([ TEST_DATA_DIR + "/myscope1/myscope1.ini" ])) cls.view = cls.harness.results_view def test_basic_result(self): self.view.active_scope = 'myscope1' self.view.search_query = '' self.assertMatchResult( CategoryListMatcher() .has_at_least(2) .mode(CategoryListMatcherMode.BY_ID) .category( CategoryMatcher('mycategory1') .has_at_least(5) .mode(CategoryMatcherMode.BY_URI) .result( ResultMatcher("myuri") .properties({'title': 'mytitle', 'art':'myart'}) .dnd_uri("test:dnd_uri") ) ).match(self.view.categories) ) Here is line-by-line explanation of the checks performed by test_basic_failures test case: * 4-6 - create main :class:`~scope_harness.ScopeHarness` scope harness object to interact with scope(s). * 7 - store a reference to :class:`~scope_harness.ResultsView` object in the test case instance to reduce typing later. * 10 - Make 'myscope1' the active scope. * 11 - set search query value (executes a background search query). * 12-25 - verify the returned result(s) match expectations: * check that there are at least 2 categories in the view (lines 13-14); * pick a specific category by its ID (15-17) and check that it has at least 5 results (line 18); * enable picking results by uri in the :class:`~scope_harness.CategoryMatcher` (line 19) and verify there is a result with uri of "myuri" and given "title", "art" and "dnd_uri" properties (lines 20-23). Note the following key features of scope harness shown in the above test case: * there is no explicit "waiting" needed for state changes while asynchronous calls (such as setting a new search query) are dispatched; this is all built-in in the scope harness and abstracted away from the developer. This makes tests more robust and eliminates the "noise", making test code easier to read. * while ResultsView and other objects representing scope view and scope state have getters that can be used to examine and test for expected values, the recommended way of implementing the checks is via the family of "matcher" objects, such as CategoryListMatcher, CategoryMatcher and ResultMatcher. These matchers provide readable and concise way of expressing test scenarios, which resemble natural language and are more easy to understand than just a series of usual test case assertions. * also, the "match" methods of matchers produce a MatchResult instance object which provides a cumulative overview of all encountered errors, along with clear descriptions about the failing assertion, which is very convinient when used in conjunction with assertMatchResult helper method. More on category and results matching modes =========================================== When testing whether the list of categories returned by your scope matches expectations, you may verify the following characteristics of the list of categories via :class:`~scope_harness.CategoryListMatcher` and :class:`~scope_harness.CategoryMatcher`: * whether the list contains at least N categories, or exactly N categories: use :meth:`~scope_harness.CategoryListMatcher.has_at_least` or :meth:`~scope_harness.CategoryListMatcher.has_exactly`, respectively. * whether the list contains specific categories (some or all of them, and in the expected order): * to only verify if the list of categories contains specific categories (regardless of their position on the list), set the matching :meth:`~scope_harness.CategoryListMatcher.mode` to ``CategoryListMatcherMode.BY_ID`` and then pass expected categories via :class:`~scope_harness.CategoryMatcher` objects to :meth:`~scope_harness.CategoryListMatcher.category`. * to verify if the list starts with specific categories in the expected order (but possibly has more categories which you don't care about), set the matching :meth:`~scope_harness.CategoryListMatcher.mode` to ``CategoryListMatcherMode.STARTS_WITH`` and then pass expected categories as explained above. * to verify if the list contains all the expected categories and in the specific order set the matching :meth:`~scope_harness.CategoryListMatcherMode.mode` to ``CategoryListMatcherMode.ALL`` and then pass expected categories as explained above. In fact ``CategoryListMatcherMode.ALL`` is the default mode if you define any categories via :class:`~scope_harness.CategoryMatcher`, so setting the mode may as well by skipped. When testing results withing a categories specified via :class:`~scope_harness.CategoryMatcher`, the following checks can be made: * whether the category has at least N results: use :meth:`~scope_harness.CategoryMatcher.has_at_least`. * whether the category contains specific results (some or all of them, in the specific order or disregarding the order): * to verify if the category contains specific results regardless of their position, set the matching :meth:`~scope_harness.CategoryMatcherMode` to ``CategoryMatcherMode.BY_URI`` and pass expected results via :class:`~scope_harness.ResultMatcher` objects to :meth:`~scope_harness.CategoryMatcher.result`. * to verify if the specific results appear first in the category, but the category possibly has more results which you don't care about, set the matching :meth:`~scope_harness.CategoryMatcherMode` to ``CategoryMatcherMode.STARTS_WITH`` and pass expected results as explained earlier. * to verify if the category contains all the expected results in the given order, set the matching :meth:`~scope_harness.CategoryMatcherMode` to ``CategoryMatcherMode.ALL`` and pass all results as explained above. This is the default matching mode if any :class:`~scope_harness.ResultMatcher` matchers are set for a category, so setting the mode can be omitted. Here is an example of test case which checks if there are at least five categories returned, and then checks four of them by ID (the order of the categories is not verified). For the four expected categories the test verifies that they have at least one result each, and for the categories ``top-apps`` and ``our-favorite-games`` specific results are tested: * the ``top-apps`` category needs to have a at least one result, and the first result of that category is matched against the provided :class:`~scope_harness.ResultMatcher`. * the ``our-favorite-games`` category needs to have at least one result, and the result specified by the the provided :class:`~scope_harness.ResultMatcher` needs to appear somewhere in that category, but it doesn't need to be the first one thanks to ``CategoryMatcherMode.BY_URI``. .. code-block:: python def test_results(self): self.view.search_query = '' self.assertMatchResult( CategoryListMatcher() .has_at_least(5) .mode(CategoryListMatcherMode.BY_ID) .category(CategoryMatcher("app-of-the-week") .has_at_least(1) ) .category(CategoryMatcher("top-apps") .has_at_least(1) .mode(CategoryMatcherMode.STARTS_WITH) .result(ResultMatcher("https://search.apps.ubuntu.com/api/v1/package/com.ubuntu.developer.bobo1993324.udropcabin") .title('uDropCabin') .subtitle('Zhang Boren') )) .category(CategoryMatcher("our-favorite-games") .has_at_least(1) .mode(CategoryMatcherMode.BY_URI) .result(ResultMatcher("https://search.apps.ubuntu.com/api/v1/package/com.ubuntu.developer.andrew-hayzen.volleyball2d") \ )) .category(CategoryMatcher("travel-apps") .has_at_least(1)) .match(self.view.categories)) Testing departments =================== Departments can be "browsed" by calling :meth:`~scope_harness.ResultsView.browse_department` method; changing the department invokes a new search and the method returns the new list of departments. The list of departments can be tested using :class:`~scope_harness.DepartmentMatcher` and :class:`~scope_harness.ChildDepartmentMatcher` matchers. The ``DepartmentMatcher`` support three modes of matching (``DepartmentMatcherMode.ALL``, ``DepartmentMatcherMode.STARTS_WITH`` and ``DepartmentMatcherMode.BY_ID``) which have the same semantics as with ``CategoryMatcher`` or ``CategoryListMatcher`` described above. Here is an example of two departments tests: the first test case checks the starting list of departments (the surfacing mode), the second case simulates browsing of ``games`` sub-department, verifies it has no further sub-departments and also verifies the returned categories. Note: the empty department ID corresponds to the root department. .. code-block:: python def test_surfacing_departments(self): self.view.search_query = '' departments = self.view.browse_department('') self.assertMatchResult( DepartmentMatcher() .mode(DepartmentMatcherMode.STARTS_WITH) .id('') .label('All') .all_label('') .parent_id('') .parent_label('') .is_root(True) .is_hidden(False) .child(ChildDepartmentMatcher('business')) .child(ChildDepartmentMatcher('communication')) .child(ChildDepartmentMatcher('education')) .child(ChildDepartmentMatcher('entertainment')) .child(ChildDepartmentMatcher('finance')) .child(ChildDepartmentMatcher('games')) .child(ChildDepartmentMatcher('graphics')) .child(ChildDepartmentMatcher('accessories')) .child(ChildDepartmentMatcher('weather')) .match(departments)) def test_department_browsing(self): self.view.search_query = '' departments = self.view.browse_department('games') self.assertMatchResult(DepartmentMatcher() .has_exactly(0) .mode(DepartmentMatcherMode.STARTS_WITH) .label('Games') .all_label('') .parent_id('') .parent_label('All') .is_root(False) .is_hidden(False) .match(departments)) self.assertMatchResult(CategoryListMatcher() .has_exactly(3) .mode(CategoryListMatcherMode.BY_ID) .category(CategoryMatcher("top-games") .has_at_least(1) ) .category(CategoryMatcher("all-scopes") .has_at_least(1) ) .category(CategoryMatcher("all-apps") .has_at_least(1) ) .match(self.view.categories)) Testing previews ================ Previews can be invoked by calling :meth:`~scope_harness.Result.tap` method of the result. Note that ``tapping`` the result will - in cases where result's ``uri`` is a canned scope query (i.e. ``scope://`` uri) - execute a new search and return a :class:`~scope_harness.ResultsView` instance; in other cases a :class:`~scope_harness.PreviewView` will be returned. This conditions are verified by checks in lines 5 and 37. Below is an example of test cases covering preview widgets. The ``test_preview_layouts`` test case verifies different column layouts within the preview. The second test case simulates activation of preview action by calling :meth:`~scope_harness.PreviewWidget.trigger` (line 47) and verifies the same preview is returned in response. .. code-block:: python :linenos: def test_preview_layouts(self): self.view.search_query = '' pview = self.view.category(0).result(0).tap() self.assertIsInstance(pview, PreviewView) self.assertMatchResult(PreviewColumnMatcher().column( PreviewMatcher() .widget(PreviewWidgetMatcher("img")) .widget(PreviewWidgetMatcher("hdr")) .widget(PreviewWidgetMatcher("desc")) .widget(PreviewWidgetMatcher("actions")) ).match(pview.widgets)) pview.column_count = 2 self.assertMatchResult(PreviewColumnMatcher() .column(PreviewMatcher() .widget(PreviewWidgetMatcher("img"))) .column(PreviewMatcher() .widget(PreviewWidgetMatcher("hdr")) .widget(PreviewWidgetMatcher("desc")) .widget(PreviewWidgetMatcher("actions")) ).match(pview.widgets)) pview.column_count = 1 self.assertMatchResult(PreviewColumnMatcher() .column(PreviewMatcher() .widget(PreviewWidgetMatcher("img")) .widget(PreviewWidgetMatcher("hdr")) .widget(PreviewWidgetMatcher("desc")) .widget(PreviewWidgetMatcher("actions")) ).match(pview.widgets)) def test_preview_action(self): self.view.search_query = '' pview = self.view.category(0).result(0).tap() self.assertIsInstance(pview, PreviewView) self.assertMatchResult(PreviewColumnMatcher() .column(PreviewMatcher() .widget(PreviewWidgetMatcher("img")) .widget(PreviewWidgetMatcher("hdr")) .widget(PreviewWidgetMatcher("desc")) .widget(PreviewWidgetMatcher("actions")) ).match(pview.widgets)) next_view = pview.widgets_in_first_column["actions"].trigger("hide", None) self.assertEqual(pview, next_view) Using scope settings ==================== Settings exported by scopes can be accessed via :meth:`~scope_harness.ResultsView.settings` property and tested using :class:`~scope_harness.SettingsMatcher`. The :class:`~scope_harness.SettingsView` object returned by the above method :meth:`~scope_harness.SettingsView.set` method that can be used to modify settings (simulate user choices). Note that ``set`` method is loosely-typed (the new value is an object / variant), that means the correct data type needs to be passed to it, depending on the type of setting to modify: * for a setting of ``number`` type, pass an integer or float number. * for a setting of ``string`` type, pass a string value. * for a setting of ``list`` type, pass the string value corresponding to one of the supported choices. * for a setting of ``boolean`` type, pass True / False literals. Changing a setting value refreshes search results. Here is an example of a test case which modifies a setting value (this test should of course also check the new results after settings change; omitted here). .. code-block:: python def test_settings_change(self): self.view.active_scope = 'mock-scope' settings = self.view.settings settings.set("location", "Barcelona") self.assertMatchResult( SettingsMatcher() .mode(SettingsMatcherMode.BY_ID) .option( SettingsOptionMatcher("location") .value("Barcelona") ) .match(settings) ) unity-scopes-shell-0.5.7+16.04.20160317/docs/CMakeLists.txt0000644000015600001650000000146312672630457023346 0ustar pbuserpbgroup00000000000000find_program(SPHINX_EXEC NAMES sphinx-build DOC "Sphinx documentation generator") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXEC ) add_custom_target(scope_harness_html_docs ALL PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/../src/python ${SPHINX_EXEC} -E -b html "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/html") add_custom_target(scope_harness_json_docs ALL PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/../src/python ${SPHINX_EXEC} -E -b json "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/json") install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html ${CMAKE_CURRENT_BINARY_DIR}/json DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/python3-scope-harness/) unity-scopes-shell-0.5.7+16.04.20160317/cmake/0000755000015600001650000000000012672635475020737 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/0000755000015600001650000000000012672635475022407 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/EnableCoverageReport.cmake0000644000015600001650000001661112672630457027447 0ustar pbuserpbgroup00000000000000# - Creates a special coverage build type and target on GCC. # # Defines a function ENABLE_COVERAGE_REPORT which generates the coverage target # for selected targets. Optional arguments to this function are used to filter # unwanted results using globbing expressions. Moreover targets with tests for # the source code can be specified to trigger regenerating the report if the # test has changed # # ENABLE_COVERAGE_REPORT(TARGETS target... [FILTER filter...] [TESTS test targets...]) # # To generate a coverage report first build the project with # CMAKE_BUILD_TYPE=coverage, then call make test and afterwards make coverage. # # The coverage report is based on gcov. Depending on the availability of lcov # a HTML report will be generated and/or an XML report of gcovr is found. # The generated coverage target executes all found solutions. Special targets # exist to create e.g. only the xml report: coverage-xml. # # Copyright (C) 2010 by Johannes Wienke # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software Foundation; # either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(ParseArguments) FIND_PACKAGE(Lcov) FIND_PACKAGE(gcovr) FUNCTION(ENABLE_COVERAGE_REPORT) # argument parsing PARSE_ARGUMENTS(ARG "FILTER;TARGETS;TESTS" "" ${ARGN}) SET(COVERAGE_RAW_FILE "${CMAKE_BINARY_DIR}/coverage.raw.info") SET(COVERAGE_FILTERED_FILE "${CMAKE_BINARY_DIR}/coverage.info") SET(COVERAGE_REPORT_DIR "${CMAKE_BINARY_DIR}/coveragereport") SET(COVERAGE_XML_FILE "${CMAKE_BINARY_DIR}/coverage.xml") SET(COVERAGE_XML_COMMAND_FILE "${CMAKE_BINARY_DIR}/coverage-xml.cmake") # decide if there is any tool to create coverage data SET(TOOL_FOUND FALSE) IF(LCOV_FOUND OR GCOVR_FOUND) SET(TOOL_FOUND TRUE) ENDIF() IF(NOT TOOL_FOUND) MESSAGE(STATUS "Cannot enable coverage targets because neither lcov nor gcovr are found.") ENDIF() STRING(TOLOWER "${CMAKE_BUILD_TYPE}" COVERAGE_BUILD_TYPE) IF(CMAKE_COMPILER_IS_GNUCXX AND TOOL_FOUND AND "${COVERAGE_BUILD_TYPE}" MATCHES "coverage") MESSAGE(STATUS "Coverage support enabled for targets: ${ARG_TARGETS}") # create coverage build type SET(CMAKE_CXX_FLAGS_COVERAGE ${CMAKE_CXX_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_C_FLAGS_COVERAGE ${CMAKE_C_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} coverage PARENT_SCOPE) # instrument targets SET_TARGET_PROPERTIES(${ARG_TARGETS} PROPERTIES COMPILE_FLAGS --coverage LINK_FLAGS --coverage) # html report IF (LCOV_FOUND) MESSAGE(STATUS "Enabling HTML coverage report") # set up coverage target ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_RAW_FILE} COMMAND ${LCOV_EXECUTABLE} -c -d ${CMAKE_BINARY_DIR} -o ${COVERAGE_RAW_FILE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Collecting coverage data" DEPENDS ${ARG_TARGETS} ${ARG_TESTS} VERBATIM) # filter unwanted stuff LIST(LENGTH ARG_FILTER FILTER_LENGTH) IF(${FILTER_LENGTH} GREATER 0) SET(FILTER COMMAND ${LCOV_EXECUTABLE}) FOREACH(F ${ARG_FILTER}) SET(FILTER ${FILTER} -r ${COVERAGE_FILTERED_FILE} ${F}) ENDFOREACH() SET(FILTER ${FILTER} -o ${COVERAGE_FILTERED_FILE}) ELSE() SET(FILTER "") ENDIF() ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_FILTERED_FILE} COMMAND ${LCOV_EXECUTABLE} -e ${COVERAGE_RAW_FILE} "${CMAKE_SOURCE_DIR}*" -o ${COVERAGE_FILTERED_FILE} ${FILTER} DEPENDS ${COVERAGE_RAW_FILE} COMMENT "Filtering recorded coverage data for project-relevant entries" VERBATIM) ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_REPORT_DIR} COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_REPORT_DIR} COMMAND ${GENHTML_EXECUTABLE} --legend --show-details -t "${PROJECT_NAME} test coverage" -o ${COVERAGE_REPORT_DIR} ${COVERAGE_FILTERED_FILE} DEPENDS ${COVERAGE_FILTERED_FILE} COMMENT "Generating HTML coverage report in ${COVERAGE_REPORT_DIR}" VERBATIM) ADD_CUSTOM_TARGET(coverage-html DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() # xml coverage report IF(GCOVR_FOUND) MESSAGE(STATUS "Enabling XML coverage report") # filter unwanted stuff SET(GCOV_FILTER "") LIST(LENGTH ARG_FILTER FILTER_LENGTH) IF(${FILTER_LENGTH} GREATER 0) FOREACH(F ${ARG_FILTER}) SET(GCOV_FILTER "${GCOV_FILTER} -e \"${F}\"") ENDFOREACH() ENDIF() # gcovr cannot write directly to a file so the execution needs to # be wrapped in a cmake file that generates the file output FILE(WRITE ${COVERAGE_XML_COMMAND_FILE} "SET(ENV{LANG} en)\n") FILE(APPEND ${COVERAGE_XML_COMMAND_FILE} "EXECUTE_PROCESS(COMMAND \"${GCOVR_EXECUTABLE}\" -x -r \"${CMAKE_SOURCE_DIR}\" ${GCOV_FILTER} OUTPUT_FILE \"${COVERAGE_XML_FILE}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")\n") ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_XML_FILE} COMMAND ${CMAKE_COMMAND} ARGS -P ${COVERAGE_XML_COMMAND_FILE} COMMENT "Generating coverage XML report" VERBATIM) ADD_CUSTOM_TARGET(coverage-xml DEPENDS ${COVERAGE_XML_FILE}) ENDIF() # provide a global coverage target executing both steps if available SET(GLOBAL_DEPENDS "") IF(LCOV_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() IF(GCOVR_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_XML_FILE}) ENDIF() IF(LCOV_FOUND OR GCOVR_FOUND) ADD_CUSTOM_TARGET(coverage DEPENDS ${GLOBAL_DEPENDS}) ENDIF() ENDIF() # This gets rid of any stale .gcda files. Run this if a running a binary causes lots of messages about # about a "merge mismatch for summaries". ADD_CUSTOM_TARGET(clean-coverage COMMAND find ${CMAKE_BINARY_DIR} -name '*.gcda' | xargs rm -f COMMAND rm -rf "${CMAKE_BINARY_DIR}/coveragereport" "${CMAKE_BINARY_DIR}/coverage.info" "${CMAKE_BINARY_DIR}/coverage.raw.info") ENDFUNCTION() unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/Findgcovr.cmake0000644000015600001650000000170212672630457025325 0ustar pbuserpbgroup00000000000000# - Find gcovr scrip # Will define: # # GCOVR_EXECUTABLE - the gcovr script # # Uses: # # GCOVR_ROOT - root to search for the script # # Copyright (C) 2011 by Johannes Wienke # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software Foundation; # either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") FIND_PACKAGE_HANDLE_STANDARD_ARGS(gcovr DEFAULT_MSG GCOVR_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(GCOVR_EXECUTABLE) unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/ParseArguments.cmake0000644000015600001650000000340612672630457026347 0ustar pbuserpbgroup00000000000000# Parse arguments passed to a function into several lists separated by # upper-case identifiers and options that do not have an associated list e.g.: # # SET(arguments # hello OPTION3 world # LIST3 foo bar # OPTION2 # LIST1 fuz baz # ) # PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments}) # # results in 7 distinct variables: # * ARG_DEFAULT_ARGS: hello;world # * ARG_LIST1: fuz;baz # * ARG_LIST2: # * ARG_LIST3: foo;bar # * ARG_OPTION1: FALSE # * ARG_OPTION2: TRUE # * ARG_OPTION3: TRUE # # taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments MACRO(PARSE_ARGUMENTS prefix arg_names option_names) SET(DEFAULT_ARGS) FOREACH(arg_name ${arg_names}) SET(${prefix}_${arg_name}) ENDFOREACH(arg_name) FOREACH(option ${option_names}) SET(${prefix}_${option} FALSE) ENDFOREACH(option) SET(current_arg_name DEFAULT_ARGS) SET(current_arg_list) FOREACH(arg ${ARGN}) SET(larg_names ${arg_names}) LIST(FIND larg_names "${arg}" is_arg_name) IF (is_arg_name GREATER -1) SET(${prefix}_${current_arg_name} ${current_arg_list}) SET(current_arg_name ${arg}) SET(current_arg_list) ELSE (is_arg_name GREATER -1) SET(loption_names ${option_names}) LIST(FIND loption_names "${arg}" is_option) IF (is_option GREATER -1) SET(${prefix}_${arg} TRUE) ELSE (is_option GREATER -1) SET(current_arg_list ${current_arg_list} ${arg}) ENDIF (is_option GREATER -1) ENDIF (is_arg_name GREATER -1) ENDFOREACH(arg) SET(${prefix}_${current_arg_name} ${current_arg_list}) ENDMACRO(PARSE_ARGUMENTS) unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/FindLcov.cmake0000644000015600001650000000172012672630457025110 0ustar pbuserpbgroup00000000000000# - Find lcov # Will define: # # LCOV_EXECUTABLE - the lcov binary # GENHTML_EXECUTABLE - the genhtml executable # # Copyright (C) 2010 by Johannes Wienke # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software Foundation; # either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(LCOV_EXECUTABLE lcov) FIND_PROGRAM(GENHTML_EXECUTABLE genhtml) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lcov DEFAULT_MSG LCOV_EXECUTABLE GENHTML_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(LCOV_EXECUTABLE GENHTML_EXECUTABLE) unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/Plugins.cmake0000644000015600001650000000420612672630457025027 0ustar pbuserpbgroup00000000000000find_program(qmlplugindump_exe qmlplugindump) if(NOT qmlplugindump_exe) msg(FATAL_ERROR "Could not locate qmlplugindump.") endif() # Creates target for copying and installing qmlfiles # # export_qmlfiles(plugin sub_path) # # # Target to be created: # - plugin-qmlfiles - Copies the qml files (*.qml, *.js, qmldir) into the shadow build folder. macro(export_qmlfiles PLUGIN PLUGIN_SUBPATH) file(GLOB QMLFILES *.qml *.js qmldir ) # copy the qmldir file add_custom_target(${PLUGIN}-qmlfiles ALL COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${QMLFILES} ) # install the qmlfiles file. install(FILES ${QMLFILES} DESTINATION ${SHELL_PLUGINDIR}/${PLUGIN_SUBPATH} ) endmacro(export_qmlfiles) # Creates target for generating the qmltypes file for a plugin and installs plugin files # # export_qmlplugin(plugin version sub_path [TARGETS target1 [target2 ...]]) # # TARGETS additional install targets (eg the plugin shared object) # # Target to be created: # - plugin-qmltypes - Generates the qmltypes file in the shadow build folder. macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH) set(multi_value_keywords TARGETS) cmake_parse_arguments(qmlplugin "" "" "${multi_value_keywords}" ${ARGN}) # Only try to generate .qmltypes if not cross compiling if(NOT CMAKE_CROSSCOMPILING) # create the plugin.qmltypes file add_custom_target(${PLUGIN}-qmltypes ALL COMMAND UNITY_SCOPES_NO_LOCATION=1 UNITY_SCOPES_LIST_DELAY=10000 ${qmlplugindump_exe} -notrelocatable ${PLUGIN} ${VERSION} ${CMAKE_CURRENT_BINARY_DIR}/../ > ${CMAKE_CURRENT_BINARY_DIR}/plugin.qmltypes ) add_dependencies(${PLUGIN}-qmltypes ${PLUGIN}-qmlfiles ${qmlplugin_TARGETS}) # install the qmltypes file. install(FILES ${CMAKE_CURRENT_BINARY_DIR}/plugin.qmltypes DESTINATION ${SHELL_PLUGINDIR}/${PLUGIN_SUBPATH} ) endif() # install the additional targets install(TARGETS ${qmlplugin_TARGETS} DESTINATION ${SHELL_PLUGINDIR}/${PLUGIN_SUBPATH} ) endmacro(export_qmlplugin) unity-scopes-shell-0.5.7+16.04.20160317/cmake/modules/QtWithObjectTarget.cmake0000644000015600001650000000064512672630457027127 0ustar pbuserpbgroup00000000000000 function(object_qt5_use_modules TARGET_NAME) foreach(_module ${ARGN}) target_include_directories( ${TARGET_NAME} PRIVATE $ ) target_compile_definitions( ${TARGET_NAME} PRIVATE $ ) endforeach() endfunction()unity-scopes-shell-0.5.7+16.04.20160317/tests/0000755000015600001650000000000012672635475021021 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/settingsendtoendtest.cpp0000644000015600001650000003735712672630457026020 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pete Woods * Pawel Stolowski */ #include #include #include #include #include #include #include #include #include #define QVERIFY_MATCHRESULT_FAILS(statement, errormsg) \ do {\ auto result = (statement);\ QVERIFY(!result.success());\ const QRegExp r(QString::fromStdString(errormsg));\ QVERIFY2(r.exactMatch(QString::fromStdString(result.concat_failures().c_str())),\ std::string("Failed to match: '\n" + result.concat_failures() + "\nagainst regexp '\n" + errormsg + "\n'").c_str());\ } while (0) namespace sh = unity::scopeharness; namespace shm = unity::scopeharness::matcher; namespace shr = unity::scopeharness::registry; namespace shv = unity::scopeharness::view; namespace sc = unity::scopes; namespace ss = unity::shell::scopes; class SettingsEndToEndTest : public QObject { Q_OBJECT private: sh::ScopeHarness::UPtr m_harness; private Q_SLOTS: void cleanupTestCase() { } void init() { qputenv("UNITY_SCOPES_NO_WAIT_LOCATION", "1"); m_harness = sh::ScopeHarness::newFromScopeList( shr::CustomRegistry::Parameters({ TEST_DATA_DIR "mock-scope-departments/mock-scope-departments.ini", TEST_DATA_DIR "mock-scope-double-nav/mock-scope-double-nav.ini", TEST_DATA_DIR "mock-scope/mock-scope.ini", }) ); } void testBasic() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QCOMPARE(static_cast(settings->count()), 5l); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .hasAtLeast(1) .option( shm::SettingsOptionMatcher("distanceUnit") .displayName("Distance Unit") .optionType(shv::SettingsView::OptionType::List) .displayValues(sc::VariantArray {sc::Variant("Kilometers"), sc::Variant("Miles")}) .value(sc::Variant("Miles")) .defaultValue(sc::Variant("Miles")) ) .match(settings) ); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::starts_with) .hasAtLeast(1) .option( shm::SettingsOptionMatcher("location") .displayName("Location") .optionType(shv::SettingsView::OptionType::String) .value(sc::Variant("London")) .defaultValue(sc::Variant("London")) ) .match(settings) ); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::all) .hasExactly(5) .option( shm::SettingsOptionMatcher("location") .displayName("Location") .optionType(shv::SettingsView::OptionType::String) .value(sc::Variant("London")) .defaultValue(sc::Variant("London")) ) .option( shm::SettingsOptionMatcher("distanceUnit") .displayName("Distance Unit") .optionType(shv::SettingsView::OptionType::List) .displayValues(sc::VariantArray {sc::Variant("Kilometers"), sc::Variant("Miles")}) .value(sc::Variant("Miles")) .defaultValue(sc::Variant("Miles")) ) .option( shm::SettingsOptionMatcher("age") .displayName("Age") .optionType(shv::SettingsView::OptionType::Number) .value(sc::Variant(23)) .defaultValue(sc::Variant(23)) ) .option( shm::SettingsOptionMatcher("enabled") .displayName("Enabled") .optionType(shv::SettingsView::OptionType::Boolean) .value(sc::Variant(true)) .defaultValue(sc::Variant(true)) ) .option( shm::SettingsOptionMatcher("color") .displayName("Color") .optionType(shv::SettingsView::OptionType::String) .value(sc::Variant()) .defaultValue(sc::Variant()) ) .match(settings) ); } void testBasicFailures() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QVERIFY_MATCHRESULT_FAILS( shm::SettingsMatcher() .hasAtLeast(6) .match(settings), "Failed expectations:\nExpected at least 6 options\n"); QVERIFY_MATCHRESULT_FAILS( shm::SettingsMatcher() .hasExactly(2) .match(settings), "Failed expectations:\nExpected exactly 2 options\n"); } void testOptionLookupFailures() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QVERIFY_MATCHRESULT_FAILS( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .option( shm::SettingsOptionMatcher("xyz") ) .match(settings), "Failed expectations:\nSettings option with ID xyz could not be found\n" ); } void testTypeCheckFailures() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QVERIFY_MATCHRESULT_FAILS( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .option( shm::SettingsOptionMatcher("age") .optionType(shv::SettingsView::OptionType::String) ) .option( shm::SettingsOptionMatcher("distanceUnit") .optionType(shv::SettingsView::OptionType::Boolean) ) .option( shm::SettingsOptionMatcher("location") .optionType(shv::SettingsView::OptionType::Number) ) .option( shm::SettingsOptionMatcher("color") .optionType(shv::SettingsView::OptionType::List) ) .match(settings), "Failed expectations:\nOption ID age is of type number, expected string\nOption ID distanceUnit is of type list, expected boolean\nOption ID" " location is of type string, expected number\nOption ID color is of type string, expected list\n" ); } void testValueCheckFailures() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QVERIFY_MATCHRESULT_FAILS( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .option( shm::SettingsOptionMatcher("age") .value(sc::Variant("xyz")) ) .option( shm::SettingsOptionMatcher("distanceUnit") .displayValues(sc::VariantArray {sc::Variant("Kilometers"), sc::Variant("Parsecs")}) ) .match(settings), "Failed expectations:\nOption with ID 'age' has 'value' == '23(.0)?' but expected " "'\"xyz\"'\nOption with ID 'distanceUnit' has 'displayValues' == '\\[\"Kilometers\",\"Miles\"\\]' but expected '\\[\"Kilometers\",\"Parsecs\"\\]'\n" ); } void testValueSetFailure() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); { bool exception_thrown = false; try { settings->set("distanceUnit", sc::Variant("foo")); } catch (const std::domain_error &e) { exception_thrown = true; QCOMPARE(e.what(), "Failed to update settings option with ID 'distanceUnit': no such value 'foo'"); } QVERIFY(exception_thrown); } { bool exception_thrown = false; try { settings->set("distanceUnit", sc::Variant(111)); } catch (const std::domain_error &e) { exception_thrown = true; QCOMPARE(e.what(), "Settings updated failed for option with ID 'distanceUnit': only string values are allowed"); } QVERIFY(exception_thrown); } { bool exception_thrown = false; try { settings->set("xyz", sc::Variant("abc")); } catch (const std::domain_error &e) { exception_thrown = true; QCOMPARE(e.what(), "Setting update failed. No such option: 'xyz'"); } QVERIFY(exception_thrown); } } void verifySettingsChange() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); auto settings = resultsView->settings(); QVERIFY(settings.get()); settings->set("location", sc::Variant("Barcelona")); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .option( shm::SettingsOptionMatcher("location") .value(sc::Variant("Barcelona")) .defaultValue(sc::Variant("London")) ) .match(settings) ); settings->set("distanceUnit", sc::Variant("Miles")); resultsView->setQuery("settings-change"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::by_id) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("result for: \"settings-change\"") .property("setting-distanceUnit", sc::Variant(1)) ) ) .match(resultsView->categories()) ); settings->set("distanceUnit", sc::Variant("Kilometers")); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::by_id) .option( shm::SettingsOptionMatcher("distanceUnit") .value(sc::Variant("Kilometers")) .defaultValue(sc::Variant("Miles")) ) .match(settings) ); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::by_id) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("result for: \"settings-change\"") .property("setting-distanceUnit", sc::Variant(0)) ) ) .match(resultsView->categories()) ); } void testChildScopes() { auto resultsView = m_harness->resultsView(); // make aggregator scope active resultsView->setActiveScope("mock-scope-departments"); auto settings = resultsView->settings(); QVERIFY(settings.get()); QCOMPARE(static_cast(settings->count()), 4l); QVERIFY_MATCHRESULT( shm::SettingsMatcher().mode(shm::SettingsMatcher::Mode::all) .option( shm::SettingsOptionMatcher("string-setting") .displayName("String Setting") .optionType(shv::SettingsView::OptionType::String) .value(sc::Variant("Hello")) .defaultValue(sc::Variant("Hello")) ) .option( shm::SettingsOptionMatcher("number-setting") .displayName("Number Setting") .optionType(shv::SettingsView::OptionType::Number) .value(sc::Variant(13)) .defaultValue(sc::Variant(13)) ) .option( shm::SettingsOptionMatcher("mock-scope-double-nav") .displayName("Display results from mock-double-nav.DisplayName") .optionType(shv::SettingsView::OptionType::Boolean) .value(sc::Variant(true)) .defaultValue(sc::Variant()) ) .option( shm::SettingsOptionMatcher("mock-scope") .displayName("Display results from mock.DisplayName") .optionType(shv::SettingsView::OptionType::Boolean) .value(sc::Variant(true)) .defaultValue(sc::Variant()) ) .match(settings) ); } }; QTEST_GUILESS_MAIN(SettingsEndToEndTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/departmentstest.cpp0000644000015600001650000002731212672630472024750 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #include #include #include #include #include using namespace std; namespace sc = unity::scopes; namespace sh = unity::scopeharness; namespace shm = unity::scopeharness::matcher; namespace shr = unity::scopeharness::registry; namespace shv = unity::scopeharness::view; namespace ss = unity::shell::scopes; namespace ng = scopes_ng; class DepartmentsTest : public QObject { Q_OBJECT private: sh::ScopeHarness::UPtr m_harness; shv::ResultsView::SPtr m_resultsView; private Q_SLOTS: void initTestCase() { qputenv("UNITY_SCOPES_NO_WAIT_LOCATION", "1"); m_harness = sh::ScopeHarness::newFromScopeList( shr::CustomRegistry::Parameters({ TEST_DATA_DIR "mock-scope-departments/mock-scope-departments.ini", TEST_DATA_DIR "mock-scope-double-nav/mock-scope-double-nav.ini", TEST_DATA_DIR "mock-scope-departments-flipflop/mock-scope-departments-flipflop.ini" }) ); m_resultsView = m_harness->resultsView(); } void cleanupTestCase() { m_resultsView.reset(); m_harness.reset(); } void testNoDepartments() { m_resultsView->setActiveScope("mock-scope-departments"); m_resultsView->setQuery("foo"); QVERIFY(!m_resultsView->hasDepartments()); } void testRootDepartment() { m_resultsView->setActiveScope("mock-scope-departments"); m_resultsView->setQuery(""); QVERIFY(m_resultsView->hasDepartments()); QVERIFY(m_resultsView->departmentId().empty()); auto departments = m_resultsView->browseDepartment(); QCOMPARE(m_resultsView->departmentId(), string()); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .hasExactly(5) .label("All departments") .allLabel(string()) .parentId(string()) .parentLabel(string()) .isRoot(true) .isHidden(false) .child(shm::ChildDepartmentMatcher("books") .label("Books") .hasChildren(true) .isActive(false) ) .child(shm::ChildDepartmentMatcher("movies")) .child(shm::ChildDepartmentMatcher("electronics")) .child(shm::ChildDepartmentMatcher("home")) .child(shm::ChildDepartmentMatcher("toys") .label("Toys, Children & Baby") .hasChildren(true) .isActive(false) ) .match(departments) ); } void testChildDepartmentModel() { m_resultsView->setActiveScope("mock-scope-departments"); m_resultsView->setQuery(""); auto departments = m_resultsView->browseDepartment("toys"); QCOMPARE(m_resultsView->departmentId(), string("toys")); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id("toys") .label("Toys, Children & Baby") .allLabel(string()) .parentId(string()) .parentLabel(string("All departments")) .isRoot(false) .hasExactly(2) .match(departments) ); } void testLeafActivationUpdatesModel() { m_resultsView->setActiveScope("mock-scope-departments"); m_resultsView->setQuery(""); auto books = m_resultsView->browseDepartment("books"); QCOMPARE(m_resultsView->departmentId(), string("books")); QVERIFY(!books.isRoot()); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("test:uri") .title("result for: \"\", department \"books\"") ) ) .match(m_resultsView->categories()) ); auto booksAudio = m_resultsView->browseDepartment("books-audio"); QVERIFY(!booksAudio.isRoot()); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("test:uri") .title("result for: \"\", department \"books-audio\"") ) ) .match(m_resultsView->categories()) ); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .mode(shm::DepartmentMatcher::Mode::by_id) .child(shm::ChildDepartmentMatcher("books-audio")) .match(books) ); } // This test has always been broken void testGoingBack() { // sh::performSearch(m_scope, QString("x")); // // QCOMPARE(m_scope->currentNavigationId(), QString("")); // QSignalSpy spy(m_scope.data(), SIGNAL(searchInProgressChanged())); // QScopedPointer navModel(m_scope->getNavigation(QString("books"))); // m_scope->setNavigationState(navModel->navigationId(), false); // QVERIFY(spy.wait()); // QCOMPARE(m_scope->searchInProgress(), false); // QScopedPointer departmentModel(m_scope->getNavigation(QString("books"))); // QCOMPARE(departmentModel->isRoot(), false); // // // get the root again without actually loading the department // departmentModel.reset(m_scope->getNavigation(departmentModel->parentNavigationId())); // QCOMPARE(departmentModel->isRoot(), true); // QEXPECT_FAIL("", "We have the department in cache, to it kind of is loaded", Continue); // QCOMPARE(departmentModel->loaded(), false); } void testIncompleteTreeOnLeaf() { m_resultsView->setActiveScope("mock-scope-departments"); m_resultsView->setQuery(""); auto toys = m_resultsView->browseDepartment("toys"); QCOMPARE(m_resultsView->departmentId(), string("toys")); QCOMPARE(toys.size(), size_t(2)); auto toysGames = m_resultsView->browseDepartment("toys-games"); QCOMPARE(m_resultsView->departmentId(), string("toys-games")); QCOMPARE(toysGames.size(), size_t(0)); // after getting the parent department model, it should still have // all the leaves, even though the leaf served just itself auto toys2 = m_resultsView->browseDepartment("toys"); QCOMPARE(m_resultsView->departmentId(), string("toys")); QCOMPARE(toys2.size(), size_t(2)); } void testDoubleNavigation() { m_resultsView->setActiveScope("mock-scope-double-nav"); m_resultsView->setQuery(""); auto root = m_resultsView->browseDepartment(); QVERIFY(m_resultsView->hasDepartments()); QVERIFY(m_resultsView->departmentId().empty()); QCOMPARE(m_resultsView->altDepartmentId(), string("featured")); auto sortOrder = m_resultsView->browseAltDepartment(); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id(string()) .label("Sort Order") .allLabel(string()) .parentId(string()) .parentLabel(string()) .isRoot(true) .isHidden(true) .hasExactly(3) .child(shm::ChildDepartmentMatcher("featured") .label("Featured") .hasChildren(false) .isActive(true) ) .child(shm::ChildDepartmentMatcher("top")) .child(shm::ChildDepartmentMatcher("best") .label("Best sellers") .hasChildren(false) .isActive(false) ) .match(sortOrder) ); } void testDoubleNavChangeActive() { m_resultsView->setActiveScope("mock-scope-double-nav"); m_resultsView->setQuery(""); m_resultsView->browseDepartment(); QCOMPARE(m_resultsView->altDepartmentId(), string("featured")); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id(string()) .label("Sort Order") .hasExactly(3) .child(shm::ChildDepartmentMatcher("featured")) .child(shm::ChildDepartmentMatcher("top") .isActive(false) ) .child(shm::ChildDepartmentMatcher("best")) .match(m_resultsView->browseAltDepartment()) ); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id(string("top")) .hasExactly(0) .match(m_resultsView->browseAltDepartment("top")) ); } void testDepartmentDissapear() { m_resultsView->setActiveScope("mock-scope-departments-flipflop"); m_resultsView->setQuery(""); auto root = m_resultsView->browseDepartment(); QVERIFY(m_resultsView->hasDepartments()); QVERIFY(m_resultsView->departmentId().empty()); QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id(string()) .label("All departments") .allLabel(string()) .parentId(string()) .parentLabel(string()) .isRoot(true) .isHidden(false) .hasExactly(5) .match(root) ); m_resultsView->forceRefresh(); root = m_resultsView->browseDepartment(); // one department removed QVERIFY_MATCHRESULT( shm::DepartmentMatcher() .id(string()) .label("All departments") .allLabel(string()) .parentId(string()) .parentLabel(string()) .isRoot(true) .isHidden(false) .hasExactly(4) .child(shm::ChildDepartmentMatcher("books") .label("Books") .hasChildren(true) .isActive(false) ) .child(shm::ChildDepartmentMatcher("movies")) .child(shm::ChildDepartmentMatcher("home")) .child(shm::ChildDepartmentMatcher("toys") .label("Toys, Children & Baby") .hasChildren(true) .isActive(false) ) .match(root) ); } }; QTEST_GUILESS_MAIN(DepartmentsTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/overviewtest.cpp0000644000015600001650000000621412672630457024271 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace scopes_ng; using namespace unity::scopeharness; using namespace unity::scopeharness::registry; class OverviewTest : public QObject { Q_OBJECT private: QScopedPointer m_scopes; Scope::Ptr m_scope; Registry::UPtr m_registry; private Q_SLOTS: void initTestCase() { m_registry.reset(new PreExistingRegistry(TEST_RUNTIME_CONFIG)); m_registry->start(); } void cleanupTestCase() { m_registry.reset(); } void init() { QStringList favs; favs << "scope://mock-scope-departments" << "scope://mock-scope-double-nav"; TestUtils::setFavouriteScopes(favs); m_scopes.reset(new Scopes(nullptr)); // no scopes on startup QCOMPARE(m_scopes->rowCount(), 0); QCOMPARE(m_scopes->loaded(), false); QSignalSpy spy(m_scopes.data(), SIGNAL(loadedChanged())); // wait till the registry spawns QVERIFY(spy.wait()); QCOMPARE(m_scopes->loaded(), true); // get scope proxy m_scope = m_scopes->overviewScopeSPtr(); QVERIFY(bool(m_scope)); } void cleanup() { m_scopes.reset(); m_scope.reset(); } void testScopeProperties() { QCOMPARE(m_scope->id(), QString("scopes")); } void testSurfacingQuery() { // ensure categories have > 0 rows auto categories = m_scope->categories(); QVERIFY(categories->rowCount() > 0); QCOMPARE(categories->data(categories->index(0), Categories::Roles::RoleCategoryId), QVariant(QString("favorites"))); QCOMPARE(categories->data(categories->index(1), Categories::Roles::RoleCategoryId), QVariant(QString("other"))); QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults); QVERIFY(results_var.canConvert()); OverviewResultsModel* results = results_var.value(); QVERIFY(results->rowCount() == 2); } }; QTEST_GUILESS_MAIN(OverviewTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/resultstest.cpp0000644000015600001650000015122012672630457024122 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace sh = unity::scopeharness; namespace shm = unity::scopeharness::matcher; namespace shr = unity::scopeharness::registry; namespace shv = unity::scopeharness::view; namespace sc = unity::scopes; namespace ss = unity::shell::scopes; class CountObject : public QObject { Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countChanged) public: explicit CountObject(QObject* parent = nullptr) : QObject(parent), m_count(0), m_waitingCount(0) { connect(&m_timer, &QTimer::timeout, this, &CountObject::asyncTimeout); } Q_SIGNALS: void countChanged(); private Q_SLOTS: void asyncTimeout() { setCount(m_waitingCount); } public: int count() const { return m_count; } void setCount(int newCount) { if (newCount != m_count) { m_count = newCount; Q_EMIT countChanged(); } } void setCountAsync(int newCount) { m_waitingCount = newCount; m_timer.setSingleShot(true); m_timer.start(1); } private: int m_count; int m_waitingCount; QTimer m_timer; }; class ResultsTest : public QObject { Q_OBJECT private: sh::ScopeHarness::UPtr m_harness; private Q_SLOTS: void initTestCase() { qputenv("UNITY_SCOPES_NO_WAIT_LOCATION", "1"); qputenv("UNITY_SCOPES_CARDINALITY_OVERRIDE", "9999"); m_harness = sh::ScopeHarness::newFromScopeList( shr::CustomRegistry::Parameters({ TEST_DATA_DIR "mock-scope/mock-scope.ini", TEST_DATA_DIR "mock-scope-info/mock-scope-info.ini", TEST_DATA_DIR "mock-scope-ttl/mock-scope-ttl.ini", TEST_DATA_DIR "mock-scope-manyresults/mock-scope-manyresults.ini" }) ); } void cleanupTestCase() { m_harness.reset(); } void init() { } void cleanup() { } void testScopeCommunication() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery(""); // ensure categories have > 0 rows // ensure results have some data QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::by_id) .category(shm::CategoryMatcher("cat1") .title("Category 1") .icon(string()) .headerLink(string()) .hasAtLeast(1) ) .match(resultsView->categories()) ); } // void testScopesGet() // { // ss::ScopeInterface* scope = m_scopes->getScope(0); // QVERIFY(scope); // // // try incorrect index as well // scope = m_scopes->getScope(65536); // QVERIFY(!scope); // scope = m_scopes->getScope(-1); // QVERIFY(!scope); // // // try to get by scope id // scope = m_scopes->getScope(QString("mock-scope")); // QVERIFY(scope); // // scope = m_scopes->getScope(QString("non-existing")); // QVERIFY(!scope); // } void testScopeProperties() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); QVERIFY(resultsView->scopeId() == "mock-scope"); QVERIFY(resultsView->displayName() == "mock.DisplayName"); QVERIFY(resultsView->iconHint() == "/mock.Icon"); QVERIFY(resultsView->description() == "mock.Description"); QVERIFY(resultsView->searchHint() == "mock.SearchHint"); QVERIFY(resultsView->shortcut() =="mock.HotKey"); QVERIFY(resultsView->query() == ""); sc::VariantMap customizations(resultsView->customizations().get_dict()); QVERIFY(!customizations.empty()); QCOMPARE(customizations["page-header"].which(), sc::Variant::Type::Dict); sc::VariantMap headerCustomizations(customizations["page-header"].get_dict()); QCOMPARE(headerCustomizations["logo"], sc::Variant("http://assets.ubuntu.com/sites/ubuntu/1110/u/img/logos/logo-ubuntu-orange.svg")); QCOMPARE(headerCustomizations["foreground-color"], sc::Variant("white")); QCOMPARE(headerCustomizations["background"], sc::Variant("color://black")); QCOMPARE(customizations["shape-images"], sc::Variant(false)); resultsView->setActiveScope("mock-scope-ttl"); QVERIFY(resultsView->scopeId() == "mock-scope-ttl"); QVERIFY(resultsView->displayName() == "mock-ttl.DisplayName"); QVERIFY(resultsView->iconHint() == "/mock-ttl.Icon"); QVERIFY(resultsView->description() == "mock-ttl.Description"); QVERIFY(resultsView->searchHint() == ""); QVERIFY(resultsView->shortcut() == ""); QVERIFY(resultsView->query() == ""); } void testCategoryQuery() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("expansion-query"); // ensure categories have > 0 rows QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .title("Category 1") .icon("") .headerLink("scope://mock-scope?q=expansion%2Dquery") .mode(shm::CategoryMatcher::Mode::by_uri) .hasAtLeast(1) ) .match(resultsView->categories()) ); } void testTwoSearches() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery(""); // ensure categories has 1 row QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .match(resultsView->categories()) ); resultsView->setQuery("foo"); // shouldn't create more nor fewer categories QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .match(resultsView->categories()) ); } void testBasicResultData() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery(""); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::by_id) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .dndUri("test:dnd_uri") .title("result for: \"\"") .art("art") .property("booleanness", sc::Variant(true)) ) ) .match(resultsView->categories()) ); } void testSessionId() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery(""); string lastSessionId; QVERIFY(!resultsView->sessionId().empty()); QCOMPARE(resultsView->queryId(), 0); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(0)) ) ) .match(resultsView->categories()) ); lastSessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); } // new search resultsView->setQuery("m"); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(0)) ) ) .match(resultsView->categories()) ); auto sessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); // new session id QVERIFY(sessionId != lastSessionId); lastSessionId = sessionId; } // appends to previous search resultsView->setQuery("met"); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(1)) ) ) .match(resultsView->categories()) ); auto sessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); // session id unchanged QCOMPARE(sessionId, lastSessionId); lastSessionId = sessionId; } // removes characters from previous search resultsView->setQuery("m"); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(2)) ) ) .match(resultsView->categories()) ); auto sessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); // session id unchanged QVERIFY(sessionId == lastSessionId); lastSessionId = sessionId; } // new non-empty search again resultsView->setQuery("iron"); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(0)) ) ) .match(resultsView->categories()) ); auto sessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); // new session id QVERIFY(sessionId != lastSessionId); lastSessionId = sessionId; } // new empty search again resultsView->setQuery(""); { QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .property("session-id", sc::Variant(resultsView->sessionId())) .property("query-id", sc::Variant(0)) ) ) .match(resultsView->categories()) ); auto sessionId = resultsView->category("cat1").results().front()["session-id"].get_string(); // new session id QVERIFY(sessionId != lastSessionId); lastSessionId = sessionId; } } void testResultMetadata() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("metadata"); // various fields have been mapped QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("result for: \"metadata\"") .subtitle("subtitle") .emblem("emblem") .mascot(string()) .attributes(sc::Variant()) .summary(sc::Variant()) ) ) .match(resultsView->categories()) ); } // void testResultsInvalidation() // { // if (!QDBusConnection::sessionBus().isConnected()) { // QSKIP("DBus unavailable, skipping test"); // } // // QStringList args; // args << "/com/canonical/unity/scopes"; // args << "com.canonical.unity.scopes.InvalidateResults"; // args << "string:mock-scope"; // QProcess::execute("dbus-send", args); // // QSignalSpy spy(m_scope, SIGNAL(searchInProgressChanged())); // QCOMPARE(m_scope->searchInProgress(), false); // QVERIFY(spy.wait()); // QCOMPARE(m_scope->searchInProgress(), true); // QVERIFY(spy.wait()); // QCOMPARE(m_scope->searchInProgress(), false); // } void testActiveTtlScope() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-ttl"); resultsView->setQuery("query text"); const QString query("query text"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("query text2") ) ) .match(resultsView->categories()) ); // The scope should refresh every 250 ms, and increment the query // counter each time. resultsView->waitForResultsChange(); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("query text3") ) ) .match(resultsView->categories()) ); resultsView->waitForResultsChange(); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("query text4") ) ) .match(resultsView->categories()) ); resultsView->waitForResultsChange(); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("test:uri") .title("query text5") ) ) .match(resultsView->categories()) ); } void testAlbumArtResult() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("music"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .result(shm::ResultMatcher("file:///tmp/foo.mp3") .title("result for: \"music\"") .art("image://albumart/artist=Foo&album=FooAlbum") ) ) .match(resultsView->categories()) ); } void testCategoryOverride() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("metadata"); auto categories = resultsView->categories(); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("test:uri") .title("result for: \"metadata\"") .emblem("emblem") .art("art") ) ) .match(categories) ); // drop all components but title resultsView->overrideCategoryJson("cat1", R"({"schema-version": 1, "components": {"title": "title"}})"); // check that the model no longer has the components QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("test:uri") .title("result for: \"metadata\"") .emblem(string()) .art(string()) ) ) .match(categories) ); resultsView->overrideCategoryJson("cat1", R"({"schema-version": 1, "components": {"title": "title", "art": {"field": "art"}}})"); // check that the model has the art QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("test:uri") .title("result for: \"metadata\"") .emblem(string()) .art("art") ) ) .match(categories) ); } void testCategoryWithRating() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("rating"); sc::VariantBuilder builder; builder.add_tuple({{"value", sc::Variant("21 reviews")}}); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::by_id) .hasAtLeast(1) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .hasAtLeast(1) .result(shm::ResultMatcher("test:uri") .title("result for: \"rating\"") .attributes(builder.end()) ) ) .match(resultsView->categories()) ); } void testCategoryAttributeLimit() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("attributes"); // Verify we only have 3 attributes sc::VariantBuilder builder; builder.add_tuple({{"value", sc::Variant("21 reviews")}}); builder.add_tuple({{"value", sc::Variant("4 comments")}}); builder.add_tuple({{"value", sc::Variant("28 stars")}}); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::by_id) .hasAtLeast(1) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::by_uri) .hasAtLeast(1) .result(shm::ResultMatcher("test:uri") .title("result for: \"attributes\"") .attributes(builder.end()) ) ) .match(resultsView->categories()) ); } void testCategoryWithBackground() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("background"); sc::VariantMap renderer { {"card-background", sc::Variant(sc::VariantMap{ {"elements", sc::Variant(sc::VariantArray{sc::Variant("black")})}, {"type", sc::Variant("color")} })}, {"card-layout", sc::Variant("vertical")}, {"card-size", sc::Variant("small")}, {"category-layout", sc::Variant("grid")}, {"collapsed-rows", sc::Variant(2.0)}, {"overlay-mode", sc::Variant()} }; sc::VariantMap background { {"elements", sc::Variant( sc::VariantArray{ sc::Variant("green"), sc::Variant("#ff00aa33") }) }, {"type", sc::Variant("gradient") } }; QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .renderer(sc::Variant(renderer)) .result(shm::ResultMatcher("test:uri") .title("result for: \"background\"") .background(sc::Variant(background)) ) ) .match(resultsView->categories()) ); } void testCategoryDefaults() { // this search return minimal category definition, defaults should kick in auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("minimal"); sc::VariantMap renderer { {"card-layout", sc::Variant("vertical")}, {"card-size", sc::Variant("small")}, {"category-layout", sc::Variant("grid")}, {"collapsed-rows", sc::Variant(2.0)}, {"overlay-mode", sc::Variant()} }; sc::VariantMap components { {"art", sc::Variant(sc::VariantMap{{"aspect-ratio", sc::Variant(1.0)}})}, {"attributes", sc::Variant(sc::VariantMap{{"max-count", sc::Variant(2.0)}})}, {"background", sc::Variant()}, {"emblem", sc::Variant()}, {"mascot", sc::Variant()}, {"overlay-color", sc::Variant()}, {"subtitle", sc::Variant()}, {"summary", sc::Variant()}, {"title", sc::Variant(sc::VariantMap{{"field", sc::Variant("title")}})} }; QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .renderer(sc::Variant(renderer)) .components(sc::Variant(components)) .result(shm::ResultMatcher("test:uri") .title("result for: \"minimal\"") .art(string()) ) ) .match(resultsView->categories()) ); } void testCategoryDefinitionChange() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("z"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .match(resultsView->categories()) ); // FIXME Restore category definition change test // qRegisterMetaType>(); // QSignalSpy spy(categories, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); // // // should at least change components // resultsView->setQuery("metadata"); // // // expecting a few dataChanged signals, count and components changes // // ensure we get the components one // bool componentsChanged = false; // while (!spy.empty() && !componentsChanged) { // QList arguments = spy.takeFirst(); // auto roles = arguments.at(2).value>(); // componentsChanged |= roles.contains(ss::CategoriesInterface::Roles::RoleComponents); // } // // QCOMPARE(componentsChanged, true); } void testCategoryOrderChange() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("two-categories"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1")) .category(shm::CategoryMatcher("cat2")) .match(resultsView->categories()) ); resultsView->setQuery("two-categories-reversed"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat2")) .category(shm::CategoryMatcher("cat1")) .match(resultsView->categories()) ); } void testCategoryOrderChange2() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("two-categories-one-result"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("test:uri")) ) .match(resultsView->categories()) ); resultsView->setQuery("two-categories-reversed"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .category(shm::CategoryMatcher("cat2")) .category(shm::CategoryMatcher("cat1")) .match(resultsView->categories()) ); } /** * This test activates a result which is previewed normally */ void testScopeActivation() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("v"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("test:uri")) ) .match(resultsView->categories()) ); auto abstractView = resultsView->category("cat1").result("test:uri").longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); } /** * This test activates a result that points to mock-scope-ttl */ void testScopeActivationWithQuery() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("perform-query"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("scope://test:perform-query")) ) .match(resultsView->categories()) ); auto abstractView = resultsView->category("cat1").result("scope://test:perform-query").tap(); QVERIFY(bool(abstractView)); auto nextView = dynamic_pointer_cast(abstractView); QVERIFY(bool(nextView)); QCOMPARE(nextView->scopeId(), string("mock-scope-ttl")); } /** * This test tries to activate a result that points to a non-existing scope */ void testScopeActivationWithQuery2() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("perform-query2"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("scope://test:perform-query")) ) .match(resultsView->categories()) ); auto abstractView = resultsView->category("cat1").result("scope://test:perform-query").tap(); QVERIFY(bool(abstractView)); auto nextView = dynamic_pointer_cast(abstractView); QVERIFY(bool(nextView)); // We shouldn't have gone anywhere QCOMPARE(nextView->scopeId(), string("mock-scope")); } /** * This test activates a result action */ void testScopeResultActionActivation() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("result-action"); // activate action1 { auto view = resultsView->category("cat1").result("test:result-action").tapAction("action1"); QVERIFY(bool(view)); auto nextView = dynamic_pointer_cast(view); QVERIFY(bool(nextView)); QCOMPARE(resultsView, nextView); // check that mock scope updated the result by inserting 'actionId' in it QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result( shm::ResultMatcher("test:result-action") .property("actionId", sc::Variant("action1")) ) ) .match(resultsView->categories()) ); } // activate action2 { auto view = resultsView->category("cat1").result("test:result-action").tapAction("action2"); QVERIFY(bool(view)); auto nextView = dynamic_pointer_cast(view); QVERIFY(bool(nextView)); QCOMPARE(resultsView, nextView); // check that mock scope updated the result QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result( shm::ResultMatcher("test:result-action") .property("actionId", sc::Variant("action2")) ) ) .match(resultsView->categories()) ); } } void testScopeResultWithScopeUri() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope"); resultsView->setQuery("scope-uri"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher(shm::ScopeUri("mock-scope").query("next-scope-query"))) ) .match(resultsView->categories()) ); auto abstractView = resultsView->category("cat1").result( shm::ScopeUri("mock-scope").query("next-scope-query").toString()).tap(); QVERIFY(bool(abstractView)); auto nextView = dynamic_pointer_cast(abstractView); QVERIFY(bool(nextView)); QCOMPARE(resultsView->query(), string("next-scope-query")); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("next-scope-query") .title("result for: \"next-scope-query\"") .art("next-scope-query-art") ) ) .match(resultsView->categories()) ); } void testInfoStatus() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-info"); // No info (Status::Okay) resultsView->setQuery("no_info"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::Okay); // NoInternet (Status::NoInternet) resultsView->setQuery("no_internet"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::NoInternet); // NoLocationData (Status::NoLocationData) resultsView->setQuery("no_location"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::NoLocationData); // DefaultSettingsUsed (unknown to shell but known to run-time so Status::Okay) resultsView->setQuery("shell_unknown"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::Okay); // DefaultSettingsUsed (unknown to runtime so Status::Unknown) resultsView->setQuery("runtime_unknown"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::Unknown); // NoLocationData and NoInternet (Status::NoInternet takes priority) resultsView->setQuery("no_location_no_internet"); QCOMPARE(resultsView->status(), ss::ScopeInterface::Status::NoInternet); } void testResultsModelChanges() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-manyresults"); resultsView->setQuery("search1"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("cat1_uri0")) .result(shm::ResultMatcher("cat1_uri1")) .result(shm::ResultMatcher("cat1_uri2")) .result(shm::ResultMatcher("cat1_uri3")) .result(shm::ResultMatcher("cat1_uri4")) ) .match(resultsView->categories()) ); resultsView->setQuery("search2"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(2) .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("cat1_uri3")) .result(shm::ResultMatcher("cat1_uri4")) .result(shm::ResultMatcher("cat1_uri5")) .result(shm::ResultMatcher("cat1_uri6")) .result(shm::ResultMatcher("cat1_uri7")) ) .category(shm::CategoryMatcher("cat2") .result(shm::ResultMatcher("cat2_uri3")) .result(shm::ResultMatcher("cat2_uri4")) .result(shm::ResultMatcher("cat2_uri5")) .result(shm::ResultMatcher("cat2_uri6")) .result(shm::ResultMatcher("cat2_uri7")) ) .match(resultsView->categories()) ); resultsView->setQuery("search3"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(2) .category(shm::CategoryMatcher("cat1") .result(shm::ResultMatcher("cat1_uri7")) .result(shm::ResultMatcher("cat1_uri6")) .result(shm::ResultMatcher("cat1_uri5")) .result(shm::ResultMatcher("cat1_uri4")) .result(shm::ResultMatcher("cat1_uri3")) ) .category(shm::CategoryMatcher("cat2") .result(shm::ResultMatcher("cat2_uri7")) .result(shm::ResultMatcher("cat2_uri6")) .result(shm::ResultMatcher("cat2_uri5")) .result(shm::ResultMatcher("cat2_uri4")) .result(shm::ResultMatcher("cat2_uri3")) ) .match(resultsView->categories()) ); resultsView->setQuery("search4"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat2") .result(shm::ResultMatcher("cat2_uri5")) ) .match(resultsView->categories()) ); } void testResultsModelChangesWithDuplicatedUris() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-manyresults"); // first search run { resultsView->setQuery("duplicated_uris1"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 10UL); for (unsigned i = 0; isetQuery("duplicated_uris2"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 10UL); for (unsigned i = 0; iresultsView(); resultsView->setActiveScope("mock-scope-manyresults"); { resultsView->setQuery("duplicated_results"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) ) .match(resultsView->categories()) ); auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 1UL); } } void testResultsMassiveModelChanges() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-manyresults"); // first search run { auto const start = std::chrono::system_clock::now(); resultsView->setQuery("lots_of_results"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(2000) ) .match(resultsView->categories()) ); auto end = std::chrono::system_clock::now(); auto search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #1 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 2000UL); for (unsigned i = 0; isetQuery("lots_of_results_reversed_plus_some"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(2100) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #2 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 2100UL); for (unsigned i = 0; isetQuery("lots_of_results_reversed"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(2000) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #3 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 2000UL); for (unsigned i = 0; isetQuery("lots_of_results_half_of_them_missing"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1000) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #4 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 1000UL); for (unsigned i = 0; isetQuery("lots_of_results_2"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(2000) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #5 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 2000UL); for (unsigned i = 0; isetQuery("lots_of_results_fast"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto end = std::chrono::system_clock::now(); auto search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #6 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 10UL); for (unsigned i = 0; isetQuery("lots_of_results_reversed_fast"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #7 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 10UL); for (unsigned i = 0; isetQuery(""); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(200) ) .match(resultsView->categories()) ); auto const end = std::chrono::system_clock::now(); auto const search_dur = std::chrono::duration_cast(end.time_since_epoch()).count() - std::chrono::duration_cast(start.time_since_epoch()).count(); qDebug() << "Search #8 duration: " << search_dur; auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), 200UL); for (unsigned i = 0; iresultsView(); resultsView->setActiveScope("mock-scope-manyresults"); for (int i = 0; i<10; i++) { const unsigned long n = 1 + rand() % 100; // up to 100 results resultsView->setQuery("random" + std::to_string(n)); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(n) ) .match(resultsView->categories()) ); auto const results = resultsView->category("cat1").results(); QCOMPARE(static_cast(results.size()), n); } } void testResultsModelUpdatesTwoCategories() { auto resultsView = m_harness->resultsView(); resultsView->setActiveScope("mock-scope-manyresults"); { resultsView->setQuery("two-categories"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(2) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .category(shm::CategoryMatcher("cat3") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto const results1 = resultsView->category("cat1").results(); QCOMPARE(static_cast(results1.size()), 10UL); auto const results2 = resultsView->category("cat3").results(); QCOMPARE(static_cast(results2.size()), 10UL); } { resultsView->setQuery("two-categories-second-gone"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasExactly(1) .category(shm::CategoryMatcher("cat1") .hasAtLeast(10) ) .match(resultsView->categories()) ); auto const results1 = resultsView->category("cat1").results(); QCOMPARE(static_cast(results1.size()), 10UL); } } }; QTEST_GUILESS_MAIN(ResultsTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/utilstest.cpp0000644000015600001650000000757512672630457023576 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #include #include #include #include #include using namespace scopes_ng; using namespace unity; class UtilsTest : public QObject { Q_OBJECT private Q_SLOTS: void testVariantConversions() { scopes::Variant v1("foo"); QCOMPARE(scopeVariantToQVariant(v1).toString(), QString("foo")); scopes::Variant v2(7); QCOMPARE(scopeVariantToQVariant(v2).toInt(), 7); scopes::Variant v3(true); QCOMPARE(scopeVariantToQVariant(v3).toBool(), true); scopes::Variant v4(3.25); QCOMPARE(scopeVariantToQVariant(v4).toDouble(), 3.25); scopes::Variant v5; QCOMPARE(scopeVariantToQVariant(v5).isNull(), true); scopes::VariantArray arr; arr.push_back(v1); arr.push_back(v3); arr.push_back(v2); QVariantList list = scopeVariantToQVariant(scopes::Variant(arr)).toList(); QCOMPARE(list.size(), 3); QCOMPARE(list[0].toString(), QString("foo")); QCOMPARE(list[1].toBool(), true); QCOMPARE(list[2].toInt(), 7); scopes::VariantMap vm; vm["first"] = v1; vm["2"] = v2; vm["last"] = v3; QVariantMap dict = scopeVariantToQVariant(scopes::Variant(vm)).toMap(); QCOMPARE(dict.size(), 3); QCOMPARE(dict.value("first").toString(), QString("foo")); QCOMPARE(dict.value("2").toInt(), 7); QCOMPARE(dict.value("last").toBool(), true); } void testInvertedConversions() { scopes::Variant v1("foo"); QVariant qv1(scopeVariantToQVariant(v1)); QCOMPARE(qVariantToScopeVariant(qv1), v1); scopes::Variant v2(7); QVariant qv2(scopeVariantToQVariant(v2)); QCOMPARE(qVariantToScopeVariant(qv2), v2); scopes::Variant v3(true); QVariant qv3(scopeVariantToQVariant(v3)); QCOMPARE(qVariantToScopeVariant(qv3), v3); scopes::Variant v4(3.25); QVariant qv4(scopeVariantToQVariant(v4)); QCOMPARE(qVariantToScopeVariant(qv4), v4); scopes::Variant v5; QVariant qv5(scopeVariantToQVariant(v5)); QCOMPARE(qVariantToScopeVariant(qv5), v5); scopes::VariantArray arr; arr.push_back(v1); arr.push_back(v3); arr.push_back(v2); QVariantList list = scopeVariantToQVariant(scopes::Variant(arr)).toList(); QCOMPARE(list.size(), 3); QCOMPARE(qVariantToScopeVariant(list[0]), v1); QCOMPARE(qVariantToScopeVariant(list[1]), v3); QCOMPARE(qVariantToScopeVariant(list[2]), v2); QCOMPARE(qVariantToScopeVariant(list), scopes::Variant(arr)); scopes::VariantMap vm; vm["first"] = v1; vm["2"] = v2; vm["last"] = v3; QVariantMap dict = scopeVariantToQVariant(scopes::Variant(vm)).toMap(); QCOMPARE(dict.size(), 3); QCOMPARE(qVariantToScopeVariant(dict.value("first")), v1); QCOMPARE(qVariantToScopeVariant(dict.value("2")), v2); QCOMPARE(qVariantToScopeVariant(dict.value("last")), v3); QCOMPARE(qVariantToScopeVariant(dict), scopes::Variant(vm)); } }; QTEST_GUILESS_MAIN(UtilsTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/locationtest.cpp0000644000015600001650000001641712672630457024241 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pete Woods */ #include "ubuntulocationservice.h" #include #include #include #include #include #include using namespace std; using namespace scopes_ng; using namespace unity::scopes; using namespace QtDBusTest; using namespace QtDBusMock; namespace { static const char* LOCATION_SERVICE_NAME = "com.ubuntu.location.Service"; static const char* LOCATION_SERVICE_PATH = "/com/ubuntu/location/Service"; static const char* LOCATION_SERVICE_INTERFACE = "com.ubuntu.location.Service"; static const char* SESSION_NAME = "com.ubuntu.location.Service.Session"; static const QString SESSION_PATH = "/com/ubuntu/location/session/%1"; static const QString SESSION_INTERFACE = "com.ubuntu.location.Service.Session"; static Variant geoip() { VariantMap result; result["area_code"] = "0"; result["city"] = "Accrington"; result["country_code"] = "GB"; result["country_name"] = "United Kingdom"; result["horizontal_accuracy"] = 100000.0; result["latitude"] = 55.76540; result["longitude"] = -2.74670; result["region_code"] = "H2"; result["region_name"] = "Lancashire"; result["zip_postal_code"] = "BB5"; return Variant(result); } static Variant gps() { VariantMap result; result["altitude"] = 3.0; result["area_code"] = "0"; result["city"] = "Accrington"; result["country_code"] = "GB"; result["country_name"] = "United Kingdom"; result["horizontal_accuracy"] = 4.0; result["latitude"] = 1.0; result["longitude"] = 2.0; result["region_code"] = "H2"; result["region_name"] = "Lancashire"; result["vertical_accuracy"] = 5.0; result["zip_postal_code"] = "BB5"; return Variant(result); } class LocationTest: public QObject { Q_OBJECT public: LocationTest() : mock(dbus) { } private: OrgFreedesktopDBusMockInterface& interface() { return mock.mockInterface(LOCATION_SERVICE_NAME, LOCATION_SERVICE_PATH, LOCATION_SERVICE_INTERFACE, QDBusConnection::SystemBus); } OrgFreedesktopDBusMockInterface& session(int id) { return mock.mockInterface(SESSION_NAME, SESSION_PATH.arg(id), SESSION_INTERFACE, QDBusConnection::SystemBus); } DBusTestRunner dbus; DBusMock mock; QScopedPointer locationService; QProcess geoIpServer; QUrl url; private Q_SLOTS: void initTestCase() { DBusMock::registerMetaTypes(); // Register the main interface object mock.registerCustomMock(LOCATION_SERVICE_NAME, LOCATION_SERVICE_PATH, LOCATION_SERVICE_INTERFACE, QDBusConnection::SystemBus); // Register the first session object mock.registerCustomMock(SESSION_NAME, SESSION_PATH.arg(0), SESSION_INTERFACE, QDBusConnection::SystemBus); dbus.startServices(); // Set up the main interface { interface().AddMethod(LOCATION_SERVICE_INTERFACE, "CreateSessionForCriteria", "bbbbdbbb", "o", "ret='/com/ubuntu/location/session/0'"); } // Set up the first session { session(0).AddMethod(SESSION_INTERFACE, "StartPositionUpdates", "", "", ""); session(0).AddMethod(SESSION_INTERFACE, "StopPositionUpdates", "", "", ""); } geoIpServer.setProcessChannelMode(QProcess::ForwardedErrorChannel); geoIpServer.start(GEOIP_SERVER_BINARY); QVERIFY(geoIpServer.waitForStarted()); QVERIFY(geoIpServer.waitForReadyRead()); url = "http://127.0.0.1:" + geoIpServer.readAllStandardOutput().trimmed() + "/lookup"; } void cleanupTestCase() { geoIpServer.terminate(); QVERIFY(geoIpServer.waitForFinished()); } void init() { locationService.reset(new UbuntuLocationService(GeoIp::Ptr(new GeoIp(url)))); } void cleanup() { locationService.reset(); } void compareVariant(const Variant& expected_in, const Variant& actual_in) { VariantMap expected(expected_in.get_dict()); VariantMap actual(actual_in.get_dict()); QVERIFY2( expected.size() <= actual.size(), qPrintable(QString("We need at least %1 entries, had %2").arg( expected.size()).arg(actual.size()))); for(const auto entry: expected) { QVERIFY(actual.find(entry.first) != actual.end()); Variant expectedVariant = entry.second; Variant actualVariant = actual[entry.first]; if (expectedVariant.which() == Variant::Double) { bool comparison = qFuzzyCompare(expectedVariant.get_double(), actualVariant.get_double()); if (!comparison) { qWarning() << "Comparison:" << expectedVariant.get_double() << "!=" << actualVariant.get_double(); } QVERIFY(comparison); } else { QCOMPARE(expectedVariant, actualVariant); } } } void testLocation() { QSignalSpy spy(locationService.data(), SIGNAL(locationChanged())); auto token = locationService->activate(); // The GeoIP HTTP call should return now QVERIFY(spy.wait()); compareVariant(geoip(), Variant(locationService->location().serialize())); // Call the object that the location service client creates QDBusInterface remoteObject(":1.4", SESSION_PATH.arg(0), SESSION_INTERFACE, QDBusConnection::systemBus()); QString errorMessage("never called"); for (int i = 0; i < 10 && !errorMessage.isEmpty(); ++i) { QDBusMessage reply = remoteObject.callWithArgumentList( QDBus::Block, "UpdatePosition", QVariantList() << 1.0 << 2.0 << true << 3.0 << true << 4.0 << true << 5.0 << qint64(1234)); errorMessage = reply.errorMessage(); } QCOMPARE(QString(), errorMessage); // The GPS update should return now QVERIFY(spy.wait()); QTRY_COMPARE((unsigned int) locationService->location().serialize().size(), 12u); compareVariant(gps(), Variant(locationService->location().serialize())); } }; } QTEST_GUILESS_MAIN(LocationTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/filterstest.cpp0000644000015600001650000002045712672630472024075 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pawel Stolowski */ #include #include #include #include #include "filters.h" #include "optionselectorfilter.h" #include using namespace scopes_ng; namespace uss = unity::shell::scopes; class FiltersTest : public QObject { Q_OBJECT private Q_SLOTS: void init() { unity::scopes::FilterState filterState; filtersModel.reset(new Filters(filterState)); f1 = unity::scopes::OptionSelectorFilter::create("f1", "Filter1", false); f1o1 = f1->add_option("o1", "Option1"); f1o2 = f1->add_option("o2", "Option2"); f2 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", false); f2o1 = f2->add_option("o1", "Option1"); f2o2 = f2->add_option("o2", "Option2"); } void testFiltersModelInit() { unity::scopes::FilterState filterState; QSignalSpy filtersSpy(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); { QList backendFilters; backendFilters.append(f1); f1->update_state(filterState, f1o1, true); filtersModel->update(backendFilters); filtersModel->update(filterState); } QCOMPARE(filtersSpy.count(), 1); // 1 filter object added // check filters model data auto idx = filtersModel->index(0, 0); QCOMPARE(filtersModel->rowCount(), 1); QCOMPARE(filtersModel->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); QCOMPARE(filtersModel->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), static_cast(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); // get filter object from the model auto opf = filtersModel->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); QCOMPARE(opf->filterId(), QString("f1")); QCOMPARE(opf->label(), QString("Filter1")); QVERIFY(!opf->multiSelect()); } void testFiltersModelInsert() { QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); { QList backendFilters; backendFilters.append(f1); filtersModel->update(backendFilters); } QCOMPARE(rowsMovedSignal.count(), 0); QCOMPARE(rowsRemovedSignal.count(), 0); QCOMPARE(rowsInsertedSignal.count(), 1); // verify arguments of rowsInsertedSignal { auto args = rowsInsertedSignal.takeFirst(); auto row = args.at(1).toInt(); QCOMPARE(row, 0); } rowsInsertedSignal.clear(); // insert new filter { QList backendFilters; backendFilters.append(f1); backendFilters.append(f2); filtersModel->update(backendFilters); } QCOMPARE(rowsMovedSignal.count(), 0); QCOMPARE(rowsRemovedSignal.count(), 0); QCOMPARE(rowsInsertedSignal.count(), 1); // verify arguments of rowsInsertedSignal { auto args = rowsInsertedSignal.takeFirst(); auto row = args.at(1).toInt(); QCOMPARE(row, 1); } auto idx1 = filtersModel->index(0, 0); auto idx2 = filtersModel->index(1, 0); QCOMPARE(filtersModel->rowCount(), 2); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), static_cast(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); } void testFiltersModelMove() { { QList backendFilters; backendFilters.append(f1); backendFilters.append(f2); filtersModel->update(backendFilters); } QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); // change filters positions { QList backendFilters; backendFilters.append(f2); backendFilters.append(f1); filtersModel->update(backendFilters); } QCOMPARE(rowsInsertedSignal.count(), 0); // no change QCOMPARE(rowsRemovedSignal.count(), 0); QCOMPARE(rowsMovedSignal.count(), 1); QCOMPARE(filtersModel->rowCount(), 2); auto idx1 = filtersModel->index(0, 0); auto idx2 = filtersModel->index(1, 0); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); // verify arguments of rowsMovedSignal { auto args = rowsMovedSignal.takeFirst(); auto srcRow = args.at(1).toInt(); auto dstRow = args.at(4).toInt(); QCOMPARE(srcRow, 0); QCOMPARE(dstRow, 2); } } void testFiltersModelRemove() { { QList backendFilters; backendFilters.append(f2); backendFilters.append(f1); filtersModel->update(backendFilters); } QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); // remove a filter { QList backendFilters; backendFilters.append(f2); // filter1 not present (removed) filtersModel->update(backendFilters); } QCOMPARE(rowsInsertedSignal.count(), 0); QCOMPARE(rowsMovedSignal.count(), 0); QCOMPARE(rowsRemovedSignal.count(), 1); // verify arguments of rowsRemovedSignal { auto args = rowsRemovedSignal.takeFirst(); auto first = args.at(1).toInt(); auto last = args.at(2).toInt(); QCOMPARE(first, 1); QCOMPARE(last, 1); } QCOMPARE(filtersModel->rowCount(), 1); auto idx1 = filtersModel->index(0, 0); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); } private: QScopedPointer filtersModel; unity::scopes::OptionSelectorFilter::SPtr f1, f2; unity::scopes::FilterOption::SCPtr f1o1, f1o2, f2o1, f2o2; }; QTEST_GUILESS_MAIN(FiltersTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/settingstest.cpp0000644000015600001650000002042112672630457024257 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pete Woods */ #include #include #include #include #include using namespace scopes_ng; using namespace unity::shell::scopes; namespace { const static QByteArray BOOLEAN_DEFINITION = R"( [ { "id": "enabledSetting", "displayName": "Enabled", "type": "boolean", "defaultValue": true } ] )"; const static QByteArray LIST_DEFINITION = R"( [ { "id": "unitTempSetting", "displayName": "Temperature Units", "type": "list", "defaultValue": 1, "displayValues": ["Celcius", "Fahrenheit"] } ] )"; const static QByteArray NUMBER_DEFINITION = R"( [ { "id": "ageSetting", "displayName": "Age", "type": "number", "defaultValue": 23 } ] )"; const static QByteArray STRING_DEFINITION = R"( [ { "id": "locationSetting", "displayName": "Location", "type": "string", "defaultValue": "London" } ] )"; const static QByteArray MIXED_DEFINITION = R"( [ { "id": "locationSetting", "displayName": "Location", "type": "string", "defaultValue": "London" }, { "id": "unitTempSetting", "displayName": "Temperature Units", "type": "list", "defaultValue": 1, "displayValues": ["Celcius", "Fahrenheit"] }, { "id": "ageSetting", "displayName": "Age", "type": "number", "defaultValue": 23 }, { "id": "enabledSetting", "displayName": "Enabled", "type": "boolean", "defaultValue": true } ] )"; class SettingsTest: public QObject { Q_OBJECT private: QScopedPointer tempDir; QSharedPointer settings; void newSettingsModel(const QString& id, const QByteArray& json) { QJsonDocument doc = QJsonDocument::fromJson(json); QVariant definitions = doc.toVariant(); settings.reset( new SettingsModel(tempDir->path(), id, definitions, 0, 0)); } void verifyData(int index, const QString& id, const QString& displayName, const QString& type, const QVariant& properties) { QCOMPARE( settings->data(settings->index(index), SettingsModelInterface::RoleSettingId), QVariant(id)); QCOMPARE( settings->data(settings->index(index), SettingsModelInterface::RoleDisplayName), QVariant(displayName)); QCOMPARE( settings->data(settings->index(index), SettingsModelInterface::RoleType), QVariant(type)); QCOMPARE( settings->data(settings->index(index), SettingsModelInterface::RoleProperties), properties); } void verifyValue(int index, const QVariant& value) { // Using this "TRY" macro repeatedly attempts the comparison until a timeout QTRY_COMPARE( settings->data(settings->index(index), SettingsModelInterface::RoleValue), value); } void setValue(int index, const QVariant& value) { QVERIFY(settings->setData(settings->index(index), value, SettingsModelInterface::RoleValue)); } private Q_SLOTS: void init() { tempDir.reset(new QTemporaryDir); } void testBooleanDefinition() { newSettingsModel("boolean", BOOLEAN_DEFINITION); QCOMPARE(settings->rowCount(), 1); // Check the various properties make it through QVariantMap properties; properties["defaultValue"] = true; verifyData(0, "enabledSetting", "Enabled", "boolean", properties); verifyValue(0, true); } void testListDefinition() { newSettingsModel("list", LIST_DEFINITION); QCOMPARE(settings->rowCount(), 1); // Check the various properties make it through QVariantMap properties; properties["defaultValue"] = 1; properties["values"] = QVariantList() << "Celcius" << "Fahrenheit"; verifyData(0, "unitTempSetting", "Temperature Units", "list", properties); // Check the default value verifyValue(0, 1); } void testNumberDefinition() { newSettingsModel("number", NUMBER_DEFINITION); QCOMPARE(settings->rowCount(), 1); // Check the various properties make it through QVariantMap properties; properties["defaultValue"] = 23; verifyData(0, "ageSetting", "Age", "number", properties); // Check the default value verifyValue(0, 23); } void testStringDefinition() { newSettingsModel("string", STRING_DEFINITION); QCOMPARE(settings->rowCount(), 1); // Check the various properties make it through QVariantMap properties; properties["defaultValue"] = "London"; verifyData(0, "locationSetting", "Location", "string", properties); // Check the default value verifyValue(0, "London"); } void testMixedDefinition() { newSettingsModel("mixed", MIXED_DEFINITION); QCOMPARE(settings->rowCount(), 4); { QVariantMap properties; properties["defaultValue"] = "London"; verifyData(0, "locationSetting", "Location", "string", properties); verifyValue(0, "London"); } { QVariantMap properties; properties["defaultValue"] = 1; properties["values"] = QVariantList() << "Celcius" << "Fahrenheit"; verifyData(1, "unitTempSetting", "Temperature Units", "list", properties); verifyValue(1, 1); } { QVariantMap properties; properties["defaultValue"] = 23; verifyData(2, "ageSetting", "Age", "number", properties); verifyValue(2, 23); } { QVariantMap properties; properties["defaultValue"] = true; verifyData(3, "enabledSetting", "Enabled", "boolean", properties); verifyValue(3, true); } } void testUpdateValue() { // Create an initial settings model newSettingsModel("update", MIXED_DEFINITION); // Verify the initial values verifyValue(0, "London"); verifyValue(1, 1); verifyValue(2, 23); verifyValue(3, true); // Update the string value setValue(0, "Banana"); verifyValue(0, "Banana"); // Update the list value setValue(1, 0); verifyValue(1, 0); // Update the number value setValue(2, 123); verifyValue(2, 123); // Update the boolean value setValue(3, false); verifyValue(3, false); // Make a new settings model to check the settings were saved to disk newSettingsModel("update", MIXED_DEFINITION); verifyValue(0, "Banana"); verifyValue(1, 0); verifyValue(2, 123); verifyValue(3, false); } void testReadUnicode() { QDir configDir(tempDir->path()); QDir iniDir(configDir.filePath("unicode")); QString iniFile = iniDir.filePath("settings.ini"); QVERIFY(configDir.mkpath("unicode")); QVERIFY(QFile::copy(TEST_SETTINGS_UNICODE, iniFile)); // Create an initial settings model newSettingsModel("unicode", STRING_DEFINITION); // Verify the initial values verifyValue(0, "北京京"); } }; } QTEST_GUILESS_MAIN(SettingsTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/favoritestest.cpp0000644000015600001650000002346312672630457024432 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pawel Stolowski */ #include #include #include #include #include #include #include #include #include #include #include namespace ng = scopes_ng; namespace sh = unity::scopeharness; namespace shr = unity::scopeharness::registry; using namespace unity::shell::scopes; class FavoritesTest: public QObject { Q_OBJECT private: QScopedPointer m_scopes; ng::Scope* m_overviewScope; shr::Registry::UPtr m_registry; private Q_SLOTS: void initTestCase() { m_registry.reset(new shr::PreExistingRegistry(TEST_RUNTIME_CONFIG)); m_registry->start(); } void cleanupTestCase() { m_registry.reset(); } void init() { sh::TestUtils::setFavouriteScopes(QStringList()); m_scopes.reset(new ng::Scopes(nullptr)); // no scopes on startup QCOMPARE(m_scopes->rowCount(), 0); QCOMPARE(m_scopes->loaded(), false); QSignalSpy spy(m_scopes.data(), SIGNAL(loadedChanged())); // wait till the registry spawns QVERIFY(spy.wait()); QCOMPARE(m_scopes->loaded(), true); // no scopes after startup, since favorites empty QCOMPARE(m_scopes->rowCount(), 0); // get overview scope proxy m_overviewScope = qobject_cast(m_scopes->overviewScope()); QVERIFY(m_overviewScope!= nullptr); m_overviewScope->setActive(true); } void testFavoritePropertyUpdates() { QStringList favs; favs << "scope://mock-scope-departments"; sh::TestUtils::setFavouriteScopes(favs); // should have one scope now QTRY_COMPARE(m_scopes->rowCount(), 1); auto scope1 = qobject_cast(m_scopes->getScope(QString("mock-scope-departments"))); QVERIFY(scope1 != nullptr); QCOMPARE(scope1->favorite(), true); favs << "scope://mock-scope-double-nav"; sh::TestUtils::setFavouriteScopes(favs); // should have two scopes now QTRY_COMPARE(m_scopes->rowCount(), 2); auto scope2 = qobject_cast(m_scopes->getScope(QString("mock-scope-double-nav"))); QVERIFY(scope2 != nullptr); QCOMPARE(scope2->favorite(), true); // unfavorite 1st scope QSignalSpy spy(scope1, SIGNAL(favoriteChanged(bool))); QSignalSpy spy2(scope1, SIGNAL(destroyed(QObject *))); scope1->setFavorite(false); QTRY_COMPARE(spy.count(), 1); QTRY_COMPARE(m_scopes->rowCount(), 1); QVERIFY(m_scopes->getScopeById("mock-scope-departments") == nullptr); QCOMPARE(m_scopes->data(m_scopes->index(0), ng::Scopes::RoleId), QVariant(QString("mock-scope-double-nav"))); // the scope should be destroyed after un-favoriting QTRY_COMPARE(spy2.count(), 1); // favorite a scope auto overviewScope = m_scopes->overviewScope(); QVERIFY(overviewScope != nullptr); connect(overviewScope, &unity::shell::scopes::ScopeInterface::openScope, [](unity::shell::scopes::ScopeInterface* scope) { QCOMPARE(scope->favorite(), false); scope->setFavorite(true); }); QVERIFY(m_scopes->getScopeById("mock-scope") == nullptr); overviewScope->performQuery("scope://mock-scope"); QTRY_VERIFY(m_scopes->getScopeById("mock-scope") != nullptr); } void testFavoritesOverviewUpdates() { auto categories = m_overviewScope->categories(); QVERIFY(categories->rowCount() > 0); QCOMPARE(categories->data(categories->index(0), ng::Categories::Roles::RoleCategoryId), QVariant(QString("favorites"))); QVariant results_var = categories->data(categories->index(0), ng::Categories::Roles::RoleResults); QVERIFY(results_var.canConvert()); ng::OverviewResultsModel* results = results_var.value(); QCOMPARE(results->rowCount(), 0); // favorite one scope, check if it appears in the favorites model QStringList favs; favs << "scope://mock-scope-departments"; sh::TestUtils::setFavouriteScopes(favs); QTRY_COMPARE(results->rowCount(), 1); // unfavorite it, verify it disappears from favorites model sh::TestUtils::setFavouriteScopes(QStringList()); QTRY_COMPARE(results->rowCount(), 0); } void testFavoritesReordering() { QStringList favs; favs << "scope://mock-scope-departments" << "scope://mock-scope-double-nav" << "scope://mock-scope"; sh::TestUtils::setFavouriteScopes(favs); // should have one scope now QTRY_COMPARE(m_scopes->rowCount(), 3); QTRY_COMPARE(qobject_cast(m_scopes->getScope(0))->id(), QString("mock-scope-departments")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(1))->id(), QString("mock-scope-double-nav")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(2))->id(), QString("mock-scope")); { QSignalSpy spy(m_scopes.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); m_scopes->moveFavoriteTo("mock-scope", 1); // check new positions QTRY_COMPARE(spy.count(), 1); QTRY_COMPARE(qobject_cast(m_scopes->getScope(0))->id(), QString("mock-scope-departments")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(1))->id(), QString("mock-scope")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(2))->id(), QString("mock-scope-double-nav")); // check overview model auto categories = m_overviewScope->categories(); QVERIFY(categories->rowCount() > 0); QCOMPARE(categories->data(categories->index(0), ng::Categories::Roles::RoleCategoryId), QVariant(QString("favorites"))); QVariant results_var = categories->data(categories->index(0), ng::Categories::Roles::RoleResults); QVERIFY(results_var.canConvert()); ng::OverviewResultsModel* results = results_var.value(); QTRY_COMPARE(results->rowCount(), 3); QTRY_COMPARE(results->data(results->index(0), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope-departments"))); QTRY_COMPARE(results->data(results->index(1), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope"))); QTRY_COMPARE(results->data(results->index(2), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope-double-nav"))); } { QSignalSpy spy(m_scopes.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); m_scopes->moveFavoriteTo("mock-scope", 2); // check new positions QTRY_COMPARE(spy.count(), 1); QTRY_COMPARE(qobject_cast(m_scopes->getScope(0))->id(), QString("mock-scope-departments")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(1))->id(), QString("mock-scope-double-nav")); QTRY_COMPARE(qobject_cast(m_scopes->getScope(2))->id(), QString("mock-scope")); // check overview model auto categories = m_overviewScope->categories(); QVERIFY(categories->rowCount() > 0); QCOMPARE(categories->data(categories->index(0), ng::Categories::Roles::RoleCategoryId), QVariant(QString("favorites"))); QVariant results_var = categories->data(categories->index(0), ng::Categories::Roles::RoleResults); QVERIFY(results_var.canConvert()); ng::OverviewResultsModel* results = results_var.value(); QTRY_COMPARE(results->rowCount(), 3); QTRY_COMPARE(results->data(results->index(0), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope-departments"))); QTRY_COMPARE(results->data(results->index(1), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope-double-nav"))); QTRY_COMPARE(results->data(results->index(2), ng::OverviewResultsModel::RoleScopeId), QVariant(QString("mock-scope"))); } } void testGSettingsUpdates() { QStringList favs; favs << "scope://mock-scope-departments" << "scope://mock-scope-double-nav"; sh::TestUtils::setFavouriteScopes(favs); // should have two scopes QTRY_COMPARE(m_scopes->rowCount(), 2); auto scope1 = qobject_cast(m_scopes->getScope(QString("mock-scope-departments"))); QVERIFY(scope1 != nullptr); // un-favorite one scope scope1->setFavorite(false); QTRY_COMPARE(sh::TestUtils::getFavoriteScopes().size(), 1); QCOMPARE(sh::TestUtils::getFavoriteScopes().at(0), QString("scope://mock-scope-double-nav")); } void cleanup() { m_scopes.reset(); } }; QTEST_GUILESS_MAIN(FavoritesTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/data/0000755000015600001650000000000012672635475021732 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-filters/0000755000015600001650000000000012672635475025440 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-filters/mock-scope-filters.ini.in0000644000015600001650000000042712672630472032247 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-scope-filters.DisplayName Description = mock-scope-filters.Description Art = /mock-scope-filters.Art Icon = /mock-scope-filters.Icon SearchHint = mock-scope-filters.SearchHint HotKey = mock-scope-filters.HotKey Author = mock-scope-filters.Author unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-filters/CMakeLists.txt0000644000015600001650000000066612672630472030200 0ustar pbuserpbgroup00000000000000pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.6.15) set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-filters.cpp ) add_library(mock-scope-filters MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-filters ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-filters.ini.in mock-scope-filters.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-filters/mock-scope-filters.cpp0000644000015600001650000000763312672630472031653 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Pawel Stolowski */ #include #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata) : SearchQueryBase(query, metadata) { } ~MyQuery() { } virtual void cancelled() override { } virtual void run(SearchReplyProxy const& reply) override { OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("f1", "Filter1"); if (query().query_string() == "test_primary_filter") { filter1->set_display_hints(FilterBase::DisplayHints::Primary); } auto opt1 = filter1->add_option("o1", "Option1"); filter1->add_option("o2", "Option2"); RangeInputFilter::SPtr filter2 = RangeInputFilter::create("f2", Variant(2.0f), Variant::null(), "start", "", "", "end", ""); auto cat1 = reply->register_category("cat1", "Category 1", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); auto selected = filter1->active_options(query().filter_state()); if (selected.size() == 1) { res1.set_title("result for option " + (*selected.begin())->id()); } else { res1.set_title("result for: \"" + query().query_string() + "\""); } bool has_start_val = filter2->has_start_value(query().filter_state()); bool has_end_val = filter2->has_end_value(query().filter_state()); if (has_start_val || has_end_val) { res1.set_title("result for range: " + (has_start_val ? std::to_string(filter2->start_value(query().filter_state())) : "***") + " - " + (has_end_val ? std::to_string(filter2->end_value(query().filter_state())) : "***")); } ValueSliderFilter::SPtr filter3 = ValueSliderFilter::create("f3", 1, 99, 50, ValueSliderLabels("Min", "Max", {{33, "One third"}})); Filters filters; filters.push_back(std::move(filter1)); filters.push_back(std::move(filter2)); filters.push_back(std::move(filter3)); reply->push(filters, query().filter_state()); reply->push(res1); } }; class MyScope : public ScopeBase { public: MyScope() { } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { return SearchQueryBase::UPtr(new MyQuery(q, metadata)); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-ttl/0000755000015600001650000000000012672635475024573 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-ttl/mock-scope-ttl.cpp0000644000015600001650000000475612672630457030147 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Pete Woods */ #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata, string const& result) : SearchQueryBase(query, metadata), result_(result) { } ~MyQuery() { } virtual void cancelled() override { } virtual void run(SearchReplyProxy const& reply) override { auto cat = reply->register_category("cat1", "Category 1", ""); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title(result_); reply->push(res); } protected: string result_; }; class MyScope : public ScopeBase { public: MyScope() : counter_(0) { } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { stringstream builder; builder << q.query_string(); builder << counter_++; return SearchQueryBase::UPtr(new MyQuery(q, metadata, builder.str())); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } protected: atomic counter_; }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-ttl/mock-scope-ttl.ini.in0000644000015600001650000000023212672630457030532 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-ttl.DisplayName Description = mock-ttl.Description Icon = /mock-ttl.Icon Author = mock-ttl.Author ResultsTtlType = Small unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-ttl/CMakeLists.txt0000644000015600001650000000054312672630457027330 0ustar pbuserpbgroup00000000000000set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-ttl.cpp ) add_library(mock-scope-ttl MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-ttl ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-ttl.ini.in mock-scope-ttl.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/0000755000015600001650000000000012672635475030127 5ustar pbuserpbgroup00000000000000././@LongLink0000000000000000000000000000016700000000000011221 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/mock-scope-departments-flipflop.cppunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/mock-scope-depart0000644000015600001650000000737612672630457033377 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Pete Woods */ #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata, bool flipflop) : SearchQueryBase(query, metadata), flipflop_(flipflop) { } ~MyQuery() { } virtual void cancelled() override { } Department::SPtr create_root_dep(CannedQuery const& query) { Department::SPtr child_dep; Department::SPtr root_dep; root_dep = Department::create("", query, "All departments"); child_dep = Department::create("books", query, "Books"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("movies", query, "Movies, TV, Music"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); if (flipflop_) { child_dep = Department::create("electronics", query, "Electronics"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); } child_dep = Department::create("home", query, "Home, Garden & DIY"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("toys", query, "Toys, Children & Baby"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); return root_dep; } virtual void run(SearchReplyProxy const& reply) override { Department::SPtr child_dep; Department::SPtr root_dep; Department::SPtr active_dep; root_dep = create_root_dep(query()); reply->register_departments(root_dep); auto cat1 = reply->register_category("cat1", "Category 1", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query().query_string() + "\""); reply->push(res1); } protected: bool flipflop_; }; class MyScope : public ScopeBase { public: MyScope() { flipflop_ = false; } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { flipflop_ = !flipflop_; return SearchQueryBase::UPtr(new MyQuery(q, metadata, flipflop_)); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } std::atomic flipflop_; }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } ././@LongLink0000000000000000000000000000017200000000000011215 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/mock-scope-departments-flipflop.ini.inunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/mock-scope-depart0000644000015600001650000000051012672630457033356 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-departments-flipflop.DisplayName Description = mock-departments-flipflop.Description Art = /mock-departments-flipflop.Art Icon = /mock-departments-flipflop.Icon SearchHint = mock-departments-flipflop.SearchHint HotKey = mock-departments-flipflop.HotKey Author = mock-departments-flipflop.Author unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments-flipflop/CMakeLists.txt0000644000015600001650000000067012672630457032665 0ustar pbuserpbgroup00000000000000set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-departments-flipflop.cpp ) add_library(mock-scope-departments-flipflop MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-departments-flipflop ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-departments-flipflop.ini.in mock-scope-departments-flipflop.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/settings-unicode.ini0000644000015600001650000000004312672630457025707 0ustar pbuserpbgroup00000000000000[General] locationSetting=北京京unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-info/0000755000015600001650000000000012672635475024723 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-info/mock-scope-info.cpp0000644000015600001650000000625212672630457030420 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Marcus Tomlinson */ #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata) : SearchQueryBase(query, metadata) , m_query(query.query_string()) { } ~MyQuery() { } virtual void cancelled() override { } virtual void run(SearchReplyProxy const& reply) override { // No info (Status::Okay) if (m_query == "no_info") { } // NoInternet (Status::NoInternet) if (m_query == "no_internet") { reply->info(OperationInfo{OperationInfo::NoInternet}); } // NoLocationData (Status::NoLocationData) if (m_query == "no_location") { reply->info(OperationInfo{OperationInfo::NoLocationData}); } // DefaultSettingsUsed (unknown to shell but known to run-time so Status::Okay) if (m_query == "shell_unknown") { reply->info(OperationInfo{OperationInfo::DefaultSettingsUsed}); } // DefaultSettingsUsed (unknown to runtime so Status::Unknown) if (m_query == "runtime_unknown") { reply->info(OperationInfo{static_cast(OperationInfo::LastInfoCode_ + 1)}); } // NoLocationData and NoInternet (Status::NoInternet takes priority) if (m_query == "no_location_no_internet") { reply->info(OperationInfo{OperationInfo::NoLocationData}); reply->info(OperationInfo{OperationInfo::NoInternet}); } } private: std::string m_query; }; class MyScope : public ScopeBase { public: MyScope() { } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { return SearchQueryBase::UPtr(new MyQuery(q, metadata)); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-info/CMakeLists.txt0000644000015600001650000000055012672630457027456 0ustar pbuserpbgroup00000000000000set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-info.cpp ) add_library(mock-scope-info MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-info ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-info.ini.in mock-scope-info.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-info/mock-scope-info.ini.in0000644000015600001650000000020712672630457031014 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-info.DisplayName Description = mock-info.Description Icon = /mock-info.Icon Author = mock-info.Author unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-double-nav/0000755000015600001650000000000012672635475026024 5ustar pbuserpbgroup00000000000000././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-double-nav/mock-scope-double-nav.ini.inunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-double-nav/mock-scope-double-nav.ini.i0000644000015600001650000000040212672630457033035 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-double-nav.DisplayName Description = mock-double-nav.Description Art = /mock-double-nav.Art Icon = /mock-double-nav.Icon SearchHint = mock-double-nav.SearchHint HotKey = mock-double-nav.HotKey Author = mock-double-nav.Author unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-double-nav/mock-scope-double-nav.cpp0000644000015600001650000001552212672630457032622 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Pete Woods */ #include #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata) : SearchQueryBase(query, metadata), department_id_(query.department_id()) { } ~MyQuery() { } virtual void cancelled() override { } static Department::SPtr create_root_dep(CannedQuery const& query) { Department::SPtr child_dep; Department::SPtr root_dep; root_dep = Department::create("", query, "All departments"); child_dep = Department::create("books", query, "Books"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("movies", query, "Movies, TV, Music"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("electronics", query, "Electronics"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("home", query, "Home, Garden & DIY"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("toys", query, "Toys, Children & Baby"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); return root_dep; } static Department::SPtr get_department_by_id(Department::SPtr root_dep, std::string const& dep_id) { auto children = root_dep->subdepartments(); for (auto it = children.begin(); it != children.end(); ++it) { if ((*it)->id() == dep_id) return const_pointer_cast(*it); } return Department::SPtr(); } virtual void run(SearchReplyProxy const& reply) override { Department::SPtr child_dep; Department::SPtr root_dep; Department::SPtr active_dep; root_dep = create_root_dep(query()); if (department_id_.compare(0, 5, "books") == 0) { active_dep = get_department_by_id(root_dep, "books"); child_dep = Department::create("books-kindle", query(), "Kindle Books"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("books-study", query(), "Books for Study"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("books-audio", query(), "Audiobooks"); active_dep->add_subdepartment(child_dep); } if (department_id_.compare(0, 4, "home") == 0) { active_dep = get_department_by_id(root_dep, "home"); child_dep = Department::create("home-garden", query(), "Garden & Outdoors"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("home-furniture", query(), "Homeware & Furniture"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("home-kitchen", query(), "Kitchen & Dining"); active_dep->add_subdepartment(child_dep); } if (department_id_.compare(0, 4, "toys") == 0) { active_dep = get_department_by_id(root_dep, "toys"); child_dep = Department::create("toys-games", query(), "Toys & Games"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("toys-baby", query(), "Baby"); active_dep->add_subdepartment(child_dep); } // provide only partial tree for this leaf if (department_id_ == "toys-games") { root_dep = Department::create("", query(), "All departments"); child_dep = Department::create("toys", query(), "Toys, Children & Baby"); root_dep->add_subdepartment(child_dep); active_dep = Department::create("toys-games", query(), "Toys & Games"); child_dep->add_subdepartment(active_dep); } reply->register_departments(root_dep); // add sort order filter OptionSelectorFilter::UPtr sort_order_filter = OptionSelectorFilter::create("sort-order", "Sort Order"); sort_order_filter->set_display_hints(FilterBase::Primary); sort_order_filter->add_option("featured", "Featured"); sort_order_filter->add_option("top", "Most popular"); sort_order_filter->add_option("best", "Best sellers"); Filters filters; filters.push_back(std::move(sort_order_filter)); FilterState state; FilterState initial_filter_state(query().filter_state()); if (initial_filter_state.has_filter("sort-order")) { state = initial_filter_state; } else { // default option OptionSelectorFilter::update_state(state, "sort-order", "featured", true); } reply->push(filters, state); auto cat1 = reply->register_category("cat1", "Category 1", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query().query_string() + "\""); reply->push(res1); } protected: string department_id_; }; class MyScope : public ScopeBase { public: MyScope() { } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { return SearchQueryBase::UPtr(new MyQuery(q, metadata)); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-double-nav/CMakeLists.txt0000644000015600001650000000060612672630457030561 0ustar pbuserpbgroup00000000000000set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-double-nav.cpp ) add_library(mock-scope-double-nav MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-double-nav ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-double-nav.ini.in mock-scope-double-nav.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/Runtime.ini.in0000644000015600001650000000032112672630457024452 0ustar pbuserpbgroup00000000000000[Runtime] Registry.Identity = Registry Registry.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Registry.ini Default.Middleware = Zmq Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini Smartscopes.Registry.Identity =unity-scopes-shell-0.5.7+16.04.20160317/tests/data/Zmq.ini.in0000644000015600001650000000005712672630457023604 0ustar pbuserpbgroup00000000000000[Zmq] EndpointDir = /tmp/scopes-test-endpoints unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-manyresults/0000755000015600001650000000000012672635475026356 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-manyresults/mock-scope-manyresults.cpp0000644000015600001650000003006712672630457033507 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pawel Stolowski */ #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; // Example scope A: replies synchronously to a query. (Replies are returned before returning from the run() method.) class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata, VariantMap const& settings) : SearchQueryBase(query, metadata), query_(query.query_string()), settings_(settings) { } ~MyQuery() noexcept { } virtual void cancelled() override { } virtual void run(SearchReplyProxy const& reply) override { CategoryRenderer meta_rndr(R"({"schema-version": 1, "components": {"title": "title", "art": "art", "subtitle": "subtitle", "emblem": "icon", "mascot": "mascot"}})"); auto cat1 = reply->register_category("cat1", "Category 1", "", meta_rndr); auto cat2 = reply->register_category("cat2", "Category 2", "", meta_rndr); if (query_ == "") { // 2000 items for (int i = 0; i<200; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } if (query_ == "search1") { // five results with uris 0..4 in a single category cat1 for (int i = 0; i<5; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result " + std::to_string(i) + " for: \"" + query_ + "\""); reply->push(res); } std::this_thread::sleep_for(std::chrono::seconds(1)); } else if (query_ == "search2") { const int start = 3; // five results with uris 3..7 in categories cat1 and cat2 for (int i = 0; i<5; i++) { { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(start + i)); res.set_title("result " + std::to_string(start + i) + " for: \"" + query_ + "\""); reply->push(res); } { CategorisedResult res(cat2); res.set_uri("cat2_uri" + std::to_string(start + i)); res.set_title("result " + std::to_string(start + i) + " for: \"" + query_ + "\""); reply->push(res); } std::this_thread::sleep_for(std::chrono::milliseconds(30)); } } else if (query_ == "search3") { const int start = 3; // five results with uris 7..3 in categories cat1 and cat2 for (int i = 4; i>=0; i--) { { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(start + i)); res.set_title("result " + std::to_string(start + i) + " for: \"" + query_ + "\""); reply->push(res); } { CategorisedResult res(cat2); res.set_uri("cat2_uri" + std::to_string(start + i)); res.set_title("result " + std::to_string(start + i) + " for: \"" + query_ + "\""); reply->push(res); } std::this_thread::sleep_for(std::chrono::milliseconds(30)); } } else if (query_ == "search4") { // one result with uri 5 in cat2 { CategorisedResult res(cat2); res.set_uri("cat2_uri5"); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); } } else if (query_ == "lots_of_results") { // 2000 items for (int i = 0; i<2000; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } else if (query_ == "lots_of_results_reversed") { // 2000 items, in the reversed order of search5 for (int i = 1999; i>=0; i--) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } else if (query_ == "lots_of_results_reversed_plus_some") { // 2100 items, in the reversed order of search5, plus 100 extra results for (int i = 2099; i>=0; i--) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } else if (query_ == "lots_of_results_half_of_them_missing") { // 1000 items with uris matching every other item from previous search for (int i = 0; i<1000; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i*2)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } else if (query_ == "lots_of_results_2") { // 2000 items, all different than in previous searches for (int i = 0; i<2000; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(5000 + i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); if (i % 100 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } else if (query_ == "lots_of_results_fast") { // 100 items for (int i = 0; i<10; i++) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); } } else if (query_ == "lots_of_results_reversed_fast") { // 100 items, in the reversed order of search5 for (int i = 9; i>=0; i--) { CategorisedResult res(cat1); res.set_uri("cat1_uri" + std::to_string(i)); res.set_title("result5 for: \"" + query_ + "\""); reply->push(res); } } else if (query_ == "duplicated_uris1") { for (int i = 0; i<10; i++) { CategorisedResult res(cat1); res.set_uri("uri"); res.set_title("result " + std::to_string(i)); reply->push(res); } } else if (query_ == "duplicated_uris2") { for (int i = 0; i<10; i++) { CategorisedResult res(cat1); if (i % 2 == 0) { // every other result uses same uri res.set_uri("uri"); } else { res.set_uri("uri" + std::to_string(i)); } res.set_title("result " + std::to_string(i)); reply->push(res); } } else if (query_ == "duplicated_results") { for (int i = 0; i<2; i++) { CategorisedResult res(cat1); res.set_uri("uri"); res.set_title("result"); reply->push(res); } } else if (query_ == "two-categories") { auto cat3 = reply->register_category("cat3", "Category 3", "", meta_rndr); for (int i = 0; i<10; i++) { CategorisedResult res(cat1); res.set_uri("uri" + std::to_string(i)); res.set_title("result " + std::to_string(i)); reply->push(res); CategorisedResult res2(cat3); res2.set_uri("uri" + std::to_string(i)); res2.set_title("result " + std::to_string(i)); reply->push(res2); } } else if (query_ == "two-categories-second-gone") { for (int i = 0; i<10; i++) { CategorisedResult res(cat1); res.set_uri("uri" + std::to_string(i)); res.set_title("result " + std::to_string(i)); reply->push(res); } } else if (query_.find("random") == 0) // "random", followed by an int for the number of results { auto rand_start = rand() % 30; for (int i = 0; ipush(res); if (i % 2 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(40)); } } } } private: string query_; VariantMap settings_; }; class MyPreview : public PreviewQueryBase { public: MyPreview(Result const& result, ActionMetadata const& metadata) : PreviewQueryBase(result, metadata), scope_data_(metadata.scope_data()) { } ~MyPreview() noexcept { } virtual void cancelled() override { } virtual void run(PreviewReplyProxy const&) override { } private: Variant scope_data_; }; class MyScope : public ScopeBase { public: virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { SearchQueryBase::UPtr query(new MyQuery(q, metadata, settings())); return query; } virtual PreviewQueryBase::UPtr preview(Result const& result, ActionMetadata const& metadata) override { PreviewQueryBase::UPtr query(new MyPreview(result, metadata)); return query; } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-manyresults/mock-scope-manyresults.ini.inunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-manyresults/mock-scope-manyresults.ini0000644000015600001650000000060012672630457033472 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock.DisplayName Description = mock.Description Art = /mock.Art Icon = /mock.Icon SearchHint = mock.SearchHint HotKey = mock.HotKey Author = mock.Author [Appearance] PageHeader.Logo = http://assets.ubuntu.com/sites/ubuntu/1110/u/img/logos/logo-ubuntu-orange.svg PageHeader.ForegroundColor = white PageHeader.Background = color://black ShapeImages = false unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-manyresults/CMakeLists.txt0000644000015600001650000000040312672630457031106 0ustar pbuserpbgroup00000000000000include_directories(${SCOPESLIB_INCLUDE_DIRS}) add_library(mock-scope-manyresults MODULE mock-scope-manyresults.cpp) target_link_libraries(mock-scope-manyresults ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-manyresults.ini.in mock-scope-manyresults.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/0000755000015600001650000000000012672635475026316 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/mock-scope-departments.cpp0000644000015600001650000001444112672630457033405 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Pete Woods */ #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata) : SearchQueryBase(query, metadata), department_id_(query.department_id()) { } ~MyQuery() { } virtual void cancelled() override { } static Department::SPtr create_root_dep(CannedQuery const& query) { Department::SPtr child_dep; Department::SPtr root_dep; root_dep = Department::create("", query, "All departments"); child_dep = Department::create("books", query, "Books"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("movies", query, "Movies, TV, Music"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("electronics", query, "Electronics"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("home", query, "Home, Garden & DIY"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); child_dep = Department::create("toys", query, "Toys, Children & Baby"); child_dep->set_has_subdepartments(); root_dep->add_subdepartment(child_dep); return root_dep; } static Department::SPtr get_department_by_id(Department::SPtr root_dep, std::string const& dep_id) { auto children = root_dep->subdepartments(); for (auto it = children.begin(); it != children.end(); ++it) { if ((*it)->id() == dep_id) return const_pointer_cast(*it); } return Department::SPtr(); } virtual void run(SearchReplyProxy const& reply) override { Department::SPtr child_dep; Department::SPtr root_dep; Department::SPtr active_dep; root_dep = create_root_dep(query()); if (department_id_.compare(0, 5, "books") == 0) { active_dep = get_department_by_id(root_dep, "books"); child_dep = Department::create("books-kindle", query(), "Kindle Books"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("books-study", query(), "Books for Study"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("books-audio", query(), "Audiobooks"); active_dep->add_subdepartment(child_dep); } if (department_id_.compare(0, 4, "home") == 0) { active_dep = get_department_by_id(root_dep, "home"); child_dep = Department::create("home-garden", query(), "Garden & Outdoors"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("home-furniture", query(), "Homeware & Furniture"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("home-kitchen", query(), "Kitchen & Dining"); active_dep->add_subdepartment(child_dep); } if (department_id_.compare(0, 4, "toys") == 0) { active_dep = get_department_by_id(root_dep, "toys"); child_dep = Department::create("toys-games", query(), "Toys & Games"); active_dep->add_subdepartment(child_dep); child_dep = Department::create("toys-baby", query(), "Baby"); active_dep->add_subdepartment(child_dep); } // provide only partial tree for this leaf if (department_id_ == "toys-games") { root_dep = Department::create("", query(), "All departments"); child_dep = Department::create("toys", query(), "Toys, Children & Baby"); root_dep->add_subdepartment(child_dep); active_dep = Department::create("toys-games", query(), "Toys & Games"); child_dep->add_subdepartment(active_dep); } reply->register_departments(root_dep); auto cat1 = reply->register_category("cat1", "Category 1", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query().query_string() + "\", department \"" + department_id_ + "\""); reply->push(res1); } protected: string department_id_; }; class MyScope : public ScopeBase { public: MyScope() { } virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { return SearchQueryBase::UPtr(new MyQuery(q, metadata)); } virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override { return nullptr; } virtual ChildScopeList find_child_scopes() const { ChildScopeList list; list.push_back({"mock-scope-double-nav", registry()->get_metadata("mock-scope-double-nav"), true}); list.push_back({"mock-scope", registry()->get_metadata("mock-scope"), true}); return list; } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } ././@LongLink0000000000000000000000000000015600000000000011217 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/mock-scope-departments-settings.iniunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/mock-scope-departments-set0000644000015600001650000000024012672630457033405 0ustar pbuserpbgroup00000000000000[string-setting] type = string defaultValue = Hello displayName = String Setting [number-setting] type = number defaultValue = 13 displayName = Number Setting ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/mock-scope-departments.ini.inunity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/mock-scope-departments.ini0000644000015600001650000000043512672630457033400 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock-departments.DisplayName Description = mock-departments.Description Art = /mock-departments.Art Icon = /mock-departments.Icon SearchHint = mock-departments.SearchHint HotKey = mock-departments.HotKey Author = mock-departments.Author IsAggregator = true unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope-departments/CMakeLists.txt0000644000015600001650000000074312672630457031055 0ustar pbuserpbgroup00000000000000set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) include_directories(${SCOPESLIB_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(SCOPE_SOURCES mock-scope-departments.cpp ) add_library(mock-scope-departments MODULE ${SCOPE_SOURCES}) target_link_libraries(mock-scope-departments ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope-departments.ini.in mock-scope-departments.ini) configure_file(mock-scope-departments-settings.ini mock-scope-departments-settings.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/CMakeLists.txt0000644000015600001650000000104312672630472024460 0ustar pbuserpbgroup00000000000000add_subdirectory(mock-scope) add_subdirectory(mock-scope-departments) add_subdirectory(mock-scope-departments-flipflop) add_subdirectory(mock-scope-double-nav) add_subdirectory(mock-scope-info) add_subdirectory(mock-scope-ttl) add_subdirectory(mock-scope-filters) add_subdirectory(mock-scope-manyresults) configure_file(Runtime.ini.in Runtime.ini @ONLY) configure_file(Registry.ini.in Registry.ini @ONLY) configure_file(Zmq.ini.in Zmq.ini @ONLY) #execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/endpoints) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope/0000755000015600001650000000000012672635475023772 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope/mock-scope.cpp0000644000015600001650000005641612672630457026545 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #define EXPORT __attribute__ ((visibility ("default"))) using namespace std; using namespace unity::scopes; // Example scope A: replies synchronously to a query. (Replies are returned before returning from the run() method.) class MyQuery : public SearchQueryBase { public: MyQuery(CannedQuery const& query, SearchMetadata const& metadata, VariantMap const& settings) : SearchQueryBase(query, metadata), query_(query.query_string()), department_id_(query.department_id()), settings_(settings) { } ~MyQuery() noexcept { } virtual void cancelled() override { } virtual void run(SearchReplyProxy const& reply) override { if (query_ == "metadata") { CategoryRenderer meta_rndr(R"({"schema-version": 1, "components": {"title": "title", "art": "art", "subtitle": "subtitle", "emblem": "icon", "mascot": "mascot"}})"); auto cat = reply->register_category("cat1", "Category 1", "", meta_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); res["subtitle"] = "subtitle"; res["icon"] = "emblem"; reply->push(res); } else if (query_ == "rating") { CategoryRenderer rating_rndr(R"({"schema-version": 1, "components": {"title": "title", "attributes": "attributes"}})"); auto cat = reply->register_category("cat1", "Category 1", "", rating_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); VariantBuilder attribute_builder; attribute_builder.add_tuple({{"value", Variant("21 reviews")}}); res["attributes"] = attribute_builder.end(); reply->push(res); } else if (query_ == "attributes") { CategoryRenderer rating_rndr(R"({"schema-version": 1, "components": {"title": "title", "attributes": {"field": "attributes", "max-count":3}}})"); auto cat = reply->register_category("cat1", "Category 1", "", rating_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); VariantBuilder attribute_builder; attribute_builder.add_tuple({{"value", Variant("21 reviews")}}); attribute_builder.add_tuple({{"value", Variant("4 comments")}}); attribute_builder.add_tuple({{"value", Variant("28 stars")}}); attribute_builder.add_tuple({{"value", Variant("foobar")}}); res["attributes"] = attribute_builder.end(); reply->push(res); } else if (query_ == "background") { CategoryRenderer bkgr_rndr(R"({"schema-version": 1, "template": {"card-background": "color:///black"}, "components": {"title": "title", "background": "background"}})"); auto cat = reply->register_category("cat1", "Category 1", "", bkgr_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_dnd_uri("test:dnd_uri"); res["background"] = "gradient:///green/#ff00aa33"; reply->push(res); } else if (query_ == "minimal") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); reply->push(res); } else if (query_ == "music") { CategoryRenderer music_rndr(R"({"schema-version": 1, "components": {"title": "title", "art": "empty"}})"); auto cat = reply->register_category("cat1", "Category 1", "", music_rndr); CategorisedResult res(cat); res.set_uri("file:///tmp/foo.mp3"); res.set_title("result for: \"" + query_ + "\""); res.set_dnd_uri("file:///tmp/foo.mp3"); res["mimetype"] = "audio/mp3"; res["artist"] = "Foo"; res["album"] = "FooAlbum"; reply->push(res); } else if (query_ == "layout") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("test:layout"); res.set_title("result for: \"" + query_ + "\""); reply->push(res); } else if (query_ == "query") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("test:query"); res.set_title("result for: \"" + query_ + "\""); reply->push(res); } else if (query_ == "result-action") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("test:result-action"); res.set_title("result for: \"" + query_ + "\""); // Add result actions VariantBuilder builder; builder.add_tuple({ {"id", Variant("action1")}, {"icon", Variant("icon1")}, {"label", Variant("Action1")}, }); builder.add_tuple({ {"id", Variant("action2")}, {"icon", Variant("icon2")}, {"label", Variant("Action2")}, }); res["social_attributes"] = builder.end(); // TODO: verify with shell reply->push(res); } else if (query_ == "update-preview") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("update-preview"); reply->push(res); } else if (query_ == "expandable-widget") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("test:expandable-widget"); res.set_art("art"); res.set_title("result for: \"" + query_ + "\""); reply->push(res); } else if (query_ == "perform-query") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("scope://test:perform-query"); // FIXME: workaround for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1428063 res.set_title("result for: \"" + query_ + "\""); res["scope-id"] = "mock-scope-ttl"; res.set_intercept_activation(); reply->push(res); } else if (query_ == "perform-query2") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("scope://test:perform-query"); // FIXME: workaround for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1428063 res.set_title("result for: \"" + query_ + "\""); res["scope-id"] = "nonexisting-scope"; res.set_intercept_activation(); reply->push(res); } else if (query_ == "scope-uri") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("scope://mock-scope?q=next-scope-query"); res.set_title("result for: \"" + query_ + "\""); reply->push(res); } else if (query_ == "next-scope-query") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title", "art": "art"}})"); auto cat = reply->register_category("cat1", "Category 1", "", minimal_rndr); CategorisedResult res(cat); res.set_uri("next-scope-query"); res.set_art("next-scope-query-art"); res.set_title("result for: \"" + query_ + "\""); reply->push(res); } else if (query_ == "two-categories") { auto cat1 = reply->register_category("cat1", "Category 1", ""); auto cat2 = reply->register_category("cat2", "Category 2", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query_ + "\""); reply->push(res1); CategorisedResult res2(cat2); res2.set_uri("test:uri"); res2.set_title("result for: \"" + query_ + "\""); reply->push(res2); } else if (query_ == "two-categories-reversed") { auto cat2 = reply->register_category("cat2", "Category 2", ""); auto cat1 = reply->register_category("cat1", "Category 1", ""); CategorisedResult res2(cat2); res2.set_uri("test:uri"); res2.set_title("result for: \"" + query_ + "\""); reply->push(res2); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query_ + "\""); reply->push(res1); } else if (query_ == "two-categories-one-result") { auto cat1 = reply->register_category("cat1", "Category 1", ""); auto cat2 = reply->register_category("cat2", "Category 2", ""); CategorisedResult res1(cat1); res1.set_uri("test:uri"); res1.set_title("result for: \"" + query_ + "\""); reply->push(res1); } else if (query_ == "expansion-query") { CategoryRenderer minimal_rndr(R"({"schema-version": 1, "components": {"title": "title"}})"); auto cat = reply->register_category("cat1", "Category 1", "", query(), minimal_rndr); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); reply->push(res); } else if (query_ == "settings-change") { auto cat = reply->register_category("cat1", "Category 1", ""); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res["setting-distanceUnit"] = settings_["distanceUnit"]; reply->push(res); } else { auto cat = reply->register_category("cat1", "Category 1", ""); CategorisedResult res(cat); res.set_uri("test:uri"); res.set_title("result for: \"" + query_ + "\""); res.set_art("art"); res.set_dnd_uri("test:dnd_uri"); res["session-id"] = search_metadata()["session-id"].get_string(); res["query-id"] = Variant(search_metadata()["query-id"].get_int()); res["booleanness"] = Variant(true); res.set_intercept_activation(); reply->push(res); } } private: string query_; string department_id_; VariantMap settings_; }; class MyPreview : public PreviewQueryBase { public: MyPreview(Result const& result, ActionMetadata const& metadata) : PreviewQueryBase(result, metadata), scope_data_(metadata.scope_data()) { } ~MyPreview() noexcept { } virtual void cancelled() override { } virtual void run(PreviewReplyProxy const& reply) override { if (result().uri().find("layout") != std::string::npos) { PreviewWidget w1("img", "image"); w1.add_attribute_value("source", Variant("foo.png")); PreviewWidget w2("hdr", "header"); w2.add_attribute_value("title", Variant("Preview title")); PreviewWidget w3("desc", "text"); w3.add_attribute_value("text", Variant("Lorum ipsum...")); PreviewWidget w4("actions", "actions"); VariantBuilder builder; builder.add_tuple({ {"id", Variant("open")}, {"label", Variant("Open")}, {"uri", Variant("application:///tmp/non-existent.desktop")} }); builder.add_tuple({ {"id", Variant("download")}, {"label", Variant("Download")} }); builder.add_tuple({ {"id", Variant("hide")}, {"label", Variant("Hide")} }); w4.add_attribute_value("actions", builder.end()); ColumnLayout l1(1); l1.add_column({"img", "hdr", "desc", "actions", "extra"}); ColumnLayout l2(2); l2.add_column({"img"}); l2.add_column({"hdr", "desc", "actions"}); reply->register_layout({l1, l2}); PreviewWidgetList widgets({w1, w2, w3, w4}); if (!scope_data_.is_null()) { PreviewWidget extra("extra", "text"); extra.add_attribute_value("text", Variant("got scope data")); widgets.push_back(extra); } reply->push(widgets); return; } else if (result().uri().find("query") != std::string::npos) { PreviewWidget w1("actions", "actions"); VariantBuilder builder; auto uri = CannedQuery("mock-scope").to_uri(); builder.add_tuple({ {"id", Variant("nothing")}, {"label", Variant("Do nothing")} }); builder.add_tuple({ {"id", Variant("query")}, {"label", Variant("Search")}, {"uri", Variant(uri)} }); w1.add_attribute_value("actions", builder.end()); ColumnLayout l1(1); l1.add_column({"actions"}); reply->register_layout({l1}); PreviewWidgetList widgets({w1}); reply->push(widgets); return; } else if (result().uri().find("expandable-widget") != std::string::npos) { PreviewWidget w1("exp", "expandable"); w1.add_attribute_value("title", Variant("Expandable widget")); PreviewWidget w2("txt", "text"); w2.add_attribute_value("title", Variant("Subwidget")); w2.add_attribute_value("text", Variant("Lorum ipsum")); PreviewWidget w3("img", "image"); w3.add_attribute_mapping("source", "src"); w1.add_widget(w2); w1.add_widget(w3); PreviewWidget w4("img", "image"); w4.add_attribute_value("source", Variant("foo.png")); PreviewWidgetList widgets({w1, w4}); reply->push(widgets); reply->push("src", Variant("bar.png")); return; } else if (result().uri().find("update-preview") != std::string::npos) { PreviewWidget w1("icon-actions", "icon-actions"); VariantBuilder builder; builder.add_tuple({ {"id", Variant("dosomething1")}, {"label", Variant("Do something 1")} }); builder.add_tuple({ {"id", Variant("dosomething2")}, {"label", Variant("Do something 2")} }); w1.add_attribute_value("actions", builder.end()); ColumnLayout l1(1); l1.add_column({"icon-actions"}); reply->register_layout({l1}); PreviewWidgetList widgets({w1}); reply->push(widgets); return; } PreviewWidgetList widgets; PreviewWidget w1(R"({"id": "hdr", "type": "header", "components": {"title": "title", "subtitle": "uri", "attribute-1": "extra-data", "session-id": "session-id-val"}})"); PreviewWidget w2(R"({"id": "img", "type": "image", "components": {"source": "art"}, "zoomable": false})"); widgets.push_back(w1); widgets.push_back(w2); reply->push(widgets); reply->push("extra-data", Variant("foo")); reply->push("session-id-val", Variant(action_metadata()["session-id"])); } private: Variant scope_data_; }; class MyActivation : public ActivationQueryBase { public: MyActivation(Result const& result, ActionMetadata const& metadata) : ActivationQueryBase(result, metadata), status_(ActivationResponse::HideDash) { } MyActivation(Result const& result, ActionMetadata const& metadata, ActivationResponse::Status status) : ActivationQueryBase(result, metadata), status_(status) { } MyActivation(Result const& result, ActionMetadata const& metadata, ActivationResponse::Status status, std::string const& action_id) : ActivationQueryBase(result, metadata), status_(status), action_id_(action_id) { } ~MyActivation() noexcept { } void setExtraData(Variant const& extra) { extra_data_ = extra; } virtual void cancelled() override { } virtual ActivationResponse activate() override { if (status_ == ActivationResponse::Status::UpdateResult) { Result updatedRes(result()); updatedRes["actionId"] = Variant(action_id_); return ActivationResponse(updatedRes); } else if (status_ == ActivationResponse::Status::PerformQuery) { auto resp = ActivationResponse(CannedQuery(result()["scope-id"].get_string())); return resp; } else { auto resp = ActivationResponse(status_); resp.set_scope_data(extra_data_); return resp; } } private: Variant extra_data_; ActivationResponse::Status status_; std::string action_id_; }; class UpdatePreviewWidgets : public ActivationQueryBase { public: UpdatePreviewWidgets(Result const& result, ActionMetadata const& metadata, PreviewWidgetList const &widgets) : ActivationQueryBase(result, metadata), widgets_(widgets) { } virtual ActivationResponse activate() override { ActivationResponse resp(widgets_); return resp; } private: PreviewWidgetList widgets_; Variant extra_data_; }; class MyScope : public ScopeBase { public: virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override { SearchQueryBase::UPtr query(new MyQuery(q, metadata, settings())); cout << "scope-A: created query: \"" << q.query_string() << "\"" << endl; return query; } virtual PreviewQueryBase::UPtr preview(Result const& result, ActionMetadata const& metadata) override { PreviewQueryBase::UPtr query(new MyPreview(result, metadata)); cout << "scope-A: created preview query: \"" << result.uri() << "\"" << endl; return query; } virtual ActivationQueryBase::UPtr perform_action(Result const& result, ActionMetadata const& meta, std::string const& widget_id, std::string const& action_id) { cout << "scope-A: called perform_action: " << widget_id << ", " << action_id << endl; if (widget_id == "actions" && action_id == "hide") { return ActivationQueryBase::UPtr(new MyActivation(result, meta)); } else if (widget_id == "actions" && action_id == "download") { MyActivation* response = new MyActivation(result, meta, ActivationResponse::ShowPreview); response->setExtraData(meta.scope_data()); return ActivationQueryBase::UPtr(response); } else if (widget_id == "icon-actions" && action_id == "dosomething1") { PreviewWidget w1("icon-actions", "icon-actions"); VariantBuilder builder; builder.add_tuple({ {"id", Variant("dosomething1")}, {"label", Variant("Did something 1")} }); builder.add_tuple({ {"id", Variant("dosomething2")}, {"label", Variant("Do something 2")} }); w1.add_attribute_value("actions", builder.end()); PreviewWidgetList widgets({w1}); return ActivationQueryBase::UPtr(new UpdatePreviewWidgets(result, meta, widgets)); } return ActivationQueryBase::UPtr(new MyActivation(result, meta, ActivationResponse::NotHandled)); } virtual ActivationQueryBase::UPtr activate(Result const& result, ActionMetadata const& meta) override { if (result.uri().find("perform-query") != std::string::npos) { return ActivationQueryBase::UPtr(new MyActivation(result, meta, ActivationResponse::PerformQuery)); } return ActivationQueryBase::UPtr(new MyActivation(result, meta)); } ActivationQueryBase::UPtr activate_result_action(Result const& result, ActionMetadata const& meta, std::string const& action_id) override { return ActivationQueryBase::UPtr(new MyActivation(result, meta, ActivationResponse::UpdateResult, action_id)); } }; extern "C" { EXPORT unity::scopes::ScopeBase* // cppcheck-suppress unusedFunction UNITY_SCOPE_CREATE_FUNCTION() { return new MyScope; } EXPORT void // cppcheck-suppress unusedFunction UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) { delete scope_base; } } unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope/mock-scope.ini.in0000644000015600001650000000060012672630457027127 0ustar pbuserpbgroup00000000000000[ScopeConfig] DisplayName = mock.DisplayName Description = mock.Description Art = /mock.Art Icon = /mock.Icon SearchHint = mock.SearchHint HotKey = mock.HotKey Author = mock.Author [Appearance] PageHeader.Logo = http://assets.ubuntu.com/sites/ubuntu/1110/u/img/logos/logo-ubuntu-orange.svg PageHeader.ForegroundColor = white PageHeader.Background = color://black ShapeImages = false unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope/mock-scope-settings.ini0000644000015600001650000000057212672630457030370 0ustar pbuserpbgroup00000000000000[location] type = string defaultValue = London displayName = Location [distanceUnit] type = list defaultValue = 1 displayName = Distance Unit displayValues = Kilometers;Miles [age] type = number defaultValue = 23 displayName = Age [enabled] type = boolean defaultValue = true displayName = Enabled # Setting without a default value [color] type = string displayName = Color unity-scopes-shell-0.5.7+16.04.20160317/tests/data/mock-scope/CMakeLists.txt0000644000015600001650000000040712672630457026526 0ustar pbuserpbgroup00000000000000include_directories(${SCOPESLIB_INCLUDE_DIRS}) add_library(mock-scope MODULE mock-scope.cpp) target_link_libraries(mock-scope ${SCOPESLIB_LDFLAGS}) configure_file(mock-scope.ini.in mock-scope.ini) configure_file(mock-scope-settings.ini mock-scope-settings.ini) unity-scopes-shell-0.5.7+16.04.20160317/tests/data/Registry.ini.in0000644000015600001650000000031012672630457024635 0ustar pbuserpbgroup00000000000000[Registry] Middleware = Zmq Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini Scope.InstallDir = @CMAKE_CURRENT_BINARY_DIR@ Click.InstallDir = /unused Scoperunner.Path = @SCOPESLIB_SCOPERUNNER_BIN@ unity-scopes-shell-0.5.7+16.04.20160317/tests/geoip.ubuntu.com.py0000755000015600001650000000360512672630457024576 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (C) 2014 Canonical Ltd # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # # Authored by: Pete Woods import tornado.httpserver import tornado.ioloop import tornado.netutil import tornado.web import sys RESPONSE = ''' 1.2.3.4 OK GB GBR United Kingdom H2 Lancashire Accrington BB5 55.7654 -2.7467 0 Europe/London ''' class Lookup(tornado.web.RequestHandler): def get(self): sys.stderr.write('GeoIP location requested\n') sys.stderr.flush() self.write(RESPONSE) self.finish() def new_app(): application = tornado.web.Application([ (r"/lookup", Lookup), ], gzip=True) sockets = tornado.netutil.bind_sockets(0, '127.0.0.1') server = tornado.httpserver.HTTPServer(application) server.add_sockets(sockets) sys.stdout.write('%d\n' % sockets[0].getsockname()[1]) sys.stdout.flush() return application if __name__ == "__main__": application = new_app() tornado.ioloop.IOLoop.instance().start() unity-scopes-shell-0.5.7+16.04.20160317/tests/filtersendtoendtest.cpp0000644000015600001650000003371012672630472025612 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pawel Stolowski */ #include #include #include #include #include #include "filters.h" #include "categories.h" #include "optionselectorfilter.h" #include "rangeinputfilter.h" #include "valuesliderfilter.h" #include #include #include #include #include #include #include using namespace unity::scopeharness; using namespace unity::scopeharness::registry; using namespace scopes_ng; namespace uss = unity::shell::scopes; // FIXME: use scope harness wrapper once it exposes filters class FiltersEndToEndTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { m_registry.reset(new PreExistingRegistry(TEST_RUNTIME_CONFIG)); m_registry->start(); } void cleanupTestCase() { m_registry.reset(); } void init() { const QStringList favs {"scope://mock-scope-filters"}; TestUtils::setFavouriteScopes(favs); m_scopes.reset(new Scopes(nullptr)); // wait till the registry spawns QSignalSpy spy(m_scopes.data(), SIGNAL(loadedChanged())); QVERIFY(spy.wait()); QCOMPARE(m_scopes->loaded(), true); // get scope proxy m_scope = m_scopes->getScopeById("mock-scope-filters"); QVERIFY(m_scope != nullptr); m_scope->setActive(true); } void cleanup() { m_scopes.reset(); m_scope.reset(); } void testBasic() { TestUtils::performSearch(m_scope, ""); QCOMPARE(m_scope->primaryNavigationTag(), QString("")); QVERIFY(m_scope->primaryNavigationFilter() == nullptr); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(0, 0); QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); idx = filters->index(1, 0); QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); idx = filters->index(2, 0); QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f3")); } void testOptionSelectorFilter() { TestUtils::performSearch(m_scope, ""); auto categories = m_scope->categories(); QVERIFY(categories != nullptr); auto results = categories->data(categories->index(0, 0), Categories::RoleResultsSPtr).value>(); QVERIFY(results != nullptr); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(0, 0); auto f1 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f1 != nullptr); // check options auto opts = f1->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); QCOMPARE(f1->filterId(), QString("f1")); QCOMPARE(f1->label(), QString("Filter1")); QVERIFY(!f1->multiSelect()); idx = opts->index(0, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("o1")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); idx = opts->index(1, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("o2")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // select option 1 opts->setChecked(0, true); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(filters, m_scope->filters()); QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for option o1")); // select option 2 opts->setChecked(1, true); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(filters, m_scope->filters()); QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for option o2")); // deselect option 2 opts->setChecked(1, false); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for: \"\"")); QCOMPARE(filters, m_scope->filters()); } void testPrimaryFilter() { TestUtils::performSearch(m_scope, "test_primary_filter"); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 2); auto idx = filters->index(0, 0); QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); idx = filters->index(1, 0); QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f3")); auto f1 = dynamic_cast(m_scope->primaryNavigationFilter()); QVERIFY(f1 != nullptr); QCOMPARE(f1->filterId(), QString("f1")); auto opts = f1->options(); // select option 1 opts->setChecked(0, true); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(m_scope->primaryNavigationTag(), QString("Option1")); } void testRangeInputFilter() { TestUtils::performSearch(m_scope, ""); auto categories = m_scope->categories(); QVERIFY(categories != nullptr); auto results = categories->data(categories->index(0, 0), Categories::RoleResultsSPtr).value>(); QVERIFY(results != nullptr); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(1, 0); auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f2 != nullptr); QCOMPARE(f2->hasStartValue(), true); QCOMPARE(f2->hasEndValue(), false); { f2->setStartValue(111.0f); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(filters, m_scope->filters()); QCOMPARE(f2->hasStartValue(), true); QCOMPARE(f2->hasEndValue(), false); auto resultIdx = filters->index(0, 0); QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: 111.000000 - ***")); } { QCOMPARE(f2, filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value()); f2->setEndValue(300.5f); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(f2->hasStartValue(), true); QCOMPARE(f2->hasEndValue(), true); auto resultIdx = filters->index(0, 0); QCOMPARE(filters, m_scope->filters()); QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: 111.000000 - 300.500000")); } // erase start value, end value still present { f2->eraseStartValue(); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(filters, m_scope->filters()); QCOMPARE(f2->hasStartValue(), false); QCOMPARE(f2->hasEndValue(), true); auto resultIdx = filters->index(0, 0); QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: *** - 300.500000")); } } void testValueSliderFilter() { TestUtils::performSearch(m_scope, ""); auto categories = m_scope->categories(); QVERIFY(categories != nullptr); auto results = categories->data(categories->index(0, 0), Categories::RoleResultsSPtr).value>(); QVERIFY(results != nullptr); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(2, 0); auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f3 != nullptr); QCOMPARE(static_cast(f3->minValue()), 1); QCOMPARE(static_cast(f3->maxValue()), 99); QCOMPARE(static_cast(f3->value()), 50); auto valuesModel = f3->values(); QVERIFY(valuesModel != nullptr); QCOMPARE(valuesModel->rowCount(), 3); QCOMPARE(valuesModel->data(valuesModel->index(0, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 1); QCOMPARE(valuesModel->data(valuesModel->index(0, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("Min")); QCOMPARE(valuesModel->data(valuesModel->index(1, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 33); QCOMPARE(valuesModel->data(valuesModel->index(1, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("One third")); QCOMPARE(valuesModel->data(valuesModel->index(2, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 99); QCOMPARE(valuesModel->data(valuesModel->index(2, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("Max")); f3->setValue(75); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(filters->rowCount(), 3); // filter object shouldn't be recreated QCOMPARE(filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(), f3); QCOMPARE(filters, m_scope->filters()); QCOMPARE(static_cast(f3->value()), 75); } void testResetToDefault() { TestUtils::performSearch(m_scope, ""); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(1, 0); auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f2 != nullptr); QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles idx = filters->index(2, 0); auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f3 != nullptr); QCOMPARE(static_cast(f3->value()), 50); f2->setStartValue(5.0f); f3->setValue(75); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(f2->startValue(), 5.0f); QCOMPARE(static_cast(f3->value()), 75); m_scope->resetFilters(); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles QCOMPARE(static_cast(f3->value()), 50); } void testCancel() { TestUtils::performSearch(m_scope, ""); auto filters = m_scope->filters(); QVERIFY(filters != nullptr); QCOMPARE(filters->rowCount(), 3); auto idx = filters->index(1, 0); auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f2 != nullptr); idx = filters->index(2, 0); auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(f3 != nullptr); QCOMPARE(static_cast(f3->value()), 50); f2->setStartValue(5.0f); f3->setValue(75); TestUtils::waitForFilterStateChange(m_scope); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(f2->startValue(), 5.0f); QCOMPARE(static_cast(f3->value()), 75); m_scope->resetPrimaryNavigationTag(); TestUtils::waitForSearchFinish(m_scope); QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles QCOMPARE(static_cast(f3->value()), 50); QCOMPARE(QString(), m_scope->primaryNavigationTag()); } private: QScopedPointer m_scopes; Scope::Ptr m_scope; Registry::UPtr m_registry; }; QTEST_GUILESS_MAIN(FiltersEndToEndTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/CMakeLists.txt0000644000015600001650000000505012672630472023551 0ustar pbuserpbgroup00000000000000pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1>=0.2 REQUIRED) pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1>=0.2 REQUIRED) set(TEST_DATA_DIR "${CMAKE_CURRENT_BINARY_DIR}/data/") set(TEST_RUNTIME_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/data/Runtime.ini") add_subdirectory(data) add_definitions( -DGEOIP_SERVER_BINARY="${CMAKE_CURRENT_SOURCE_DIR}/geoip.ubuntu.com.py" -DTEST_DATA_DIR="${TEST_DATA_DIR}" -DTEST_RUNTIME_CONFIG="${TEST_RUNTIME_CONFIG}" -DTEST_SETTINGS_UNICODE="${CMAKE_CURRENT_SOURCE_DIR}/data/settings-unicode.ini" ) include_directories( ${CMAKE_SOURCE_DIR}/src/Unity ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} ${SCOPESLIB_INCLUDE_DIRS} ${UBUNTU_LOCATION_SERVICE_INCLUDE_DIRS} ${QTDBUSTEST_INCLUDE_DIRS} ${QTDBUSMOCK_INCLUDE_DIRS} ${GSETTINGSQT_INCLUDE_DIRS} ) macro(run_tests) set(_test_list "") foreach(_test ${ARGN}) set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/${_test}Exec -o ${CMAKE_BINARY_DIR}/${_test}.xml,xunitxml -o -,txt) add_test(NAME test${CLASSNAME}${_test} COMMAND ${testCommand}) add_custom_target(${_test} ${testCommand}) add_executable(${_test}Exec ${_test}.cpp ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ScopeInterface.h ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FilterBaseInterface.h ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorFilterInterface.h ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorOptionsInterface.h ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/SettingsModelInterface.h ) qt5_use_modules(${_test}Exec Test Core Qml DBus) set_tests_properties(test${CLASSNAME}${_test} PROPERTIES RUN_SERIAL TRUE) target_link_libraries(${_test}Exec Unity-qml ${SCOPESLIB_LDFLAGS} ${QTDBUSTEST_LIBRARIES} ${QTDBUSMOCK_LIBRARIES} scope-harness ) set(_test_list "${_test_list};${_test}") endforeach() endmacro(run_tests) run_tests( filterstest filtersendtoendtest optionselectorfiltertest favoritestest locationtest overviewtest previewtest resultstest settingsendtoendtest settingstest utilstest ) qt5_use_modules(settingstestExec Sql) unity-scopes-shell-0.5.7+16.04.20160317/tests/optionselectorfiltertest.cpp0000644000015600001650000002716112672630472026703 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Pawel Stolowski */ #include #include #include #include #include "filters.h" #include "optionselectorfilter.h" #include using namespace scopes_ng; namespace uss = unity::shell::scopes; class OptionSelectorFilterTest: public QObject { Q_OBJECT private Q_SLOTS: void init() { unity::scopes::FilterState filterState; filtersModel.reset(new Filters(filterState)); f1 = unity::scopes::OptionSelectorFilter::create("f1", "Filter1", false); f1o1 = f1->add_option("f1o1", "Option1"); f1o2 = f1->add_option("f1o2", "Option2"); f2 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", true); f2o1 = f2->add_option("f2o1", "Option1"); f2o2 = f2->add_option("f2o2", "Option2"); backendFilters.clear(); backendFilters.append(f1); backendFilters.append(f2); filtersModel->update(backendFilters); f1->update_state(filterState, f1o1, true); filtersModel->update(filterState); } void testOptions() { // check filters model data auto idx1 = filtersModel->index(0, 0); auto idx2 = filtersModel->index(1, 0); QCOMPARE(filtersModel->rowCount(), 2); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), static_cast(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), static_cast(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); { // get 1st option selector filter auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); QCOMPARE(opf->filterId(), QString("f1")); QCOMPARE(opf->label(), QString("Filter1")); QVERIFY(!opf->multiSelect()); // check options auto opts = opf->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); auto idx = opts->index(0, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option1 is checked idx = opts->index(1, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); } { // get 2nd option selector filter auto opf = filtersModel->data(idx2, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); QCOMPARE(opf->filterId(), QString("f2")); QCOMPARE(opf->label(), QString("Filter2")); QVERIFY(opf->multiSelect()); // check options auto opts = opf->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); auto idx = opts->index(0, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f2o1")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); idx = opts->index(1, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f2o2")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); } } void testBackendCheckedStateChange() { auto idx1 = filtersModel->index(0, 0); { // get 1st option selector filter auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); auto opts = opf->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); // enable second option (which disables 1st option) f1->update_state(filterState, f1o2, true); filtersModel->update(filterState); QCOMPARE(dataChangedSignal.count(), 2); QCOMPARE(stateChangeSignal.count(), 0); // change initiated by backend, so no state change signal // verify arguments of dataChanged signal { auto args = dataChangedSignal.takeFirst(); auto topLeft = args.at(0).value(); auto roles = args.at(2).value>(); QCOMPARE(topLeft.row(), 0); QCOMPARE(roles[0], static_cast(uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked)); } auto idx = opts->index(0, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 1 is now off idx = opts->index(1, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 2 is now on } } void testBackendOptionLabelChange() { auto idx = filtersModel->index(1, 0); { // get 1st option selector filter auto opf = filtersModel->data(idx, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); QCOMPARE(opf->filterId(), QString("f2")); auto opts = opf->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); auto idx1 = opts->index(0, 0); auto idx2 = opts->index(1, 0); QCOMPARE(opts->data(idx1, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option1")); QCOMPARE(opts->data(idx2, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option2")); QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); unity::scopes::OptionSelectorFilter::SPtr f3 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", true); auto f3o1 = f3->add_option("f2o1", "Option1"); auto f3o2 = f3->add_option("f2o2", "UpdatedOption2"); QList backendFilters2; backendFilters2.append(f1); backendFilters2.append(f3); // sync model with new backend filters filtersModel->update(backendFilters2); if (dataChangedSignal.empty()) { QVERIFY(dataChangedSignal.wait()); } QCOMPARE(dataChangedSignal.count(), 1); QCOMPARE(opts->data(idx1, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option1")); QCOMPARE(opts->data(idx2, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("UpdatedOption2")); QCOMPARE(stateChangeSignal.count(), 0); // no state change signal // verify arguments of dataChanged signal { auto args = dataChangedSignal.takeFirst(); auto topLeft = args.at(0).value(); auto roles = args.at(2).value>(); QCOMPARE(topLeft.row(), 1); QCOMPARE(roles[0], static_cast(uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel)); } } } void testUICheckedStateChange() { auto idx1 = filtersModel->index(0, 0); { // get 1st option selector filter auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value(); QVERIFY(opf != nullptr); auto opts = opf->options(); QVERIFY(opts != nullptr); QCOMPARE(opts->rowCount(), 2); QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector&))); QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); // enable second option (which disables 1st option) opts->setChecked(1, true); if (stateChangeSignal.empty()) { stateChangeSignal.wait(); } if (dataChangedSignal.empty()) { dataChangedSignal.wait(); } QCOMPARE(stateChangeSignal.count(), 1); QCOMPARE(dataChangedSignal.count(), 2); // verify arguments of dataChanged signal { auto args = dataChangedSignal.takeFirst(); auto topLeft = args.at(0).value(); auto roles = args.at(2).value>(); QCOMPARE(topLeft.row(), 0); QCOMPARE(roles[0], static_cast(uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked)); } auto idx = opts->index(0, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 1 is now off idx = opts->index(1, 0); QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 2 is now on } } private: unity::scopes::FilterState filterState; QScopedPointer filtersModel; unity::scopes::OptionSelectorFilter::SPtr f1, f2; unity::scopes::FilterOption::SCPtr f1o1, f1o2, f2o1, f2o2; QList backendFilters; }; QTEST_GUILESS_MAIN(OptionSelectorFilterTest) #include unity-scopes-shell-0.5.7+16.04.20160317/tests/previewtest.cpp0000644000015600001650000003600412672630457024104 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2013-2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: * Michal Hruby */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace sh = unity::scopeharness; namespace shm = unity::scopeharness::matcher; namespace shr = unity::scopeharness::registry; namespace shv = unity::scopeharness::view; namespace sc = unity::scopes; namespace ss = unity::shell::scopes; class PreviewTest : public QObject { Q_OBJECT private: sh::ScopeHarness::UPtr m_harness; shv::ResultsView::SPtr m_resultsView; private Q_SLOTS: void initTestCase() { m_harness = sh::ScopeHarness::newFromScopeList( shr::CustomRegistry::Parameters({ TEST_DATA_DIR "mock-scope/mock-scope.ini" }) ); } void cleanupTestCase() { m_harness.reset(); } void init() { m_resultsView = m_harness->resultsView(); m_resultsView->setActiveScope("mock-scope"); } void cleanup() { m_resultsView.reset(); } void testScopePreview() { m_resultsView->setQuery("x"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("test:uri")) ) .match(m_resultsView->categories()) ); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); sc::VariantMap widget1 { {"attribute-1", sc::Variant("foo")}, {"subtitle", sc::Variant("test:uri")}, {"title", sc::Variant("result for: \"x\"")} }; sc::VariantMap widget2 { {"source", sc::Variant("art")}, {"zoomable", sc::Variant(false)} }; QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget( shm::PreviewWidgetMatcher("hdr") .type("header") .data(sc::Variant(widget1)) ) .widget( shm::PreviewWidgetMatcher("img") .type("image") .data(sc::Variant(widget2)) ) ) .match(previewView->widgets()) ); } void testExpandablePreviewWidget() { // QScopedPointer preview_stack; // QVERIFY(previewForFirstResult(m_scope, QString("expandable-widget"), preview_stack)); // unity::scopes::Result::SPtr result; // QVERIFY(getFirstResult(m_scope->categories(), result)); // // QCOMPARE(preview_stack->rowCount(), 1); // QCOMPARE(preview_stack->widgetColumnCount(), 1); // auto preview_var = preview_stack->data(preview_stack->index(0), PreviewStack::RolePreviewModel); // auto preview_model = preview_stack->getPreviewModel(0); // QCOMPARE(preview_model, preview_var.value()); // QCOMPARE(preview_model->widgetColumnCount(), 1); // QTRY_COMPARE(preview_model->loaded(), true); // // auto preview_widgets = preview_model->data(preview_model->index(0), PreviewModel::RoleColumnModel).value(); // QVERIFY(!preview_widgets->roleNames().isEmpty()); // QCOMPARE(preview_widgets->rowCount(), 2); // QVariantMap props; // QModelIndex idx; // // idx = preview_widgets->index(0); // QCOMPARE(preview_widgets->data(idx, PreviewWidgetModel::RoleWidgetId).toString(), QString("exp")); // QCOMPARE(preview_widgets->data(idx, PreviewWidgetModel::RoleType).toString(), QString("expandable")); // props = preview_widgets->data(idx, PreviewWidgetModel::RoleProperties).toMap(); // QCOMPARE(props[QString("title")].toString(), QString("Expandable widget")); // auto widgets = props[QString("widgets")]; // QVERIFY(widgets.canConvert()); // // // test the model of widgets in expandable widget // { // auto widgets_model = widgets.value(); // idx = widgets_model->index(0); // QCOMPARE(widgets_model->rowCount(), 2); // QCOMPARE(widgets_model->data(idx, PreviewWidgetModel::RoleWidgetId).toString(), QString("txt")); // QCOMPARE(widgets_model->data(idx, PreviewWidgetModel::RoleType).toString(), QString("text")); // props = widgets_model->data(idx, PreviewWidgetModel::RoleProperties).toMap(); // QCOMPARE(props[QString("title")].toString(), QString("Subwidget")); // QCOMPARE(props[QString("text")].toString(), QString("Lorum ipsum")); // idx = widgets_model->index(1); // QCOMPARE(widgets_model->data(idx, PreviewWidgetModel::RoleWidgetId).toString(), QString("img")); // QCOMPARE(widgets_model->data(idx, PreviewWidgetModel::RoleType).toString(), QString("image")); // props = widgets_model->data(idx, PreviewWidgetModel::RoleProperties).toMap(); // QCOMPARE(props[QString("source")].toString(), QString("bar.png")); // } // // idx = preview_widgets->index(1); // QCOMPARE(preview_widgets->data(idx, PreviewWidgetModel::RoleWidgetId).toString(), QString("img")); // QCOMPARE(preview_widgets->data(idx, PreviewWidgetModel::RoleType).toString(), QString("image")); // props = preview_widgets->data(idx, PreviewWidgetModel::RoleProperties).toMap(); // QVERIFY(props.contains("source")); // QCOMPARE(props[QString("source")].toString(), QString("foo.png")); } void testPreviewLayouts() { m_resultsView->setQuery("layout"); QVERIFY_MATCHRESULT( shm::CategoryListMatcher() .hasAtLeast(1) .mode(shm::CategoryListMatcher::Mode::starts_with) .category(shm::CategoryMatcher("cat1") .hasAtLeast(1) .mode(shm::CategoryMatcher::Mode::starts_with) .result(shm::ResultMatcher("test:layout")) ) .match(m_resultsView->categories()) ); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); previewView->setColumnCount(2); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) ) .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); previewView->setColumnCount(1); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); } void testPreviewAction() { m_resultsView->setQuery("layout"); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); auto sameView = previewView->widgetsInFirstColumn().at("actions").trigger("hide", sc::Variant()); QCOMPARE(abstractView, sameView); auto previewView2 = dynamic_pointer_cast(sameView); QVERIFY(bool(previewView2)); } void testPreviewUpdateViaAction() { m_resultsView->setQuery("update-preview"); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); sc::VariantMap vm; { sc::VariantMap action1; action1["id"] = "dosomething1"; action1["label"] = "Do something 1"; sc::VariantMap action2; action2["id"] = "dosomething2"; action2["label"] = "Do something 2"; sc::VariantArray actions({sc::Variant(action1), sc::Variant(action2)}); vm["actions"] = actions; } QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("icon-actions") .type("icon-actions") .data(sc::Variant(vm))) ) .match(previewView->widgets()) ); auto sameView = previewView->widgetsInFirstColumn().at("icon-actions").trigger("dosomething1", sc::Variant()); QCOMPARE(abstractView, sameView); auto previewView2 = dynamic_pointer_cast(sameView); QVERIFY(bool(previewView2)); { sc::VariantMap action1; action1["id"] = "dosomething1"; action1["label"] = "Did something 1"; // label of action 1 changed sc::VariantMap action2; action2["id"] = "dosomething2"; action2["label"] = "Do something 2"; sc::VariantArray actions({sc::Variant(action1), sc::Variant(action2)}); vm["actions"] = actions; } QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("icon-actions") .type("icon-actions") .data(sc::Variant(vm))) ) .match(previewView2->widgets()) ); } void testPreviewActionRequestingSearch() { m_resultsView->setQuery("query"); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); auto resView = previewView->widgetsInFirstColumn().at("actions").trigger("query", previewView->widgetsInFirstColumn().at("actions").data()); // action with canned query uri should trigger a search auto resultsView2 = dynamic_pointer_cast(resView); QVERIFY(bool(resultsView2)); QCOMPARE(m_resultsView, resultsView2); } void testPreviewReplacingPreview() { m_resultsView->setQuery("layout"); auto abstractView = m_resultsView->category(0).result(0).longPress(); QVERIFY(bool(abstractView)); auto previewView = dynamic_pointer_cast(abstractView); QVERIFY(bool(previewView)); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) ) .match(previewView->widgets()) ); sc::VariantMap hints {{"session-id", sc::Variant("goo")}}; auto sameView = previewView->widgetsInFirstColumn().at("actions").trigger("download", sc::Variant(hints)); auto previewView2 = dynamic_pointer_cast(sameView); QVERIFY(bool(previewView2)); QVERIFY_MATCHRESULT( shm::PreviewColumnMatcher() .column( shm::PreviewMatcher() .widget(shm::PreviewWidgetMatcher("img")) .widget(shm::PreviewWidgetMatcher("hdr")) .widget(shm::PreviewWidgetMatcher("desc")) .widget(shm::PreviewWidgetMatcher("actions")) .widget(shm::PreviewWidgetMatcher("extra")) ) .match(previewView2->widgets()) ); } }; QTEST_GUILESS_MAIN(PreviewTest) #include unity-scopes-shell-0.5.7+16.04.20160317/src/0000755000015600001650000000000012672635475020446 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/0000755000015600001650000000000012672635475023220 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/test-utils.h0000644000015600001650000000371312672630472025502 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include #include namespace unity { namespace scopeharness { class TestUtils { public: Q_DECL_EXPORT static void throwIf(bool condition, const std::string& message); Q_DECL_EXPORT static void throwIfNot(bool condition, const std::string& message); Q_DECL_EXPORT static void checkedFirstResult(unity::shell::scopes::CategoriesInterface* categories, unity::scopes::Result::SPtr& result, bool& success); Q_DECL_EXPORT static bool getFirstResult(unity::shell::scopes::CategoriesInterface* categories, unity::scopes::Result::SPtr& result); Q_DECL_EXPORT static void refreshSearch(scopes_ng::Scope::Ptr); Q_DECL_EXPORT static void performSearch(QSharedPointer scope, QString const& searchString); Q_DECL_EXPORT static void waitForFilterStateChange(QSharedPointer scope); Q_DECL_EXPORT static void waitForResultsChange(QSharedPointer scope); Q_DECL_EXPORT static void waitForSearchFinish(QSharedPointer scope); Q_DECL_EXPORT static void setFavouriteScopes(const QStringList& cannedQueries); Q_DECL_EXPORT static QStringList getFavoriteScopes(); }; } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/scope-harness.h0000644000015600001650000000331312672630457026136 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include #include #include #include #include #define QVERIFY_MATCHRESULT(statement) \ do {\ auto result = (statement);\ QVERIFY2(result.success(), result.concat_failures().c_str());\ } while (0) namespace unity { namespace scopeharness { class Q_DECL_EXPORT ScopeHarness final { public: UNITY_DEFINES_PTRS(ScopeHarness); Q_DECL_EXPORT static ScopeHarness::UPtr newFromPreExistingConfig(const std::string& directory); Q_DECL_EXPORT static ScopeHarness::UPtr newFromScopeList(const registry::CustomRegistry::Parameters& parameters); Q_DECL_EXPORT static ScopeHarness::UPtr newFromSystem(); ~ScopeHarness() = default; view::ResultsView::SPtr resultsView(); protected: ScopeHarness(registry::Registry::SPtr registry); struct _Priv; std::shared_ptr<_Priv> p; }; } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/0000755000015600001650000000000012672635475024643 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/category-matcher.cpp0000644000015600001650000002147312672630457030607 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include #include #include #include using namespace std; using namespace boost; namespace sc = unity::scopes; namespace unity { namespace scopeharness { namespace matcher { namespace { static void check_variant(MatchResult& matchResult, const results::Category& category, const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue) { if (!(actualValue == expectedValue)) { auto actualValueString = actualValue.serialize_json(); auto expectedValueString = expectedValue.serialize_json(); // serialize_json includes a trailing carriage return actualValueString.pop_back(); expectedValueString.pop_back(); matchResult.failure( "Category with ID '" + category.id() + "' has '" + name + "' == '" + actualValueString + "' but expected '" + expectedValueString + "'"); } } static void check_string(MatchResult& matchResult, const results::Category& category, const string& name, const string& actualValue, const string& expectedValue) { try { if (actualValue != expectedValue) { matchResult.failure( "Category with ID '" + category.id() + "' has '" + name + "' == '" + actualValue + "' but expected '" + expectedValue + "'"); } } catch (std::exception& e) { matchResult.failure( "Category with ID '" + category.id() + "' does not contain expected property '" + name + "'"); } } } struct CategoryMatcher::_Priv { void all(MatchResult& matchResult, const results::Result::List& resultList) { if (resultList.size() != m_results.size()) { matchResult.failure( "Result list contained " + to_string(resultList.size()) + " expected " + to_string(m_results.size())); return; } for (size_t row = 0; row < m_results.size(); ++row) { const auto& expectedResult = m_results[row]; const auto& actualResult = resultList[row]; expectedResult.match(matchResult, actualResult); } } void startsWith(MatchResult& matchResult, const results::Result::List&resultList) { if (resultList.size() < m_results.size()) { matchResult.failure( "Result list contained " + to_string(resultList.size()) + " expected at least " + to_string(m_results.size())); return; } for (size_t row = 0; row < m_results.size(); ++row) { const auto& expectedResult = m_results[row]; const auto& actualResult = resultList[row]; expectedResult.match(matchResult, actualResult); } } void byUri(MatchResult& matchResult, const results::Result::List& resultList) { for (const auto& expectedResult : m_results) { string expectedUri = expectedResult.getUri(); TestUtils::throwIf(expectedUri.empty(), "Cannot match by_uri with empty expected URI"); regex e(expectedUri); bool matched = false; for (const auto& result : resultList) { if (regex_match(result.uri(), e)) { matched = true; expectedResult.match(matchResult, result); break; } } if (!matched) { matchResult.failure( "Result with URI " + expectedResult.getUri() + " could not be found"); } } } string m_id; Mode m_mode = Mode::all; vector m_results; optional m_hasAtLeast; optional m_title; optional m_icon; optional m_headerLink; optional m_renderer; optional m_components; }; CategoryMatcher::CategoryMatcher(const string& id) : p(new _Priv) { p->m_id = id; } CategoryMatcher::CategoryMatcher(const CategoryMatcher& other) : p(new _Priv) { *this = other; } CategoryMatcher::CategoryMatcher(CategoryMatcher&& other) { *this = std::move(other); } CategoryMatcher& CategoryMatcher::operator=(const CategoryMatcher& other) { p->m_id = other.p->m_id; p->m_mode = other.p->m_mode; p->m_results = other.p->m_results; p->m_hasAtLeast = other.p->m_hasAtLeast; p->m_title = other.p->m_title; p->m_icon = other.p->m_icon; p->m_headerLink = other.p->m_headerLink; p->m_renderer = other.p->m_renderer; p->m_components = other.p->m_components; return *this; } CategoryMatcher& CategoryMatcher::operator=(CategoryMatcher&& other) { p = std::move(other.p); return *this; } CategoryMatcher& CategoryMatcher::mode(Mode mode) { p->m_mode = mode; return *this; } CategoryMatcher& CategoryMatcher::title(const string& title) { p->m_title = title; return *this; } CategoryMatcher& CategoryMatcher::icon(const string& icon) { p->m_icon = icon; return *this; } CategoryMatcher& CategoryMatcher::headerLink(const string& headerLink) { p->m_headerLink = headerLink; return *this; } CategoryMatcher& CategoryMatcher::hasAtLeast(size_t minimum) { p->m_hasAtLeast = minimum; return *this; } CategoryMatcher& CategoryMatcher::renderer(const sc::Variant& renderer) { p->m_renderer = renderer; return *this; } CategoryMatcher& CategoryMatcher::components(const sc::Variant& components) { p->m_components = components; return *this; } CategoryMatcher& CategoryMatcher::result(const ResultMatcher& resultMatcher) { p->m_results.emplace_back(resultMatcher); return *this; } CategoryMatcher& CategoryMatcher::result(ResultMatcher&& resultMatcher) { p->m_results.emplace_back(std::move(resultMatcher)); return *this; } void CategoryMatcher::match(MatchResult& matchResult, const results::Category& category) const { auto results = category.results(); if (p->m_id != category.id()) { matchResult.failure("Category ID " + category.id() + " != " + p->m_id); } if (p->m_hasAtLeast && results.size() < p->m_hasAtLeast.get()) { matchResult.failure( "Category with ID " + category.id() + " contains only " + to_string(results.size()) + " results. Expected at least " + to_string(p->m_hasAtLeast.get())); } if (p->m_title) { check_string(matchResult, category, "title", category.title(), p->m_title.get()); } if (p->m_icon) { check_string(matchResult, category, "icon", category.icon(), p->m_icon.get()); } if (p->m_headerLink) { check_string(matchResult, category, "header_link", category.headerLink(), p->m_headerLink.get()); } if (p->m_renderer) { check_variant(matchResult, category, "renderer", category.renderer(), p->m_renderer.get()); } if (p->m_components) { check_variant(matchResult, category, "components", category.components(), p->m_components.get()); } if (!p->m_results.empty()) { switch (p->m_mode) { case Mode::all: p->all(matchResult, results); break; case Mode::starts_with: p->startsWith(matchResult, results); break; case Mode::by_uri: p->byUri(matchResult, results); break; } } } MatchResult CategoryMatcher::match(const results::Category& category) const { MatchResult matchResult; match(matchResult, category); return matchResult; } string& CategoryMatcher::getId() const { return p->m_id; } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/department-matcher.cpp0000644000015600001650000001771512672630457031141 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include using namespace std; using namespace boost; namespace unity { namespace scopeharness { namespace matcher { namespace { static void check_string(MatchResult& matchResult, const results::Department& department, const string& name, const string& actualValue, const string& expectedValue) { if (actualValue != expectedValue) { matchResult.failure( "Department with ID '" + department.id() + "' has '" + name + "' == '" + actualValue + "' but expected '" + expectedValue + "'"); } } static void check_bool(MatchResult& matchResult, const results::Department& department, const string& name, bool actualValue, bool expectedValue) { if (actualValue != expectedValue) { matchResult.failure( "Department with ID '" + department.id() + "' has '" + name + "' == " + (actualValue ? "true" : "false") + " but expected " + (expectedValue ? "true" : "false")); } } } struct DepartmentMatcher::_Priv { void all(MatchResult& matchResult, const results::Department& department) { if (department.size() != m_children.size()) { matchResult.failure( "Department contained " + to_string(department.size()) + " children, expected " + to_string(m_children.size())); return; } for (size_t row = 0; row < m_children.size(); ++row) { const auto& expectedChild = m_children[row]; auto actualChild = department.child(row); expectedChild.match(matchResult, actualChild); } } void byId(MatchResult& matchResult, const results::Department& department) { unordered_map childDepartmentsById; for (size_t row = 0; row < department.size(); ++row) { auto child = department.child(row); childDepartmentsById.insert({child.id(), child}); } for (const auto& expectedChild : m_children) { auto it = childDepartmentsById.find(expectedChild.getId()); if (it == childDepartmentsById.end()) { matchResult.failure( "Child department with ID " + expectedChild.getId() + " could not be found"); } else { expectedChild.match(matchResult, it->second); } } } void startsWith(MatchResult& matchResult, const results::Department& department) { if (department.size() < m_children.size()) { matchResult.failure( "Department contained " + to_string(department.size()) + " expected at least " + to_string(m_children.size())); return; } for (size_t row = 0; row < m_children.size(); ++row) { const auto& expectedChild = m_children[row]; auto actualChild = department.child(row); expectedChild.match(matchResult, actualChild); } } optional m_id; optional m_label; optional m_allLabel; optional m_parentId; optional m_parentLabel; optional m_isRoot; optional m_isHidden; optional m_hasExactly; optional m_hasAtLeast; Mode m_mode = Mode::all; vector m_children; }; DepartmentMatcher::DepartmentMatcher() : p(new _Priv) { } DepartmentMatcher::~DepartmentMatcher() { } DepartmentMatcher& DepartmentMatcher::mode(Mode mode) { p->m_mode = mode; return *this; } DepartmentMatcher& DepartmentMatcher::hasExactly(size_t childCount) { p->m_hasExactly = childCount; return *this; } DepartmentMatcher& DepartmentMatcher::hasAtLeast(size_t childCount) { p->m_hasAtLeast = childCount; return *this; } DepartmentMatcher& DepartmentMatcher::id(const string& id) { p->m_id = id; return *this; } DepartmentMatcher& DepartmentMatcher::label(const string& label) { p->m_label = label; return *this; } DepartmentMatcher& DepartmentMatcher::allLabel(const string& allLabel) { p->m_allLabel = allLabel; return *this; } DepartmentMatcher& DepartmentMatcher::parentId(const string& parentId) { p->m_parentId = parentId; return *this; } DepartmentMatcher& DepartmentMatcher::parentLabel(const string& parentLabel) { p->m_parentLabel = parentLabel; return *this; } DepartmentMatcher& DepartmentMatcher::isRoot(bool isRoot) { p->m_isRoot = isRoot; return *this; } DepartmentMatcher& DepartmentMatcher::isHidden(bool isHidden) { p->m_isHidden = isHidden; return *this; } DepartmentMatcher& DepartmentMatcher::child(const ChildDepartmentMatcher& child) { p->m_children.emplace_back(child); return *this; } DepartmentMatcher& DepartmentMatcher::child(ChildDepartmentMatcher&& child) { p->m_children.emplace_back(child); return *this; } MatchResult DepartmentMatcher::match(const results::Department& department) const { MatchResult matchResult; match(matchResult, department); return matchResult; } void DepartmentMatcher::match(MatchResult& matchResult, const results::Department& department) const { if (p->m_id) { check_string(matchResult, department, "id", department.id(), p->m_id.get()); } if (p->m_label) { check_string(matchResult, department, "label", department.label(), p->m_label.get()); } if (p->m_allLabel) { check_string(matchResult, department, "all label", department.allLabel(), p->m_allLabel.get()); } if (p->m_parentId) { check_string(matchResult, department, "parent ID", department.parentId(), p->m_parentId.get()); } if (p->m_parentLabel) { check_string(matchResult, department, "parent label", department.parentLabel(), p->m_parentLabel.get()); } if (p->m_isRoot) { check_bool(matchResult, department, "is root", department.isRoot(), p->m_isRoot.get()); } if (p->m_isHidden) { check_bool(matchResult, department, "is hidden", department.isHidden(), p->m_isHidden.get()); } if (p->m_hasExactly && department.size() != p->m_hasExactly.get()) { matchResult.failure( "Expected exactly " + to_string(p->m_hasExactly.get()) + " child departments"); } if (p->m_hasAtLeast && department.size() < p->m_hasAtLeast.get()) { matchResult.failure( "Expected at least " + to_string(p->m_hasAtLeast.get()) + " child departments"); } if (!p->m_children.empty()) { switch (p->m_mode) { case Mode::all: p->all(matchResult, department); break; case Mode::by_id: p->byId(matchResult, department); break; case Mode::starts_with: p->startsWith(matchResult, department); break; } } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/settings-option-matcher.cpp0000644000015600001650000001343612672630457032140 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #include #include using namespace std; using namespace boost; namespace sc = unity::scopes; namespace unity { namespace scopeharness { namespace matcher { static string to_string(view::SettingsView::OptionType t) { switch (t) { case view::SettingsView::OptionType::String: return "string"; case view::SettingsView::OptionType::Number: return "number"; case view::SettingsView::OptionType::List: return "list"; case view::SettingsView::OptionType::Boolean: return "boolean"; default: break; } throw std::logic_error("Unexpected settings option type"); } // // Convert scopes::Variant of type int/int64_t/double // to double. static double number_to_double(const sc::Variant v) { auto tp = v.which(); if (tp == sc::Variant::Double) { return v.get_double(); } if (tp == sc::Variant::Int) { return static_cast(v.get_int()); } if (tp == sc::Variant::Int64) { return static_cast(v.get_int64_t()); } throw std::logic_error("Variant doesn't have numeric value"); } static void check(MatchResult& matchResult, const view::SettingsView::Option& option, const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue) { if (!(actualValue == expectedValue)) { // the values may be actually the same but of different type; also doubles should be compared // with some fuzziness. try { if (std::abs(number_to_double(actualValue) - number_to_double(expectedValue)) < 0.0000000001f) { return; } } catch (...) { // ignore - no match between variants possible, error out below } auto actualValueString = actualValue.serialize_json(); auto expectedValueString = expectedValue.serialize_json(); // serialize_json includes a trailing carriage return actualValueString.pop_back(); expectedValueString.pop_back(); matchResult.failure( "Option with ID '" + option.id + "' has '" + name + "' == '" + actualValueString + "' but expected '" + expectedValueString + "'"); } } struct SettingsOptionMatcher::_Priv { std::string m_optionId; optional m_optionType; optional m_displayName; optional m_defaultValue; optional m_value; optional m_displayValues; }; SettingsOptionMatcher::SettingsOptionMatcher(const std::string& optionId) : p(new _Priv) { p->m_optionId = optionId; } SettingsOptionMatcher::SettingsOptionMatcher(const SettingsOptionMatcher& other) : p(new _Priv) { *this = other; } SettingsOptionMatcher& SettingsOptionMatcher::operator=(const SettingsOptionMatcher& other) { p->m_optionId = other.p->m_optionId; p->m_optionType = other.p->m_optionType; p->m_displayName = other.p->m_displayName; p->m_defaultValue = other.p->m_defaultValue; p->m_value = other.p->m_value; p->m_displayValues = other.p->m_displayValues; return *this; } std::string SettingsOptionMatcher::getId() const { return p->m_optionId; } SettingsOptionMatcher& SettingsOptionMatcher::displayName(const std::string& name) { p->m_displayName = name; return *this; } SettingsOptionMatcher& SettingsOptionMatcher::optionType(view::SettingsView::OptionType optionType) { p->m_optionType = optionType; return *this; } SettingsOptionMatcher& SettingsOptionMatcher::defaultValue(const sc::Variant& value) { p->m_defaultValue = value; return *this; } SettingsOptionMatcher& SettingsOptionMatcher::value(const sc::Variant& value) { p->m_value = value; return *this; } SettingsOptionMatcher& SettingsOptionMatcher::displayValues(const unity::scopes::VariantArray& values) { p->m_displayValues = values; return *this; } void SettingsOptionMatcher::match(MatchResult& matchResult, const view::SettingsView::Option& option) const { if (p->m_optionId != option.id) { matchResult.failure("Option ID " + option.id + " != " + p->m_optionId); } if (p->m_optionType && p->m_optionType != option.optionType) { matchResult.failure("Option ID " + option.id + " is of type " + to_string(option.optionType) + ", expected " + to_string(p->m_optionType.get())); } if (p->m_displayName) { check(matchResult, option, "displayName", sc::Variant(option.displayName), sc::Variant(p->m_displayName.get())); } if (p->m_defaultValue) { check(matchResult, option, "defaultValue", option.defaultValue, p->m_defaultValue.get()); } if (p->m_value) { check(matchResult, option, "value", option.value, p->m_value.get()); } if (p->m_displayValues) { check(matchResult, option, "displayValues", sc::Variant(option.displayValues), sc::Variant(p->m_displayValues.get())); } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-matcher.h0000644000015600001650000000314112672630457030110 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace scopeharness { namespace matcher { class PreviewWidgetMatcher; class Q_DECL_EXPORT PreviewMatcher final { public: PreviewMatcher(); ~PreviewMatcher(); PreviewMatcher(const PreviewMatcher& other); PreviewMatcher(PreviewMatcher&& other); PreviewMatcher& operator=(const PreviewMatcher& other); PreviewMatcher& operator=(PreviewMatcher&& other); PreviewMatcher& widget(const PreviewWidgetMatcher& previewWidgetMatcher); PreviewMatcher& widget(PreviewWidgetMatcher&& previewWidgetMatcher); MatchResult match(const preview::PreviewWidgetList& previewWidgetList) const; void match(MatchResult& matchResult, const preview::PreviewWidgetList& previewWidgetList) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/category-list-matcher.cpp0000644000015600001650000001175712672630457031564 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include using namespace std; using namespace boost; namespace unity { namespace scopeharness { namespace matcher { struct CategoryListMatcher::_Priv { Mode m_mode = Mode::all; vector m_categories; optional m_hasAtLeast; optional m_hasExactly; void all(MatchResult& matchResult, const results::Category::List& categoryList) { if (categoryList.size() != m_categories.size()) { matchResult.failure( "Category list contained " + to_string(categoryList.size()) + " expected " + to_string(m_categories.size())); return; } for (size_t row = 0; row < m_categories.size(); ++row) { const auto& expectedCategory = m_categories[row]; const auto& actualCategory = categoryList[row]; expectedCategory.match(matchResult, actualCategory); } } void byId(MatchResult& matchResult, const results::Category::List& categoryList) { unordered_map categoriesById; for (const auto& category : categoryList) { categoriesById.insert({category.id(), category}); } for (const auto& expectedCategory : m_categories) { auto it = categoriesById.find(expectedCategory.getId()); if (it == categoriesById.end()) { matchResult.failure( "Category with ID " + expectedCategory.getId() + " could not be found"); } else { expectedCategory.match(matchResult, it->second); } } } void startsWith(MatchResult& matchResult, const results::Category::List& categoryList) { if (categoryList.size() < m_categories.size()) { matchResult.failure( "Category list contained " + to_string(categoryList.size()) + " expected at least " + to_string(m_categories.size())); return; } for (size_t row = 0; row < m_categories.size(); ++row) { const auto& expectedCategory = m_categories[row]; const auto& actualCategory = categoryList[row]; expectedCategory.match(matchResult, actualCategory); } } }; CategoryListMatcher::CategoryListMatcher() : p(new _Priv) { } CategoryListMatcher& CategoryListMatcher::mode(CategoryListMatcher::Mode mode) { p->m_mode = mode; return *this; } CategoryListMatcher& CategoryListMatcher::category(CategoryMatcher&& categoryMatcher) { p->m_categories.emplace_back(std::move(categoryMatcher)); return *this; } CategoryListMatcher& CategoryListMatcher::category(const CategoryMatcher& categoryMatcher) { p->m_categories.emplace_back(categoryMatcher); return *this; } CategoryListMatcher& CategoryListMatcher::hasAtLeast(size_t minimum) { p->m_hasAtLeast = minimum; return *this; } CategoryListMatcher& CategoryListMatcher::hasExactly(size_t amount) { p->m_hasExactly = amount; return *this; } MatchResult CategoryListMatcher::match(const results::Category::List& categoryList) const { MatchResult matchResult; if (p->m_hasAtLeast && categoryList.size() < p->m_hasAtLeast.get()) { matchResult.failure( "Expected at least " + to_string(p->m_hasAtLeast.get()) + " categories"); } if (p->m_hasExactly && categoryList.size() != p->m_hasExactly.get()) { matchResult.failure( "Expected exactly " + to_string(p->m_hasExactly.get()) + " categories"); } if (!p->m_categories.empty()) { switch (p->m_mode) { case Mode::all: p->all(matchResult, categoryList); break; case Mode::by_id: p->byId(matchResult, categoryList); break; case Mode::starts_with: p->startsWith(matchResult, categoryList); break; } } return matchResult; } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/result-matcher.h0000644000015600001650000000422112672630457027745 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace scopes { class Variant; } namespace scopeharness { namespace results { class Result; } namespace matcher { class Q_DECL_EXPORT ResultMatcher final { public: ResultMatcher(const ScopeUri& uri); ResultMatcher(const std::string& uri); static ResultMatcher any_uri(); ~ResultMatcher() = default; ResultMatcher(const ResultMatcher& other); ResultMatcher& operator=(const ResultMatcher& other); ResultMatcher& operator=(ResultMatcher&& other); ResultMatcher& dndUri(const std::string& dndUri); ResultMatcher& title(const std::string& title); ResultMatcher& art(const std::string& art); ResultMatcher& subtitle(const std::string& subtitle); ResultMatcher& emblem(const std::string& emblem); ResultMatcher& mascot(const std::string& mascot); ResultMatcher& attributes(const unity::scopes::Variant& attributes); ResultMatcher& summary(const unity::scopes::Variant& summary); ResultMatcher& background(const unity::scopes::Variant& background); ResultMatcher& property(const std::string& name, const unity::scopes::Variant& value); MatchResult match(const results::Result& result) const; void match(MatchResult& matchResult, const results::Result& result) const; std::string getUri() const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/match-result.cpp0000644000015600001650000000363312672630457027757 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include using namespace std; namespace unity { namespace scopeharness { namespace matcher { struct MatchResult::_Priv { bool m_success = true; vector m_failures; }; MatchResult::MatchResult() : p(new _Priv) { } MatchResult::MatchResult(MatchResult&& other) { *this = std::move(other); } MatchResult::MatchResult(const MatchResult& other) : p(new _Priv) { *this = other; } MatchResult& MatchResult::operator=(const MatchResult& other) { p->m_success = other.p->m_success; p->m_failures= other.p->m_failures; return *this; } MatchResult& MatchResult::operator=(MatchResult&& other) { p = std::move(other.p); return *this; } void MatchResult::failure(const string& message) { p->m_success = false; p->m_failures.emplace_back(message); } bool MatchResult::success() const { return p->m_success; } vector& MatchResult::failures() const { return p->m_failures; } string MatchResult::concat_failures() const { stringstream ss; ss << "Failed expectations:" << endl; for (const auto& failure : p->m_failures) { ss << failure << endl; } return ss.str(); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/category-matcher.h0000644000015600001650000000416112672630457030247 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace scopes { class Variant; } namespace scopeharness { namespace results { class Category; } namespace matcher { class ResultMatcher; class Q_DECL_EXPORT CategoryMatcher final { public: enum class Mode { all, starts_with, by_uri }; CategoryMatcher(const std::string& id); CategoryMatcher(const CategoryMatcher& other); CategoryMatcher(CategoryMatcher&& other); CategoryMatcher& operator=(const CategoryMatcher& other); CategoryMatcher& operator=(CategoryMatcher&& other); ~CategoryMatcher() = default; CategoryMatcher& mode(Mode mode); CategoryMatcher& title(const std::string& title); CategoryMatcher& icon(const std::string& icon); CategoryMatcher& headerLink(const std::string& headerLink); CategoryMatcher& hasAtLeast(std::size_t minimum); CategoryMatcher& renderer(const unity::scopes::Variant& renderer); CategoryMatcher& components(const unity::scopes::Variant& components); CategoryMatcher& result(const ResultMatcher& resultMatcher); CategoryMatcher& result(ResultMatcher&& resultMatcher); std::string& getId() const; MatchResult match(const results::Category& category) const; void match(MatchResult& matchResult, const results::Category& category) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-column-matcher.h0000644000015600001650000000323012672630457031402 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace scopeharness { namespace matcher { class PreviewMatcher; class Q_DECL_EXPORT PreviewColumnMatcher final { public: PreviewColumnMatcher(); PreviewColumnMatcher(const PreviewColumnMatcher& other); PreviewColumnMatcher(PreviewColumnMatcher&& other); ~PreviewColumnMatcher(); PreviewColumnMatcher& operator=(const PreviewColumnMatcher& other); PreviewColumnMatcher& operator=(PreviewColumnMatcher&& other); PreviewColumnMatcher& column(const PreviewMatcher& previewMatcher); PreviewColumnMatcher& column(PreviewMatcher&& previewMatcher); MatchResult match(const std::vector& preview) const; void match(MatchResult& matchResult, const std::vector& preview) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/category-list-matcher.h0000644000015600001650000000350012672630457031214 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include #include namespace unity { namespace scopeharness { namespace matcher { class CategoryMatcher; class ResultsView; class Q_DECL_EXPORT CategoryListMatcher final { public: enum class Mode { all, by_id, starts_with }; CategoryListMatcher(); ~CategoryListMatcher() = default; CategoryListMatcher& mode(Mode mode); CategoryListMatcher& category(const CategoryMatcher& categoryMatcher); CategoryListMatcher& category(CategoryMatcher&& categoryMatcher); CategoryListMatcher& hasAtLeast(std::size_t minimum); CategoryListMatcher& hasExactly(std::size_t amount); MatchResult match(const results::Category::List& resultList) const; protected: CategoryListMatcher(const CategoryListMatcher& other) = delete; CategoryListMatcher(CategoryListMatcher&& other) = delete; CategoryListMatcher& operator=(const CategoryListMatcher& other) = delete; CategoryListMatcher& operator=(CategoryListMatcher&& other) = delete; struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/settings-matcher.cpp0000644000015600001650000001105612672630457030626 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #include #include #include #include using namespace std; using namespace boost; namespace unity { namespace scopeharness { namespace matcher { struct SettingsMatcher::_Priv { Mode m_mode = Mode::all; vector m_options; optional m_hasAtLeast; optional m_hasExactly; void all(MatchResult& matchResult, const view::SettingsView& settings) { auto opts = settings.options(); if (opts.size() != m_options.size()) { matchResult.failure( "Settings options list contained " + to_string(opts.size()) + " expected " + to_string(m_options.size())); return; } for (size_t row = 0; row < m_options.size(); ++row) { const auto& expected = m_options[row]; const auto& actual = opts[row]; expected.match(matchResult, actual); } } void byId(MatchResult& matchResult, const view::SettingsView& settings) { unordered_map optionsById; for (const auto& opt: settings.options()) { optionsById.insert({opt.id, opt}); } for (const auto& expected: m_options) { auto it = optionsById.find(expected.getId()); if (it == optionsById.end()) { matchResult.failure( "Settings option with ID " + expected.getId() + " could not be found"); } else { expected.match(matchResult, it->second); } } } void startsWith(MatchResult& matchResult, const view::SettingsView& settings) { auto opts = settings.options(); if (opts.size() < m_options.size()) { matchResult.failure( "Settings options list contained " + to_string(opts.size()) + " expected at least " + to_string(m_options.size())); return; } for (size_t row = 0; row < m_options.size(); ++row) { const auto& expected = m_options[row]; const auto& actual = opts[row]; expected.match(matchResult, actual); } } }; SettingsMatcher::SettingsMatcher() : p(new _Priv) { } SettingsMatcher& SettingsMatcher::mode(Mode mode) { p->m_mode= mode; return *this; } SettingsMatcher& SettingsMatcher::hasAtLeast(size_t minimum) { p->m_hasAtLeast = minimum; return *this; } SettingsMatcher& SettingsMatcher::hasExactly(size_t amount) { p->m_hasExactly = amount; return *this; } SettingsMatcher& SettingsMatcher::option(const SettingsOptionMatcher& optionMatcher) { p->m_options.emplace_back(optionMatcher); return *this; } MatchResult SettingsMatcher::match(const view::SettingsView::SPtr& settings) const { MatchResult matchResult; if (p->m_hasAtLeast && settings->count() < p->m_hasAtLeast) { matchResult.failure( "Expected at least " + to_string(p->m_hasAtLeast.get()) + " options"); } if (p->m_hasExactly && settings->count() != p->m_hasExactly) { matchResult.failure( "Expected exactly " + to_string(p->m_hasExactly.get()) + " options"); } if (!p->m_options.empty()) { switch (p->m_mode) { case Mode::all: p->all(matchResult, *settings); break; case Mode::by_id: p->byId(matchResult, *settings); break; case Mode::starts_with: p->startsWith(matchResult, *settings); break; } } return matchResult; } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/child-department-matcher.h0000644000015600001650000000332712672630457031661 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include namespace unity { namespace scopeharness { namespace results { class ChildDepartment; } namespace matcher { class Q_DECL_EXPORT ChildDepartmentMatcher final { public: ChildDepartmentMatcher(const std::string& id); ChildDepartmentMatcher(const ChildDepartmentMatcher& other); ChildDepartmentMatcher(ChildDepartmentMatcher&& other); ~ChildDepartmentMatcher(); ChildDepartmentMatcher& operator=(const ChildDepartmentMatcher& other); ChildDepartmentMatcher& operator=(ChildDepartmentMatcher&& other); std::string getId() const; ChildDepartmentMatcher& label(const std::string& label); ChildDepartmentMatcher& hasChildren(bool hasChildren); ChildDepartmentMatcher& isActive(bool isActive); MatchResult match(const results::ChildDepartment& childDepartment) const; void match(MatchResult& matchResult, const results::ChildDepartment& childDepartment) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/settings-option-matcher.h0000644000015600001650000000356712672630457031611 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #pragma once #include #include #include #include #include namespace unity { namespace scopeharness { namespace matcher { class Q_DECL_EXPORT SettingsOptionMatcher final { public: SettingsOptionMatcher(const std::string& optionId); SettingsOptionMatcher(const SettingsOptionMatcher&); SettingsOptionMatcher(SettingsOptionMatcher&&) = default; SettingsOptionMatcher& operator=(const SettingsOptionMatcher&); SettingsOptionMatcher& operator=(SettingsOptionMatcher&&) = default; SettingsOptionMatcher& displayName(const std::string& name); SettingsOptionMatcher& optionType(view::SettingsView::OptionType optionType); SettingsOptionMatcher& defaultValue(const unity::scopes::Variant& value); SettingsOptionMatcher& value(const unity::scopes::Variant& value); SettingsOptionMatcher& displayValues(const unity::scopes::VariantArray& values); std::string getId() const; void match(MatchResult& matchResult, const view::SettingsView::Option& option) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-matcher.cpp0000644000015600001650000000507612672630457030454 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include using namespace std; namespace unity { namespace scopeharness { namespace matcher { struct PreviewMatcher::_Priv { vector m_matchers; }; PreviewMatcher::PreviewMatcher() : p(new _Priv) { } PreviewMatcher::~PreviewMatcher() { } PreviewMatcher::PreviewMatcher(const PreviewMatcher& other) : p(new _Priv) { *this = other; } PreviewMatcher::PreviewMatcher(PreviewMatcher&& other) { *this = std::move(other); } PreviewMatcher& PreviewMatcher::operator=(const PreviewMatcher& other) { p->m_matchers = other.p->m_matchers; return *this; } PreviewMatcher& PreviewMatcher::operator=(PreviewMatcher&& other) { p = std::move(other.p); return *this; } PreviewMatcher& PreviewMatcher::widget(const PreviewWidgetMatcher& previewWidgetMatcher) { p->m_matchers.emplace_back(previewWidgetMatcher); return *this; } PreviewMatcher& PreviewMatcher::widget(PreviewWidgetMatcher&& previewWidgetMatcher) { p->m_matchers.emplace_back(previewWidgetMatcher); return *this; } MatchResult PreviewMatcher::match(const preview::PreviewWidgetList& previewWidgetList) const { MatchResult matchResult; match(matchResult, previewWidgetList); return matchResult; } void PreviewMatcher::match(MatchResult& matchResult, const preview::PreviewWidgetList& previewWidgetList) const { if (p->m_matchers.size() != previewWidgetList.size()) { matchResult.failure( "Incorrect number of preview widgets " + to_string(previewWidgetList.size()) + ", expected " + to_string(p->m_matchers.size())); return; } for (size_t i = 0; i < p->m_matchers.size(); ++i) { p->m_matchers.at(i).match(matchResult, previewWidgetList.at(i)); } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-widget-matcher.cpp0000644000015600001650000001026012672630457031724 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include using namespace std; using namespace boost; namespace sc = unity::scopes; namespace unity { namespace scopeharness { namespace matcher { namespace { static void check_string(MatchResult& matchResult, const preview::PreviewWidget& previewWidget, const string& name, const string& actualValue, const string& expectedValue) { if (actualValue != expectedValue) { matchResult.failure( "PreviewWidget with ID '" + previewWidget.id() + "' has '" + name + "' == '" + actualValue + "' but expected '" + expectedValue + "'"); } } static void check_variant(MatchResult& matchResult, const preview::PreviewWidget& previewWidget, const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue) { if (!(actualValue == expectedValue)) { auto actualValueString = actualValue.serialize_json(); auto expectedValueString = expectedValue.serialize_json(); // serialize_json includes a trailing carriage return actualValueString.pop_back(); expectedValueString.pop_back(); matchResult.failure( "PreviewWidget with ID '" + previewWidget.id() + "' has '" + name + "' == '" + actualValueString + "' but expected '" + expectedValueString + "'"); } } } struct PreviewWidgetMatcher::_Priv { string m_id; optional m_type; optional m_data; }; PreviewWidgetMatcher::PreviewWidgetMatcher(const string& id) : p(new _Priv) { p->m_id = id; } PreviewWidgetMatcher::PreviewWidgetMatcher(const PreviewWidgetMatcher& other) : p(new _Priv) { *this = other; } PreviewWidgetMatcher::PreviewWidgetMatcher(PreviewWidgetMatcher&& other) { *this = std::move(other); } PreviewWidgetMatcher& PreviewWidgetMatcher::operator=(const PreviewWidgetMatcher& other) { p->m_id = other.p->m_id; p->m_type = other.p->m_type; p->m_data = other.p->m_data; return *this; } PreviewWidgetMatcher& PreviewWidgetMatcher::operator=(PreviewWidgetMatcher&& other) { p = std::move(other.p); return *this; } PreviewWidgetMatcher::~PreviewWidgetMatcher() { } PreviewWidgetMatcher& PreviewWidgetMatcher::type(const string& type) { p->m_type = type; return *this; } PreviewWidgetMatcher& PreviewWidgetMatcher::data(const sc::Variant& data) { p->m_data = data; return *this; } PreviewWidgetMatcher& PreviewWidgetMatcher::data(sc::Variant&& data) { p->m_data = std::move(data); return *this; } MatchResult PreviewWidgetMatcher::match(const preview::PreviewWidget& previewWidget) const { MatchResult matchResult; match(matchResult, previewWidget); return matchResult; } void PreviewWidgetMatcher::match(MatchResult& matchResult, const preview::PreviewWidget& previewWidget) const { check_string(matchResult, previewWidget, "id", previewWidget.id(), p->m_id); if (p->m_type) { check_string(matchResult, previewWidget, "type", previewWidget.type(), p->m_type.get()); } if (p->m_data) { auto dict = previewWidget.data().get_dict(); // No point comparing this transitory field dict.erase("session-id"); check_variant(matchResult, previewWidget, "data", sc::Variant(dict), p->m_data.get()); } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/child-department-matcher.cpp0000644000015600001650000001021612672630457032207 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include using namespace std; using namespace boost; namespace unity { namespace scopeharness { namespace matcher { namespace { static void check_string(MatchResult& matchResult, const results::ChildDepartment& department, const string& name, const string& actualValue, const string& expectedValue) { if (actualValue != expectedValue) { matchResult.failure( "Child department with ID '" + department.id() + "' has '" + name + "' == '" + actualValue + "' but expected '" + expectedValue + "'"); } } static void check_bool(MatchResult& matchResult, const results::ChildDepartment& department, const string& name, bool actualValue, bool expectedValue) { if (actualValue != expectedValue) { matchResult.failure( "Child department with ID '" + department.id() + "' has '" + name + "' == " + (actualValue ? "true" : "false") + " but expected " + (expectedValue ? "true" : "false")); } } } struct ChildDepartmentMatcher::_Priv { string m_id; optional m_label; optional m_hasChildren; optional m_isActive; }; ChildDepartmentMatcher::ChildDepartmentMatcher(const string& id) : p(new _Priv) { p->m_id = id; } ChildDepartmentMatcher::~ChildDepartmentMatcher() { } ChildDepartmentMatcher::ChildDepartmentMatcher(const ChildDepartmentMatcher& other) : p(new _Priv) { *this = other; } ChildDepartmentMatcher::ChildDepartmentMatcher(ChildDepartmentMatcher&& other) { *this = std::move(other); } ChildDepartmentMatcher& ChildDepartmentMatcher::operator=(const ChildDepartmentMatcher& other) { p->m_id = other.p->m_id; p->m_label = other.p->m_label; p->m_hasChildren = other.p->m_hasChildren; p->m_isActive = other.p->m_isActive; return *this; } ChildDepartmentMatcher& ChildDepartmentMatcher::operator=(ChildDepartmentMatcher&& other) { p = std::move(other.p); return *this; } string ChildDepartmentMatcher::getId() const { return p->m_id; } ChildDepartmentMatcher& ChildDepartmentMatcher::label(const std::string& label) { p->m_label = label; return *this; } ChildDepartmentMatcher& ChildDepartmentMatcher::hasChildren(bool hasChildren) { p->m_hasChildren = hasChildren; return *this; } ChildDepartmentMatcher& ChildDepartmentMatcher::isActive(bool isActive) { p->m_isActive = isActive; return *this; } MatchResult ChildDepartmentMatcher::match(const results::ChildDepartment& childDepartment) const { MatchResult matchResult; match(matchResult, childDepartment); return matchResult; } void ChildDepartmentMatcher::match(MatchResult& matchResult, const results::ChildDepartment& childDepartment) const { check_string(matchResult, childDepartment, "id", childDepartment.id(), p->m_id); if (p->m_label) { check_string(matchResult, childDepartment, "label", childDepartment.label(), p->m_label.get()); } if (p->m_hasChildren) { check_bool(matchResult, childDepartment, "has children", childDepartment.hasChildren(), p->m_hasChildren.get()); } if (p->m_isActive) { check_bool(matchResult, childDepartment, "is active", childDepartment.isActive(), p->m_isActive.get()); } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/department-matcher.h0000644000015600001650000000430512672630457030575 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #pragma once namespace unity { namespace scopeharness { namespace results { class Department; } namespace matcher { class Q_DECL_EXPORT DepartmentMatcher final { public: enum class Mode { all, by_id, starts_with }; DepartmentMatcher(); DepartmentMatcher(const DepartmentMatcher& other) = delete; DepartmentMatcher(DepartmentMatcher&& other) = delete; ~DepartmentMatcher(); DepartmentMatcher& operator=(const DepartmentMatcher& other) = delete; DepartmentMatcher& operator=(DepartmentMatcher&& other) = delete; DepartmentMatcher& mode(Mode mode); DepartmentMatcher& hasExactly(std::size_t childCount); DepartmentMatcher& hasAtLeast(std::size_t childCount); DepartmentMatcher& id(const std::string& id); DepartmentMatcher& label(const std::string& label); DepartmentMatcher& allLabel(const std::string& allLabel); DepartmentMatcher& parentId(const std::string& parentId); DepartmentMatcher& parentLabel(const std::string& parentLabel); DepartmentMatcher& isRoot(bool isRoot); DepartmentMatcher& isHidden(bool isHidden); DepartmentMatcher& child(const ChildDepartmentMatcher& child); DepartmentMatcher& child(ChildDepartmentMatcher&& child); MatchResult match(const results::Department& department) const; void match(MatchResult& matchResult, const results::Department& department) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/scope-uri.h0000644000015600001650000000244712672630457026724 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include namespace unity { namespace scopeharness { namespace matcher { class Q_DECL_EXPORT ScopeUri { public: ScopeUri(const std::string& id); ScopeUri(const ScopeUri& other); ScopeUri(ScopeUri&& other); ~ScopeUri(); ScopeUri& operator=(const ScopeUri& other); ScopeUri& operator=(ScopeUri&& other); ScopeUri& department(const std::string& departmentId); ScopeUri& query(const std::string& queryString); std::string toString() const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/settings-matcher.h0000644000015600001650000000264312672630457030275 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #pragma once #include #include #include #include namespace unity { namespace scopeharness { namespace matcher { class SettingsOptionMatcher; class Q_DECL_EXPORT SettingsMatcher final { public: enum class Mode { all, by_id, starts_with }; SettingsMatcher(); SettingsMatcher& mode(Mode mode); SettingsMatcher& option(const SettingsOptionMatcher& optionMatcher); SettingsMatcher& hasAtLeast(std::size_t minimum); SettingsMatcher& hasExactly(std::size_t amount); MatchResult match(const view::SettingsView::SPtr& settings) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-column-matcher.cpp0000644000015600001650000000520512672630457031741 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include using namespace std; namespace unity { namespace scopeharness { namespace matcher { struct PreviewColumnMatcher::_Priv { vector m_matchers; }; PreviewColumnMatcher::PreviewColumnMatcher() : p(new _Priv) { } PreviewColumnMatcher::~PreviewColumnMatcher() { } PreviewColumnMatcher::PreviewColumnMatcher(const PreviewColumnMatcher& other) : p(new _Priv) { *this = other; } PreviewColumnMatcher::PreviewColumnMatcher(PreviewColumnMatcher&& other) { *this = std::move(other); } PreviewColumnMatcher& PreviewColumnMatcher::operator=(const PreviewColumnMatcher& other) { p->m_matchers = other.p->m_matchers; return *this; } PreviewColumnMatcher& PreviewColumnMatcher::operator=(PreviewColumnMatcher&& other) { p = std::move(other.p); return *this; } PreviewColumnMatcher& PreviewColumnMatcher::column(const PreviewMatcher& previewMatcher) { p->m_matchers.emplace_back(previewMatcher); return *this; } PreviewColumnMatcher& PreviewColumnMatcher::column(PreviewMatcher&& previewMatcher) { p->m_matchers.emplace_back(previewMatcher); return *this; } MatchResult PreviewColumnMatcher::match(const vector& preview) const { MatchResult matchResult; match(matchResult, preview); return matchResult; } void PreviewColumnMatcher::match(MatchResult& matchResult, const vector& preview) const { if (p->m_matchers.size() != preview.size()) { matchResult.failure( "Incorrect number of preview columns " + to_string(preview.size()) + ", expected " + to_string(p->m_matchers.size())); return; } for (size_t i = 0; i < p->m_matchers.size(); ++i) { p->m_matchers.at(i).match(matchResult, preview.at(i)); } } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/match-result.h0000644000015600001650000000254512672630457027425 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include #include namespace unity { namespace scopeharness { namespace matcher { class Q_DECL_EXPORT MatchResult final { public: MatchResult(); MatchResult(MatchResult&& other); MatchResult(const MatchResult& other); MatchResult& operator=(const MatchResult& other); MatchResult& operator=(MatchResult&& other); ~MatchResult() = default; void failure(const std::string& message); bool success() const; std::vector& failures() const; std::string concat_failures() const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/preview-widget-matcher.h0000644000015600001650000000331212672630457031371 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include namespace unity { namespace scopes { class Variant; } namespace scopeharness { namespace preview { class PreviewWidget; } namespace matcher { class Q_DECL_EXPORT PreviewWidgetMatcher final { public: PreviewWidgetMatcher(const std::string& id); PreviewWidgetMatcher(const PreviewWidgetMatcher& other); PreviewWidgetMatcher(PreviewWidgetMatcher&& other); PreviewWidgetMatcher& operator=(const PreviewWidgetMatcher& other); PreviewWidgetMatcher& operator=(PreviewWidgetMatcher&& other); ~PreviewWidgetMatcher(); PreviewWidgetMatcher& type(const std::string& type); PreviewWidgetMatcher& data(const unity::scopes::Variant& data); PreviewWidgetMatcher& data(unity::scopes::Variant&& data); MatchResult match(const preview::PreviewWidget& previewWidget) const; void match(MatchResult& matchResult, const preview::PreviewWidget& previewWidget) const; protected: struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/result-matcher.cpp0000644000015600001650000001772112672630457030311 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include #include using namespace std; using namespace boost; namespace sc = unity::scopes; namespace unity { namespace scopeharness { namespace matcher { namespace { static void check_variant(MatchResult& matchResult, const results::Result& result, const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue) { if (!(actualValue == expectedValue)) { auto actualValueString = actualValue.serialize_json(); auto expectedValueString = expectedValue.serialize_json(); // serialize_json includes a trailing carriage return actualValueString.pop_back(); expectedValueString.pop_back(); matchResult.failure( "Result with URI '" + result.uri() + "' has '" + name + "' == '" + actualValueString + "' but expected '" + expectedValueString + "'"); } } static void check_variant(MatchResult& matchResult, const results::Result& result, const string& name, const sc::Variant& expectedValue) { try { const auto& actualValue = result[name]; check_variant(matchResult, result, name, actualValue, expectedValue); } catch (unity::InvalidArgumentException& e) { matchResult.failure( "Result with URI '" + result.uri() + "' missing expected property '" + name + "'"); } } static void check_string(MatchResult& matchResult, const results::Result& result, const string& name, const string& actualValue, const string& expectedValue) { try { if (actualValue != expectedValue) { matchResult.failure( "Result with URI '" + result.uri() + "' has '" + name + "' == '" + actualValue + "' but expected '" + expectedValue + "'"); } } catch (std::exception& e) { matchResult.failure( "Result with URI '" + result.uri() + "' does not contain expected property '" + name + "'"); } } static void check_regex(MatchResult& matchResult, const results::Result& result, const string& name, const string& actualValue, const regex& expectedValue) { try { if (!regex_match(actualValue, expectedValue)) { matchResult.failure( "Result with URI '" + result.uri() + "' has '" + name + "' == '" + actualValue + "' but expected to match '" + expectedValue.str() + "'"); } } catch (std::exception& e) { matchResult.failure( "Result with URI '" + result.uri() + "' does not contain expected property '" + name + "'"); } } } struct ResultMatcher::_Priv { string m_uri; optional m_dndUri; optional m_title; optional m_art; optional m_subtitle; optional m_emblem; optional m_mascot; optional m_attributes; optional m_summary; optional m_background; vector> m_properties; }; ResultMatcher::ResultMatcher(const string& uri) : p(new _Priv) { p->m_uri = uri; } ResultMatcher::ResultMatcher(const ScopeUri& uri) : p(new _Priv) { p->m_uri = uri.toString(); } ResultMatcher ResultMatcher::any_uri() { return ResultMatcher(string()); } ResultMatcher::ResultMatcher(const ResultMatcher& other) : p(new _Priv) { *this = other; } ResultMatcher& ResultMatcher::operator=(const ResultMatcher& other) { p->m_uri = other.p->m_uri; p->m_dndUri = other.p->m_dndUri; p->m_title = other.p->m_title; p->m_art = other.p->m_art; p->m_subtitle = other.p->m_subtitle; p->m_emblem = other.p->m_emblem; p->m_mascot = other.p->m_mascot; p->m_attributes = other.p->m_attributes; p->m_summary = other.p->m_summary; p->m_background = other.p->m_background; p->m_properties = other.p->m_properties; return *this; } ResultMatcher& ResultMatcher::operator=(ResultMatcher&& other) { p = std::move(other.p); return *this; } ResultMatcher& ResultMatcher::dndUri(const string& dndUri) { p->m_dndUri = dndUri; return *this; } ResultMatcher& ResultMatcher::title(const string& title) { p->m_title = title; return *this; } ResultMatcher& ResultMatcher::art(const string& art) { p->m_art = art; return *this; } ResultMatcher& ResultMatcher::subtitle(const string& subtitle) { p->m_subtitle = subtitle; return *this; } ResultMatcher& ResultMatcher::emblem(const string& emblem) { p->m_emblem = emblem; return *this; } ResultMatcher& ResultMatcher::mascot(const string& mascot) { p->m_mascot = mascot; return *this; } ResultMatcher& ResultMatcher::attributes(const sc::Variant& attributes) { p->m_attributes = attributes; return *this; } ResultMatcher& ResultMatcher::summary(const sc::Variant& summary) { p->m_summary = summary; return *this; } ResultMatcher& ResultMatcher::background(const sc::Variant& background) { p->m_background = background; return *this; } ResultMatcher& ResultMatcher::property(const string& name, const sc::Variant& value) { p->m_properties.emplace_back(make_pair(name, value)); return *this; } MatchResult ResultMatcher::match(const results::Result& result) const { MatchResult matchResult; match(matchResult, result); return matchResult; } void ResultMatcher::match(MatchResult& matchResult, const results::Result& result) const { if(!p->m_uri.empty()) { check_regex(matchResult, result, "uri", result.uri(), regex(p->m_uri)); } if (p->m_dndUri) { check_string(matchResult, result, "dnd_uri", result.dnd_uri(), p->m_dndUri.get()); } if (p->m_title) { check_string(matchResult, result, "title", result.title(), p->m_title.get()); } if (p->m_art) { check_string(matchResult, result, "art", result.art(), p->m_art.get()); } if (p->m_subtitle) { check_string(matchResult, result, "subtitle", result.subtitle(), p->m_subtitle.get()); } if (p->m_emblem) { check_string(matchResult, result, "emblem", result.emblem(), p->m_emblem.get()); } if (p->m_mascot) { check_string(matchResult, result, "mascot", result.mascot(), p->m_mascot.get()); } if (p->m_attributes) { check_variant(matchResult, result, "attributes", result.attributes(), p->m_attributes.get()); } if (p->m_summary) { check_variant(matchResult, result, "summary", result.summary(), p->m_summary.get()); } if (p->m_background) { check_variant(matchResult, result, "background", result.background(), p->m_background.get()); } for (const auto& property : p->m_properties) { check_variant(matchResult, result, property.first, property.second); } } string ResultMatcher::getUri() const { return p->m_uri; } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/matcher/scope-uri.cpp0000644000015600001650000000531712672630457027256 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include using namespace std; namespace unity { namespace scopeharness { namespace matcher { namespace { static void paramJoin(stringstream& s, const vector>& v) { bool first = true; for (const auto& e : v) { if (first) { first = false; s << "\\?"; } else { s << "&"; } s << QUrl::toPercentEncoding(QString::fromStdString(e.first)).constData() << "=" << QUrl::toPercentEncoding(QString::fromStdString(e.second)).constData(); } } } struct ScopeUri::_Priv { string m_id; string m_department; string m_query; }; ScopeUri::ScopeUri(const string& id) : p(new _Priv) { p->m_id = id; } ScopeUri::~ScopeUri() { } ScopeUri::ScopeUri(const ScopeUri& other) : p(new _Priv) { *this = other; } ScopeUri::ScopeUri(ScopeUri&& other) { *this = std::move(other); } ScopeUri& ScopeUri::operator=(const ScopeUri& other) { p->m_id = other.p->m_id; p->m_department = other.p->m_department; p->m_query = other.p->m_query; return *this; } ScopeUri& ScopeUri::operator=(ScopeUri&& other) { p = std::move(other.p); return *this; } ScopeUri& ScopeUri::department(const std::string& departmentId) { p->m_department = departmentId; return *this; } ScopeUri& ScopeUri::query(const std::string& queryString) { p->m_query = queryString; return *this; } string ScopeUri::toString() const { stringstream result; result << "scope:\\/\\/" << QUrl::toPercentEncoding(QString::fromStdString(p->m_id)).constData(); vector> params; if (!p->m_department.empty()) { params.emplace_back(make_pair("department", p->m_department)); } if (!p->m_query.empty()) { params.emplace_back(make_pair("q", p->m_query)); } paramJoin(result, params); return result.str(); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/preview/0000755000015600001650000000000012672635475024701 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/preview/preview-widget.h0000644000015600001650000000313412672630457030010 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include namespace unity { namespace scopeharness { namespace internal { class PreviewWidgetArguments; } namespace view { class AbstractView; class PreviewView; } namespace preview { class Q_DECL_EXPORT PreviewWidget final { public: PreviewWidget(const PreviewWidget& other); PreviewWidget(PreviewWidget&& other); PreviewWidget& operator=(const PreviewWidget& other); PreviewWidget& operator=(PreviewWidget&& other); ~PreviewWidget(); std::string id() const; std::string type() const; unity::scopes::Variant data() const; std::shared_ptr trigger(const std::string& name, const unity::scopes::Variant& v); protected: friend view::PreviewView; PreviewWidget(const internal::PreviewWidgetArguments& arguments); struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/preview/preview-widget-list.cpp0000644000015600001650000000444612672630457031323 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include using namespace std; namespace unity { namespace scopeharness { namespace preview { struct PreviewWidgetList::_Priv { std::vector previewWidgets; }; PreviewWidgetList::PreviewWidgetList(const internal::PreviewWidgetListArguments& arguments) : p(new _Priv) { p->previewWidgets = arguments.previewWidgets; } PreviewWidgetList::PreviewWidgetList(const PreviewWidgetList& other) : p(new _Priv) { *this = other; } PreviewWidgetList::PreviewWidgetList(PreviewWidgetList&& other) { *this = std::move(other); } PreviewWidgetList::~PreviewWidgetList() { } PreviewWidgetList& PreviewWidgetList::operator=(const PreviewWidgetList& other) { p->previewWidgets = other.p->previewWidgets; return *this; } PreviewWidgetList& PreviewWidgetList::operator=(PreviewWidgetList&& other) { p = std::move(other.p); return *this; } PreviewWidget PreviewWidgetList::at(std::size_t index) const { return p->previewWidgets.at(index); } PreviewWidget PreviewWidgetList::at(const std::string& id) const { for (const auto& widget : p->previewWidgets) { if (widget.id() == id) { return widget; } } throw domain_error("Widget '" + id + "' not found"); } PreviewWidget PreviewWidgetList::operator[](std::size_t index) const { return at(index); } PreviewWidget PreviewWidgetList::operator[](const std::string& id) const { return at(id); } std::size_t PreviewWidgetList::size() const { return p->previewWidgets.size(); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/preview/preview-widget.cpp0000644000015600001650000001151112672630457030341 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace ng = scopes_ng; namespace sc = unity::scopes; namespace ss = unity::shell::scopes; namespace unity { namespace scopeharness { using namespace internal; namespace preview { struct PreviewWidget::_Priv { unity::shell::scopes::PreviewWidgetModelInterface* m_previewWidgetModel; QModelIndex m_index; unity::shell::scopes::PreviewModelInterface* m_previewModel; weak_ptr m_resultsView; weak_ptr m_previewView; }; PreviewWidget::PreviewWidget(const internal::PreviewWidgetArguments& arguments) : p(new _Priv) { p->m_previewWidgetModel = arguments.previewWidgetModel; p->m_previewModel = arguments.previewModel; p->m_index = arguments.index; p->m_resultsView = arguments.resultsView; p->m_previewView = arguments.previewView; } PreviewWidget::PreviewWidget(const PreviewWidget& other) : p(new _Priv) { *this = other; } PreviewWidget::PreviewWidget(PreviewWidget&& other) { *this = std::move(other); } PreviewWidget& PreviewWidget::operator=(const PreviewWidget& other) { p->m_previewWidgetModel = other.p->m_previewWidgetModel; p->m_previewModel = other.p->m_previewModel; p->m_index = other.p->m_index; p->m_resultsView = other.p->m_resultsView; p->m_previewView = other.p->m_previewView; return *this; } PreviewWidget& PreviewWidget::operator=(PreviewWidget&& other) { p = std::move(other.p); return *this; } PreviewWidget::~PreviewWidget() { } std::string PreviewWidget::id() const { return p->m_previewWidgetModel->data( p->m_index, ss::PreviewWidgetModelInterface::RoleWidgetId).toString().toStdString(); } std::string PreviewWidget::type() const { return p->m_previewWidgetModel->data( p->m_index, ss::PreviewWidgetModelInterface::RoleType).toString().toStdString(); } sc::Variant PreviewWidget::data() const { return ng::qVariantToScopeVariant( p->m_previewWidgetModel->data( p->m_index, ss::PreviewWidgetModelInterface::RoleProperties)); } view::AbstractView::SPtr PreviewWidget::trigger(const string& name, const sc::Variant& v) { auto ps = dynamic_cast(p->m_previewModel); TestUtils::throwIfNot(bool(ps->associatedScope()), "Preview model has no associated scope"); QSignalSpy showDashSpy(ps->associatedScope(), SIGNAL(showDash())); QVariant widgetData; if ((type() == "actions" || type() == "icon-actions") && v.which() == sc::Variant::Dict && v.get_dict()["actions"].which() == sc::Variant::Array) { for (auto el: v.get_dict()["actions"].get_array()) { auto d = el.get_dict(); if (d["id"].get_string() == name) { widgetData = ng::scopeVariantToQVariant(el); break; } } } else { widgetData = ng::scopeVariantToQVariant(v); } Q_EMIT ps->triggered( QString::fromStdString(id()), QString::fromStdString(name), widgetData.toMap()); if (!showDashSpy.empty()) { return p->m_resultsView.lock(); } TestUtils::throwIfNot(p->m_previewModel->processingAction(), "Should be processing action"); QSignalSpy spy(p->m_previewModel, SIGNAL(processingActionChanged())); TestUtils::throwIfNot(spy.wait(), "Processing action property didn't change"); TestUtils::throwIf(p->m_previewModel->processingAction(), "Should have finished processing action"); view::PreviewView::SPtr previewView = p->m_previewView.lock(); previewView->refresh(); return p->m_previewView.lock(); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/preview/preview-widget-list.h0000644000015600001650000000320412672630457030757 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include namespace unity { namespace scopeharness { namespace internal { struct PreviewWidgetListArguments; } namespace view { class PreviewView; } namespace preview { class Q_DECL_EXPORT PreviewWidgetList { public: PreviewWidgetList(const PreviewWidgetList& other); PreviewWidgetList(PreviewWidgetList&& other); PreviewWidgetList& operator=(const PreviewWidgetList& other); PreviewWidgetList& operator=(PreviewWidgetList&& other); ~PreviewWidgetList(); PreviewWidget at(std::size_t index) const; PreviewWidget at(const std::string& id) const; PreviewWidget operator[](std::size_t index) const; PreviewWidget operator[](const std::string& id) const; std::size_t size() const; protected: friend view::PreviewView; PreviewWidgetList(const internal::PreviewWidgetListArguments& arguments); struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/0000755000015600001650000000000012672635475024172 5ustar pbuserpbgroup00000000000000unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/preview-view.h0000644000015600001650000000373312672630457026775 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace shell { namespace scopes { class PreviewModelInterface; } } namespace scopeharness { class ScopeHarness; namespace results { class Result; } namespace view { class ResultsView; class Q_DECL_EXPORT PreviewView final: public AbstractView { public: UNITY_DEFINES_PTRS(PreviewView); PreviewView(); ~PreviewView() = default; PreviewView(const PreviewView& other) = delete; PreviewView(PreviewView&& other) = delete; PreviewView& operator=(const PreviewView& other) = delete; PreviewView& operator=(PreviewView&& other) = delete; void setColumnCount(unsigned int count); unsigned int columnCount() const; std::vector widgets(); preview::PreviewWidgetList widgetsInColumn(std::size_t column); preview::PreviewWidgetList widgetsInFirstColumn(); protected: friend results::Result; friend ScopeHarness; friend preview::PreviewWidget; void preview(std::shared_ptr previewModel); void setResultsView(std::shared_ptr resultsView); void refresh(); struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/results-view.h0000644000015600001650000000616012672630457027012 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include #include #include #include #include #include #include namespace scopes_ng { class Scopes; } namespace unity { namespace shell { namespace scopes { class CategoriesInterface; } } namespace scopeharness { class ScopeHarness; namespace internal { struct ResultsViewArguments; } namespace view { class PreviewView; class Q_DECL_EXPORT ResultsView final: public AbstractView { public: UNITY_DEFINES_PTRS(ResultsView); ResultsView(const internal::ResultsViewArguments& arguments); ~ResultsView() = default; ResultsView(const ResultsView& other) = delete; ResultsView(ResultsView&& other) = delete; ResultsView& operator=(const ResultsView& other) = delete; ResultsView& operator=(ResultsView&& other) = delete; void setQuery(const std::string& searchString); std::string query() const; void setActiveScope(const std::string& id); std::string activeScope() const; void waitForResultsChange(); bool overrideCategoryJson(std::string const& categoryId, std::string const& json); std::string scopeId() const; std::string displayName() const; std::string iconHint() const; std::string description() const; std::string searchHint() const; std::string shortcut() const; unity::scopes::Variant customizations() const; std::string sessionId() const; int queryId() const; void forceRefresh(); results::Category::List categories(); results::Category category(std::size_t row); results::Category category(const std::string& categoryId); unity::shell::scopes::ScopeInterface::Status status() const; // Navigation bool hasDepartments() const; bool hasAltDepartments() const; std::string departmentId() const; std::string altDepartmentId() const; results::Department browseDepartment(const std::string& id = std::string()); results::Department browseAltDepartment(const std::string& id = std::string()); SettingsView::SPtr settings() const; protected: friend ScopeHarness; friend preview::PreviewWidget; void setPreviewView(std::shared_ptr previewView); struct _Priv; std::shared_ptr<_Priv> p; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/abstract-view.h0000644000015600001650000000240312672630457027110 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #pragma once #include #include namespace unity { namespace scopeharness { namespace view { class Q_DECL_EXPORT AbstractView: public std::enable_shared_from_this { public: UNITY_DEFINES_PTRS(AbstractView); AbstractView() = default; virtual ~AbstractView() = default; AbstractView(const AbstractView& other) = delete; AbstractView(AbstractView&& other) = delete; AbstractView& operator=(const AbstractView& other) = delete; AbstractView& operator=(AbstractView&& other) = delete; }; } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/settings-view.cpp0000644000015600001650000001372212672630457027506 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #include #include #include #include #include #include namespace ss = unity::shell::scopes; namespace sc = unity::scopes; using namespace std; namespace unity { namespace scopeharness { namespace view { struct SettingsView::_Priv { ng::Scope::Ptr m_scope; }; SettingsView::SettingsView(const internal::SettingsViewArguments& args) : p(new _Priv) { p->m_scope = args.m_scope; } SettingsView::Option::List SettingsView::options() const { // // convert all current options from settings model to SettingsView::Option::List auto settings = p->m_scope->settings(); Option::List opts; for (int i = 0; icount(); i++) { Option opt; auto const index = settings->index(i, 0); auto const optType = settings->data(index, ss::SettingsModelInterface::Roles::RoleType).toString().toStdString(); opt.id = settings->data(index, ss::SettingsModelInterface::Roles::RoleSettingId).toString().toStdString(); opt.value = ng::qVariantToScopeVariant(settings->data(index, ss::SettingsModelInterface::Roles::RoleValue)); opt.displayName = settings->data(index, ss::SettingsModelInterface::Roles::RoleDisplayName).toString().toStdString(); auto props = settings->data(index, ss::SettingsModelInterface::Roles::RoleProperties).toMap(); if (props.contains("defaultValue")) { opt.defaultValue = ng::qVariantToScopeVariant(props["defaultValue"]); } if (props.contains("values")) { opt.displayValues = ng::qVariantToScopeVariant(props["values"]).get_array(); } if (optType == "string") { opt.optionType = OptionType::String; } else if (optType == "number") { opt.optionType = OptionType::Number; } else if (optType == "boolean") { opt.optionType = OptionType::Boolean; } else if (optType == "list") { // for list type, the value is an index in the list; // make value keep actual option string. opt.optionType = OptionType::List; auto i = opt.value.get_int64_t(); if (i < static_cast(opt.displayValues.size())) { opt.value = opt.displayValues[i]; if (opt.defaultValue.which() == sc::Variant::Int) { opt.defaultValue = opt.displayValues[opt.defaultValue.get_int()]; } } else { throw std::domain_error("Failed to process list option with ID '" + opt.id + "'. No value for index " + to_string(i)); } } else { throw std::domain_error("Failed to process settings. Unknown option type for option with ID " + opt.id + "'"); } opts.push_back(opt); } return opts; } size_t SettingsView::count() const { return p->m_scope->settings()->count(); } void SettingsView::set(const std::string& option_id, const sc::Variant &value) { auto settings = p->m_scope->settings(); for (auto i = 0; icount(); i++) { auto const index = settings->index(i, 0); auto const id = settings->data(index, ss::SettingsModelInterface::Roles::RoleSettingId).toString().toStdString(); if (id == option_id) { sc::Variant val = value; if (settings->data(index, ss::SettingsModelInterface::Roles::RoleType).toString() == "list") { TestUtils::throwIfNot(value.which() == sc::Variant::String, "Settings updated failed for option with ID '" + option_id + "': only string values are allowed"); // list option expects index of current value, so iterate over list options to find the index. bool found = false; auto props = settings->data(index, ss::SettingsModelInterface::Roles::RoleProperties).toMap(); if (props.contains("values")) { auto str = val.get_string(); auto const values = props["values"].toList(); for (int i = 0; isetData(index, ng::scopeVariantToQVariant(val), ss::SettingsModelInterface::Roles::RoleValue); TestUtils::throwIfNot(settingChangedSpy.wait(), "Settings update failed"); TestUtils::waitForSearchFinish(p->m_scope); return; } } throw std::domain_error("Setting update failed. No such option: '" + option_id + "'"); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/preview-view.cpp0000644000015600001650000001076512672630457027333 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include #include #include #include #include using namespace std; namespace ss = unity::shell::scopes; namespace unity { namespace scopeharness { using namespace internal; namespace view { struct PreviewView::_Priv { preview::PreviewWidgetList iterateWidgetModel(ss::PreviewWidgetModelInterface* previewWidgetModel, ss::PreviewModelInterface* previewModel, PreviewView::SPtr previewView) { vector previewWidgets; int rowCount = previewWidgetModel->rowCount(); for (int row = 0; row < rowCount; ++row) { previewWidgets.emplace_back( preview::PreviewWidget(internal::PreviewWidgetArguments { previewWidgetModel, previewWidgetModel->index(row), previewModel, m_resultsView.lock(), previewView })); } return preview::PreviewWidgetList(internal::PreviewWidgetListArguments{previewWidgets}); } vector iteratePreviewModel(ss::PreviewModelInterface* previewModel, PreviewView::SPtr previewView) { if (!previewModel->loaded()) { QSignalSpy spy(previewModel, SIGNAL(loadedChanged())); spy.wait(); } vector previewModels; int rowCount = previewModel->rowCount(); for (int row = 0; row < rowCount; ++row) { QVariant var = previewModel->data( previewModel->index(row), ss::PreviewModelInterface::RoleColumnModel); previewModels.emplace_back(iterateWidgetModel(var.value(), previewModel, previewView)); } return previewModels; } void setPreviewModel(shared_ptr previewModel, PreviewView::SPtr previewView) { m_previewModel = previewModel; updateModels(previewView); } void updateModels(PreviewView::SPtr previewView) { m_previewModels = iteratePreviewModel(m_previewModel.get(), previewView); } void checkPreviewModel() { TestUtils::throwIfNot(bool(m_previewModel), ""); } shared_ptr m_previewModel; vector m_previewModels; weak_ptr m_resultsView; }; PreviewView::PreviewView() : p(new _Priv) { } void PreviewView::setResultsView(ResultsView::SPtr resultsView) { p->m_resultsView = resultsView; } void PreviewView::preview(shared_ptr previewModel) { p->setPreviewModel(previewModel, dynamic_pointer_cast(shared_from_this())); } void PreviewView::setColumnCount(unsigned int count) { p->checkPreviewModel(); p->m_previewModel->setWidgetColumnCount(count); // TODO Wait? refresh(); } void PreviewView::refresh() { p->updateModels(dynamic_pointer_cast(shared_from_this())); } unsigned int PreviewView::columnCount() const { p->checkPreviewModel(); return p->m_previewModel->widgetColumnCount(); } vector PreviewView::widgets() { p->checkPreviewModel(); return p->m_previewModels; } preview::PreviewWidgetList PreviewView::widgetsInColumn(size_t column) { p->checkPreviewModel(); return p->m_previewModels.at(column); } preview::PreviewWidgetList PreviewView::widgetsInFirstColumn() { return widgetsInColumn(0); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/results-view.cpp0000644000015600001650000002766012672630472027352 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2014 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pete Woods */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace ng = scopes_ng; namespace sc = unity::scopes; namespace ss = unity::shell::scopes; namespace unity { namespace scopeharness { using namespace internal; namespace view { struct ResultsView::_Priv { _Priv(ResultsView& self, shared_ptr scopes) : m_self(self), m_scopes(scopes) { } void checkActiveScope() const { TestUtils::throwIfNot(m_active_scope, "There is no active scope"); } ss::CategoriesInterface* internalRawCategories() const { checkActiveScope(); return m_active_scope->categories(); } results::Category internalCategory(size_t row) { auto cats = internalRawCategories(); auto categoryIndex = cats->index(row); QVariant variant = cats->data(categoryIndex, ng::Categories::RoleCategorySPtr); if (!variant.canConvert()) { throw range_error("Invalid category data at index " + to_string(row)); } auto rawCategory = variant.value(); QVariant resultsVariant = cats->data( cats->index(row), ng::Categories::RoleResultsSPtr); QSharedPointer resultModel = resultsVariant.value< QSharedPointer>(); results::Result::List results; if (resultModel) { for (int i = 0; i < resultModel->rowCount(); ++i) { auto idx = resultModel->index(i); results.emplace_back(results::Result(internal::ResultArguments { resultModel, m_active_scope, idx, dynamic_pointer_cast(m_self.shared_from_this()), m_previewView.lock() })); } } return results::Category(internal::CategoryArguments{cats, categoryIndex, results}); } results::Department browseDepartment(const string& id, bool altNavigation) { if (altNavigation) { throw std::domain_error("ResultsView::browseAltDepartment(): altNavigation is deprecated"); } checkActiveScope(); QSharedPointer navigationModel; navigationModel.reset(m_active_scope->getNavigation(QString::fromStdString(id))); TestUtils::throwIfNot(bool(navigationModel), "Unknown department: '" + id + "'"); QSignalSpy spy(navigationModel.data(), SIGNAL(loadedChanged())); bool shouldUpdate = false; if (m_active_scope->currentNavigationId().toStdString() != id) { shouldUpdate = true; } if (shouldUpdate) { m_active_scope->setNavigationState(QString::fromStdString(id)); TestUtils::waitForSearchFinish(m_active_scope); } if (!navigationModel->loaded()) { TestUtils::throwIfNot(spy.wait(), "Department model failed to load"); } return results::Department(internal::DepartmentArguments{navigationModel}); } ResultsView& m_self; shared_ptr m_scopes; weak_ptr m_previewView; ng::Scope::Ptr m_active_scope; shared_ptr m_settings; }; ResultsView::ResultsView(const internal::ResultsViewArguments& arguments) : p(new _Priv(*this, arguments.scopes)) { } void ResultsView::setPreviewView(PreviewView::SPtr previewView) { p->m_previewView = previewView; } void ResultsView::setActiveScope(const string &id_) { QString id = QString::fromStdString(id_); // Deactivate the previous scopes first for (int row = 0; row < p->m_scopes->rowCount(); ++row) { ng::Scope::Ptr scope = p->m_scopes->getScopeByRow(row); if (scope->id() != id) { scope->setActive(false); } } p->m_active_scope.reset(); // Activate the new scope for (int row = 0; row < p->m_scopes->rowCount(); ++row) { ng::Scope::Ptr scope = p->m_scopes->getScopeByRow(row); if (scope->id() == id) { p->m_active_scope = scope; QSignalSpy spy(scope.data(), SIGNAL(searchInProgressChanged())); scope->setSearchQuery(""); scope->setActive(true); if (!scope->searchInProgress()) { spy.wait(100); } if (scope->searchInProgress()) { TestUtils::throwIfNot(spy.wait(), "Active scope didn't finish searching"); } break; } } } string ResultsView::activeScope() const { string result; if (p->m_active_scope) { result = p->m_active_scope->id().toStdString(); } return result; } void ResultsView::setQuery(const string& searchString_) { p->checkActiveScope(); QString searchString = QString::fromStdString(searchString_); // If we've already got a completed search for this string then do nothing if (p->m_active_scope->searchQuery() == searchString) { return; } TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search is already in progress"); QSignalSpy spy(p->m_active_scope.data(), SIGNAL(searchInProgressChanged())); // perform a search p->m_active_scope->setSearchQuery(searchString); // search should not be happening yet TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search was in progress too soon"); TestUtils::throwIfNot(spy.wait(), "Search spy received no events"); if (p->m_active_scope->searchInProgress()) { // wait for the search to finish TestUtils::throwIfNot(spy.wait(), "Search spy received no events"); } TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search did not complete"); } void ResultsView::forceRefresh() { p->checkActiveScope(); TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search is already in progress"); QSignalSpy spy(p->m_active_scope.data(), SIGNAL(searchInProgressChanged())); // perform a search p->m_active_scope->refresh(); // search should not be happening yet TestUtils::throwIfNot(p->m_active_scope->searchInProgress() || spy.count() > 1, "Refresh failed to start"); if (p->m_active_scope->searchInProgress()) { // wait for the search to finish TestUtils::throwIfNot(spy.wait(), "Search spy received no events"); } TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search did not complete"); } void ResultsView::waitForResultsChange() { p->checkActiveScope(); TestUtils::throwIf(p->m_active_scope->searchInProgress(), "Search is already in progress"); // wait for the search to finish QSignalSpy spy(p->m_active_scope.data(), SIGNAL(searchInProgressChanged())); TestUtils::throwIfNot(spy.wait(), "Search status didn't change"); if(spy.size() == 1) { TestUtils::throwIfNot(spy.wait(), "Search status didn't change"); } TestUtils::throwIf(p->m_active_scope->searchInProgress(), ""); } bool ResultsView::hasDepartments() const { p->checkActiveScope(); return p->m_active_scope->hasNavigation(); } bool ResultsView::hasAltDepartments() const { throw std::domain_error("ResultsView::hasAltDepartments() is deprecated"); } string ResultsView::departmentId() const { p->checkActiveScope(); return p->m_active_scope->currentNavigationId().toStdString(); } string ResultsView::altDepartmentId() const { throw std::domain_error("ResultsView::altDepartmentId() is deprecated"); } results::Department ResultsView::browseDepartment(const string& id) { return p->browseDepartment(id, false); } results::Department ResultsView::browseAltDepartment(const string& id) { throw std::domain_error("ResultsView::browseAltDepartment() is deprecated"); } bool ResultsView::overrideCategoryJson(string const& categoryId, string const& json) { p->checkActiveScope(); return p->m_active_scope->categories()->overrideCategoryJson( QString::fromStdString(categoryId), QString::fromStdString(json)); } results::Category::List ResultsView::categories() { auto cats = p->internalRawCategories(); results::Category::List result; for (int i = 0; i < cats->rowCount(); ++i) { try { auto cat = p->internalCategory(i); if (!cat.empty()) { result.emplace_back(cat); } } catch (range_error& e) { } } return result; } results::Category ResultsView::category(size_t row) { auto cats = categories(); return cats.at(row); } results::Category ResultsView::category(const string& categoryId_) { auto cats = p->internalRawCategories(); QString categoryId = QString::fromStdString(categoryId_); int row = -1; for (int i = 0; i < cats->rowCount(); ++i) { QVariant variant = cats->data(cats->index(i), ss::CategoriesInterface::RoleCategoryId); if (variant.toString() == categoryId) { row = i; break; } } TestUtils::throwIf(row == -1, "Could not find category"); return p->internalCategory(row); } string ResultsView::scopeId() const { p->checkActiveScope(); return p->m_active_scope->id().toStdString(); } string ResultsView::displayName() const { p->checkActiveScope(); return p->m_active_scope->name().toStdString(); } string ResultsView::iconHint() const { p->checkActiveScope(); return p->m_active_scope->iconHint().toStdString(); } string ResultsView::description() const { p->checkActiveScope(); return p->m_active_scope->description().toStdString(); } string ResultsView::searchHint() const { p->checkActiveScope(); return p->m_active_scope->searchHint().toStdString(); } string ResultsView::shortcut() const { p->checkActiveScope(); return p->m_active_scope->shortcut().toStdString(); } string ResultsView::query() const { p->checkActiveScope(); return p->m_active_scope->searchQuery().toStdString(); } sc::Variant ResultsView::customizations() const { p->checkActiveScope(); return ng::qVariantToScopeVariant(p->m_active_scope->customizations()); } SettingsView::SPtr ResultsView::settings() const { p->checkActiveScope(); if (!p->m_settings) { p->m_settings = std::shared_ptr(new SettingsView(internal::SettingsViewArguments { p->m_active_scope })); } return p->m_settings; } string ResultsView::sessionId() const { p->checkActiveScope(); return p->m_active_scope->sessionId().toStdString(); } int ResultsView::queryId() const { p->checkActiveScope(); return p->m_active_scope->queryId(); } unity::shell::scopes::ScopeInterface::Status ResultsView::status() const { p->checkActiveScope(); return p->m_active_scope->status(); } } } } unity-scopes-shell-0.5.7+16.04.20160317/src/scope-harness/view/settings-view.h0000644000015600001650000000351312672630457027150 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2015 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify it under * the terms of version 3 of the GNU Lesser General Public License as published * by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Pawel Stolowski */ #pragma once #include #include #include namespace unity { namespace scopeharness { namespace internal { struct SettingsViewArguments; } namespace view { class Q_DECL_EXPORT SettingsView final: public AbstractView { public: UNITY_DEFINES_PTRS(SettingsView); enum OptionType { String, Number, List, Boolean }; struct Option { typedef std::vector