diff options
| author | Christopher Lee <chris.lee@canonical.com> | 2012-08-27 15:01:36 +1200 |
|---|---|---|
| committer | Christopher Lee <chris.lee@canonical.com> | 2012-08-27 15:01:36 +1200 |
| commit | d5cb12609edc74f620a97b7d1f9089427eeda689 (patch) | |
| tree | efca7ffe0910b03b0cdd42b200b8966db2152253 /tests | |
| parent | 1ac4b147b06f56968effc55bdf3e2ad375074594 (diff) | |
| parent | 2e9c835e6ff61cd09074609e022920bdd1507e52 (diff) | |
Merged trunk and resolved conflict
(bzr r2490.2.9)
Diffstat (limited to 'tests')
82 files changed, 5929 insertions, 1155 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0cea996e3..453e3082c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,6 +11,8 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/update-manager.desktop ${CMAKE_BINARY_DIR}/tests/data/update-manager.desktop) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/bzr-handle-patch.desktop ${CMAKE_BINARY_DIR}/tests/data/bzr-handle-patch.desktop) +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/no-icon.desktop + ${CMAKE_BINARY_DIR}/tests/data/no-icon.desktop) # # Unit tests # @@ -37,7 +39,7 @@ set (LIBS ${TEST_UNIT_DEPS_LIBRARIES} "-lunity-core-${UNITY_API_VERSION} -lcompi link_libraries (${LIBS}) set (LIB_PATHS ${TEST_UNIT_DEPS_LIBRARY_DIRS}) -link_directories (${CMAKE_BINARY_DIR}/UnityCore ${LIB_PATHS}) +link_directories (${CMAKE_BINARY_DIR}/UnityCore ${LIB_PATHS} ${COMPIZ_LIBDIR}) include_directories (. .. ../services ../UnityCore ${UNITY_SRC} ${CMAKE_BINARY_DIR}) include_directories (${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src) @@ -60,18 +62,11 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/panel-marshal.c add_executable (test-unit unit/TestMain.cpp - unit/TestQuicklistMenuitems.cpp unit/TestPanelService.cpp unit/TestUBus.cpp unit/TestStaticCairoText.cpp ${CMAKE_SOURCE_DIR}/launcher/CairoBaseWindow.cpp ${CMAKE_SOURCE_DIR}/unity-shared/Introspectable.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItem.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItemCheckmark.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItemLabel.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItemRadio.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItemSeparator.cpp - ${CMAKE_SOURCE_DIR}/launcher/QuicklistView.cpp ${CMAKE_SOURCE_DIR}/unity-shared/StaticCairoText.cpp ../services/panel-service.c ${CMAKE_CURRENT_BINARY_DIR}/panel-marshal.c @@ -122,6 +117,7 @@ if (GTEST_SRC_DIR AND # The actual test executable (xless) - do not put anything that requires X in here add_executable(test-gtest-xless + test_main_xless.cpp test_animator.cpp test_launcher_model.cpp test_glib_object.cpp @@ -132,24 +128,26 @@ if (GTEST_SRC_DIR AND test_glib_signals_utils.h test_glib_source.cpp test_glib_variant.cpp + test_grabhandle.cpp test_desktop_utilities.cpp - ${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp + test_hud_private.cpp test_indicator.cpp test_indicator_appmenu.cpp test_indicator_entry.cpp test_indicators.cpp + test_introspection.cpp test_favorite_store_gsettings.cpp test_favorite_store_private.cpp test_home_lens.cpp test_launcher_entry_remote.cpp + test_model_iterator.cpp + test_pointer_barrier.cpp + test_previews.cpp test_shortcut_model.cpp test_shortcut_private.cpp - test_introspection.cpp - test_main_xless.cpp - test_grabhandle.cpp - test_unityshell_private.cpp test_showdesktop_handler.cpp - test_hud_private.cpp + test_unityshell_private.cpp + ${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp ${CMAKE_SOURCE_DIR}/launcher/AbstractLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/unity-shared/Animator.cpp ${UNITY_SRC}/DebugDBusInterface.cpp @@ -159,7 +157,9 @@ if (GTEST_SRC_DIR AND ${CMAKE_SOURCE_DIR}/unity-shared/IconTextureSource.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherModel.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherEntryRemote.cpp + ${CMAKE_SOURCE_DIR}/launcher/MockLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp + ${CMAKE_SOURCE_DIR}/launcher/PointerBarrier.cpp ${CMAKE_SOURCE_DIR}/shortcuts/ShortcutModel.cpp ${CMAKE_SOURCE_DIR}/shortcuts/ShortcutHintPrivate.cpp ${CMAKE_SOURCE_DIR}/unity-shared/Introspectable.cpp @@ -199,27 +199,51 @@ if (GTEST_SRC_DIR AND # Tests that require X add_executable(test-gtest + test_main.cpp test_bamflaunchericon.cpp - test_hud_button.cpp - test_hud_controller.cpp + test_bfb_launcher_icon.cpp test_dashview_impl.cpp - test_texture_cache.cpp - test_main.cpp + test_edge_barrier_controller.cpp + test_launcher.cpp + test_device_launcher_section.cpp test_lensview_impl.cpp + test_hud_button.cpp + test_hud_controller.cpp + test_hud_view.cpp test_icon_loader.cpp test_im_text_entry.cpp - test_hud_view.cpp + test_launcher_controller.cpp test_keyboard_util.cpp + test_panel_style.cpp + test_previews_application.cpp + test_previews_generic.cpp + test_previews_movie.cpp + test_previews_music.cpp + test_quicklist_menu_item.cpp + test_quicklist_view.cpp test_resultviewgrid.cpp test_single_monitor_launcher_icon.cpp test_switcher_controller.cpp test_switcher_model.cpp + test_texture_cache.cpp + test_thumbnail_generator.cpp + gmockvolume.c ${CMAKE_SOURCE_DIR}/dash/AbstractPlacesGroup.cpp ${CMAKE_SOURCE_DIR}/dash/DashViewPrivate.cpp ${CMAKE_SOURCE_DIR}/dash/LensViewPrivate.cpp ${CMAKE_SOURCE_DIR}/dash/ResultRenderer.cpp ${CMAKE_SOURCE_DIR}/dash/ResultView.cpp ${CMAKE_SOURCE_DIR}/dash/ResultViewGrid.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/ActionButton.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/ApplicationPreview.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/GenericPreview.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/MoviePreview.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/MusicPreview.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/Preview.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/PreviewInfoHintWidget.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/PreviewRatingsWidget.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/Tracks.cpp + ${CMAKE_SOURCE_DIR}/dash/previews/Track.cpp ${CMAKE_SOURCE_DIR}/hud/HudAbstractView.cpp ${CMAKE_SOURCE_DIR}/hud/HudButton.cpp ${CMAKE_SOURCE_DIR}/hud/HudController.cpp @@ -229,22 +253,32 @@ if (GTEST_SRC_DIR AND ${CMAKE_SOURCE_DIR}/hud/HudView.cpp ${CMAKE_SOURCE_DIR}/launcher/AbstractLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/BamfLauncherIcon.cpp + ${CMAKE_SOURCE_DIR}/launcher/BFBLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/CairoBaseWindow.cpp ${CMAKE_SOURCE_DIR}/launcher/DNDCollectionWindow.cpp ${CMAKE_SOURCE_DIR}/launcher/Decaymulator.cpp + ${CMAKE_SOURCE_DIR}/launcher/DesktopLauncherIcon.cpp + ${CMAKE_SOURCE_DIR}/launcher/DeviceLauncherIcon.cpp + ${CMAKE_SOURCE_DIR}/launcher/DeviceLauncherSection.cpp + ${CMAKE_SOURCE_DIR}/launcher/DevicesSettings.cpp ${CMAKE_SOURCE_DIR}/launcher/DndData.cpp + ${CMAKE_SOURCE_DIR}/launcher/EdgeBarrierController.cpp ${CMAKE_SOURCE_DIR}/launcher/FavoriteStore.cpp ${CMAKE_SOURCE_DIR}/launcher/FavoriteStoreGSettings.cpp ${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp - ${CMAKE_SOURCE_DIR}/launcher/GeisAdapter.cpp + ${CMAKE_SOURCE_DIR}/launcher/HudLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/Launcher.cpp + ${CMAKE_SOURCE_DIR}/launcher/LauncherController.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherDragWindow.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherEntryRemote.cpp + ${CMAKE_SOURCE_DIR}/launcher/LauncherEntryRemoteModel.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherHideMachine.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherHoverMachine.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/LauncherModel.cpp + ${CMAKE_SOURCE_DIR}/launcher/LauncherOptions.cpp ${CMAKE_SOURCE_DIR}/launcher/LayoutSystem.cpp + ${CMAKE_SOURCE_DIR}/launcher/MockLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/PointerBarrier.cpp ${CMAKE_SOURCE_DIR}/launcher/QuicklistManager.cpp ${CMAKE_SOURCE_DIR}/launcher/QuicklistMenuItem.cpp @@ -255,14 +289,19 @@ if (GTEST_SRC_DIR AND ${CMAKE_SOURCE_DIR}/launcher/QuicklistView.cpp ${CMAKE_SOURCE_DIR}/launcher/SimpleLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/SingleMonitorLauncherIcon.cpp + ${CMAKE_SOURCE_DIR}/launcher/SoftwareCenterLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/SpacerLauncherIcon.cpp ${CMAKE_SOURCE_DIR}/launcher/SwitcherController.cpp ${CMAKE_SOURCE_DIR}/launcher/SwitcherModel.cpp ${CMAKE_SOURCE_DIR}/launcher/SwitcherView.cpp ${CMAKE_SOURCE_DIR}/launcher/Tooltip.cpp + ${CMAKE_SOURCE_DIR}/launcher/TrashLauncherIcon.cpp + ${CMAKE_SOURCE_DIR}/launcher/VolumeMonitorWrapper.cpp ${CMAKE_SOURCE_DIR}/unity-shared/Animator.cpp ${CMAKE_SOURCE_DIR}/unity-shared/BackgroundEffectHelper.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/CoverArt.cpp ${CMAKE_SOURCE_DIR}/unity-shared/DashStyle.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/DefaultThumbnailProvider.cpp ${CMAKE_SOURCE_DIR}/unity-shared/IconLoader.cpp ${CMAKE_SOURCE_DIR}/unity-shared/IconRenderer.cpp ${CMAKE_SOURCE_DIR}/unity-shared/IconTexture.cpp @@ -274,17 +313,23 @@ if (GTEST_SRC_DIR AND ${CMAKE_SOURCE_DIR}/unity-shared/KeyboardUtil.cpp ${CMAKE_SOURCE_DIR}/unity-shared/OverlayRenderer.cpp ${CMAKE_SOURCE_DIR}/unity-shared/PanelStyle.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/PlacesVScrollBar.cpp ${CMAKE_SOURCE_DIR}/unity-shared/PluginAdapterStandalone.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/PreviewStyle.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/RatingsButton.cpp ${CMAKE_SOURCE_DIR}/unity-shared/SearchBar.cpp ${CMAKE_SOURCE_DIR}/unity-shared/SearchBarSpinner.cpp ${CMAKE_SOURCE_DIR}/unity-shared/StaticCairoText.cpp ${CMAKE_SOURCE_DIR}/unity-shared/TextureCache.cpp ${CMAKE_SOURCE_DIR}/unity-shared/Timer.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/TextureThumbnailProvider.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/ThumbnailGenerator.cpp ${CMAKE_SOURCE_DIR}/unity-shared/UBusWrapper.cpp ${CMAKE_SOURCE_DIR}/unity-shared/UScreen.cpp ${CMAKE_SOURCE_DIR}/unity-shared/UnitySettings.cpp ${CMAKE_SOURCE_DIR}/unity-shared/UnityWindowStyle.cpp ${CMAKE_SOURCE_DIR}/unity-shared/UnityWindowView.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/UserThumbnailProvider.cpp ${CMAKE_SOURCE_DIR}/unity-shared/WindowManager.cpp ${CMAKE_SOURCE_DIR}/unity-shared/ubus-server.cpp ) @@ -296,7 +341,7 @@ endif (GTEST_SRC_DIR AND GMOCK_LIB AND GMOCK_MAIN_LIB) -add_subdirectory (test-gesture-engine) +add_subdirectory (test-gestures) # # check target @@ -307,25 +352,25 @@ set (TEST_RESULT_HTML ${TEST_RESULT_DIR}/test-results.html) set (GTEST_TEST_COMMAND ./test-gtest) set (GTEST_TEST_COMMAND_XLESS ./test-gtest-xless) set (GTEST_TEST_COMMAND_DBUS dbus-test-runner --task ./test-gtest-service --task ./test-gtest-dbus) -set (GTEST_TEST_COMMAND_GESTURE_ENGINE ./test-gesture-engine/test-gesture-engine) +set (GTEST_TEST_COMMAND_GESTURES ./test-gestures/test-gestures) set (TEST_COMMAND gtester --verbose -k --g-fatal-warnings -o=${TEST_RESULT_XML} ./test-unit - && ${GTEST_TEST_COMMAND} - && ${GTEST_TEST_COMMAND_XLESS} - && ${GTEST_TEST_COMMAND_GESTURE_ENGINE} - && ${GTEST_TEST_COMMAND_DBUS} + && ${GTEST_TEST_COMMAND} --gtest_output=xml:./ + && ${GTEST_TEST_COMMAND_XLESS} --gtest_output=xml:./ + && ${GTEST_TEST_COMMAND_GESTURES} --gtest_output=xml:./ + && ${GTEST_TEST_COMMAND_DBUS} --gtest_output=xml:./ ) set (TEST_COMMAND_HEADLESS - ${GTEST_TEST_COMMAND_XLESS} - && ${GTEST_TEST_COMMAND_GESTURE_ENGINE} - #&& ${GTEST_TEST_COMMAND_DBUS} + ${GTEST_TEST_COMMAND_XLESS} --gtest_output=xml:./ + && ${GTEST_TEST_COMMAND_GESTURES} --gtest_output=xml:./ + #&& ${GTEST_TEST_COMMAND_DBUS} --gtest_output=xml:./ && echo "Warning, DBus test cases are disabled!!") if (GTEST_SRC_DIR) - add_custom_target (check COMMAND ${TEST_COMMAND} DEPENDS test-unit test-gtest test-gtest-xless test-gtest-dbus test-gesture-engine) - add_custom_target (check-headless COMMAND ${TEST_COMMAND_HEADLESS} DEPENDS test-gtest-xless test-gtest-dbus test-gesture-engine) + add_custom_target (check COMMAND ${TEST_COMMAND} DEPENDS test-unit test-gtest test-gtest-xless test-gtest-dbus test-gestures) + add_custom_target (check-headless COMMAND ${TEST_COMMAND_HEADLESS} DEPENDS test-gtest-xless test-gtest-dbus test-gestures) add_custom_target (check-report COMMAND ${TEST_UNIT_COMMAND} && gtester-report ${TEST_RESULT_XML} > ${TEST_RESULT_HTML}) add_custom_target (gcheck COMMAND ${DBUS_TEST_COMMAND} DEPENDS test-gtest test-gtest-xless) else (GTEST_SRC_DIR) diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py index f7d315b65..86c747f4b 100644 --- a/tests/autopilot/unity/emulators/dash.py +++ b/tests/autopilot/unity/emulators/dash.py @@ -9,12 +9,13 @@ from __future__ import absolute_import -from autopilot.introspection.dbus import make_introspection_object from autopilot.emulators.X11 import Keyboard, Mouse from autopilot.keybindings import KeybindingsHelper +from testtools.matchers import GreaterThan from unity.emulators import UnityIntrospectionObject import logging +from time import sleep logger = logging.getLogger(__name__) @@ -82,6 +83,11 @@ class Dash(KeybindingsHelper): """Returns the searchbar attached to the dash.""" return self.view.get_searchbar() + @property + def preview_displaying(self): + """Returns true if the dash is currently displaying a preview""" + return self.view.preview_displaying; + def get_num_rows(self): """Returns the number of displayed rows in the dash.""" return self.view.num_rows @@ -114,6 +120,12 @@ class Dash(KeybindingsHelper): self._reveal_lens("lens_reveal/files", clear_search) return self.view.get_lensview_by_name("files.lens") + def reveal_video_lens(self, clear_search=True): + """Reveal the video lens""" + logger.debug("Revealing video lens with Super+v.") + self._reveal_lens("lens_reveal/video", clear_search) + return self.view.get_lensview_by_name("video.lens") + def reveal_command_lens(self, clear_search=True): """Reveal the 'run command' lens.""" logger.debug("Revealing command lens with Alt+F2.") @@ -164,6 +176,13 @@ class DashView(UnityIntrospectionObject): if lens.name == lens_name: return lens + def get_preview_container(self): + """Get the preview container attached to this dash view.""" + preview_containers = self.get_children_by_type(PreviewContainer) + for preview_container in preview_containers: + return preview_container + return None + class SearchBar(UnityIntrospectionObject): """The search bar for the dash view.""" @@ -238,6 +257,20 @@ class ResultView(UnityIntrospectionObject): class Result(UnityIntrospectionObject): """A single result in the dash.""" + def activate(self): + tx = self.x + (self.width / 2) + ty = self.y + (self.height / 2) + m = Mouse() + m.move(tx, ty) + m.click(1) + + def preview(self): + tx = self.x + (self.width / 2) + ty = self.y + (self.height / 2) + m = Mouse() + m.move(tx, ty) + m.click(3) + class FilterBar(UnityIntrospectionObject): """A filterbar, as shown inside a lens.""" @@ -293,8 +326,225 @@ class FilterBar(UnityIntrospectionObject): """ searchbar_state = self.get_state_by_path("//DashView/SearchBar") assert(len(searchbar_state) == 1) - return make_introspection_object(searchbar_state[0]) + return self.make_introspection_object(searchbar_state[0]) class FilterExpanderLabel(UnityIntrospectionObject): """A label that expands into a filter within a filter bar.""" + + def ensure_expanded(self): + """Expand the filter expander label, if it's not already""" + if not self.expanded: + tx = x + width / 2 + ty = y + height / 2 + m = Mouse() + m.move(tx, ty) + m.click() + self.expanded.wait_for(True) + + def ensure_collapsed(self): + """Collapse the filter expander label, if it's not already""" + if self.expanded: + tx = x + width / 2 + ty = y + height / 2 + m = Mouse() + m.move(tx, ty) + m.click() + self.expanded.wait_for(False) + + +class CoverArt(UnityIntrospectionObject): + """A view which can be used to show a texture, or generate one using a thumbnailer.""" + + +class RatingsButton(UnityIntrospectionObject): + """A button which shows user rating as a function of stars.""" + + +class Preview(UnityIntrospectionObject): + """A preview of a dash lens result.""" + + def get_num_actions(self): + """Get the number of actions for the preview.""" + actions = self.get_children_by_type(ActionButton) + return len(actions) + + def get_action_by_id(self, action_id): + """Returns the action given it's action hint.""" + actions = self.get_children_by_type(ActionButton) + for action in actions: + if action.action == action_id: + return action + return None + + def execute_action_by_id(action_id, action): + """Executes an action given by the id.""" + action = self.get_action_by_id(action_id) + if action: + tx = action.x + (searchbar.width / 2) + ty = action.y + (searchbar.height / 2) + m = Mouse() + m.move(tx, ty) + m.click() + + @property + def cover_art(self): + return self.get_children_by_type(CoverArt)[0] + +class ApplicationPreview(Preview): + """A application preview of a dash lens result.""" + +class GenericPreview(Preview): + """A generic preview of a dash lens result.""" + +class MusicPreview(Preview): + """A music preview of a dash lens result.""" + +class MoviePreview(Preview): + """A movie preview of a dash lens result.""" + +class PreviewContent(UnityIntrospectionObject): + """A preview content layout for the dash previews.""" + + def get_current_preview(self): + previews = self.get_children_by_type(Preview) + if len(previews) > 0: + return previews[0] + return None + + +class PreviewContainer(UnityIntrospectionObject): + """A container view for the main dash preview widget.""" + + @property + def content(self): + return self.get_content() + + def get_num_previews(self): + """Get the number of previews queued and current in the container.""" + previews = self.content.get_children_by_type(Preview) + return len(previews) + + def get_content(self): + """Get the preview content layout for the container.""" + return self.get_children_by_type(PreviewContent)[0] + + def get_left_navigator(self): + """Return the left navigator object""" + navigators = self.get_children_by_type(PreviewNavigator) + for nav in navigators: + if nav.direction == 2: + return nav + return None + + def get_right_navigator(self): + """Return the right navigator object""" + navigators = self.get_children_by_type(PreviewNavigator) + for nav in navigators: + if nav.direction == 3: + return nav + return None + + def navigate_left(self, count=1): + """Navigate preview left""" + navigator = self.get_left_navigator() + + tx = navigator.button_x + (navigator.button_width / 2) + ty = navigator.button_y + (navigator.button_height / 2) + m = Mouse() + m.move(tx, ty) + + old_preview_initiate_count = self.preview_initiate_count + + for i in range(count): + self.navigate_left_enabled.wait_for(True) + m.click() + self.preview_initiate_count.wait_for(GreaterThan(old_preview_initiate_count)) + old_preview_initiate_count = self.preview_initiate_count + + def navigate_right(self, count=1): + """Navigate preview right""" + navigator = self.get_right_navigator() + + tx = navigator.button_x + (navigator.button_width / 2) + ty = navigator.button_y + (navigator.button_height / 2) + m = Mouse() + m.move(tx, ty) + + old_preview_initiate_count = self.preview_initiate_count + + for i in range(count): + self.navigate_right_enabled.wait_for(True) + m.click() + self.preview_initiate_count.wait_for(GreaterThan(old_preview_initiate_count)) + old_preview_initiate_count = self.preview_initiate_count + + @property + def animating(self): + """Return True if the preview is animating, False otherwise.""" + return self.content.animating + + @property + def waiting_preview(self): + """Return True if waiting for a preview, False otherwise.""" + return self.content.waiting_preview + + @property + def animation_progress(self): + """Return the progress of the current preview animation.""" + return self.content.animation_progress + + @property + def current_preview(self): + """Return the current preview object.""" + return self.content.get_current_preview() + preview_initiate_count_ + + @property + def preview_initiate_count(self): + """Return the number of initiated previews since opened.""" + return self.content.preview_initiate_count + + @property + def navigation_complete_count(self): + """Return the number of completed previews since opened.""" + return self.content.navigation_complete_count + + @property + def relative_nav_index(self): + """Return the navigation position relative to the direction of movement.""" + return self.content.relative_nav_index + + @property + def navigate_right_enabled(self): + """Return True if right preview navigation is enabled, False otherwise.""" + return self.content.navigate_right_enabled + + @property + def navigate_left_enabled(self): + """Return True if left preview navigation is enabled, False otherwise.""" + return self.content.navigate_left_enabled + + +class PreviewNavigator(UnityIntrospectionObject): + """A view containing a button to nagivate between previews.""" + + def icon(self): + return self.get_children_by_type(IconTexture); + + +class PreviewRatingsWidget(UnityIntrospectionObject): + """A view containing a rating button and user rating count.""" + + +class Tracks(UnityIntrospectionObject): + """A view containing music tracks.""" + + +class Track(UnityIntrospectionObject): + """A singular music track for dash prevews.""" + + +class ActionButton(UnityIntrospectionObject): + """A preview action button.""" + diff --git a/tests/autopilot/unity/emulators/hud.py b/tests/autopilot/unity/emulators/hud.py index c0e841ead..500a607a8 100644 --- a/tests/autopilot/unity/emulators/hud.py +++ b/tests/autopilot/unity/emulators/hud.py @@ -32,6 +32,11 @@ class Hud(KeybindingsHelper): def ensure_hidden(self): """Hides the hud if it's not already hidden.""" if self.visible: + if self.search_string: + # need this to clear the search string, and then another to + # close the hud. + self.keyboard.press_and_release("Escape") + self.search_string.wait_for("") self.keyboard.press_and_release("Escape") self.visible.wait_for(False) diff --git a/tests/autopilot/unity/emulators/launcher.py b/tests/autopilot/unity/emulators/launcher.py index 1ae9bb40d..fa5361ac5 100644 --- a/tests/autopilot/unity/emulators/launcher.py +++ b/tests/autopilot/unity/emulators/launcher.py @@ -305,9 +305,10 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): self._perform_switcher_binding("launcher/switcher/down") self._get_controller().key_nav_selection.wait_for(NotEquals(old_selection)) - def click_launcher_icon(self, icon, button=1): + def click_launcher_icon(self, icon, button=1, move_mouse_after=True): """Move the mouse over the launcher icon, and click it. `icon` must be an instance of SimpleLauncherIcon or it's descendants. + `move_mouse_after` moves the mouse outside the launcher if true. """ if not isinstance(icon, SimpleLauncherIcon): raise TypeError("icon must be a LauncherIcon, not %s" % type(icon)) @@ -325,7 +326,8 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): self._mouse.move(target_x, target_y ) sleep(1) self._mouse.click(button) - self.move_mouse_to_right_of_launcher() + if (move_mouse_after): + self.move_mouse_to_right_of_launcher() def drag_icon_to_position(self, icon, pos, drag_type=IconDragType.INSIDE): """Place the supplied icon above the icon in the position pos. diff --git a/tests/autopilot/unity/emulators/panel.py b/tests/autopilot/unity/emulators/panel.py index 2b0d69254..147afba88 100644 --- a/tests/autopilot/unity/emulators/panel.py +++ b/tests/autopilot/unity/emulators/panel.py @@ -338,3 +338,9 @@ class IndicatorEntry(UnityIntrospectionObject): """Returns a tuple of (x,y,w,h) for the opened menu geometry.""" return (self.menu_x, self.menu_y, self.menu_width, self.menu_height) + def __repr__(self): + return "<IndicatorEntry 0x%x (%s)>" % (id(self), self.label) + + +class Tray(UnityIntrospectionObject): + """A panel tray object.""" diff --git a/tests/autopilot/unity/emulators/unity.py b/tests/autopilot/unity/emulators/unity.py index 69ecab582..97b1840a0 100644 --- a/tests/autopilot/unity/emulators/unity.py +++ b/tests/autopilot/unity/emulators/unity.py @@ -18,17 +18,22 @@ DEBUG_PATH = '/com/canonical/Unity/Debug' LOGGING_IFACE = 'com.canonical.Unity.Debug.Logging' -_debug_proxy_obj = session_bus.get_object(UNITY_BUS_NAME, DEBUG_PATH) -_logging_iface = Interface(_debug_proxy_obj, LOGGING_IFACE) +def get_dbus_proxy_object(): + return session_bus.get_object(UNITY_BUS_NAME, DEBUG_PATH) + + +def get_dbus_logging_interface(): + return Interface(get_dbus_proxy_object(), LOGGING_IFACE) + def start_log_to_file(file_path): """Instruct Unity to start logging to the given file.""" - _logging_iface.StartLogToFile(file_path) + get_dbus_logging_interface().StartLogToFile(file_path) def reset_logging(): """Instruct Unity to stop logging to a file.""" - _logging_iface.ResetLogging() + get_dbus_logging_interface().ResetLogging() def set_log_severity(component, severity): @@ -39,7 +44,7 @@ def set_log_severity(component, severity): 'severity' is the severity name (like 'DEBUG', 'INFO' etc.) """ - _logging_iface.SetLogSeverity(component, severity) + get_dbus_logging_interface().SetLogSeverity(component, severity) def log_unity_message(severity, message): @@ -53,5 +58,5 @@ def log_unity_message(severity, message): test, use the python logging framework instead. """ - _logging_iface.LogMessage(severity, message) + get_dbus_logging_interface().LogMessage(severity, message) diff --git a/tests/autopilot/unity/tests/__init__.py b/tests/autopilot/unity/tests/__init__.py index a241a0a63..90b7c10ae 100644 --- a/tests/autopilot/unity/tests/__init__.py +++ b/tests/autopilot/unity/tests/__init__.py @@ -65,37 +65,37 @@ class UnityTestCase(AutopilotTestCase): log.info("Checking system state for badly behaving test...") # Have we switched workspace? - if self.workspace.current_workspace != self._initial_workspace_num: + if not self.well_behaved(self.workspace, current_workspace=self._initial_workspace_num): well_behaved = False reasons.append("The test changed the active workspace from %d to %d." \ % (self._initial_workspace_num, self.workspace.current_workspace)) log.warning("Test changed the active workspace, changing it back...") self.workspace.switch_to(self._initial_workspace_num) # Have we left the dash open? - if self.dash.visible: + if not self.well_behaved(self.dash, visible=False): well_behaved = False reasons.append("The test left the dash open.") log.warning("Test left the dash open, closing it...") self.dash.ensure_hidden() # ... or the hud? - if self.hud.visible: + if not self.well_behaved(self.hud, visible=False): well_behaved = False reasons.append("The test left the hud open.") log.warning("Test left the hud open, closing it...") self.hud.ensure_hidden() # Are we in show desktop mode? - if self.window_manager.showdesktop_active: + if not self.well_behaved(self.window_manager, showdesktop_active=False): well_behaved = False reasons.append("The test left the system in show_desktop mode.") log.warning("Test left the system in show desktop mode, exiting it...") self.window_manager.leave_show_desktop() for launcher in self.launcher.get_launchers(): - if launcher.in_keynav_mode: + if not self.well_behaved(launcher, in_keynav_mode=False): well_behaved = False reasons.append("The test left the launcher keynav mode enabled.") log.warning("Test left the launcher in keynav mode, exiting it...") launcher.key_nav_cancel() - if launcher.in_switcher_mode: + if not self.well_behaved(launcher, in_switcher_mode=False): well_behaved = False reasons.append("The test left the launcher in switcher mode.") log.warning("Test left the launcher in switcher mode, exiting it...") @@ -106,6 +106,13 @@ class UnityTestCase(AutopilotTestCase): else: log.info("Test was well behaved.") + def well_behaved(self, object, **kwargs): + try: + self.assertProperty(object, **kwargs) + except AssertionError: + return False + return True + @property def dash(self): if not getattr(self, '__dash', None): diff --git a/tests/autopilot/unity/tests/launcher/test_capture.py b/tests/autopilot/unity/tests/launcher/test_capture.py index a6f4b602e..6783301bf 100644 --- a/tests/autopilot/unity/tests/launcher/test_capture.py +++ b/tests/autopilot/unity/tests/launcher/test_capture.py @@ -80,9 +80,25 @@ class LauncherCaptureTests(UnityTestCase): # The launcher should have held the mouse a little bit self.assertThat(x_fin, Equals(x - width / 2)) + def test_launcher_capture_while_not_sticky_and_hidden(self): + """Tests that the launcher captures the mouse when moving between monitors + while hidden and sticky is off. (moving left) + """ + + self.set_unity_option('launcher_capture_mouse', False) + self.setHideMode(1) + + x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor()) + self.mouse.move(x + width / 2, y + height / 2, False) + self.mouse.move(x - width / 2, y + height / 2, True, 5, .002) + + x_fin, y_fin = self.mouse.position() + # The launcher should have held the mouse a little bit + self.assertThat(x_fin, GreaterThan(x - width / 2)) + def test_launcher_not_capture_while_not_sticky_and_hidden_moving_right(self): """Tests that the launcher doesn't capture the mouse when moving between monitors - while hidden and sticky is off. + while hidden and sticky is off (moving right). """ self.set_unity_option('launcher_capture_mouse', False) diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py index f214b3a08..798283d21 100644 --- a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py +++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py @@ -66,54 +66,75 @@ class LauncherIconsTests(LauncherTestCase): of that application. """ - mah_win1 = self.start_app_window("Mahjongg") + char_win1 = self.start_app_window("Character Map") calc_win = self.start_app_window("Calculator") - mah_win2 = self.start_app_window("Mahjongg") + char_win2 = self.start_app_window("Character Map") - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) - mahj_icon = self.launcher.model.get_icon( - desktop_id=mah_win2.application.desktop_file) + char_icon = self.launcher.model.get_icon( + desktop_id=char_win2.application.desktop_file) calc_icon = self.launcher.model.get_icon( desktop_id=calc_win.application.desktop_file) self.launcher_instance.click_launcher_icon(calc_icon) self.assertProperty(calc_win, is_focused=True) - self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1]) + self.assertVisibleWindowStack([calc_win, char_win2, char_win1]) - self.launcher_instance.click_launcher_icon(mahj_icon) - self.assertProperty(mah_win2, is_focused=True) - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + self.launcher_instance.click_launcher_icon(char_icon) + self.assertProperty(char_win2, is_focused=True) + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) self.keybinding("window/minimize") - self.assertThat(lambda: mah_win2.is_hidden, Eventually(Equals(True))) + self.assertThat(lambda: char_win2.is_hidden, Eventually(Equals(True))) self.assertProperty(calc_win, is_focused=True) - self.assertVisibleWindowStack([calc_win, mah_win1]) + self.assertVisibleWindowStack([calc_win, char_win1]) - self.launcher_instance.click_launcher_icon(mahj_icon) - self.assertProperty(mah_win1, is_focused=True) - self.assertThat(lambda: mah_win2.is_hidden, Eventually(Equals(True))) - self.assertVisibleWindowStack([mah_win1, calc_win]) + self.launcher_instance.click_launcher_icon(char_icon) + self.assertProperty(char_win1, is_focused=True) + self.assertThat(lambda: char_win2.is_hidden, Eventually(Equals(True))) + self.assertVisibleWindowStack([char_win1, calc_win]) def test_clicking_icon_twice_initiates_spread(self): """This tests shows that when you click on a launcher icon twice, when an application window is focused, the spread is initiated. """ - calc_win1 = self.start_app_window("Calculator") - calc_win2 = self.start_app_window("Calculator") - calc_app = calc_win1.application + char_win1 = self.start_app_window("Character Map") + char_win2 = self.start_app_window("Character Map") + char_app = char_win1.application - self.assertVisibleWindowStack([calc_win2, calc_win1]) - self.assertProperty(calc_win2, is_focused=True) + self.assertVisibleWindowStack([char_win2, char_win1]) + self.assertProperty(char_win2, is_focused=True) - calc_icon = self.launcher.model.get_icon(desktop_id=calc_app.desktop_file) + char_icon = self.launcher.model.get_icon(desktop_id=char_app.desktop_file) self.addCleanup(self.keybinding, "spread/cancel") - self.launcher_instance.click_launcher_icon(calc_icon) + self.launcher_instance.click_launcher_icon(char_icon) self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) self.assertThat(self.window_manager.scale_active_for_group, Eventually(Equals(True))) + def test_while_in_scale_mode_the_dash_will_still_open(self): + """If scale is initiated through the laucher pressing super must close + scale and open the dash. + """ + char_win1 = self.start_app_window("Character Map") + char_win2 = self.start_app_window("Character Map") + char_app = char_win1.application + + self.assertVisibleWindowStack([char_win2, char_win1]) + self.assertProperty(char_win2, is_focused=True) + + char_icon = self.launcher.model.get_icon(desktop_id=char_app.desktop_file) + self.launcher_instance.click_launcher_icon(char_icon) + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + + self.assertThat(self.dash.visible, Eventually(Equals(True))) + self.assertThat(self.window_manager.scale_active, Eventually(Equals(False))) + def test_icon_shows_on_quick_application_reopen(self): """Icons must stay on launcher when an application is quickly closed/reopened.""" calc = self.start_app("Calculator") @@ -146,7 +167,7 @@ class LauncherDragIconsBehavior(LauncherTestCase): # the old fashioned way. refresh_fn = lambda: self.launcher.model.get_children_by_type( BamfLauncherIcon, desktop_id="gcalctool.desktop") - self.assertThat(refresh_fn, Eventually(Equals(None))) + self.assertThat(refresh_fn, Eventually(Equals([]))) def test_can_drag_icon_below_bfb(self): """Application icons must be draggable to below the BFB.""" diff --git a/tests/autopilot/unity/tests/launcher/test_reveal.py b/tests/autopilot/unity/tests/launcher/test_reveal.py index 00cad97a5..45976fa7b 100644 --- a/tests/autopilot/unity/tests/launcher/test_reveal.py +++ b/tests/autopilot/unity/tests/launcher/test_reveal.py @@ -73,6 +73,34 @@ class LauncherRevealTests(LauncherTestCase): sleep(5) self.assertThat(self.launcher_instance.is_showing, Equals(False)) + def test_launcher_stays_open_after_spread(self): + """Clicking on the launcher to close an active spread must not hide the launcher.""" + char_win1 = self.start_app_window("Character Map") + char_win2 = self.start_app_window("Character Map") + char_app = char_win1.application + + char_icon = self.launcher.model.get_icon(desktop_id=char_app.desktop_file) + + self.launcher_instance.click_launcher_icon(char_icon, move_mouse_after=False) + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + self.launcher_instance.click_launcher_icon(char_icon, move_mouse_after=False) + + self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) + self.assertThat(self.window_manager.scale_active, Eventually(Equals(False))) + + def test_launcher_stays_open_after_icon_click(self): + """Clicking on a launcher icon must not hide the launcher.""" + char_win = self.start_app_window("Character Map") + char_app = char_win.application + + char_icon = self.launcher.model.get_icon(desktop_id=char_app.desktop_file) + self.launcher_instance.click_launcher_icon(char_icon, move_mouse_after=False) + + # Have to sleep to give the launcher time to hide (what the old behavior was) + sleep(5) + + self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) + def test_new_icon_has_the_shortcut(self): """New icons should have an associated shortcut""" if self.launcher.model.num_bamf_launcher_icons() >= 10: diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py index 18190cb16..ab4c5b489 100644 --- a/tests/autopilot/unity/tests/test_dash.py +++ b/tests/autopilot/unity/tests/test_dash.py @@ -8,11 +8,10 @@ from __future__ import absolute_import -from time import sleep - +from autopilot.emulators.clipboard import get_clipboard_contents from autopilot.matchers import Eventually -from gtk import Clipboard -from testtools.matchers import Equals, NotEquals +from testtools.matchers import Equals, NotEquals, GreaterThan +from time import sleep from unity.tests import UnityTestCase @@ -51,6 +50,11 @@ class DashRevealTests(DashTestCase): self.dash.reveal_file_lens() self.assertThat(self.dash.active_lens, Eventually(Equals('files.lens'))) + def test_video_lens_shortcut(self): + """Video lens must reveal when super+v is pressed.""" + self.dash.reveal_video_lens() + self.assertThat(self.dash.active_lens, Eventually(Equals('video.lens'))) + def test_command_lens_shortcut(self): """Run Command lens must reveat on alt+F2.""" self.dash.reveal_command_lens() @@ -180,7 +184,7 @@ class DashKeyNavTests(DashTestCase): current_focused_icon = lensbar.focused_lens_icon - self.keyboard.press_and_release("Right"); + self.keyboard.press_and_release("Right") self.assertThat(lensbar.focused_lens_icon, Eventually(NotEquals(current_focused_icon))) self.keyboard.press_and_release("Left") @@ -192,17 +196,35 @@ class DashKeyNavTests(DashTestCase): for i in range(self.dash.get_num_rows()): self.keyboard.press_and_release("Down") - self.keyboard.press_and_release("Right"); + self.keyboard.press_and_release("Right") lensbar = self.dash.view.get_lensbar() focused_icon = lensbar.focused_lens_icon - self.keyboard.press_and_release("Enter"); + self.keyboard.press_and_release("Enter") self.assertThat(lensbar.active_lens, Eventually(Equals(focused_icon))) # lensbar should lose focus after activation. - # TODO this should be a different test to make sure focus - # returns to the correct place. self.assertThat(lensbar.focused_lens_icon, Eventually(Equals(""))) + + def test_focus_returns_to_searchbar(self): + """This test makes sure that the focus is returned to the searchbar of the newly + activated lens.""" + self.dash.ensure_visible() + + for i in range(self.dash.get_num_rows()): + self.keyboard.press_and_release("Down") + self.keyboard.press_and_release("Right") + lensbar = self.dash.view.get_lensbar() + focused_icon = lensbar.focused_lens_icon + self.keyboard.press_and_release("Enter") + + self.assertThat(lensbar.active_lens, Eventually(Equals(focused_icon))) + self.assertThat(lensbar.focused_lens_icon, Eventually(Equals(""))) + + # Now we make sure if the newly activated lens searchbar have the focus. + self.keyboard.type("HasFocus") + + self.assertThat(self.dash.search_string, Eventually(Equals("HasFocus"))) def test_category_header_keynav(self): """ Tests that a category header gets focus when 'down' is pressed after the @@ -280,6 +302,34 @@ class DashKeyNavTests(DashTestCase): category = lens.get_focused_category() self.assertIsNot(category, None) + def test_bottom_up_keynav_with_filter_bar(self): + """This test makes sure that bottom-up key navigation works well + in the dash filter bar. + """ + self.dash.reveal_application_lens() + lens = self.dash.get_current_lens() + + filter_bar = lens.get_filterbar() + filter_bar.ensure_expanded() + + # Tab to fist filter expander + self.keyboard.press_and_release('Tab') + self.assertThat(lambda: filter_bar.get_focused_filter(), Eventually(NotEquals(None))) + old_focused_filter = filter_bar.get_focused_filter() + old_focused_filter.ensure_expanded() + + # Tab to the next filter expander + self.keyboard.press_and_release('Tab') + self.assertThat(lambda: filter_bar.get_focused_filter(), Eventually(NotEquals(None))) + new_focused_filter = filter_bar.get_focused_filter() + self.assertNotEqual(old_focused_filter, new_focused_filter) + new_focused_filter.ensure_expanded() + + # Move the focus up. + self.keyboard.press_and_release("Up") + self.assertThat(lambda: filter_bar.get_focused_filter(), Eventually(Equals(None))) + self.assertThat(old_focused_filter.content_has_focus, Eventually(Equals(True))) + class DashClipboardTests(DashTestCase): """Test the Unity clipboard""" @@ -305,8 +355,7 @@ class DashClipboardTests(DashTestCase): self.keyboard.press_and_release("Ctrl+a") self.keyboard.press_and_release("Ctrl+c") - cb = Clipboard(selection="CLIPBOARD") - self.assertThat(self.dash.search_string, Eventually(Equals(cb.wait_for_text()))) + self.assertThat(get_clipboard_contents, Eventually(Equals("Copy"))) def test_ctrl_x(self): """ This test if ctrl+x deletes all text and copys it """ @@ -319,8 +368,7 @@ class DashClipboardTests(DashTestCase): self.keyboard.press_and_release("Ctrl+x") self.assertThat(self.dash.search_string, Eventually(Equals(""))) - cb = Clipboard(selection="CLIPBOARD") - self.assertEqual(cb.wait_for_text(), u'Cut') + self.assertThat(get_clipboard_contents, Eventually(Equals('Cut'))) def test_ctrl_c_v(self): """ This test if ctrl+c and ctrl+v copies and pastes text""" @@ -349,6 +397,23 @@ class DashClipboardTests(DashTestCase): self.keyboard.press_and_release("Ctrl+v") self.assertThat(self.dash.search_string, Eventually(Equals('CutPasteCutPaste'))) + + def test_middle_click_paste(self): + """Tests if Middle mouse button pastes into searchbar""" + + self.start_app_window("Calculator", locale='C') + + self.keyboard.type("ThirdButtonPaste") + self.keyboard.press_and_release("Ctrl+a") + + self.dash.ensure_visible() + + self.mouse.move(self.dash.searchbar.x + self.dash.searchbar.width / 2, + self.dash.searchbar.y + self.dash.searchbar.height / 2) + + self.mouse.click(button=2) + + self.assertThat(self.dash.search_string, Eventually(Equals('ThirdButtonPaste'))) class DashKeyboardFocusTests(DashTestCase): @@ -497,8 +562,8 @@ class DashBorderTests(DashTestCase): if (self.dash.view.form_factor != "desktop"): self.skip("Not in desktop form-factor.") - x = self.dash.view.x + self.dash.view.width + self.dash.view.right_border_width / 2; - y = self.dash.view.y + self.dash.view.height / 2; + x = self.dash.view.x + self.dash.view.width + self.dash.view.right_border_width / 2 + y = self.dash.view.y + self.dash.view.height / 2 self.mouse.move(x, y) self.mouse.click() @@ -512,8 +577,8 @@ class DashBorderTests(DashTestCase): if (self.dash.view.form_factor != "desktop"): self.skip("Not in desktop form-factor.") - x = self.dash.view.x + self.dash.view.width / 2; - y = self.dash.view.y + self.dash.view.height + self.dash.view.bottom_border_height / 2; + x = self.dash.view.x + self.dash.view.width / 2 + y = self.dash.view.y + self.dash.view.height + self.dash.view.bottom_border_height / 2 self.mouse.move(x, y) self.mouse.click() @@ -543,3 +608,210 @@ class CategoryHeaderTests(DashTestCase): self.mouse.click() self.assertThat(category.is_expanded, Eventually(Equals(is_expanded))) + +class PreviewAppLensInvocationTests(DashTestCase): + """Tests that application lens previews can be opened and closed + """ + def assertSearchText(self, text): + self.assertThat(self.dash.search_string, Eventually(Equals(text))) + + def test_open_preview_close_preview(self): + """Right clicking on any result shall open a preview, + escaping shall close the preview + """ + lens = self.dash.reveal_application_lens() + self.addCleanup(self.dash.ensure_hidden) + + category = lens.get_category_by_name("Installed") + results = category.get_results() + # wait for a result + refresh_fn = lambda: len(results) + self.assertThat(refresh_fn, Eventually(GreaterThan(0))) + + result = results[0] + # result.preview handles finding xy co-ords and right mouse-click + result.preview() + # revealing a preview may be very slow, not sure if Eventually handles that nicely + self.assertThat(self.dash.preview_displaying, Eventually(Equals(True))) + + self.keyboard.press_and_release("Escape") + + self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + + def test_preview_refocus_close(self): + """This tests that if the mouse is clicked on a preview element (Cover art for example), + the keyboard shortcut for closing ('Escape') still works correctly. + """ + lens = self.dash.reveal_application_lens() + self.addCleanup(self.dash.ensure_hidden) + + category = lens.get_category_by_name("Installed") + results = category.get_results() + # wait for a result + refresh_fn = lambda: len(results) + self.assertThat(refresh_fn, Eventually(GreaterThan(0))) + + result = results[0] + # result.preview handles finding xy co-ords and right mouse-click + result.preview() + # revealing a preview may be very slow, not sure if Eventually handles that nicely + self.assertThat(self.dash.preview_displaying, Eventually(Equals(True))) + + preview_container = self.dash.view.get_preview_container() + # wait for settle. + self.assertThat(preview_container.animating, Eventually(Equals(False))) + cover_art = preview_container.current_preview.cover_art + + # click the cover-art (this will set focus) + tx = cover_art.x + (cover_art.width / 2) + ty = cover_art.y + (cover_art.height / 2) + self.mouse.move(tx, ty) + self.mouse.click() + + self.keyboard.press_and_release("Escape") + + self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + + +class PreviewFileLensInvocationTests(DashTestCase): + """Tests that file lens previews can be opened and closed + """ + def assertSearchText(self, text): + self.assertThat(self.dash.search_string, Eventually(Equals(text))) + + def test_open_preview_close_preview(self): + """Right clicking on any result shall open a preview, + escaping shall close the preview + """ + lens = self.dash.reveal_file_lens() + self.addCleanup(self.dash.ensure_hidden) + + category = lens.get_category_by_name("Folders") + results = category.get_results() + # wait for a result + refresh_fn = lambda: len(results) + self.assertThat(refresh_fn, Eventually(GreaterThan(0))) + + result = results[0] + # result.preview handles finding xy co-ords and right mouse-click + result.preview() + # revealing a preview may be very slow, not sure if Eventually handles that nicely + self.assertThat(self.dash.preview_displaying, Eventually(Equals(True))) + + self.keyboard.press_and_release("Escape") + + self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + + +class PreviewNavigateTests(DashTestCase): + """Tests that mouse navigation works with previews.""" + + def setUp(self): + super(PreviewNavigateTests, self).setUp() + + self.dash.reveal_application_lens() + self.addCleanup(self.dash.ensure_hidden) + + lens = self.dash.get_current_lens() + + results_category = lens.get_category_by_name("Installed") + results = results_category.get_results() + # wait for results (we need 4 results to perorm the multi-navigation tests) + refresh_fn = lambda: len(results) + self.assertThat(refresh_fn, Eventually(GreaterThan(4))) + + result = results[2] # 2 so we can navigate left + result.preview() + self.assertThat(self.dash.view.preview_displaying, Eventually(Equals(True))) + + self.preview_container = self.dash.view.get_preview_container() + + def test_navigate_left(self): + """Tests that left navigation works with previews.""" + + # wait until preview has finished animating + self.assertThat(self.preview_container.animating, Eventually(Equals(False))) + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + + old_navigation_complete_count = self.preview_container.navigation_complete_count + old_relative_nav_index = self.preview_container.relative_nav_index + + self.preview_container.navigate_left(1) + + self.assertThat(self.preview_container.navigation_complete_count, Eventually(Equals(old_navigation_complete_count+1))) + self.assertThat(self.preview_container.relative_nav_index, Eventually(Equals(old_relative_nav_index-1))) + + # should be one more on the left + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + # if we've navigated left, there should be at least one preview available on right. + self.assertThat(self.preview_container.navigate_right_enabled, Eventually(Equals(True))) + + # Test close preview after navigate + self.keyboard.press_and_release("Escape") + self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + + def test_navigate_left_multi(self): + """Tests that multiple left navigation works with previews.""" + + # wait until preview has finished animating + self.assertThat(self.preview_container.animating, Eventually(Equals(False))) + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + + old_navigation_complete_count = self.preview_container.navigation_complete_count + old_relative_nav_index = self.preview_container.relative_nav_index + + self.preview_container.navigate_left(2) + + self.assertThat(self.preview_container.navigation_complete_count, Eventually(Equals(old_navigation_complete_count+2))) + self.assertThat(self.preview_container.relative_nav_index, Eventually(Equals(old_relative_nav_index-2))) + + # shouldnt be any previews on left. + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(False))) + # if we've navigated left, there should be at least one preview available on right. + self.assertThat(self.preview_container.navigate_right_enabled, Eventually(Equals(True))) + + + def test_navigate_right(self): + """Tests that right navigation works with previews.""" + + # wait until preview has finished animating + self.assertThat(self.preview_container.animating, Eventually(Equals(False))) + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + + old_navigation_complete_count = self.preview_container.navigation_complete_count + old_relative_nav_index = self.preview_container.relative_nav_index + + self.preview_container.navigate_right(1) + + self.assertThat(self.preview_container.navigation_complete_count, Eventually(Equals(old_navigation_complete_count+1))) + self.assertThat(self.preview_container.relative_nav_index, Eventually(Equals(old_relative_nav_index+1))) + + # should be at least one more on the left + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + # if we've navigated right, there should be at least one preview available on left. + self.assertThat(self.preview_container.navigate_right_enabled, Eventually(Equals(True))) + + # Test close preview after navigate + self.keyboard.press_and_release("Escape") + self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + + def test_navigate_right_multi(self): + """Tests that multiple right navigation works with previews.""" + + # wait until preview has finished animating + self.assertThat(self.preview_container.animating, Eventually(Equals(False))) + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + + old_navigation_complete_count = self.preview_container.navigation_complete_count + old_relative_nav_index = self.preview_container.relative_nav_index + + self.preview_container.navigate_right(2) + + self.assertThat(self.preview_container.navigation_complete_count, Eventually(Equals(old_navigation_complete_count+2))) + self.assertThat(self.preview_container.relative_nav_index, Eventually(Equals(old_relative_nav_index+2))) + + # if we've navigated right, there should be at least one preview available on left. + self.assertThat(self.preview_container.navigate_left_enabled, Eventually(Equals(True))) + + + diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py index 9411184a0..0fbbf57cf 100644 --- a/tests/autopilot/unity/tests/test_hud.py +++ b/tests/autopilot/unity/tests/test_hud.py @@ -247,6 +247,20 @@ class HudBehaviorTests(HudTestsBase): self.mouse.click() self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_hud_closes_click_after_text_removed(self): + """Clicking outside of the hud after a search text has been entered and + then removed from the searchbox will make it close.""" + + self.hud.ensure_visible() + self.keyboard.type("Test") + self.keyboard.press_and_release("Escape") + + (x,y,w,h) = self.hud.view.geometry + self.mouse.move(w/2, h+50) + self.mouse.click() + + self.assertThat(self.hud.visible, Eventually(Equals(False))) def test_alt_f4_close_hud(self): """Hud must close on alt+F4.""" @@ -262,7 +276,64 @@ class HudBehaviorTests(HudTestsBase): self.hud.ensure_visible() self.keyboard.press_and_release("Alt+F4") self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_app_activate_on_enter(self): + """Hud must close after activating a search item with Enter.""" + self.hud.ensure_visible() + + self.keyboard.type("Device > System Settings") + self.assertThat(self.hud.search_string, Eventually(Equals("Device > System Settings"))) + + self.keyboard.press_and_release("Enter") + + app_found = self.bamf.wait_until_application_is_running("gnome-control-center.desktop", 5) + self.assertTrue(app_found) + self.addCleanup(self.close_all_app, "System Settings") + + self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_hud_closes_on_escape(self): + """Hud must close on escape after searchbox is cleared""" + self.hud.ensure_visible() + + self.keyboard.type("ThisText") + self.keyboard.press_and_release("Escape") + self.keyboard.press_and_release("Escape") + + self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_hud_closes_on_escape_shrunk(self): + """Hud must close when escape key is pressed""" + self.hud.ensure_visible() + self.keyboard.press_and_release("Escape") + + self.assertThat(self.hud.visible, Eventually(Equals(False))) + def test_alt_arrow_keys_not_eaten(self): + """Tests that Alt+ArrowKey events are correctly passed to the + active window when Unity is not responding to them.""" + + self.start_app_window("Terminal") + + #There's no easy way to read text from terminal, writing input + #to a text file and then reading from there works. + self.keyboard.type('echo "') + + #Terminal is receiving input with Alt+Arrowkeys + self.keyboard.press("Alt") + self.keyboard.press_and_release("Up") + self.keyboard.press_and_release("Down") + self.keyboard.press_and_release("Right") + self.keyboard.press_and_release("Left") + self.keyboard.release("Alt") + + self.keyboard.type('" > /tmp/ap_test_alt_keys') + self.addCleanup(remove, '/tmp/ap_test_alt_keys') + self.keyboard.press_and_release("Enter") + + file_contents = open('/tmp/ap_test_alt_keys', 'r').read().strip() + + self.assertThat(file_contents, Equals('ABCD')) class HudLauncherInteractionsTests(HudTestsBase): @@ -358,9 +429,9 @@ class HudLockedLauncherInteractionsTests(HudTestsBase): for icon in self.launcher.model.get_launcher_icons_for_monitor(self.hud_monitor): if isinstance(icon, HudLauncherIcon): - self.assertFalse(icon.desaturated) + self.assertThat(icon.desaturated, Eventually(Equals(False))) else: - self.assertTrue(icon.desaturated) + self.assertThat(icon.desaturated, Eventually(Equals(True))) def test_hud_launcher_icon_click_hides_hud(self): """Clicking the Hud Icon should hide the HUD""" diff --git a/tests/autopilot/unity/tests/test_ibus.py b/tests/autopilot/unity/tests/test_ibus.py index 35480b1cf..b64cc291e 100644 --- a/tests/autopilot/unity/tests/test_ibus.py +++ b/tests/autopilot/unity/tests/test_ibus.py @@ -18,6 +18,8 @@ from autopilot.emulators.ibus import ( from autopilot.matchers import Eventually from autopilot.testcase import multiply_scenarios from testtools.matchers import Equals, NotEquals +from unity.emulators.dash import Dash +from unity.emulators.hud import Hud from unity.tests import UnityTestCase @@ -27,9 +29,29 @@ class IBusTests(UnityTestCase): def setUp(self): super(IBusTests, self).setUp() + self.set_correct_ibus_trigger_keys() - def tearDown(self): - super(IBusTests, self).tearDown() + def set_correct_ibus_trigger_keys(self): + """Set the correct keys to trigger IBus. + + This method configures the ibus trigger keys inside gconf, and also sets + self.activate_binding and self.activate_release_binding. + + This method adds a cleanUp to reset the old keys once the test is done. + + """ + # get the existing keys: + trigger_hotkey_path = '/desktop/ibus/general/hotkey/trigger' + old_keys = self.get_gconf_option(trigger_hotkey_path) + + self.activate_binding = 'Control+space' + activate_release_binding_option = 'Alt+Release+Control_L' + new_keys = [self.activate_binding, activate_release_binding_option] + + if new_keys != old_keys: + self.set_gconf_option(trigger_hotkey_path, new_keys) + self.addCleanup(self.set_gconf_option, trigger_hotkey_path, old_keys) + self.activate_release_binding = 'Alt+Control_L' @classmethod def setUpClass(cls): @@ -41,6 +63,10 @@ class IBusTests(UnityTestCase): set_active_engines(cls._old_engines) def activate_input_engine_or_skip(self, engine_name): + """Activate the input engine 'engine_name', or skip the test if the + engine name is not avaialble (probably because it's not been installed). + + """ available_engines = get_available_input_engines() if engine_name in available_engines: if get_active_input_engines() != [engine_name]: @@ -49,92 +75,93 @@ class IBusTests(UnityTestCase): self.skip("This test requires the '%s' engine to be installed." % (engine_name)) def activate_ibus(self, widget): - """Activate IBus, and wait till it's actived on 'widget'""" + """Activate IBus, and wait till it's actived on 'widget'.""" self.assertThat(widget.im_active, Equals(False)) - self.keyboard.press_and_release('Ctrl+Space', 0.05) + self.keyboard.press_and_release(self.activate_binding) self.assertThat(widget.im_active, Eventually(Equals(True))) def deactivate_ibus(self, widget): - """Deactivate ibus, and wait till it's inactive on 'widget'""" + """Deactivate ibus, and wait till it's inactive on 'widget'.""" self.assertThat(widget.im_active, Equals(True)) - self.keyboard.press_and_release('Ctrl+Space', 0.05) + self.keyboard.press_and_release(self.activate_binding) self.assertThat(widget.im_active, Eventually(Equals(False))) - def do_dash_test_with_engine(self): - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - self.activate_ibus(self.dash.searchbar) - self.keyboard.type(self.input) - commit_key = getattr(self, 'commit_key', None) - if commit_key: - self.keyboard.press_and_release(commit_key) - self.deactivate_ibus(self.dash.searchbar) - self.assertThat(self.dash.search_string, Eventually(Equals(self.result))) - def do_hud_test_with_engine(self): - self.hud.ensure_visible() - self.addCleanup(self.hud.ensure_hidden) - self.activate_ibus(self.hud.searchbar) +class IBusWidgetScenariodTests(IBusTests): + """A class that includes scenarios for the hud and dash widgets.""" + + scenarios = [ + ('dash', {'widget': Dash()}), + ('hud', {'widget': Hud()}) + ] + + def do_ibus_test(self): + """Do the basic IBus test on self.widget using self.input and self.result.""" + self.widget.ensure_visible() + self.addCleanup(self.widget.ensure_hidden) + self.activate_ibus(self.widget.searchbar) self.keyboard.type(self.input) commit_key = getattr(self, 'commit_key', None) if commit_key: self.keyboard.press_and_release(commit_key) - self.deactivate_ibus(self.hud.searchbar) - self.assertThat(self.hud.search_string, Eventually(Equals(self.result))) + self.deactivate_ibus(self.widget.searchbar) + self.assertThat(self.widget.search_string, Eventually(Equals(self.result))) + -class IBusTestsPinyin(IBusTests): +class IBusTestsPinyin(IBusWidgetScenariodTests): """Tests for the Pinyin(Chinese) input engine.""" engine_name = "pinyin" - scenarios = [ - ('basic', {'input': 'abc1', 'result': u'\u963f\u5e03\u4ece'}), - ('photo', {'input': 'zhaopian ', 'result': u'\u7167\u7247'}), - ('internet', {'input': 'hulianwang ', 'result': u'\u4e92\u8054\u7f51'}), - ('disk', {'input': 'cipan ', 'result': u'\u78c1\u76d8'}), - ('disk_management', {'input': 'cipan guanli ', 'result': u'\u78c1\u76d8\u7ba1\u7406'}), - ] + scenarios = multiply_scenarios( + IBusWidgetScenariodTests.scenarios, + [ + ('basic', {'input': 'abc1', 'result': u'\u963f\u5e03\u4ece'}), + ('photo', {'input': 'zhaopian ', 'result': u'\u7167\u7247'}), + ('internet', {'input': 'hulianwang ', 'result': u'\u4e92\u8054\u7f51'}), + ('disk', {'input': 'cipan ', 'result': u'\u78c1\u76d8'}), + ('disk_management', {'input': 'cipan guanli ', 'result': u'\u78c1\u76d8\u7ba1\u7406'}), + ] + ) def setUp(self): super(IBusTestsPinyin, self).setUp() self.activate_input_engine_or_skip(self.engine_name) - def test_simple_input_dash(self): - self.do_dash_test_with_engine() - - def test_simple_input_hud(self): - self.do_hud_test_with_engine() + def test_pinyin(self): + self.do_ibus_test() -class IBusTestsHangul(IBusTests): +class IBusTestsHangul(IBusWidgetScenariodTests): """Tests for the Hangul(Korean) input engine.""" engine_name = "hangul" - scenarios = [ - ('transmission', {'input': 'xmfostmaltus ', 'result': u'\ud2b8\ub79c\uc2a4\ubbf8\uc158 '}), - ('social', {'input': 'httuf ', 'result': u'\uc18c\uc15c '}), - ('document', {'input': 'anstj ', 'result': u'\ubb38\uc11c '}), - ] + scenarios = multiply_scenarios( + IBusWidgetScenariodTests.scenarios, + [ + ('transmission', {'input': 'xmfostmaltus ', 'result': u'\ud2b8\ub79c\uc2a4\ubbf8\uc158 '}), + ('social', {'input': 'httuf ', 'result': u'\uc18c\uc15c '}), + ('document', {'input': 'anstj ', 'result': u'\ubb38\uc11c '}), + ] + ) def setUp(self): super(IBusTestsHangul, self).setUp() self.activate_input_engine_or_skip(self.engine_name) - def test_simple_input_dash(self): - self.do_dash_test_with_engine() - - def test_simple_input_hud(self): - self.do_hud_test_with_engine() + def test_hangul(self): + self.do_ibus_test() -class IBusTestsAnthy(IBusTests): +class IBusTestsAnthy(IBusWidgetScenariodTests): """Tests for the Anthy(Japanese) input engine.""" engine_name = "anthy" scenarios = multiply_scenarios( + IBusWidgetScenariodTests.scenarios, [ ('system', {'input': 'shisutemu ', 'result': u'\u30b7\u30b9\u30c6\u30e0'}), ('game', {'input': 'ge-mu ', 'result': u'\u30b2\u30fc\u30e0'}), @@ -150,11 +177,8 @@ class IBusTestsAnthy(IBusTests): super(IBusTestsAnthy, self).setUp() self.activate_input_engine_or_skip(self.engine_name) - def test_simple_input_dash(self): - self.do_dash_test_with_engine() - - def test_simple_input_hud(self): - self.do_hud_test_with_engine() + def test_anthy(self): + self.do_ibus_test() class IBusTestsPinyinIgnore(IBusTests): @@ -194,6 +218,7 @@ class IBusTestsPinyinIgnore(IBusTests): class IBusTestsAnthyIgnore(IBusTests): """Tests for ignoring key events while the Anthy input engine is active.""" + scenarios = None engine_name = "anthy" def setUp(self): @@ -224,3 +249,92 @@ class IBusTestsAnthyIgnore(IBusTests): self.deactivate_ibus(self.hud.searchbar) self.assertEqual(old_selected, new_selected) + + +class IBusActivationTests(IBusTests): + + """This class contains tests that make sure each IBus engine can activate + and deactivate correctly with various keystrokes. + + """ + + scenarios = multiply_scenarios( + IBusWidgetScenariodTests.scenarios, + [ (e, {'engine_name': e}) for e in ('pinyin','anthy','hangul') ] + ) + + def setUp(self): + super(IBusActivationTests, self).setUp() + self.activate_input_engine_or_skip(self.engine_name) + + def activate_ibus_on_release(self, widget): + """Activate IBus when keys have been released, and wait till it's actived + on 'widget'. + + """ + self.assertThat(widget.im_active, Equals(False)) + self.keyboard.press_and_release(self.activate_release_binding) + self.assertThat(widget.im_active, Eventually(Equals(True))) + + def deactivate_ibus_on_release(self, widget): + """Activate IBus when keys have been released, and wait till it's actived + on 'widget'. + + """ + self.assertThat(widget.im_active, Equals(True)) + self.keyboard.press_and_release(self.activate_release_binding) + self.assertThat(widget.im_active, Eventually(Equals(False))) + + def test_activate(self): + """Tests the ibus activation using the "key-down" keybinding.""" + self.widget.ensure_visible() + self.addCleanup(self.widget.ensure_hidden) + self.assertThat(self.widget.searchbar.im_active, Equals(False)) + + self.keyboard.press(self.activate_binding) + self.addCleanup(self.keyboard.release, self.activate_binding) + + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(True))) + self.keyboard.release(self.activate_binding) + + self.deactivate_ibus(self.widget.searchbar) + + def test_deactivate(self): + """Tests the ibus deactivation using the "key-down" keybinding""" + self.widget.ensure_visible() + self.addCleanup(self.widget.ensure_hidden) + self.activate_ibus(self.widget.searchbar) + + self.assertThat(self.widget.searchbar.im_active, Equals(True)) + self.keyboard.press(self.activate_binding) + self.addCleanup(self.keyboard.release, self.activate_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(False))) + self.keyboard.release(self.activate_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(False))) + + def test_activate_on_release(self): + """Tests the ibus activation using "key-up" keybinding""" + self.widget.ensure_visible() + self.addCleanup(self.widget.ensure_hidden) + + self.assertThat(self.widget.searchbar.im_active, Equals(False)) + self.keyboard.press(self.activate_release_binding) + self.addCleanup(self.keyboard.release, self.activate_release_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(False))) + self.keyboard.release(self.activate_release_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(True))) + + self.deactivate_ibus_on_release(self.widget.searchbar) + + def test_deactivate_on_release(self): + """Tests the ibus deactivation using "key-up" keybinding""" + self.widget.ensure_visible() + self.addCleanup(self.widget.ensure_hidden) + self.activate_ibus_on_release(self.widget.searchbar) + + self.assertThat(self.widget.searchbar.im_active, Equals(True)) + self.keyboard.press(self.activate_release_binding) + self.addCleanup(self.keyboard.release, self.activate_release_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(True))) + self.keyboard.release(self.activate_release_binding) + self.assertThat(self.widget.searchbar.im_active, Eventually(Equals(False))) diff --git a/tests/autopilot/unity/tests/test_panel.py b/tests/autopilot/unity/tests/test_panel.py index abbb77641..1d31f81be 100644 --- a/tests/autopilot/unity/tests/test_panel.py +++ b/tests/autopilot/unity/tests/test_panel.py @@ -54,9 +54,8 @@ class PanelTestsBase(UnityTestCase): """ self.close_all_app(app_name) - app = self.start_app(app_name, locale="C") - - [app_win] = app.get_windows() + app_win = self.start_app_window(app_name, locale="C") + app = app_win.application app_win.set_focus() self.assertTrue(app.is_active) @@ -113,7 +112,7 @@ class PanelTestsBase(UnityTestCase): self.addCleanup(self.keyboard.press_and_release, "Escape") self.assertThat(indicator.active, Eventually(Equals(True))) - def assert_win_buttons_in_overlay_mode(self, overlay_mode): + def assertWinButtonsInOverlayMode(self, overlay_mode): """Assert that there are three panel window buttons and all of them are in the specified overlay mode. @@ -126,7 +125,7 @@ class PanelTestsBase(UnityTestCase): for button in buttons: self.assertThat(button.overlay_mode, Eventually(Equals(overlay_mode))) - def assert_no_window_open_with_xid(self, x_id): + def assertNoWindowOpenWithXid(self, x_id): """Assert that Bamf doesn't know of any open windows with the given xid.""" # We can't check text_win.closed since we've just destroyed the window. # Instead we make sure no window with it's x_id exists. @@ -202,16 +201,24 @@ class PanelTitleTests(PanelTestsBase): old_title = text_win.title text_win.set_focus() - self.keyboard.type("Unity rocks!") - self.keyboard.press_and_release("Ctrl+S") - sleep(.25) - self.keyboard.type("/tmp/autopilot-awesome-test.txt") - self.keyboard.press_and_release("Return") - self.addCleanup(os.remove, "/tmp/autopilot-awesome-test.txt") + self.keyboard.press_and_release("Ctrl+n") self.assertThat(lambda: text_win.title, Eventually(NotEquals(old_title))) self.assertThat(self.panel.title, Eventually(Equals(text_win.title))) + def test_panel_title_doesnt_change_with_switcher(self): + """Switching between apps must not change the Panels title.""" + calc_win = self.open_new_application_window("Calculator") + text_win = self.open_new_application_window("Text Editor") + current_title = self.panel.title + + self.switcher.initiate() + self.addCleanup(self.switcher.terminate) + self.switcher.next_icon() + + self.assertThat(self.panel.title, + Eventually(Equals(current_title))) + class PanelWindowButtonsTests(PanelTestsBase): @@ -225,7 +232,7 @@ class PanelWindowButtonsTests(PanelTestsBase): def test_window_buttons_dont_show_on_empty_desktop(self): """Tests that the window buttons are not shown on clean desktop.""" - # THis initially used Show Desktop mode, but it's very buggy from within + # This initially used Show Desktop mode, but it's very buggy from within # autopilot. We assume that workspace 2 is empty (which is safe for the # jenkins runs at least.) initial_workspace = self.workspace.current_workspace @@ -272,7 +279,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.panel.move_mouse_over_window_buttons() self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True))) - self.assert_win_buttons_in_overlay_mode(False) + self.assertWinButtonsInOverlayMode(False) def test_window_buttons_show_with_dash(self): """Window buttons must be shown when the dash is open.""" @@ -280,7 +287,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.addCleanup(self.dash.ensure_hidden) self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True))) - self.assert_win_buttons_in_overlay_mode(True) + self.assertWinButtonsInOverlayMode(True) def test_window_buttons_show_with_hud(self): """Window buttons must be shown when the HUD is open.""" @@ -288,7 +295,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.addCleanup(self.hud.ensure_hidden) self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True))) - self.assert_win_buttons_in_overlay_mode(True) + self.assertWinButtonsInOverlayMode(True) def test_window_buttons_update_visual_state(self): """Window button must update its state in response to mouse events.""" @@ -310,19 +317,9 @@ class PanelWindowButtonsTests(PanelTestsBase): their area. """ self.hud.ensure_visible() - button = self.panel.window_buttons.close - - # FIXME: THere's a bug in unity that prevents us from doing: - # self.addCleanup(self.hud.ensure_hidden) - # SO we do this instead. The bug is: - # - # https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1021087 - # - # Once that's fixed the next two lines can be removed, and the one above - # added instead. - self.addCleanup(self.assertThat, self.hud.visible, Eventually(Equals(False))) - self.addCleanup(button.mouse_click) + self.addCleanup(self.hud.ensure_hidden) + button = self.panel.window_buttons.close button.mouse_move_to() self.mouse.press() self.assertThat(button.visual_state, Eventually(Equals("pressed"))) @@ -340,7 +337,7 @@ class PanelWindowButtonsTests(PanelTestsBase): win_xid = text_win.x_id self.panel.window_buttons.close.mouse_click() - self.assert_no_window_open_with_xid(win_xid) + self.assertNoWindowOpenWithXid(win_xid) def test_window_buttons_close_follows_fitts_law(self): """Tests that the 'Close' button is activated when clicking at 0,0. @@ -357,7 +354,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.mouse.move(screen_x, screen_y) self.mouse.click() - self.assert_no_window_open_with_xid(win_xid) + self.assertNoWindowOpenWithXid(win_xid) def test_window_buttons_minimize_button_works_for_window(self): """Tests that the window button 'Minimize' actually minimizes a window.""" @@ -367,7 +364,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.panel.window_buttons.minimize.mouse_click() - self.assertThat(lambda: text_win.is_hidden, Eventually(Equals(True))) + self.assertProperty(text_win, is_hidden=True) def test_window_buttons_minimize_follows_fitts_law(self): """Tests that the 'Minimize' button is conform to Fitts's Law. @@ -385,7 +382,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.mouse.move(target_x, target_y) self.mouse.click() - self.assertThat(lambda: text_win.is_hidden, Eventually(Equals(True))) + self.assertProperty(text_win, is_hidden=True) def test_window_buttons_unmaximize_button_works_for_window(self): """Tests that the window button 'Unmaximize' actually unmaximizes a window.""" @@ -415,7 +412,7 @@ class PanelWindowButtonsTests(PanelTestsBase): sleep(1) self.mouse.click() - self.assertThat(lambda: text_win.is_maximized, Eventually(Equals(False))) + self.assertProperty(text_win, is_maximized=False) def test_window_buttons_close_button_works_for_hud(self): """Tests that the window 'Close' actually closes the HUD.""" @@ -435,13 +432,8 @@ class PanelWindowButtonsTests(PanelTestsBase): def test_minimize_button_does_nothing_for_hud(self): """Minimize button must not affect the Hud.""" self.hud.ensure_visible() - # FIXME: When this bug is fixed: - # - # https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1021087 - # - # We can replace the following line with: - # self.addCleanup(self.hud.ensure_hidden) - self.addCleanup(self.panel.window_buttons.close.mouse_click) + self.addCleanup(self.hud.ensure_hidden) + self.panel.window_buttons.minimize.mouse_click() self.assertThat(self.hud.visible, Eventually(Equals(True))) @@ -456,13 +448,8 @@ class PanelWindowButtonsTests(PanelTestsBase): def test_maximize_button_does_nothing_for_hud(self): """Maximize button must not affect the Hud.""" self.hud.ensure_visible() - # FIXME: When this bug is fixed: - # - # https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1021087 - # - # We can replace the following line with: - # self.addCleanup(self.hud.ensure_hidden) - self.addCleanup(self.panel.window_buttons.close.mouse_click) + self.addCleanup(self.hud.ensure_hidden) + self.panel.window_buttons.maximize.mouse_click() self.assertThat(self.hud.visible, Eventually(Equals(True))) @@ -475,13 +462,7 @@ class PanelWindowButtonsTests(PanelTestsBase): """ inital_form_factor = self.dash.view.form_factor self.hud.ensure_visible() - # FIXME: When this bug is fixed: - # - # https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1021087 - # - # We can replace the following line with: - # self.addCleanup(self.hud.ensure_hidden) - self.addCleanup(self.panel.window_buttons.close.mouse_click) + self.addCleanup(self.hud.ensure_hidden) self.panel.window_buttons.maximize.mouse_click() # long sleep here to make sure that any change that might happen will @@ -595,7 +576,7 @@ class PanelWindowButtonsTests(PanelTestsBase): self.move_window_to_panel_monitor(target_win, restore_position=False) self.keybinding("window/maximize") - self.assertThat(lambda: target_win.is_maximized, Eventually(Equals(True))) + self.assertProperty(target_win, is_maximized=True) self.assertThat(self.panel.window_buttons.close.enabled, Eventually(Equals(True))) self.assertThat(self.panel.window_buttons.minimize.enabled, Eventually(Equals(False))) @@ -647,6 +628,16 @@ class PanelWindowButtonsTests(PanelTestsBase): self.keyboard.type("World") self.assertThat(self.hud.search_string, Eventually(Equals("HelloWorld"))) + + def test_double_click_unmaximize_window(self): + """Double clicking the grab area must unmaximize a maximized window.""" + gedit_win = self.open_new_application_window("Text Editor", maximized=True) + + self.panel.move_mouse_over_grab_area() + self.mouse.click() + self.mouse.click() + + self.assertThat(self.panel.title, Eventually(Equals(gedit_win.application.name))) class PanelHoverTests(PanelTestsBase): @@ -821,7 +812,10 @@ class PanelMenuTests(PanelTestsBase): self.patch_environment("UBUNTU_MENUPROXY", "") calc_win = self.open_new_application_window("Calculator") - self.assertThat(lambda: len(self.panel.menus.get_entries()), Eventually(Equals(0))) + self.assertThat( + lambda: len(self.panel.menus.get_entries()), + Eventually(Equals(0)), + "Current panel entries are: %r" % self.panel.menus.get_entries()) self.panel.move_mouse_over_grab_area() self.assertThat(self.panel.title, Eventually(Equals(calc_win.application.name))) @@ -836,10 +830,10 @@ class PanelMenuTests(PanelTestsBase): def test_menus_dont_show_if_a_new_application_window_is_opened(self): """This tests the menu discovery feature on new window for a know application.""" - self.open_new_application_window("Calculator") + self.open_new_application_window("Character Map") self.sleep_menu_settle_period() - self.start_app("Calculator") + self.start_app("Character Map") sleep(self.panel.menus.fadein_duration / 1000.0) # Not using Eventually here since this is time-critical. Need to work # out a better way to do this. @@ -906,10 +900,17 @@ class PanelIndicatorEntryTests(PanelTestsBase): scenarios = _make_monitor_scenarios() - def test_menu_opens_on_click(self): - """Tests that clicking on a menu entry, opens a menu.""" + def open_app_and_get_menu_entry(self): + """Open the test app and wait for the menu entry to appear.""" self.open_new_application_window("Calculator") + refresh_fn = lambda: len(self.panel.menus.get_entries()) + self.assertThat(refresh_fn, Eventually(GreaterThan(0))) menu_entry = self.panel.menus.get_entries()[0] + return menu_entry + + def test_menu_opens_on_click(self): + """Tests that clicking on a menu entry, opens a menu.""" + menu_entry = self.open_app_and_get_menu_entry() self.mouse_open_indicator(menu_entry) self.assertThat(menu_entry.active, Eventually(Equals(True))) @@ -918,8 +919,7 @@ class PanelIndicatorEntryTests(PanelTestsBase): def test_menu_opens_closes_on_click(self): """Clicking on an open menu entru must close it again.""" - self.open_new_application_window("Calculator") - menu_entry = self.panel.menus.get_entries()[0] + menu_entry = self.open_app_and_get_menu_entry() self.mouse_open_indicator(menu_entry) # This assert is for timing purposes only: @@ -932,8 +932,7 @@ class PanelIndicatorEntryTests(PanelTestsBase): def test_menu_closes_on_click_outside(self): """Clicking outside an open menu must close it.""" - self.open_new_application_window("Calculator") - menu_entry = self.panel.menus.get_entries()[0] + menu_entry = self.open_app_and_get_menu_entry() self.mouse_open_indicator(menu_entry) # This assert is for timing purposes only: @@ -973,7 +972,7 @@ class PanelKeyNavigationTests(PanelTestsBase): self.assertThat(open_indicator.entry_id, Eventually(Equals(expected_indicator.entry_id))) self.keybinding("panel/open_first_menu") - self.assertThat(self.panel.get_active_indicator(), Eventually(Equals(None))) + self.assertThat(self.panel.get_active_indicator, Eventually(Equals(None))) def test_panel_menu_accelerators_work(self): """Pressing a valid menu accelerator must open the correct menu item.""" @@ -1050,33 +1049,33 @@ class PanelGrabAreaTests(PanelTestsBase): self.panel.move_mouse_below_the_panel() self.mouse.release() - self.assertThat(lambda: text_win.is_maximized, Eventually(Equals(False))) + self.assertProperty(text_win, is_maximized=False) def test_focus_the_maximized_window_works(self): """Clicking on the grab area must put a maximized window in focus.""" text_win = self.open_new_application_window("Text Editor", maximized=True) calc_win = self.open_new_application_window("Calculator") - self.assertThat(lambda: text_win.is_focused, Eventually(Equals(False))) - self.assertThat(lambda: calc_win.is_focused, Eventually(Equals(True))) + self.assertProperty(text_win, is_focused=False) + self.assertProperty(calc_win, is_focused=True) self.move_mouse_over_grab_area() self.mouse.click() - self.assertThat(lambda: text_win.is_focused, Eventually(Equals(True))) + self.assertProperty(text_win, is_focused=True) def test_lower_the_maximized_window_works(self): """Middle-clicking on the panel grab area must lower a maximized window.""" calc_win = self.open_new_application_window("Calculator") text_win = self.open_new_application_window("Text Editor", maximized=True) - self.assertThat(lambda: text_win.is_focused, Eventually(Equals(True))) - self.assertThat(lambda: calc_win.is_focused, Eventually(Equals(False))) + self.assertProperty(text_win, is_focused=True) + self.assertProperty(calc_win, is_focused=False) self.move_mouse_over_grab_area() self.mouse.click(2) - self.assertThat(lambda: calc_win.is_focused, Eventually(Equals(True))) + self.assertProperty(calc_win, is_focused=True) def test_panels_dont_steal_keynav_foucs_from_hud(self): """On a mouse click event on the panel you must still be able to type into the Hud.""" diff --git a/tests/autopilot/unity/tests/test_quicklist.py b/tests/autopilot/unity/tests/test_quicklist.py index d9cfe6647..8aa4a3ad2 100644 --- a/tests/autopilot/unity/tests/test_quicklist.py +++ b/tests/autopilot/unity/tests/test_quicklist.py @@ -72,14 +72,14 @@ class QuicklistActionTests(UnityTestCase): Then we activate the Calculator quicklist item. Then we actiavte the Mahjongg launcher icon. """ - mah_win1 = self.start_app_window("Mahjongg") + char_win1 = self.start_app_window("Character Map") calc_win = self.start_app_window("Calculator") - mah_win2 = self.start_app_window("Mahjongg") + char_win2 = self.start_app_window("Character Map") - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) - mahj_icon = self.launcher.model.get_icon( - desktop_id=mah_win1.application.desktop_file) + char_icon = self.launcher.model.get_icon( + desktop_id=char_win1.application.desktop_file) calc_icon = self.launcher.model.get_icon( desktop_id=calc_win.application.desktop_file) @@ -87,29 +87,29 @@ class QuicklistActionTests(UnityTestCase): calc_ql.get_quicklist_application_item(calc_win.application.name).mouse_click() self.assertProperty(calc_win, is_focused=True) - self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1]) + self.assertVisibleWindowStack([calc_win, char_win2, char_win1]) - mahj_ql = self.open_quicklist_for_icon(mahj_icon) - mahj_ql.get_quicklist_application_item(mah_win1.application.name).mouse_click() + char_ql = self.open_quicklist_for_icon(char_icon) + char_ql.get_quicklist_application_item(char_win1.application.name).mouse_click() - self.assertProperty(mah_win2, is_focused=True) - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + self.assertProperty(char_win2, is_focused=True) + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) def test_quicklist_application_item_initiate_spread(self): """This tests shows that when you activate a quicklist application item when an application window is focused, the spread is initiated. """ - calc_win1 = self.start_app_window("Calculator") - calc_win2 = self.start_app_window("Calculator") - calc_app = calc_win1.application + char_win1 = self.start_app_window("Character Map") + char_win2 = self.start_app_window("Character Map") + char_app = char_win1.application - self.assertVisibleWindowStack([calc_win2, calc_win1]) - self.assertProperty(calc_win2, is_focused=True) + self.assertVisibleWindowStack([char_win2, char_win1]) + self.assertProperty(char_win2, is_focused=True) - calc_icon = self.launcher.model.get_icon(desktop_id=calc_app.desktop_file) + char_icon = self.launcher.model.get_icon(desktop_id=char_app.desktop_file) - calc_ql = self.open_quicklist_for_icon(calc_icon) - app_item = calc_ql.get_quicklist_application_item(calc_app.name) + char_ql = self.open_quicklist_for_icon(char_icon) + app_item = char_ql.get_quicklist_application_item(char_app.name) self.addCleanup(self.keybinding, "spread/cancel") app_item.mouse_click() @@ -155,6 +155,44 @@ class QuicklistActionTests(UnityTestCase): self.addCleanup(self.dash.ensure_hidden) self.assertThat(self.dash.visible, Eventually(Equals(True))) + def test_right_click_opens_quicklist_if_already_open(self): + """A right click to another icon in the launcher must + close the current open quicklist and open the other + icons quicklist. + lp:890991 + """ + + calc_win = self.start_app_window("Calculator") + mahj_win = self.start_app_window("Mahjongg") + + calc_icon = self.launcher.model.get_icon( + desktop_id=calc_win.application.desktop_file) + mahj_icon = self.launcher.model.get_icon( + desktop_id=mahj_win.application.desktop_file) + + calc_ql = self.open_quicklist_for_icon(calc_icon) + self.assertThat(calc_ql.active, Eventually(Equals(True))) + + mahj_ql = self.open_quicklist_for_icon(mahj_icon) + self.assertThat(mahj_ql.active, Eventually(Equals(True))) + self.assertThat(calc_ql.active, Eventually(Equals(False))) + + def test_right_clicking_same_icon_doesnt_reopen_ql(self): + """A right click to the same icon in the launcher must + not re-open the quicklist if already open. It must hide. + """ + + calc_win = self.start_app_window("Calculator") + + calc_icon = self.launcher.model.get_icon( + desktop_id=calc_win.application.desktop_file) + + calc_ql = self.open_quicklist_for_icon(calc_icon) + self.assertThat(calc_ql.active, Eventually(Equals(True))) + + calc_ql = self.open_quicklist_for_icon(calc_icon) + self.assertThat(calc_ql.active, Eventually(Equals(False))) + class QuicklistKeyNavigationTests(UnityTestCase): """Tests for the quicklist key navigation.""" @@ -343,3 +381,23 @@ class QuicklistKeyNavigationTests(UnityTestCase): mouse_item = self.quicklist.selectable_items[-2] mouse_item.mouse_move_to() self.assertCorrectItemSelected(mouse_item) + + def test_moving_mouse_during_grab_select_correct_menuitem(self): + """Test that moving the mouse during grabbing selects the + correct menu item. See bug #1027955. + """ + self.open_quicklist_with_mouse() + mouse_item = self.quicklist.selectable_items[0] + mouse_item.mouse_move_to() + self.assertThat(mouse_item.selected, Eventually(Equals(True))) + + # Dragging the mouse horizontally doesn't change the selection + self.mouse.press() + self.addCleanup(self.mouse.release) + self.mouse.move(mouse_item.x + mouse_item.width - 10, mouse_item.y + mouse_item.height / 2) + self.assertThat(mouse_item.selected, Eventually(Equals(True))) + + # Moving the mouse down selects the next item + mouse_item = self.quicklist.selectable_items[1] + mouse_item.mouse_move_to() + self.assertThat(mouse_item.selected, Eventually(Equals(True))) diff --git a/tests/autopilot/unity/tests/test_shortcut_hint.py b/tests/autopilot/unity/tests/test_shortcut_hint.py index 63b4eaf1e..5af6f883d 100644 --- a/tests/autopilot/unity/tests/test_shortcut_hint.py +++ b/tests/autopilot/unity/tests/test_shortcut_hint.py @@ -32,11 +32,11 @@ class BaseShortcutHintTests(UnityTestCase): def skip_if_monitor_too_small(self): monitor = self.screen_geo.get_primary_monitor() - monitor_geo = self.screen_geo.get_monitor_geometry(monitor); - monitor_w = monitor_geo[2]; - monitor_h = monitor_geo[3]; - launcher_width = self.launcher.get_launcher_for_monitor(monitor).geometry[2]; - panel_height = 24 # TODO get it from panel + monitor_geo = self.screen_geo.get_monitor_geometry(monitor) + monitor_w = monitor_geo[2] + monitor_h = monitor_geo[3] + launcher_width = self.launcher.get_launcher_for_monitor(monitor).geometry[2] + panel_height = self.panels.get_panel_for_monitor(monitor).geometry[3] if ((monitor_w - launcher_width) <= self.DEFAULT_WIDTH or (monitor_h - panel_height) <= self.DEFAULT_HEIGHT): diff --git a/tests/autopilot/unity/tests/test_showdesktop.py b/tests/autopilot/unity/tests/test_showdesktop.py index e2f87faed..6efc9d972 100644 --- a/tests/autopilot/unity/tests/test_showdesktop.py +++ b/tests/autopilot/unity/tests/test_showdesktop.py @@ -8,11 +8,8 @@ from __future__ import absolute_import -from autopilot.matchers import Eventually -from testtools.matchers import NotEquals from time import sleep -from unity.emulators.icons import DesktopLauncherIcon from unity.tests import UnityTestCase @@ -65,13 +62,13 @@ class ShowDesktopTests(UnityTestCase): def test_unhide_single_app(self): """Un-hide a single app from launcher after hiding all apps.""" - test_windows = self.launch_test_apps() + charmap, calc = self.launch_test_apps() # show desktop, verify all windows are hidden: self.window_manager.enter_show_desktop() self.addCleanup(self.window_manager.leave_show_desktop) - for win in test_windows: + for win in (charmap, calc): self.assertProperty(win, is_valid=True) self.assertProperty(win, is_hidden=True) @@ -88,7 +85,7 @@ class ShowDesktopTests(UnityTestCase): # hide desktop - now all windows should be visible: self.window_manager.leave_show_desktop() - for win in test_windows: + for win in (charmap, calc): self.assertProperty(win, is_hidden=False) def test_showdesktop_switcher(self): diff --git a/tests/autopilot/unity/tests/test_switcher.py b/tests/autopilot/unity/tests/test_switcher.py index f3a301959..9e7639b8e 100644 --- a/tests/autopilot/unity/tests/test_switcher.py +++ b/tests/autopilot/unity/tests/test_switcher.py @@ -9,6 +9,7 @@ from __future__ import absolute_import from autopilot.matchers import Eventually +from autopilot.testcase import multiply_scenarios import logging from testtools.matchers import Equals, Contains, Not from time import sleep @@ -19,6 +20,22 @@ from unity.tests import UnityTestCase logger = logging.getLogger(__name__) class SwitcherTestCase(UnityTestCase): + + scenarios = [ + ('show_desktop_icon_true', {'show_desktop_option': True}), + ('show_desktop_icon_false', {'show_desktop_option': False}), + ] + + def setUp(self): + super(SwitcherTestCase, self).setUp() + self.set_show_desktop(self.show_desktop_option) + + def set_show_desktop(self, state): + if type(state) is not bool: + raise TypeError("'state' must be boolean, not %r" % type(state)) + self.set_unity_option("disable_show_desktop", state) + self.assertThat(self.switcher.controller.show_desktop_disabled, Eventually(Equals(state))) + def set_timeout_setting(self, state): if type(state) is not bool: raise TypeError("'state' must be boolean, not %r" % type(state)) @@ -29,9 +46,9 @@ class SwitcherTestCase(UnityTestCase): """Start some applications, returning their windows. If no applications are specified, the following will be started: - * Character Map - * Calculator * Calculator + * Character Map + * Character Map Windows are always started in the order that they are specified (which means the last specified application will *probably* be at the top of the @@ -40,7 +57,7 @@ class SwitcherTestCase(UnityTestCase): """ if len(args) == 0: - args = ('Character Map', 'Calculator', 'Calculator') + args = ('Calculator', 'Character Map', 'Character Map') windows = [] for app in args: windows.append(self.start_app_window(app)) @@ -134,6 +151,8 @@ class SwitcherTests(SwitcherTestCase): open the switcher. """ + self.start_app("Character Map") + self.keybinding_hold("switcher/reveal_normal") self.addCleanup(self.keybinding_release, "switcher/reveal_normal") self.assertThat(self.switcher.visible, Eventually(Equals(False))) @@ -144,6 +163,8 @@ class SwitcherTests(SwitcherTestCase): def test_switcher_cancel(self): """Pressing the switcher cancel keystroke must cancel the switcher.""" + self.start_app("Character Map") + self.switcher.initiate() self.addCleanup(self.switcher.terminate) @@ -153,6 +174,8 @@ class SwitcherTests(SwitcherTestCase): def test_lazy_switcher_cancel(self): """Must be able to cancel the switcher after a 'lazy' initiation.""" + self.start_app("Character Map") + self.keybinding_hold("switcher/reveal_normal") self.addCleanup(self.keybinding_release, "switcher/reveal_normal") self.assertThat(self.switcher.visible, Eventually(Equals(False))) @@ -208,24 +231,25 @@ class SwitcherWindowsManagementTests(SwitcherTestCase): Then we close the currently focused window. """ - mah_win1, calc_win, mah_win2 = self.start_applications("Mahjongg", "Calculator", "Mahjongg") - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + char_win1, calc_win, char_win2 = self.start_applications("Character Map", "Calculator", "Character Map") + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) self.keybinding("switcher/reveal_normal") self.assertProperty(calc_win, is_focused=True) - self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1]) + self.assertVisibleWindowStack([calc_win, char_win2, char_win1]) self.keybinding("switcher/reveal_normal") - self.assertProperty(mah_win2, is_focused=True) - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + self.assertProperty(char_win2, is_focused=True) + self.assertVisibleWindowStack([char_win2, calc_win, char_win1]) self.keybinding("window/close") self.assertProperty(calc_win, is_focused=True) - self.assertVisibleWindowStack([calc_win, mah_win1]) + self.assertVisibleWindowStack([calc_win, char_win1]) class SwitcherDetailsTests(SwitcherTestCase): """Test the details mode for the switcher.""" + def setUp(self): super(SwitcherDetailsTests, self).setUp() self.set_timeout_setting(True) @@ -271,10 +295,12 @@ class SwitcherDetailsModeTests(SwitcherTestCase): """ - scenarios = [ - ('initiate_with_grave', {'initiate_keycode': '`'}), - ('initiate_with_down', {'initiate_keycode': 'Down'}), - ] + scenarios = multiply_scenarios(SwitcherTestCase.scenarios, + [ + ('initiate_with_grave', {'initiate_keycode': '`'}), + ('initiate_with_down', {'initiate_keycode': 'Down'}), + ] + ) def test_can_start_details_mode(self): """Must be able to switch to details mode using selected scenario keycode. @@ -308,6 +334,22 @@ class SwitcherDetailsModeTests(SwitcherTestCase): self.switcher.next_icon() self.assertThat(self.switcher.selection_index, Eventually(Equals(0))) + def test_detail_mode_selects_last_active_window(self): + """The active selection in detail mode must be the last focused window. + If it was the currently active application type. + """ + char_win1, char_win2 = self.start_applications("Character Map", "Character Map") + self.assertVisibleWindowStack([char_win2, char_win1]) + + self.switcher.initiate() + while self.switcher.current_icon.tooltip_text != char_win2.application.name: + self.switcher.next_icon() + self.keyboard.press_and_release(self.initiate_keycode) + sleep(0.5) + self.switcher.select() + + self.assertProperty(char_win1, is_focused=True) + class SwitcherWorkspaceTests(SwitcherTestCase): """Test Switcher behavior with respect to multiple workspaces.""" @@ -339,7 +381,6 @@ class SwitcherWorkspaceTests(SwitcherTestCase): self.workspace.switch_to(2) char_map = self.start_app("Character Map") - self.switcher.initiate(SwitcherMode.ALL) self.addCleanup(self.switcher.terminate) @@ -361,18 +402,34 @@ class SwitcherWorkspaceTests(SwitcherTestCase): self.set_unity_option("alt_tab_timeout", False) self.workspace.switch_to(1) - self.start_app("Mahjongg") + self.start_app("Character Map") self.workspace.switch_to(3) - mah_win2 = self.start_app_window("Mahjongg") + char_win2 = self.start_app_window("Character Map") self.keybinding("window/minimize") - self.assertProperty(mah_win2, is_hidden=True) + self.assertProperty(char_win2, is_hidden=True) self.start_app("Calculator") self.switcher.initiate() - while self.switcher.current_icon.tooltip_text != mah_win2.application.name: + while self.switcher.current_icon.tooltip_text != char_win2.application.name: self.switcher.next_icon() self.switcher.select() - self.assertProperty(mah_win2, is_hidden=False) + self.assertProperty(char_win2, is_hidden=False) + + def test_switcher_is_disabled_when_wall_plugin_active(self): + """The switcher must not open when the wall plugin is active using ctrl+alt+<direction>.""" + + initial_workspace = self.workspace.current_workspace + self.addCleanup(self.workspace.switch_to, initial_workspace) + + self.workspace.switch_to(0) + sleep(1) + self.keyboard.press("Ctrl+Alt+Right") + self.addCleanup(self.keyboard.release, "Ctrl+Alt+Right") + sleep(1) + self.keybinding_hold_part_then_tap("switcher/reveal_normal") + self.addCleanup(self.switcher.terminate) + + self.assertThat(self.switcher.visible, Eventually(Equals(False))) diff --git a/tests/data/no-icon.desktop b/tests/data/no-icon.desktop new file mode 100644 index 000000000..4f2902fe2 --- /dev/null +++ b/tests/data/no-icon.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=Default +Comment=Interactive viewer for a Default icon! +Exec=gedit +Terminal=false +Type=Application +Categories=GTK;Science;Graphics; diff --git a/tests/gmockvolume.c b/tests/gmockvolume.c new file mode 100644 index 000000000..5ee2d23a1 --- /dev/null +++ b/tests/gmockvolume.c @@ -0,0 +1,176 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright 2012 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#include <glib.h> + +#include "gmockvolume.h" + +static void g_mock_volume_volume_iface_init (GVolumeIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GMockVolume, g_mock_volume, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, + g_mock_volume_volume_iface_init)) + +static void +g_mock_volume_finalize (GObject *object) +{ + G_OBJECT_CLASS (g_mock_volume_parent_class)->finalize (object); +} + +static void +g_mock_volume_class_init (GMockVolumeClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_mock_volume_finalize; +} + +static void +g_mock_volume_init (GMockVolume *mock_volume) +{ +} + +GMockVolume * +g_mock_volume_new () +{ + GMockVolume *volume; + + volume = g_object_new (G_TYPE_MOCK_VOLUME, NULL); + + return volume; +} + +static char * +g_mock_volume_get_name (GVolume *volume) +{ + return g_strdup (""); +} + +static GIcon * +g_mock_volume_get_icon (GVolume *volume) +{ + return g_icon_new_for_string("", NULL); +} + +static char * +g_mock_volume_get_uuid (GVolume *volume) +{ + return NULL; +} + +static GDrive * +g_mock_volume_get_drive (GVolume *volume) +{ + return NULL; +} + +static GMount * +g_mock_volume_get_mount (GVolume *volume) +{ + return NULL; +} + +static gboolean +g_mock_volume_can_mount (GVolume *volume) +{ + return TRUE; +} + +static gboolean +g_mock_volume_can_eject (GVolume *volume) +{ + return FALSE; +} + +static gboolean +g_mock_volume_should_automount (GVolume *volume) +{ + return TRUE; +} + +static void +g_mock_volume_mount (GVolume *volume, + GMountMountFlags flags, + GMountOperation *mount_operation, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ +} + +static gboolean +g_mock_volume_mount_finish (GVolume *volume, + GAsyncResult *result, + GError **error) +{ + return TRUE; +} + +static void +g_mock_volume_eject (GVolume *volume, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ +} + +static gboolean +g_mock_volume_eject_finish (GVolume *volume, + GAsyncResult *result, + GError **error) +{ + return TRUE; +} + +static gchar * +g_mock_volume_get_identifier (GVolume *volume, + const gchar *kind) +{ + return NULL; +} + +static gchar ** +g_mock_volume_enumerate_identifiers (GVolume *volume) +{ + return NULL; +} + +static void +g_mock_volume_volume_iface_init (GVolumeIface *iface) +{ + iface->get_name = g_mock_volume_get_name; + iface->get_icon = g_mock_volume_get_icon; + iface->get_uuid = g_mock_volume_get_uuid; + iface->get_drive = g_mock_volume_get_drive; + iface->get_mount = g_mock_volume_get_mount; + iface->can_mount = g_mock_volume_can_mount; + iface->can_eject = g_mock_volume_can_eject; + iface->should_automount = g_mock_volume_should_automount; + iface->mount_fn = g_mock_volume_mount; + iface->mount_finish = g_mock_volume_mount_finish; + iface->eject = g_mock_volume_eject; + iface->eject_finish = g_mock_volume_eject_finish; + iface->get_identifier = g_mock_volume_get_identifier; + iface->enumerate_identifiers = g_mock_volume_enumerate_identifiers; +} + diff --git a/tests/gmockvolume.h b/tests/gmockvolume.h new file mode 100644 index 000000000..0c9ee118a --- /dev/null +++ b/tests/gmockvolume.h @@ -0,0 +1,53 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright 2012 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#ifndef UNITYSHELL_G_MOCK_VOLUME_H +#define UNITYSHELL_G_MOCK_VOLUME_H + +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define G_TYPE_MOCK_VOLUME (g_mock_volume_get_type ()) +#define G_MOCK_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_MOCK_VOLUME, GMockVolume)) +#define G_MOCK_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_MOCK_VOLUME, GMockVolumeClass)) +#define G_IS_MOCK_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_MOCK_VOLUME)) +#define G_IS_MOCK_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_MOCK_VOLUME)) + +typedef struct _GMockVolume GMockVolume; +typedef struct _GMockVolumeClass GMockVolumeClass; + +struct _GMockVolume { + GObject parent; +}; + +struct _GMockVolumeClass { + GObjectClass parent_class; +}; + +GType g_mock_volume_get_type (void) G_GNUC_CONST; +GMockVolume * g_mock_volume_new (); + +G_END_DECLS + +#endif // UNITYSHELL_G_MOCK_VOLUME_H + diff --git a/tests/test-gesture-engine/CMakeLists.txt b/tests/test-gesture-engine/CMakeLists.txt deleted file mode 100644 index 49596e152..000000000 --- a/tests/test-gesture-engine/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -if (GTEST_SRC_DIR) - set(UNITY_SRC ${CMAKE_SOURCE_DIR}/plugins/unityshell/src) - - add_custom_command(OUTPUT GestureEngine.cpp GestureEngine.h UBusMessages.h - COMMAND cp ${UNITY_SRC}/GestureEngine.cpp ${UNITY_SRC}/GestureEngine.h ${CMAKE_SOURCE_DIR}/unity-shared//UBusMessages.h ${CMAKE_CURRENT_BINARY_DIR} - COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script ${UNITY_SRC}/GestureEngine.cpp > ${CMAKE_CURRENT_BINARY_DIR}/GestureEngine.cpp - COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script ${UNITY_SRC}/GestureEngine.h > ${CMAKE_CURRENT_BINARY_DIR}/GestureEngine.h - DEPENDS ${UNITY_SRC}/GestureEngine.cpp ${UNITY_SRC}/GestureEngine.h ${CMAKE_SOURCE_DIR}/unity-shared/UBusMessages.h - COMMENT "Copying GestureEngine source.") - - # Clean-up includes and definitions made in ../CmakeLists.txt - remove_definitions(${CFLAGS}) - set_directory_properties(PROPERTY INCLUDE_DIRECTORIES "") - # And make our own - pkg_check_modules (TEST_GESTURE_ENGINE_DEPS REQUIRED QUIET "${UNITY_PLUGIN_DEPS}") - set(TEST_GESTURE_ENGINE_CFLAGS - "-g" - "-I${CMAKE_CURRENT_SOURCE_DIR}" - "-I${CMAKE_CURRENT_BINARY_DIR}" - ${TEST_GESTURE_ENGINE_DEPS_CFLAGS} - ) - add_definitions(${TEST_GESTURE_ENGINE_CFLAGS}) - - pkg_check_modules (COMPIZ REQUIRED QUIET compiz) - link_directories (${COMPIZ_LIBDIR}) - - add_executable(test-gesture-engine - test_gesture_engine.cpp - X11_mock.cpp - GestureEngine.cpp - PluginAdapterMock.cpp - GeisAdapterMock.cpp - ubus-server-mock.cpp - ) - target_link_libraries(test-gesture-engine gtest ${TEST_GESTURE_ENGINE_DEPS_LIBRARIES} -lcompiz_core) - add_test(UnityGTestGestureEngine test-gesture-engine) - add_dependencies(test-gesture-engine gtest unity-core-${UNITY_API_VERSION}) - - add_custom_target (check-gesture-engine COMMAND ./test-gesture-engine DEPENDS test-gesture-engine) -endif (GTEST_SRC_DIR) diff --git a/tests/test-gesture-engine/GeisAdapterMock.cpp b/tests/test-gesture-engine/GeisAdapterMock.cpp deleted file mode 100644 index 2d4355a21..000000000 --- a/tests/test-gesture-engine/GeisAdapterMock.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY 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 - * version 3 along with this program. If not, see - * <http://www.gnu.org/licenses/> - * - * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> - * - */ - -#include "GeisAdapterMock.h" - -GeisAdapterMock *GeisAdapterMock::_default = nullptr; - -GeisAdapterMock& GeisAdapterMock::Instance() { - if (!_default) - { - _default = new GeisAdapterMock; - } - return *_default; -} diff --git a/tests/test-gesture-engine/GeisAdapterMock.h b/tests/test-gesture-engine/GeisAdapterMock.h deleted file mode 100644 index c4237a0a8..000000000 --- a/tests/test-gesture-engine/GeisAdapterMock.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY 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 - * version 3 along with this program. If not, see - * <http://www.gnu.org/licenses/> - * - * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> - * - */ - -#ifndef GEISADAPTER_MOCK_H -#define GEISADAPTER_MOCK_H - -#include <sigc++/sigc++.h> -#include <X11/Xlib.h> - -class GeisAdapterMock : public sigc::trackable -{ -public: - static GeisAdapterMock& Instance(); - - ~GeisAdapterMock() {} - - typedef struct _GeisTapData - { - int id; - int device_id; - Window window; - int touches; - int timestamp; - float focus_x; - float focus_y; - int tap_length_ms; - float position_x; - float position_y; - float bound_x1; - float bound_y1; - float bound_x2; - float bound_y2; - } GeisTapData; - - typedef struct _GeisDragData - { - int id; - int device_id; - Window window; - int touches; - int timestamp; - float focus_x; - float focus_y; - float delta_x; - float delta_y; - float velocity_x; - float velocity_y; - float position_x; - float position_y; - float bound_x1; - float bound_y1; - float bound_x2; - float bound_y2; - } GeisDragData; - - typedef struct _GeisRotateData - { - int id; - int device_id; - Window window; - int touches; - int timestamp; - float focus_x; - float focus_y; - float angle; - float angle_delta; - float angle_velocity; - float bound_x1; - float bound_y1; - float bound_x2; - float bound_y2; - } GeisRotateData; - - typedef struct _GeisPinchData - { - int id; - int device_id; - Window window; - int touches; - int timestamp; - float focus_x; - float focus_y; - float radius; - float radius_delta; - float radius_velocity; - float bound_x1; - float bound_y1; - float bound_x2; - float bound_y2; - } GeisPinchData; - - typedef struct _GeisTouchData - { - int id; - int device_id; - Window window; - int touches; - int timestamp; - float focus_x; - float focus_y; - float bound_x1; - float bound_y1; - float bound_x2; - float bound_y2; - } GeisTouchData; - - sigc::signal<void, GeisTapData*> tap; - - sigc::signal<void, GeisDragData*> drag_start; - sigc::signal<void, GeisDragData*> drag_update; - sigc::signal<void, GeisDragData*> drag_finish; - - sigc::signal<void, GeisRotateData*> rotate_start; - sigc::signal<void, GeisRotateData*> rotate_update; - sigc::signal<void, GeisRotateData*> rotate_finish; - - sigc::signal<void, GeisPinchData*> pinch_start; - sigc::signal<void, GeisPinchData*> pinch_update; - sigc::signal<void, GeisPinchData*> pinch_finish; - - sigc::signal<void, GeisTouchData*> touch_start; - sigc::signal<void, GeisTouchData*> touch_update; - sigc::signal<void, GeisTouchData*> touch_finish; - -private: - GeisAdapterMock() {} - - static GeisAdapterMock* _default; - -}; -#endif diff --git a/tests/test-gesture-engine/test_gesture_engine.cpp b/tests/test-gesture-engine/test_gesture_engine.cpp deleted file mode 100644 index 1c009bd55..000000000 --- a/tests/test-gesture-engine/test_gesture_engine.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY 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 - * version 3 along with this program. If not, see - * <http://www.gnu.org/licenses/> - * - * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> - * - */ - -#include <gtest/gtest.h> -#include <compiz_mock/core/core.h> -#include "GestureEngine.h" - -CompScreenMock concrete_screen_mock; -CompScreenMock *screen_mock = &concrete_screen_mock; -int pointerX_mock = 0; -int pointerY_mock = 0; - -class GestureEngineTest : public ::testing::Test { - protected: - virtual void SetUp() { - screen_mock->_width = 1280; - screen_mock->_height = 1024; - - GenerateWindows(); - } - - void PerformPinch(GestureEngine &gesture_engine, float peak_radius) { - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - GeisAdapterMock::GeisTouchData touch_data; - touch_data.id = 1; - touch_data.touches = 3; - touch_data.window = 123; - touch_data.focus_x = 100; /* hits the middle window */ - touch_data.focus_y = 100; - gesture_engine.OnTouchStart(&touch_data); - - GeisAdapterMock::GeisPinchData pinch_data; - pinch_data.id = 1; - pinch_data.touches = 3; - pinch_data.window = 123; - pinch_data.focus_x = 100; /* hits the middle window */ - pinch_data.focus_y = 100; - pinch_data.radius = 1.0; - gesture_engine.OnPinchStart(&pinch_data); - - touch_data.focus_x += 10; - touch_data.focus_y += 20; - gesture_engine.OnTouchUpdate(&touch_data); - - pinch_data.focus_x += 10; - pinch_data.focus_y += 20; - pinch_data.radius = peak_radius; - gesture_engine.OnPinchUpdate(&pinch_data); - - gesture_engine.OnTouchFinish(&touch_data); - gesture_engine.OnPinchFinish(&pinch_data); - } - - private: - void GenerateWindows() { - /* remove windows from previous test */ - for (auto window : screen_mock->_client_list_stacking) { - delete window; - } - screen_mock->_client_list_stacking.clear(); - - /* and generate new ones */ - CompWindowMock *window; - - /* the root window */ - window = new CompWindowMock; - /* x, y, width, height, border */ - window->_geometry.set(0, 0, screen_mock->width(), screen_mock->height(), 0); - window->_serverGeometry = window->_geometry; - window->_actions = 0; - window->_state = 0; - screen_mock->_client_list_stacking.push_back(window); - - /* middle window */ - window = new CompWindowMock; - window->_geometry.set(10, 10, 400, 400, 0); - window->_serverGeometry = window->_geometry; - window->_actions = CompWindowActionMoveMask; - window->_state = 0; - screen_mock->_client_list_stacking.push_back(window); - - /* top-level window */ - window = new CompWindowMock; - window->_geometry.set(500, 500, 410, 410, 0); - window->_serverGeometry = window->_geometry; - window->_actions = CompWindowActionMoveMask; - window->_state = 0; - screen_mock->_client_list_stacking.push_back(window); - - screen_mock->_client_list = screen_mock->_client_list_stacking; - std::reverse(screen_mock->_client_list.begin(), - screen_mock->_client_list.end()); - } -}; - -TEST_F(GestureEngineTest, ThreeFingersDragMovesWindow) -{ - GestureEngine gestureEngine(screen_mock); - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - GeisAdapterMock::GeisTouchData touch_data; - touch_data.id = 1; - touch_data.touches = 3; - touch_data.window = 123; - touch_data.focus_x = 100; /* hits the middle window */ - touch_data.focus_y = 100; - gestureEngine.OnTouchStart(&touch_data); - - GeisAdapterMock::GeisDragData drag_data; - drag_data.id = 1; - drag_data.touches = 3; - drag_data.window = 123; - drag_data.focus_x = 100; /* hits the middle window */ - drag_data.focus_y = 100; - gestureEngine.OnDragStart(&drag_data); - - ASSERT_FALSE(middle_window->_moved); - - touch_data.focus_x += 10; - touch_data.focus_y += 20; - gestureEngine.OnTouchUpdate(&touch_data); - - drag_data.delta_x = 10; - drag_data.delta_y = 20; - drag_data.focus_x += drag_data.delta_x; - drag_data.focus_y += drag_data.delta_x; - gestureEngine.OnDragUpdate(&drag_data); - - ASSERT_TRUE(middle_window->_moved); - ASSERT_EQ(drag_data.delta_x, middle_window->_movement_x); - ASSERT_EQ(drag_data.delta_y, middle_window->_movement_y); -} - -TEST_F(GestureEngineTest, ThreeFingersDragDoesntMoveStaticWindow) -{ - GestureEngine gestureEngine(screen_mock); - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - /* can't be moved */ - middle_window->_actions = 0; - - GeisAdapterMock::GeisTouchData touch_data; - touch_data.id = 1; - touch_data.touches = 3; - touch_data.window = 123; - touch_data.focus_x = 100; /* hits the middle window */ - touch_data.focus_y = 100; - gestureEngine.OnTouchStart(&touch_data); - - GeisAdapterMock::GeisDragData drag_data; - drag_data.id = 1; - drag_data.touches = 3; - drag_data.window = 123; - drag_data.focus_x = 100; /* hits the middle window */ - drag_data.focus_y = 100; - gestureEngine.OnDragStart(&drag_data); - - ASSERT_FALSE(middle_window->_moved); - - touch_data.focus_x += 10; - touch_data.focus_y += 20; - gestureEngine.OnTouchUpdate(&touch_data); - - drag_data.delta_x = 10; - drag_data.delta_y = 20; - drag_data.focus_x += drag_data.delta_x; - drag_data.focus_y += drag_data.delta_x; - gestureEngine.OnDragUpdate(&drag_data); - - ASSERT_FALSE(middle_window->_moved); -} - -TEST_F(GestureEngineTest, ThreeFingersPinchMaximizesWindow) -{ - GestureEngine gesture_engine(screen_mock); - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - PerformPinch(gesture_engine, 2.0); - - ASSERT_EQ(1, middle_window->_maximize_count); - ASSERT_EQ(MAXIMIZE_STATE, middle_window->_maximize_state); -} - -TEST_F(GestureEngineTest, ThreeFingersPinchRestoresWindow) -{ - GestureEngine gesture_engine(screen_mock); - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - PerformPinch(gesture_engine, 0.3); - - ASSERT_EQ(1, middle_window->_maximize_count); - ASSERT_EQ(0, middle_window->_maximize_state); -} - -TEST_F(GestureEngineTest, MinimalThreeFingersPinchDoesNothing) -{ - GestureEngine gesture_engine(screen_mock); - CompWindowMock *middle_window = screen_mock->_client_list_stacking[1]; - - PerformPinch(gesture_engine, 1.1); - - ASSERT_EQ(0, middle_window->_maximize_count); -} - -/* Regression test for lp:979418, where the grab is not removed if the gesture - * id is 0. */ -TEST_F(GestureEngineTest, DragGrabCheck) -{ - screen_mock->_grab_count = 0; - - GestureEngine gesture_engine(screen_mock); - - GeisAdapterMock::GeisDragData drag_data; - drag_data.id = 0; - drag_data.touches = 3; - drag_data.window = 123; - drag_data.focus_x = 100; /* hits the middle window */ - drag_data.focus_y = 100; - gesture_engine.OnDragStart(&drag_data); - - gesture_engine.OnDragFinish(&drag_data); - - ASSERT_EQ(0, screen_mock->_grab_count); -} - -int main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - - int ret = RUN_ALL_TESTS(); - - return ret; -} diff --git a/tests/test-gestures/CMakeLists.txt b/tests/test-gestures/CMakeLists.txt new file mode 100644 index 000000000..00ef9e450 --- /dev/null +++ b/tests/test-gestures/CMakeLists.txt @@ -0,0 +1,94 @@ +if (GTEST_SRC_DIR) + set(UNITY_SRC ${CMAKE_SOURCE_DIR}/plugins/unityshell/src) + + add_custom_command(OUTPUT CompoundGestureRecognizer.cpp + CompoundGestureRecognizer.h + GesturalWindowSwitcher.cpp + GesturalWindowSwitcher.h + UnityGestureBroker.cpp + UnityGestureBroker.h + UBusMessages.h + WindowGestureTarget.h + WindowGestureTarget.cpp + + COMMAND cp ${UNITY_SRC}/CompoundGestureRecognizer.cpp + ${UNITY_SRC}/CompoundGestureRecognizer.h + ${CMAKE_CURRENT_BINARY_DIR} + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_broker + ${UNITY_SRC}/UnityGestureBroker.cpp > + ${CMAKE_CURRENT_BINARY_DIR}/UnityGestureBroker.cpp + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_broker + ${UNITY_SRC}/UnityGestureBroker.h > + ${CMAKE_CURRENT_BINARY_DIR}/UnityGestureBroker.h + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_gesture + ${UNITY_SRC}/WindowGestureTarget.h > + ${CMAKE_CURRENT_BINARY_DIR}/WindowGestureTarget.h + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_gesture + ${UNITY_SRC}/WindowGestureTarget.cpp > + ${CMAKE_CURRENT_BINARY_DIR}/WindowGestureTarget.cpp + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_switcher + ${UNITY_SRC}/GesturalWindowSwitcher.cpp > + ${CMAKE_CURRENT_BINARY_DIR}/GesturalWindowSwitcher.cpp + + COMMAND sed -f ${CMAKE_CURRENT_SOURCE_DIR}/sed_script_switcher + ${UNITY_SRC}/GesturalWindowSwitcher.h > + ${CMAKE_CURRENT_BINARY_DIR}/GesturalWindowSwitcher.h + + DEPENDS ${UNITY_SRC}/CompoundGestureRecognizer.cpp + ${UNITY_SRC}/CompoundGestureRecognizer.h + ${UNITY_SRC}/GesturalWindowSwitcher.cpp + ${UNITY_SRC}/GesturalWindowSwitcher.h + ${UNITY_SRC}/UnityGestureBroker.cpp + ${UNITY_SRC}/UnityGestureBroker.h + ${CMAKE_SOURCE_DIR}/unity-shared/UBusMessages.h + ${UNITY_SRC}/WindowGestureTarget.h + ${UNITY_SRC}/WindowGestureTarget.cpp + sed_script_broker + sed_script_gesture + + COMMENT "Copying and modifying sources under test.") + + # Clean-up includes and definitions made in ../CmakeLists.txt + remove_definitions(${CFLAGS}) + set_directory_properties(PROPERTY INCLUDE_DIRECTORIES "") + # And make our own + pkg_check_modules (TEST_GESTURES_DEPS REQUIRED QUIET "${UNITY_PLUGIN_DEPS}") + set(TEST_GESTURES_CFLAGS + "-g" + "-I${CMAKE_CURRENT_SOURCE_DIR}" + "-I${CMAKE_CURRENT_BINARY_DIR}" + ${TEST_GESTURES_DEPS_CFLAGS} + ) + add_definitions(${TEST_GESTURES_CFLAGS}) + + pkg_check_modules (COMPIZ REQUIRED QUIET compiz) + link_directories (${COMPIZ_LIBDIR}) + + add_executable(test-gestures + CompoundGestureRecognizer.cpp + CompoundGestureRecognizer.h + GesturalWindowSwitcher.cpp + GesturalWindowSwitcher.h + test_compound_gesture_recognizer.cpp + test_gestural_window_switcher.cpp + test_gestures_main.cpp + test_gesture_broker.cpp + test_window_gesture_target.cpp + X11_mock.cpp + UnityGestureBroker.cpp + WindowGestureTarget.cpp + PluginAdapterMock.cpp + ubus-server-mock.cpp + UnityGestureTargetMock.h + ) + target_link_libraries(test-gestures gtest ${TEST_GESTURES_DEPS_LIBRARIES} -lcompiz_core) + add_test(UnityGTestGestures test-gestures) + add_dependencies(test-gestures gtest unity-core-${UNITY_API_VERSION}) + + add_custom_target (check-gestures COMMAND ./test-gestures DEPENDS test-gestures) +endif (GTEST_SRC_DIR) diff --git a/tests/test-gestures/FakeGestureEvent.h b/tests/test-gestures/FakeGestureEvent.h new file mode 100644 index 000000000..9cc13aa76 --- /dev/null +++ b/tests/test-gestures/FakeGestureEvent.h @@ -0,0 +1,63 @@ +#ifndef FAKE_GESTURE_EVENT_H +#define FAKE_GESTURE_EVENT_H + +#include <NuxGraphics/GestureEvent.h> +#include <map> + +namespace nux { +class FakeGestureEvent +{ + public: + nux::EventType type; + + int gesture_id; + int gesture_classes; + bool is_direct_touch; + int timestamp; + nux::Point2D<float> focus; + nux::Point2D<float> delta; + float angle; + float angle_delta; + float angular_velocity; + int tap_duration; + nux::Point2D<float> velocity; + float radius; + float radius_delta; + float radial_velocity; + std::vector<nux::TouchPoint> touches; + bool is_construction_finished; + + nux::GestureEvent &ToGestureEvent() + { + event_.type = type; + + event_.gesture_id_ = gesture_id; + event_.gesture_classes_ = gesture_classes; + event_.is_direct_touch_ = is_direct_touch; + event_.timestamp_ = timestamp; + event_.focus_ = focus; + event_.delta_ = delta; + event_.angle_ = angle; + event_.angle_delta_ = angle_delta; + event_.angular_velocity_ = angular_velocity; + event_.tap_duration_ = tap_duration; + event_.velocity_ = velocity; + event_.radius_ = radius; + event_.radius_delta_ = radius_delta; + event_.radial_velocity_ = radial_velocity; + event_.touches_ = touches; + event_.is_construction_finished_ = is_construction_finished; + + return event_; + } + + private: + nux::GestureEvent event_; +}; +} // namespace nux + +// maps a gesture id to its acceptance +extern std::map<int, int> g_gesture_event_accept_count; +extern std::map<int, int> g_gesture_event_reject_count; + +#endif // FAKE_GESTURE_EVENT_H diff --git a/tests/test-gestures/GesturalWindowSwitcherMock.h b/tests/test-gestures/GesturalWindowSwitcherMock.h new file mode 100644 index 000000000..b21a2f7b6 --- /dev/null +++ b/tests/test-gestures/GesturalWindowSwitcherMock.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#ifndef GESTURAL_WINDOW_SWITCHER_MOCK_H +#define GESTURAL_WINDOW_SWITCHER_MOCK_H + +#include <Nux/Gesture.h> + +namespace unity +{ + +class GesturalWindowSwitcherMock : public nux::GestureTarget +{ + public: + GesturalWindowSwitcherMock() {} + + virtual nux::GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event) + { + return nux::GestureDeliveryRequest::NONE; + } +}; +typedef std::shared_ptr<GesturalWindowSwitcherMock> ShPtGesturalWindowSwitcherMock; + +} //namespace unity +#endif // GESTURAL_WINDOW_SWITCHER_MOCK_H diff --git a/tests/test-gestures/NuxMock.h b/tests/test-gestures/NuxMock.h new file mode 100644 index 000000000..4ae586655 --- /dev/null +++ b/tests/test-gestures/NuxMock.h @@ -0,0 +1,27 @@ +#ifndef NUX_MOCK_H +#define NUX_MOCK_H + +#include <Nux/Nux.h> + +namespace nux +{ + +class InputAreaMock : public Object +{ + public: + void GestureEvent(const GestureEvent &event) + { + } +}; + +class ViewMock : public InputAreaMock +{ + public: + sigc::signal<void, int, int, unsigned long, unsigned long> mouse_down; + sigc::signal<void, int, int, unsigned long, unsigned long> mouse_up; + sigc::signal<void, int, int, int, int, unsigned long, unsigned long> mouse_drag; +}; + +} // namespace nux + +#endif // NUX_MOCK_H diff --git a/tests/test-gesture-engine/PluginAdapterMock.cpp b/tests/test-gestures/PluginAdapterMock.cpp index a71af2421..a71af2421 100644 --- a/tests/test-gesture-engine/PluginAdapterMock.cpp +++ b/tests/test-gestures/PluginAdapterMock.cpp diff --git a/tests/test-gesture-engine/PluginAdapterMock.h b/tests/test-gestures/PluginAdapterMock.h index 2b111a68b..2b111a68b 100644 --- a/tests/test-gesture-engine/PluginAdapterMock.h +++ b/tests/test-gestures/PluginAdapterMock.h diff --git a/tests/test-gestures/SwitcherControllerMock.h b/tests/test-gestures/SwitcherControllerMock.h new file mode 100644 index 000000000..9c14a8ee7 --- /dev/null +++ b/tests/test-gestures/SwitcherControllerMock.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#ifndef SWITCHER_CONTROLLER_MOCK_H +#define SWITCHER_CONTROLLER_MOCK_H + +#include "NuxMock.h" + +namespace unity { +namespace switcher { + +class SwitcherViewMock : public nux::ViewMock +{ +public: + int IconIndexAt(int x, int y) + { + return x*y; + } +}; + +class ControllerMock +{ +public: + ControllerMock() + { + Reset(); + } + + void Reset() + { + is_visible_ = false; + prev_count_ = 0; + next_count_ = 0; + index_selected_ = -1; + } + + typedef std::shared_ptr<ControllerMock> Ptr; + + sigc::signal<void> view_built; + + void Next() + { + ++next_count_; + } + + void Prev() + { + ++prev_count_; + } + + void Select(int index) + { + index_selected_ = index; + } + + bool Visible() + { + return is_visible_; + } + + void Hide() + { + is_visible_ = false; + } + + SwitcherViewMock *GetView() + { + return &view_; + } + + bool is_visible_; + SwitcherViewMock view_; + int prev_count_; + int next_count_; + int index_selected_; +}; + +} // namespace switcher +} // namespace unity + + +#endif // SWITCHER_CONTROLLER_MOCK_H diff --git a/tests/test-gestures/UnityGestureTargetMock.h b/tests/test-gestures/UnityGestureTargetMock.h new file mode 100644 index 000000000..9fd621fb8 --- /dev/null +++ b/tests/test-gestures/UnityGestureTargetMock.h @@ -0,0 +1,15 @@ +#ifndef UNITY_GESTURE_TARGET_MOCK_H +#define UNITY_GESTURE_TARGET_MOCK_H + +#include <Nux/Gesture.h> + +class UnityGestureTargetMock : public nux::GestureTarget +{ + public: + virtual nux::GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event) + { + return nux::GestureDeliveryRequest::NONE; + } +}; + +#endif // UNITY_GESTURE_TARGET_MOCK_H diff --git a/tests/test-gestures/WindowGestureTargetMock.h b/tests/test-gestures/WindowGestureTargetMock.h new file mode 100644 index 000000000..e43bad80c --- /dev/null +++ b/tests/test-gestures/WindowGestureTargetMock.h @@ -0,0 +1,55 @@ +#ifndef WINDOW_GESTURE_TARGET_MOCK_H +#define WINDOW_GESTURE_TARGET_MOCK_H + +#include <Nux/Gesture.h> + +#include <set> + +class CompWindowMock; +class WindowGestureTargetMock; + +extern std::set<WindowGestureTargetMock*> g_window_target_mocks; + +class WindowGestureTargetMock : public nux::GestureTarget +{ + public: + WindowGestureTargetMock(CompWindowMock *window) : window(window) + { + g_window_target_mocks.insert(this); + } + + virtual ~WindowGestureTargetMock() + { + g_window_target_mocks.erase(this); + } + + virtual nux::GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event) + { + events_received.push_back(event); + return nux::GestureDeliveryRequest::NONE; + } + + CompWindowMock *window; + std::list<nux::GestureEvent> events_received; + + static Cursor fleur_cursor; + private: + virtual bool Equals(const nux::GestureTarget& other) const + { + const WindowGestureTargetMock *window_target = dynamic_cast<const WindowGestureTargetMock *>(&other); + + if (window_target) + { + if (window && window_target->window) + return window->id() == window_target->window->id(); + else + return window == window_target->window; + } + else + { + return false; + } + } +}; + +#endif // WINDOW_GESTURE_TARGET_MOCK_H diff --git a/tests/test-gesture-engine/X11_mock.cpp b/tests/test-gestures/X11_mock.cpp index 5560aa9ac..5560aa9ac 100644 --- a/tests/test-gesture-engine/X11_mock.cpp +++ b/tests/test-gestures/X11_mock.cpp diff --git a/tests/test-gesture-engine/X11_mock.h b/tests/test-gestures/X11_mock.h index f98e028be..f98e028be 100644 --- a/tests/test-gesture-engine/X11_mock.h +++ b/tests/test-gestures/X11_mock.h diff --git a/tests/test-gesture-engine/compiz_mock/core/core.h b/tests/test-gestures/compiz_mock/core/core.h index f1c358fbf..f1c358fbf 100644 --- a/tests/test-gesture-engine/compiz_mock/core/core.h +++ b/tests/test-gestures/compiz_mock/core/core.h diff --git a/tests/test-gesture-engine/compiz_mock/core/screen.h b/tests/test-gestures/compiz_mock/core/screen.h index 38795db15..225d41c65 100644 --- a/tests/test-gesture-engine/compiz_mock/core/screen.h +++ b/tests/test-gestures/compiz_mock/core/screen.h @@ -31,41 +31,42 @@ typedef std::vector<CompWindowMock*> CompWindowMockVector; class CompScreenMock { public: - CompScreenMock() : _grab_count(0) {} + CompScreenMock() : grab_count_(0), next_grab_handle_(1) {} typedef int GrabHandle; - int width() const {return _width;} - int height() const {return _height;} + int width() const {return width_;} + int height() const {return height_;} - Display *dpy() {return _dpy;} + Display *dpy() {return dpy_;} const CompWindowMockVector & clientList(bool stackingOrder = true) { if (stackingOrder) - return _client_list_stacking; + return client_list_stacking_; else - return _client_list; + return client_list_; } - Window root() {return _root;} + Window root() {return root_;} GrabHandle pushGrab(Cursor cursor, const char *name) { - _grab_count++; - return 0; + grab_count_++; + return next_grab_handle_++; } void removeGrab(GrabHandle handle, CompPoint *restorePointer) { - _grab_count--; + grab_count_--; } Cursor invisibleCursor() {return 1;} - int _width; - int _height; - Display *_dpy; - CompWindowMockVector _client_list; - CompWindowMockVector _client_list_stacking; - Window _root; - int _grab_count; + int width_; + int height_; + Display *dpy_; + CompWindowMockVector client_list_; + CompWindowMockVector client_list_stacking_; + Window root_; + int grab_count_; + int next_grab_handle_; }; extern CompScreenMock *screen_mock; diff --git a/tests/test-gestures/compiz_mock/core/timer.h b/tests/test-gestures/compiz_mock/core/timer.h new file mode 100644 index 000000000..2452da7dc --- /dev/null +++ b/tests/test-gestures/compiz_mock/core/timer.h @@ -0,0 +1,79 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + * + */ + +#ifndef COMPIZ_TIMER_MOCK_H +#define COMPIZ_TIMER_MOCK_H + +#include <boost/function.hpp> + +class CompTimerMock +{ + public: + typedef boost::function<bool ()> CallBack; + + CompTimerMock() + { + is_running = false; + callback = NULL; + + // OBS: no support for more than one simultaneous timer + instance = this; + } + + virtual ~CompTimerMock() + { + instance = nullptr; + } + + void setCallback (CallBack callback) + { + this->callback = callback; + } + + void setTimes(unsigned int min, unsigned int max = 0) + { + } + + void start() + { + is_running = true; + } + + void stop() + { + is_running = false; + } + + void ForceTimeout() + { + if (is_running && callback) + { + callback(); + is_running = false; + } + } + + CallBack callback; + bool is_running; + + static CompTimerMock *instance; +}; + +#endif // COMPIZ_TIMER_MOCK_H diff --git a/tests/test-gesture-engine/compiz_mock/core/window.h b/tests/test-gestures/compiz_mock/core/window.h index d65524b7d..f5e930107 100644 --- a/tests/test-gesture-engine/compiz_mock/core/window.h +++ b/tests/test-gestures/compiz_mock/core/window.h @@ -24,46 +24,56 @@ /* The real CompWindow */ #include <core/window.h> -class CompWindowMock { +class CompWindowMock +{ public: - CompWindowMock() : _moved(false), _maximize_count(0), _maximize_state(0) {} + CompWindowMock() : moved_(false), maximize_count_(0), maximize_state_(0), + minimized_(false) {} - int x() const {return _geometry.x();} - int y() const {return _geometry.y();} - int width() const {return _geometry.width() + (_geometry.border()*2);} - int height() const {return _geometry.height() + (_geometry.border()*2);} + int x() const {return geometry_.x();} + int y() const {return geometry_.y();} + int width() const {return geometry_.width() + (geometry_.border()*2);} + int height() const {return geometry_.height() + (geometry_.border()*2);} + int id() { return id_; } - void move(int dx, int dy, bool immediate = true) { - _moved = true; - _movement_x = dx; - _movement_y = dy; + void move(int dx, int dy, bool immediate = true) + { + moved_ = true; + movement_x_ = dx; + movement_y_ = dy; } - unsigned int actions () {return _actions;} + unsigned int actions () {return actions_;} - void maximize(int state) {++_maximize_count; _maximize_state = state;} + bool minimized() { return minimized_; } + + void maximize(int state) {++maximize_count_; maximize_state_ = state;} /* OBS: I wonder why it returns a reference */ - unsigned int &state() {return _state;} + unsigned int &state() {return state_;} void grabNotify(int x, int y, unsigned int state, unsigned int mask) {} void ungrabNotify() {} void syncPosition() {} - compiz::window::Geometry &serverGeometry() {return _serverGeometry;} + compiz::window::Geometry &serverGeometry() {return server_geometry_;} + + unsigned int actions_; + unsigned int state_; + compiz::window::Geometry server_geometry_; + compiz::window::Geometry geometry_; + + bool moved_; + int movement_x_; + int movement_y_; - unsigned int _actions; - unsigned int _state; - compiz::window::Geometry _serverGeometry; - compiz::window::Geometry _geometry; + int maximize_count_; + int maximize_state_; - bool _moved; - int _movement_x; - int _movement_y; + int id_; - int _maximize_count; - int _maximize_state; + bool minimized_; }; #endif diff --git a/tests/test-gestures/sed_script_broker b/tests/test-gestures/sed_script_broker new file mode 100644 index 000000000..626f8f244 --- /dev/null +++ b/tests/test-gestures/sed_script_broker @@ -0,0 +1,12 @@ +s|<core/core.h>|<compiz_mock/core/core.h>| +s|\<CompScreen\>|CompScreenMock|g +s|\<CompWindow\>|CompWindowMock|g +s|\<CompWindowVector\>|CompWindowMockVector|g +s|\<screen\>|screen_mock|g +s|\<pointerX\>|pointerX_mock|g +s|\<pointerY\>|pointerY_mock|g +s|\<XFreeCursor\>|XFreeCursorMock|g +s|\<XCreateFontCursor\>|XCreateFontCursorMock|g +s|\<WindowGestureTarget\>|WindowGestureTargetMock|g +s|\<UnityGestureTarget\>|UnityGestureTargetMock|g +s|GesturalWindowSwitcher|GesturalWindowSwitcherMock|g diff --git a/tests/test-gesture-engine/sed_script b/tests/test-gestures/sed_script_gesture index 94fb691f6..c2e3ffa48 100644 --- a/tests/test-gesture-engine/sed_script +++ b/tests/test-gestures/sed_script_gesture @@ -9,6 +9,10 @@ s|\<XSync\>|XSyncMock|g s|\<XWarpPointer\>|XWarpPointerMock|g s|\<XFreeCursor\>|XFreeCursorMock|g s|\<XCreateFontCursor\>|XCreateFontCursorMock|g -s|\<GeisAdapter\>|GeisAdapterMock|g -s|\<PluginAdapter\>|PluginAdapterMock|g s|\<ubus-server.h\>|ubus-server-mock.h|g +s|\<unityshell.h\>|unityshell_mock.h|g +s|\<PluginAdapter\>|PluginAdapterMock|g +s|\<UnityWindow\>|UnityWindowMock|g +s|\<UnityScreen\>|UnityScreenMock|g +s|\<InputArea\>|InputAreaMock|g +s|\<Nux/Nux\.h\>|NuxMock.h|g diff --git a/tests/test-gestures/sed_script_switcher b/tests/test-gestures/sed_script_switcher new file mode 100644 index 000000000..8deb1b585 --- /dev/null +++ b/tests/test-gestures/sed_script_switcher @@ -0,0 +1,25 @@ +s|<core/core.h>|<compiz_mock/core/core.h>| +s|<core/timer.h>|<compiz_mock/core/timer.h>| +s|\<CompScreen\>|CompScreenMock|g +s|\<CompWindow\>|CompWindowMock|g +s|\<CompWindowVector\>|CompWindowMockVector|g +s|\<screen\>|screen_mock|g +s|\<pointerX\>|pointerX_mock|g +s|\<pointerY\>|pointerY_mock|g +s|\<XSync\>|XSyncMock|g +s|\<XWarpPointer\>|XWarpPointerMock|g +s|\<XFreeCursor\>|XFreeCursorMock|g +s|\<XCreateFontCursor\>|XCreateFontCursorMock|g +s|\<ubus-server.h\>|ubus-server-mock.h|g +s|\<unityshell.h\>|unityshell_mock.h|g +s|\<PluginAdapter\>|PluginAdapterMock|g +s|\<UnityWindow\>|UnityWindowMock|g +s|\<UnityScreen\>|UnityScreenMock|g +s|\<InputArea\>|InputAreaMock|g +s|\<Nux/Nux\.h\>|NuxMock.h|g +s|\<CompTimer\>|CompTimerMock|g +s|\<LauncherController\>|LauncherControllerMock|g +s|\<SwitcherController\>|SwitcherControllerMock|g +s|\<switcher\:\:Controller\>|switcher\:\:ControllerMock|g +s|\<launcher\:\:Controller\>|launcher\:\:ControllerMock|g +s|\<SwitcherView\>|SwitcherViewMock|g diff --git a/tests/test-gestures/test_compound_gesture_recognizer.cpp b/tests/test-gestures/test_compound_gesture_recognizer.cpp new file mode 100644 index 000000000..56e83a86f --- /dev/null +++ b/tests/test-gestures/test_compound_gesture_recognizer.cpp @@ -0,0 +1,189 @@ +/* + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity 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 of the License, or + * (at your option) any later version. + * + * Unity 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#include <gtest/gtest.h> +#include "CompoundGestureRecognizer.h" +#include "FakeGestureEvent.h" + +using namespace unity; + +class CompoundGestureRecognizerTest : public ::testing::Test +{ + public: + CompoundGestureRecognizerTest() + { + fake_event.gesture_id = 0; + fake_event.timestamp = 12345; // some arbitrary, big value + } + + RecognitionResult PerformTap() + { + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id += 1; + fake_event.gesture_classes = nux::TOUCH_GESTURE; + if (gesture_recognizer.GestureEvent(fake_event.ToGestureEvent()) + != RecognitionResult::NONE) + ADD_FAILURE(); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 0.2 * CompoundGestureRecognizer::MAX_TAP_TIME; + if (gesture_recognizer.GestureEvent(fake_event.ToGestureEvent()) + != RecognitionResult::NONE) + ADD_FAILURE(); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TAP_TIME; + return gesture_recognizer.GestureEvent(fake_event.ToGestureEvent()); + } + + + CompoundGestureRecognizer gesture_recognizer; + nux::FakeGestureEvent fake_event; +}; + +TEST_F(CompoundGestureRecognizerTest, DoubleTap) +{ + // First tap + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Second tap + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::DOUBLE_TAP_RECOGNIZED, PerformTap()); +} + +/* + If too much time passes between two consecutive taps, + it's not considered a double tap + */ +TEST_F(CompoundGestureRecognizerTest, Tap_BigInterval_Tap) +{ + // First tap + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Second tap + fake_event.timestamp += 2 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); +} + +TEST_F(CompoundGestureRecognizerTest, Tap_BigInterval_DoubleTap) +{ + // First tap + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Second tap + fake_event.timestamp += 2 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Third tap + fake_event.timestamp += 0.5 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::DOUBLE_TAP_RECOGNIZED, PerformTap()); +} + +TEST_F(CompoundGestureRecognizerTest, TapAndDrag) +{ + // First tap + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Drag + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 1; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.gesture_classes = nux::TOUCH_GESTURE | nux::DRAG_GESTURE; + fake_event.timestamp += 0.2 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TAP_TIME; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); +} + +TEST_F(CompoundGestureRecognizerTest, TapAndHold) +{ + // Tap + + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Hold + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 1; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 0.2 * CompoundGestureRecognizer::MAX_TAP_TIME; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 1.0 * CompoundGestureRecognizer::HOLD_TIME; + ASSERT_EQ(RecognitionResult::TAP_AND_HOLD_RECOGNIZED, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.3 * CompoundGestureRecognizer::HOLD_TIME; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); +} + +TEST_F(CompoundGestureRecognizerTest, Tap_ShortHold_DoubleTap) +{ + // Tap + + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + // Short hold + // Too long for a tap and too short for a hold. + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 1; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += (CompoundGestureRecognizer::MAX_TAP_TIME + + CompoundGestureRecognizer::HOLD_TIME) / 2; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 1; + ASSERT_EQ(RecognitionResult::NONE, + gesture_recognizer.GestureEvent(fake_event.ToGestureEvent())); + + // Verify that the state machine went back to its initial state + // by checking that a subsequent double tap gets recognized normally + + fake_event.timestamp += 0.5 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::NONE, PerformTap()); + + fake_event.timestamp += 0.5 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + ASSERT_EQ(RecognitionResult::DOUBLE_TAP_RECOGNIZED, PerformTap()); +} diff --git a/tests/test-gestures/test_gestural_window_switcher.cpp b/tests/test-gestures/test_gestural_window_switcher.cpp new file mode 100644 index 000000000..be0586992 --- /dev/null +++ b/tests/test-gestures/test_gestural_window_switcher.cpp @@ -0,0 +1,323 @@ +/* + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity 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 of the License, or + * (at your option) any later version. + * + * Unity 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#include <gtest/gtest.h> +#include "GesturalWindowSwitcher.h" +#include "FakeGestureEvent.h" +#include "unityshell_mock.h" +#include "compiz_mock/core/timer.h" + +using namespace unity; + +class GesturalWindowSwitcherTest: public ::testing::Test +{ + public: + virtual void SetUp() + { + unity_screen = unity::UnityScreenMock::get(screen_mock); + unity_screen->Reset(); + + fake_event.gesture_id = 0; + fake_event.timestamp = 12345; // some arbitrary, big value + + unity_screen->switcher_controller()->view_built.emit(); + } + + void PerformTap() + { + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id += 1; + fake_event.gesture_classes = nux::TOUCH_GESTURE; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 0.2 * CompoundGestureRecognizer::MAX_TAP_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TAP_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + } + + void PerformTapAndHold() + { + PerformTap(); + + // Hold + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id += 1; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 0.2 * CompoundGestureRecognizer::MAX_TAP_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.timestamp += 1.0 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + } + + GesturalWindowSwitcher gestural_switcher; + nux::FakeGestureEvent fake_event; + unity::UnityScreenMock *unity_screen; +}; + +TEST_F(GesturalWindowSwitcherTest, DoubleTapSwitchesWindow) +{ + PerformTap(); + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES; + PerformTap(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // simulate that enough time has passed + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); +} + +TEST_F(GesturalWindowSwitcherTest, TapAndHoldShowsSwitcher) +{ + PerformTapAndHold(); + + // switcher should show up + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // simulate that enough idle time has passed + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + // nothing should change + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // lift fingers. End hold. + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // nothing should change + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // simulate that enough idle time has passed + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + // switcher should finally be closed + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); +} + +TEST_F(GesturalWindowSwitcherTest, TapAndHoldAndDragSelectsNextWindow) +{ + PerformTapAndHold(); + + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // Drag far enough to the right. + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.gesture_classes = nux::TOUCH_GESTURE | nux::DRAG_GESTURE; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = 0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = 0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // Selection should have jumped to the next window + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // Drag far enough to the left. + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = -0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = -0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // Selection should have jumped to the previous window + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // End gesture + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // Switcher should have been closed at once + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->prev_count_); + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); +} + +TEST_F(GesturalWindowSwitcherTest, NewDragAfterTapAndHoldSelectsNextWindow) +{ + PerformTapAndHold(); + + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // End hold gesture + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // Start a new gesture and drag far enough to the right. + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id += 1; + fake_event.gesture_classes = nux::TOUCH_GESTURE; + fake_event.timestamp += 0.6 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.gesture_classes |= nux::DRAG_GESTURE; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = 0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + fake_event.delta.x = 0.6 * GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // switcher should have been closed + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); +} + +TEST_F(GesturalWindowSwitcherTest, ClickAfterTapAndHoldSelectsWindow) +{ + PerformTapAndHold(); + + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // lift fingers. End hold. + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // click on position (12, 23) + unity_screen->switcher_controller()->view_.mouse_down.emit(12, 23, 0, 0); + unity_screen->switcher_controller()->view_.mouse_up.emit(12, 23, 0, 0); + + // Should have selected the icon index corresponding to the + // position clicked. + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + ASSERT_EQ(12*23, unity_screen->switcher_controller()->index_selected_); + + // simulate that enough time has passed + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); +} + +TEST_F(GesturalWindowSwitcherTest, MouseDragAfterTapAndHoldSelectsNextWindow) +{ + unity::switcher::SwitcherViewMock &switcher_view = + unity_screen->switcher_controller()->view_; + int drag_delta = GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION * 1.5f; + + PerformTapAndHold(); + + if (CompTimerMock::instance) + CompTimerMock::instance->ForceTimeout(); + + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_TRUE(unity_screen->switcher_controller()->is_visible_); + + // lift fingers. End hold. + fake_event.type = nux::EVENT_GESTURE_END; + fake_event.timestamp += 0.1 * CompoundGestureRecognizer::HOLD_TIME; + gestural_switcher.GestureEvent(fake_event.ToGestureEvent()); + + // drag right far enough to trigger the selection of the next item + switcher_view.mouse_down.emit(12, 23, 0, 0); + switcher_view.mouse_drag.emit(12 + drag_delta, 23, drag_delta, 0, 0, 0); + switcher_view.mouse_up.emit(12 + drag_delta, 23, 0, 0); + + // Should selected the next icon and close the switcher right away + ASSERT_EQ(1, unity_screen->SetUpAndShowSwitcher_count_); + ASSERT_EQ(1, unity_screen->switcher_controller()->next_count_); + ASSERT_EQ(0, unity_screen->switcher_controller()->prev_count_); + ASSERT_FALSE(unity_screen->switcher_controller()->is_visible_); + ASSERT_EQ(-1, unity_screen->switcher_controller()->index_selected_); +} diff --git a/tests/test-gestures/test_gesture_broker.cpp b/tests/test-gestures/test_gesture_broker.cpp new file mode 100644 index 000000000..b7f30ec04 --- /dev/null +++ b/tests/test-gestures/test_gesture_broker.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + * + */ + +#include <gtest/gtest.h> +#include <compiz_mock/core/core.h> +#include "UnityGestureBroker.h" +#include "FakeGestureEvent.h" +#include "unityshell_mock.h" +#include "WindowGestureTargetMock.h" + +class GestureBrokerTest : public ::testing::Test +{ + protected: + virtual void SetUp() + { + screen_mock->width_ = 1280; + screen_mock->height_ = 1024; + + GenerateWindows(); + } + + private: + void GenerateWindows() + { + /* remove windows from previous test */ + for (auto window : screen_mock->client_list_stacking_) { + delete window; + } + screen_mock->client_list_stacking_.clear(); + + /* and generate new ones */ + CompWindowMock *window; + + /* the root window */ + window = new unity::UnityWindowMock; + window->id_ = 0; + /* x, y, width, height, border */ + window->geometry_.set(0, 0, screen_mock->width(), screen_mock->height(), 0); + window->server_geometry_ = window->geometry_; + window->actions_ = 0; + window->state_ = 0; + screen_mock->client_list_stacking_.push_back(window); + + /* middle window */ + window = new unity::UnityWindowMock; + window->id_ = 1; + window->geometry_.set(10, 10, 400, 400, 0); + window->server_geometry_ = window->geometry_; + window->actions_ = CompWindowActionMoveMask; + window->state_ = 0; + screen_mock->client_list_stacking_.push_back(window); + + /* top-level window */ + window = new unity::UnityWindowMock; + window->id_ = 2; + window->geometry_.set(500, 500, 410, 410, 0); + window->server_geometry_ = window->geometry_; + window->actions_ = CompWindowActionMoveMask; + window->state_ = 0; + screen_mock->client_list_stacking_.push_back(window); + + screen_mock->client_list_ = screen_mock->client_list_stacking_; + std::reverse(screen_mock->client_list_.begin(), + screen_mock->client_list_.end()); + } +}; + +/* + Tests that events from a three-fingers' Touch gesture goes to the + correct window. I.e., to the window that lies where the gesture starts. + */ +TEST_F(GestureBrokerTest, ThreeFingersTouchHitsCorrectWindow) +{ + UnityGestureBroker gesture_broker; + CompWindowMock *middle_window = screen_mock->client_list_stacking_[1]; + nux::FakeGestureEvent fake_event; + + // init counters + g_gesture_event_accept_count[0] = 0; + g_gesture_event_reject_count[0] = 0; + + /* prepare and send the fake event */ + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 0; + fake_event.is_direct_touch = false; + fake_event.focus.x = 100.0f; // hits the middle window + fake_event.focus.y = 100.0f; + // in touch device's coordinate system (because it's not a direct device). + // Thus not used by WindowCompositor + fake_event.touches.push_back(nux::TouchPoint(0, 10.0f, 10.0f)); + fake_event.touches.push_back(nux::TouchPoint(1, 20.0f, 20.0f)); + fake_event.touches.push_back(nux::TouchPoint(2, 22.0f, 22.0f)); + fake_event.is_construction_finished = false; + gesture_broker.ProcessGestureBegin(fake_event.ToGestureEvent()); + + // Gesture shouldn't be accepted as constructions hasn't finished + ASSERT_EQ(0, g_gesture_event_accept_count[0]); + ASSERT_EQ(0, g_gesture_event_reject_count[0]); + ASSERT_EQ(1, g_window_target_mocks.size()); + WindowGestureTargetMock *target_mock = *g_window_target_mocks.begin(); + ASSERT_TRUE(target_mock->window == middle_window); + // No events yet as the broker didn't accept the gesture yet + ASSERT_EQ(0, target_mock->events_received.size()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.delta.x += 10.0f; + fake_event.delta.y += 20.0f; + fake_event.focus.x += fake_event.delta.x; + fake_event.focus.y += fake_event.delta.y; + fake_event.is_construction_finished = true; + gesture_broker.ProcessGestureUpdate(fake_event.ToGestureEvent()); + + // Gesture should have been accepted now since the construction has finished. + ASSERT_EQ(1, g_gesture_event_accept_count[0]); + ASSERT_EQ(0, g_gesture_event_reject_count[0]); + // Check that this gesture target is still valid + ASSERT_EQ(1, g_window_target_mocks.count(target_mock)); + // Gesture events should have been sent to the target by now + ASSERT_EQ(2, target_mock->events_received.size()); +} diff --git a/tests/test-gestures/test_gestures_main.cpp b/tests/test-gestures/test_gestures_main.cpp new file mode 100644 index 000000000..1d99b8a25 --- /dev/null +++ b/tests/test-gestures/test_gestures_main.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + * + */ + +#include <gtest/gtest.h> +#include <compiz_mock/core/core.h> +#include <compiz_mock/core/timer.h> +#include <NuxGraphics/GestureEvent.h> +#include "WindowGestureTargetMock.h" +#include "unityshell_mock.h" + +unity::UnityScreenMock concrete_screen_mock; +CompScreenMock *screen_mock = &concrete_screen_mock; +int pointerX_mock = 0; +int pointerY_mock = 0; + +CompTimerMock *CompTimerMock::instance = nullptr; + +std::map<int, int> g_gesture_event_accept_count; +void nux::GestureEvent::Accept() +{ + g_gesture_event_accept_count[gesture_id_] = + g_gesture_event_accept_count[gesture_id_] + 1; +} + +std::map<int, int> g_gesture_event_reject_count; +void nux::GestureEvent::Reject() +{ + g_gesture_event_reject_count[gesture_id_] = + g_gesture_event_reject_count[gesture_id_] + 1; +} + +Cursor WindowGestureTargetMock::fleur_cursor = 0; +std::set<WindowGestureTargetMock*> g_window_target_mocks; + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + + int ret = RUN_ALL_TESTS(); + + return ret; +} diff --git a/tests/test-gestures/test_window_gesture_target.cpp b/tests/test-gestures/test_window_gesture_target.cpp new file mode 100644 index 000000000..4491a9ca3 --- /dev/null +++ b/tests/test-gestures/test_window_gesture_target.cpp @@ -0,0 +1,235 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + * + */ + +#include <gtest/gtest.h> +#include <compiz_mock/core/core.h> +#include "FakeGestureEvent.h" +#include "unityshell_mock.h" +#include <WindowGestureTarget.h> + +class WindowGestureTargetTest : public ::testing::Test +{ + protected: + virtual void SetUp() + { + screen_mock->width_ = 1280; + screen_mock->height_ = 1024; + } + + void PerformPinch(WindowGestureTarget &gesture_target, float peak_radius) + { + nux::FakeGestureEvent fake_event; + + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 0; + fake_event.gesture_classes = nux::PINCH_GESTURE; + fake_event.is_direct_touch = false; + // in touch device's coordinate system (because it's not a direct device). + // Thus not used by WindowCompositor + fake_event.touches.push_back(nux::TouchPoint(0, 10.0f, 10.0f)); + fake_event.touches.push_back(nux::TouchPoint(1, 20.0f, 20.0f)); + fake_event.touches.push_back(nux::TouchPoint(2, 22.0f, 22.0f)); + fake_event.focus.x = gesture_target.window()->geometry_.centerX(); + fake_event.focus.y = gesture_target.window()->geometry_.centerY();; + fake_event.radius = 1.0; + fake_event.is_construction_finished = false; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.radius = peak_radius; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_END; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + } +}; + +TEST_F(WindowGestureTargetTest, ThreeFingersDragMovesWindow) +{ + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = CompWindowActionMoveMask; + window.state_ = 0; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + nux::FakeGestureEvent fake_event; + + /* prepare and send the fake event */ + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 0; + fake_event.gesture_classes = nux::TOUCH_GESTURE; + fake_event.is_direct_touch = false; + fake_event.focus.x = 100.0f; // hits the middle window + fake_event.focus.y = 100.0f; + // in touch device's coordinate system (because it's not a direct device). + // Thus not used by WindowCompositor + fake_event.touches.push_back(nux::TouchPoint(0, 10.0f, 10.0f)); + fake_event.touches.push_back(nux::TouchPoint(1, 20.0f, 20.0f)); + fake_event.touches.push_back(nux::TouchPoint(2, 22.0f, 22.0f)); + fake_event.is_construction_finished = false; + fake_event.radius = 1.0f; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_FALSE(window.moved_); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.gesture_classes = nux::TOUCH_GESTURE | nux::DRAG_GESTURE; + fake_event.delta.x = 10.0f; + fake_event.delta.y = 20.0f; + fake_event.focus.x += fake_event.delta.x; + fake_event.focus.y += fake_event.delta.y; + fake_event.is_construction_finished = true; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_TRUE(window.moved_); + ASSERT_EQ(fake_event.delta.x, window.movement_x_); + ASSERT_EQ(fake_event.delta.y, window.movement_y_); +} + +TEST_F(WindowGestureTargetTest, ThreeFingersDragDoesntMoveStaticWindow) +{ + + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = 0; /* can't be moved */ + window.state_ = 0; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + nux::FakeGestureEvent fake_event; + + /* prepare and send the fake event */ + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 0; + fake_event.is_direct_touch = false; + fake_event.focus.x = 100.0f; // hits the middle window + fake_event.focus.y = 100.0f; + // in touch device's coordinate system (because it's not a direct device). + // Thus not used by WindowCompositor + fake_event.touches.push_back(nux::TouchPoint(0, 10.0f, 10.0f)); + fake_event.touches.push_back(nux::TouchPoint(1, 20.0f, 20.0f)); + fake_event.touches.push_back(nux::TouchPoint(2, 22.0f, 22.0f)); + fake_event.is_construction_finished = false; + fake_event.radius = 1.0f; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_FALSE(window.moved_); + + fake_event.type = nux::EVENT_GESTURE_UPDATE; + fake_event.delta.x += 10.0f; + fake_event.delta.y += 20.0f; + fake_event.focus.x += fake_event.delta.x; + fake_event.focus.y += fake_event.delta.y; + fake_event.is_construction_finished = true; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_FALSE(window.moved_); +} + +TEST_F(WindowGestureTargetTest, ThreeFingersPinchMaximizesWindow) +{ + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = CompWindowActionMoveMask; + window.state_ = 0; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + PerformPinch(gesture_target, 2.0); + + ASSERT_EQ(1, window.maximize_count_); + ASSERT_EQ(MAXIMIZE_STATE, window.maximize_state_); +} + +TEST_F(WindowGestureTargetTest, ThreeFingersPinchRestoresWindow) +{ + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = CompWindowActionMoveMask; + window.state_ = MAXIMIZE_STATE; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + PerformPinch(gesture_target, 0.3); + + ASSERT_EQ(1, window.maximize_count_); + ASSERT_EQ(0, window.maximize_state_); +} + +TEST_F(WindowGestureTargetTest, MinimalThreeFingersPinchDoesNothing) +{ + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = CompWindowActionMoveMask; + window.state_ = 0; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + PerformPinch(gesture_target, 1.1); + + ASSERT_EQ(0, window.maximize_count_); +} + +/* Regression test for lp:979418, where the grab is not removed if the gesture + * id is 0. */ +TEST_F(WindowGestureTargetTest, DragGrabCheck) +{ + screen_mock->grab_count_ = 0; + + unity::UnityWindowMock window; + window.geometry_.set(10, 10, 400, 400, 0); + window.server_geometry_ = window.geometry_; + window.actions_ = CompWindowActionMoveMask; + window.state_ = 0; + window.id_ = 1; + + WindowGestureTarget gesture_target(&window); + + /* prepare and send the fake event */ + nux::FakeGestureEvent fake_event; + fake_event.type = nux::EVENT_GESTURE_BEGIN; + fake_event.gesture_id = 0; + fake_event.is_direct_touch = false; + fake_event.focus.x = 100.0f; // hits the middle window + fake_event.focus.y = 100.0f; + // in touch device's coordinate system (because it's not a direct device). + // Thus not used by WindowCompositor + fake_event.touches.push_back(nux::TouchPoint(0, 10.0f, 10.0f)); + fake_event.touches.push_back(nux::TouchPoint(1, 20.0f, 20.0f)); + fake_event.touches.push_back(nux::TouchPoint(2, 22.0f, 22.0f)); + fake_event.is_construction_finished = false; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + fake_event.type = nux::EVENT_GESTURE_END; + gesture_target.GestureEvent(fake_event.ToGestureEvent()); + + ASSERT_EQ(0, screen_mock->grab_count_); +} diff --git a/tests/test-gesture-engine/ubus-server-mock.cpp b/tests/test-gestures/ubus-server-mock.cpp index 8305aedff..8305aedff 100644 --- a/tests/test-gesture-engine/ubus-server-mock.cpp +++ b/tests/test-gestures/ubus-server-mock.cpp diff --git a/tests/test-gesture-engine/ubus-server-mock.h b/tests/test-gestures/ubus-server-mock.h index 21a642253..21a642253 100644 --- a/tests/test-gesture-engine/ubus-server-mock.h +++ b/tests/test-gestures/ubus-server-mock.h diff --git a/tests/test-gestures/unityshell_mock.h b/tests/test-gestures/unityshell_mock.h new file mode 100644 index 000000000..36a34c667 --- /dev/null +++ b/tests/test-gestures/unityshell_mock.h @@ -0,0 +1,68 @@ +#ifndef UNITYSHELL_MOCK_H +#define UNITYSHELL_MOCK_H + +#include <compiz_mock/core/core.h> +#include <sigc++/sigc++.h> +#include <NuxMock.h> + +#include "SwitcherControllerMock.h" + + +namespace unity +{ + +class UnityWindowMock : public CompWindowMock +{ + public: + static UnityWindowMock *get(CompWindowMock *window) + { + return static_cast<UnityWindowMock*>(window); + + } + + sigc::signal<void> being_destroyed; +}; + +class UnityScreenMock : public CompScreenMock +{ + public: + UnityScreenMock() + { + switcher_controller_ = std::make_shared<switcher::ControllerMock>(); + Reset(); + } + + void Reset() + { + SetUpAndShowSwitcher_count_ = 0; + switcher_controller_->Reset(); + } + + virtual ~UnityScreenMock() + { + } + + static UnityScreenMock *get(CompScreenMock *screen) + { + return static_cast<UnityScreenMock*>(screen); + + } + + void SetUpAndShowSwitcher() + { + ++SetUpAndShowSwitcher_count_; + switcher_controller_->is_visible_ = true; + } + + switcher::ControllerMock::Ptr switcher_controller() + { + return switcher_controller_; + } + + switcher::ControllerMock::Ptr switcher_controller_; + int SetUpAndShowSwitcher_count_; +}; + +} // namespace unity + +#endif // UNITYSHELL_MOCK_H diff --git a/tests/test_bamflaunchericon.cpp b/tests/test_bamflaunchericon.cpp index 9719e9a5f..874407b75 100644 --- a/tests/test_bamflaunchericon.cpp +++ b/tests/test_bamflaunchericon.cpp @@ -15,6 +15,8 @@ * <http://www.gnu.org/licenses/> * * Authored by: Andrea Azzarone <azzarone@gmail.com> + * Brandon Schaefer <brandon.schaefer@canonical.com> + * Marco Trevisan <marco.trevisan@canonical.com> */ #include <config.h> @@ -23,33 +25,40 @@ #include <UnityCore/GLibWrapper.h> #include "BamfLauncherIcon.h" + using namespace unity; namespace { +const std::string USC_DESKTOP = BUILDDIR"/tests/data/ubuntu-software-center.desktop"; +const std::string NO_ICON_DESKTOP = BUILDDIR"/tests/data/no-icon.desktop"; + class TestBamfLauncherIcon : public testing::Test { public: virtual void SetUp() { + BamfApplication* bamf_app; bamf_matcher = bamf_matcher_get_default(); - bamf_app = bamf_matcher_get_application_for_desktop_file(bamf_matcher, - BUILDDIR"/tests/data/ubuntu-software-center.desktop", - TRUE); + bamf_app = bamf_matcher_get_application_for_desktop_file(bamf_matcher, USC_DESKTOP.c_str(), TRUE); usc_icon = new launcher::BamfLauncherIcon(bamf_app); + ASSERT_EQ(usc_icon->DesktopFile(), USC_DESKTOP); - } + bamf_app = bamf_matcher_get_application_for_desktop_file(bamf_matcher, NO_ICON_DESKTOP.c_str(), TRUE); + empty_icon = new launcher::BamfLauncherIcon(bamf_app); + ASSERT_EQ(empty_icon->DesktopFile(), NO_ICON_DESKTOP); - virtual void TearDown() - { + bamf_app = static_cast<BamfApplication*>(g_object_new(BAMF_TYPE_APPLICATION, nullptr)); + empty_app = new launcher::BamfLauncherIcon(bamf_app); + ASSERT_TRUE(empty_app->DesktopFile().empty()); } glib::Object<BamfMatcher> bamf_matcher; - BamfApplication* bamf_app; nux::ObjectPtr<launcher::BamfLauncherIcon> usc_icon; - + nux::ObjectPtr<launcher::BamfLauncherIcon> empty_icon; + nux::ObjectPtr<launcher::BamfLauncherIcon> empty_app; }; TEST_F(TestBamfLauncherIcon, TestCustomBackgroundColor) @@ -62,4 +71,11 @@ TEST_F(TestBamfLauncherIcon, TestCustomBackgroundColor) EXPECT_EQ(color.alpha, 0xff / 255.0f); } +TEST_F(TestBamfLauncherIcon, TestDefaultIcon) +{ + EXPECT_EQ(usc_icon->icon_name.Get(), "softwarecenter"); + EXPECT_EQ(empty_icon->icon_name.Get(), "application-default-icon"); + EXPECT_EQ(empty_app->icon_name.Get(), "application-default-icon"); +} + } diff --git a/tests/test_bfb_launcher_icon.cpp b/tests/test_bfb_launcher_icon.cpp new file mode 100644 index 000000000..bcc6c5f54 --- /dev/null +++ b/tests/test_bfb_launcher_icon.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + */ + +#include <gmock/gmock.h> + +#include "BFBLauncherIcon.h" + +using namespace unity; +using namespace unity::launcher; + +namespace +{ + +class MockBFBLauncherIcon : public BFBLauncherIcon +{ +public: + MockBFBLauncherIcon() + : BFBLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER) + {} + + AbstractLauncherIcon::MenuItemsVector GetMenus() + { + return BFBLauncherIcon::GetMenus(); + } +}; + +TEST(TestBFBLauncherIcon, OverlayMenus) +{ + MockBFBLauncherIcon bfb; + + for (auto menu_item : bfb.GetMenus()) + { + bool overlay_item = dbusmenu_menuitem_property_get_bool(menu_item, QuicklistMenuItem::OVERLAY_MENU_ITEM_PROPERTY); + ASSERT_TRUE(overlay_item); + } +} + +} diff --git a/tests/test_device_launcher_section.cpp b/tests/test_device_launcher_section.cpp new file mode 100644 index 000000000..b00bbfc72 --- /dev/null +++ b/tests/test_device_launcher_section.cpp @@ -0,0 +1,111 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright 2012 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#include <gmock/gmock.h> +using namespace testing; + +#include "DeviceLauncherSection.h" +#include "AbstractVolumeMonitorWrapper.h" +using namespace unity; +using namespace unity::launcher; + +#include "gmockvolume.h" +#include "test_utils.h" + +namespace +{ + +class EventListener +{ +public: + EventListener() + : icon_added(false) + {} + + void OnIconAdded(AbstractLauncherIcon::Ptr icon) + { + icon_added = true; + } + + bool icon_added; +}; + +class MockVolumeMonitorWrapper : public AbstractVolumeMonitorWrapper +{ +public: + typedef std::shared_ptr<MockVolumeMonitorWrapper> Ptr; + + MockVolumeMonitorWrapper() + : volume1(G_VOLUME(g_mock_volume_new())) + , volume2(G_VOLUME(g_mock_volume_new())) + { + } + + VolumeList GetVolumes() + { + VolumeList ret; + + ret.push_back(volume1); + ret.push_back(volume2); + + return ret; + } + + glib::Object<GVolume> volume1; + glib::Object<GVolume> volume2; +}; + +class TestDeviceLauncherSection : public Test +{ +public: + TestDeviceLauncherSection() + : monitor_(new MockVolumeMonitorWrapper) + , section_(monitor_) + {} + + void SetUp() + { + // Make sure PopulateEntries is called. + Utils::WaitForTimeoutMSec(1500); + } + + MockVolumeMonitorWrapper::Ptr monitor_; + DeviceLauncherSection section_; +}; + + +TEST_F(TestDeviceLauncherSection, TestNoDuplicates) +{ + std::shared_ptr<EventListener> listener(new EventListener); + section_.IconAdded.connect(sigc::mem_fun(*listener, &EventListener::OnIconAdded)); + + // Emit the signal volume_added for each volume. + monitor_->volume_added.emit(monitor_->volume1); + monitor_->volume_added.emit(monitor_->volume2); + + Utils::WaitForTimeoutMSec(500); + + EXPECT_EQ(listener->icon_added, false); +} + +} + diff --git a/tests/test_edge_barrier_controller.cpp b/tests/test_edge_barrier_controller.cpp new file mode 100644 index 000000000..f00ac2bf1 --- /dev/null +++ b/tests/test_edge_barrier_controller.cpp @@ -0,0 +1,272 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + * + */ + +#include <gmock/gmock.h> +#include "test_utils.h" +#include "test_uscreen_mock.h" + +#include "EdgeBarrierController.h" + +using namespace unity; +using namespace unity::ui; +using namespace testing; + +namespace +{ + +class MockPointerBarrier : public PointerBarrierWrapper +{ +public: + MockPointerBarrier(int monitor = 0, bool released_ = false) + { + index = monitor; + x1 = 1; + released = released_; + } + + MOCK_METHOD0(ConstructBarrier, void()); + MOCK_METHOD0(DestroyBarrier, void()); + MOCK_METHOD1(ReleaseBarrier, void(int)); +}; + +class MockEdgeBarrierController : public EdgeBarrierController +{ +public: + void ProcessBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event) + { + EdgeBarrierController::ProcessBarrierEvent(owner, event); + } + + EdgeBarrierSubscriber* GetSubscriber(unsigned int monitor) + { + return EdgeBarrierController::GetSubscriber(monitor); + } +}; + +class TestBarrierSubscriber : public EdgeBarrierSubscriber +{ +public: + TestBarrierSubscriber(bool handles = false) + : handles_(handles) + {} + + bool HandleBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr event) + { + return handles_; + } + + bool handles_; +}; + +class TestEdgeBarrierController : public Test +{ +public: + virtual void SetUp() + { + bc.options = std::make_shared<launcher::Options>(); + bc.options()->edge_resist = true; + bc.options()->edge_passed_disabled_ms = 150; + + uscreen.SetupFakeMultiMonitor(); + + for (int i = 0; i < max_num_monitors; ++i) + { + // By default we assume that no subscriber handles the events!!! + bc.Subscribe(&subscribers_[i], i); + } + } + + BarrierEvent::Ptr MakeBarrierEvent(int id, bool breaker) + { + int velocity = breaker ? std::numeric_limits<int>::max() : bc.options()->edge_overcome_pressure() - 1; + return std::make_shared<BarrierEvent>(0, 1, velocity, id); + } + + TestBarrierSubscriber subscribers_[max_num_monitors]; + MockUScreen uscreen; + MockEdgeBarrierController bc; +}; + +TEST_F(TestEdgeBarrierController, Construction) +{ + EXPECT_TRUE(bc.sticky_edges); + + for (int i = 0; i < max_num_monitors; ++i) + ASSERT_EQ(bc.GetSubscriber(i), &subscribers_[i]); +} + +TEST_F(TestEdgeBarrierController, Unsubscribe) +{ + for (int i = 0; i < max_num_monitors; ++i) + { + bc.Unsubscribe(&subscribers_[i], i); + ASSERT_EQ(bc.GetSubscriber(i), nullptr); + } +} + +TEST_F(TestEdgeBarrierController, UnsubscribeInvalid) +{ + bc.Unsubscribe(&subscribers_[2], 1); + ASSERT_EQ(bc.GetSubscriber(2), &subscribers_[2]); +} + +TEST_F(TestEdgeBarrierController, SubscriberReplace) +{ + TestBarrierSubscriber handling_subscriber(true); + bc.Subscribe(&handling_subscriber, 0); + EXPECT_EQ(bc.GetSubscriber(0), &handling_subscriber); +} + +TEST_F(TestEdgeBarrierController, ProcessHandledEvent) +{ + int monitor = 0; + + TestBarrierSubscriber handling_subscriber(true); + bc.Subscribe(&handling_subscriber, monitor); + + MockPointerBarrier owner(monitor); + auto breaking_barrier_event = MakeBarrierEvent(0, true); + + EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0); + bc.ProcessBarrierEvent(&owner, breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, ProcessHandledEventOnReleasedBarrier) +{ + int monitor = max_num_monitors-1; + + TestBarrierSubscriber handling_subscriber(true); + bc.Subscribe(&handling_subscriber, monitor); + + MockPointerBarrier owner(monitor, true); + auto breaking_barrier_event = MakeBarrierEvent(0, true); + + EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0); + bc.ProcessBarrierEvent(&owner, breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, ProcessUnHandledEventBreakingBarrier) +{ + int monitor = 1; + + MockPointerBarrier owner(monitor); + int breaking_id = 12345; + auto breaking_barrier_event = MakeBarrierEvent(breaking_id, true); + + EXPECT_CALL(owner, ReleaseBarrier(breaking_id)); + bc.ProcessBarrierEvent(&owner, breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, ProcessUnHandledEventBreakingBarrierOnMaxMonitor) +{ + int monitor = max_num_monitors; + + MockPointerBarrier owner(monitor); + auto breaking_barrier_event = MakeBarrierEvent(0, true); + + // This was leading to a crash, see bug #1020075 + // you can reproduce this repeating this test multiple times using the + // --gtest_repeat=X command line + EXPECT_CALL(owner, ReleaseBarrier(_)); + bc.ProcessBarrierEvent(&owner, breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, ProcessUnHandledEventNotBreakingBarrier) +{ + int monitor = 2; + + MockPointerBarrier owner(monitor); + int not_breaking_id = 54321; + auto not_breaking_barrier_event = MakeBarrierEvent(not_breaking_id, false); + + EXPECT_CALL(owner, ReleaseBarrier(not_breaking_id)).Times(0); + bc.ProcessBarrierEvent(&owner, not_breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, ProcessUnHandledEventOnReleasedBarrier) +{ + int monitor = 2; + + MockPointerBarrier owner(monitor, true); + int not_breaking_id = 345678; + auto not_breaking_barrier_event = MakeBarrierEvent(not_breaking_id, false); + + EXPECT_CALL(owner, ReleaseBarrier(not_breaking_id)); + bc.ProcessBarrierEvent(&owner, not_breaking_barrier_event); +} + +TEST_F(TestEdgeBarrierController, BreakingEdgeTemporaryReleasesBarrier) +{ + MockPointerBarrier owner; + + EXPECT_CALL(owner, ReleaseBarrier(1)); + bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(1, true)); + ASSERT_TRUE(owner.released()); + + Utils::WaitForTimeoutMSec(bc.options()->edge_passed_disabled_ms); + EXPECT_FALSE(owner.released()); +} + +TEST_F(TestEdgeBarrierController, BreakingEdgeTemporaryReleasesBarrierForNotHandledEvents) +{ + MockPointerBarrier owner; + int monitor = 0; + subscribers_[monitor].handles_ = false; + + EXPECT_CALL(owner, ReleaseBarrier(5)); + bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(5, true)); + ASSERT_TRUE(owner.released()); + + subscribers_[monitor].handles_ = false; + EXPECT_CALL(owner, ReleaseBarrier(6)); + bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(6, false)); +} + +TEST_F(TestEdgeBarrierController, BreakingEdgeDontReleasesBarrierForHandledEvents) +{ + MockPointerBarrier owner; + int monitor = 0; + subscribers_[monitor].handles_ = false; + + EXPECT_CALL(owner, ReleaseBarrier(5)); + bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(5, true)); + ASSERT_TRUE(owner.released()); + + subscribers_[monitor].handles_ = true; + EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0); + bc.ProcessBarrierEvent(&owner, MakeBarrierEvent(6, true)); +} + +TEST_F(TestEdgeBarrierController, StickyEdgePropertyProxiesLauncherOption) +{ + bc.options()->edge_resist = false; + EXPECT_FALSE(bc.sticky_edges()); + + bc.options()->edge_resist = true; + EXPECT_TRUE(bc.sticky_edges()); + + bc.sticky_edges = false; + EXPECT_FALSE(bc.options()->edge_resist()); + + bc.sticky_edges = true; + EXPECT_TRUE(bc.options()->edge_resist()); +} + +} diff --git a/tests/test_favorite_store_gsettings.cpp b/tests/test_favorite_store_gsettings.cpp index 8609d9379..245fcd001 100644 --- a/tests/test_favorite_store_gsettings.cpp +++ b/tests/test_favorite_store_gsettings.cpp @@ -41,10 +41,9 @@ using testing::Eq; namespace { // Constant +const gchar* SETTINGS_NAME = "com.canonical.Unity.Launcher"; +const gchar* SETTINGS_KEY = "favorites"; const gchar* SCHEMA_DIRECTORY = BUILDDIR"/settings"; -const gchar* BASE_STORE_FILE = BUILDDIR"/settings/test-favorite-store-gsettings.store"; -const gchar* BASE_STORE_CONTENTS = "[desktop/unity/launcher]\n" \ - "favorites=['%s', '%s', '%s']"; const char* base_store_favs[] = { BUILDDIR"/tests/data/ubuntuone-installer.desktop", BUILDDIR"/tests/data/ubuntu-software-center.desktop", @@ -76,41 +75,33 @@ bool ends_with(std::string const& value, std::string const& suffix) class TestFavoriteStoreGSettings : public testing::Test { public: - glib::Object<GSettingsBackend> backend; - std::unique_ptr<internal::FavoriteStoreGSettings> setting_singleton_instance; + std::unique_ptr<internal::FavoriteStoreGSettings> favorite_store; + glib::Object<GSettings> gsettings_client; virtual void SetUp() { // set the data directory so gsettings can find the schema - g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIRECTORY, false); + g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIRECTORY, true); + g_setenv("GSETTINGS_BACKEND", "memory", true); - glib::Error error; - glib::String contents(g_strdup_printf(BASE_STORE_CONTENTS, - base_store_favs[0], - base_store_favs[1], - base_store_favs[2] - )); + favorite_store.reset(new internal::FavoriteStoreGSettings()); - g_file_set_contents(BASE_STORE_FILE, - contents.Value(), - -1, - error.AsOutParam()); - - ASSERT_FALSE(error); - - backend = g_keyfile_settings_backend_new(BASE_STORE_FILE, "/", "root"); - setting_singleton_instance.reset(new internal::FavoriteStoreGSettings(backend.RawPtr())); + // Setting the test values + gsettings_client = g_settings_new(SETTINGS_NAME); + g_settings_set_strv(gsettings_client, SETTINGS_KEY, base_store_favs); } virtual void TearDown() { + g_setenv("GSETTINGS_SCHEMA_DIR", "", true); + g_setenv("GSETTINGS_BACKEND", "", true); } - }; TEST_F(TestFavoriteStoreGSettings, TestAllocation) { - EXPECT_TRUE(G_IS_SETTINGS_BACKEND(backend.RawPtr())); + FavoriteStore &settings = FavoriteStore::Instance(); + EXPECT_EQ(&settings, favorite_store.get()); } TEST_F(TestFavoriteStoreGSettings, TestGetFavorites) @@ -245,9 +236,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalFirst) favs.push_back(base_store_favs[0]); favs.push_back(base_store_favs[1]); favs.push_back(base_store_favs[2]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); EXPECT_EQ(position, base_store_favs[0]); @@ -273,9 +262,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalMiddle) favs.push_back(base_store_favs[1]); favs.push_back(other_desktop); favs.push_back(base_store_favs[2]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); EXPECT_EQ(position, base_store_favs[1]); @@ -301,9 +288,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalEnd) favs.push_back(base_store_favs[1]); favs.push_back(base_store_favs[2]); favs.push_back(other_desktop); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); EXPECT_EQ(position, base_store_favs[2]); @@ -326,9 +311,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalEmpty) FavoriteList favs; favs.push_back(other_desktop); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); EXPECT_EQ(position, ""); @@ -350,9 +333,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteRemoved) FavoriteList favs; favs.push_back(base_store_favs[0]); favs.push_back(base_store_favs[2]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); EXPECT_EQ(path_removed, base_store_favs[1]); @@ -372,9 +353,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteReordered) favs.push_back(base_store_favs[0]); favs.push_back(base_store_favs[2]); favs.push_back(base_store_favs[1]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_TRUE(signal_received); @@ -382,9 +361,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteReordered) favs.push_back(base_store_favs[0]); favs.push_back(base_store_favs[2]); favs.push_back(base_store_favs[1]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); ASSERT_FALSE(signal_received); } @@ -415,9 +392,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed1) favs.push_back(base_store_favs[0]); favs.push_back(base_store_favs[1]); favs.push_back(other_desktop); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); EXPECT_TRUE(added_received); EXPECT_TRUE(removed_received); @@ -450,9 +425,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed2) favs.push_back(base_store_favs[1]); favs.push_back(other_desktop); favs.push_back(base_store_favs[0]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); EXPECT_TRUE(added_received); EXPECT_TRUE(removed_received); @@ -484,9 +457,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed3) FavoriteList favs; favs.push_back(base_store_favs[1]); favs.push_back(base_store_favs[0]); - setting_singleton_instance->SaveFavorites(favs, false); - - sleep(1); + favorite_store->SaveFavorites(favs, false); EXPECT_FALSE(added_received); EXPECT_TRUE(removed_received); diff --git a/tests/test_filesystem_lenses.cpp b/tests/test_filesystem_lenses.cpp index aef7c2164..49d7226e3 100644 --- a/tests/test_filesystem_lenses.cpp +++ b/tests/test_filesystem_lenses.cpp @@ -31,12 +31,7 @@ void WaitForResult(bool& result) void WaitForLensesToLoad(FilesystemLenses& lenses) { bool result = false; - - auto lenses_loaded_cb = [&result]() - { - result = true; - }; - lenses.lenses_loaded.connect(sigc::slot<void>(lenses_loaded_cb)); + lenses.lenses_loaded.connect([&result] {result = true;}); WaitForResult(result); EXPECT_TRUE(result); @@ -61,12 +56,7 @@ TEST(TestFilesystemLenses, TestLensesAdded) LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TESTDATADIR"/lenses")); FilesystemLenses lenses(test_reader); unsigned int n_lenses = 0; - - auto lens_added_cb = [&n_lenses](Lens::Ptr & p) - { - n_lenses++; - }; - lenses.lens_added.connect(sigc::slot<void, Lens::Ptr&>(lens_added_cb)); + lenses.lens_added.connect([&n_lenses](Lens::Ptr & p) { ++n_lenses; }); WaitForLensesToLoad(lenses); EXPECT_EQ(n_lenses, (unsigned int)3); diff --git a/tests/test_glib_signals.cpp b/tests/test_glib_signals.cpp index e3f0fa34c..7a45821ac 100644 --- a/tests/test_glib_signals.cpp +++ b/tests/test_glib_signals.cpp @@ -1,4 +1,5 @@ #include <UnityCore/GLibSignal.h> +#include <sigc++/sigc++.h> #include <gtest/gtest.h> #include "test_glib_signals_utils.h" @@ -274,6 +275,22 @@ TEST_F(TestGLibSignals, TestCleanDestruction) signal.Connect(test_signals_, "signal0", sigc::mem_fun(this, &TestGLibSignals::Signal0Callback)); g_object_unref(test_signals_); + EXPECT_EQ(signal.object(), nullptr); +} + +TEST_F(TestGLibSignals, TestConnectReplacePreviousConnection) +{ + Signal<void, TestSignals*> signal; + signal.Connect(test_signals_, "signal0", + sigc::mem_fun(this, &TestGLibSignals::Signal0Callback)); + + unsigned signal0_num_cb = 0; + signal.Connect(test_signals_, "signal0", [&] (TestSignals*) {++signal0_num_cb;}); + + g_signal_emit_by_name(test_signals_, "signal0"); + + EXPECT_FALSE(signal0_received_); + EXPECT_EQ(signal0_num_cb, 1); } TEST_F(TestGLibSignals, TestManagerConstruction) @@ -403,4 +420,26 @@ TEST_F(TestGLibSignals, TestManagerObjectDisconnection) EXPECT_FALSE(signal1_received_); } +TEST_F(TestGLibSignals, TestManagerUnreffingObjectDeletesConnections) +{ + MockSignalManager manager; + + manager.Add<void, TestSignals*>(test_signals_, "signal0", + sigc::mem_fun(this, &TestGLibSignals::Signal0Callback)); + manager.Add<void, TestSignals*, const char*>(test_signals_, "signal1", + sigc::mem_fun(this, &TestGLibSignals::Signal1Callback)); + manager.Add<void, TestSignals*, const char*, int>(test_signals_, "signal2", + sigc::mem_fun(this, &TestGLibSignals::Signal2Callback)); + manager.Add<void, TestSignals*, const char*, int, float>(test_signals_, "signal3", + sigc::mem_fun(this, &TestGLibSignals::Signal3Callback)); + manager.Add<void, TestSignals*, const char*, int, float, double>(test_signals_, "signal4", + sigc::mem_fun(this, &TestGLibSignals::Signal4Callback)); + manager.Add<void, TestSignals*, const char*, int, float, double, gboolean>(test_signals_, "signal5", + sigc::mem_fun(this, &TestGLibSignals::Signal5Callback)); + manager.Add<gboolean, TestSignals*, const char*, int, float, double, gboolean, char>(test_signals_, "signal6", sigc::mem_fun(this, &TestGLibSignals::Signal6Callback)); + + g_object_unref(test_signals_); + EXPECT_TRUE(manager.GetConnections().empty()); +} + } diff --git a/tests/test_home_lens.cpp b/tests/test_home_lens.cpp index 069175ab5..9e5105850 100644 --- a/tests/test_home_lens.cpp +++ b/tests/test_home_lens.cpp @@ -63,6 +63,7 @@ public: ModelType::LOCAL) { search_in_global(true); + connected.SetGetterFunction(sigc::mem_fun(this, &StaticTestLens::force_connected)); DeeModel* cats = categories()->model(); DeeModel* results = global_results()->model(); @@ -88,6 +89,11 @@ public: virtual ~StaticTestLens() {} + bool force_connected() + { + return true; + } + virtual void DoGlobalSearch(string const& search_string) { DeeModel* model = global_results()->model(); @@ -258,9 +264,10 @@ TEST(TestHomeLens, TestTwoStaticLenses) EXPECT_EQ(home_lens_.GetLensAtIndex(1)->id(), "second.lens"); } -TEST(TestHomeLens, TestCategoryMerging) +TEST(TestHomeLens, TestCategoryMergingDisplayName) { - HomeLens home_lens_("name", "description", "searchhint"); + HomeLens home_lens_("name", "description", "searchhint", + HomeLens::MergeMode::DISPLAY_NAME); TwoStaticTestLenses lenses_; DeeModel* cats = home_lens_.categories()->model(); DeeModelIter* iter; @@ -292,6 +299,27 @@ TEST(TestHomeLens, TestCategoryMerging) EXPECT_EQ("cat1+second.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); } +TEST(TestHomeLens, TestCategoryMergingPerLens) +{ + HomeLens home_lens_("name", "description", "searchhint", + HomeLens::MergeMode::OWNER_LENS); + TwoStaticTestLenses lenses_; + DeeModel* cats = home_lens_.categories()->model(); + DeeModelIter* iter; + const unsigned int NAME_COLUMN = 0; + + home_lens_.AddLenses(lenses_); + + EXPECT_EQ(dee_model_get_n_rows(cats), 2); // just two lenses + + /* Validate the merged categories */ + iter = dee_model_get_iter_at_row(cats, 0); + EXPECT_EQ("First Lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); + + iter = dee_model_get_iter_at_row(cats, 1); + EXPECT_EQ("Second Lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); +} + // It's not that we must not support filters. It is just not implemented yet. // But we actively test against it to make sure we don't end up with broken // filters in the UI. When/if we land support for filters on the home screen @@ -307,7 +335,8 @@ TEST(TestHomeLens, TestIgnoreFilters) TEST(TestHomeLens, TestOneSearch) { - HomeLens home_lens_("name", "description", "searchhint"); + HomeLens home_lens_("name", "description", "searchhint", + HomeLens::MergeMode::DISPLAY_NAME); TwoStaticTestLenses lenses_; DeeModel* results = home_lens_.results()->model(); DeeModel* cats = home_lens_.categories()->model(); diff --git a/tests/test_icon_loader.cpp b/tests/test_icon_loader.cpp index a97d0a117..f717bf585 100644 --- a/tests/test_icon_loader.cpp +++ b/tests/test_icon_loader.cpp @@ -18,6 +18,7 @@ */ #include <gmock/gmock.h> +#include <sigc++/sigc++.h> #include "IconLoader.h" @@ -42,7 +43,7 @@ gboolean TimeoutReached (gpointer data) struct LoadResult { - GdkPixbuf *pixbuf; + glib::Object<GdkPixbuf> pixbuf; bool got_callback; LoadResult() : pixbuf(NULL), got_callback(false) {} @@ -85,6 +86,28 @@ TEST(TestIconLoader, TestGetOneIcon) g_source_remove (tid); } +TEST(TestIconLoader, TestGetAnnotatedIcon) +{ + LoadResult load_result; + IconLoader& icon_loader = IconLoader::GetDefault(); + volatile bool timeout_reached = false; + + + icon_loader.LoadFromGIconString(". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'gedit-icon'%3E,%20'ribbon':%20%3C'foo'%3E%7D", 48, sigc::mem_fun(load_result, + &LoadResult::IconLoaded)); + + guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached)); + while (!timeout_reached && !load_result.got_callback) + { + g_main_context_iteration (NULL, TRUE); + } + + EXPECT_TRUE(load_result.got_callback); + EXPECT_TRUE(IsValidPixbuf(load_result.pixbuf)); + + g_source_remove (tid); +} + TEST(TestIconLoader, TestGetOneIconManyTimes) { std::vector<LoadResult> results; diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp new file mode 100644 index 000000000..b6f6e22ad --- /dev/null +++ b/tests/test_launcher.cpp @@ -0,0 +1,158 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> + +#include "launcher/DNDCollectionWindow.h" +#include "launcher/MockLauncherIcon.h" +#include "launcher/Launcher.h" +#include "unity-shared/PanelStyle.h" +#include "unity-shared/UnitySettings.h" +#include "test_utils.h" +using namespace unity; + +namespace unity +{ +namespace launcher +{ +namespace +{ + +const int STARTING_ANIMATION_DURATION = 150; + +class MockMockLauncherIcon : public launcher::MockLauncherIcon +{ +public: + typedef nux::ObjectPtr<MockMockLauncherIcon> Ptr; + + MOCK_METHOD1(ShouldHighlightOnDrag, bool(DndData const&)); +}; + +} + +class TestLauncher : public Test +{ +public: + TestLauncher() + : parent_window_(new nux::BaseWindow("TestLauncherWindow")) + , dnd_collection_window_(new DNDCollectionWindow) + , model_(new LauncherModel) + , options_(new Options) + , launcher_(new Launcher(parent_window_, dnd_collection_window_)) + { + launcher_->options = options_; + launcher_->SetModel(model_); + } + + float IconBackgroundIntensity(AbstractLauncherIcon::Ptr icon, timespec const& current) const + { + return launcher_->IconBackgroundIntensity(icon, current); + } + + nux::BaseWindow* parent_window_; + nux::ObjectPtr<DNDCollectionWindow> dnd_collection_window_; + Settings settings; + panel::Style panel_style; + LauncherModel::Ptr model_; + Options::Ptr options_; + nux::ObjectPtr<Launcher> launcher_; +}; + +TEST_F(TestLauncher, TestQuirksDuringDnd) +{ + MockMockLauncherIcon::Ptr first(new MockMockLauncherIcon); + model_->AddIcon(first); + + MockMockLauncherIcon::Ptr second(new MockMockLauncherIcon); + model_->AddIcon(second); + + MockMockLauncherIcon::Ptr third(new MockMockLauncherIcon); + model_->AddIcon(third); + + EXPECT_CALL(*first, ShouldHighlightOnDrag(_)) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*second, ShouldHighlightOnDrag(_)) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*third, ShouldHighlightOnDrag(_)) + .WillRepeatedly(Return(false)); + + std::list<char*> uris; + dnd_collection_window_->collected.emit(uris); + + Utils::WaitForTimeout(1); + + EXPECT_FALSE(first->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT)); + EXPECT_FALSE(second->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT)); + EXPECT_TRUE(third->GetQuirk(launcher::AbstractLauncherIcon::Quirk::DESAT)); +} + +TEST_F(TestLauncher, TestMouseWheelScroll) +{ + int initial_scroll_delta; + + launcher_->SetHover(true); + initial_scroll_delta = launcher_->GetDragDelta(); + + // scroll down + launcher_->RecvMouseWheel(0,0,20,0,0); + EXPECT_EQ((launcher_->GetDragDelta() - initial_scroll_delta), 25); + + // scroll up + launcher_->RecvMouseWheel(0,0,-20,0,0); + EXPECT_EQ(launcher_->GetDragDelta(), initial_scroll_delta); + + launcher_->SetHover(false); +} + +TEST_F(TestLauncher, TestIconBackgroundIntensity) +{ + MockMockLauncherIcon::Ptr first(new MockMockLauncherIcon); + model_->AddIcon(first); + + MockMockLauncherIcon::Ptr second(new MockMockLauncherIcon); + model_->AddIcon(second); + + MockMockLauncherIcon::Ptr third(new MockMockLauncherIcon); + model_->AddIcon(third); + + options_->backlight_mode = BACKLIGHT_NORMAL; + options_->launch_animation = LAUNCH_ANIMATION_PULSE; + + first->SetQuirk(AbstractLauncherIcon::Quirk::RUNNING, true); + second->SetQuirk(AbstractLauncherIcon::Quirk::RUNNING, true); + third->SetQuirk(AbstractLauncherIcon::Quirk::RUNNING, false); + + Utils::WaitForTimeoutMSec(STARTING_ANIMATION_DURATION); + timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + + EXPECT_THAT(IconBackgroundIntensity(first, current), Gt(0.0f)); + EXPECT_THAT(IconBackgroundIntensity(second, current), Gt(0.0f)); + EXPECT_EQ(IconBackgroundIntensity(third, current), 0.0f); +} + +} +} diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp new file mode 100644 index 000000000..16fbbf5ee --- /dev/null +++ b/tests/test_launcher_controller.cpp @@ -0,0 +1,233 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + */ + +#include <gmock/gmock.h> +#include "test_uscreen_mock.h" + +#include "FavoriteStore.h" +#include "LauncherController.h" +#include "LauncherControllerPrivate.h" +#include "PanelStyle.h" +#include "UnitySettings.h" + +using namespace unity::launcher; +using namespace testing; + +namespace unity +{ + +class MockFavoriteStore : public FavoriteStore +{ +public: + FavoriteList const& GetFavorites() + { + return fav_list_; + }; + + void AddFavorite(std::string const& desktop_path, int position) {}; + void RemoveFavorite(std::string const& desktop_path) {}; + void MoveFavorite(std::string const& desktop_path, int position) {}; + void SetFavorites(FavoriteList const& desktop_paths) {}; + +private: + FavoriteList fav_list_; +}; + +class MockBamfLauncherIcon : public BamfLauncherIcon +{ +public: + //typedef nux::ObjectPtr<MockMockLauncherIcon> Ptr; + MockBamfLauncherIcon(BamfApplication* app) + : BamfLauncherIcon(app) {} + + MOCK_METHOD0(UnStick, void()); + MOCK_METHOD0(Quit, void()); +}; + +namespace launcher +{ +class TestLauncherController : public testing::Test +{ +public: + TestLauncherController() + : lc(nux::GetGraphicsDisplay()->GetX11Display()) + {} + + virtual void SetUp() + { + lc.options = std::make_shared<Options>(); + lc.multiple_launchers = true; + } + +protected: + ui::EdgeBarrierController &GetBarrierController() + { + return lc.pimpl->edge_barriers_; + } + + LauncherModel::Ptr GetLauncherModel() + { + return lc.pimpl->model_; + } + + MockUScreen uscreen; + Settings settings; + panel::Style panel_style; + MockFavoriteStore favorite_store; + Controller lc; +}; +} + +TEST_F(TestLauncherController, Construction) +{ + EXPECT_NE(lc.options(), nullptr); + EXPECT_TRUE(lc.multiple_launchers()); +} + +TEST_F(TestLauncherController, MultimonitorMultipleLaunchers) +{ + lc.multiple_launchers = true; + uscreen.SetupFakeMultiMonitor(); + + ASSERT_EQ(lc.launchers().size(), max_num_monitors); + + for (int i = 0; i < max_num_monitors; ++i) + { + EXPECT_EQ(lc.launchers()[i]->monitor(), i); + } +} + +TEST_F(TestLauncherController, MultimonitorSingleLauncher) +{ + lc.multiple_launchers = false; + uscreen.SetupFakeMultiMonitor(0, false); + + for (int i = 0; i < max_num_monitors; ++i) + { + uscreen.SetPrimary(i); + ASSERT_EQ(lc.launchers().size(), 1); + EXPECT_EQ(lc.launcher().monitor(), i); + } +} + +TEST_F(TestLauncherController, MultimonitorSwitchToMultipleLaunchers) +{ + lc.multiple_launchers = false; + uscreen.SetupFakeMultiMonitor(); + + ASSERT_EQ(lc.launchers().size(), 1); + + lc.multiple_launchers = true; + EXPECT_EQ(lc.launchers().size(), max_num_monitors); +} + +TEST_F(TestLauncherController, MultimonitorSwitchToSingleLauncher) +{ + lc.multiple_launchers = true; + int primary = 3; + uscreen.SetupFakeMultiMonitor(primary); + + ASSERT_EQ(lc.launchers().size(), max_num_monitors); + + lc.multiple_launchers = false; + EXPECT_EQ(lc.launchers().size(), 1); + EXPECT_EQ(lc.launcher().monitor(), primary); +} + +TEST_F(TestLauncherController, MultimonitorSwitchToSingleMonitor) +{ + uscreen.SetupFakeMultiMonitor(); + ASSERT_EQ(lc.launchers().size(), max_num_monitors); + + uscreen.Reset(); + EXPECT_EQ(lc.launchers().size(), 1); + EXPECT_EQ(lc.launcher().monitor(), 0); +} + +TEST_F(TestLauncherController, MultimonitorRemoveMiddleMonitor) +{ + uscreen.SetupFakeMultiMonitor(); + ASSERT_EQ(lc.launchers().size(), max_num_monitors); + + std::vector<nux::Geometry> &monitors = uscreen.GetMonitors(); + monitors.erase(monitors.begin() + monitors.size()/2); + uscreen.changed.emit(uscreen.GetPrimaryMonitor(), uscreen.GetMonitors()); + ASSERT_EQ(lc.launchers().size(), max_num_monitors - 1); + + for (int i = 0; i < max_num_monitors - 1; ++i) + EXPECT_EQ(lc.launchers()[i]->monitor(), i); +} + +TEST_F(TestLauncherController, SingleMonitorSwitchToMultimonitor) +{ + ASSERT_EQ(lc.launchers().size(), 1); + + uscreen.SetupFakeMultiMonitor(); + + EXPECT_EQ(lc.launchers().size(), max_num_monitors); +} + +TEST_F(TestLauncherController, MultiMonitorEdgeBarrierSubscriptions) +{ + uscreen.SetupFakeMultiMonitor(); + + for (int i = 0; i < max_num_monitors; ++i) + ASSERT_EQ(GetBarrierController().GetSubscriber(i), lc.launchers()[i].GetPointer()); +} + +TEST_F(TestLauncherController, SingleMonitorEdgeBarrierSubscriptionsUpdates) +{ + lc.multiple_launchers = false; + uscreen.SetupFakeMultiMonitor(0, false); + + for (int i = 0; i < max_num_monitors; ++i) + { + uscreen.SetPrimary(i); + + for (int j = 0; j < max_num_monitors; ++j) + { + if (j == i) + { + ASSERT_EQ(GetBarrierController().GetSubscriber(j), &lc.launcher()); + } + else + { + ASSERT_EQ(GetBarrierController().GetSubscriber(j), nullptr); + } + } + } +} + +TEST_F(TestLauncherController, OnlyUnstickIconOnFavoriteRemoval) +{ + const std::string USC_DESKTOP = BUILDDIR"/tests/data/ubuntu-software-center.desktop"; + + glib::Object<BamfMatcher> matcher(bamf_matcher_get_default()); + + auto bamf_app = bamf_matcher_get_application_for_desktop_file(matcher, USC_DESKTOP.c_str(), TRUE); + MockBamfLauncherIcon *bamf_icon = new MockBamfLauncherIcon(bamf_app); + GetLauncherModel()->AddIcon(AbstractLauncherIcon::Ptr(bamf_icon)); + + EXPECT_CALL(*bamf_icon, UnStick()); + EXPECT_CALL(*bamf_icon, Quit()).Times(0); + + favorite_store.favorite_removed.emit(USC_DESKTOP); +} + +} diff --git a/tests/test_lens.cpp b/tests/test_lens.cpp index 0c222f512..c0c2f678b 100644 --- a/tests/test_lens.cpp +++ b/tests/test_lens.cpp @@ -6,7 +6,9 @@ #include <UnityCore/GLibWrapper.h> #include <UnityCore/Lens.h> #include <UnityCore/MultiRangeFilter.h> -#include <UnityCore/MusicPreviews.h> +#include <UnityCore/Preview.h> +#include <UnityCore/MoviePreview.h> +#include <UnityCore/Variant.h> #include <UnityCore/RadioOptionFilter.h> #include <UnityCore/RatingsFilter.h> @@ -52,7 +54,7 @@ public: void WaitForConnected() { bool timeout_reached = false; - guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached); + guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached, 2000); while (!lens_->connected && !timeout_reached) { @@ -68,7 +70,7 @@ public: void WaitForModel(Model<Adaptor>* model, unsigned int n_rows) { bool timeout_reached = false; - guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached); + guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached, 2000); while (model->count != n_rows && !timeout_reached) { @@ -190,7 +192,7 @@ TEST_F(TestLens, TestGlobalSearch) TEST_F(TestLens, TestActivation) { std::string uri = PopulateAndGetFirstResultURI(); - + bool activated = false; auto activated_cb = [&activated, &uri] (std::string const& uri_, HandledType handled, @@ -201,45 +203,101 @@ TEST_F(TestLens, TestActivation) EXPECT_EQ(hints.size(), 0); activated = true; }; - lens_->activated.connect(sigc::slot<void, std::string const&, HandledType,Lens::Hints const&>(activated_cb)); - + lens_->activated.connect(activated_cb); + lens_->Activate(uri); Utils::WaitUntil(activated); } TEST_F(TestLens, TestPreview) { - // FIXME: fix up when unity-core supports current preview protocol - /* std::string uri = PopulateAndGetFirstResultURI(); bool previewed = false; auto preview_cb = [&previewed, &uri] (std::string const& uri_, - Preview::Ptr preview) + Preview::Ptr const& preview) { EXPECT_EQ(uri, uri_); - EXPECT_EQ(preview->renderer_name, "preview-generic"); - - TrackPreview::Ptr track_preview = std::static_pointer_cast<TrackPreview>(preview); - EXPECT_EQ(track_preview->number, (unsigned int)1); - EXPECT_EQ(track_preview->title, "Animus Vox"); - EXPECT_EQ(track_preview->artist, "The Glitch Mob"); - EXPECT_EQ(track_preview->album, "Drink The Sea"); - EXPECT_EQ(track_preview->length, (unsigned int)404); - EXPECT_EQ(track_preview->album_cover, "file://music/the/track"); - EXPECT_EQ(track_preview->primary_action_name, "Play"); - EXPECT_EQ(track_preview->primary_action_icon_hint, ""); - EXPECT_EQ(track_preview->primary_action_uri, "play://music/the/track"); - EXPECT_EQ(track_preview->play_action_uri, "preview://music/the/track"); - EXPECT_EQ(track_preview->pause_action_uri, "pause://music/the/track"); - EXPECT_EQ(track_preview->genres.size(), (unsigned int)1); + EXPECT_EQ(preview->renderer_name, "preview-movie"); + + auto movie_preview = std::dynamic_pointer_cast<MoviePreview>(preview); + EXPECT_EQ(movie_preview->title, "A movie"); + EXPECT_EQ(movie_preview->subtitle, "With subtitle"); + EXPECT_EQ(movie_preview->description, "And description"); + previewed = true; }; - lens_->preview_ready.connect(sigc::slot<void, std::string const&, Preview::Ptr>(preview_cb)); + + lens_->preview_ready.connect(preview_cb); lens_->Preview(uri); Utils::WaitUntil(previewed); - */ +} + +TEST_F(TestLens, TestPreviewAction) +{ + std::string uri = PopulateAndGetFirstResultURI(); + bool previewed = false; + Preview::Ptr preview; + + auto preview_cb = [&previewed, &uri, &preview] + (std::string const& uri_, + Preview::Ptr const& preview_) + { + EXPECT_EQ(uri, uri_); + EXPECT_EQ(preview_->renderer_name, "preview-movie"); + + preview = preview_; + previewed = true; + }; + + lens_->preview_ready.connect(preview_cb); + lens_->Preview(uri); + + Utils::WaitUntil(previewed); + + bool action_executed = false; + auto activated_cb = [&action_executed] (std::string const& uri, + HandledType handled_type, + Lens::Hints const& hints) + { + EXPECT_EQ(handled_type, HandledType::SHOW_DASH); + action_executed = true; + }; + + lens_->activated.connect(activated_cb); + EXPECT_GT(preview->GetActions().size(), (unsigned)0); + auto action = preview->GetActions()[0]; + preview->PerformAction(action->id); + + Utils::WaitUntil(action_executed); +} + +TEST_F(TestLens, TestEmitClosedSignal) +{ + std::string uri = PopulateAndGetFirstResultURI(); + bool previewed = false; + MoviePreview::Ptr movie_preview; + + auto preview_cb = [&previewed, &uri, &movie_preview] + (std::string const& uri_, + Preview::Ptr const& preview) + { + EXPECT_EQ(uri, uri_); + EXPECT_EQ(preview->renderer_name, "preview-movie"); + + movie_preview = std::dynamic_pointer_cast<MoviePreview>(preview); + + //there isn't anything we can really test here - other than it's not crashing here + movie_preview->EmitClosed(); + + previewed = true; + }; + + lens_->preview_ready.connect(preview_cb); + lens_->Preview(uri); + + Utils::WaitUntil(previewed); } TEST_F(TestLens, TestFilterSync) diff --git a/tests/test_model_iterator.cpp b/tests/test_model_iterator.cpp new file mode 100644 index 000000000..1d90551f9 --- /dev/null +++ b/tests/test_model_iterator.cpp @@ -0,0 +1,126 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Michal Hruby <michal.hruby@canonical.com> + */ + +#include <list> +#include <algorithm> +#include <gmock/gmock.h> +#include <UnityCore/GLibWrapper.h> +#include <UnityCore/Results.h> +#include <UnityCore/ResultIterator.h> + +#include <dee.h> + +using namespace std; +using namespace testing; +using namespace unity; +using namespace unity::glib; +using namespace unity::dash; + +namespace +{ + +class TestResultIterator : public ::testing::Test +{ +public: + TestResultIterator() + : results(new Results(ModelType::LOCAL)) + { + dee_model_set_schema (results->model(), + "s", "s", "u", "s", "s", "s", "s", NULL); + } + + void AddResult(std::string const& uri, std::string const& name) + { + dee_model_append(results->model(), + uri.c_str(), // uri + "icon", // icon-hint + 0, // category + "text/plain", // mimetype + name.c_str(), // display name + "", // comment + uri.c_str()); // dnd-uri + } + + Results::Ptr results; +}; + +TEST_F(TestResultIterator, TestNullModel) +{ + Object<DeeModel> model; + ResultIterator it(model); + + EXPECT_TRUE(it.IsLast()); + // first could be undefined, but let's make sure the behaviour doesn't change + EXPECT_TRUE(it.IsFirst()); +} + +TEST_F(TestResultIterator, TestEmpty) +{ + ResultIterator it(results->model()); + + EXPECT_TRUE(it.IsLast()); + // first could be undefined, but let's make sure the behaviour doesn't change + EXPECT_TRUE(it.IsFirst()); +} + +TEST_F(TestResultIterator, TestNonEmpty) +{ + AddResult("mailto:nospam@example.org", "Email"); + + ResultIterator it(results->model()); + + EXPECT_TRUE(it.IsFirst()); + EXPECT_FALSE(it.IsLast()); +} + +TEST_F(TestResultIterator, TestCopy) +{ + AddResult("mailto:nospam@example.org", "Email"); + + ResultIterator one(results->model()); + ResultIterator two(one); + + EXPECT_EQ(one, two); + + ResultIterator const& original = two++; + EXPECT_EQ(original, one); + EXPECT_NE(one, two); +} + +TEST_F(TestResultIterator, TestIncrement) +{ + AddResult("file:///foo.txt", "Result #1"); + AddResult("file:///qoo.txt", "Result #2"); + + ResultIterator it(results->model()); + + EXPECT_EQ((*it).uri, "file:///foo.txt"); + EXPECT_EQ((*it).name, "Result #1"); + + it++; + EXPECT_EQ((*it).uri, "file:///qoo.txt"); + EXPECT_EQ((*it).name, "Result #2"); + + it++; + EXPECT_TRUE(it.IsLast()); + EXPECT_FALSE(it.IsFirst()); +} + + +} // Namespace diff --git a/tests/test_panel_style.cpp b/tests/test_panel_style.cpp new file mode 100644 index 000000000..3e795c3d4 --- /dev/null +++ b/tests/test_panel_style.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#include <config.h> + +#include <gio/gio.h> +#include <gtest/gtest.h> + +#include "unity-shared/PanelStyle.h" +#include "unity-shared/UnitySettings.h" + +using namespace unity; +using namespace testing; + +namespace +{ + +const std::string TITLEBAR_FONT = "Ubuntu Bold 11"; + +class TestPanelStyle : public Test +{ +public: + glib::Object<GSettings> gsettings; + Settings unity_settings; + std::unique_ptr<panel::Style> panel_style_instance; + + /* override */ void SetUp() + { + g_setenv("GSETTINGS_BACKEND", "memory", TRUE); + + gsettings = g_settings_new("org.gnome.desktop.wm.preferences"); + g_settings_set_string(gsettings, "titlebar-font", TITLEBAR_FONT.c_str()); + + panel_style_instance.reset(new panel::Style()); + } + + /* override */ void TearDown() + { + g_setenv("GSETTINGS_BACKEND", "", TRUE); + } +}; + +TEST_F(TestPanelStyle, TestGetFontDescription) +{ + ASSERT_EQ(panel_style_instance->GetFontDescription(panel::PanelItem::TITLE), TITLEBAR_FONT); +} + +TEST_F(TestPanelStyle, TestChangedSignal) +{ + bool signal_received = false; + + panel_style_instance->changed.connect([&](){ + signal_received = true; + }); + + g_settings_set_string(gsettings, "titlebar-font", "Ubuntu Italic 11"); + + sleep(1); + + ASSERT_TRUE(signal_received); + ASSERT_EQ(panel_style_instance->GetFontDescription(panel::PanelItem::TITLE), "Ubuntu Italic 11"); +} + +} diff --git a/tests/test_pointer_barrier.cpp b/tests/test_pointer_barrier.cpp new file mode 100644 index 000000000..5c07e0d4b --- /dev/null +++ b/tests/test_pointer_barrier.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + * + */ + +#include <gtest/gtest.h> +#include <limits> + +#include "test_utils.h" +#include "PointerBarrier.h" + +using namespace unity::ui; + +namespace +{ + +class MockPointerBarrier : public PointerBarrierWrapper +{ +public: + bool HandleEvent(XEvent ev) { return PointerBarrierWrapper::HandleEvent(ev); } +}; + +TEST(TestPointerBarrier, Construction) +{ + PointerBarrierWrapper pb; + + EXPECT_EQ(pb.active, false); + EXPECT_EQ(pb.released, false); + EXPECT_EQ(pb.smoothing, 75); + EXPECT_EQ(pb.max_velocity_multiplier, 1.0f); + EXPECT_EQ(pb.direction, BOTH); +} + +TEST(TestPointerBarrier, EventConstruction) +{ + BarrierEvent bev(1, 2, 3, 4); + EXPECT_EQ(bev.x, 1); + EXPECT_EQ(bev.y, 2); + EXPECT_EQ(bev.velocity, 3); + EXPECT_EQ(bev.event_id, 4); +} + +TEST(TestPointerBarrier, HandleInvalidEvents) +{ + MockPointerBarrier pb; + XFixesBarrierNotifyEvent ev; + auto xev = reinterpret_cast<XEvent*>(&ev); + + ev.type = XFixesBarrierNotify + 1; + EXPECT_FALSE(pb.HandleEvent(*xev)); + + ev.type = XFixesBarrierNotify; + ev.subtype = XFixesBarrierHitNotify + 1; + ev.barrier = 1; + EXPECT_FALSE(pb.HandleEvent(*xev)); + + ev.barrier = 0; + EXPECT_TRUE(pb.HandleEvent(*xev)); +} + +TEST(TestPointerBarrier, HandleHitNotifyEvents) +{ + MockPointerBarrier pb; + XFixesBarrierNotifyEvent ev; + auto xev = reinterpret_cast<XEvent*>(&ev); + + ev.type = XFixesBarrierNotify; + ev.subtype = XFixesBarrierHitNotify; + ev.barrier = 0; + ev.event_id = 0xdeadbeef; + ev.x = 555; + ev.y = 333; + ev.velocity = std::numeric_limits<int>::max(); + + bool got_event = false; + + pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) { + got_event = true; + + EXPECT_EQ(pbw, &pb); + EXPECT_EQ(bev->x, ev.x); + EXPECT_EQ(bev->y, ev.y); + EXPECT_EQ(bev->velocity, 600 * pb.max_velocity_multiplier); + EXPECT_EQ(bev->event_id, ev.event_id); + }); + + EXPECT_TRUE(pb.HandleEvent(*xev)); + EXPECT_FALSE(got_event); + + Utils::WaitForTimeoutMSec(pb.smoothing()); + + EXPECT_TRUE(got_event); +} + +TEST(TestPointerBarrier, HandleHitNotifyReleasedEvents) +{ + MockPointerBarrier pb; + XFixesBarrierNotifyEvent ev; + auto xev = reinterpret_cast<XEvent*>(&ev); + + ev.type = XFixesBarrierNotify; + ev.subtype = XFixesBarrierHitNotify; + ev.barrier = 0; + ev.event_id = 0xabba; + ev.x = 3333; + ev.y = 5555; + ev.velocity = std::numeric_limits<int>::max(); + + bool got_event = false; + + pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) { + got_event = true; + + EXPECT_EQ(pbw, &pb); + EXPECT_EQ(bev->x, ev.x); + EXPECT_EQ(bev->y, ev.y); + EXPECT_EQ(bev->velocity, ev.velocity); + EXPECT_EQ(bev->event_id, ev.event_id); + }); + + pb.released = true; + EXPECT_TRUE(pb.HandleEvent(*xev)); + EXPECT_TRUE(got_event); +} + +} diff --git a/tests/test_previews.cpp b/tests/test_previews.cpp new file mode 100644 index 000000000..a688c7727 --- /dev/null +++ b/tests/test_previews.cpp @@ -0,0 +1,266 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan (Treviño) <3v1n0@ubuntu.com> + */ + +#include <list> +#include <algorithm> +#include <gmock/gmock.h> +#include <gio/gio.h> +#include <UnityCore/Variant.h> +#include <UnityCore/Preview.h> +#include <UnityCore/ApplicationPreview.h> +#include <UnityCore/MoviePreview.h> +#include <UnityCore/MusicPreview.h> +#include <UnityCore/SeriesPreview.h> +#include <unity-protocol.h> + +using namespace std; +using namespace testing; +using namespace unity; +using namespace unity::glib; +using namespace unity::dash; + +namespace +{ + +bool IsVariant(Variant const& variant) +{ + return g_variant_get_type_string(variant) != NULL; +} + +TEST(TestPreviews, DeserializeGeneric) +{ + Object<GIcon> icon(g_icon_new_for_string("accessories", NULL)); + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new())); + unity_protocol_preview_set_title(proto_obj, "Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Description"); + unity_protocol_preview_set_image(proto_obj, icon); + unity_protocol_preview_set_image_source_uri(proto_obj, "Source"); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr preview = Preview::PreviewForVariant(v); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-generic"); + EXPECT_EQ(preview->title, "Title"); + EXPECT_EQ(preview->subtitle, "Subtitle"); + EXPECT_EQ(preview->description, "Description"); + EXPECT_EQ(preview->image_source_uri, "Source"); + EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE); +} + +TEST(TestPreviews, DeserializeGenericWithMeta) +{ + Object<GIcon> icon(g_icon_new_for_string("accessories", NULL)); + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new())); + unity_protocol_preview_set_title(proto_obj, "Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Description"); + unity_protocol_preview_set_image(proto_obj, icon); + unity_protocol_preview_set_image_source_uri(proto_obj, "Source"); + unity_protocol_preview_add_action(proto_obj, "action1", "Action #1", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action2", "Action #2", NULL, 0); + unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("i", 34)); + unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint")); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr preview = Preview::PreviewForVariant(v); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-generic"); + EXPECT_EQ(preview->title, "Title"); + EXPECT_EQ(preview->subtitle, "Subtitle"); + EXPECT_EQ(preview->description, "Description"); + EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE); + EXPECT_EQ(preview->image_source_uri, "Source"); + + auto actions = preview->GetActions(); + auto info_hints = preview->GetInfoHints(); + + EXPECT_EQ(actions.size(), 2); + + auto action1 = actions[0]; + EXPECT_EQ(action1->id, "action1"); + EXPECT_EQ(action1->display_name, "Action #1"); + EXPECT_EQ(action1->icon_hint, ""); + EXPECT_EQ(action1->layout_hint, 0); + + auto action2 = actions[1]; + EXPECT_EQ(action2->id, "action2"); + EXPECT_EQ(action2->display_name, "Action #2"); + EXPECT_EQ(action2->icon_hint, ""); + + EXPECT_EQ(info_hints.size(), 2); + auto hint1 = info_hints[0]; + EXPECT_EQ(hint1->id, "hint1"); + EXPECT_EQ(hint1->display_name, "Hint 1"); + EXPECT_EQ(hint1->icon_hint, ""); + EXPECT_EQ(hint1->value.GetInt(), 34); + auto hint2 = info_hints[1]; + EXPECT_EQ(hint2->id, "hint2"); + EXPECT_EQ(hint2->display_name, "Hint 2"); + EXPECT_EQ(hint2->icon_hint, ""); + EXPECT_EQ(hint2->value.GetString(), "string hint"); +} + +TEST(TestPreviews, DeserializeApplication) +{ + Object<GIcon> icon(g_icon_new_for_string("application", NULL)); + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); + unity_protocol_preview_set_title(proto_obj, "Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Description"); + unity_protocol_preview_set_image(proto_obj, icon); + auto app_proto_obj = glib::object_cast<UnityProtocolApplicationPreview>(proto_obj); + unity_protocol_application_preview_set_last_update(app_proto_obj, "2012/06/13"); + unity_protocol_application_preview_set_copyright(app_proto_obj, "(c) Canonical"); + unity_protocol_application_preview_set_license(app_proto_obj, "GPLv3"); + unity_protocol_application_preview_set_app_icon(app_proto_obj, icon); + unity_protocol_application_preview_set_rating(app_proto_obj, 4.0); + unity_protocol_application_preview_set_num_ratings(app_proto_obj, 12); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr base_preview = Preview::PreviewForVariant(v); + ApplicationPreview::Ptr preview = std::dynamic_pointer_cast<ApplicationPreview>(base_preview); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-application"); + EXPECT_EQ(preview->title, "Title"); + EXPECT_EQ(preview->subtitle, "Subtitle"); + EXPECT_EQ(preview->description, "Description"); + EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE); + EXPECT_EQ(preview->last_update, "2012/06/13"); + EXPECT_EQ(preview->copyright, "(c) Canonical"); + EXPECT_EQ(preview->license, "GPLv3"); + EXPECT_TRUE(g_icon_equal(preview->app_icon(), icon) != FALSE); + EXPECT_EQ(preview->rating, 4.0); + EXPECT_EQ(preview->num_ratings, static_cast<unsigned>(12)); +} + +TEST(TestPreviews, DeserializeMovie) +{ + Object<GIcon> icon(g_icon_new_for_string("movie", NULL)); + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_movie_preview_new())); + unity_protocol_preview_set_title(proto_obj, "Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Description"); + unity_protocol_preview_set_image(proto_obj, icon); + auto movie_proto_obj = glib::object_cast<UnityProtocolMoviePreview>(proto_obj); + unity_protocol_movie_preview_set_year(movie_proto_obj, "2012"); + unity_protocol_movie_preview_set_rating(movie_proto_obj, 4.0); + unity_protocol_movie_preview_set_num_ratings(movie_proto_obj, 12); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr base_preview = Preview::PreviewForVariant(v); + MoviePreview::Ptr preview = std::dynamic_pointer_cast<MoviePreview>(base_preview); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-movie"); + EXPECT_EQ(preview->title, "Title"); + EXPECT_EQ(preview->subtitle, "Subtitle"); + EXPECT_EQ(preview->description, "Description"); + EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE); + EXPECT_EQ(preview->year, "2012"); + EXPECT_EQ(preview->rating, 4.0); + EXPECT_EQ(preview->num_ratings, static_cast<unsigned int>(12)); +} + +TEST(TestPreviews, DeserializeMusic) +{ + Object<GIcon> icon(g_icon_new_for_string("music", NULL)); + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_music_preview_new())); + unity_protocol_preview_set_title(proto_obj, "Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Description"); + unity_protocol_preview_set_image(proto_obj, icon); + auto music_proto_obj = glib::object_cast<UnityProtocolMusicPreview>(proto_obj); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr base_preview = Preview::PreviewForVariant(v); + MusicPreview::Ptr preview = std::dynamic_pointer_cast<MusicPreview>(base_preview); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-music"); + EXPECT_EQ(preview->title, "Title"); + EXPECT_EQ(preview->subtitle, "Subtitle"); + EXPECT_EQ(preview->description, "Description"); + EXPECT_TRUE(g_icon_equal(preview->image(), icon) != FALSE); +} + +TEST(TestPreviews, DeserializeSeries) +{ + Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_series_preview_new())); + auto series_proto_obj = glib::object_cast<UnityProtocolSeriesPreview>(proto_obj); + unity_protocol_series_preview_add_series_item( + series_proto_obj, "#1", "scheme://path/0", NULL); + unity_protocol_series_preview_add_series_item( + series_proto_obj, "#2", "scheme://path/1", NULL); + unity_protocol_series_preview_set_selected_item(series_proto_obj, 1); + + Object<GIcon> icon(g_icon_new_for_string("accessories", NULL)); + Object<UnityProtocolPreview> child_proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new())); + unity_protocol_preview_set_title(child_proto_obj, "Title"); + unity_protocol_preview_set_subtitle(child_proto_obj, "Subtitle"); + unity_protocol_preview_set_description(child_proto_obj, "Description"); + unity_protocol_preview_set_image(child_proto_obj, icon); + + unity_protocol_series_preview_set_child_preview(series_proto_obj, + child_proto_obj); + + Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), + glib::StealRef()); + EXPECT_TRUE(IsVariant(v)); + + Preview::Ptr base_preview = Preview::PreviewForVariant(v); + SeriesPreview::Ptr preview = std::dynamic_pointer_cast<SeriesPreview>(base_preview); + EXPECT_TRUE(preview != nullptr); + + EXPECT_EQ(preview->renderer_name, "preview-series"); + + auto items = preview->GetItems(); + EXPECT_EQ(items.size(), 2); + + auto item1 = preview->GetItems()[1]; + EXPECT_EQ(item1->uri, "scheme://path/1"); + EXPECT_EQ(item1->title, "#2"); + + auto child_preview = preview->GetChildPreview(); + EXPECT_EQ(child_preview->renderer_name, "preview-generic"); + EXPECT_EQ(child_preview->title, "Title"); + EXPECT_EQ(child_preview->subtitle, "Subtitle"); + EXPECT_EQ(child_preview->description, "Description"); + EXPECT_TRUE(g_icon_equal(child_preview->image(), icon) != FALSE); +} + +} // Namespace diff --git a/tests/test_previews_application.cpp b/tests/test_previews_application.cpp new file mode 100644 index 000000000..e5a3adcc1 --- /dev/null +++ b/tests/test_previews_application.cpp @@ -0,0 +1,124 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <unity-shared/StaticCairoText.h> +#include <unity-shared/DashStyle.h> +#include <unity-shared/PreviewStyle.h> +#include <unity-shared/ThumbnailGenerator.h> +#include "unity-shared/UnitySettings.h" + +#include <unity-protocol.h> +#include "UnityCore/ApplicationPreview.h" +#include "dash/previews/ApplicationPreview.h" +#include "dash/previews/PreviewInfoHintWidget.h" +#include "dash/previews/PreviewRatingsWidget.h" +#include "test_utils.h" +using namespace unity; +using namespace unity::dash; + +namespace +{ + +class MockApplicationPreview : public previews::ApplicationPreview +{ +public: + typedef nux::ObjectPtr<MockApplicationPreview> Ptr; + + MockApplicationPreview(dash::Preview::Ptr preview_model) + : ApplicationPreview(preview_model) + {} + + using ApplicationPreview::title_; + using ApplicationPreview::subtitle_; + using ApplicationPreview::license_; + using ApplicationPreview::last_update_; + using ApplicationPreview::copywrite_; + using ApplicationPreview::description_; + using ApplicationPreview::action_buttons_; + using ApplicationPreview::preview_info_hints_; + using ApplicationPreview::app_rating_; +}; + +class TestPreviewApplication : public Test +{ +public: + TestPreviewApplication() + : parent_window_(new nux::BaseWindow("TestPreviewApplication")) + { + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); + + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); + unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "License"); + unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Copywrite"); + unity_protocol_application_preview_set_last_update(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "11th Apr 2012"); + unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.8); + unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 12); + + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); + unity_protocol_preview_set_title(proto_obj, "Application Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Application Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Application Desctiption"); + unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); + unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); + unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); + + glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); + preview_model_ = dash::Preview::PreviewForVariant(v); + } + + nux::BaseWindow* parent_window_; + dash::Preview::Ptr preview_model_; + + unity::Settings settings; + previews::Style panel_style; + dash::Style dash_style; + ThumbnailGenerator thumbnail_generator; +}; + +TEST_F(TestPreviewApplication, TestCreate) +{ + previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_); + + EXPECT_TRUE(dynamic_cast<previews::ApplicationPreview*>(preview_view.GetPointer()) != NULL); +} + +TEST_F(TestPreviewApplication, TestUIValues) +{ + MockApplicationPreview::Ptr preview_view(new MockApplicationPreview(preview_model_)); + + EXPECT_EQ(preview_view->title_->GetText(), "Application Title"); + EXPECT_EQ(preview_view->subtitle_->GetText(), "Application Subtitle"); + EXPECT_EQ(preview_view->description_->GetText(), "Application Desctiption"); + EXPECT_EQ(preview_view->license_->GetText(), "License"); + //EXPECT_EQ(preview_view->last_update_->GetText(), "Last Updated 11th Apr 2012"); // Not 100% sure this will work with translations. + EXPECT_EQ(preview_view->copywrite_->GetText(), "Copywrite"); + + EXPECT_EQ(preview_view->app_rating_->GetRating(), 0.8f); + EXPECT_EQ(preview_view->action_buttons_.size(), 2); +} + +} diff --git a/tests/test_previews_generic.cpp b/tests/test_previews_generic.cpp new file mode 100644 index 000000000..a803afa9c --- /dev/null +++ b/tests/test_previews_generic.cpp @@ -0,0 +1,107 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <unity-shared/StaticCairoText.h> +#include <unity-shared/DashStyle.h> +#include <unity-shared/PreviewStyle.h> +#include <unity-shared/ThumbnailGenerator.h> +#include "unity-shared/UnitySettings.h" + +#include <unity-protocol.h> +#include "UnityCore/GenericPreview.h" +#include "dash/previews/GenericPreview.h" +#include "test_utils.h" +using namespace unity; +using namespace unity::dash; + +namespace +{ + +class MockGenericPreview : public previews::GenericPreview +{ +public: + typedef nux::ObjectPtr<MockGenericPreview> Ptr; + + MockGenericPreview(dash::Preview::Ptr preview_model) + : GenericPreview(preview_model) + {} + + using GenericPreview::title_; + using GenericPreview::subtitle_; + using GenericPreview::description_; + using GenericPreview::action_buttons_; + using GenericPreview::preview_info_hints_; +}; + +class TestPreviewGeneric : public Test +{ +public: + TestPreviewGeneric() + : parent_window_(new nux::BaseWindow("TestPreviewGeneric")) + { + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new())); + + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); + unity_protocol_preview_set_title(proto_obj, "Generic Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Generic Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Generic Desctiption"); + unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); + unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); + unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); + + glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); + preview_model_ = dash::Preview::PreviewForVariant(v); + } + + nux::BaseWindow* parent_window_; + dash::Preview::Ptr preview_model_; + + unity::Settings settings; + previews::Style panel_style; + dash::Style dash_style; + ThumbnailGenerator thumbnail_generator; +}; + +TEST_F(TestPreviewGeneric, TestCreate) +{ + previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_); + + EXPECT_TRUE(dynamic_cast<previews::GenericPreview*>(preview_view.GetPointer()) != NULL); +} + +TEST_F(TestPreviewGeneric, TestUIValues) +{ + MockGenericPreview::Ptr preview_view(new MockGenericPreview(preview_model_)); + + EXPECT_EQ(preview_view->title_->GetText(), "Generic Title"); + EXPECT_EQ(preview_view->subtitle_->GetText(), "Generic Subtitle"); + EXPECT_EQ(preview_view->description_->GetText(), "Generic Desctiption"); + + EXPECT_EQ(preview_view->action_buttons_.size(), 2); +} + +} diff --git a/tests/test_previews_movie.cpp b/tests/test_previews_movie.cpp new file mode 100644 index 000000000..ae7610bcb --- /dev/null +++ b/tests/test_previews_movie.cpp @@ -0,0 +1,114 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <unity-shared/StaticCairoText.h> +#include <unity-shared/DashStyle.h> +#include <unity-shared/PreviewStyle.h> +#include <unity-shared/ThumbnailGenerator.h> +#include "unity-shared/UnitySettings.h" + +#include <unity-protocol.h> +#include "UnityCore/MoviePreview.h" +#include "dash/previews/MoviePreview.h" +#include "dash/previews/PreviewInfoHintWidget.h" +#include "dash/previews/PreviewRatingsWidget.h" +#include "test_utils.h" +using namespace unity; +using namespace unity::dash; + +namespace +{ + +class MockMoviePreview : public previews::MoviePreview +{ +public: + typedef nux::ObjectPtr<MockMoviePreview> Ptr; + + MockMoviePreview(dash::Preview::Ptr preview_model) + : MoviePreview(preview_model) + {} + + using MoviePreview::title_; + using MoviePreview::subtitle_; + using MoviePreview::description_; + using MoviePreview::action_buttons_; + using MoviePreview::preview_info_hints_; + using MoviePreview::rating_; +}; + +class TestPreviewMovie : public Test +{ +public: + TestPreviewMovie() + : parent_window_(new nux::BaseWindow("TestPreviewMovie")) + { + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_movie_preview_new())); + + unity_protocol_movie_preview_set_rating(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), 0.8); + unity_protocol_movie_preview_set_num_ratings(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), 12); + + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); + unity_protocol_preview_set_title(proto_obj, "Movie Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Movie Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Movie Desctiption"); + unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); + unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); + unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); + + glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); + preview_model_ = dash::Preview::PreviewForVariant(v); + } + + nux::BaseWindow* parent_window_; + dash::Preview::Ptr preview_model_; + + unity::Settings settings; + previews::Style panel_style; + dash::Style dash_style; + ThumbnailGenerator thumbnail_generator; +}; + +TEST_F(TestPreviewMovie, TestCreate) +{ + previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_); + + EXPECT_TRUE(dynamic_cast<previews::MoviePreview*>(preview_view.GetPointer()) != NULL); +} + +TEST_F(TestPreviewMovie, TestUIValues) +{ + MockMoviePreview::Ptr preview_view(new MockMoviePreview(preview_model_)); + + EXPECT_EQ(preview_view->title_->GetText(), "Movie Title"); + EXPECT_EQ(preview_view->subtitle_->GetText(), "Movie Subtitle"); + EXPECT_EQ(preview_view->description_->GetText(), "Movie Desctiption"); + + EXPECT_EQ(preview_view->rating_->GetRating(), 0.8f); + EXPECT_EQ(preview_view->action_buttons_.size(), 2); +} + +} diff --git a/tests/test_previews_music.cpp b/tests/test_previews_music.cpp new file mode 100644 index 000000000..095bdb261 --- /dev/null +++ b/tests/test_previews_music.cpp @@ -0,0 +1,109 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <unity-shared/StaticCairoText.h> +#include <unity-shared/DashStyle.h> +#include <unity-shared/PreviewStyle.h> +#include <unity-shared/ThumbnailGenerator.h> +#include "unity-shared/UnitySettings.h" + +#include <unity-protocol.h> +#include "UnityCore/MusicPreview.h" +#include "dash/previews/MusicPreview.h" +#include "dash/previews/PreviewInfoHintWidget.h" +#include "dash/previews/PreviewRatingsWidget.h" +#include "test_utils.h" +using namespace unity; +using namespace unity::dash; + +namespace +{ + +class MockMusicPreview : public previews::MusicPreview +{ +public: + typedef nux::ObjectPtr<MockMusicPreview> Ptr; + + MockMusicPreview(dash::Preview::Ptr preview_model) + : MusicPreview(preview_model) + {} + + using MusicPreview::title_; + using MusicPreview::subtitle_; + using MusicPreview::action_buttons_; + using MusicPreview::preview_info_hints_; +}; + +class TestPreviewMusic : public Test +{ +public: + TestPreviewMusic() + : parent_window_(new nux::BaseWindow("TestPreviewMusic")) + { + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_music_preview_new())); + + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); + unity_protocol_preview_set_title(proto_obj, "Music Title"); + unity_protocol_preview_set_subtitle(proto_obj, "Music Subtitle"); + unity_protocol_preview_set_description(proto_obj, "Music Desctiption"); + unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action3", "Action 3", NULL, 0); + unity_protocol_preview_add_action(proto_obj, "action4", "Action 4", NULL, 0); + unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); + unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); + unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); + + glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); + preview_model_ = dash::Preview::PreviewForVariant(v); + } + + nux::BaseWindow* parent_window_; + dash::Preview::Ptr preview_model_; + + unity::Settings settings; + previews::Style panel_style; + dash::Style dash_style; + ThumbnailGenerator thumbnail_generator; +}; + +TEST_F(TestPreviewMusic, TestCreate) +{ + previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model_); + + EXPECT_TRUE(dynamic_cast<previews::MusicPreview*>(preview_view.GetPointer()) != NULL); +} + +TEST_F(TestPreviewMusic, TestUIValues) +{ + MockMusicPreview::Ptr preview_view(new MockMusicPreview(preview_model_)); + + EXPECT_EQ(preview_view->title_->GetText(), "Music Title"); + EXPECT_EQ(preview_view->subtitle_->GetText(), "Music Subtitle"); + + EXPECT_EQ(preview_view->action_buttons_.size(), 4); +} + +} diff --git a/tests/test_quicklist_menu_item.cpp b/tests/test_quicklist_menu_item.cpp new file mode 100644 index 000000000..dbba9d078 --- /dev/null +++ b/tests/test_quicklist_menu_item.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2010-2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + * Mirco Müller <mirco.mueller@canonical.com> + */ + +#include <gmock/gmock.h> +#include <libdbusmenu-glib/client.h> +#include <UnityCore/GLibSignal.h> + +#include "QuicklistMenuItem.h" +#include "QuicklistMenuItemCheckmark.h" +#include "QuicklistMenuItemLabel.h" +#include "QuicklistMenuItemRadio.h" +#include "QuicklistMenuItemSeparator.h" +#include "unity-shared/UBusWrapper.h" +#include "unity-shared/UBusMessages.h" +#include "test_utils.h" + +using namespace unity; +using namespace testing; + +namespace +{ + +struct TestQuicklistMenuItem : public Test +{ + TestQuicklistMenuItem() + : item(dbusmenu_menuitem_new()) + {} + + glib::Object<DbusmenuMenuitem> item; +}; + +TEST_F(TestQuicklistMenuItem, QuicklistMenuItemCheckmark) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Unchecked"); + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, + DBUSMENU_MENUITEM_TOGGLE_CHECK); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, false); + dbusmenu_menuitem_property_set_int(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); + + nux::ObjectPtr<QuicklistMenuItemCheckmark> qlitem(new QuicklistMenuItemCheckmark(item)); + + EXPECT_EQ(qlitem->GetLabel(), "Unchecked"); + EXPECT_FALSE(qlitem->GetEnabled()); + EXPECT_FALSE(qlitem->GetActive()); + EXPECT_FALSE(qlitem->GetSelectable()); + EXPECT_FALSE(qlitem->IsMarkupEnabled()); +} + +TEST_F(TestQuicklistMenuItem, QuicklistMenuItemLabel) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "A Label"); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, true); + + nux::ObjectPtr<QuicklistMenuItemLabel> qlitem(new QuicklistMenuItemLabel(item)); + + EXPECT_EQ(qlitem->GetLabel(), "A Label"); + EXPECT_TRUE(qlitem->GetEnabled()); + EXPECT_TRUE(qlitem->GetSelectable()); + EXPECT_TRUE(qlitem->IsMarkupEnabled()); +} + +TEST_F(TestQuicklistMenuItem, QuicklistMenuItemRadio) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Radio Active"); + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, + DBUSMENU_MENUITEM_TOGGLE_RADIO); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_int(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); + + nux::ObjectPtr<QuicklistMenuItemRadio> qlitem(new QuicklistMenuItemRadio(item)); + qlitem->EnableLabelMarkup(true); + + EXPECT_EQ(qlitem->GetLabel(), "Radio Active"); + EXPECT_TRUE(qlitem->GetEnabled()); + EXPECT_TRUE(qlitem->GetActive()); + EXPECT_TRUE(qlitem->GetSelectable()); + EXPECT_TRUE(qlitem->IsMarkupEnabled()); +} + +TEST_F(TestQuicklistMenuItem, QuicklistMenuItemSeparator) +{ + dbusmenu_menuitem_property_set(item, "type", DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + + nux::ObjectPtr<QuicklistMenuItemSeparator> qlitem(new QuicklistMenuItemSeparator(item)); + + EXPECT_TRUE(qlitem->GetEnabled()); + EXPECT_FALSE(qlitem->GetSelectable()); +} + +TEST_F(TestQuicklistMenuItem, OverlayMenuitem) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Label"); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + + nux::ObjectPtr<QuicklistMenuItemLabel> qlitem(new QuicklistMenuItemLabel(item)); + + EXPECT_FALSE(qlitem->IsOverlayQuicklist()); + + dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::OVERLAY_MENU_ITEM_PROPERTY, true); + EXPECT_TRUE(qlitem->IsOverlayQuicklist()); +} + +TEST_F(TestQuicklistMenuItem, ItemActivate) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Label"); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + + nux::ObjectPtr<QuicklistMenuItemLabel> qlitem(new QuicklistMenuItemLabel(item)); + + bool item_activated = false; + glib::Signal<void, DbusmenuMenuitem*, int> signal(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [&] (DbusmenuMenuitem* menu_item, int time) { + EXPECT_EQ(menu_item, item); + item_activated = true; + }); + + qlitem->Activate(); + EXPECT_TRUE(item_activated); +} + +TEST_F(TestQuicklistMenuItem, ItemActivateClosesDash) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Label"); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + + nux::ObjectPtr<QuicklistMenuItemLabel> qlitem(new QuicklistMenuItemLabel(item)); + + bool closes_dash = false; + UBusManager manager; + manager.RegisterInterest(UBUS_PLACE_VIEW_CLOSE_REQUEST, [&] (GVariant*) { closes_dash = true; }); + + qlitem->Activate(); + Utils::WaitUntil(closes_dash); + + EXPECT_TRUE(closes_dash); +} + +TEST_F(TestQuicklistMenuItem, OverlayItemActivateDoesNotCloseDash) +{ + dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Label"); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::OVERLAY_MENU_ITEM_PROPERTY, true); + + nux::ObjectPtr<QuicklistMenuItemLabel> qlitem(new QuicklistMenuItemLabel(item)); + + bool closes_dash = false; + UBusManager manager; + manager.RegisterInterest(UBUS_PLACE_VIEW_CLOSE_REQUEST, [&] (GVariant*) { closes_dash = true; }); + + qlitem->Activate(); + Utils::WaitForTimeoutMSec(100); + + EXPECT_FALSE(closes_dash); +} + +} diff --git a/tests/test_quicklist_view.cpp b/tests/test_quicklist_view.cpp new file mode 100644 index 000000000..908cb50bc --- /dev/null +++ b/tests/test_quicklist_view.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2010-2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + * Mirco Müller <mirco.mueller@canonical.com> + */ + +#include <gmock/gmock.h> +#include <libdbusmenu-glib/client.h> + +#include "QuicklistView.h" +#include "QuicklistMenuItemCheckmark.h" +#include "QuicklistMenuItemLabel.h" +#include "QuicklistMenuItemRadio.h" +#include "QuicklistMenuItemSeparator.h" + +using namespace unity; +using namespace testing; + +namespace +{ + +struct TestQuicklistView : public Test +{ + TestQuicklistView() + : quicklist(new QuicklistView()) + {} + + void AddMenuItems(glib::Object<DbusmenuMenuitem> const& root) + { + quicklist->RemoveAllMenuItem(); + + if (!root) + return; + + for (GList* child = dbusmenu_menuitem_get_children(root); child; child = child->next) + { + glib::Object<DbusmenuMenuitem> item(static_cast<DbusmenuMenuitem*>(child->data), glib::AddRef()); + const gchar* type = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_TYPE); + const gchar* toggle_type = dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE); + + if (g_strcmp0(type, DBUSMENU_CLIENT_TYPES_SEPARATOR) == 0) + { + QuicklistMenuItemSeparator* qlitem = new QuicklistMenuItemSeparator(item, NUX_TRACKER_LOCATION); + quicklist->AddMenuItem(qlitem); + } + else if (g_strcmp0(toggle_type, DBUSMENU_MENUITEM_TOGGLE_CHECK) == 0) + { + QuicklistMenuItemCheckmark* qlitem = new QuicklistMenuItemCheckmark(item, NUX_TRACKER_LOCATION); + quicklist->AddMenuItem(qlitem); + } + else if (g_strcmp0(toggle_type, DBUSMENU_MENUITEM_TOGGLE_RADIO) == 0) + { + QuicklistMenuItemRadio* qlitem = new QuicklistMenuItemRadio(item, NUX_TRACKER_LOCATION); + quicklist->AddMenuItem(qlitem); + } + else //if (g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0) + { + QuicklistMenuItemLabel* qlitem = new QuicklistMenuItemLabel(item, NUX_TRACKER_LOCATION); + quicklist->AddMenuItem(qlitem); + } + } + } + + nux::ObjectPtr<QuicklistView> quicklist; +}; + +TEST_F(TestQuicklistView, AddItems) +{ + glib::Object<DbusmenuMenuitem> root(dbusmenu_menuitem_new()); + + dbusmenu_menuitem_set_root(root, true); + + DbusmenuMenuitem* child = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_MENUITEM_PROP_LABEL); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "label 0"); + dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_child_append(root, child); + + child = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_child_append(root, child); + + child = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_MENUITEM_PROP_LABEL); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "label 1"); + dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_child_append(root, child); + + child = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK); + dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "check mark 0"); + dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_int(child, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); + dbusmenu_menuitem_child_append(root, child); + + AddMenuItems(root); + + ASSERT_EQ(quicklist->GetChildren().size(), 4); + ASSERT_EQ(quicklist->GetNumItems(), 4); + EXPECT_EQ(quicklist->GetNthType(0), unity::QuicklistMenuItemType::LABEL); + EXPECT_EQ(quicklist->GetNthType(1), unity::QuicklistMenuItemType::SEPARATOR); + EXPECT_EQ(quicklist->GetNthType(2), unity::QuicklistMenuItemType::LABEL); + EXPECT_EQ(quicklist->GetNthType(3), unity::QuicklistMenuItemType::CHECK); + + EXPECT_EQ(quicklist->GetNthItems(0)->GetLabel(), "label 0"); + EXPECT_EQ(quicklist->GetNthItems(2)->GetLabel(), "label 1"); + EXPECT_EQ(quicklist->GetNthItems(3)->GetLabel(), "check mark 0"); +} + +} diff --git a/tests/test_results.cpp b/tests/test_results.cpp index 730430333..e4b4d5165 100644 --- a/tests/test_results.cpp +++ b/tests/test_results.cpp @@ -3,11 +3,13 @@ #include <UnityCore/GLibWrapper.h> #include <UnityCore/Results.h> +#include <UnityCore/ResultIterator.h> #include "test_utils.h" using namespace std; using namespace unity::dash; +using namespace unity; namespace { @@ -35,27 +37,97 @@ TEST(TestResults, TestSynchronization) EXPECT_EQ(model.count, n_rows); } +TEST(TestResults, TestFilterValid) +{ + Results model; + DeeFilter filter; + + model.swarm_name = swarm_name; + WaitForSynchronize(model); + + dee_filter_new_for_any_column(2, g_variant_new_uint32(1), &filter); + glib::Object<DeeModel> filter_model(dee_filter_model_new(model.model(), &filter)); + + unsigned int i = 0; + for (ResultIterator iter(filter_model); !iter.IsLast(); ++iter) + { + EXPECT_EQ((*iter).category_index(), 1); + i++; + } + + EXPECT_EQ(i, 50); +} + TEST(TestResults, TestRowsValid) { Results model; model.swarm_name = swarm_name; WaitForSynchronize(model); + + ResultIterator iter(model.model); + unsigned int i = 0; + for (Result result : model) + { + //Result adaptor = *iter; + unity::glib::String tmp(g_strdup_printf("Result%d", i)); + string value = tmp.Str(); + EXPECT_EQ(result.uri(), value); + EXPECT_EQ(result.icon_hint(), value); + EXPECT_EQ(result.category_index(), (i / 50)); + EXPECT_EQ(result.mimetype(), value); + EXPECT_EQ(result.name(), value); + EXPECT_EQ(result.comment(), value); + EXPECT_EQ(result.dnd_uri(), value); + i++; + } - for (unsigned int i = 0; i < n_rows; i++) + //test reading a subset + i = 20; + for (auto iter = model.begin() + i; iter != model.end(); ++iter) { - Result adaptor = model.RowAtIndex(i); + Result result = (*iter); + unity::glib::String tmp(g_strdup_printf("Result%d", i)); + string value = tmp.Str(); + EXPECT_EQ(result.uri(), value); + i++; + } + // test post incrementor + i = 20; + for (auto iter = model.begin() + i; iter != model.end(); iter++) + { + Result result = (*iter); unity::glib::String tmp(g_strdup_printf("Result%d", i)); string value = tmp.Str(); - EXPECT_EQ(adaptor.uri, value); - EXPECT_EQ(adaptor.icon_hint, value); - EXPECT_EQ(adaptor.category_index, i); - EXPECT_EQ(adaptor.mimetype, value); - EXPECT_EQ(adaptor.name, value); - EXPECT_EQ(adaptor.comment, value); - EXPECT_EQ(adaptor.dnd_uri, value); + EXPECT_EQ(result.uri(), value); + i++; } + + // test equality + EXPECT_TRUE(model.begin() == model.begin()); + EXPECT_TRUE(model.begin() != model.end()); + + EXPECT_FALSE(model.begin().IsLast()); + EXPECT_FALSE(model.end().IsFirst()); + EXPECT_TRUE(model.begin().IsFirst()); + EXPECT_TRUE(model.end().IsLast()); + + EXPECT_TRUE(model.begin() < model.end()); + EXPECT_FALSE(model.end() < model.begin()); + EXPECT_TRUE(model.end() > model.begin()); + EXPECT_FALSE(model.begin() > model.end()); + EXPECT_TRUE(model.begin() <= model.end()); + EXPECT_FALSE(model.end() <= model.begin()); + EXPECT_TRUE(model.end() >= model.begin()); + EXPECT_FALSE(model.begin() >= model.end()); + + + EXPECT_TRUE(model.begin() + 20 > model.begin()); + EXPECT_TRUE(model.begin() + 20 > model.begin() + 19); + EXPECT_TRUE(model.end() - 20 < model.end()); + EXPECT_TRUE(model.end() - 20 < model.end() - 19); + } // We're testing the model's ability to store and retrieve random pointers diff --git a/tests/test_service_lens.c b/tests/test_service_lens.c index 854c99ec9..cea0feec0 100644 --- a/tests/test_service_lens.c +++ b/tests/test_service_lens.c @@ -174,7 +174,7 @@ on_search_changed(UnityScope* scope, UnityLensSearch *search, g_free(name); } - g_signal_emit_by_name (search, "finished"); + unity_lens_search_finished (search); } static UnityActivationResponse* @@ -183,15 +183,27 @@ on_activate_uri(UnityScope* scope, const char* uri, ServiceLens* self) return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, ""); } +static UnityActivationResponse* +preview_action_activated(UnityPreviewAction* action, const char* uri) +{ + return unity_activation_response_new(UNITY_HANDLED_TYPE_SHOW_DASH, ""); +} + static UnityPreview* on_preview_uri(UnityScope* scope, const char* uri, ServiceLens *self) { - return NULL; - // FIXME: update when the new preview types are well defined - /* - return (UnityPreview*)unity_generic_preview_new( - "Animus Vox", "The Glitch Mob - Drink The Sea", NULL); - */ + UnityPreviewAction* action; + UnityMoviePreview* preview; + + preview = unity_movie_preview_new("A movie", "With subtitle", + "And description", NULL); + + action = unity_preview_action_new("action_A", "An action", NULL); + unity_preview_add_action(UNITY_PREVIEW(preview), action); + g_signal_connect(action, "activated", + G_CALLBACK(preview_action_activated), NULL); + + return (UnityPreview*) preview; } ServiceLens* diff --git a/tests/test_service_model.c b/tests/test_service_model.c index 8acdda48f..95f07f615 100644 --- a/tests/test_service_model.c +++ b/tests/test_service_model.c @@ -58,7 +58,7 @@ service_model_create_results(ServiceModel* self) dee_model_append(self->results_model_, name, name, - (guint)i, + (guint)(i/50), // new category every 50 results name, name, name, diff --git a/tests/test_single_monitor_launcher_icon.cpp b/tests/test_single_monitor_launcher_icon.cpp index 22f512b65..eeaa9f373 100644 --- a/tests/test_single_monitor_launcher_icon.cpp +++ b/tests/test_single_monitor_launcher_icon.cpp @@ -30,7 +30,7 @@ namespace TEST(TestSingleMonitorLauncherIcon, Construction) { - SingleMonitorLauncherIcon icon(1); + SingleMonitorLauncherIcon icon(AbstractLauncherIcon::IconType::NONE, 1); EXPECT_EQ(icon.GetMonitor(), 1); EXPECT_TRUE(icon.IsVisibleOnMonitor(1)); @@ -39,7 +39,7 @@ TEST(TestSingleMonitorLauncherIcon, Construction) TEST(TestSingleMonitorLauncherIcon, MonitorVisibility) { - SingleMonitorLauncherIcon icon(2); + SingleMonitorLauncherIcon icon(AbstractLauncherIcon::IconType::NONE, 2); for (int i = 0; i < max_num_monitors; ++i) { diff --git a/tests/test_switcher_controller.cpp b/tests/test_switcher_controller.cpp index b039c3cec..70bda5fd0 100644 --- a/tests/test_switcher_controller.cpp +++ b/tests/test_switcher_controller.cpp @@ -24,6 +24,7 @@ #include "test_utils.h" #include "SwitcherController.h" +#include "DesktopLauncherIcon.h" #include "TimeUtil.h" @@ -127,6 +128,7 @@ TEST(TestSwitcherController, InitialDetailTimeout) { MockSwitcherController controller; std::vector<unity::launcher::AbstractLauncherIcon::Ptr> results; + results.push_back(unity::launcher::AbstractLauncherIcon::Ptr(new unity::launcher::DesktopLauncherIcon())); struct timespec current; controller.initial_detail_timeout_length = 2000; @@ -160,6 +162,7 @@ TEST(TestSwitcherController, ShowSwitcher) { MockSwitcherController controller; std::vector<unity::launcher::AbstractLauncherIcon::Ptr> results; + results.push_back(unity::launcher::AbstractLauncherIcon::Ptr(new unity::launcher::DesktopLauncherIcon())); controller.Show(ShowMode::ALL, SortMode::LAUNCHER_ORDER, false, results); @@ -167,4 +170,24 @@ TEST(TestSwitcherController, ShowSwitcher) ASSERT_TRUE(controller.view_shown_); } +TEST(TestSwitcherController, ShowSwitcherNoShowDeskop) +{ + MockSwitcherController controller; + controller.SetShowDesktopDisabled(true); + + ASSERT_TRUE(controller.IsShowDesktopDisabled()); + ASSERT_TRUE(controller.StartIndex() == 0); +} + +TEST(TestSwitcherController, ShowSwitcherNoResults) +{ + MockSwitcherController controller; + controller.SetShowDesktopDisabled(true); + std::vector<unity::launcher::AbstractLauncherIcon::Ptr> results; + + controller.Show(ShowMode::CURRENT_VIEWPORT, SortMode::FOCUS_ORDER, false, results); + + ASSERT_FALSE(controller.Visible()); +} + } diff --git a/tests/test_thumbnail_generator.cpp b/tests/test_thumbnail_generator.cpp new file mode 100644 index 000000000..361837f62 --- /dev/null +++ b/tests/test_thumbnail_generator.cpp @@ -0,0 +1,266 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <list> +#include <gmock/gmock.h> +using namespace testing; + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <unity-shared/ThumbnailGenerator.h> + +#include <unity-protocol.h> +#include "test_utils.h" +#include "config.h" + +using namespace unity; +using namespace unity::dash; + +namespace +{ + +gboolean TimeoutReached (gpointer data) +{ + bool *b = static_cast<bool*>(data); + + *b = true; + + return FALSE; +} + +struct LoadResult +{ + std::string return_string; + bool got_callback; + bool succeeded; + + LoadResult() : got_callback(false),succeeded(false) {} + void ThumbnailReady(std::string const& result) + { + return_string = result; + + got_callback = true; + succeeded = true; + } + void ThumbnailFailed(std::string const& result) + { + return_string = result; + + got_callback = true; + succeeded = false; + } +}; + +TEST(TestThumbnailGenerator, TestNoURIThumbnail) +{ + ThumbnailGenerator thumbnail_generator; + ThumbnailNotifier::Ptr thumb = thumbnail_generator.GetThumbnail("", 256); + EXPECT_TRUE(thumb == nullptr); +} + +TEST(TestThumbnailGenerator, TestGetOneFileThumbnail) +{ + ThumbnailGenerator thumbnail_generator; + + LoadResult load_result; + ThumbnailNotifier::Ptr thumb = thumbnail_generator.GetThumbnail("file://" PKGDATADIR "/switcher_background.png", 256); + EXPECT_TRUE(thumb != nullptr); + + thumb->ready.connect(sigc::mem_fun(load_result, &LoadResult::ThumbnailReady)); + thumb->error.connect(sigc::mem_fun(load_result, &LoadResult::ThumbnailFailed)); + + volatile bool timeout_reached = false; + guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached)); + while (!timeout_reached && !load_result.got_callback) + { + g_main_context_iteration (NULL, TRUE); + } + + EXPECT_TRUE(load_result.succeeded); + glib::Object<GIcon> icon(g_icon_new_for_string(load_result.return_string.c_str(), NULL)); + EXPECT_TRUE(G_IS_ICON(icon.RawPtr())); + + g_source_remove (tid); +} + + +TEST(TestThumbnailGenerator, TestGetManyFileThumbnail) +{ + srand ( time(NULL) ); + ThumbnailGenerator thumbnail_generator; + + const char* thumbs[] = { "file://" PKGDATADIR "/switcher_background.png" , "file://" PKGDATADIR "/star_highlight.png", + "file://" PKGDATADIR "/switcher_round_rect.png", "file://" PKGDATADIR "/switcher_corner.png", + "file://" PKGDATADIR "/switcher_top.png", "file://" PKGDATADIR "/switcher_left.png", + "file://" PKGDATADIR "/dash_bottom_left_corner.png", "file://" PKGDATADIR "/dash_bottom_right_corner.png"}; + + std::vector<LoadResult> results; + std::vector< ThumbnailNotifier::Ptr> notifiers; + + // 100 times should be good + int load_count = 100; + results.resize (load_count); + notifiers.resize (load_count); + + for (int i = 0; i < load_count; i++) + { + notifiers[i] = thumbnail_generator.GetThumbnail(thumbs[rand() % (sizeof(thumbs) / sizeof(char*))], 256); + EXPECT_TRUE(notifiers[i] != nullptr); + + notifiers[i]->ready.connect(sigc::mem_fun(results[i], &LoadResult::ThumbnailReady)); + notifiers[i]->error.connect(sigc::mem_fun(results[i], &LoadResult::ThumbnailFailed)); + } + + // disconnect every other handler (and especially the first one) + for (int i = 0; i < load_count; i += 2) + { + notifiers[i]->Cancel(); + } + + + volatile bool timeout_reached = false; + guint tid = g_timeout_add (30000, TimeoutReached, (gpointer)(&timeout_reached)); + while (!timeout_reached) + { + g_main_context_iteration (NULL, TRUE); + bool all_loaded = true; + bool any_loaded = false; + for (int i = 1; i < load_count; i += 2) + { + all_loaded &= results[i].got_callback; + any_loaded |= results[i].got_callback; + if (!all_loaded) break; + } + if (all_loaded) break; + } + + for (int i = 0; i < load_count; i++) + { + if (i % 2) + { + EXPECT_TRUE(results[i].got_callback); + EXPECT_TRUE(results[i].succeeded); + glib::Object<GIcon> icon(g_icon_new_for_string(results[i].return_string.c_str(), NULL)); + EXPECT_TRUE(G_IS_ICON(icon.RawPtr())); + } + else + { + EXPECT_FALSE(results[i].got_callback); + } + } + + g_source_remove (tid); +} + + +TEST(TestThumbnailGenerator, TestGetOneGIcon) +{ + ThumbnailGenerator thumbnail_generator; + + LoadResult load_result; + ThumbnailNotifier::Ptr thumb = thumbnail_generator.GetThumbnail("file:///home", 256); + EXPECT_TRUE(thumb != nullptr); + + thumb->ready.connect(sigc::mem_fun(load_result, &LoadResult::ThumbnailReady)); + thumb->error.connect(sigc::mem_fun(load_result, &LoadResult::ThumbnailFailed)); + + volatile bool timeout_reached = false; + guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached)); + while (!timeout_reached && !load_result.got_callback) + { + g_main_context_iteration (NULL, TRUE); + } + + EXPECT_TRUE(load_result.succeeded); + glib::Object<GIcon> icon(g_icon_new_for_string(load_result.return_string.c_str(), NULL)); + EXPECT_TRUE(G_IS_ICON(icon.RawPtr())); + + g_source_remove (tid); +} + + +TEST(TestThumbnailGenerator, TestGetManyGIcon) +{ + srand ( time(NULL) ); + ThumbnailGenerator thumbnail_generator; + + const char* thumbs[] = { "file:///home", + "file:///usr", + "file:///bin/bash", + "file:///usr/bin/unity"}; + + std::vector<LoadResult> results; + std::vector< ThumbnailNotifier::Ptr> notifiers; + + // 100 times should be good + int load_count = 100; + results.resize (load_count); + notifiers.resize (load_count); + + for (int i = 0; i < load_count; i++) + { + notifiers[i] = thumbnail_generator.GetThumbnail(thumbs[rand() % (sizeof(thumbs) / sizeof(char*))], 256); + EXPECT_TRUE(notifiers[i] != nullptr); + + notifiers[i]->ready.connect(sigc::mem_fun(results[i], &LoadResult::ThumbnailReady)); + notifiers[i]->error.connect(sigc::mem_fun(results[i], &LoadResult::ThumbnailFailed)); + } + + // disconnect every other handler (and especially the first one) + for (int i = 0; i < load_count; i += 2) + { + notifiers[i]->Cancel(); + } + + volatile bool timeout_reached = false; + guint tid = g_timeout_add (30000, TimeoutReached, (gpointer)(&timeout_reached)); + while (!timeout_reached) + { + g_main_context_iteration (NULL, TRUE); + bool all_loaded = true; + bool any_loaded = false; + for (int i = 1; i < load_count; i += 2) + { + all_loaded &= results[i].got_callback; + any_loaded |= results[i].got_callback; + if (!all_loaded) break; + } + if (all_loaded) break; + } + + for (int i = 0; i < load_count; i++) + { + if (i % 2) + { + EXPECT_TRUE(results[i].got_callback); + EXPECT_TRUE(results[i].succeeded); + glib::Object<GIcon> icon(g_icon_new_for_string(results[i].return_string.c_str(), NULL)); + EXPECT_TRUE(G_IS_ICON(icon.RawPtr())); + } + else + { + EXPECT_FALSE(results[i].got_callback); + } + } + + g_source_remove (tid); +} + + +} diff --git a/tests/test_uscreen_mock.h b/tests/test_uscreen_mock.h new file mode 100644 index 000000000..a81c6037c --- /dev/null +++ b/tests/test_uscreen_mock.h @@ -0,0 +1,85 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY 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 + * version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com> + + */ + +#ifndef TEST_USCREEN_MOCK_H +#define TEST_USCREEN_MOCK_H + +#include "MultiMonitor.h" +#include "UScreen.h" + +namespace unity +{ + +const unsigned MONITOR_WIDTH = 1024; +const unsigned MONITOR_HEIGHT = 768; + +class MockUScreen : public UScreen +{ +public: + MockUScreen() + { + Reset(false); + } + + ~MockUScreen() + { + if (default_screen_ == this) + default_screen_ = nullptr; + } + + void Reset(bool emit = true) + { + default_screen_ = this; + primary_ = 0; + monitors_ = {nux::Geometry(0, 0, MONITOR_WIDTH, MONITOR_HEIGHT)}; + + changed.emit(primary_, monitors_); + } + + void SetupFakeMultiMonitor(int primary = 0, bool emit_update = true) + { + SetPrimary(primary, false); + monitors_.clear(); + + for (int i = 0, total_width = 0; i < max_num_monitors; ++i) + { + monitors_.push_back(nux::Geometry(MONITOR_WIDTH, MONITOR_HEIGHT, total_width, 0)); + total_width += MONITOR_WIDTH; + + if (emit_update) + changed.emit(GetPrimaryMonitor(), GetMonitors()); + } + } + + void SetPrimary(int primary, bool emit = true) + { + if (primary_ != primary) + { + primary_ = primary; + + if (emit) + changed.emit(primary_, monitors_); + } + } +}; + +} + +#endif \ No newline at end of file diff --git a/tests/unit/TestMain.cpp b/tests/unit/TestMain.cpp index 76ad925ad..b95b2d0f3 100644 --- a/tests/unit/TestMain.cpp +++ b/tests/unit/TestMain.cpp @@ -27,7 +27,6 @@ void TestPanelServiceCreateSuite(); void TestUBusCreateSuite(); -void TestQuicklistMenuitemsCreateSuite(); void TestStaticCairoTextCreateSuite(); nux::WindowThread* @@ -71,7 +70,6 @@ main(int argc, char** argv) //Keep alphabetical please TestPanelServiceCreateSuite(); - TestQuicklistMenuitemsCreateSuite(); TestStaticCairoTextCreateSuite(); TestUBusCreateSuite(); diff --git a/tests/unit/TestQuicklistMenuitems.cpp b/tests/unit/TestQuicklistMenuitems.cpp deleted file mode 100644 index 1d29f0c08..000000000 --- a/tests/unit/TestQuicklistMenuitems.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2010 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY 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 - * version 3 along with this program. If not, see - * <http://www.gnu.org/licenses/> - * - * Authored by: Mirco Müller <mirco.mueller@canonical.com> - * - */ - -#include "config.h" - -#include "QuicklistMenuItem.h" -#include "QuicklistMenuItemCheckmark.h" -#include "QuicklistMenuItemLabel.h" -#include "QuicklistMenuItemRadio.h" -#include "QuicklistMenuItemSeparator.h" - -#include "Nux/Nux.h" -#include "Nux/VLayout.h" -#include "Nux/HLayout.h" -#include "Nux/WindowThread.h" -#include "Nux/WindowCompositor.h" -#include "Nux/BaseWindow.h" - -#include "QuicklistView.h" -#include "TestThreadHelper.h" - -using unity::QuicklistView; -using unity::QuicklistMenuItem; -using unity::QuicklistMenuItemCheckmark; -using unity::QuicklistMenuItemLabel; -using unity::QuicklistMenuItemRadio; -using unity::QuicklistMenuItemSeparator; - -static void TestMenuItemCheckmark(void); -static void TestMenuItemLabel(void); -static void TestMenuItemRadio(void); -static void TestMenuItemSeparator(void); -static void TestQuicklistMenuItem(void); - -nux::WindowThread* thread = NULL; - -void -TestQuicklistMenuitemsCreateSuite() -{ -#define _DOMAIN "/Unit/QuicklistMenuitems" - - g_test_add_func(_DOMAIN"/MenuItemCheckmark", TestMenuItemCheckmark); - g_test_add_func(_DOMAIN"/MenuItemLabel", TestMenuItemLabel); - g_test_add_func(_DOMAIN"/MenuItemRadio", TestMenuItemRadio); - g_test_add_func(_DOMAIN"/MenuItemSeparator", TestMenuItemSeparator); - g_test_add_func(_DOMAIN"/QuicklistMenuItem", TestQuicklistMenuItem); -} - -static void -TestMenuItemCheckmark() -{ - DbusmenuMenuitem* item = NULL; - - - item = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set(item, - DBUSMENU_MENUITEM_PROP_LABEL, - "Unchecked"); - - dbusmenu_menuitem_property_set(item, - DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, - DBUSMENU_MENUITEM_TOGGLE_CHECK); - - dbusmenu_menuitem_property_set_bool(item, - DBUSMENU_MENUITEM_PROP_ENABLED, - false); - - dbusmenu_menuitem_property_set_int(item, - DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, - DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); - - QuicklistMenuItemCheckmark* qlCheckmarkItem = NULL; - - qlCheckmarkItem = new QuicklistMenuItemCheckmark(item, true); - - g_assert_cmpstr(qlCheckmarkItem->GetLabel(), == , "Unchecked"); - g_assert_cmpint(qlCheckmarkItem->GetEnabled(), == , false); - g_assert_cmpint(qlCheckmarkItem->GetActive(), == , false); - g_assert_cmpint(qlCheckmarkItem->GetSelectable(), == , false); - g_assert_cmpint(qlCheckmarkItem->IsMarkupEnabled(), == , false); - - //qlCheckmarkItem->sigChanged.connect (sigc::mem_fun (pointerToCallerClass, - // &CallerClass::RecvChanged)); - - - qlCheckmarkItem->Dispose(); - g_object_unref(item); -} - -static void -TestMenuItemLabel() -{ - DbusmenuMenuitem* item = NULL; - - item = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set(item, - DBUSMENU_MENUITEM_PROP_LABEL, - "A Label"); - - dbusmenu_menuitem_property_set_bool(item, - DBUSMENU_MENUITEM_PROP_ENABLED, - true); - - dbusmenu_menuitem_property_set_bool(item, - "unity-use-markup", - true); - - QuicklistMenuItemLabel* qlLabelItem = NULL; - - qlLabelItem = new QuicklistMenuItemLabel(item, true); - - g_assert_cmpstr(qlLabelItem->GetLabel(), == , "A Label"); - g_assert_cmpint(qlLabelItem->GetEnabled(), == , true); - g_assert_cmpint(qlLabelItem->GetSelectable(), == , true); - g_assert_cmpint(qlLabelItem->IsMarkupEnabled(), == , true); - - //qlLabelItem->sigChanged.connect (sigc::mem_fun (pointerToCallerClass, - // &CallerClass::RecvChanged)); - - qlLabelItem->Dispose(); - g_object_unref(item); -} - -static void -TestMenuItemRadio() -{ - DbusmenuMenuitem* item = NULL; - - item = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set(item, - DBUSMENU_MENUITEM_PROP_LABEL, - "Radio Active"); - - dbusmenu_menuitem_property_set(item, - DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, - DBUSMENU_MENUITEM_TOGGLE_RADIO); - - dbusmenu_menuitem_property_set_bool(item, - DBUSMENU_MENUITEM_PROP_ENABLED, - true); - - dbusmenu_menuitem_property_set_int(item, - DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, - DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); - - QuicklistMenuItemRadio* qlRadioItem = NULL; - - qlRadioItem = new QuicklistMenuItemRadio(item, true); - qlRadioItem->EnableLabelMarkup(true); - - g_assert_cmpstr(qlRadioItem->GetLabel(), == , "Radio Active"); - g_assert_cmpint(qlRadioItem->GetEnabled(), == , true); - g_assert_cmpint(qlRadioItem->GetActive(), == , true); - g_assert_cmpint(qlRadioItem->GetSelectable(), == , true); - g_assert_cmpint(qlRadioItem->IsMarkupEnabled(), == , true); - - //qlRadioItem->sigChanged.connect (sigc::mem_fun (pointerToCallerClass, - // &CallerClass::RecvChanged)); - - qlRadioItem->Dispose(); - g_object_unref(item); -} - -static void -TestMenuItemSeparator() -{ - DbusmenuMenuitem* item = NULL; - - item = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_property_set(item, - "type", - DBUSMENU_CLIENT_TYPES_SEPARATOR); - - dbusmenu_menuitem_property_set_bool(item, - DBUSMENU_MENUITEM_PROP_ENABLED, - true); - - QuicklistMenuItemSeparator* qlSeparatorItem = NULL; - - qlSeparatorItem = new QuicklistMenuItemSeparator(item, true); - - g_assert_cmpint(qlSeparatorItem->GetEnabled(), == , true); - g_assert_cmpint(qlSeparatorItem->GetSelectable(), == , false); - - qlSeparatorItem->Dispose(); - g_object_unref(item); -} - -static void -TestQuicklistMenuItem() -{ - DbusmenuMenuitem* root = dbusmenu_menuitem_new(); - - dbusmenu_menuitem_set_root(root, true); - - DbusmenuMenuitem* child = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_MENUITEM_PROP_LABEL); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "label 0"); - dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_child_append(root, child); - - child = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_child_append(root, child); - - child = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_MENUITEM_PROP_LABEL); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "label 1"); - dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_child_append(root, child); - - child = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK); - dbusmenu_menuitem_property_set(child, DBUSMENU_MENUITEM_PROP_LABEL, "check mark 0"); - dbusmenu_menuitem_property_set_bool(child, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_property_set_int(child, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); - dbusmenu_menuitem_child_append(root, child); - - QuicklistView* quicklist = new QuicklistView(); - - quicklist->TestMenuItems(root); - - g_assert_cmpint(quicklist->GetNumItems(), == , 4); - g_assert_cmpint(quicklist->GetNthType(0), == , unity::MENUITEM_TYPE_LABEL); - g_assert_cmpint(quicklist->GetNthType(1), == , unity::MENUITEM_TYPE_SEPARATOR); - g_assert_cmpint(quicklist->GetNthType(2), == , unity::MENUITEM_TYPE_LABEL); - g_assert_cmpint(quicklist->GetNthType(3), == , unity::MENUITEM_TYPE_CHECK); - - g_assert_cmpstr(quicklist->GetNthItems(0)->GetLabel(), == , "label 0"); - g_assert_cmpstr(quicklist->GetNthItems(2)->GetLabel(), == , "label 1"); - g_assert_cmpstr(quicklist->GetNthItems(3)->GetLabel(), == , "check mark 0"); - - g_assert_cmpint(quicklist->GetChildren().size(), == , 4); - - quicklist->Dispose(); -} |
