Merge lp:~unity-api-team/unity-scopes-shell/scope-harness into lp:unity-scopes-shell

Proposed by Pete Woods
Status: Merged
Approved by: Pete Woods
Approved revision: 247
Merged at revision: 200
Proposed branch: lp:~unity-api-team/unity-scopes-shell/scope-harness
Merge into: lp:unity-scopes-shell
Diff against target: 11336 lines (+8276/-1417)
95 files modified
CMakeLists.txt (+6/-5)
cmake/modules/QtWithObjectTarget.cmake (+13/-0)
data/CMakeLists.txt (+10/-0)
data/libscope-harness.pc.in (+10/-0)
debian/control (+22/-0)
debian/libscope-harness-dev.install (+3/-0)
debian/libscope-harness1.install (+1/-0)
debian/rules (+4/-2)
debian/unity-plugin-scopes.install (+2/-0)
po/unity-plugin-scopes.pot (+1/-1)
src/CMakeLists.txt (+30/-0)
src/Unity/CMakeLists.txt (+42/-17)
src/Unity/categories.cpp (+26/-2)
src/Unity/categories.h (+7/-0)
src/Unity/overviewscope.cpp (+6/-1)
src/Unity/overviewscope.h (+5/-1)
src/Unity/previewmodel.cpp (+1/-1)
src/Unity/resultsmodel.cpp (+1/-1)
src/Unity/scope.cpp (+42/-23)
src/Unity/scope.h (+12/-4)
src/Unity/scopes.cpp (+55/-30)
src/Unity/scopes.h (+17/-10)
src/Unity/utils.cpp (+1/-1)
src/scope-harness/CMakeLists.txt (+95/-0)
src/scope-harness/internal/category-arguments.h (+53/-0)
src/scope-harness/internal/child-department-arguments.h (+45/-0)
src/scope-harness/internal/department-arguments.h (+42/-0)
src/scope-harness/internal/preview-widget-arguments.h (+59/-0)
src/scope-harness/internal/preview-widget-list-arguments.h (+38/-0)
src/scope-harness/internal/result-arguments.h (+60/-0)
src/scope-harness/internal/results-view-arguments.h (+41/-0)
src/scope-harness/internal/signal-handler.cpp (+107/-0)
src/scope-harness/internal/signal-handler.h (+63/-0)
src/scope-harness/internal/test-utils.cpp (+80/-42)
src/scope-harness/internal/test-utils.h (+47/-39)
src/scope-harness/matcher/category-list-matcher.cpp (+182/-0)
src/scope-harness/matcher/category-list-matcher.h (+78/-0)
src/scope-harness/matcher/category-matcher.cpp (+334/-0)
src/scope-harness/matcher/category-matcher.h (+93/-0)
src/scope-harness/matcher/child-department-matcher.cpp (+161/-0)
src/scope-harness/matcher/child-department-matcher.h (+69/-0)
src/scope-harness/matcher/department-matcher.cpp (+307/-0)
src/scope-harness/matcher/department-matcher.h (+90/-0)
src/scope-harness/matcher/match-result.cpp (+97/-0)
src/scope-harness/matcher/match-result.h (+65/-0)
src/scope-harness/matcher/preview-column-matcher.cpp (+108/-0)
src/scope-harness/matcher/preview-column-matcher.h (+64/-0)
src/scope-harness/matcher/preview-matcher.cpp (+106/-0)
src/scope-harness/matcher/preview-matcher.h (+63/-0)
src/scope-harness/matcher/preview-widget-matcher.cpp (+161/-0)
src/scope-harness/matcher/preview-widget-matcher.h (+71/-0)
src/scope-harness/matcher/result-matcher.cpp (+317/-0)
src/scope-harness/matcher/result-matcher.h (+90/-0)
src/scope-harness/matcher/scope-uri.cpp (+133/-0)
src/scope-harness/matcher/scope-uri.h (+62/-0)
src/scope-harness/preview/preview-widget-list.cpp (+105/-0)
src/scope-harness/preview/preview-widget-list.h (+73/-0)
src/scope-harness/preview/preview-widget.cpp (+140/-0)
src/scope-harness/preview/preview-widget.h (+76/-0)
src/scope-harness/registry/custom-registry-main.cpp (+53/-0)
src/scope-harness/registry/custom-registry.cpp (+262/-0)
src/scope-harness/registry/custom-registry.h (+93/-0)
src/scope-harness/registry/pre-existing-registry.cpp (+108/-0)
src/scope-harness/registry/pre-existing-registry.h (+57/-0)
src/scope-harness/registry/registry.h (+55/-0)
src/scope-harness/registry/system-registry.cpp (+42/-0)
src/scope-harness/registry/system-registry.h (+52/-0)
src/scope-harness/results/category.cpp (+158/-0)
src/scope-harness/results/category.h (+87/-0)
src/scope-harness/results/child-department.cpp (+108/-0)
src/scope-harness/results/child-department.h (+74/-0)
src/scope-harness/results/department.cpp (+146/-0)
src/scope-harness/results/department.h (+91/-0)
src/scope-harness/results/result.cpp (+352/-0)
src/scope-harness/results/result.h (+99/-0)
src/scope-harness/scope-harness.cpp (+112/-0)
src/scope-harness/scope-harness.h (+69/-0)
src/scope-harness/view/abstract-view.h (+52/-0)
src/scope-harness/view/preview-view.cpp (+167/-0)
src/scope-harness/view/preview-view.h (+90/-0)
src/scope-harness/view/results-view.cpp (+449/-0)
src/scope-harness/view/results-view.h (+143/-0)
tests/CMakeLists.txt (+8/-29)
tests/data/CMakeLists.txt (+1/-1)
tests/data/mock-scope-departments/mock-scope-departments.cpp (+1/-1)
tests/data/mock-scope/mock-scope.cpp (+11/-0)
tests/data/scopes/scopes.cpp (+2/-2)
tests/departmentstest.cpp (+265/-283)
tests/favoritestest.cpp (+46/-42)
tests/overviewtest.cpp (+12/-8)
tests/previewtest.cpp (+244/-181)
tests/registry-spawner.cpp (+0/-68)
tests/registry-spawner.h (+0/-40)
tests/resultstest.cpp (+665/-576)
tests/settingsendtoendtest.cpp (+10/-6)
To merge this branch: bzr merge lp:~unity-api-team/unity-scopes-shell/scope-harness
Reviewer Review Type Date Requested Status
dobey (community) Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Paweł Stołowski (community) Approve
Review via email: mp+250612@code.launchpad.net

Commit message

Add test harness for scopes

Description of the change

Add test harness for scopes

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

767 +void Scopes::addTempScope(Scope::Ptr const& scope)

I've found the change from raw ptrs to shared ptrs for temporary scopes problematic - it makes it crash in closeScope() at the moment. closeScope() expects that Scopes object is the owner of all created temporary scopes (it needs to call deleteLater on it), but this cannot be guaranteed with shared pointers (NB, closeScope is exposed to QML via Scope/Scopes interfaces in unity-api).
In general, using shared ptrs to QObjects in Qt is problematic, because all the standard Qt APIs expect raw QObject pointers and it conflicts with Qt's internal semantics of child-parent object relationships and QObject lifetime control.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

693 // we need to delay actual deletion of Scope object so that shell can animate it
694 - QTimer::singleShot(1000 * SCOPE_DELETE_DELAY, (*it), SLOT(deleteLater()));
695 + QTimer::singleShot(1000 * SCOPE_DELETE_DELAY, (*it).data(), SLOT(deleteLater()));
696 it = m_scopes.erase(it);

I think that will not work anymore, because erasing from m_scopes will just invoke deleteLater immediately?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

Great stuff! Proved to work while I worked on python bindings. +1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

Many of the methods added in this code are using typedef types, such as size_t, which the C++ symbol mangling will morph into unsigned long or unsigned int, depending on whether it's on 64-bit or 32-bit. This is causing the symbols check failures in https://code.launchpad.net/~unity-api-team/unity-scopes-shell/harness-symbols/+merge/252323 .

These symbols, which show up as #MISSING# in the failed build console output, need to be changed to use a different type which is stable across architectures.

review: Needs Fixing
Revision history for this message
James Henstridge (jamesh) wrote :

Rodney: why are you marking this MP as needs-fixing if it is the other one that you have an issue with?

Yes, size_t mangles to a different symbol on different architectures. But the branch fixing the symbols addresses that. This is hardly the only library that hits this 32-bit/64-bit difference.

Revision history for this message
dobey (dobey) wrote :

On Wed, 2015-03-18 at 10:17 +0000, James Henstridge wrote:
> Rodney: why are you marking this MP as needs-fixing if it is the other
> one that you have an issue with?
>
> Yes, size_t mangles to a different symbol on different architectures.
> But the branch fixing the symbols addresses that. This is hardly the
> only library that hits this 32-bit/64-bit difference.

This is the branch which introduces the size_t (and this library, and
the symbols file should really be part of this branch, not a separate
one). The correct way to fix this was to use an int and wrap the size_t
exposure out of our own API, using error checking to prevent negative
values or such.

We do have the same issue in other libraries, but that is not an excuse
to keep reintroducing the problem in new libraries we write.

Revision history for this message
Michi Henning (michihenning) wrote :

I agree with the sentiment in general. size_t shouldn't be part of a public API unless it *really* (*really*) means "size of the largest object supported by the implementation". size_t most definitely does *not* mean "non-negative" (and is useless for that, anyway).

People need to learn to hate unsigned. It creates the illusion of something that doesn't exist…

One of the few legitimate uses of unsigned is when bit shifting, to avoid sign extension. Other than that, unsigned creates far more problems than it's worth. (And, in hindsight, having the same single >> operator behave differently depending on the type of its left-hand operand was a thoroughly bad idea. A better language would have different operators for arithmetic shift and logical shift, and a ton of subtle bugs would have been avoided over the past 35 years.)

Revision history for this message
James Henstridge (jamesh) wrote :

If your premise is that size_t should never be used in an API, then I disagree. It is unfortunate that it causes mangling differences, but this is hardly the only package to have to deal with this issue.

The API is simply using size_t where the underlying STL containers use it too, which seems sensible.

Revision history for this message
Michi Henning (michihenning) wrote :

size_t *could* be used in an API, if it really happens to mean "largest size of an object supported by the implementation". In other words, the same thing as sizeof(something). However, there is nothing to be gained by using size_t; an integer will do the same job more safely.

If size_t is used to indicate something like "number of things in this container", size_t is always the wrong type. If anything, in that case, it should be int (or, if I really want to insist on using an unsigned type), unsigned. With int and unsigned, there are no surprises with implementation-defined types.

Note that STL containers do *not* use size_t for things like counts. They use size_type instead. size_type sometimes happens to be defined as size_t beneath the covers. If so, it's just as wrong, because that introduces the exact same problem we ran into here...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-02-03 07:32:37 +0000
3+++ CMakeLists.txt 2015-03-04 08:54:34 +0000
4@@ -1,10 +1,5 @@
5 cmake_minimum_required(VERSION 2.8.9)
6
7-# Default install location. Must be set here, before setting the project.
8-if (NOT DEFINED CMAKE_INSTALL_PREFIX)
9- set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "" FORCE)
10-endif()
11-
12 project(unity-scopes-shell C CXX)
13
14 if(${PROJECT_BINARY_DIR} STREQUAL ${PROJECT_SOURCE_DIR})
15@@ -15,6 +10,7 @@
16
17 # Instruct CMake to run moc automatically when needed.
18 set(CMAKE_AUTOMOC ON)
19+set(CMAKE_INCLUDE_CURRENT_DIR ON)
20
21 string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) # Build types should always be lowercase but sometimes they are not.
22
23@@ -45,11 +41,16 @@
24
25 find_package(PkgConfig)
26 find_package(Intltool)
27+find_package(Qt5Concurrent)
28 find_package(Qt5Core)
29 find_package(Qt5DBus)
30 find_package(Qt5Qml)
31 find_package(Qt5Quick)
32 find_package(Qt5Gui)
33+find_package(Boost COMPONENTS regex REQUIRED)
34+
35+pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.6.12)
36+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=6)
37
38 # Standard install paths
39 include(GNUInstallDirs)
40
41=== added file 'cmake/modules/QtWithObjectTarget.cmake'
42--- cmake/modules/QtWithObjectTarget.cmake 1970-01-01 00:00:00 +0000
43+++ cmake/modules/QtWithObjectTarget.cmake 2015-03-04 08:54:34 +0000
44@@ -0,0 +1,13 @@
45+
46+function(object_qt5_use_modules TARGET_NAME)
47+ foreach(_module ${ARGN})
48+ target_include_directories(
49+ ${TARGET_NAME} PRIVATE
50+ $<TARGET_PROPERTY:Qt5::${_module},INTERFACE_INCLUDE_DIRECTORIES>
51+ )
52+ target_compile_definitions(
53+ ${TARGET_NAME} PRIVATE
54+ $<TARGET_PROPERTY:Qt5::${_module},INTERFACE_COMPILE_DEFINITIONS>
55+ )
56+ endforeach()
57+endfunction()
58\ No newline at end of file
59
60=== modified file 'data/CMakeLists.txt'
61--- data/CMakeLists.txt 2013-11-18 17:58:14 +0000
62+++ data/CMakeLists.txt 2015-03-04 08:54:34 +0000
63@@ -1,3 +1,13 @@
64 # Set up package config.
65 configure_file(unity-plugin-scopes.pc.in unity-plugin-scopes.pc @ONLY)
66 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-plugin-scopes.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
67+
68+configure_file(
69+ "libscope-harness.pc.in"
70+ "libscope-harness.pc"
71+ @ONLY
72+)
73+install(
74+ FILES "${CMAKE_CURRENT_BINARY_DIR}/libscope-harness.pc"
75+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
76+)
77\ No newline at end of file
78
79=== added file 'data/libscope-harness.pc.in'
80--- data/libscope-harness.pc.in 1970-01-01 00:00:00 +0000
81+++ data/libscope-harness.pc.in 2015-03-04 08:54:34 +0000
82@@ -0,0 +1,10 @@
83+prefix=@CMAKE_INSTALL_PREFIX@
84+exec_prefix=${prefix}
85+libdir=${exec_prefix}/lib
86+includedir=${exec_prefix}/include
87+
88+Name: libscope-harness
89+Description: Test harness for scopes
90+Version: 1.0
91+Cflags: -I${includedir}
92+Libs: -L${libdir} -lscope-harness
93
94=== modified file 'debian/control'
95--- debian/control 2015-02-12 17:19:29 +0000
96+++ debian/control 2015-03-04 08:54:34 +0000
97@@ -3,6 +3,7 @@
98 Section: libs
99 Build-Depends: cmake,
100 debhelper (>= 9),
101+ libboost-regex-dev,
102 libunity-api-dev (>= 7.96),
103 libunity-scopes-dev (>= 0.6.12~),
104 libgsettings-qt-dev (>= 0.1),
105@@ -44,3 +45,24 @@
106 Replaces: unity8-private (<< 7.84)
107 Description: QML plugin for Scopes
108 Plugin to integrate scopes with the Unity shell
109+
110+Package: libscope-harness1
111+Section: libdevel
112+Architecture: any
113+Multi-Arch: same
114+Depends: ${misc:Depends},
115+ ${shlibs:Depends},
116+Description: Test harness for Unity scopes
117+ Drive Unity scopes with a simple synchronous API. Make assertions
118+ about results. Runtime library.
119+
120+Package: libscope-harness-dev
121+Section: libdevel
122+Architecture: any
123+Multi-Arch: same
124+Depends: ${misc:Depends},
125+ ${shlibs:Depends},
126+ libscope-harness1 (= ${binary:Version})
127+Description: Test harness for Unity scopes
128+ Drive Unity scopes with a simple synchronous API. Make assertions
129+ about results. Development files.
130
131=== added file 'debian/libscope-harness-dev.install'
132--- debian/libscope-harness-dev.install 1970-01-01 00:00:00 +0000
133+++ debian/libscope-harness-dev.install 2015-03-04 08:54:34 +0000
134@@ -0,0 +1,3 @@
135+usr/include/*
136+usr/lib/*/libscope-harness.so
137+usr/lib/*/pkgconfig/libscope-harness.pc
138
139=== added file 'debian/libscope-harness1.install'
140--- debian/libscope-harness1.install 1970-01-01 00:00:00 +0000
141+++ debian/libscope-harness1.install 2015-03-04 08:54:34 +0000
142@@ -0,0 +1,1 @@
143+usr/lib/*/libscope-harness.so.*
144
145=== modified file 'debian/rules'
146--- debian/rules 2014-03-19 16:59:10 +0000
147+++ debian/rules 2015-03-04 08:54:34 +0000
148@@ -1,8 +1,10 @@
149 #!/usr/bin/make -f
150 # -*- makefile -*-
151
152+include /usr/share/dpkg/default.mk
153+
154 # Uncomment this to turn on verbose mode.
155-#export DH_VERBOSE=1
156+export DH_VERBOSE=1
157
158 DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
159 ifneq (,$(findstring powerpc,$(DEB_HOST_GNU_TYPE)))
160@@ -17,4 +19,4 @@
161 dh $@ --parallel --fail-missing
162
163 override_dh_auto_configure:
164- dh_auto_configure -- -DLIBDIR=/usr/lib/$(DEB_HOST_MULTIARCH)
165+ dh_auto_configure -- -DCMAKE_INSTALL_LIBDIR=/usr/lib/$(DEB_HOST_MULTIARCH)
166
167=== added file 'debian/unity-plugin-scopes.install'
168--- debian/unity-plugin-scopes.install 1970-01-01 00:00:00 +0000
169+++ debian/unity-plugin-scopes.install 2015-03-04 08:54:34 +0000
170@@ -0,0 +1,2 @@
171+usr/lib/*/pkgconfig/unity-plugin-scopes.pc
172+usr/lib/*/unity8/*
173
174=== modified file 'po/unity-plugin-scopes.pot'
175--- po/unity-plugin-scopes.pot 2015-02-03 08:28:40 +0000
176+++ po/unity-plugin-scopes.pot 2015-03-04 08:54:34 +0000
177@@ -8,7 +8,7 @@
178 msgstr ""
179 "Project-Id-Version: PACKAGE VERSION\n"
180 "Report-Msgid-Bugs-To: \n"
181-"POT-Creation-Date: 2015-02-03 10:03+0200\n"
182+"POT-Creation-Date: 2015-03-04 08:52+0000\n"
183 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
184 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
185 "Language-Team: LANGUAGE <LL@li.org>\n"
186
187=== modified file 'src/CMakeLists.txt'
188--- src/CMakeLists.txt 2013-11-08 17:01:37 +0000
189+++ src/CMakeLists.txt 2015-03-04 08:54:34 +0000
190@@ -1,2 +1,32 @@
191+
192+# Dependencies
193+pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt)
194+pkg_check_modules(UBUNTU_LOCATION_SERVICE REQUIRED ubuntu-location-service)
195+pkg_check_modules(ONLINE_ACCOUNTS_CLIENT REQUIRED OnlineAccountsClient)
196+pkg_check_modules(UBUNTU_LOCATION_SERVICE REQUIRED ubuntu-location-service)
197+
198+include_directories(
199+ ${UBUNTU_LOCATION_SERVICE_INCLUDE_DIRS}
200+)
201+
202+set(
203+ SCOPES_SHELL_DEPENDENCIES
204+ ${SCOPESLIB_LDFLAGS}
205+ ${GSETTINGSQT_LDFLAGS}
206+ ${U1DB_LDFLAGS}
207+ ${UBUNTU_LOCATION_SERVICE_LDFLAGS}
208+ ${ONLINE_ACCOUNTS_CLIENT_LDFLAGS}
209+)
210+
211+set(
212+ SCOPES_SHELL_QT_DEPENDENCIES
213+ Concurrent
214+ DBus
215+ Gui
216+ Network
217+ Qml
218+)
219+
220 add_subdirectory(Unity)
221+add_subdirectory(scope-harness)
222
223
224=== modified file 'src/Unity/CMakeLists.txt'
225--- src/Unity/CMakeLists.txt 2015-02-13 16:47:34 +0000
226+++ src/Unity/CMakeLists.txt 2015-03-04 08:54:34 +0000
227@@ -1,11 +1,10 @@
228 # export_qmlplugin macro
229 include(Plugins)
230
231+include(QtWithObjectTarget)
232+
233 # Dependencies
234-pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=6)
235-pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.6.12)
236 pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt)
237-pkg_check_modules(UBUNTU_LOCATION_SERVICE REQUIRED ubuntu-location-service)
238 pkg_check_modules(ONLINE_ACCOUNTS_CLIENT REQUIRED OnlineAccountsClient)
239
240 include_directories(
241@@ -14,9 +13,12 @@
242 ${SCOPESLIB_INCLUDE_DIRS}
243 ${GSETTINGSQT_INCLUDE_DIRS}
244 ${U1DB_INCLUDE_DIRS}
245- ${UBUNTU_LOCATION_SERVICE_INCLUDE_DIRS}
246 )
247
248+add_definitions(
249+ -DUNITY_DLL_EXPORTS=1
250+ )
251+
252 set(QMLPLUGIN_SRC
253 categories.cpp
254 collectors.cpp
255@@ -37,7 +39,6 @@
256 settingsmodel.cpp
257 ubuntulocationservice.cpp
258 utils.cpp
259- plugin.cpp
260 iconutils.cpp
261 # We need these headers here so moc runs and we get the moc-stuff
262 # compiled in, otherwise we miss some symbols
263@@ -52,21 +53,45 @@
264 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/SettingsModelInterface.h
265 )
266
267+# Object code library
268+
269+add_library(
270+ Unity-qml-object OBJECT
271+ ${QMLPLUGIN_SRC}
272+)
273+
274+set_target_properties(
275+ Unity-qml-object
276+ PROPERTIES
277+ COMPILE_FLAGS -fPIC
278+)
279+
280+# Work around cmake definciency for using Qt with OBJECT target
281+object_qt5_use_modules(
282+ Unity-qml-object
283+ ${SCOPES_SHELL_QT_DEPENDENCIES}
284+)
285+
286+# Shared library for plugin
287+
288+add_library(
289+ Unity-qml SHARED
290+ $<TARGET_OBJECTS:Unity-qml-object>
291+ plugin.cpp
292+)
293+
294+target_link_libraries(
295+ Unity-qml
296+ ${SCOPES_SHELL_DEPENDENCIES}
297+)
298+
299+qt5_use_modules(
300+ Unity-qml
301+ ${SCOPES_SHELL_QT_DEPENDENCIES}
302+)
303 # Workaround for gcc failure LP: #1417664
304 set_source_files_properties(previewwidgetmodel.cpp PROPERTIES COMPILE_FLAGS -O1)
305
306-add_library(Unity-qml SHARED ${QMLPLUGIN_SRC})
307-
308-target_link_libraries(Unity-qml
309- ${SCOPESLIB_LDFLAGS}
310- ${GSETTINGSQT_LDFLAGS}
311- ${U1DB_LDFLAGS}
312- ${UBUNTU_LOCATION_SERVICE_LDFLAGS}
313- ${ONLINE_ACCOUNTS_CLIENT_LDFLAGS}
314- )
315-
316-qt5_use_modules(Unity-qml Qml Gui DBus Concurrent)
317-
318 # export the qmldir qmltypes and plugin files
319 export_qmlfiles(Unity Unity)
320 export_qmlplugin(Unity 0.2 Unity TARGETS Unity-qml)
321
322=== modified file 'src/Unity/categories.cpp'
323--- src/Unity/categories.cpp 2014-11-24 10:55:37 +0000
324+++ src/Unity/categories.cpp 2015-03-04 08:54:34 +0000
325@@ -247,9 +247,9 @@
326 return true;
327 }
328
329+ scopes::Category::SCPtr m_category;
330 private:
331 static QJsonValue* DEFAULTS;
332- scopes::Category::SCPtr m_category;
333 QString m_catId;
334 QString m_catTitle;
335 QString m_catIcon;
336@@ -512,7 +512,7 @@
337 Categories::data(const QModelIndex& index, int role) const
338 {
339 int row = index.row();
340- if (row >= m_categories.size())
341+ if (row >= m_categories.size() || row < 0)
342 {
343 qWarning() << "Categories::data - invalid index" << row << "size"
344 << m_categories.size();
345@@ -552,11 +552,35 @@
346 }
347 else
348 {
349+ qWarning() << "Category data has no results model" << catData->categoryId();
350 return QVariant();
351 }
352 }
353 case RoleCount:
354 return catData->resultsModelCount();
355+ case RoleResultsSPtr:
356+ {
357+ QSharedPointer<unity::shell::scopes::ResultsModelInterface> resultsModel = catData->resultsModel();
358+ if (resultsModel)
359+ {
360+ return QVariant::fromValue(resultsModel);
361+ }
362+ else
363+ {
364+ return QVariant();
365+ }
366+ }
367+ case RoleCategorySPtr:
368+ {
369+ if (catData->m_category)
370+ {
371+ return QVariant::fromValue(catData->m_category);
372+ }
373+ else
374+ {
375+ return QVariant();
376+ }
377+ }
378 default:
379 return QVariant();
380 }
381
382=== modified file 'src/Unity/categories.h'
383--- src/Unity/categories.h 2014-11-20 13:29:07 +0000
384+++ src/Unity/categories.h 2015-03-04 08:54:34 +0000
385@@ -43,6 +43,12 @@
386 public:
387 explicit Categories(QObject* parent = 0);
388
389+ enum ExtraRoles
390+ {
391+ RoleResultsSPtr = 999998,
392+ RoleCategorySPtr = 999999
393+ };
394+
395 ~Categories();
396
397 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
398@@ -73,5 +79,6 @@
399 } // namespace scopes_ng
400
401 Q_DECLARE_METATYPE(scopes_ng::Categories*)
402+Q_DECLARE_METATYPE(std::shared_ptr<const unity::scopes::Category>)
403
404 #endif // NG_CATEGORIES_H
405
406=== modified file 'src/Unity/overviewscope.cpp'
407--- src/Unity/overviewscope.cpp 2014-10-24 13:20:36 +0000
408+++ src/Unity/overviewscope.cpp 2015-03-04 08:54:34 +0000
409@@ -33,7 +33,12 @@
410
411 using namespace unity;
412
413-OverviewScope::OverviewScope(QObject *parent) : scopes_ng::Scope(parent)
414+QSharedPointer<OverviewScope> OverviewScope::newInstance(scopes_ng::Scopes* parent)
415+{
416+ return QSharedPointer<OverviewScope>(new OverviewScope(parent), &QObject::deleteLater);
417+}
418+
419+OverviewScope::OverviewScope(scopes_ng::Scopes* parent) : scopes_ng::Scope(parent)
420 {
421 m_categories.reset(new OverviewCategories(this));
422
423
424=== modified file 'src/Unity/overviewscope.h'
425--- src/Unity/overviewscope.h 2014-10-24 13:20:36 +0000
426+++ src/Unity/overviewscope.h 2015-03-04 08:54:34 +0000
427@@ -30,7 +30,8 @@
428 Q_OBJECT
429
430 public:
431- explicit OverviewScope(QObject *parent = 0);
432+ static QSharedPointer<OverviewScope> newInstance(scopes_ng::Scopes* parent);
433+
434 virtual ~OverviewScope();
435
436 /* getters */
437@@ -42,6 +43,9 @@
438
439 unity::scopes::ScopeProxy proxy_for_result(unity::scopes::Result::SPtr const& result) const override;
440
441+protected:
442+ explicit OverviewScope(scopes_ng::Scopes* parent);
443+
444 private Q_SLOTS:
445 void metadataChanged();
446
447
448=== modified file 'src/Unity/previewmodel.cpp'
449--- src/Unity/previewmodel.cpp 2014-11-19 13:08:17 +0000
450+++ src/Unity/previewmodel.cpp 2015-03-04 08:54:34 +0000
451@@ -203,7 +203,7 @@
452 for (int i = 0; i < numColumns; i++) {
453 std::vector<std::string> widgetArr(layout.column(i));
454 QStringList widgets;
455- for (unsigned int j = 0; j < widgetArr.size(); j++) {
456+ for (std::size_t j = 0; j < widgetArr.size(); j++) {
457 widgets.append(QString::fromStdString(widgetArr[j]));
458 }
459 widgetsPerColumn.append(widgets);
460
461=== modified file 'src/Unity/resultsmodel.cpp'
462--- src/Unity/resultsmodel.cpp 2014-11-28 08:52:30 +0000
463+++ src/Unity/resultsmodel.cpp 2015-03-04 08:54:34 +0000
464@@ -143,7 +143,7 @@
465
466 QVariantList attributes;
467 scopes::VariantArray arr(v.get_array());
468- for (unsigned i = 0; i < arr.size(); i++) {
469+ for (size_t i = 0; i < arr.size(); i++) {
470 if (arr[i].which() != scopes::Variant::Type::Dict) {
471 continue;
472 }
473
474=== modified file 'src/Unity/scope.cpp'
475--- src/Unity/scope.cpp 2015-02-26 18:02:32 +0000
476+++ src/Unity/scope.cpp 2015-03-04 08:54:34 +0000
477@@ -24,6 +24,7 @@
478 #include "categories.h"
479 #include "collectors.h"
480 #include "previewstack.h"
481+#include "locationservice.h"
482 #include "utils.h"
483 #include "scopes.h"
484 #include "settingsmodel.h"
485@@ -32,8 +33,8 @@
486 #include <QUrl>
487 #include <QUrlQuery>
488 #include <QDebug>
489+#include <QGSettings>
490 #include <QtGui/QDesktopServices>
491-#include <QQmlEngine>
492 #include <QEvent>
493 #include <QMutex>
494 #include <QMutexLocker>
495@@ -45,6 +46,8 @@
496 #include <QLocale>
497 #include <QtConcurrent>
498
499+#include <QQmlEngine>
500+
501 #include <libintl.h>
502
503 #include <online-accounts-client/Setup>
504@@ -71,8 +74,13 @@
505 const int RESULTS_TTL_MEDIUM = 300000; // 5 minutes
506 const int RESULTS_TTL_LARGE = 3600000; // 1 hour
507
508-Scope::Scope(QObject *parent) : unity::shell::scopes::ScopeInterface(parent)
509- , m_query_id(0)
510+Scope::Ptr Scope::newInstance(scopes_ng::Scopes* parent)
511+{
512+ return Scope::Ptr(new Scope(parent), &QObject::deleteLater);
513+}
514+
515+Scope::Scope(scopes_ng::Scopes* parent) :
516+ m_query_id(0)
517 , m_formFactor("phone")
518 , m_isActive(false)
519 , m_searchInProgress(false)
520@@ -86,12 +94,13 @@
521 , m_activationController(new CollectionController)
522 , m_status(Status::Okay)
523 {
524+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
525 m_categories.reset(new Categories(this));
526
527 m_settings = QGSettings::isSchemaInstalled("com.canonical.Unity.Lenses") ? new QGSettings("com.canonical.Unity.Lenses", QByteArray(), this) : nullptr;
528 QObject::connect(m_settings, &QGSettings::changed, this, &Scope::internetFlagChanged);
529
530- setScopesInstance(qobject_cast<scopes_ng::Scopes*>(parent));
531+ setScopesInstance(parent);
532
533 m_typingTimer.setSingleShot(true);
534 if (qEnvironmentVariableIsSet("UNITY_SCOPES_TYPING_TIMEOUT_OVERRIDE"))
535@@ -263,10 +272,13 @@
536 scope = this;
537 } else {
538 // figure out if this scope is already favourited
539- scope = m_scopesInstance->getScopeById(scopeId);
540+ auto tmp = m_scopesInstance->getScopeById(scopeId);
541+ if (tmp) {
542+ scope = tmp.data();
543+ }
544 }
545
546- if (scope != nullptr) {
547+ if (scope) {
548 scope->setCurrentNavigationId(departmentId);
549 scope->setFilterState(query.filter_state());
550 scope->setSearchQuery(searchString);
551@@ -274,25 +286,27 @@
552 if (!scope->searchInProgress()) {
553 scope->invalidateResults();
554 }
555- if (scope != this) Q_EMIT gotoScope(scopeId);
556+ if (scope != this) {
557+ Q_EMIT gotoScope(scopeId);
558+ }
559 } else {
560 // create temp dash page
561 auto meta_sptr = m_scopesInstance->getCachedMetadata(scopeId);
562 if (meta_sptr) {
563- scope = new scopes_ng::Scope(m_scopesInstance);
564- scope->setScopeData(*meta_sptr);
565- scope->setScopesInstance(m_scopesInstance);
566- scope->setCurrentNavigationId(departmentId);
567- scope->setFilterState(query.filter_state());
568- scope->setSearchQuery(searchString);
569- m_scopesInstance->addTempScope(scope);
570- Q_EMIT openScope(scope);
571+ Scope::Ptr newScope = Scope::newInstance(m_scopesInstance);
572+ newScope->setScopeData(*meta_sptr);
573+ newScope->setCurrentNavigationId(departmentId);
574+ newScope->setFilterState(query.filter_state());
575+ newScope->setSearchQuery(searchString);
576+ m_scopesInstance->addTempScope(newScope);
577+ Q_EMIT openScope(newScope.data());
578 } else if (allowDelayedActivation) {
579 // request registry refresh to get the missing metadata
580 m_delayedActivation = std::make_shared<scopes::ActivationResponse>(query);
581 m_scopesInstance->refreshScopeMetadata();
582 } else {
583- qWarning("Unable to find scope \"%s\" after metadata refresh", query.scope_id().c_str());
584+ qWarning("Unable to find scope \"%s\" after metadata refresh", qPrintable(scopeId));
585+ Q_EMIT activationFailed(scopeId);
586 }
587 }
588 }
589@@ -429,12 +443,12 @@
590 }
591 }
592
593-unity::shell::scopes::ScopeInterface* Scope::findTempScope(QString const& id) const
594+Scope::Ptr Scope::findTempScope(QString const& id) const
595 {
596 if (m_scopesInstance) {
597 return m_scopesInstance->findTempScope(id);
598 }
599- return nullptr;
600+ return Scope::Ptr();
601 }
602
603 void Scope::updateNavigationModels(DepartmentNode* rootNode, QMultiMap<QString, Department*>& navigationModels, QString const& activeNavigation)
604@@ -1253,13 +1267,18 @@
605 /*
606 * If it's a scope URI, perform the query, otherwise ask Qt to open it.
607 */
608+ Q_EMIT gotoUri(uri);
609 QUrl url(uri);
610- if (url.scheme() == QLatin1String("scope")) {
611- qDebug() << "Got scope URI" << uri;
612+ if (url.scheme() == QLatin1String("scope"))
613+ {
614 performQuery(uri);
615- } else {
616- qDebug() << "Trying to open" << uri;
617- QDesktopServices::openUrl(url);
618+ }
619+ else
620+ {
621+ if (qEnvironmentVariableIsEmpty("UNITY_SCOPES_NO_OPEN_URL"))
622+ {
623+ QDesktopServices::openUrl(url);
624+ }
625 }
626 }
627
628
629=== modified file 'src/Unity/scope.h'
630--- src/Unity/scope.h 2015-02-26 18:02:32 +0000
631+++ src/Unity/scope.h 2015-03-04 08:54:34 +0000
632@@ -29,7 +29,6 @@
633 #include <QNetworkConfigurationManager>
634 #include <QPointer>
635 #include <QMultiMap>
636-#include <QGSettings>
637 #include <QUuid>
638
639 // scopes
640@@ -44,12 +43,15 @@
641 #include "department.h"
642 #include "locationservice.h"
643
644+class QGSettings;
645+
646 namespace scopes_ng
647 {
648
649 class Categories;
650 class PushEvent;
651 class PreviewStack;
652+class LocationService;
653 class SettingsModel;
654 class Scopes;
655
656@@ -106,7 +108,10 @@
657 Q_OBJECT
658
659 public:
660- explicit Scope(QObject *parent = 0);
661+ typedef QSharedPointer<Scope> Ptr;
662+
663+ static Scope::Ptr newInstance(scopes_ng::Scopes* parent);
664+
665 virtual ~Scope();
666
667 virtual bool event(QEvent* ev) override;
668@@ -163,7 +168,7 @@
669 int queryId() const;
670 bool initialQueryDone() const;
671
672- unity::shell::scopes::ScopeInterface* findTempScope(QString const& id) const;
673+ Scope::Ptr findTempScope(QString const& id) const;
674
675 bool loginToAccount(QString const& scope_id, QString const& service_name, QString const& service_type, QString const& provider_name);
676
677@@ -174,6 +179,7 @@
678 Q_SIGNALS:
679 void resultsDirtyChanged();
680 void favoriteChanged(bool);
681+ void activationFailed(QString const& id);
682
683 private Q_SLOTS:
684 void typingFinished();
685@@ -183,6 +189,8 @@
686 void departmentModelDestroyed(QObject* obj);
687
688 protected:
689+ explicit Scope(scopes_ng::Scopes* parent);
690+
691 void setSearchInProgress(bool searchInProgress);
692 void setStatus(unity::shell::scopes::ScopeInterface::Status status);
693 void invalidateLastSearch();
694@@ -249,7 +257,7 @@
695 QMultiMap<QString, Department*> m_altNavModels;
696 QMap<Department*, QString> m_inverseDepartments;
697 QMetaObject::Connection m_metadataConnection;
698- LocationService::Ptr m_locationService;
699+ QSharedPointer<LocationService> m_locationService;
700 QSharedPointer<LocationService::Token> m_locationToken;
701 QNetworkConfigurationManager m_network_manager;
702 };
703
704=== modified file 'src/Unity/scopes.cpp'
705--- src/Unity/scopes.cpp 2015-02-12 15:34:38 +0000
706+++ src/Unity/scopes.cpp 2015-03-04 08:54:34 +0000
707@@ -27,6 +27,7 @@
708
709 // Qt
710 #include <QDebug>
711+#include <QGSettings>
712 #include <QTimer>
713 #include <QDBusConnection>
714 #include <QProcess>
715@@ -123,10 +124,14 @@
716 QObject::connect(m_dashSettings, &QGSettings::changed, this, &Scopes::dashSettingsChanged);
717 }
718
719- m_overviewScope = new OverviewScope(this);
720+ m_overviewScope = OverviewScope::newInstance(this);
721 m_locationService.reset(new UbuntuLocationService());
722
723 createUserAgentString();
724+
725+ m_scopesToDeleteTimer.setSingleShot(true);
726+ m_scopesToDeleteTimer.setInterval(1000 * SCOPE_DELETE_DELAY);
727+ connect(&m_scopesToDeleteTimer, SIGNAL(timeout()), SLOT(purgeScopesToDelete()));
728 }
729
730 Scopes::~Scopes()
731@@ -142,6 +147,11 @@
732 return m_userAgent;
733 }
734
735+void Scopes::purgeScopesToDelete()
736+{
737+ m_scopesToDelete.clear();
738+}
739+
740 int Scopes::rowCount(const QModelIndex& parent) const
741 {
742 Q_UNUSED(parent)
743@@ -294,8 +304,8 @@
744 // add all visible scopes
745 for (auto it = scopes.begin(); it != scopes.end(); ++it) {
746 if (!it->second.invisible()) {
747- auto scope = new Scope(this);
748- connect(scope, SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes()));
749+ Scope::Ptr scope = Scope::newInstance(this);
750+ connect(scope.data(), SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes()));
751 scope->setScopeData(it->second);
752 m_scopes.append(scope);
753 }
754@@ -360,7 +370,7 @@
755
756 void Scopes::prepopulateNextScopes()
757 {
758- for (QList<Scope*>::iterator it = m_scopes.begin(); it != m_scopes.end(); it++) {
759+ for (auto it = m_scopes.begin(); it != m_scopes.end(); it++) {
760 // query next two scopes following currently active scope
761 if ((*it)->isActive()) {
762 ++it;
763@@ -432,10 +442,12 @@
764 if (!favScopesLut.contains((*it)->id()))
765 {
766 beginRemoveRows(QModelIndex(), row, row);
767- (*it)->setFavorite(false);
768- //
769+ Scope::Ptr toDelete = *it;
770+ toDelete->setFavorite(false);
771 // we need to delay actual deletion of Scope object so that shell can animate it
772- QTimer::singleShot(1000 * SCOPE_DELETE_DELAY, (*it), SLOT(deleteLater()));
773+ m_scopesToDelete.push_back(toDelete);
774+ // if the timer is already active, we just wait a bit longer, which is no problem
775+ m_scopesToDeleteTimer.start();
776 it = m_scopes.erase(it);
777 endRemoveRows();
778 }
779@@ -457,8 +469,8 @@
780 auto it = m_cachedMetadata.find(fav);
781 if (it != m_cachedMetadata.end())
782 {
783- auto scope = new Scope(this);
784- connect(scope, SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes()));
785+ Scope::Ptr scope = Scope::newInstance(this);
786+ connect(scope.data(), SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes()));
787 scope->setScopeData(*(it.value()));
788 scope->setFavorite(true);
789 beginInsertRows(QModelIndex(), row, row);
790@@ -538,13 +550,13 @@
791 } else if (scopeName == "scopes") {
792 // emitted when smart-scopes proxy or scope registry discovers new scopes
793 refreshScopeMetadata();
794- Q_FOREACH(Scope* scope, m_scopes) {
795+ Q_FOREACH(Scope::Ptr scope, m_scopes) {
796 scope->invalidateResults();
797 }
798 return;
799 }
800
801- Scope* scope = getScopeById(scopeName);
802+ auto scope = getScopeById(scopeName);
803 if (scope == nullptr) {
804 // check temporary scopes
805 scope = qobject_cast<Scope*>(findTempScope(scopeName));
806@@ -567,11 +579,11 @@
807 return QVariant();
808 }
809
810- Scope* scope = m_scopes.at(index.row());
811+ Scope::Ptr scope = m_scopes.at(index.row());
812
813 switch (role) {
814 case Scopes::RoleScope:
815- return QVariant::fromValue(scope);
816+ return QVariant::fromValue(scope.data());
817 case Scopes::RoleId:
818 return QString(scope->id());
819 case Scopes::RoleTitle:
820@@ -583,26 +595,31 @@
821
822 unity::shell::scopes::ScopeInterface* Scopes::getScope(int row) const
823 {
824+ return getScopeByRow(row).data();
825+}
826+
827+Scope::Ptr Scopes::getScopeByRow(int row) const
828+{
829 if (row >= m_scopes.size() || row < 0) {
830- return nullptr;
831+ return Scope::Ptr();
832 }
833 return m_scopes[row];
834 }
835
836 unity::shell::scopes::ScopeInterface* Scopes::getScope(const QString& scopeId) const
837 {
838- return getScopeById(scopeId);
839+ return getScopeById(scopeId).data();
840 }
841
842-Scope* Scopes::getScopeById(QString const& scopeId) const
843+Scope::Ptr Scopes::getScopeById(QString const& scopeId) const
844 {
845- Q_FOREACH(Scope* scope, m_scopes) {
846+ Q_FOREACH(Scope::Ptr scope, m_scopes) {
847 if (scope->id() == scopeId) {
848 return scope;
849 }
850 }
851
852- return nullptr;
853+ return Scope::Ptr();
854 }
855
856 QStringList Scopes::getFavoriteIds() const
857@@ -647,26 +664,24 @@
858 }
859 }
860
861-void Scopes::addTempScope(unity::shell::scopes::ScopeInterface* scope)
862+void Scopes::addTempScope(Scope::Ptr const& scope)
863 {
864- m_tempScopes.insert(scope);
865+ m_tempScopes.insert(scope->id(), scope);
866 }
867
868 void Scopes::closeScope(unity::shell::scopes::ScopeInterface* scope)
869 {
870- if (m_tempScopes.remove(scope)) {
871- scope->deleteLater();
872- }
873+ m_tempScopes.remove(scope->id());
874 }
875
876-unity::shell::scopes::ScopeInterface* Scopes::findTempScope(QString const& id) const
877+Scope::Ptr Scopes::findTempScope(QString const& id) const
878 {
879- for (auto s: m_tempScopes) {
880- if (s->id() == id) {
881- return s;
882- }
883+ auto it = m_tempScopes.find(id);
884+ if (it != m_tempScopes.end())
885+ {
886+ return *it;
887 }
888- return nullptr;
889+ return Scope::Ptr();
890 }
891
892 void Scopes::moveFavoriteTo(QString const& scopeId, int index)
893@@ -733,7 +748,17 @@
894
895 unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
896 {
897- return m_loaded ? m_overviewScope : nullptr;
898+ return overviewScopeSPtr().data();
899+}
900+
901+Scope::Ptr Scopes::overviewScopeSPtr() const
902+{
903+ Scope::Ptr result;
904+ if (m_loaded)
905+ {
906+ result = m_overviewScope;
907+ }
908+ return result;
909 }
910
911 bool Scopes::loaded() const
912
913=== modified file 'src/Unity/scopes.h'
914--- src/Unity/scopes.h 2015-02-05 09:25:18 +0000
915+++ src/Unity/scopes.h 2015-03-04 08:54:34 +0000
916@@ -21,8 +21,7 @@
917 #define NG_SCOPES_H
918
919 #include <unity/shell/scopes/ScopesInterface.h>
920-
921-#include "locationservice.h"
922+#include "scope.h"
923
924 // Qt
925 #include <QList>
926@@ -39,9 +38,12 @@
927 #include <unity/scopes/ScopeProxyFwd.h>
928 #include <unity/scopes/ScopeMetadata.h>
929
930+class QGSettings;
931+
932 namespace scopes_ng
933 {
934
935+class LocationService;
936 class Scope;
937 class OverviewScope;
938
939@@ -58,7 +60,8 @@
940 Q_INVOKABLE unity::shell::scopes::ScopeInterface* getScope(int row) const override;
941 Q_INVOKABLE unity::shell::scopes::ScopeInterface* getScope(QString const& scopeId) const override;
942
943- Scope* getScopeById(QString const& scopeId) const;
944+ Scope::Ptr getScopeByRow(int row) const;
945+ Scope::Ptr getScopeById(QString const& scopeId) const;
946 unity::scopes::ScopeMetadata::SPtr getCachedMetadata(QString const& scopeId) const;
947 QMap<QString, unity::scopes::ScopeMetadata::SPtr> getAllMetadata() const;
948 QStringList getFavoriteIds() const;
949@@ -70,12 +73,13 @@
950 bool loaded() const override;
951 int count() const override;
952 unity::shell::scopes::ScopeInterface* overviewScope() const override;
953+ Scope::Ptr overviewScopeSPtr() const;
954
955- LocationService::Ptr locationService() const;
956+ QSharedPointer<LocationService> locationService() const;
957 QString userAgentString() const;
958
959- unity::shell::scopes::ScopeInterface* findTempScope(QString const& id) const;
960- void addTempScope(unity::shell::scopes::ScopeInterface* scope);
961+ Scope::Ptr findTempScope(QString const& id) const;
962+ void addTempScope(Scope::Ptr const& scope);
963 Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override;
964
965 Q_SIGNALS:
966@@ -97,6 +101,7 @@
967 void dpkgFinished();
968 void lsbReleaseFinished();
969 void completeDiscoveryFinished();
970+ void purgeScopesToDelete();
971
972 private:
973 void createUserAgentString();
974@@ -105,22 +110,24 @@
975 static const int SCOPE_DELETE_DELAY;
976 class Priv;
977
978- QList<Scope*> m_scopes;
979+ QList<QSharedPointer<Scope>> m_scopes;
980+ QList<QSharedPointer<Scope>> m_scopesToDelete;
981 bool m_noFavorites;
982 QStringList m_favoriteScopes;
983 QGSettings* m_dashSettings;
984 QMap<QString, unity::scopes::ScopeMetadata::SPtr> m_cachedMetadata;
985- OverviewScope* m_overviewScope;
986+ QSharedPointer<OverviewScope> m_overviewScope;
987 QThread* m_listThread;
988 QList<QPair<QString, QString>> m_versions;
989 QString m_userAgent;
990 bool m_loaded;
991
992- LocationService::Ptr m_locationService;
993+ QSharedPointer<LocationService> m_locationService;
994 QTimer m_startupQueryTimeout;
995+ QTimer m_scopesToDeleteTimer;
996
997 unity::scopes::Runtime::SPtr m_scopesRuntime;
998- QSet<unity::shell::scopes::ScopeInterface*> m_tempScopes;
999+ QMap<QString, Scope::Ptr> m_tempScopes;
1000
1001 std::unique_ptr<Priv> m_priv;
1002 };
1003
1004=== modified file 'src/Unity/utils.cpp'
1005--- src/Unity/utils.cpp 2014-09-04 09:26:58 +0000
1006+++ src/Unity/utils.cpp 2015-03-04 08:54:34 +0000
1007@@ -51,7 +51,7 @@
1008 case scopes::Variant::Type::Array: {
1009 scopes::VariantArray arr(variant.get_array());
1010 QVariantList result_list;
1011- for (unsigned i = 0; i < arr.size(); i++) {
1012+ for (size_t i = 0; i < arr.size(); i++) {
1013 result_list.append(scopeVariantToQVariant(arr[i]));
1014 }
1015 return result_list;
1016
1017=== added directory 'src/scope-harness'
1018=== added file 'src/scope-harness/CMakeLists.txt'
1019--- src/scope-harness/CMakeLists.txt 1970-01-01 00:00:00 +0000
1020+++ src/scope-harness/CMakeLists.txt 2015-03-04 08:54:34 +0000
1021@@ -0,0 +1,95 @@
1022+
1023+set(API_VERSION 1)
1024+set(ABI_VERSION 1)
1025+
1026+_pkgconfig_invoke(libunity-scopes SCOPESLIB SCOPERUNNER_BIN "" --variable=scoperunner_bin )
1027+_pkgconfig_invoke(libunity-scopes SCOPESLIB SCOPEREGISTRY_BIN "" --variable=scoperegistry_bin )
1028+_pkgconfig_invoke(libunity-scopes SCOPESLIB SCOPESDIR "" --variable=scopesdir )
1029+
1030+include_directories(
1031+ ${CMAKE_SOURCE_DIR}/src
1032+ ${SCOPESLIB_INCLUDE_DIRS}
1033+ ${GSETTINGSQT_INCLUDE_DIRS}
1034+ ${Boost_INCLUDE_DIRS}
1035+)
1036+
1037+add_definitions(
1038+ -DSCOPESLIB_SCOPERUNNER_BIN="${SCOPESLIB_SCOPERUNNER_BIN}"
1039+ -DSCOPESLIB_SCOPEREGISTRY_BIN="${SCOPESLIB_SCOPEREGISTRY_BIN}"
1040+ -DSCOPESLIB_SCOPESDIR="${SCOPESLIB_SCOPESDIR}"
1041+ -DDEB_HOST_MULTIARCH="${CMAKE_LIBRARY_ARCHITECTURE}"
1042+)
1043+
1044+# Scope harness library
1045+
1046+add_library(
1047+ scope-harness SHARED
1048+ $<TARGET_OBJECTS:Unity-qml-object>
1049+ internal/signal-handler.cpp
1050+ internal/test-utils.cpp
1051+ matcher/category-matcher.cpp
1052+ matcher/category-list-matcher.cpp
1053+ matcher/child-department-matcher.cpp
1054+ matcher/department-matcher.cpp
1055+ matcher/match-result.cpp
1056+ matcher/preview-matcher.cpp
1057+ matcher/preview-column-matcher.cpp
1058+ matcher/preview-widget-matcher.cpp
1059+ matcher/result-matcher.cpp
1060+ matcher/scope-uri.cpp
1061+ preview/preview-widget.cpp
1062+ preview/preview-widget-list.cpp
1063+ registry/custom-registry.cpp
1064+ registry/pre-existing-registry.cpp
1065+ registry/system-registry.cpp
1066+ results/category.cpp
1067+ results/child-department.cpp
1068+ results/department.cpp
1069+ results/result.cpp
1070+ view/preview-view.cpp
1071+ view/results-view.cpp
1072+ scope-harness.cpp
1073+)
1074+
1075+target_link_libraries(
1076+ scope-harness
1077+ ${SCOPES_SHELL_DEPENDENCIES}
1078+ ${Boost_LIBRARIES}
1079+)
1080+
1081+qt5_use_modules(
1082+ scope-harness
1083+ Test
1084+ ${SCOPES_SHELL_QT_DEPENDENCIES}
1085+)
1086+
1087+set_target_properties(
1088+ scope-harness
1089+ PROPERTIES
1090+ VERSION ${API_VERSION}.0.0
1091+ SOVERSION ${ABI_VERSION}
1092+)
1093+
1094+install(
1095+ TARGETS scope-harness
1096+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
1097+)
1098+
1099+install(
1100+ DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
1101+ DESTINATION "include"
1102+ FILES_MATCHING PATTERN "*.h"
1103+ PATTERN "internal" EXCLUDE
1104+)
1105+
1106+# Custom registry executable
1107+
1108+add_executable(
1109+ custom-registry
1110+ registry/custom-registry-main.cpp
1111+)
1112+
1113+target_link_libraries(
1114+ custom-registry
1115+ scope-harness
1116+)
1117
1118=== added directory 'src/scope-harness/internal'
1119=== added file 'src/scope-harness/internal/category-arguments.h'
1120--- src/scope-harness/internal/category-arguments.h 1970-01-01 00:00:00 +0000
1121+++ src/scope-harness/internal/category-arguments.h 2015-03-04 08:54:34 +0000
1122@@ -0,0 +1,53 @@
1123+/*
1124+ * Copyright (C) 2014 Canonical, Ltd.
1125+ *
1126+ * This library is free software; you can redistribute it and/or modify it under
1127+ * the terms of version 3 of the GNU Lesser General Public License as published
1128+ * by the Free Software Foundation.
1129+ *
1130+ * This library is distributed in the hope that it will be useful, but WITHOUT
1131+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1132+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1133+ * details.
1134+ *
1135+ * You should have received a copy of the GNU Lesser General Public License
1136+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1137+ *
1138+ * Author: Pete Woods <pete.woods@canonical.com>
1139+ */
1140+
1141+#pragma once
1142+
1143+#include <QtGlobal>
1144+#include <QAbstractItemModel>
1145+
1146+#include <vector>
1147+
1148+namespace unity
1149+{
1150+namespace shell
1151+{
1152+namespace scopes
1153+{
1154+ class CategoriesInterface;
1155+}
1156+}
1157+namespace scopeharness
1158+{
1159+namespace results
1160+{
1161+class Result;
1162+}
1163+namespace internal
1164+{
1165+struct CategoryArguments
1166+{
1167+ unity::shell::scopes::CategoriesInterface* categoriesModel;
1168+
1169+ QModelIndex index;
1170+
1171+ std::vector<results::Result> results;
1172+};
1173+}
1174+}
1175+}
1176
1177=== added file 'src/scope-harness/internal/child-department-arguments.h'
1178--- src/scope-harness/internal/child-department-arguments.h 1970-01-01 00:00:00 +0000
1179+++ src/scope-harness/internal/child-department-arguments.h 2015-03-04 08:54:34 +0000
1180@@ -0,0 +1,45 @@
1181+/*
1182+ * Copyright (C) 2014 Canonical, Ltd.
1183+ *
1184+ * This library is free software; you can redistribute it and/or modify it under
1185+ * the terms of version 3 of the GNU Lesser General Public License as published
1186+ * by the Free Software Foundation.
1187+ *
1188+ * This library is distributed in the hope that it will be useful, but WITHOUT
1189+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1190+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1191+ * details.
1192+ *
1193+ * You should have received a copy of the GNU Lesser General Public License
1194+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1195+ *
1196+ * Author: Pete Woods <pete.woods@canonical.com>
1197+ */
1198+
1199+#pragma once
1200+
1201+#include <QSharedPointer>
1202+#include <QAbstractItemModel>
1203+
1204+namespace unity
1205+{
1206+namespace shell
1207+{
1208+namespace scopes
1209+{
1210+ class NavigationInterface;
1211+}
1212+}
1213+namespace scopeharness
1214+{
1215+namespace internal
1216+{
1217+struct ChildDepartmentArguments
1218+{
1219+ QSharedPointer<unity::shell::scopes::NavigationInterface> navigationModel;
1220+
1221+ QModelIndex index;
1222+};
1223+}
1224+}
1225+}
1226
1227=== added file 'src/scope-harness/internal/department-arguments.h'
1228--- src/scope-harness/internal/department-arguments.h 1970-01-01 00:00:00 +0000
1229+++ src/scope-harness/internal/department-arguments.h 2015-03-04 08:54:34 +0000
1230@@ -0,0 +1,42 @@
1231+/*
1232+ * Copyright (C) 2014 Canonical, Ltd.
1233+ *
1234+ * This library is free software; you can redistribute it and/or modify it under
1235+ * the terms of version 3 of the GNU Lesser General Public License as published
1236+ * by the Free Software Foundation.
1237+ *
1238+ * This library is distributed in the hope that it will be useful, but WITHOUT
1239+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1240+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1241+ * details.
1242+ *
1243+ * You should have received a copy of the GNU Lesser General Public License
1244+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1245+ *
1246+ * Author: Pete Woods <pete.woods@canonical.com>
1247+ */
1248+
1249+#pragma once
1250+
1251+#include <QSharedPointer>
1252+
1253+namespace unity
1254+{
1255+namespace shell
1256+{
1257+namespace scopes
1258+{
1259+ class NavigationInterface;
1260+}
1261+}
1262+namespace scopeharness
1263+{
1264+namespace internal
1265+{
1266+struct DepartmentArguments
1267+{
1268+ QSharedPointer<unity::shell::scopes::NavigationInterface> navigationModel;
1269+};
1270+}
1271+}
1272+}
1273
1274=== added file 'src/scope-harness/internal/preview-widget-arguments.h'
1275--- src/scope-harness/internal/preview-widget-arguments.h 1970-01-01 00:00:00 +0000
1276+++ src/scope-harness/internal/preview-widget-arguments.h 2015-03-04 08:54:34 +0000
1277@@ -0,0 +1,59 @@
1278+/*
1279+ * Copyright (C) 2014 Canonical, Ltd.
1280+ *
1281+ * This library is free software; you can redistribute it and/or modify it under
1282+ * the terms of version 3 of the GNU Lesser General Public License as published
1283+ * by the Free Software Foundation.
1284+ *
1285+ * This library is distributed in the hope that it will be useful, but WITHOUT
1286+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1287+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1288+ * details.
1289+ *
1290+ * You should have received a copy of the GNU Lesser General Public License
1291+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1292+ *
1293+ * Author: Pete Woods <pete.woods@canonical.com>
1294+ */
1295+
1296+#pragma once
1297+
1298+#include <QtGlobal>
1299+#include <QAbstractItemModel>
1300+
1301+#include <memory>
1302+
1303+namespace unity
1304+{
1305+namespace shell
1306+{
1307+namespace scopes
1308+{
1309+ class PreviewWidgetModelInterface;
1310+ class PreviewModelInterface;
1311+}
1312+}
1313+namespace scopeharness
1314+{
1315+namespace view
1316+{
1317+class PreviewView;
1318+class ResultsView;
1319+}
1320+namespace internal
1321+{
1322+struct PreviewWidgetArguments
1323+{
1324+ unity::shell::scopes::PreviewWidgetModelInterface* previewWidgetModel;
1325+
1326+ QModelIndex index;
1327+
1328+ unity::shell::scopes::PreviewModelInterface* previewModel;
1329+
1330+ std::shared_ptr<view::ResultsView> resultsView;
1331+
1332+ std::shared_ptr<view::PreviewView> previewView;
1333+};
1334+}
1335+}
1336+}
1337
1338=== added file 'src/scope-harness/internal/preview-widget-list-arguments.h'
1339--- src/scope-harness/internal/preview-widget-list-arguments.h 1970-01-01 00:00:00 +0000
1340+++ src/scope-harness/internal/preview-widget-list-arguments.h 2015-03-04 08:54:34 +0000
1341@@ -0,0 +1,38 @@
1342+/*
1343+ * Copyright (C) 2014 Canonical, Ltd.
1344+ *
1345+ * This library is free software; you can redistribute it and/or modify it under
1346+ * the terms of version 3 of the GNU Lesser General Public License as published
1347+ * by the Free Software Foundation.
1348+ *
1349+ * This library is distributed in the hope that it will be useful, but WITHOUT
1350+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1351+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1352+ * details.
1353+ *
1354+ * You should have received a copy of the GNU Lesser General Public License
1355+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1356+ *
1357+ * Author: Pete Woods <pete.woods@canonical.com>
1358+ */
1359+
1360+#pragma once
1361+
1362+#include <QtGlobal>
1363+#include <QAbstractItemModel>
1364+
1365+#include <scope-harness/preview/preview-widget.h>
1366+
1367+namespace unity
1368+{
1369+namespace scopeharness
1370+{
1371+namespace internal
1372+{
1373+struct PreviewWidgetListArguments
1374+{
1375+ std::vector<preview::PreviewWidget> previewWidgets;
1376+};
1377+}
1378+}
1379+}
1380
1381=== added file 'src/scope-harness/internal/result-arguments.h'
1382--- src/scope-harness/internal/result-arguments.h 1970-01-01 00:00:00 +0000
1383+++ src/scope-harness/internal/result-arguments.h 2015-03-04 08:54:34 +0000
1384@@ -0,0 +1,60 @@
1385+/*
1386+ * Copyright (C) 2014 Canonical, Ltd.
1387+ *
1388+ * This library is free software; you can redistribute it and/or modify it under
1389+ * the terms of version 3 of the GNU Lesser General Public License as published
1390+ * by the Free Software Foundation.
1391+ *
1392+ * This library is distributed in the hope that it will be useful, but WITHOUT
1393+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1394+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1395+ * details.
1396+ *
1397+ * You should have received a copy of the GNU Lesser General Public License
1398+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1399+ *
1400+ * Author: Pete Woods <pete.woods@canonical.com>
1401+ */
1402+
1403+#pragma once
1404+
1405+#include <QtGlobal>
1406+#include <QAbstractItemModel>
1407+#include <QSharedPointer>
1408+
1409+#include <memory>
1410+
1411+namespace unity
1412+{
1413+namespace shell
1414+{
1415+namespace scopes
1416+{
1417+ class ResultsModelInterface;
1418+ class ScopeInterface;
1419+}
1420+}
1421+namespace scopeharness
1422+{
1423+namespace view
1424+{
1425+class PreviewView;
1426+class ResultsView;
1427+}
1428+namespace internal
1429+{
1430+struct ResultArguments
1431+{
1432+ QSharedPointer<unity::shell::scopes::ResultsModelInterface> resultsModel;
1433+
1434+ QSharedPointer<unity::shell::scopes::ScopeInterface> scope;
1435+
1436+ QModelIndex index;
1437+
1438+ std::shared_ptr<view::ResultsView> resultsView;
1439+
1440+ std::shared_ptr<view::PreviewView> previewView;
1441+};
1442+}
1443+}
1444+}
1445
1446=== added file 'src/scope-harness/internal/results-view-arguments.h'
1447--- src/scope-harness/internal/results-view-arguments.h 1970-01-01 00:00:00 +0000
1448+++ src/scope-harness/internal/results-view-arguments.h 2015-03-04 08:54:34 +0000
1449@@ -0,0 +1,41 @@
1450+/*
1451+ * Copyright (C) 2014 Canonical, Ltd.
1452+ *
1453+ * This library is free software; you can redistribute it and/or modify it under
1454+ * the terms of version 3 of the GNU Lesser General Public License as published
1455+ * by the Free Software Foundation.
1456+ *
1457+ * This library is distributed in the hope that it will be useful, but WITHOUT
1458+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1459+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1460+ * details.
1461+ *
1462+ * You should have received a copy of the GNU Lesser General Public License
1463+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1464+ *
1465+ * Author: Pete Woods <pete.woods@canonical.com>
1466+ */
1467+
1468+#pragma once
1469+
1470+#include <QtGlobal>
1471+
1472+#include <memory>
1473+
1474+namespace scopes_ng
1475+{
1476+class Scopes;
1477+}
1478+namespace unity
1479+{
1480+namespace scopeharness
1481+{
1482+namespace internal
1483+{
1484+struct ResultsViewArguments
1485+{
1486+ std::shared_ptr<scopes_ng::Scopes> scopes;
1487+};
1488+}
1489+}
1490+}
1491
1492=== added file 'src/scope-harness/internal/signal-handler.cpp'
1493--- src/scope-harness/internal/signal-handler.cpp 1970-01-01 00:00:00 +0000
1494+++ src/scope-harness/internal/signal-handler.cpp 2015-03-04 08:54:34 +0000
1495@@ -0,0 +1,107 @@
1496+/*
1497+ * Copyright (C) 2014 Canonical, Ltd.
1498+ *
1499+ * This library is free software; you can redistribute it and/or modify it under
1500+ * the terms of version 3 of the GNU Lesser General Public License as published
1501+ * by the Free Software Foundation.
1502+ *
1503+ * This library is distributed in the hope that it will be useful, but WITHOUT
1504+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1505+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1506+ * details.
1507+ *
1508+ * You should have received a copy of the GNU Lesser General Public License
1509+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1510+ *
1511+ * Author: Pete Woods <pete.woods@canonical.com>
1512+ */
1513+
1514+#include <scope-harness/internal/signal-handler.h>
1515+
1516+#include <QCoreApplication>
1517+#include <QDebug>
1518+
1519+#include <csignal>
1520+#include <sys/socket.h>
1521+#include <unistd.h>
1522+
1523+namespace unity
1524+{
1525+namespace scopeharness
1526+{
1527+namespace internal
1528+{
1529+int SignalHandler::sigintFd[2];
1530+
1531+int SignalHandler::sigtermFd[2];
1532+
1533+SignalHandler::SignalHandler(QObject *parent) :
1534+ QObject(parent) {
1535+
1536+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd)) {
1537+ qFatal("Couldn't create INT socketpair");
1538+ }
1539+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd)) {
1540+ qFatal("Couldn't create TERM socketpair");
1541+ }
1542+
1543+ m_socketNotifierInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
1544+ connect(m_socketNotifierInt, &QSocketNotifier::activated, this, &SignalHandler::handleSigInt);
1545+ m_socketNotifierTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
1546+ connect(m_socketNotifierTerm, &QSocketNotifier::activated, this, &SignalHandler::handleSigTerm);
1547+}
1548+
1549+void SignalHandler::intSignalHandler(int) {
1550+ char a = 1;
1551+ ::write(sigintFd[0], &a, sizeof(a));
1552+}
1553+
1554+void SignalHandler::termSignalHandler(int) {
1555+ char a = 1;
1556+ ::write(sigtermFd[0], &a, sizeof(a));
1557+}
1558+
1559+int SignalHandler::setupUnixSignalHandlers() {
1560+ struct sigaction sigint, sigterm;
1561+
1562+ sigint.sa_handler = SignalHandler::intSignalHandler;
1563+ sigemptyset(&sigint.sa_mask);
1564+ sigint.sa_flags = 0;
1565+ sigint.sa_flags |= SA_RESTART;
1566+
1567+ if (sigaction(SIGINT, &sigint, 0) > 0)
1568+ return 1;
1569+
1570+ sigterm.sa_handler = SignalHandler::termSignalHandler;
1571+ sigemptyset(&sigterm.sa_mask);
1572+ sigterm.sa_flags |= SA_RESTART;
1573+
1574+ if (sigaction(SIGTERM, &sigterm, 0) > 0)
1575+ return 2;
1576+
1577+ return 0;
1578+}
1579+
1580+void SignalHandler::handleSigTerm() {
1581+ m_socketNotifierTerm->setEnabled(false);
1582+ char tmp;
1583+ ::read(sigtermFd[1], &tmp, sizeof(tmp));
1584+
1585+ QCoreApplication::exit(0);
1586+
1587+ m_socketNotifierTerm->setEnabled(true);
1588+}
1589+
1590+void SignalHandler::handleSigInt() {
1591+ m_socketNotifierInt->setEnabled(false);
1592+ char tmp;
1593+ ::read(sigintFd[1], &tmp, sizeof(tmp));
1594+
1595+ QCoreApplication::exit(0);
1596+
1597+ m_socketNotifierInt->setEnabled(true);
1598+}
1599+
1600+}
1601+}
1602+}
1603
1604=== added file 'src/scope-harness/internal/signal-handler.h'
1605--- src/scope-harness/internal/signal-handler.h 1970-01-01 00:00:00 +0000
1606+++ src/scope-harness/internal/signal-handler.h 2015-03-04 08:54:34 +0000
1607@@ -0,0 +1,63 @@
1608+/*
1609+ * Copyright (C) 2014 Canonical, Ltd.
1610+ *
1611+ * This library is free software; you can redistribute it and/or modify it under
1612+ * the terms of version 3 of the GNU Lesser General Public License as published
1613+ * by the Free Software Foundation.
1614+ *
1615+ * This library is distributed in the hope that it will be useful, but WITHOUT
1616+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1617+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1618+ * details.
1619+ *
1620+ * You should have received a copy of the GNU Lesser General Public License
1621+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1622+ *
1623+ * Author: Pete Woods <pete.woods@canonical.com>
1624+ */
1625+
1626+#pragma once
1627+
1628+#include <QObject>
1629+#include <QSocketNotifier>
1630+
1631+namespace unity
1632+{
1633+namespace scopeharness
1634+{
1635+namespace internal
1636+{
1637+
1638+class Q_DECL_EXPORT SignalHandler: public QObject
1639+{
1640+Q_OBJECT
1641+
1642+public:
1643+ SignalHandler(QObject *parent = 0);
1644+
1645+ ~SignalHandler() = default;
1646+
1647+ static int setupUnixSignalHandlers();
1648+
1649+protected Q_SLOTS:
1650+ void handleSigInt();
1651+
1652+ void handleSigTerm();
1653+
1654+protected:
1655+ static void intSignalHandler(int unused);
1656+
1657+ static void termSignalHandler(int unused);
1658+
1659+ static int sigintFd[2];
1660+
1661+ static int sigtermFd[2];
1662+
1663+ QSocketNotifier *m_socketNotifierInt;
1664+
1665+ QSocketNotifier *m_socketNotifierTerm;
1666+};
1667+
1668+}
1669+}
1670+}
1671
1672=== renamed file 'tests/test-utils.cpp' => 'src/scope-harness/internal/test-utils.cpp'
1673--- tests/test-utils.cpp 2014-09-24 09:55:13 +0000
1674+++ src/scope-harness/internal/test-utils.cpp 2015-03-04 08:54:34 +0000
1675@@ -1,20 +1,19 @@
1676 /*
1677- * Copyright (C) 2013-2014 Canonical, Ltd.
1678- *
1679- * This program is free software; you can redistribute it and/or modify
1680- * it under the terms of the GNU General Public License as published by
1681- * the Free Software Foundation; version 3.
1682- *
1683- * This program is distributed in the hope that it will be useful,
1684- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1685- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1686- * GNU General Public License for more details.
1687- *
1688- * You should have received a copy of the GNU General Public License
1689+ * Copyright (C) 2014 Canonical, Ltd.
1690+ *
1691+ * This library is free software; you can redistribute it and/or modify it under
1692+ * the terms of version 3 of the GNU Lesser General Public License as published
1693+ * by the Free Software Foundation.
1694+ *
1695+ * This library is distributed in the hope that it will be useful, but WITHOUT
1696+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1697+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1698+ * details.
1699+ *
1700+ * You should have received a copy of the GNU Lesser General Public License
1701 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1702 *
1703- * Authors:
1704- * Michal Hruby <michal.hruby@canonical.com>
1705+ * Author: Pete Woods <pete.woods@canonical.com>
1706 */
1707
1708 #include "test-utils.h"
1709@@ -23,48 +22,71 @@
1710 #include <QTest>
1711 #include <QFile>
1712 #include <QFileInfo>
1713+#include <QGSettings>
1714 #include <QDir>
1715 #include <QProcess>
1716 #include <QThread>
1717 #include <QScopedPointer>
1718 #include <QSignalSpy>
1719
1720-#include <scopes.h>
1721-#include <scope.h>
1722-#include <categories.h>
1723-#include <resultsmodel.h>
1724-#include <previewstack.h>
1725-
1726-using namespace scopes_ng;
1727-
1728-void scopes_ng::checkedFirstResult(Scope* scope, unity::scopes::Result::SPtr& result, bool& success)
1729+#include <Unity/scopes.h>
1730+#include <Unity/scope.h>
1731+#include <Unity/categories.h>
1732+#include <Unity/resultsmodel.h>
1733+#include <Unity/previewstack.h>
1734+
1735+namespace sc = unity::scopes;
1736+namespace ng = scopes_ng;
1737+namespace ss = unity::shell::scopes;
1738+
1739+namespace unity {
1740+namespace scopeharness {
1741+namespace internal {
1742+
1743+void throwIf(bool condition, const std::string& message)
1744+{
1745+ if (condition)
1746+ {
1747+ throw std::domain_error(message);
1748+ }
1749+}
1750+
1751+void throwIfNot(bool condition, const std::string& message)
1752+{
1753+ if (!condition)
1754+ {
1755+ throw std::domain_error(message);
1756+ }
1757+}
1758+
1759+void checkedFirstResult(unity::shell::scopes::CategoriesInterface* categories, sc::Result::SPtr& result, bool& success)
1760 {
1761 // ensure categories have > 0 rows
1762- auto categories = scope->categories();
1763 QVERIFY(categories->rowCount() > 0);
1764- QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults);
1765- QVERIFY(results_var.canConvert<ResultsModel*>());
1766+ QVariant results_var = categories->data(categories->index(0), ng::Categories::Roles::RoleResults);
1767+ QVERIFY(results_var.canConvert<ng::ResultsModel*>());
1768
1769 // ensure results have some data
1770- auto results = results_var.value<ResultsModel*>();
1771+ auto results = results_var.value<ng::ResultsModel*>();
1772+ QVERIFY(results);
1773 QVERIFY(results->rowCount() > 0);
1774- auto result_var = results->data(results->index(0), ResultsModel::RoleResult);
1775+ auto result_var = results->data(results->index(0), ng::ResultsModel::RoleResult);
1776 QCOMPARE(result_var.isNull(), false);
1777- result = result_var.value<std::shared_ptr<unity::scopes::Result>>();
1778+ result = result_var.value<std::shared_ptr<sc::Result>>();
1779 success = true;
1780 }
1781
1782-bool scopes_ng::getFirstResult(Scope* scope, unity::scopes::Result::SPtr& result)
1783+bool getFirstResult(unity::shell::scopes::CategoriesInterface* categories, sc::Result::SPtr& result)
1784 {
1785 bool success = false;
1786- checkedFirstResult(scope, result, success);
1787+ checkedFirstResult(categories, result, success);
1788 return success;
1789 }
1790
1791-void scopes_ng::refreshSearch(Scope* scope)
1792+void refreshSearch(ng::Scope::Ptr scope)
1793 {
1794 QCOMPARE(scope->searchInProgress(), false);
1795- QSignalSpy spy(scope, SIGNAL(searchInProgressChanged()));
1796+ QSignalSpy spy(scope.data(), SIGNAL(searchInProgressChanged()));
1797 // refresh the search
1798 scope->refresh();
1799 QVERIFY(scope->searchInProgress() || spy.count() > 1);
1800@@ -75,10 +97,10 @@
1801 QCOMPARE(scope->searchInProgress(), false);
1802 }
1803
1804-void scopes_ng::performSearch(Scope* scope, QString const& searchString)
1805+void performSearch(QSharedPointer<ss::ScopeInterface> scope, QString const& searchString)
1806 {
1807 QCOMPARE(scope->searchInProgress(), false);
1808- QSignalSpy spy(scope, SIGNAL(searchInProgressChanged()));
1809+ QSignalSpy spy(scope.data(), SIGNAL(searchInProgressChanged()));
1810 // perform a search
1811 scope->setSearchQuery(searchString);
1812 // search should not be happening yet
1813@@ -91,11 +113,11 @@
1814 QCOMPARE(scope->searchInProgress(), false);
1815 }
1816
1817-void scopes_ng::waitForResultsChange(Scope* scope)
1818+void waitForResultsChange(QSharedPointer<ss::ScopeInterface> scope)
1819 {
1820 QCOMPARE(scope->searchInProgress(), false);
1821 // wait for the search to finish
1822- QSignalSpy spy(scope, SIGNAL(searchInProgressChanged()));
1823+ QSignalSpy spy(scope.data(), SIGNAL(searchInProgressChanged()));
1824 QVERIFY(spy.wait());
1825 if(spy.size() == 1) {
1826 QVERIFY(spy.wait());
1827@@ -103,26 +125,38 @@
1828 QCOMPARE(scope->searchInProgress(), false);
1829 }
1830
1831-bool scopes_ng::previewForFirstResult(Scope* scope, QString const& searchString, QScopedPointer<PreviewStack>& preview_stack)
1832+void waitForSearchFinish(QSharedPointer<ss::ScopeInterface> scope)
1833+{
1834+ QCOMPARE(scope->searchInProgress(), true);
1835+ QSignalSpy spy(scope.data(), SIGNAL(searchInProgressChanged()));
1836+ QVERIFY(spy.wait());
1837+ if (scope->searchInProgress()) {
1838+ // wait for the search to finish
1839+ QVERIFY(spy.wait());
1840+ }
1841+ QCOMPARE(scope->searchInProgress(), false);
1842+}
1843+
1844+bool previewForFirstResult(ng::Scope::Ptr scope, QString const& searchString, QScopedPointer<ng::PreviewStack>& preview_stack)
1845 {
1846 performSearch(scope, searchString);
1847
1848 unity::scopes::Result::SPtr result;
1849- if (!getFirstResult(scope, result))
1850+ if (!getFirstResult(scope->categories(), result))
1851 return false;
1852- preview_stack.reset(static_cast<PreviewStack*>(scope->preview(QVariant::fromValue(result))));
1853+ preview_stack.reset(static_cast<ng::PreviewStack*>(scope->preview(QVariant::fromValue(result))));
1854
1855 return true;
1856 }
1857
1858-void scopes_ng::setFavouriteScopes(const QStringList& cannedQueries)
1859+void setFavouriteScopes(const QStringList& cannedQueries)
1860 {
1861 setenv("GSETTINGS_BACKEND", "memory", 1);
1862 QGSettings settings("com.canonical.Unity.Dash", QByteArray(), nullptr);
1863 settings.set("favoriteScopes", QVariant(cannedQueries));
1864 }
1865
1866-QStringList scopes_ng::getFavoriteScopes()
1867+QStringList getFavoriteScopes()
1868 {
1869 setenv("GSETTINGS_BACKEND", "memory", 1);
1870 QGSettings settings("com.canonical.Unity.Dash", QByteArray(), nullptr);
1871@@ -132,3 +166,7 @@
1872 }
1873 return favs;
1874 }
1875+
1876+}
1877+}
1878+}
1879
1880=== renamed file 'tests/test-utils.h' => 'src/scope-harness/internal/test-utils.h'
1881--- tests/test-utils.h 2014-09-24 09:55:13 +0000
1882+++ src/scope-harness/internal/test-utils.h 2015-03-04 08:54:34 +0000
1883@@ -1,52 +1,60 @@
1884 /*
1885- * Copyright (C) 2013-2014 Canonical, Ltd.
1886- *
1887- * This program is free software; you can redistribute it and/or modify
1888- * it under the terms of the GNU General Public License as published by
1889- * the Free Software Foundation; version 3.
1890- *
1891- * This program is distributed in the hope that it will be useful,
1892- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1893- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1894- * GNU General Public License for more details.
1895- *
1896- * You should have received a copy of the GNU General Public License
1897+ * Copyright (C) 2014 Canonical, Ltd.
1898+ *
1899+ * This library is free software; you can redistribute it and/or modify it under
1900+ * the terms of version 3 of the GNU Lesser General Public License as published
1901+ * by the Free Software Foundation.
1902+ *
1903+ * This library is distributed in the hope that it will be useful, but WITHOUT
1904+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1905+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1906+ * details.
1907+ *
1908+ * You should have received a copy of the GNU Lesser General Public License
1909 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1910 *
1911- * Authors:
1912- * Michal Hruby <michal.hruby@canonical.com>
1913+ * Author: Pete Woods <pete.woods@canonical.com>
1914 */
1915
1916-#ifndef TEST_UTILS_H
1917-#define TEST_UTILS_H
1918+#pragma once
1919
1920-#include <scope.h>
1921+#include <Unity/scope.h>
1922
1923 #include <unity/scopes/Result.h>
1924
1925 #include <QScopedPointer>
1926 #include <QStringList>
1927
1928-namespace scopes_ng
1929-{
1930-
1931-Q_DECL_EXPORT
1932-void checkedFirstResult(Scope* scope, unity::scopes::Result::SPtr& result, bool& success);
1933-
1934-Q_DECL_EXPORT
1935-bool getFirstResult(Scope* scope, unity::scopes::Result::SPtr& result);
1936-
1937-Q_DECL_EXPORT
1938-void refreshSearch(scopes_ng::Scope*);
1939-
1940-Q_DECL_EXPORT
1941-void performSearch(Scope* scope, QString const& searchString);
1942-
1943-Q_DECL_EXPORT
1944-void waitForResultsChange(Scope* scope);
1945-
1946-Q_DECL_EXPORT
1947-bool previewForFirstResult(Scope* scope, QString const& searchString, QScopedPointer<PreviewStack>& preview_stack);
1948+namespace unity {
1949+namespace scopeharness {
1950+namespace internal {
1951+
1952+Q_DECL_EXPORT
1953+void throwIf(bool condition, const std::string& message);
1954+
1955+Q_DECL_EXPORT
1956+void throwIfNot(bool condition, const std::string& message);
1957+
1958+Q_DECL_EXPORT
1959+void checkedFirstResult(unity::shell::scopes::CategoriesInterface* categories, unity::scopes::Result::SPtr& result, bool& success);
1960+
1961+Q_DECL_EXPORT
1962+bool getFirstResult(unity::shell::scopes::CategoriesInterface* categories, unity::scopes::Result::SPtr& result);
1963+
1964+Q_DECL_EXPORT
1965+void refreshSearch(scopes_ng::Scope::Ptr);
1966+
1967+Q_DECL_EXPORT
1968+void performSearch(QSharedPointer<shell::scopes::ScopeInterface> scope, QString const& searchString);
1969+
1970+Q_DECL_EXPORT
1971+void waitForResultsChange(QSharedPointer<shell::scopes::ScopeInterface> scope);
1972+
1973+Q_DECL_EXPORT
1974+void waitForSearchFinish(QSharedPointer<shell::scopes::ScopeInterface> scope);
1975+
1976+Q_DECL_EXPORT
1977+bool previewForFirstResult(scopes_ng::Scope::Ptr scope, QString const& searchString, QScopedPointer<scopes_ng::PreviewStack>& preview_stack);
1978
1979 Q_DECL_EXPORT
1980 void setFavouriteScopes(const QStringList& cannedQueries);
1981@@ -55,5 +63,5 @@
1982 QStringList getFavoriteScopes();
1983
1984 }
1985-
1986-#endif //TEST_UTILS_H
1987+}
1988+}
1989
1990=== added directory 'src/scope-harness/matcher'
1991=== added file 'src/scope-harness/matcher/category-list-matcher.cpp'
1992--- src/scope-harness/matcher/category-list-matcher.cpp 1970-01-01 00:00:00 +0000
1993+++ src/scope-harness/matcher/category-list-matcher.cpp 2015-03-04 08:54:34 +0000
1994@@ -0,0 +1,182 @@
1995+/*
1996+ * Copyright (C) 2014 Canonical, Ltd.
1997+ *
1998+ * This library is free software; you can redistribute it and/or modify it under
1999+ * the terms of version 3 of the GNU Lesser General Public License as published
2000+ * by the Free Software Foundation.
2001+ *
2002+ * This library is distributed in the hope that it will be useful, but WITHOUT
2003+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2004+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2005+ * details.
2006+ *
2007+ * You should have received a copy of the GNU Lesser General Public License
2008+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2009+ *
2010+ * Author: Pete Woods <pete.woods@canonical.com>
2011+ */
2012+
2013+#include <scope-harness/matcher/category-matcher.h>
2014+#include <scope-harness/matcher/category-list-matcher.h>
2015+
2016+#include <boost/optional.hpp>
2017+
2018+#include <vector>
2019+#include <unordered_map>
2020+
2021+using namespace std;
2022+using namespace boost;
2023+
2024+namespace unity
2025+{
2026+namespace scopeharness
2027+{
2028+namespace matcher
2029+{
2030+
2031+struct CategoryListMatcher::Priv
2032+{
2033+ Mode m_mode = Mode::all;
2034+
2035+ vector<CategoryMatcher> m_categories;
2036+
2037+ optional<size_t> m_hasAtLeast;
2038+
2039+ optional<size_t> m_hasExactly;
2040+
2041+ void all(MatchResult& matchResult, const results::Category::List& categoryList)
2042+ {
2043+ if (categoryList.size() != m_categories.size())
2044+ {
2045+ matchResult.failure(
2046+ "Category list contained " + to_string(categoryList.size())
2047+ + " expected " + to_string(m_categories.size()));
2048+ return;
2049+ }
2050+
2051+ for (size_t row = 0; row < m_categories.size(); ++row)
2052+ {
2053+ const auto& expectedCategory = m_categories[row];
2054+ const auto& actualCategory = categoryList[row];
2055+ expectedCategory.match(matchResult, actualCategory);
2056+ }
2057+ }
2058+
2059+ void byId(MatchResult& matchResult, const results::Category::List& categoryList)
2060+ {
2061+ unordered_map<string, results::Category> categoriesById;
2062+ for (const auto& category : categoryList)
2063+ {
2064+ categoriesById.insert({category.id(), category});
2065+ }
2066+
2067+ for (const auto& expectedCategory : m_categories)
2068+ {
2069+ auto it = categoriesById.find(expectedCategory.getId());
2070+ if (it == categoriesById.end())
2071+ {
2072+ matchResult.failure(
2073+ "Category with ID " + expectedCategory.getId()
2074+ + " could not be found");
2075+ }
2076+ else
2077+ {
2078+ expectedCategory.match(matchResult, it->second);
2079+ }
2080+ }
2081+ }
2082+
2083+ void startsWith(MatchResult& matchResult, const results::Category::List& categoryList)
2084+ {
2085+ if (categoryList.size() < m_categories.size())
2086+ {
2087+ matchResult.failure(
2088+ "Category list contained " + to_string(categoryList.size())
2089+ + " expected at least " + to_string(m_categories.size()));
2090+ return;
2091+ }
2092+
2093+ for (size_t row = 0; row < m_categories.size(); ++row)
2094+ {
2095+ const auto& expectedCategory = m_categories[row];
2096+ const auto& actualCategory = categoryList[row];
2097+ expectedCategory.match(matchResult, actualCategory);
2098+ }
2099+ }
2100+};
2101+
2102+CategoryListMatcher::CategoryListMatcher() :
2103+ p(new Priv)
2104+{
2105+}
2106+
2107+CategoryListMatcher& CategoryListMatcher::mode(CategoryListMatcher::Mode mode)
2108+{
2109+ p->m_mode = mode;
2110+ return *this;
2111+}
2112+
2113+CategoryListMatcher& CategoryListMatcher::category(CategoryMatcher&& categoryMatcher)
2114+{
2115+ p->m_categories.emplace_back(move(categoryMatcher));
2116+ return *this;
2117+}
2118+
2119+CategoryListMatcher& CategoryListMatcher::category(const CategoryMatcher& categoryMatcher)
2120+{
2121+ p->m_categories.emplace_back(categoryMatcher);
2122+ return *this;
2123+}
2124+
2125+CategoryListMatcher& CategoryListMatcher::hasAtLeast(size_t minimum)
2126+{
2127+ p->m_hasAtLeast = minimum;
2128+ return *this;
2129+}
2130+
2131+CategoryListMatcher& CategoryListMatcher::hasExactly(size_t amount)
2132+{
2133+ p->m_hasExactly = amount;
2134+ return *this;
2135+}
2136+
2137+MatchResult CategoryListMatcher::match(const results::Category::List& categoryList) const
2138+{
2139+ MatchResult matchResult;
2140+
2141+ if (p->m_hasAtLeast && categoryList.size() < p->m_hasAtLeast.get())
2142+ {
2143+ matchResult.failure(
2144+ "Expected at least " + to_string(p->m_hasAtLeast.get())
2145+ + " categories");
2146+ }
2147+
2148+ if (p->m_hasExactly && categoryList.size() != p->m_hasExactly.get())
2149+ {
2150+ matchResult.failure(
2151+ "Expected exactly " + to_string(p->m_hasExactly.get())
2152+ + " categories");
2153+ }
2154+
2155+ if (!p->m_categories.empty())
2156+ {
2157+ switch (p->m_mode)
2158+ {
2159+ case Mode::all:
2160+ p->all(matchResult, categoryList);
2161+ break;
2162+ case Mode::by_id:
2163+ p->byId(matchResult, categoryList);
2164+ break;
2165+ case Mode::starts_with:
2166+ p->startsWith(matchResult, categoryList);
2167+ break;
2168+ }
2169+ }
2170+
2171+ return matchResult;
2172+}
2173+
2174+}
2175+}
2176+}
2177
2178=== added file 'src/scope-harness/matcher/category-list-matcher.h'
2179--- src/scope-harness/matcher/category-list-matcher.h 1970-01-01 00:00:00 +0000
2180+++ src/scope-harness/matcher/category-list-matcher.h 2015-03-04 08:54:34 +0000
2181@@ -0,0 +1,78 @@
2182+/*
2183+ * Copyright (C) 2014 Canonical, Ltd.
2184+ *
2185+ * This library is free software; you can redistribute it and/or modify it under
2186+ * the terms of version 3 of the GNU Lesser General Public License as published
2187+ * by the Free Software Foundation.
2188+ *
2189+ * This library is distributed in the hope that it will be useful, but WITHOUT
2190+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2191+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2192+ * details.
2193+ *
2194+ * You should have received a copy of the GNU Lesser General Public License
2195+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2196+ *
2197+ * Author: Pete Woods <pete.woods@canonical.com>
2198+ */
2199+
2200+#pragma once
2201+
2202+#include <scope-harness/results/category.h>
2203+
2204+#include <memory>
2205+#include <string>
2206+
2207+#include <QtGlobal>
2208+
2209+namespace unity
2210+{
2211+namespace scopeharness
2212+{
2213+namespace matcher
2214+{
2215+
2216+class CategoryMatcher;
2217+class ResultsView;
2218+
2219+class Q_DECL_EXPORT CategoryListMatcher final
2220+{
2221+public:
2222+ enum class Mode
2223+ {
2224+ all, by_id, starts_with
2225+ };
2226+
2227+ CategoryListMatcher();
2228+
2229+ ~CategoryListMatcher() = default;
2230+
2231+ CategoryListMatcher& mode(Mode mode);
2232+
2233+ CategoryListMatcher& category(const CategoryMatcher& categoryMatcher);
2234+
2235+ CategoryListMatcher& category(CategoryMatcher&& categoryMatcher);
2236+
2237+ CategoryListMatcher& hasAtLeast(std::size_t minimum);
2238+
2239+ CategoryListMatcher& hasExactly(std::size_t amount);
2240+
2241+ MatchResult match(const results::Category::List& resultList) const;
2242+
2243+protected:
2244+ CategoryListMatcher(const CategoryListMatcher& other) = delete;
2245+
2246+ CategoryListMatcher(CategoryListMatcher&& other) = delete;
2247+
2248+ CategoryListMatcher& operator=(const CategoryListMatcher& other) = delete;
2249+
2250+ CategoryListMatcher& operator=(CategoryListMatcher&& other) = delete;
2251+
2252+ struct Priv;
2253+
2254+ std::shared_ptr<Priv> p;
2255+};
2256+
2257+}
2258+}
2259+}
2260
2261=== added file 'src/scope-harness/matcher/category-matcher.cpp'
2262--- src/scope-harness/matcher/category-matcher.cpp 1970-01-01 00:00:00 +0000
2263+++ src/scope-harness/matcher/category-matcher.cpp 2015-03-04 08:54:34 +0000
2264@@ -0,0 +1,334 @@
2265+/*
2266+ * Copyright (C) 2014 Canonical, Ltd.
2267+ *
2268+ * This library is free software; you can redistribute it and/or modify it under
2269+ * the terms of version 3 of the GNU Lesser General Public License as published
2270+ * by the Free Software Foundation.
2271+ *
2272+ * This library is distributed in the hope that it will be useful, but WITHOUT
2273+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2274+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2275+ * details.
2276+ *
2277+ * You should have received a copy of the GNU Lesser General Public License
2278+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2279+ *
2280+ * Author: Pete Woods <pete.woods@canonical.com>
2281+ */
2282+
2283+#include <scope-harness/internal/test-utils.h>
2284+#include <scope-harness/matcher/category-matcher.h>
2285+#include <scope-harness/matcher/result-matcher.h>
2286+#include <scope-harness/results/category.h>
2287+#include <scope-harness/results/result.h>
2288+
2289+#include <boost/optional.hpp>
2290+#include <boost/regex.hpp>
2291+
2292+#include <unordered_map>
2293+
2294+using namespace std;
2295+using namespace boost;
2296+
2297+namespace sc = unity::scopes;
2298+
2299+namespace unity
2300+{
2301+namespace scopeharness
2302+{
2303+namespace matcher
2304+{
2305+namespace
2306+{
2307+static void check_variant(MatchResult& matchResult, const results::Category& category,
2308+ const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue)
2309+{
2310+ if (!(actualValue == expectedValue))
2311+ {
2312+ auto actualValueString = actualValue.serialize_json();
2313+ auto expectedValueString = expectedValue.serialize_json();
2314+ // serialize_json includes a trailing carriage return
2315+ actualValueString.pop_back();
2316+ expectedValueString.pop_back();
2317+
2318+ matchResult.failure(
2319+ "Category with ID '" + category.id() + "' has '" + name
2320+ + "' == '" + actualValueString + "' but expected '"
2321+ + expectedValueString + "'");
2322+ }
2323+}
2324+
2325+static void check_string(MatchResult& matchResult, const results::Category& category,
2326+ const string& name, const string& actualValue,
2327+ const string& expectedValue)
2328+{
2329+ try
2330+ {
2331+ if (actualValue != expectedValue)
2332+ {
2333+ matchResult.failure(
2334+ "Category with ID '" + category.id() + "' has '" + name
2335+ + "' == '" + actualValue + "' but expected '"
2336+ + expectedValue + "'");
2337+ }
2338+ }
2339+ catch (std::exception& e)
2340+ {
2341+ matchResult.failure(
2342+ "Category with ID '" + category.id()
2343+ + "' does not contain expected property '" + name
2344+ + "'");
2345+ }
2346+}
2347+}
2348+
2349+struct CategoryMatcher::Priv
2350+{
2351+ void all(MatchResult& matchResult, const results::Result::List& resultList)
2352+ {
2353+ if (resultList.size() != m_results.size())
2354+ {
2355+ matchResult.failure(
2356+ "Result list contained " + to_string(resultList.size())
2357+ + " expected " + to_string(m_results.size()));
2358+ return;
2359+ }
2360+
2361+ for (size_t row = 0; row < m_results.size(); ++row)
2362+ {
2363+ const auto& expectedResult = m_results[row];
2364+ const auto& actualResult = resultList[row];
2365+ expectedResult.match(matchResult, actualResult);
2366+ }
2367+ }
2368+
2369+ void startsWith(MatchResult& matchResult, const results::Result::List&resultList)
2370+ {
2371+ if (resultList.size() < m_results.size())
2372+ {
2373+ matchResult.failure(
2374+ "Result list contained " + to_string(resultList.size())
2375+ + " expected at least " + to_string(m_results.size()));
2376+ return;
2377+ }
2378+
2379+ for (size_t row = 0; row < m_results.size(); ++row)
2380+ {
2381+ const auto& expectedResult = m_results[row];
2382+ const auto& actualResult = resultList[row];
2383+ expectedResult.match(matchResult, actualResult);
2384+ }
2385+ }
2386+
2387+ void byUri(MatchResult& matchResult, const results::Result::List& resultList)
2388+ {
2389+ for (const auto& expectedResult : m_results)
2390+ {
2391+ string expectedUri = expectedResult.getUri();
2392+ internal::throwIf(expectedUri.empty(), "Cannot match by_uri with empty expected URI");
2393+
2394+ regex e(expectedUri);
2395+ bool matched = false;
2396+ for (const auto& result : resultList)
2397+ {
2398+ if (regex_match(result.uri(), e)) {
2399+ matched = true;
2400+ expectedResult.match(matchResult, result);
2401+ break;
2402+ }
2403+ }
2404+
2405+ if (!matched)
2406+ {
2407+ matchResult.failure(
2408+ "Result with URI " + expectedResult.getUri()
2409+ + " could not be found");
2410+ }
2411+ }
2412+ }
2413+
2414+ string m_id;
2415+
2416+ Mode m_mode = Mode::all;
2417+
2418+ vector<ResultMatcher> m_results;
2419+
2420+ optional<size_t> m_hasAtLeast;
2421+
2422+ optional<string> m_title;
2423+
2424+ optional<string> m_icon;
2425+
2426+ optional<string> m_headerLink;
2427+
2428+ optional<sc::Variant> m_renderer;
2429+
2430+ optional<sc::Variant> m_components;
2431+};
2432+
2433+CategoryMatcher::CategoryMatcher(const string& id) :
2434+ p(new Priv)
2435+{
2436+ p->m_id = id;
2437+}
2438+
2439+CategoryMatcher::CategoryMatcher(const CategoryMatcher& other) :
2440+ p(new Priv)
2441+{
2442+ *this = other;
2443+}
2444+
2445+CategoryMatcher::CategoryMatcher(CategoryMatcher&& other)
2446+{
2447+ *this = move(other);
2448+}
2449+
2450+CategoryMatcher& CategoryMatcher::operator=(const CategoryMatcher& other)
2451+{
2452+ p->m_id = other.p->m_id;
2453+ p->m_mode = other.p->m_mode;
2454+ p->m_results = other.p->m_results;
2455+ p->m_hasAtLeast = other.p->m_hasAtLeast;
2456+ p->m_title = other.p->m_title;
2457+ p->m_icon = other.p->m_icon;
2458+ p->m_headerLink = other.p->m_headerLink;
2459+ p->m_renderer = other.p->m_renderer;
2460+ p->m_components = other.p->m_components;
2461+ return *this;
2462+}
2463+
2464+CategoryMatcher& CategoryMatcher::operator=(CategoryMatcher&& other)
2465+{
2466+ p = move(other.p);
2467+ return *this;
2468+}
2469+
2470+CategoryMatcher& CategoryMatcher::mode(Mode mode)
2471+{
2472+ p->m_mode = mode;
2473+ return *this;
2474+}
2475+
2476+CategoryMatcher& CategoryMatcher::title(const string& title)
2477+{
2478+ p->m_title = title;
2479+ return *this;
2480+}
2481+
2482+CategoryMatcher& CategoryMatcher::icon(const string& icon)
2483+{
2484+ p->m_icon = icon;
2485+ return *this;
2486+}
2487+
2488+CategoryMatcher& CategoryMatcher::headerLink(const string& headerLink)
2489+{
2490+ p->m_headerLink = headerLink;
2491+ return *this;
2492+}
2493+
2494+CategoryMatcher& CategoryMatcher::hasAtLeast(size_t minimum)
2495+{
2496+ p->m_hasAtLeast = minimum;
2497+ return *this;
2498+}
2499+
2500+CategoryMatcher& CategoryMatcher::renderer(const sc::Variant& renderer)
2501+{
2502+ p->m_renderer = renderer;
2503+ return *this;
2504+}
2505+
2506+CategoryMatcher& CategoryMatcher::components(const sc::Variant& components)
2507+{
2508+ p->m_components = components;
2509+ return *this;
2510+}
2511+
2512+CategoryMatcher& CategoryMatcher::result(const ResultMatcher& resultMatcher)
2513+{
2514+ p->m_results.emplace_back(resultMatcher);
2515+ return *this;
2516+}
2517+
2518+CategoryMatcher& CategoryMatcher::result(ResultMatcher&& resultMatcher)
2519+{
2520+ p->m_results.emplace_back(move(resultMatcher));
2521+ return *this;
2522+}
2523+
2524+void CategoryMatcher::match(MatchResult& matchResult, const results::Category& category) const
2525+{
2526+ auto results = category.results();
2527+
2528+ if (p->m_id != category.id())
2529+ {
2530+ matchResult.failure("Category ID " + category.id() + " != " + p->m_id);
2531+ }
2532+
2533+ if (p->m_hasAtLeast && results.size() < p->m_hasAtLeast.get())
2534+ {
2535+ matchResult.failure(
2536+ "Category with ID " + category.id() + " contains only "
2537+ + to_string(results.size())
2538+ + " results. Expected at least "
2539+ + to_string(p->m_hasAtLeast.get()));
2540+ }
2541+
2542+ if (p->m_title)
2543+ {
2544+ check_string(matchResult, category, "title", category.title(), p->m_title.get());
2545+ }
2546+
2547+ if (p->m_icon)
2548+ {
2549+ check_string(matchResult, category, "icon", category.icon(), p->m_icon.get());
2550+ }
2551+
2552+ if (p->m_headerLink)
2553+ {
2554+ check_string(matchResult, category, "header_link", category.headerLink(), p->m_headerLink.get());
2555+ }
2556+
2557+ if (p->m_renderer)
2558+ {
2559+ check_variant(matchResult, category, "renderer", category.renderer(), p->m_renderer.get());
2560+ }
2561+
2562+ if (p->m_components)
2563+ {
2564+ check_variant(matchResult, category, "components", category.components(), p->m_components.get());
2565+ }
2566+
2567+ if (!p->m_results.empty())
2568+ {
2569+ switch (p->m_mode)
2570+ {
2571+ case Mode::all:
2572+ p->all(matchResult, results);
2573+ break;
2574+ case Mode::starts_with:
2575+ p->startsWith(matchResult, results);
2576+ break;
2577+ case Mode::by_uri:
2578+ p->byUri(matchResult, results);
2579+ break;
2580+ }
2581+ }
2582+}
2583+
2584+MatchResult CategoryMatcher::match(const results::Category& category) const
2585+{
2586+ MatchResult matchResult;
2587+ match(matchResult, category);
2588+ return matchResult;
2589+}
2590+
2591+string& CategoryMatcher::getId() const
2592+{
2593+ return p->m_id;
2594+}
2595+
2596+}
2597+}
2598+}
2599
2600=== added file 'src/scope-harness/matcher/category-matcher.h'
2601--- src/scope-harness/matcher/category-matcher.h 1970-01-01 00:00:00 +0000
2602+++ src/scope-harness/matcher/category-matcher.h 2015-03-04 08:54:34 +0000
2603@@ -0,0 +1,93 @@
2604+/*
2605+ * Copyright (C) 2014 Canonical, Ltd.
2606+ *
2607+ * This library is free software; you can redistribute it and/or modify it under
2608+ * the terms of version 3 of the GNU Lesser General Public License as published
2609+ * by the Free Software Foundation.
2610+ *
2611+ * This library is distributed in the hope that it will be useful, but WITHOUT
2612+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2613+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2614+ * details.
2615+ *
2616+ * You should have received a copy of the GNU Lesser General Public License
2617+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2618+ *
2619+ * Author: Pete Woods <pete.woods@canonical.com>
2620+ */
2621+
2622+#pragma once
2623+
2624+#include <scope-harness/matcher/match-result.h>
2625+
2626+#include <QtGlobal>
2627+
2628+namespace unity
2629+{
2630+namespace scopes
2631+{
2632+class Variant;
2633+}
2634+namespace scopeharness
2635+{
2636+namespace results
2637+{
2638+class Category;
2639+}
2640+namespace matcher
2641+{
2642+class ResultMatcher;
2643+
2644+class Q_DECL_EXPORT CategoryMatcher final
2645+{
2646+public:
2647+ enum class Mode
2648+ {
2649+ all, starts_with, by_uri
2650+ };
2651+
2652+ CategoryMatcher(const std::string& id);
2653+
2654+ CategoryMatcher(const CategoryMatcher& other);
2655+
2656+ CategoryMatcher(CategoryMatcher&& other);
2657+
2658+ CategoryMatcher& operator=(const CategoryMatcher& other);
2659+
2660+ CategoryMatcher& operator=(CategoryMatcher&& other);
2661+
2662+ ~CategoryMatcher() = default;
2663+
2664+ CategoryMatcher& mode(Mode mode);
2665+
2666+ CategoryMatcher& title(const std::string& title);
2667+
2668+ CategoryMatcher& icon(const std::string& icon);
2669+
2670+ CategoryMatcher& headerLink(const std::string& headerLink);
2671+
2672+ CategoryMatcher& hasAtLeast(std::size_t minimum);
2673+
2674+ CategoryMatcher& renderer(const unity::scopes::Variant& renderer);
2675+
2676+ CategoryMatcher& components(const unity::scopes::Variant& components);
2677+
2678+ CategoryMatcher& result(const ResultMatcher& resultMatcher);
2679+
2680+ CategoryMatcher& result(ResultMatcher&& resultMatcher);
2681+
2682+ std::string& getId() const;
2683+
2684+ MatchResult match(const results::Category& category) const;
2685+
2686+ void match(MatchResult& matchResult, const results::Category& category) const;
2687+
2688+protected:
2689+ struct Priv;
2690+
2691+ std::shared_ptr<Priv> p;
2692+};
2693+
2694+}
2695+}
2696+}
2697
2698=== added file 'src/scope-harness/matcher/child-department-matcher.cpp'
2699--- src/scope-harness/matcher/child-department-matcher.cpp 1970-01-01 00:00:00 +0000
2700+++ src/scope-harness/matcher/child-department-matcher.cpp 2015-03-04 08:54:34 +0000
2701@@ -0,0 +1,161 @@
2702+/*
2703+ * Copyright (C) 2014 Canonical, Ltd.
2704+ *
2705+ * This library is free software; you can redistribute it and/or modify it under
2706+ * the terms of version 3 of the GNU Lesser General Public License as published
2707+ * by the Free Software Foundation.
2708+ *
2709+ * This library is distributed in the hope that it will be useful, but WITHOUT
2710+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2711+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2712+ * details.
2713+ *
2714+ * You should have received a copy of the GNU Lesser General Public License
2715+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2716+ *
2717+ * Author: Pete Woods <pete.woods@canonical.com>
2718+ */
2719+
2720+#include <scope-harness/matcher/child-department-matcher.h>
2721+#include <scope-harness/results/child-department.h>
2722+
2723+#include <boost/optional.hpp>
2724+
2725+using namespace std;
2726+using namespace boost;
2727+
2728+namespace unity
2729+{
2730+namespace scopeharness
2731+{
2732+namespace matcher
2733+{
2734+namespace
2735+{
2736+static void check_string(MatchResult& matchResult, const results::ChildDepartment& department,
2737+ const string& name, const string& actualValue,
2738+ const string& expectedValue)
2739+{
2740+ if (actualValue != expectedValue)
2741+ {
2742+ matchResult.failure(
2743+ "Child department with ID '" + department.id() + "' has '" + name
2744+ + "' == '" + actualValue + "' but expected '"
2745+ + expectedValue + "'");
2746+ }
2747+}
2748+
2749+static void check_bool(MatchResult& matchResult, const results::ChildDepartment& department,
2750+ const string& name, bool actualValue,
2751+ bool expectedValue)
2752+{
2753+ if (actualValue != expectedValue)
2754+ {
2755+ matchResult.failure(
2756+ "Child department with ID '" + department.id() + "' has '" + name
2757+ + "' == " + (actualValue ? "true" : "false") + " but expected "
2758+ + (expectedValue ? "true" : "false"));
2759+ }
2760+}
2761+}
2762+
2763+struct ChildDepartmentMatcher::Priv
2764+{
2765+ string m_id;
2766+
2767+ optional<string> m_label;
2768+
2769+ optional<bool> m_hasChildren;
2770+
2771+ optional<bool> m_isActive;
2772+};
2773+
2774+ChildDepartmentMatcher::ChildDepartmentMatcher(const string& id) :
2775+ p(new Priv)
2776+{
2777+ p->m_id = id;
2778+}
2779+
2780+ChildDepartmentMatcher::~ChildDepartmentMatcher()
2781+{
2782+}
2783+
2784+ChildDepartmentMatcher::ChildDepartmentMatcher(const ChildDepartmentMatcher& other) :
2785+ p(new Priv)
2786+{
2787+ *this = other;
2788+}
2789+
2790+ChildDepartmentMatcher::ChildDepartmentMatcher(ChildDepartmentMatcher&& other)
2791+{
2792+ *this = move(other);
2793+}
2794+
2795+ChildDepartmentMatcher& ChildDepartmentMatcher::operator=(const ChildDepartmentMatcher& other)
2796+{
2797+ p->m_id = other.p->m_id;
2798+ p->m_label = other.p->m_label;
2799+ p->m_hasChildren = other.p->m_hasChildren;
2800+ p->m_isActive = other.p->m_isActive;
2801+ return *this;
2802+}
2803+
2804+ChildDepartmentMatcher& ChildDepartmentMatcher::operator=(ChildDepartmentMatcher&& other)
2805+{
2806+ p = move(other.p);
2807+ return *this;
2808+}
2809+
2810+string ChildDepartmentMatcher::getId() const
2811+{
2812+ return p->m_id;
2813+}
2814+
2815+ChildDepartmentMatcher& ChildDepartmentMatcher::label(const std::string& label)
2816+{
2817+ p->m_label = label;
2818+ return *this;
2819+}
2820+
2821+ChildDepartmentMatcher& ChildDepartmentMatcher::hasChildren(bool hasChildren)
2822+{
2823+ p->m_hasChildren = hasChildren;
2824+ return *this;
2825+}
2826+
2827+ChildDepartmentMatcher& ChildDepartmentMatcher::isActive(bool isActive)
2828+{
2829+ p->m_isActive = isActive;
2830+ return *this;
2831+}
2832+
2833+MatchResult ChildDepartmentMatcher::match(const results::ChildDepartment& childDepartment) const
2834+{
2835+ MatchResult matchResult;
2836+ match(matchResult, childDepartment);
2837+ return matchResult;
2838+}
2839+
2840+void ChildDepartmentMatcher::match(MatchResult& matchResult, const results::ChildDepartment& childDepartment) const
2841+{
2842+ check_string(matchResult, childDepartment, "id", childDepartment.id(), p->m_id);
2843+
2844+ if (p->m_label)
2845+ {
2846+ check_string(matchResult, childDepartment, "label", childDepartment.label(), p->m_label.get());
2847+ }
2848+
2849+ if (p->m_hasChildren)
2850+ {
2851+ check_bool(matchResult, childDepartment, "has children", childDepartment.hasChildren(), p->m_hasChildren.get());
2852+ }
2853+
2854+ if (p->m_isActive)
2855+ {
2856+ check_bool(matchResult, childDepartment, "is active", childDepartment.isActive(), p->m_isActive.get());
2857+ }
2858+}
2859+
2860+}
2861+}
2862+}
2863
2864=== added file 'src/scope-harness/matcher/child-department-matcher.h'
2865--- src/scope-harness/matcher/child-department-matcher.h 1970-01-01 00:00:00 +0000
2866+++ src/scope-harness/matcher/child-department-matcher.h 2015-03-04 08:54:34 +0000
2867@@ -0,0 +1,69 @@
2868+/*
2869+ * Copyright (C) 2014 Canonical, Ltd.
2870+ *
2871+ * This library is free software; you can redistribute it and/or modify it under
2872+ * the terms of version 3 of the GNU Lesser General Public License as published
2873+ * by the Free Software Foundation.
2874+ *
2875+ * This library is distributed in the hope that it will be useful, but WITHOUT
2876+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2877+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2878+ * details.
2879+ *
2880+ * You should have received a copy of the GNU Lesser General Public License
2881+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2882+ *
2883+ * Author: Pete Woods <pete.woods@canonical.com>
2884+ */
2885+
2886+#pragma once
2887+
2888+#include <scope-harness/matcher/match-result.h>
2889+
2890+namespace unity
2891+{
2892+namespace scopeharness
2893+{
2894+namespace results
2895+{
2896+class ChildDepartment;
2897+}
2898+namespace matcher
2899+{
2900+
2901+class Q_DECL_EXPORT ChildDepartmentMatcher final
2902+{
2903+public:
2904+ ChildDepartmentMatcher(const std::string& id);
2905+
2906+ ChildDepartmentMatcher(const ChildDepartmentMatcher& other);
2907+
2908+ ChildDepartmentMatcher(ChildDepartmentMatcher&& other);
2909+
2910+ ~ChildDepartmentMatcher();
2911+
2912+ ChildDepartmentMatcher& operator=(const ChildDepartmentMatcher& other);
2913+
2914+ ChildDepartmentMatcher& operator=(ChildDepartmentMatcher&& other);
2915+
2916+ std::string getId() const;
2917+
2918+ ChildDepartmentMatcher& label(const std::string& label);
2919+
2920+ ChildDepartmentMatcher& hasChildren(bool hasChildren);
2921+
2922+ ChildDepartmentMatcher& isActive(bool isActive);
2923+
2924+ MatchResult match(const results::ChildDepartment& childDepartment) const;
2925+
2926+ void match(MatchResult& matchResult, const results::ChildDepartment& childDepartment) const;
2927+
2928+protected:
2929+ struct Priv;
2930+
2931+ std::shared_ptr<Priv> p;
2932+};
2933+
2934+}
2935+}
2936+}
2937
2938=== added file 'src/scope-harness/matcher/department-matcher.cpp'
2939--- src/scope-harness/matcher/department-matcher.cpp 1970-01-01 00:00:00 +0000
2940+++ src/scope-harness/matcher/department-matcher.cpp 2015-03-04 08:54:34 +0000
2941@@ -0,0 +1,307 @@
2942+/*
2943+ * Copyright (C) 2014 Canonical, Ltd.
2944+ *
2945+ * This library is free software; you can redistribute it and/or modify it under
2946+ * the terms of version 3 of the GNU Lesser General Public License as published
2947+ * by the Free Software Foundation.
2948+ *
2949+ * This library is distributed in the hope that it will be useful, but WITHOUT
2950+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2951+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
2952+ * details.
2953+ *
2954+ * You should have received a copy of the GNU Lesser General Public License
2955+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2956+ *
2957+ * Author: Pete Woods <pete.woods@canonical.com>
2958+ */
2959+
2960+#include <scope-harness/results/department.h>
2961+#include <scope-harness/matcher/department-matcher.h>
2962+
2963+#include <boost/optional.hpp>
2964+#include <unordered_map>
2965+
2966+using namespace std;
2967+using namespace boost;
2968+
2969+namespace unity
2970+{
2971+namespace scopeharness
2972+{
2973+namespace matcher
2974+{
2975+namespace
2976+{
2977+static void check_string(MatchResult& matchResult, const results::Department& department,
2978+ const string& name, const string& actualValue,
2979+ const string& expectedValue)
2980+{
2981+ if (actualValue != expectedValue)
2982+ {
2983+ matchResult.failure(
2984+ "Department with ID '" + department.id() + "' has '" + name
2985+ + "' == '" + actualValue + "' but expected '"
2986+ + expectedValue + "'");
2987+ }
2988+}
2989+
2990+static void check_bool(MatchResult& matchResult, const results::Department& department,
2991+ const string& name, bool actualValue,
2992+ bool expectedValue)
2993+{
2994+ if (actualValue != expectedValue)
2995+ {
2996+ matchResult.failure(
2997+ "Department with ID '" + department.id() + "' has '" + name
2998+ + "' == " + (actualValue ? "true" : "false") + " but expected "
2999+ + (expectedValue ? "true" : "false"));
3000+ }
3001+}
3002+}
3003+
3004+struct DepartmentMatcher::Priv
3005+{
3006+ void all(MatchResult& matchResult, const results::Department& department)
3007+ {
3008+ if (department.size() != m_children.size())
3009+ {
3010+ matchResult.failure(
3011+ "Department contained " + to_string(department.size())
3012+ + " children, expected " + to_string(m_children.size()));
3013+ return;
3014+ }
3015+
3016+ for (size_t row = 0; row < m_children.size(); ++row)
3017+ {
3018+ const auto& expectedChild = m_children[row];
3019+ auto actualChild = department.child(row);
3020+ expectedChild.match(matchResult, actualChild);
3021+ }
3022+ }
3023+
3024+ void byId(MatchResult& matchResult, const results::Department& department)
3025+ {
3026+ unordered_map<string, results::ChildDepartment> childDepartmentsById;
3027+ for (size_t row = 0; row < department.size(); ++row)
3028+ {
3029+ auto child = department.child(row);
3030+ childDepartmentsById.insert({child.id(), child});
3031+ }
3032+
3033+ for (const auto& expectedChild : m_children)
3034+ {
3035+ auto it = childDepartmentsById.find(expectedChild.getId());
3036+ if (it == childDepartmentsById.end())
3037+ {
3038+ matchResult.failure(
3039+ "Child department with ID " + expectedChild.getId()
3040+ + " could not be found");
3041+ }
3042+ else
3043+ {
3044+ expectedChild.match(matchResult, it->second);
3045+ }
3046+ }
3047+ }
3048+
3049+ void startsWith(MatchResult& matchResult, const results::Department& department)
3050+ {
3051+ if (department.size() < m_children.size())
3052+ {
3053+ matchResult.failure(
3054+ "Department contained " + to_string(department.size())
3055+ + " expected at least " + to_string(m_children.size()));
3056+ return;
3057+ }
3058+
3059+ for (size_t row = 0; row < m_children.size(); ++row)
3060+ {
3061+ const auto& expectedChild = m_children[row];
3062+ auto actualChild = department.child(row);
3063+ expectedChild.match(matchResult, actualChild);
3064+ }
3065+ }
3066+
3067+ optional<string> m_id;
3068+
3069+ optional<string> m_label;
3070+
3071+ optional<string> m_allLabel;
3072+
3073+ optional<string> m_parentId;
3074+
3075+ optional<string> m_parentLabel;
3076+
3077+ optional<bool> m_isRoot;
3078+
3079+ optional<bool> m_isHidden;
3080+
3081+ optional<size_t> m_hasExactly;
3082+
3083+ optional<size_t> m_hasAtLeast;
3084+
3085+ Mode m_mode = Mode::all;
3086+
3087+ vector<ChildDepartmentMatcher> m_children;
3088+};
3089+
3090+DepartmentMatcher::DepartmentMatcher() :
3091+ p(new Priv)
3092+{
3093+}
3094+
3095+DepartmentMatcher::~DepartmentMatcher()
3096+{
3097+}
3098+
3099+DepartmentMatcher& DepartmentMatcher::mode(Mode mode)
3100+{
3101+ p->m_mode = mode;
3102+ return *this;
3103+}
3104+
3105+DepartmentMatcher& DepartmentMatcher::hasExactly(size_t childCount)
3106+{
3107+ p->m_hasExactly = childCount;
3108+ return *this;
3109+}
3110+
3111+DepartmentMatcher& DepartmentMatcher::hasAtLeast(size_t childCount)
3112+{
3113+ p->m_hasAtLeast = childCount;
3114+ return *this;
3115+}
3116+
3117+DepartmentMatcher& DepartmentMatcher::id(const string& id)
3118+{
3119+ p->m_id = id;
3120+ return *this;
3121+}
3122+
3123+DepartmentMatcher& DepartmentMatcher::label(const string& label)
3124+{
3125+ p->m_label = label;
3126+ return *this;
3127+}
3128+
3129+DepartmentMatcher& DepartmentMatcher::allLabel(const string& allLabel)
3130+{
3131+ p->m_allLabel = allLabel;
3132+ return *this;
3133+}
3134+
3135+DepartmentMatcher& DepartmentMatcher::parentId(const string& parentId)
3136+{
3137+ p->m_parentId = parentId;
3138+ return *this;
3139+}
3140+
3141+DepartmentMatcher& DepartmentMatcher::parentLabel(const string& parentLabel)
3142+{
3143+ p->m_parentLabel = parentLabel;
3144+ return *this;
3145+}
3146+
3147+DepartmentMatcher& DepartmentMatcher::isRoot(bool isRoot)
3148+{
3149+ p->m_isRoot = isRoot;
3150+ return *this;
3151+}
3152+
3153+DepartmentMatcher& DepartmentMatcher::isHidden(bool isHidden)
3154+{
3155+ p->m_isHidden = isHidden;
3156+ return *this;
3157+}
3158+
3159+DepartmentMatcher& DepartmentMatcher::child(const ChildDepartmentMatcher& child)
3160+{
3161+ p->m_children.emplace_back(child);
3162+ return *this;
3163+}
3164+
3165+DepartmentMatcher& DepartmentMatcher::child(ChildDepartmentMatcher&& child)
3166+{
3167+ p->m_children.emplace_back(child);
3168+ return *this;
3169+}
3170+
3171+MatchResult DepartmentMatcher::match(const results::Department& department) const
3172+{
3173+ MatchResult matchResult;
3174+ match(matchResult, department);
3175+ return matchResult;
3176+}
3177+
3178+void DepartmentMatcher::match(MatchResult& matchResult, const results::Department& department) const
3179+{
3180+ if (p->m_id)
3181+ {
3182+ check_string(matchResult, department, "id", department.id(), p->m_id.get());
3183+ }
3184+
3185+ if (p->m_label)
3186+ {
3187+ check_string(matchResult, department, "label", department.label(), p->m_label.get());
3188+ }
3189+
3190+ if (p->m_allLabel)
3191+ {
3192+ check_string(matchResult, department, "all label", department.allLabel(), p->m_allLabel.get());
3193+ }
3194+
3195+ if (p->m_parentId)
3196+ {
3197+ check_string(matchResult, department, "parent ID", department.parentId(), p->m_parentId.get());
3198+ }
3199+
3200+ if (p->m_parentLabel)
3201+ {
3202+ check_string(matchResult, department, "parent label", department.parentLabel(), p->m_parentLabel.get());
3203+ }
3204+
3205+ if (p->m_isRoot)
3206+ {
3207+ check_bool(matchResult, department, "is root", department.isRoot(), p->m_isRoot.get());
3208+ }
3209+
3210+ if (p->m_isHidden)
3211+ {
3212+ check_bool(matchResult, department, "is hidden", department.isHidden(), p->m_isHidden.get());
3213+ }
3214+
3215+ if (p->m_hasExactly && department.size() != p->m_hasExactly.get())
3216+ {
3217+ matchResult.failure(
3218+ "Expected exactly " + to_string(p->m_hasExactly.get())
3219+ + " child departments");
3220+ }
3221+
3222+ if (p->m_hasAtLeast && department.size() < p->m_hasAtLeast.get())
3223+ {
3224+ matchResult.failure(
3225+ "Expected at least " + to_string(p->m_hasAtLeast.get())
3226+ + " child departments");
3227+ }
3228+
3229+ if (!p->m_children.empty())
3230+ {
3231+ switch (p->m_mode)
3232+ {
3233+ case Mode::all:
3234+ p->all(matchResult, department);
3235+ break;
3236+ case Mode::by_id:
3237+ p->byId(matchResult, department);
3238+ break;
3239+ case Mode::starts_with:
3240+ p->startsWith(matchResult, department);
3241+ break;
3242+ }
3243+ }
3244+}
3245+
3246+}
3247+}
3248+}
3249
3250=== added file 'src/scope-harness/matcher/department-matcher.h'
3251--- src/scope-harness/matcher/department-matcher.h 1970-01-01 00:00:00 +0000
3252+++ src/scope-harness/matcher/department-matcher.h 2015-03-04 08:54:34 +0000
3253@@ -0,0 +1,90 @@
3254+/*
3255+ * Copyright (C) 2014 Canonical, Ltd.
3256+ *
3257+ * This library is free software; you can redistribute it and/or modify it under
3258+ * the terms of version 3 of the GNU Lesser General Public License as published
3259+ * by the Free Software Foundation.
3260+ *
3261+ * This library is distributed in the hope that it will be useful, but WITHOUT
3262+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3263+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3264+ * details.
3265+ *
3266+ * You should have received a copy of the GNU Lesser General Public License
3267+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3268+ *
3269+ * Author: Pete Woods <pete.woods@canonical.com>
3270+ */
3271+
3272+#include <scope-harness/matcher/child-department-matcher.h>
3273+
3274+#pragma once
3275+
3276+namespace unity
3277+{
3278+namespace scopeharness
3279+{
3280+namespace results
3281+{
3282+class Department;
3283+}
3284+namespace matcher
3285+{
3286+
3287+class Q_DECL_EXPORT DepartmentMatcher final
3288+{
3289+public:
3290+ enum class Mode
3291+ {
3292+ all, by_id, starts_with
3293+ };
3294+
3295+ DepartmentMatcher();
3296+
3297+ DepartmentMatcher(const DepartmentMatcher& other) = delete;
3298+
3299+ DepartmentMatcher(DepartmentMatcher&& other) = delete;
3300+
3301+ ~DepartmentMatcher();
3302+
3303+ DepartmentMatcher& operator=(const DepartmentMatcher& other) = delete;
3304+
3305+ DepartmentMatcher& operator=(DepartmentMatcher&& other) = delete;
3306+
3307+ DepartmentMatcher& mode(Mode mode);
3308+
3309+ DepartmentMatcher& hasExactly(std::size_t childCount);
3310+
3311+ DepartmentMatcher& hasAtLeast(std::size_t childCount);
3312+
3313+ DepartmentMatcher& id(const std::string& id);
3314+
3315+ DepartmentMatcher& label(const std::string& label);
3316+
3317+ DepartmentMatcher& allLabel(const std::string& allLabel);
3318+
3319+ DepartmentMatcher& parentId(const std::string& parentId);
3320+
3321+ DepartmentMatcher& parentLabel(const std::string& parentLabel);
3322+
3323+ DepartmentMatcher& isRoot(bool isRoot);
3324+
3325+ DepartmentMatcher& isHidden(bool isHidden);
3326+
3327+ DepartmentMatcher& child(const ChildDepartmentMatcher& child);
3328+
3329+ DepartmentMatcher& child(ChildDepartmentMatcher&& child);
3330+
3331+ MatchResult match(const results::Department& department) const;
3332+
3333+ void match(MatchResult& matchResult, const results::Department& department) const;
3334+
3335+protected:
3336+ struct Priv;
3337+
3338+ std::shared_ptr<Priv> p;
3339+};
3340+
3341+}
3342+}
3343+}
3344
3345=== added file 'src/scope-harness/matcher/match-result.cpp'
3346--- src/scope-harness/matcher/match-result.cpp 1970-01-01 00:00:00 +0000
3347+++ src/scope-harness/matcher/match-result.cpp 2015-03-04 08:54:34 +0000
3348@@ -0,0 +1,97 @@
3349+/*
3350+ * Copyright (C) 2014 Canonical, Ltd.
3351+ *
3352+ * This library is free software; you can redistribute it and/or modify it under
3353+ * the terms of version 3 of the GNU Lesser General Public License as published
3354+ * by the Free Software Foundation.
3355+ *
3356+ * This library is distributed in the hope that it will be useful, but WITHOUT
3357+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3358+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3359+ * details.
3360+ *
3361+ * You should have received a copy of the GNU Lesser General Public License
3362+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3363+ *
3364+ * Author: Pete Woods <pete.woods@canonical.com>
3365+ */
3366+
3367+#include <scope-harness/matcher/match-result.h>
3368+
3369+#include <sstream>
3370+
3371+using namespace std;
3372+
3373+namespace unity
3374+{
3375+namespace scopeharness
3376+{
3377+namespace matcher
3378+{
3379+
3380+struct MatchResult::Priv
3381+{
3382+ bool m_success = true;
3383+
3384+ vector<string> m_failures;
3385+};
3386+
3387+MatchResult::MatchResult() :
3388+ p(new Priv)
3389+{
3390+}
3391+
3392+MatchResult::MatchResult(MatchResult&& other)
3393+{
3394+ *this = move(other);
3395+}
3396+
3397+MatchResult::MatchResult(const MatchResult& other) :
3398+ p(new Priv)
3399+{
3400+ *this = other;
3401+}
3402+
3403+MatchResult& MatchResult::operator=(const MatchResult& other)
3404+{
3405+ p->m_success = other.p->m_success;
3406+ p->m_failures= other.p->m_failures;
3407+ return *this;
3408+}
3409+
3410+MatchResult& MatchResult::operator=(MatchResult&& other)
3411+{
3412+ p = move(other.p);
3413+ return *this;
3414+}
3415+
3416+void MatchResult::failure(const string& message)
3417+{
3418+ p->m_success = false;
3419+ p->m_failures.emplace_back(message);
3420+}
3421+
3422+bool MatchResult::success() const
3423+{
3424+ return p->m_success;
3425+}
3426+
3427+vector<string>& MatchResult::failures() const
3428+{
3429+ return p->m_failures;
3430+}
3431+
3432+string MatchResult::concat_failures() const
3433+{
3434+ stringstream ss;
3435+ ss << "Failed expectations:" << endl;
3436+ for (const auto& failure : p->m_failures)
3437+ {
3438+ ss << failure << endl;
3439+ }
3440+ return ss.str();
3441+}
3442+
3443+}
3444+}
3445+}
3446
3447=== added file 'src/scope-harness/matcher/match-result.h'
3448--- src/scope-harness/matcher/match-result.h 1970-01-01 00:00:00 +0000
3449+++ src/scope-harness/matcher/match-result.h 2015-03-04 08:54:34 +0000
3450@@ -0,0 +1,65 @@
3451+/*
3452+ * Copyright (C) 2014 Canonical, Ltd.
3453+ *
3454+ * This library is free software; you can redistribute it and/or modify it under
3455+ * the terms of version 3 of the GNU Lesser General Public License as published
3456+ * by the Free Software Foundation.
3457+ *
3458+ * This library is distributed in the hope that it will be useful, but WITHOUT
3459+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3460+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3461+ * details.
3462+ *
3463+ * You should have received a copy of the GNU Lesser General Public License
3464+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3465+ *
3466+ * Author: Pete Woods <pete.woods@canonical.com>
3467+ */
3468+
3469+#pragma once
3470+
3471+#include <QtGlobal>
3472+
3473+#include <vector>
3474+#include <memory>
3475+#include <string>
3476+
3477+namespace unity
3478+{
3479+namespace scopeharness
3480+{
3481+namespace matcher
3482+{
3483+
3484+class Q_DECL_EXPORT MatchResult final
3485+{
3486+public:
3487+ MatchResult();
3488+
3489+ MatchResult(MatchResult&& other);
3490+
3491+ MatchResult(const MatchResult& other);
3492+
3493+ MatchResult& operator=(const MatchResult& other);
3494+
3495+ MatchResult& operator=(MatchResult&& other);
3496+
3497+ ~MatchResult() = default;
3498+
3499+ void failure(const std::string& message);
3500+
3501+ bool success() const;
3502+
3503+ std::vector<std::string>& failures() const;
3504+
3505+ std::string concat_failures() const;
3506+
3507+protected:
3508+ struct Priv;
3509+
3510+ std::shared_ptr<Priv> p;
3511+};
3512+
3513+}
3514+}
3515+}
3516
3517=== added file 'src/scope-harness/matcher/preview-column-matcher.cpp'
3518--- src/scope-harness/matcher/preview-column-matcher.cpp 1970-01-01 00:00:00 +0000
3519+++ src/scope-harness/matcher/preview-column-matcher.cpp 2015-03-04 08:54:34 +0000
3520@@ -0,0 +1,108 @@
3521+/*
3522+ * Copyright (C) 2014 Canonical, Ltd.
3523+ *
3524+ * This library is free software; you can redistribute it and/or modify it under
3525+ * the terms of version 3 of the GNU Lesser General Public License as published
3526+ * by the Free Software Foundation.
3527+ *
3528+ * This library is distributed in the hope that it will be useful, but WITHOUT
3529+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3530+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3531+ * details.
3532+ *
3533+ * You should have received a copy of the GNU Lesser General Public License
3534+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3535+ *
3536+ * Author: Pete Woods <pete.woods@canonical.com>
3537+ */
3538+
3539+#include <scope-harness/matcher/preview-matcher.h>
3540+#include <scope-harness/matcher/preview-column-matcher.h>
3541+
3542+#include <vector>
3543+
3544+using namespace std;
3545+
3546+namespace unity
3547+{
3548+namespace scopeharness
3549+{
3550+namespace matcher
3551+{
3552+
3553+struct PreviewColumnMatcher::Priv
3554+{
3555+ vector<PreviewMatcher> m_matchers;
3556+};
3557+
3558+PreviewColumnMatcher::PreviewColumnMatcher() :
3559+ p(new Priv)
3560+{
3561+}
3562+
3563+PreviewColumnMatcher::~PreviewColumnMatcher()
3564+{
3565+}
3566+
3567+PreviewColumnMatcher::PreviewColumnMatcher(const PreviewColumnMatcher& other) :
3568+ p(new Priv)
3569+{
3570+ *this = other;
3571+}
3572+
3573+PreviewColumnMatcher::PreviewColumnMatcher(PreviewColumnMatcher&& other)
3574+{
3575+ *this = move(other);
3576+}
3577+
3578+PreviewColumnMatcher& PreviewColumnMatcher::operator=(const PreviewColumnMatcher& other)
3579+{
3580+ p->m_matchers = other.p->m_matchers;
3581+ return *this;
3582+}
3583+
3584+PreviewColumnMatcher& PreviewColumnMatcher::operator=(PreviewColumnMatcher&& other)
3585+{
3586+ p = move(other.p);
3587+ return *this;
3588+}
3589+
3590+PreviewColumnMatcher& PreviewColumnMatcher::column(const PreviewMatcher& previewMatcher)
3591+{
3592+ p->m_matchers.emplace_back(previewMatcher);
3593+ return *this;
3594+}
3595+
3596+PreviewColumnMatcher& PreviewColumnMatcher::column(PreviewMatcher&& previewMatcher)
3597+{
3598+ p->m_matchers.emplace_back(previewMatcher);
3599+ return *this;
3600+}
3601+
3602+MatchResult PreviewColumnMatcher::match(const vector<preview::PreviewWidgetList>& preview) const
3603+{
3604+ MatchResult matchResult;
3605+ match(matchResult, preview);
3606+ return matchResult;
3607+}
3608+
3609+void PreviewColumnMatcher::match(MatchResult& matchResult, const vector<preview::PreviewWidgetList>& preview) const
3610+{
3611+ if (p->m_matchers.size() != preview.size())
3612+ {
3613+ matchResult.failure(
3614+ "Incorrect number of preview columns "
3615+ + to_string(preview.size()) + ", expected "
3616+ + to_string(p->m_matchers.size()));
3617+ return;
3618+ }
3619+
3620+ for (size_t i = 0; i < p->m_matchers.size(); ++i)
3621+ {
3622+ p->m_matchers.at(i).match(matchResult, preview.at(i));
3623+ }
3624+}
3625+
3626+}
3627+}
3628+}
3629
3630=== added file 'src/scope-harness/matcher/preview-column-matcher.h'
3631--- src/scope-harness/matcher/preview-column-matcher.h 1970-01-01 00:00:00 +0000
3632+++ src/scope-harness/matcher/preview-column-matcher.h 2015-03-04 08:54:34 +0000
3633@@ -0,0 +1,64 @@
3634+/*
3635+ * Copyright (C) 2014 Canonical, Ltd.
3636+ *
3637+ * This library is free software; you can redistribute it and/or modify it under
3638+ * the terms of version 3 of the GNU Lesser General Public License as published
3639+ * by the Free Software Foundation.
3640+ *
3641+ * This library is distributed in the hope that it will be useful, but WITHOUT
3642+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3643+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3644+ * details.
3645+ *
3646+ * You should have received a copy of the GNU Lesser General Public License
3647+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3648+ *
3649+ * Author: Pete Woods <pete.woods@canonical.com>
3650+ */
3651+
3652+#pragma once
3653+
3654+#include <scope-harness/matcher/match-result.h>
3655+#include <scope-harness/preview/preview-widget-list.h>
3656+
3657+namespace unity
3658+{
3659+namespace scopeharness
3660+{
3661+namespace matcher
3662+{
3663+
3664+class PreviewMatcher;
3665+
3666+class Q_DECL_EXPORT PreviewColumnMatcher final
3667+{
3668+public:
3669+ PreviewColumnMatcher();
3670+
3671+ PreviewColumnMatcher(const PreviewColumnMatcher& other);
3672+
3673+ PreviewColumnMatcher(PreviewColumnMatcher&& other);
3674+
3675+ ~PreviewColumnMatcher();
3676+
3677+ PreviewColumnMatcher& operator=(const PreviewColumnMatcher& other);
3678+
3679+ PreviewColumnMatcher& operator=(PreviewColumnMatcher&& other);
3680+
3681+ PreviewColumnMatcher& column(const PreviewMatcher& previewMatcher);
3682+
3683+ PreviewColumnMatcher& column(PreviewMatcher&& previewMatcher);
3684+
3685+ MatchResult match(const std::vector<preview::PreviewWidgetList>& preview) const;
3686+
3687+ void match(MatchResult& matchResult, const std::vector<preview::PreviewWidgetList>& preview) const;
3688+
3689+protected:
3690+ struct Priv;
3691+
3692+ std::shared_ptr<Priv> p;
3693+};
3694+
3695+}
3696+}
3697+}
3698
3699=== added file 'src/scope-harness/matcher/preview-matcher.cpp'
3700--- src/scope-harness/matcher/preview-matcher.cpp 1970-01-01 00:00:00 +0000
3701+++ src/scope-harness/matcher/preview-matcher.cpp 2015-03-04 08:54:34 +0000
3702@@ -0,0 +1,106 @@
3703+/*
3704+ * Copyright (C) 2014 Canonical, Ltd.
3705+ *
3706+ * This library is free software; you can redistribute it and/or modify it under
3707+ * the terms of version 3 of the GNU Lesser General Public License as published
3708+ * by the Free Software Foundation.
3709+ *
3710+ * This library is distributed in the hope that it will be useful, but WITHOUT
3711+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3712+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3713+ * details.
3714+ *
3715+ * You should have received a copy of the GNU Lesser General Public License
3716+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3717+ *
3718+ * Author: Pete Woods <pete.woods@canonical.com>
3719+ */
3720+
3721+#include <scope-harness/matcher/preview-matcher.h>
3722+#include <scope-harness/matcher/preview-widget-matcher.h>
3723+
3724+using namespace std;
3725+
3726+namespace unity
3727+{
3728+namespace scopeharness
3729+{
3730+namespace matcher
3731+{
3732+
3733+struct PreviewMatcher::Priv
3734+{
3735+ vector<PreviewWidgetMatcher> m_matchers;
3736+};
3737+
3738+PreviewMatcher::PreviewMatcher() :
3739+ p(new Priv)
3740+{
3741+}
3742+
3743+PreviewMatcher::~PreviewMatcher()
3744+{
3745+}
3746+
3747+PreviewMatcher::PreviewMatcher(const PreviewMatcher& other) :
3748+ p(new Priv)
3749+{
3750+ *this = other;
3751+}
3752+
3753+PreviewMatcher::PreviewMatcher(PreviewMatcher&& other)
3754+{
3755+ *this = move(other);
3756+}
3757+
3758+PreviewMatcher& PreviewMatcher::operator=(const PreviewMatcher& other)
3759+{
3760+ p->m_matchers = other.p->m_matchers;
3761+ return *this;
3762+}
3763+
3764+PreviewMatcher& PreviewMatcher::operator=(PreviewMatcher&& other)
3765+{
3766+ p = move(other.p);
3767+ return *this;
3768+}
3769+
3770+PreviewMatcher& PreviewMatcher::widget(const PreviewWidgetMatcher& previewWidgetMatcher)
3771+{
3772+ p->m_matchers.emplace_back(previewWidgetMatcher);
3773+ return *this;
3774+}
3775+
3776+PreviewMatcher& PreviewMatcher::widget(PreviewWidgetMatcher&& previewWidgetMatcher)
3777+{
3778+ p->m_matchers.emplace_back(previewWidgetMatcher);
3779+ return *this;
3780+}
3781+
3782+MatchResult PreviewMatcher::match(const preview::PreviewWidgetList& previewWidgetList) const
3783+{
3784+ MatchResult matchResult;
3785+ match(matchResult, previewWidgetList);
3786+ return matchResult;
3787+}
3788+
3789+void PreviewMatcher::match(MatchResult& matchResult, const preview::PreviewWidgetList& previewWidgetList) const
3790+{
3791+ if (p->m_matchers.size() != previewWidgetList.size())
3792+ {
3793+ matchResult.failure(
3794+ "Incorrect number of preview widgets "
3795+ + to_string(previewWidgetList.size()) + ", expected "
3796+ + to_string(p->m_matchers.size()));
3797+ return;
3798+ }
3799+
3800+ for (size_t i = 0; i < p->m_matchers.size(); ++i)
3801+ {
3802+ p->m_matchers.at(i).match(matchResult, previewWidgetList.at(i));
3803+ }
3804+}
3805+
3806+}
3807+}
3808+}
3809
3810=== added file 'src/scope-harness/matcher/preview-matcher.h'
3811--- src/scope-harness/matcher/preview-matcher.h 1970-01-01 00:00:00 +0000
3812+++ src/scope-harness/matcher/preview-matcher.h 2015-03-04 08:54:34 +0000
3813@@ -0,0 +1,63 @@
3814+/*
3815+ * Copyright (C) 2014 Canonical, Ltd.
3816+ *
3817+ * This library is free software; you can redistribute it and/or modify it under
3818+ * the terms of version 3 of the GNU Lesser General Public License as published
3819+ * by the Free Software Foundation.
3820+ *
3821+ * This library is distributed in the hope that it will be useful, but WITHOUT
3822+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3823+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3824+ * details.
3825+ *
3826+ * You should have received a copy of the GNU Lesser General Public License
3827+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3828+ *
3829+ * Author: Pete Woods <pete.woods@canonical.com>
3830+ */
3831+
3832+#pragma once
3833+
3834+#include <scope-harness/matcher/match-result.h>
3835+#include <scope-harness/preview/preview-widget-list.h>
3836+
3837+namespace unity
3838+{
3839+namespace scopeharness
3840+{
3841+namespace matcher
3842+{
3843+class PreviewWidgetMatcher;
3844+
3845+class Q_DECL_EXPORT PreviewMatcher final
3846+{
3847+public:
3848+ PreviewMatcher();
3849+
3850+ ~PreviewMatcher();
3851+
3852+ PreviewMatcher(const PreviewMatcher& other);
3853+
3854+ PreviewMatcher(PreviewMatcher&& other);
3855+
3856+ PreviewMatcher& operator=(const PreviewMatcher& other);
3857+
3858+ PreviewMatcher& operator=(PreviewMatcher&& other);
3859+
3860+ PreviewMatcher& widget(const PreviewWidgetMatcher& previewWidgetMatcher);
3861+
3862+ PreviewMatcher& widget(PreviewWidgetMatcher&& previewWidgetMatcher);
3863+
3864+ MatchResult match(const preview::PreviewWidgetList& previewWidgetList) const;
3865+
3866+ void match(MatchResult& matchResult, const preview::PreviewWidgetList& previewWidgetList) const;
3867+
3868+protected:
3869+ struct Priv;
3870+
3871+ std::shared_ptr<Priv> p;
3872+};
3873+
3874+}
3875+}
3876+}
3877
3878=== added file 'src/scope-harness/matcher/preview-widget-matcher.cpp'
3879--- src/scope-harness/matcher/preview-widget-matcher.cpp 1970-01-01 00:00:00 +0000
3880+++ src/scope-harness/matcher/preview-widget-matcher.cpp 2015-03-04 08:54:34 +0000
3881@@ -0,0 +1,161 @@
3882+/*
3883+ * Copyright (C) 2014 Canonical, Ltd.
3884+ *
3885+ * This library is free software; you can redistribute it and/or modify it under
3886+ * the terms of version 3 of the GNU Lesser General Public License as published
3887+ * by the Free Software Foundation.
3888+ *
3889+ * This library is distributed in the hope that it will be useful, but WITHOUT
3890+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3891+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
3892+ * details.
3893+ *
3894+ * You should have received a copy of the GNU Lesser General Public License
3895+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3896+ *
3897+ * Author: Pete Woods <pete.woods@canonical.com>
3898+ */
3899+
3900+#include <scope-harness/matcher/preview-widget-matcher.h>
3901+#include <scope-harness/preview/preview-widget.h>
3902+
3903+#include <unity/scopes/Variant.h>
3904+
3905+#include <boost/optional.hpp>
3906+
3907+using namespace std;
3908+using namespace boost;
3909+namespace sc = unity::scopes;
3910+
3911+namespace unity
3912+{
3913+namespace scopeharness
3914+{
3915+namespace matcher
3916+{
3917+namespace
3918+{
3919+
3920+static void check_string(MatchResult& matchResult, const preview::PreviewWidget& previewWidget,
3921+ const string& name, const string& actualValue,
3922+ const string& expectedValue)
3923+{
3924+ if (actualValue != expectedValue)
3925+ {
3926+ matchResult.failure(
3927+ "PreviewWidget with ID '" + previewWidget.id() + "' has '" + name
3928+ + "' == '" + actualValue + "' but expected '"
3929+ + expectedValue + "'");
3930+ }
3931+}
3932+
3933+static void check_variant(MatchResult& matchResult, const preview::PreviewWidget& previewWidget,
3934+ const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue)
3935+{
3936+ if (!(actualValue == expectedValue))
3937+ {
3938+ auto actualValueString = actualValue.serialize_json();
3939+ auto expectedValueString = expectedValue.serialize_json();
3940+ // serialize_json includes a trailing carriage return
3941+ actualValueString.pop_back();
3942+ expectedValueString.pop_back();
3943+
3944+ matchResult.failure(
3945+ "PreviewWidget with ID '" + previewWidget.id() + "' has '" + name
3946+ + "' == '" + actualValueString + "' but expected '"
3947+ + expectedValueString + "'");
3948+ }
3949+}
3950+
3951+}
3952+
3953+struct PreviewWidgetMatcher::Priv
3954+{
3955+ string m_id;
3956+
3957+ optional<string> m_type;
3958+
3959+ optional<sc::Variant> m_data;
3960+};
3961+
3962+PreviewWidgetMatcher::PreviewWidgetMatcher(const string& id) :
3963+ p(new Priv)
3964+{
3965+ p->m_id = id;
3966+}
3967+
3968+PreviewWidgetMatcher::PreviewWidgetMatcher(const PreviewWidgetMatcher& other) :
3969+ p(new Priv)
3970+{
3971+ *this = other;
3972+}
3973+
3974+PreviewWidgetMatcher::PreviewWidgetMatcher(PreviewWidgetMatcher&& other)
3975+{
3976+ *this = move(other);
3977+}
3978+
3979+PreviewWidgetMatcher& PreviewWidgetMatcher::operator=(const PreviewWidgetMatcher& other)
3980+{
3981+ p->m_id = other.p->m_id;
3982+ p->m_type = other.p->m_type;
3983+ p->m_data = other.p->m_data;
3984+ return *this;
3985+}
3986+
3987+PreviewWidgetMatcher& PreviewWidgetMatcher::operator=(PreviewWidgetMatcher&& other)
3988+{
3989+ p = move(other.p);
3990+ return *this;
3991+}
3992+
3993+PreviewWidgetMatcher::~PreviewWidgetMatcher()
3994+{
3995+}
3996+
3997+PreviewWidgetMatcher& PreviewWidgetMatcher::type(const string& type)
3998+{
3999+ p->m_type = type;
4000+ return *this;
4001+}
4002+
4003+PreviewWidgetMatcher& PreviewWidgetMatcher::data(const sc::Variant& data)
4004+{
4005+ p->m_data = data;
4006+ return *this;
4007+}
4008+
4009+PreviewWidgetMatcher& PreviewWidgetMatcher::data(sc::Variant&& data)
4010+{
4011+ p->m_data = move(data);
4012+ return *this;
4013+}
4014+
4015+MatchResult PreviewWidgetMatcher::match(const preview::PreviewWidget& previewWidget) const
4016+{
4017+ MatchResult matchResult;
4018+ match(matchResult, previewWidget);
4019+ return matchResult;
4020+}
4021+
4022+void PreviewWidgetMatcher::match(MatchResult& matchResult, const preview::PreviewWidget& previewWidget) const
4023+{
4024+ check_string(matchResult, previewWidget, "id", previewWidget.id(), p->m_id);
4025+
4026+ if (p->m_type)
4027+ {
4028+ check_string(matchResult, previewWidget, "type", previewWidget.type(), p->m_type.get());
4029+ }
4030+
4031+ if (p->m_data)
4032+ {
4033+ auto dict = previewWidget.data().get_dict();
4034+ // No point comparing this transitory field
4035+ dict.erase("session-id");
4036+ check_variant(matchResult, previewWidget, "data", sc::Variant(dict), p->m_data.get());
4037+ }
4038+}
4039+
4040+}
4041+}
4042+}
4043
4044=== added file 'src/scope-harness/matcher/preview-widget-matcher.h'
4045--- src/scope-harness/matcher/preview-widget-matcher.h 1970-01-01 00:00:00 +0000
4046+++ src/scope-harness/matcher/preview-widget-matcher.h 2015-03-04 08:54:34 +0000
4047@@ -0,0 +1,71 @@
4048+/*
4049+ * Copyright (C) 2014 Canonical, Ltd.
4050+ *
4051+ * This library is free software; you can redistribute it and/or modify it under
4052+ * the terms of version 3 of the GNU Lesser General Public License as published
4053+ * by the Free Software Foundation.
4054+ *
4055+ * This library is distributed in the hope that it will be useful, but WITHOUT
4056+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4057+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4058+ * details.
4059+ *
4060+ * You should have received a copy of the GNU Lesser General Public License
4061+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4062+ *
4063+ * Author: Pete Woods <pete.woods@canonical.com>
4064+ */
4065+
4066+#pragma once
4067+
4068+#include <scope-harness/matcher/match-result.h>
4069+
4070+namespace unity
4071+{
4072+namespace scopes
4073+{
4074+class Variant;
4075+}
4076+namespace scopeharness
4077+{
4078+namespace preview
4079+{
4080+class PreviewWidget;
4081+}
4082+namespace matcher
4083+{
4084+
4085+class Q_DECL_EXPORT PreviewWidgetMatcher final
4086+{
4087+public:
4088+ PreviewWidgetMatcher(const std::string& id);
4089+
4090+ PreviewWidgetMatcher(const PreviewWidgetMatcher& other);
4091+
4092+ PreviewWidgetMatcher(PreviewWidgetMatcher&& other);
4093+
4094+ PreviewWidgetMatcher& operator=(const PreviewWidgetMatcher& other);
4095+
4096+ PreviewWidgetMatcher& operator=(PreviewWidgetMatcher&& other);
4097+
4098+ ~PreviewWidgetMatcher();
4099+
4100+ PreviewWidgetMatcher& type(const std::string& type);
4101+
4102+ PreviewWidgetMatcher& data(const unity::scopes::Variant& data);
4103+
4104+ PreviewWidgetMatcher& data(unity::scopes::Variant&& data);
4105+
4106+ MatchResult match(const preview::PreviewWidget& previewWidget) const;
4107+
4108+ void match(MatchResult& matchResult, const preview::PreviewWidget& previewWidget) const;
4109+
4110+protected:
4111+ struct Priv;
4112+
4113+ std::shared_ptr<Priv> p;
4114+};
4115+
4116+}
4117+}
4118+}
4119
4120=== added file 'src/scope-harness/matcher/result-matcher.cpp'
4121--- src/scope-harness/matcher/result-matcher.cpp 1970-01-01 00:00:00 +0000
4122+++ src/scope-harness/matcher/result-matcher.cpp 2015-03-04 08:54:34 +0000
4123@@ -0,0 +1,317 @@
4124+/*
4125+ * Copyright (C) 2014 Canonical, Ltd.
4126+ *
4127+ * This library is free software; you can redistribute it and/or modify it under
4128+ * the terms of version 3 of the GNU Lesser General Public License as published
4129+ * by the Free Software Foundation.
4130+ *
4131+ * This library is distributed in the hope that it will be useful, but WITHOUT
4132+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4133+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4134+ * details.
4135+ *
4136+ * You should have received a copy of the GNU Lesser General Public License
4137+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4138+ *
4139+ * Author: Pete Woods <pete.woods@canonical.com>
4140+ */
4141+
4142+#include <scope-harness/results/result.h>
4143+#include <scope-harness/matcher/result-matcher.h>
4144+
4145+#include <unity/UnityExceptions.h>
4146+#include <unity/scopes/Variant.h>
4147+
4148+#include <boost/optional.hpp>
4149+#include <boost/regex.hpp>
4150+
4151+using namespace std;
4152+using namespace boost;
4153+
4154+namespace sc = unity::scopes;
4155+
4156+namespace unity
4157+{
4158+namespace scopeharness
4159+{
4160+namespace matcher
4161+{
4162+namespace
4163+{
4164+static void check_variant(MatchResult& matchResult, const results::Result& result,
4165+ const string& name, const sc::Variant& actualValue, const sc::Variant& expectedValue)
4166+{
4167+ if (!(actualValue == expectedValue))
4168+ {
4169+ auto actualValueString = actualValue.serialize_json();
4170+ auto expectedValueString = expectedValue.serialize_json();
4171+ // serialize_json includes a trailing carriage return
4172+ actualValueString.pop_back();
4173+ expectedValueString.pop_back();
4174+
4175+ matchResult.failure(
4176+ "Result with URI '" + result.uri() + "' has '" + name
4177+ + "' == '" + actualValueString + "' but expected '"
4178+ + expectedValueString + "'");
4179+ }
4180+}
4181+
4182+static void check_variant(MatchResult& matchResult, const results::Result& result,
4183+ const string& name, const sc::Variant& expectedValue)
4184+{
4185+ try
4186+ {
4187+ const auto& actualValue = result[name];
4188+ check_variant(matchResult, result, name, actualValue, expectedValue);
4189+ }
4190+ catch (unity::InvalidArgumentException& e)
4191+ {
4192+ matchResult.failure(
4193+ "Result with URI '" + result.uri()
4194+ + "' missing expected property '" + name + "'");
4195+ }
4196+}
4197+
4198+
4199+static void check_string(MatchResult& matchResult, const results::Result& result,
4200+ const string& name, const string& actualValue,
4201+ const string& expectedValue)
4202+{
4203+ try
4204+ {
4205+ if (actualValue != expectedValue)
4206+ {
4207+ matchResult.failure(
4208+ "Result with URI '" + result.uri() + "' has '" + name
4209+ + "' == '" + actualValue + "' but expected '"
4210+ + expectedValue + "'");
4211+ }
4212+ }
4213+ catch (std::exception& e)
4214+ {
4215+ matchResult.failure(
4216+ "Result with URI '" + result.uri()
4217+ + "' does not contain expected property '" + name
4218+ + "'");
4219+ }
4220+}
4221+
4222+static void check_regex(MatchResult& matchResult, const results::Result& result,
4223+ const string& name, const string& actualValue,
4224+ const regex& expectedValue)
4225+{
4226+ try
4227+ {
4228+ if (!regex_match(actualValue, expectedValue))
4229+ {
4230+ matchResult.failure(
4231+ "Result with URI '" + result.uri() + "' has '" + name
4232+ + "' == '" + actualValue + "' but expected to match '"
4233+ + expectedValue.str() + "'");
4234+ }
4235+ }
4236+ catch (std::exception& e)
4237+ {
4238+ matchResult.failure(
4239+ "Result with URI '" + result.uri()
4240+ + "' does not contain expected property '" + name
4241+ + "'");
4242+ }
4243+}
4244+}
4245+
4246+struct ResultMatcher::Priv
4247+{
4248+ string m_uri;
4249+
4250+ optional<string> m_dndUri;
4251+
4252+ optional<string> m_title;
4253+
4254+ optional<string> m_art;
4255+
4256+ optional<string> m_subtitle;
4257+
4258+ optional<string> m_emblem;
4259+
4260+ optional<string> m_mascot;
4261+
4262+ optional<sc::Variant> m_attributes;
4263+
4264+ optional<sc::Variant> m_summary;
4265+
4266+ optional<sc::Variant> m_background;
4267+
4268+ vector<pair<string, sc::Variant>> m_properties;
4269+};
4270+
4271+ResultMatcher::ResultMatcher(const string& uri) :
4272+ p(new Priv)
4273+{
4274+ p->m_uri = uri;
4275+}
4276+
4277+ResultMatcher::ResultMatcher(const ScopeUri& uri) :
4278+ p(new Priv)
4279+{
4280+ p->m_uri = uri.toString();
4281+}
4282+
4283+ResultMatcher ResultMatcher::any_uri()
4284+{
4285+ return ResultMatcher(string());
4286+}
4287+
4288+ResultMatcher::ResultMatcher(const ResultMatcher& other) :
4289+ p(new Priv)
4290+{
4291+ *this = other;
4292+}
4293+
4294+ResultMatcher& ResultMatcher::operator=(const ResultMatcher& other)
4295+{
4296+ p->m_uri = other.p->m_uri;
4297+ p->m_dndUri = other.p->m_dndUri;
4298+ p->m_title = other.p->m_title;
4299+ p->m_art = other.p->m_art;
4300+ p->m_subtitle = other.p->m_subtitle;
4301+ p->m_emblem = other.p->m_emblem;
4302+ p->m_mascot = other.p->m_mascot;
4303+ p->m_attributes = other.p->m_attributes;
4304+ p->m_summary = other.p->m_summary;
4305+ p->m_background = other.p->m_background;
4306+ p->m_properties = other.p->m_properties;
4307+ return *this;
4308+}
4309+
4310+ResultMatcher& ResultMatcher::operator=(ResultMatcher&& other)
4311+{
4312+ p = move(other.p);
4313+ return *this;
4314+}
4315+
4316+ResultMatcher& ResultMatcher::dndUri(const string& dndUri)
4317+{
4318+ p->m_dndUri = dndUri;
4319+ return *this;
4320+}
4321+
4322+ResultMatcher& ResultMatcher::title(const string& title)
4323+{
4324+ p->m_title = title;
4325+ return *this;
4326+}
4327+
4328+ResultMatcher& ResultMatcher::art(const string& art)
4329+{
4330+ p->m_art = art;
4331+ return *this;
4332+}
4333+
4334+ResultMatcher& ResultMatcher::subtitle(const string& subtitle)
4335+{
4336+ p->m_subtitle = subtitle;
4337+ return *this;
4338+}
4339+
4340+ResultMatcher& ResultMatcher::emblem(const string& emblem)
4341+{
4342+ p->m_emblem = emblem;
4343+ return *this;
4344+}
4345+
4346+ResultMatcher& ResultMatcher::mascot(const string& mascot)
4347+{
4348+ p->m_mascot = mascot;
4349+ return *this;
4350+}
4351+
4352+ResultMatcher& ResultMatcher::attributes(const sc::Variant& attributes)
4353+{
4354+ p->m_attributes = attributes;
4355+ return *this;
4356+}
4357+
4358+ResultMatcher& ResultMatcher::summary(const sc::Variant& summary)
4359+{
4360+ p->m_summary = summary;
4361+ return *this;
4362+}
4363+
4364+ResultMatcher& ResultMatcher::background(const sc::Variant& background)
4365+{
4366+ p->m_background = background;
4367+ return *this;
4368+}
4369+
4370+ResultMatcher& ResultMatcher::property(const string& name, const sc::Variant& value)
4371+{
4372+ p->m_properties.emplace_back(make_pair(name, value));
4373+ return *this;
4374+}
4375+
4376+MatchResult ResultMatcher::match(const results::Result& result) const
4377+{
4378+ MatchResult matchResult;
4379+ match(matchResult, result);
4380+ return matchResult;
4381+}
4382+
4383+void ResultMatcher::match(MatchResult& matchResult, const results::Result& result) const
4384+{
4385+ if(!p->m_uri.empty())
4386+ {
4387+ check_regex(matchResult, result, "uri", result.uri(), regex(p->m_uri));
4388+ }
4389+ if (p->m_dndUri)
4390+ {
4391+ check_string(matchResult, result, "dnd_uri", result.dnd_uri(),
4392+ p->m_dndUri.get());
4393+ }
4394+ if (p->m_title)
4395+ {
4396+ check_string(matchResult, result, "title", result.title(), p->m_title.get());
4397+ }
4398+ if (p->m_art)
4399+ {
4400+ check_string(matchResult, result, "art", result.art(), p->m_art.get());
4401+ }
4402+ if (p->m_subtitle)
4403+ {
4404+ check_string(matchResult, result, "subtitle", result.subtitle(), p->m_subtitle.get());
4405+ }
4406+ if (p->m_emblem)
4407+ {
4408+ check_string(matchResult, result, "emblem", result.emblem(), p->m_emblem.get());
4409+ }
4410+ if (p->m_mascot)
4411+ {
4412+ check_string(matchResult, result, "mascot", result.mascot(), p->m_mascot.get());
4413+ }
4414+ if (p->m_attributes)
4415+ {
4416+ check_variant(matchResult, result, "attributes", result.attributes(), p->m_attributes.get());
4417+ }
4418+ if (p->m_summary)
4419+ {
4420+ check_variant(matchResult, result, "summary", result.summary(), p->m_summary.get());
4421+ }
4422+ if (p->m_background)
4423+ {
4424+ check_variant(matchResult, result, "background", result.background(), p->m_background.get());
4425+ }
4426+
4427+ for (const auto& property : p->m_properties)
4428+ {
4429+ check_variant(matchResult, result, property.first, property.second);
4430+ }
4431+}
4432+
4433+string ResultMatcher::getUri() const
4434+{
4435+ return p->m_uri;
4436+}
4437+
4438+}
4439+}
4440+}
4441
4442=== added file 'src/scope-harness/matcher/result-matcher.h'
4443--- src/scope-harness/matcher/result-matcher.h 1970-01-01 00:00:00 +0000
4444+++ src/scope-harness/matcher/result-matcher.h 2015-03-04 08:54:34 +0000
4445@@ -0,0 +1,90 @@
4446+/*
4447+ * Copyright (C) 2014 Canonical, Ltd.
4448+ *
4449+ * This library is free software; you can redistribute it and/or modify it under
4450+ * the terms of version 3 of the GNU Lesser General Public License as published
4451+ * by the Free Software Foundation.
4452+ *
4453+ * This library is distributed in the hope that it will be useful, but WITHOUT
4454+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4455+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4456+ * details.
4457+ *
4458+ * You should have received a copy of the GNU Lesser General Public License
4459+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4460+ *
4461+ * Author: Pete Woods <pete.woods@canonical.com>
4462+ */
4463+
4464+#pragma once
4465+
4466+#include <scope-harness/matcher/match-result.h>
4467+#include <scope-harness/matcher/scope-uri.h>
4468+
4469+namespace unity
4470+{
4471+namespace scopes
4472+{
4473+class Variant;
4474+}
4475+namespace scopeharness
4476+{
4477+namespace results
4478+{
4479+class Result;
4480+}
4481+namespace matcher
4482+{
4483+
4484+class Q_DECL_EXPORT ResultMatcher final
4485+{
4486+public:
4487+ ResultMatcher(const ScopeUri& uri);
4488+
4489+ ResultMatcher(const std::string& uri);
4490+
4491+ static ResultMatcher any_uri();
4492+
4493+ ~ResultMatcher() = default;
4494+
4495+ ResultMatcher(const ResultMatcher& other);
4496+
4497+ ResultMatcher& operator=(const ResultMatcher& other);
4498+
4499+ ResultMatcher& operator=(ResultMatcher&& other);
4500+
4501+ ResultMatcher& dndUri(const std::string& dndUri);
4502+
4503+ ResultMatcher& title(const std::string& title);
4504+
4505+ ResultMatcher& art(const std::string& art);
4506+
4507+ ResultMatcher& subtitle(const std::string& subtitle);
4508+
4509+ ResultMatcher& emblem(const std::string& emblem);
4510+
4511+ ResultMatcher& mascot(const std::string& mascot);
4512+
4513+ ResultMatcher& attributes(const unity::scopes::Variant& attributes);
4514+
4515+ ResultMatcher& summary(const unity::scopes::Variant& summary);
4516+
4517+ ResultMatcher& background(const unity::scopes::Variant& background);
4518+
4519+ ResultMatcher& property(const std::string& name, const unity::scopes::Variant& value);
4520+
4521+ MatchResult match(const results::Result& result) const;
4522+
4523+ void match(MatchResult& matchResult, const results::Result& result) const;
4524+
4525+ std::string getUri() const;
4526+
4527+protected:
4528+ struct Priv;
4529+
4530+ std::shared_ptr<Priv> p;
4531+};
4532+
4533+}
4534+}
4535+}
4536
4537=== added file 'src/scope-harness/matcher/scope-uri.cpp'
4538--- src/scope-harness/matcher/scope-uri.cpp 1970-01-01 00:00:00 +0000
4539+++ src/scope-harness/matcher/scope-uri.cpp 2015-03-04 08:54:34 +0000
4540@@ -0,0 +1,133 @@
4541+/*
4542+ * Copyright (C) 2014 Canonical, Ltd.
4543+ *
4544+ * This library is free software; you can redistribute it and/or modify it under
4545+ * the terms of version 3 of the GNU Lesser General Public License as published
4546+ * by the Free Software Foundation.
4547+ *
4548+ * This library is distributed in the hope that it will be useful, but WITHOUT
4549+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4550+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4551+ * details.
4552+ *
4553+ * You should have received a copy of the GNU Lesser General Public License
4554+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4555+ *
4556+ * Author: Pete Woods <pete.woods@canonical.com>
4557+ */
4558+
4559+#include <scope-harness/matcher/scope-uri.h>
4560+
4561+#include <QUrl>
4562+
4563+#include <sstream>
4564+
4565+using namespace std;
4566+
4567+namespace unity
4568+{
4569+namespace scopeharness
4570+{
4571+namespace matcher
4572+{
4573+namespace
4574+{
4575+static void paramJoin(stringstream& s, const vector<pair<string, string>>& v)
4576+{
4577+ bool first = true;
4578+ for (const auto& e : v)
4579+ {
4580+ if (first)
4581+ {
4582+ first = false;
4583+ s << "\\?";
4584+ }
4585+ else
4586+ {
4587+ s << "&";
4588+ }
4589+ s
4590+ << QUrl::toPercentEncoding(QString::fromStdString(e.first)).constData()
4591+ << "="
4592+ << QUrl::toPercentEncoding(QString::fromStdString(e.second)).constData();
4593+ }
4594+}
4595+}
4596+
4597+struct ScopeUri::Priv
4598+{
4599+ string m_id;
4600+
4601+ string m_department;
4602+
4603+ string m_query;
4604+};
4605+
4606+ScopeUri::ScopeUri(const string& id) :
4607+ p(new Priv)
4608+{
4609+ p->m_id = id;
4610+}
4611+
4612+ScopeUri::~ScopeUri()
4613+{
4614+}
4615+
4616+ScopeUri::ScopeUri(const ScopeUri& other) :
4617+ p(new Priv)
4618+{
4619+ *this = other;
4620+}
4621+
4622+ScopeUri::ScopeUri(ScopeUri&& other)
4623+{
4624+ *this = move(other);
4625+}
4626+
4627+ScopeUri& ScopeUri::operator=(const ScopeUri& other)
4628+{
4629+ p->m_id = other.p->m_id;
4630+ p->m_department = other.p->m_department;
4631+ p->m_query = other.p->m_query;
4632+ return *this;
4633+}
4634+
4635+ScopeUri& ScopeUri::operator=(ScopeUri&& other)
4636+{
4637+ p = move(other.p);
4638+ return *this;
4639+}
4640+
4641+ScopeUri& ScopeUri::department(const std::string& departmentId)
4642+{
4643+ p->m_department = departmentId;
4644+ return *this;
4645+}
4646+
4647+ScopeUri& ScopeUri::query(const std::string& queryString)
4648+{
4649+ p->m_query = queryString;
4650+ return *this;
4651+}
4652+
4653+string ScopeUri::toString() const
4654+{
4655+ stringstream result;
4656+ result << "scope:\\/\\/"
4657+ << QUrl::toPercentEncoding(QString::fromStdString(p->m_id)).constData();
4658+ vector<pair<string, string>> params;
4659+ if (!p->m_department.empty())
4660+ {
4661+ params.emplace_back(make_pair("department", p->m_department));
4662+ }
4663+ if (!p->m_query.empty())
4664+ {
4665+ params.emplace_back(make_pair("q", p->m_query));
4666+ }
4667+ paramJoin(result, params);
4668+ return result.str();
4669+}
4670+
4671+}
4672+}
4673+}
4674
4675=== added file 'src/scope-harness/matcher/scope-uri.h'
4676--- src/scope-harness/matcher/scope-uri.h 1970-01-01 00:00:00 +0000
4677+++ src/scope-harness/matcher/scope-uri.h 2015-03-04 08:54:34 +0000
4678@@ -0,0 +1,62 @@
4679+/*
4680+ * Copyright (C) 2014 Canonical, Ltd.
4681+ *
4682+ * This library is free software; you can redistribute it and/or modify it under
4683+ * the terms of version 3 of the GNU Lesser General Public License as published
4684+ * by the Free Software Foundation.
4685+ *
4686+ * This library is distributed in the hope that it will be useful, but WITHOUT
4687+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4688+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4689+ * details.
4690+ *
4691+ * You should have received a copy of the GNU Lesser General Public License
4692+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4693+ *
4694+ * Author: Pete Woods <pete.woods@canonical.com>
4695+ */
4696+
4697+#pragma once
4698+
4699+#include <QtGlobal>
4700+
4701+#include <memory>
4702+#include <string>
4703+
4704+namespace unity
4705+{
4706+namespace scopeharness
4707+{
4708+namespace matcher
4709+{
4710+
4711+class Q_DECL_EXPORT ScopeUri
4712+{
4713+public:
4714+ ScopeUri(const std::string& id);
4715+
4716+ ScopeUri(const ScopeUri& other);
4717+
4718+ ScopeUri(ScopeUri&& other);
4719+
4720+ ~ScopeUri();
4721+
4722+ ScopeUri& operator=(const ScopeUri& other);
4723+
4724+ ScopeUri& operator=(ScopeUri&& other);
4725+
4726+ ScopeUri& department(const std::string& departmentId);
4727+
4728+ ScopeUri& query(const std::string& queryString);
4729+
4730+ std::string toString() const;
4731+
4732+protected:
4733+ struct Priv;
4734+
4735+ std::shared_ptr<Priv> p;
4736+};
4737+
4738+}
4739+}
4740+}
4741
4742=== added directory 'src/scope-harness/preview'
4743=== added file 'src/scope-harness/preview/preview-widget-list.cpp'
4744--- src/scope-harness/preview/preview-widget-list.cpp 1970-01-01 00:00:00 +0000
4745+++ src/scope-harness/preview/preview-widget-list.cpp 2015-03-04 08:54:34 +0000
4746@@ -0,0 +1,105 @@
4747+/*
4748+ * Copyright (C) 2014 Canonical, Ltd.
4749+ *
4750+ * This library is free software; you can redistribute it and/or modify it under
4751+ * the terms of version 3 of the GNU Lesser General Public License as published
4752+ * by the Free Software Foundation.
4753+ *
4754+ * This library is distributed in the hope that it will be useful, but WITHOUT
4755+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4756+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4757+ * details.
4758+ *
4759+ * You should have received a copy of the GNU Lesser General Public License
4760+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4761+ *
4762+ * Author: Pete Woods <pete.woods@canonical.com>
4763+ */
4764+
4765+#include <internal/preview-widget-list-arguments.h>
4766+#include <preview/preview-widget-list.h>
4767+
4768+using namespace std;
4769+
4770+namespace unity
4771+{
4772+namespace scopeharness
4773+{
4774+namespace preview
4775+{
4776+
4777+struct PreviewWidgetList::Priv
4778+{
4779+ std::vector<preview::PreviewWidget> previewWidgets;
4780+};
4781+
4782+PreviewWidgetList::PreviewWidgetList(const internal::PreviewWidgetListArguments& arguments) :
4783+ p(new Priv)
4784+{
4785+ p->previewWidgets = arguments.previewWidgets;
4786+}
4787+
4788+
4789+PreviewWidgetList::PreviewWidgetList(const PreviewWidgetList& other) :
4790+ p(new Priv)
4791+{
4792+ *this = other;
4793+}
4794+
4795+PreviewWidgetList::PreviewWidgetList(PreviewWidgetList&& other)
4796+{
4797+ *this = move(other);
4798+}
4799+
4800+PreviewWidgetList::~PreviewWidgetList()
4801+{
4802+}
4803+
4804+PreviewWidgetList& PreviewWidgetList::operator=(const PreviewWidgetList& other)
4805+{
4806+ p->previewWidgets = other.p->previewWidgets;
4807+ return *this;
4808+}
4809+
4810+PreviewWidgetList& PreviewWidgetList::operator=(PreviewWidgetList&& other)
4811+{
4812+ p = move(other.p);
4813+ return *this;
4814+}
4815+
4816+PreviewWidget PreviewWidgetList::at(std::size_t index) const
4817+{
4818+ return p->previewWidgets.at(index);
4819+}
4820+
4821+PreviewWidget PreviewWidgetList::at(const std::string& id) const
4822+{
4823+ for (const auto& widget : p->previewWidgets)
4824+ {
4825+ if (widget.id() == id)
4826+ {
4827+ return widget;
4828+ }
4829+ }
4830+
4831+ throw domain_error("Widget '" + id + "' not found");
4832+}
4833+
4834+PreviewWidget PreviewWidgetList::operator[](std::size_t index) const
4835+{
4836+ return at(index);
4837+}
4838+
4839+PreviewWidget PreviewWidgetList::operator[](const std::string& id) const
4840+{
4841+ return at(id);
4842+}
4843+
4844+std::size_t PreviewWidgetList::size() const
4845+{
4846+ return p->previewWidgets.size();
4847+}
4848+
4849+}
4850+}
4851+}
4852
4853=== added file 'src/scope-harness/preview/preview-widget-list.h'
4854--- src/scope-harness/preview/preview-widget-list.h 1970-01-01 00:00:00 +0000
4855+++ src/scope-harness/preview/preview-widget-list.h 2015-03-04 08:54:34 +0000
4856@@ -0,0 +1,73 @@
4857+/*
4858+ * Copyright (C) 2014 Canonical, Ltd.
4859+ *
4860+ * This library is free software; you can redistribute it and/or modify it under
4861+ * the terms of version 3 of the GNU Lesser General Public License as published
4862+ * by the Free Software Foundation.
4863+ *
4864+ * This library is distributed in the hope that it will be useful, but WITHOUT
4865+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4866+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4867+ * details.
4868+ *
4869+ * You should have received a copy of the GNU Lesser General Public License
4870+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4871+ *
4872+ * Author: Pete Woods <pete.woods@canonical.com>
4873+ */
4874+
4875+#pragma once
4876+
4877+#include <scope-harness/preview/preview-widget.h>
4878+
4879+namespace unity
4880+{
4881+namespace scopeharness
4882+{
4883+namespace internal
4884+{
4885+struct PreviewWidgetListArguments;
4886+}
4887+namespace view
4888+{
4889+class PreviewView;
4890+}
4891+namespace preview
4892+{
4893+
4894+class Q_DECL_EXPORT PreviewWidgetList
4895+{
4896+public:
4897+ PreviewWidgetList(const PreviewWidgetList& other);
4898+
4899+ PreviewWidgetList(PreviewWidgetList&& other);
4900+
4901+ PreviewWidgetList& operator=(const PreviewWidgetList& other);
4902+
4903+ PreviewWidgetList& operator=(PreviewWidgetList&& other);
4904+
4905+ ~PreviewWidgetList();
4906+
4907+ PreviewWidget at(std::size_t index) const;
4908+
4909+ PreviewWidget at(const std::string& id) const;
4910+
4911+ PreviewWidget operator[](std::size_t index) const;
4912+
4913+ PreviewWidget operator[](const std::string& id) const;
4914+
4915+ std::size_t size() const;
4916+
4917+protected:
4918+ friend view::PreviewView;
4919+
4920+ PreviewWidgetList(const internal::PreviewWidgetListArguments& arguments);
4921+
4922+ struct Priv;
4923+
4924+ std::shared_ptr<Priv> p;
4925+};
4926+
4927+}
4928+}
4929+}
4930
4931=== added file 'src/scope-harness/preview/preview-widget.cpp'
4932--- src/scope-harness/preview/preview-widget.cpp 1970-01-01 00:00:00 +0000
4933+++ src/scope-harness/preview/preview-widget.cpp 2015-03-04 08:54:34 +0000
4934@@ -0,0 +1,140 @@
4935+/*
4936+ * Copyright (C) 2014 Canonical, Ltd.
4937+ *
4938+ * This library is free software; you can redistribute it and/or modify it under
4939+ * the terms of version 3 of the GNU Lesser General Public License as published
4940+ * by the Free Software Foundation.
4941+ *
4942+ * This library is distributed in the hope that it will be useful, but WITHOUT
4943+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4944+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
4945+ * details.
4946+ *
4947+ * You should have received a copy of the GNU Lesser General Public License
4948+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4949+ *
4950+ * Author: Pete Woods <pete.woods@canonical.com>
4951+ */
4952+
4953+#include <scope-harness/internal/preview-widget-arguments.h>
4954+#include <scope-harness/preview/preview-widget.h>
4955+#include <scope-harness/view/abstract-view.h>
4956+#include <scope-harness/view/preview-view.h>
4957+#include <scope-harness/internal/test-utils.h>
4958+
4959+#include <unity/shell/scopes/PreviewModelInterface.h>
4960+#include <unity/shell/scopes/PreviewWidgetModelInterface.h>
4961+
4962+#include <Unity/utils.h>
4963+
4964+#include <QDebug>
4965+#include <QSignalSpy>
4966+
4967+using namespace std;
4968+namespace ng = scopes_ng;
4969+namespace sc = unity::scopes;
4970+namespace ss = unity::shell::scopes;
4971+
4972+namespace unity
4973+{
4974+namespace scopeharness
4975+{
4976+using namespace internal;
4977+namespace preview
4978+{
4979+
4980+struct PreviewWidget::Priv
4981+{
4982+ unity::shell::scopes::PreviewWidgetModelInterface* m_previewWidgetModel;
4983+
4984+ QModelIndex m_index;
4985+
4986+ unity::shell::scopes::PreviewModelInterface* m_previewModel;
4987+
4988+ weak_ptr<view::ResultsView> m_resultsView;
4989+
4990+ weak_ptr<view::PreviewView> m_previewView;
4991+};
4992+
4993+PreviewWidget::PreviewWidget(const internal::PreviewWidgetArguments& arguments) :
4994+ p(new Priv)
4995+{
4996+ p->m_previewWidgetModel = arguments.previewWidgetModel;
4997+ p->m_previewModel = arguments.previewModel;
4998+ p->m_index = arguments.index;
4999+ p->m_resultsView = arguments.resultsView;
5000+ p->m_previewView = arguments.previewView;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: