Merge lp:~mhr3/unity-scopes-shell/scopes-ng-tests into lp:unity-scopes-shell
- scopes-ng-tests
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 37 |
Merged at revision: | 31 |
Proposed branch: | lp:~mhr3/unity-scopes-shell/scopes-ng-tests |
Merge into: | lp:unity-scopes-shell |
Diff against target: |
810 lines (+479/-47) 18 files modified
src/Unity/CMakeLists.txt (+1/-1) src/Unity/scopes-ng/CMakeLists.txt (+1/-1) src/Unity/scopes-ng/categories.cpp (+4/-4) src/Unity/scopes-ng/categories.h (+2/-2) src/Unity/scopes-ng/resultsmodel.cpp (+60/-23) src/Unity/scopes-ng/resultsmodel.h (+18/-6) src/Unity/scopes-ng/scope.h (+1/-1) src/Unity/scopes-ng/scopes.cpp (+16/-7) src/Unity/scopes-ng/scopes.h (+3/-1) tests/CMakeLists.txt (+13/-1) tests/data/CMakeLists.txt (+7/-0) tests/data/Registry.ini.in (+7/-0) tests/data/Runtime.ini.in (+6/-0) tests/data/Zmq.ini.in (+3/-0) tests/data/mock-scope/CMakeLists.txt (+11/-0) tests/data/mock-scope/mock-scope.cpp (+119/-0) tests/data/mock-scope/mock-scope.ini.in (+7/-0) tests/resultstest-ng.cpp (+200/-0) |
To merge this branch: | bzr merge lp:~mhr3/unity-scopes-shell/scopes-ng-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Michael Zanetti (community) | Approve | ||
Review via email: mp+198437@code.launchpad.net |
Commit message
Updated result model roles and added unit tests for the new scopes framework.
Description of the change
Updated result model roles and added unit tests for the new scopes framework.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:31
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:32
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:33
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
92 + return QVariant(
107 + return QVariant(
You don't need to write the QVariant there (and all the following lines) explicity. Obviously it doesn't really hurt in terms of performance but imho it hurts readability. You don't gain anything in terms of converting anyways by writing it explicitly anyways.
=====
168 +#include <unordered_map>
210 + std::unordered_
unused?
========
379 +#Scope.
as this is commented I gotta ask: Is this needed at all? in the future? do we perhaps need a FIXME comment?
======
418 === added file 'tests/
This seems like a mock. calling the directory "mocks" instead of data would make that more obvious imho.
=======
674 + void testTwoSearches()
675 + {
676 + QCOMPARE(
677 + // perform a search
678 + m_scope-
679 + QCOMPARE(
680 + QTRY_COMPARE(
681 +
682 + // ensure categories have > 0 rows
683 + auto categories = m_scope-
684 + auto categories_count = categories-
685 + QVERIFY(
686 +
687 + m_scope-
688 + QCOMPARE(
689 + // wait for the search to finish
690 + QTRY_COMPARE(
691 +
692 + // shouldn't create more nor fewer categories
693 + QVERIFY(
694 + }
Wouldn't it make sense to use data columns/rows? This way we can just add new rows to test different things like uppercase, lowercase, special chars etc for search strings (and it's even fewer code than what you have now)
Ok. I guess the testTwoSearches is intentionally performing 2 searches in a row to see if it recovers from searches. Still, there might be issues in different search strings and I really think we should have such a data driven test case to easily be able to add new search terms to the tests. Maybe it makes more sense to transform the testBasicResultData into such a thing. Maybe both? You decide.
======
I really don't like the overuse of the "auto" type. Imho it makes code hard to read.
Michal Hruby (mhr3) wrote : | # |
> You don't need to write the QVariant there (and all the following lines)
> explicity. Obviously it doesn't really hurt in terms of performance but imho
> it hurts readability. You don't gain anything in terms of converting anyways
> by writing it explicitly anyways.
Changed to do implicit conversions.
>
> =====
> 168 +#include <unordered_map>
> 210 + std::unordered_
>
> unused?
Will be used soon :)
> 379 +#Scope.
>
> as this is commented I gotta ask: Is this needed at all? in the future? do we
> perhaps need a FIXME comment?
Removed.
> 418 === added file 'tests/
>
> This seems like a mock. calling the directory "mocks" instead of data would
> make that more obvious imho.
The data dir has all test configuration data files, plus the scope itself is really a "data" provider :) But I at least renamed the scope itself to mock-scope.
> Wouldn't it make sense to use data columns/rows? This way we can just add new
> rows to test different things like uppercase, lowercase, special chars etc for
> search strings (and it's even fewer code than what you have now)
>
> Ok. I guess the testTwoSearches is intentionally performing 2 searches in a
> row to see if it recovers from searches. Still, there might be issues in
> different search strings and I really think we should have such a data driven
> test case to easily be able to add new search terms to the tests. Maybe it
> makes more sense to transform the testBasicResultData into such a thing. Maybe
> both? You decide.
The thing is, I'm not really using the various search strings to just change the data the scope gives you, it's mostly used to change behaviour of the search.
Maybe the problem really is with the naming of the test file, it's not just testing results (that's really just the last step), it's testing end to end communication with a real scope - that's why these four tiny test methods are able to cover 75% of the entire codebase.
> I really don't like the overuse of the "auto" type. Imho it makes code hard to
> read.
Not sure what to do about that, it's convenient to write it that way :) Maybe it's again a naming issue, the variable name should be expressive enough to convey what it is.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:36
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:37
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Michal Hruby (mhr3) wrote : | # |
qmlplugindump crash, retrying...
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'src/Unity/CMakeLists.txt' |
2 | --- src/Unity/CMakeLists.txt 2013-11-25 18:41:16 +0000 |
3 | +++ src/Unity/CMakeLists.txt 2013-12-12 12:53:45 +0000 |
4 | @@ -5,7 +5,7 @@ |
5 | include(FindPkgConfig) |
6 | pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2) |
7 | pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0>=7.1.1) |
8 | -pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1) |
9 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1.3) |
10 | |
11 | include_directories( |
12 | ${CMAKE_CURRENT_SOURCE_DIR} |
13 | |
14 | === modified file 'src/Unity/scopes-ng/CMakeLists.txt' |
15 | --- src/Unity/scopes-ng/CMakeLists.txt 2013-12-05 12:21:23 +0000 |
16 | +++ src/Unity/scopes-ng/CMakeLists.txt 2013-12-12 12:53:45 +0000 |
17 | @@ -1,6 +1,6 @@ |
18 | # Dependencies |
19 | include(FindPkgConfig) |
20 | -pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1.2) |
21 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1.3) |
22 | |
23 | include_directories( |
24 | ${CMAKE_CURRENT_SOURCE_DIR} |
25 | |
26 | === modified file 'src/Unity/scopes-ng/categories.cpp' |
27 | --- src/Unity/scopes-ng/categories.cpp 2013-12-06 10:47:26 +0000 |
28 | +++ src/Unity/scopes-ng/categories.cpp 2013-12-12 12:53:45 +0000 |
29 | @@ -181,17 +181,17 @@ |
30 | |
31 | switch (role) { |
32 | case RoleCategoryId: |
33 | - return QVariant(QString::fromStdString(cat->id())); |
34 | + return QString::fromStdString(cat->id()); |
35 | case RoleName: |
36 | - return QVariant(QString::fromStdString(cat->title())); |
37 | + return QString::fromStdString(cat->title()); |
38 | case RoleIcon: |
39 | - return QVariant(QString::fromStdString(cat->icon())); |
40 | + return QString::fromStdString(cat->icon()); |
41 | case RoleRenderer: |
42 | return catData->renderer_template.toVariant(); |
43 | case RoleComponents: |
44 | return catData->components.toVariant(); |
45 | case RoleContentType: |
46 | - return QVariant(QString("default")); |
47 | + return QString("default"); |
48 | case RoleRendererHint: |
49 | return QVariant(); |
50 | case RoleProgressSource: |
51 | |
52 | === modified file 'src/Unity/scopes-ng/categories.h' |
53 | --- src/Unity/scopes-ng/categories.h 2013-12-04 17:23:15 +0000 |
54 | +++ src/Unity/scopes-ng/categories.h 2013-12-12 12:53:45 +0000 |
55 | @@ -36,7 +36,7 @@ |
56 | |
57 | struct CategoryData; |
58 | |
59 | -class Categories : public QAbstractListModel |
60 | +class Q_DECL_EXPORT Categories : public QAbstractListModel |
61 | { |
62 | Q_OBJECT |
63 | |
64 | @@ -60,7 +60,7 @@ |
65 | |
66 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
67 | QHash<int, QByteArray> roleNames() const override; |
68 | - int rowCount(const QModelIndex& parent) const override; |
69 | + int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
70 | |
71 | ResultsModel* lookupCategory(std::string const& category_id); |
72 | void registerCategory(unity::api::scopes::Category::SCPtr category, ResultsModel* model); |
73 | |
74 | === modified file 'src/Unity/scopes-ng/resultsmodel.cpp' |
75 | --- src/Unity/scopes-ng/resultsmodel.cpp 2013-12-06 10:47:26 +0000 |
76 | +++ src/Unity/scopes-ng/resultsmodel.cpp 2013-12-12 12:53:45 +0000 |
77 | @@ -30,13 +30,20 @@ |
78 | : QAbstractListModel(parent) |
79 | { |
80 | m_roles[ResultsModel::RoleUri] = "uri"; |
81 | - m_roles[ResultsModel::RoleIconHint] = "icon"; |
82 | - m_roles[ResultsModel::RoleCategory] = "category"; |
83 | - m_roles[ResultsModel::RoleTitle] = "title"; |
84 | - m_roles[ResultsModel::RoleComment] = "comment"; |
85 | + m_roles[ResultsModel::RoleCategoryId] = "categoryId"; |
86 | m_roles[ResultsModel::RoleDndUri] = "dndUri"; |
87 | m_roles[ResultsModel::RoleMetadata] = "metadata"; |
88 | - m_roles[ResultsModel::RoleRendererHints] = "rendererHints"; |
89 | + m_roles[ResultsModel::RoleTitle] = "title"; |
90 | + m_roles[ResultsModel::RoleArt] = "art"; |
91 | + m_roles[ResultsModel::RoleSubtitle] = "subtitle"; |
92 | + m_roles[ResultsModel::RoleMascot] = "mascot"; |
93 | + m_roles[ResultsModel::RoleEmblem] = "emblem"; |
94 | + m_roles[ResultsModel::RoleOldPrice] = "oldPrice"; |
95 | + m_roles[ResultsModel::RolePrice] = "price"; |
96 | + m_roles[ResultsModel::RoleAltPrice] = "altPrice"; |
97 | + m_roles[ResultsModel::RoleRating] = "rating"; |
98 | + m_roles[ResultsModel::RoleAltRating] = "altRating"; |
99 | + m_roles[ResultsModel::RoleSummary] = "summary"; |
100 | } |
101 | |
102 | QString ResultsModel::categoryId() const |
103 | @@ -95,36 +102,66 @@ |
104 | } |
105 | |
106 | QVariant |
107 | +ResultsModel::componentValue(scopes::CategorisedResult* result, std::string const& fieldName) const |
108 | +{ |
109 | + // FIXME: component field mapping |
110 | + if (!result->has_metadata(fieldName)) { |
111 | + return QVariant(); |
112 | + } |
113 | + scopes::Variant const& v = result->metadata(fieldName); |
114 | + if (v.which() != scopes::Variant::Type::String) { |
115 | + return QVariant(); |
116 | + } |
117 | + |
118 | + return QString::fromStdString(v.get_string()); |
119 | +} |
120 | + |
121 | +QVariant |
122 | ResultsModel::data(const QModelIndex& index, int role) const |
123 | { |
124 | scopes::CategorisedResult* result = m_results.at(index.row()).get(); |
125 | |
126 | switch (role) { |
127 | case RoleUri: |
128 | - return QVariant(QString::fromStdString(result->uri())); |
129 | - case RoleIconHint: { |
130 | - QString iconHint(QString::fromStdString(result->art())); |
131 | - if (iconHint.isEmpty()) { |
132 | + return QString::fromStdString(result->uri()); |
133 | + case RoleCategoryId: |
134 | + return QString::fromStdString(result->category()->id()); |
135 | + case RoleDndUri: |
136 | + return QString::fromStdString(result->dnd_uri()); |
137 | + case RoleMetadata: |
138 | + return QVariantMap(); // FIXME! would be great to keep it opaque, so it isn't misused |
139 | + case RoleTitle: |
140 | + return QString::fromStdString(result->title()); |
141 | + case RoleArt: { |
142 | + QString image(QString::fromStdString(result->art())); |
143 | + if (image.isEmpty()) { |
144 | QString uri(QString::fromStdString(result->uri())); |
145 | + // FIXME: what to do about mimetype? |
146 | QString thumbnailerUri(uriToThumbnailerProviderString(uri, QString(), QVariantHash())); |
147 | if (!thumbnailerUri.isNull()) { |
148 | - return QVariant::fromValue(thumbnailerUri); |
149 | + return thumbnailerUri; |
150 | } |
151 | } |
152 | - return QVariant(iconHint); |
153 | + return image; |
154 | } |
155 | - case RoleCategory: |
156 | - return QVariant(QString::fromStdString(result->category()->id())); |
157 | - case RoleTitle: |
158 | - return QVariant(QString::fromStdString(result->title())); |
159 | - case RoleComment: |
160 | - return QVariant(); |
161 | - case RoleDndUri: |
162 | - return QVariant(QString::fromStdString(result->dnd_uri())); |
163 | - case RoleMetadata: |
164 | - return QVariant(QVariantMap()); |
165 | - case RoleRendererHints: |
166 | - return QVariant(); |
167 | + case RoleSubtitle: |
168 | + return componentValue(result, "subtitle"); |
169 | + case RoleMascot: |
170 | + return componentValue(result, "mascot"); |
171 | + case RoleEmblem: |
172 | + return componentValue(result, "emblem"); |
173 | + case RoleOldPrice: |
174 | + return componentValue(result, "old-price"); |
175 | + case RolePrice: |
176 | + return componentValue(result, "price"); |
177 | + case RoleAltPrice: |
178 | + return componentValue(result, "alt-price"); |
179 | + case RoleRating: |
180 | + return componentValue(result, "rating"); |
181 | + case RoleAltRating: |
182 | + return componentValue(result, "alt-rating"); |
183 | + case RoleSummary: |
184 | + return componentValue(result, "summary"); |
185 | default: |
186 | return QVariant(); |
187 | } |
188 | |
189 | === modified file 'src/Unity/scopes-ng/resultsmodel.h' |
190 | --- src/Unity/scopes-ng/resultsmodel.h 2013-12-05 10:40:44 +0000 |
191 | +++ src/Unity/scopes-ng/resultsmodel.h 2013-12-12 12:53:45 +0000 |
192 | @@ -24,6 +24,7 @@ |
193 | #include <QAbstractListModel> |
194 | |
195 | #include <scopes/CategorisedResult.h> |
196 | +#include <unordered_map> |
197 | |
198 | namespace scopes_ng { |
199 | |
200 | @@ -41,16 +42,24 @@ |
201 | |
202 | enum Roles { |
203 | RoleUri, |
204 | - RoleIconHint, |
205 | - RoleCategory, |
206 | - RoleTitle, |
207 | - RoleComment, |
208 | + RoleCategoryId, |
209 | RoleDndUri, |
210 | RoleMetadata, |
211 | - RoleRendererHints |
212 | + // card components |
213 | + RoleTitle, |
214 | + RoleArt, |
215 | + RoleSubtitle, |
216 | + RoleMascot, |
217 | + RoleEmblem, |
218 | + RoleOldPrice, |
219 | + RolePrice, |
220 | + RoleAltPrice, |
221 | + RoleRating, |
222 | + RoleAltRating, |
223 | + RoleSummary |
224 | }; |
225 | |
226 | - int rowCount(const QModelIndex& parent) const override; |
227 | + int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
228 | QHash<int, QByteArray> roleNames() const override; |
229 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
230 | |
231 | @@ -69,7 +78,10 @@ |
232 | void countChanged(); |
233 | |
234 | private: |
235 | + QVariant componentValue(unity::api::scopes::CategorisedResult* result, std::string const& fieldName) const; |
236 | + |
237 | QHash<int, QByteArray> m_roles; |
238 | + std::unordered_map<std::string, std::string> m_componentMapping; |
239 | QList<std::shared_ptr<unity::api::scopes::CategorisedResult>> m_results; |
240 | QString m_categoryId; |
241 | }; |
242 | |
243 | === modified file 'src/Unity/scopes-ng/scope.h' |
244 | --- src/Unity/scopes-ng/scope.h 2013-12-05 18:05:13 +0000 |
245 | +++ src/Unity/scopes-ng/scope.h 2013-12-12 12:53:45 +0000 |
246 | @@ -35,7 +35,7 @@ |
247 | |
248 | class Categories; |
249 | |
250 | -class Scope : public QObject |
251 | +class Q_DECL_EXPORT Scope : public QObject |
252 | { |
253 | Q_OBJECT |
254 | |
255 | |
256 | === modified file 'src/Unity/scopes-ng/scopes.cpp' |
257 | --- src/Unity/scopes-ng/scopes.cpp 2013-12-06 10:47:26 +0000 |
258 | +++ src/Unity/scopes-ng/scopes.cpp 2013-12-12 12:53:45 +0000 |
259 | @@ -41,9 +41,8 @@ |
260 | { |
261 | try |
262 | { |
263 | - // FIXME: use proper path for the runtime config |
264 | - // but have libunity-scopes export it first?! |
265 | - m_scopesRuntime = scopes::Runtime::create(); |
266 | + // m_runtimeConfig should be null in most cases, and empty string is for system-wide fallback |
267 | + m_scopesRuntime = scopes::Runtime::create(m_runtimeConfig.toStdString()); |
268 | auto registry = m_scopesRuntime->registry(); |
269 | m_metadataMap = registry->list(); |
270 | } |
271 | @@ -54,6 +53,11 @@ |
272 | Q_EMIT discoveryFinished(); |
273 | } |
274 | |
275 | +void ScopeListWorker::setRuntimeConfig(QString const& config) |
276 | +{ |
277 | + m_runtimeConfig = config; |
278 | +} |
279 | + |
280 | scopes::Runtime::UPtr ScopeListWorker::takeRuntime() |
281 | { |
282 | return std::move(m_scopesRuntime); |
283 | @@ -63,7 +67,7 @@ |
284 | { |
285 | return m_metadataMap; |
286 | } |
287 | - |
288 | + |
289 | Scopes::Scopes(QObject *parent) |
290 | : QAbstractListModel(parent) |
291 | , m_listThread(nullptr) |
292 | @@ -102,6 +106,8 @@ |
293 | void Scopes::populateScopes() |
294 | { |
295 | auto thread = new ScopeListWorker; |
296 | + QByteArray runtimeConfig = qgetenv("UNITY_SCOPES_RUNTIME_PATH"); |
297 | + thread->setRuntimeConfig(QString::fromLocal8Bit(runtimeConfig)); |
298 | QObject::connect(thread, &ScopeListWorker::discoveryFinished, this, &Scopes::discoveryFinished); |
299 | QObject::connect(thread, &ScopeListWorker::finished, thread, &QObject::deleteLater); |
300 | |
301 | @@ -138,11 +144,11 @@ |
302 | case Scopes::RoleScope: |
303 | return QVariant::fromValue(scope); |
304 | case Scopes::RoleId: |
305 | - return QVariant::fromValue(scope->id()); |
306 | + return QString(scope->id()); |
307 | case Scopes::RoleVisible: |
308 | return QVariant::fromValue(scope->visible()); |
309 | case Scopes::RoleTitle: |
310 | - return QVariant::fromValue(scope->name()); |
311 | + return QString(scope->name()); |
312 | default: |
313 | return QVariant(); |
314 | } |
315 | @@ -150,7 +156,10 @@ |
316 | |
317 | QVariant Scopes::get(int row) const |
318 | { |
319 | - return data(QAbstractListModel::index(row), 0); |
320 | + if (row >= m_scopes.size() || row < 0) { |
321 | + return QVariant(); |
322 | + } |
323 | + return data(QAbstractListModel::index(row), RoleScope); |
324 | } |
325 | |
326 | QVariant Scopes::get(const QString& scope_id) const |
327 | |
328 | === modified file 'src/Unity/scopes-ng/scopes.h' |
329 | --- src/Unity/scopes-ng/scopes.h 2013-12-04 14:13:45 +0000 |
330 | +++ src/Unity/scopes-ng/scopes.h 2013-12-12 12:53:45 +0000 |
331 | @@ -35,7 +35,7 @@ |
332 | |
333 | class Scope; |
334 | |
335 | -class Scopes : public QAbstractListModel |
336 | +class Q_DECL_EXPORT Scopes : public QAbstractListModel |
337 | { |
338 | Q_OBJECT |
339 | |
340 | @@ -85,6 +85,7 @@ |
341 | Q_OBJECT |
342 | |
343 | public: |
344 | + void setRuntimeConfig(QString const& config); |
345 | void run() override; |
346 | unity::api::scopes::Runtime::UPtr takeRuntime(); |
347 | unity::api::scopes::MetadataMap metadataMap() const; |
348 | @@ -93,6 +94,7 @@ |
349 | void discoveryFinished(); |
350 | |
351 | private: |
352 | + QString m_runtimeConfig; |
353 | unity::api::scopes::Runtime::UPtr m_scopesRuntime; |
354 | unity::api::scopes::MetadataMap m_metadataMap; |
355 | }; |
356 | |
357 | === modified file 'tests/CMakeLists.txt' |
358 | --- tests/CMakeLists.txt 2013-11-25 15:07:51 +0000 |
359 | +++ tests/CMakeLists.txt 2013-12-12 12:53:45 +0000 |
360 | @@ -1,8 +1,15 @@ |
361 | +include(FindPkgConfig) |
362 | pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0>=7.1.1) |
363 | pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private) |
364 | pkg_check_modules(LIBUNITY REQUIRED unity) |
365 | pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0) |
366 | pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2) |
367 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1.3) |
368 | + |
369 | +set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) |
370 | +set(SCOPES_TEST_RUNTIME ${CMAKE_CURRENT_BINARY_DIR}/data/Runtime.ini) |
371 | + |
372 | +add_subdirectory(data) |
373 | |
374 | include_directories( |
375 | ${Unity-qml_SOURCE_DIR} |
376 | @@ -13,6 +20,7 @@ |
377 | ${LIBSIGCPP_INCLUDE_DIRS} |
378 | ${UNITYCORE_INCLUDE_DIRS} |
379 | ${QTDEE_INCLUDE_DIRS} |
380 | + ${SCOPESLIB_INCLUDE_DIRS} |
381 | ) |
382 | |
383 | macro(run_tests) |
384 | @@ -27,7 +35,9 @@ |
385 | add_executable(${_test}Exec ${_test}.cpp) |
386 | qt5_use_modules(${_test}Exec Test Core Qml) |
387 | set_tests_properties(test${CLASSNAME}${_test} |
388 | - PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Unity:${LIBUNITYPROTO_LIBRARY_DIRS}") |
389 | + PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Unity:${LIBUNITYPROTO_LIBRARY_DIRS};UNITY_SCOPES_RUNTIME_PATH=${SCOPES_TEST_RUNTIME}") |
390 | + set_target_properties(${_test}Exec |
391 | + PROPERTIES COMPILE_FLAGS "-DTEST_SCOPEREGISTRY_BIN='\"${SCOPES_BIN_DIR}/scoperegistry/scoperegistry\"' -DTEST_RUNTIME_CONFIG='\"${SCOPES_TEST_RUNTIME}\"'") |
392 | |
393 | target_link_libraries(${_test}Exec |
394 | Unity-qml |
395 | @@ -36,6 +46,7 @@ |
396 | ${LIBUNITYPROTO_LDFLAGS} |
397 | ${LIBSIGCPP_LDFLAGS} |
398 | ${QTDEE_LDFLAGS} |
399 | + ${SCOPESLIB_LDFLAGS} |
400 | ) |
401 | |
402 | set(_test_list "${_test_list};${_test}") |
403 | @@ -47,4 +58,5 @@ |
404 | previewbindingstest |
405 | filtersbindingstest |
406 | resultstest |
407 | + resultstest-ng |
408 | ) |
409 | |
410 | === added directory 'tests/data' |
411 | === added file 'tests/data/CMakeLists.txt' |
412 | --- tests/data/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
413 | +++ tests/data/CMakeLists.txt 2013-12-12 12:53:45 +0000 |
414 | @@ -0,0 +1,7 @@ |
415 | +add_subdirectory(mock-scope) |
416 | + |
417 | +configure_file(Runtime.ini.in Runtime.ini @ONLY) |
418 | +configure_file(Registry.ini.in Registry.ini @ONLY) |
419 | +configure_file(Zmq.ini.in Zmq.ini @ONLY) |
420 | + |
421 | +execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/endpoints) |
422 | |
423 | === added file 'tests/data/Registry.ini.in' |
424 | --- tests/data/Registry.ini.in 1970-01-01 00:00:00 +0000 |
425 | +++ tests/data/Registry.ini.in 2013-12-12 12:53:45 +0000 |
426 | @@ -0,0 +1,7 @@ |
427 | +[Registry] |
428 | +Middleware = Zmq |
429 | +Zmq.Endpoint = ipc:///tmp/scopes-test-endpoints/Registry |
430 | +Zmq.EndpointDir = /tmp/scopes-test-endpoints |
431 | +Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini |
432 | +Scope.InstallDir = @CMAKE_CURRENT_BINARY_DIR@ |
433 | +Scoperunner.Path = @SCOPES_BIN_DIR@/scoperunner/scoperunner |
434 | |
435 | === added file 'tests/data/Runtime.ini.in' |
436 | --- tests/data/Runtime.ini.in 1970-01-01 00:00:00 +0000 |
437 | +++ tests/data/Runtime.ini.in 2013-12-12 12:53:45 +0000 |
438 | @@ -0,0 +1,6 @@ |
439 | +[Runtime] |
440 | +Registry.Identity = Registry |
441 | +Registry.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Registry.ini |
442 | +Default.Middleware = Zmq |
443 | +Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini |
444 | +Factory.ConfigFile = Factory.ini |
445 | |
446 | === added file 'tests/data/Zmq.ini.in' |
447 | --- tests/data/Zmq.ini.in 1970-01-01 00:00:00 +0000 |
448 | +++ tests/data/Zmq.ini.in 2013-12-12 12:53:45 +0000 |
449 | @@ -0,0 +1,3 @@ |
450 | +[Zmq] |
451 | +EndpointDir.Public = /tmp/scopes-test-endpoints |
452 | +EndpointDir.Private = /tmp/scopes-test-endpoints |
453 | |
454 | === added directory 'tests/data/mock-scope' |
455 | === added file 'tests/data/mock-scope/CMakeLists.txt' |
456 | --- tests/data/mock-scope/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
457 | +++ tests/data/mock-scope/CMakeLists.txt 2013-12-12 12:53:45 +0000 |
458 | @@ -0,0 +1,11 @@ |
459 | +include(FindPkgConfig) |
460 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.1.2) |
461 | + |
462 | +set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) |
463 | + |
464 | +include_directories(${SCOPESLIB_INCLUDE_DIRS}) |
465 | + |
466 | +add_library(mock-scope MODULE mock-scope.cpp) |
467 | +target_link_libraries(mock-scope ${SCOPESLIB_LDFLAGS}) |
468 | + |
469 | +configure_file(mock-scope.ini.in mock-scope.ini) |
470 | |
471 | === added file 'tests/data/mock-scope/mock-scope.cpp' |
472 | --- tests/data/mock-scope/mock-scope.cpp 1970-01-01 00:00:00 +0000 |
473 | +++ tests/data/mock-scope/mock-scope.cpp 2013-12-12 12:53:45 +0000 |
474 | @@ -0,0 +1,119 @@ |
475 | +/* |
476 | + * Copyright (C) 2013 Canonical, Ltd. |
477 | + * |
478 | + * This program is free software; you can redistribute it and/or modify |
479 | + * it under the terms of the GNU General Public License as published by |
480 | + * the Free Software Foundation; version 3. |
481 | + * |
482 | + * This program is distributed in the hope that it will be useful, |
483 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
484 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
485 | + * GNU General Public License for more details. |
486 | + * |
487 | + * You should have received a copy of the GNU General Public License |
488 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
489 | + * |
490 | + * Authors: |
491 | + * Michal Hruby <michal.hruby@canonical.com> |
492 | + */ |
493 | + |
494 | +#include <scopes/ScopeBase.h> |
495 | +#include <scopes/Reply.h> |
496 | +#include <scopes/Category.h> |
497 | +#include <scopes/CategorisedResult.h> |
498 | +#include <scopes/CategoryRenderer.h> |
499 | + |
500 | +#include <iostream> |
501 | + |
502 | +#define EXPORT __attribute__ ((visibility ("default"))) |
503 | + |
504 | +using namespace std; |
505 | +using namespace unity::api::scopes; |
506 | + |
507 | +// Example scope A: replies synchronously to a query. (Replies are returned before returning from the run() method.) |
508 | + |
509 | +class MyQuery : public QueryBase |
510 | +{ |
511 | +public: |
512 | + MyQuery(string const& query) : |
513 | + query_(query) |
514 | + { |
515 | + } |
516 | + |
517 | + ~MyQuery() noexcept |
518 | + { |
519 | + } |
520 | + |
521 | + virtual void cancelled() override |
522 | + { |
523 | + } |
524 | + |
525 | + virtual void run(ReplyProxy const& reply) override |
526 | + { |
527 | + CategoryRenderer rdr; |
528 | + if (query_ == "metadata") |
529 | + { |
530 | + auto cat = reply->register_category("cat1", "Category 1", "", rdr); |
531 | + CategorisedResult res(cat); |
532 | + res.set_uri("test:uri"); |
533 | + res.set_title("result for: \"" + query_ + "\""); |
534 | + res.set_art("art"); |
535 | + res.set_dnd_uri("test:dnd_uri"); |
536 | + res.add_metadata("subtitle", Variant("subtitle")); |
537 | + res.add_metadata("emblem", Variant("emblem")); |
538 | + reply->push(res); |
539 | + } |
540 | + else |
541 | + { |
542 | + auto cat = reply->register_category("cat1", "Category 1", "", rdr); |
543 | + CategorisedResult res(cat); |
544 | + res.set_uri("test:uri"); |
545 | + res.set_title("result for: \"" + query_ + "\""); |
546 | + res.set_art("art"); |
547 | + res.set_dnd_uri("test:dnd_uri"); |
548 | + reply->push(res); |
549 | + } |
550 | + } |
551 | + |
552 | +private: |
553 | + string query_; |
554 | +}; |
555 | + |
556 | +class MyScope : public ScopeBase |
557 | +{ |
558 | +public: |
559 | + virtual int start(string const&, RegistryProxy const&) override |
560 | + { |
561 | + return VERSION; |
562 | + } |
563 | + |
564 | + virtual void stop() override {} |
565 | + |
566 | + virtual QueryBase::UPtr create_query(string const& q, VariantMap const&) override |
567 | + { |
568 | + QueryBase::UPtr query(new MyQuery(q)); |
569 | + cout << "scope-A: created query: \"" << q << "\"" << endl; |
570 | + return query; |
571 | + } |
572 | +}; |
573 | + |
574 | +extern "C" |
575 | +{ |
576 | + |
577 | + EXPORT |
578 | + unity::api::scopes::ScopeBase* |
579 | + // cppcheck-suppress unusedFunction |
580 | + UNITY_API_SCOPE_CREATE_FUNCTION() |
581 | + { |
582 | + return new MyScope; |
583 | + } |
584 | + |
585 | + EXPORT |
586 | + void |
587 | + // cppcheck-suppress unusedFunction |
588 | + UNITY_API_SCOPE_DESTROY_FUNCTION(unity::api::scopes::ScopeBase* scope_base) |
589 | + { |
590 | + delete scope_base; |
591 | + } |
592 | + |
593 | +} |
594 | |
595 | === added file 'tests/data/mock-scope/mock-scope.ini.in' |
596 | --- tests/data/mock-scope/mock-scope.ini.in 1970-01-01 00:00:00 +0000 |
597 | +++ tests/data/mock-scope/mock-scope.ini.in 2013-12-12 12:53:45 +0000 |
598 | @@ -0,0 +1,7 @@ |
599 | +[ScopeConfig] |
600 | +DisplayName = mock.DisplayName |
601 | +Description = mock.Description |
602 | +Art = mock.Art |
603 | +Icon = mock.Icon |
604 | +SearchHint = mock.SearchHint |
605 | +HotKey = mock.HotKey |
606 | |
607 | === added file 'tests/resultstest-ng.cpp' |
608 | --- tests/resultstest-ng.cpp 1970-01-01 00:00:00 +0000 |
609 | +++ tests/resultstest-ng.cpp 2013-12-12 12:53:45 +0000 |
610 | @@ -0,0 +1,200 @@ |
611 | +/* |
612 | + * Copyright (C) 2013 Canonical, Ltd. |
613 | + * |
614 | + * This program is free software; you can redistribute it and/or modify |
615 | + * it under the terms of the GNU General Public License as published by |
616 | + * the Free Software Foundation; version 3. |
617 | + * |
618 | + * This program is distributed in the hope that it will be useful, |
619 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
620 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
621 | + * GNU General Public License for more details. |
622 | + * |
623 | + * You should have received a copy of the GNU General Public License |
624 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
625 | + * |
626 | + * Authors: |
627 | + * Michal Hruby <michal.hruby@canonical.com> |
628 | + */ |
629 | + |
630 | +#include <QObject> |
631 | +#include <QTest> |
632 | +#include <QFile> |
633 | +#include <QFileInfo> |
634 | +#include <QDir> |
635 | +#include <QProcess> |
636 | +#include <QThread> |
637 | +#include <QScopedPointer> |
638 | + |
639 | +#include <scopes-ng/scopes.h> |
640 | +#include <scopes-ng/scope.h> |
641 | +#include <scopes-ng/categories.h> |
642 | +#include <scopes-ng/resultsmodel.h> |
643 | + |
644 | +#define SCOPES_TMP_ENDPOINT_DIR "/tmp/scopes-test-endpoints" |
645 | + |
646 | +using namespace scopes_ng; |
647 | + |
648 | +class ResultsTestNg : public QObject |
649 | +{ |
650 | + Q_OBJECT |
651 | +private: |
652 | + QScopedPointer<Scopes> m_scopes; |
653 | + Scope* m_scope; |
654 | + QScopedPointer<QProcess> m_registry; |
655 | + |
656 | +private Q_SLOTS: |
657 | + void initTestCase() |
658 | + { |
659 | + QDir endpointdir(QFileInfo(TEST_RUNTIME_CONFIG).dir()); |
660 | + endpointdir.cd(QString("endpoints")); |
661 | + QFile::remove(SCOPES_TMP_ENDPOINT_DIR); |
662 | + // symlinking to workaround "File name too long" issue |
663 | + QVERIFY2(QFile::link(endpointdir.absolutePath(), SCOPES_TMP_ENDPOINT_DIR), |
664 | + "Unable to create symlink " SCOPES_TMP_ENDPOINT_DIR); |
665 | + // startup our private scope registry |
666 | + QString registryBin(TEST_SCOPEREGISTRY_BIN); |
667 | + QStringList arguments; |
668 | + arguments << TEST_RUNTIME_CONFIG; |
669 | + |
670 | + m_registry.reset(new QProcess(nullptr)); |
671 | + m_registry->start(registryBin, arguments); |
672 | + } |
673 | + |
674 | + void cleanupTestCase() |
675 | + { |
676 | + if (m_registry) { |
677 | + m_registry->terminate(); |
678 | + if (!m_registry->waitForFinished()) { |
679 | + m_registry->kill(); |
680 | + } |
681 | + } |
682 | + QFile::remove(SCOPES_TMP_ENDPOINT_DIR); |
683 | + } |
684 | + |
685 | + void init() |
686 | + { |
687 | + m_scopes.reset(new Scopes(nullptr)); |
688 | + // no scopes on startup |
689 | + QCOMPARE(m_scopes->rowCount(), 0); |
690 | + // wait till the registry spawns |
691 | + QTRY_COMPARE(m_scopes->loaded(), true); |
692 | + // should have one scope now |
693 | + QCOMPARE(m_scopes->rowCount(), 1); |
694 | + |
695 | + QVariant scope_var = m_scopes->data(m_scopes->index(0), Scopes::Roles::RoleScope); |
696 | + QVERIFY(scope_var.canConvert<Scope*>()); |
697 | + |
698 | + // get scope proxy |
699 | + m_scope = scope_var.value<Scope*>(); |
700 | + } |
701 | + |
702 | + void cleanup() |
703 | + { |
704 | + m_scopes.reset(); |
705 | + m_scope = nullptr; |
706 | + } |
707 | + |
708 | + void testScopeCommunication() |
709 | + { |
710 | + QCOMPARE(m_scope->searchInProgress(), false); |
711 | + // perform a search |
712 | + m_scope->setSearchQuery(QString("")); |
713 | + QCOMPARE(m_scope->searchInProgress(), true); |
714 | + QTRY_COMPARE(m_scope->searchInProgress(), false); |
715 | + |
716 | + // ensure categories have > 0 rows |
717 | + auto categories = m_scope->categories(); |
718 | + QVERIFY(categories->rowCount() > 0); |
719 | + QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults); |
720 | + QVERIFY(results_var.canConvert<ResultsModel*>()); |
721 | + |
722 | + // ensure results have some data |
723 | + auto results = results_var.value<ResultsModel*>(); |
724 | + QVERIFY(results->rowCount() > 0); |
725 | + } |
726 | + |
727 | + void testScopesGet() |
728 | + { |
729 | + QVariant scope_var = m_scopes->get(0); |
730 | + QVERIFY(scope_var.canConvert<scopes_ng::Scope*>()); |
731 | + |
732 | + // try incorrect index as well |
733 | + scope_var = m_scopes->get(65536); |
734 | + QVERIFY(scope_var.isNull()); |
735 | + scope_var = m_scopes->get(-1); |
736 | + QVERIFY(scope_var.isNull()); |
737 | + } |
738 | + |
739 | + void testTwoSearches() |
740 | + { |
741 | + QCOMPARE(m_scope->searchInProgress(), false); |
742 | + // perform a search |
743 | + m_scope->setSearchQuery(QString("")); |
744 | + QCOMPARE(m_scope->searchInProgress(), true); |
745 | + QTRY_COMPARE(m_scope->searchInProgress(), false); |
746 | + |
747 | + // ensure categories have > 0 rows |
748 | + auto categories = m_scope->categories(); |
749 | + auto categories_count = categories->rowCount(); |
750 | + QVERIFY(categories_count > 0); |
751 | + |
752 | + m_scope->setSearchQuery(QString("foo")); |
753 | + QCOMPARE(m_scope->searchInProgress(), true); |
754 | + // wait for the search to finish |
755 | + QTRY_COMPARE(m_scope->searchInProgress(), false); |
756 | + |
757 | + // shouldn't create more nor fewer categories |
758 | + QVERIFY(categories->rowCount() == categories_count); |
759 | + } |
760 | + |
761 | + void testBasicResultData() |
762 | + { |
763 | + QCOMPARE(m_scope->searchInProgress(), false); |
764 | + // perform a search |
765 | + m_scope->setSearchQuery(QString("")); |
766 | + QCOMPARE(m_scope->searchInProgress(), true); |
767 | + QTRY_COMPARE(m_scope->searchInProgress(), false); |
768 | + |
769 | + // get ResultsModel instance |
770 | + auto categories = m_scope->categories(); |
771 | + QVERIFY(categories->rowCount() > 0); |
772 | + QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults); |
773 | + QVERIFY(results_var.canConvert<ResultsModel*>()); |
774 | + auto results = results_var.value<ResultsModel*>(); |
775 | + QVERIFY(results->rowCount() > 0); |
776 | + |
777 | + auto idx = results->index(0); |
778 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleUri).toString(), QString("test:uri")); |
779 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleDndUri).toString(), QString("test:dnd_uri")); |
780 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleTitle).toString(), QString("result for: \"\"")); |
781 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleArt).toString(), QString("art")); |
782 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleCategoryId), categories->data(categories->index(0), Categories::Roles::RoleCategoryId)); |
783 | + } |
784 | + |
785 | + void testMetadataData() |
786 | + { |
787 | + QCOMPARE(m_scope->searchInProgress(), false); |
788 | + // perform a search |
789 | + m_scope->setSearchQuery(QString("metadata")); |
790 | + QCOMPARE(m_scope->searchInProgress(), true); |
791 | + QTRY_COMPARE(m_scope->searchInProgress(), false); |
792 | + |
793 | + // get ResultsModel instance |
794 | + auto categories = m_scope->categories(); |
795 | + QVERIFY(categories->rowCount() > 0); |
796 | + QVariant results_var = categories->data(categories->index(0), Categories::Roles::RoleResults); |
797 | + QVERIFY(results_var.canConvert<ResultsModel*>()); |
798 | + auto results = results_var.value<ResultsModel*>(); |
799 | + QVERIFY(results->rowCount() > 0); |
800 | + |
801 | + auto idx = results->index(0); |
802 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleTitle).toString(), QString("result for: \"metadata\"")); |
803 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleSubtitle).toString(), QString("subtitle")); |
804 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleEmblem).toString(), QString("emblem")); |
805 | + QCOMPARE(results->data(idx, ResultsModel::Roles::RoleAltRating).toString(), QString()); |
806 | + } |
807 | +}; |
808 | + |
809 | +QTEST_MAIN(ResultsTestNg) |
810 | +#include <resultstest-ng.moc> |
FAILED: Continuous integration, rev:29 jenkins. qa.ubuntu. com/job/ unity-scopes- shell-ci/ 12/ jenkins. qa.ubuntu. com/job/ unity-scopes- shell-trusty- amd64-ci/ 12/console jenkins. qa.ubuntu. com/job/ unity-scopes- shell-trusty- armhf-ci/ 12/console jenkins. qa.ubuntu. com/job/ unity-scopes- shell-trusty- i386-ci/ 12/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- scopes- shell-ci/ 12/rebuild
http://