Merge lp:~mhr3/unity-scopes-shell/scopes-ng-tests into lp:unity-scopes-shell

Proposed by Michal Hruby
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
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.

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
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
Michael Zanetti (mzanetti) wrote :

92 + return QVariant(QString::fromStdString(v.get_string()));
107 + return QVariant(QString::fromStdString(result->category()->id()));

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_map<std::string, std::string> m_componentMapping;

unused?

========

379 +#Scope.GroupConfigDir = @CMAKE_CURRENT_BINARY_DIR@/scope-groups

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/data/scope-A/scope-A.cpp'

This seems like a mock. calling the directory "mocks" instead of data would make that more obvious imho.

=======
674 + void testTwoSearches()
675 + {
676 + QCOMPARE(m_scope->searchInProgress(), false);
677 + // perform a search
678 + m_scope->setSearchQuery(QString(""));
679 + QCOMPARE(m_scope->searchInProgress(), true);
680 + QTRY_COMPARE(m_scope->searchInProgress(), false);
681 +
682 + // ensure categories have > 0 rows
683 + auto categories = m_scope->categories();
684 + auto categories_count = categories->rowCount();
685 + QVERIFY(categories_count > 0);
686 +
687 + m_scope->setSearchQuery(QString("foo"));
688 + QCOMPARE(m_scope->searchInProgress(), true);
689 + // wait for the search to finish
690 + QTRY_COMPARE(m_scope->searchInProgress(), false);
691 +
692 + // shouldn't create more nor fewer categories
693 + QVERIFY(categories->rowCount() == categories_count);
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.

Revision history for this message
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_map<std::string, std::string> m_componentMapping;
>
> unused?

Will be used soon :)

> 379 +#Scope.GroupConfigDir = @CMAKE_CURRENT_BINARY_DIR@/scope-groups
>
> 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/data/scope-A/scope-A.cpp'
>
> 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.

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
Michael Zanetti (mzanetti) wrote :

+1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

qmlplugindump crash, retrying...

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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>

Subscribers

People subscribed via source and target branches

to all changes: