on xenial help sign in
Started writing test for search indicator.
eb5de7fNicolas d'Offay
plugins/Unity/scope.cpp+30−5
@@ -33,12 +33,14 @@
33#include <QQmlEngine>
33#include <QQmlEngine>
34
34
35#include <UnityCore/Variant.h>
35#include <UnityCore/Variant.h>
36+#include <UnityCore/GLibWrapper.h>
36
37
37#include <libintl.h>
38#include <libintl.h>
38#include <glib.h>
39#include <glib.h>
39
40
40Scope::Scope(QObject *parent) : QObject(parent)
41Scope::Scope(QObject *parent) : QObject(parent)
41 , m_formFactor("phone")
42 , m_formFactor("phone")
43+ , m_searchInProgress(false)
42{
44{
43 m_categories.reset(new Categories(this));
45 m_categories.reset(new Categories(this));
44}
46}
@@ -68,6 +70,11 @@ QString Scope::searchHint() const
68 return QString::fromStdString(m_unityScope->search_hint());
70 return QString::fromStdString(m_unityScope->search_hint());
69}
71}
70
72
73+bool Scope::searchInProgress() const
74+{
75+ return m_searchInProgress;
76+}
77+
71bool Scope::visible() const
78bool Scope::visible() const
72{
79{
73 return m_unityScope->visible();
80 return m_unityScope->visible();
@@ -115,10 +122,15 @@ void Scope::setSearchQuery(const QString& search_query)
115 string ("") and m_searchQuery is the null string,
122 string ("") and m_searchQuery is the null string,
116 search_query != m_searchQuery is still true.
123 search_query != m_searchQuery is still true.
117 */
124 */
125+ using namespace std::placeholders;
126+
118 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
127 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
119 m_searchQuery = search_query;
128 m_searchQuery = search_query;
129+ m_cancellable.Renew();
130+ m_searchInProgress = true;
120− m_unityScope->Search(search_query.toStdString(), sigc::mem_fun(this, &Scope::searchFinished));
131+ m_unityScope->Search(search_query.toStdString(), std::bind(&Scope::onSearchFinished, this, _1, _2, _3), m_cancellable);
121 Q_EMIT searchQueryChanged();
132 Q_EMIT searchQueryChanged();
133+ Q_EMIT searchInProgressChanged();
122 }
134 }
123}
135}
124
136
@@ -294,8 +306,6 @@ void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
294 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
306 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
295 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
307 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
296 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
308 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
297− /* Signals forwarding */
298− connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
299
309
300 /* FIXME: signal should be forwarded instead of calling the handler directly */
310 /* FIXME: signal should be forwarded instead of calling the handler directly */
301 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
311 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
@@ -316,18 +326,33 @@ unity::dash::Scope::Ptr Scope::unityScope() const
316
326
317void Scope::synchronizeStates()
327void Scope::synchronizeStates()
318{
328{
329+ using namespace std::placeholders;
330+
319 if (connected()) {
331 if (connected()) {
320 /* Forward local states to m_unityScope */
332 /* Forward local states to m_unityScope */
321 if (!m_searchQuery.isNull()) {
333 if (!m_searchQuery.isNull()) {
334+ m_cancellable.Renew();
335+ m_searchInProgress = true;
322− m_unityScope->Search(m_searchQuery.toStdString());
336+ m_unityScope->Search(m_searchQuery.toStdString(), std::bind(&Scope::onSearchFinished, this, _1, _2, _3), m_cancellable);
337+ Q_EMIT searchInProgressChanged();
323 }
338 }
324 }
339 }
325}
340}
326
341
327−void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
342+void Scope::onSearchFinished(std::string const& /* query */, unity::glib::HintsMap const& hints, unity::glib::Error const& err)
328{
343{
329 QString hint;
344 QString hint;
330
345
346+ GError* error = const_cast<unity::glib::Error&>(err);
347+
348+ if (!err || !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
349+ m_searchInProgress = false;
350+ Q_EMIT searchInProgressChanged();
351+ } else {
352+ // no need to check the results hint, we're still searching
353+ return;
354+ }
355+
331 if (!m_unityScope->results()->count()) {
356 if (!m_unityScope->results()->count()) {
332 unity::glib::HintsMap::const_iterator it = hints.find("no-results-hint");
357 unity::glib::HintsMap::const_iterator it = hints.find("no-results-hint");
333 if (it != hints.end()) {
358 if (it != hints.end()) {
plugins/Unity/scope.h+7−2
@@ -28,6 +28,7 @@
28// libunity-core
28// libunity-core
29#include <UnityCore/Scope.h>
29#include <UnityCore/Scope.h>
30#include <UnityCore/Results.h>
30#include <UnityCore/Results.h>
31+#include <UnityCore/GLibWrapper.h>
31
32
32#include "categories.h"
33#include "categories.h"
33#include "filters.h"
34#include "filters.h"
@@ -43,6 +44,7 @@ class Scope : public QObject
43 Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
44 Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
44 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
45 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
45 Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
46 Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
47+ Q_PROPERTY(bool searchInProgress READ searchInProgress NOTIFY searchInProgressChanged)
46 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
48 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
47 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
49 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
48 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
50 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
@@ -65,6 +67,7 @@ public:
65 bool visible() const;
67 bool visible() const;
66 QString shortcut() const;
68 QString shortcut() const;
67 bool connected() const;
69 bool connected() const;
70+ bool searchInProgress() const;
68 Categories* categories() const;
71 Categories* categories() const;
69 Filters* filters() const;
72 Filters* filters() const;
70 QString searchQuery() const;
73 QString searchQuery() const;
@@ -95,11 +98,11 @@ Q_SIGNALS:
95 void iconHintChanged(const std::string&);
98 void iconHintChanged(const std::string&);
96 void descriptionChanged(const std::string&);
99 void descriptionChanged(const std::string&);
97 void searchHintChanged(const std::string&);
100 void searchHintChanged(const std::string&);
101+ void searchInProgressChanged();
98 void visibleChanged(bool);
102 void visibleChanged(bool);
99 void shortcutChanged(const std::string&);
103 void shortcutChanged(const std::string&);
100 void connectedChanged(bool);
104 void connectedChanged(bool);
101 void categoriesChanged();
105 void categoriesChanged();
102− void searchFinished(const std::string&, unity::glib::HintsMap const&, unity::glib::Error const&);
103 void searchQueryChanged();
106 void searchQueryChanged();
104 void noResultsHintChanged();
107 void noResultsHintChanged();
105 void formFactorChanged();
108 void formFactorChanged();
@@ -115,7 +118,7 @@ Q_SIGNALS:
115
118
116private Q_SLOTS:
119private Q_SLOTS:
117 void synchronizeStates();
120 void synchronizeStates();
118− void onSearchFinished(const std::string &, unity::glib::HintsMap const &);
121+ void onSearchFinished(std::string const &, unity::glib::HintsMap const &, unity::glib::Error const&);
119
122
120private:
123private:
121 unity::dash::LocalResult createLocalResult(const QVariant &uri, const QVariant &icon_hint,
124 unity::dash::LocalResult createLocalResult(const QVariant &uri, const QVariant &icon_hint,
@@ -133,6 +136,8 @@ private:
133 QString m_searchQuery;
136 QString m_searchQuery;
134 QString m_noResultsHint;
137 QString m_noResultsHint;
135 QString m_formFactor;
138 QString m_formFactor;
139+ bool m_searchInProgress;
140+ unity::glib::Cancellable m_cancellable;
136 unity::glib::Cancellable m_previewCancellable;
141 unity::glib::Cancellable m_previewCancellable;
137};
142};
138
143
tests/mocks/Unity/fake_scope.cpp+6
@@ -30,6 +30,7 @@ static DeeModel* create_results_model(unsigned category_count, unsigned result_c
30Scope::Scope(QObject* parent)
30Scope::Scope(QObject* parent)
31 : QObject(parent)
31 : QObject(parent)
32 , m_visible(false)
32 , m_visible(false)
33+ , m_searching(false)
33 , m_categories(new Categories(this))
34 , m_categories(new Categories(this))
34 , m_results(new DeeListModel(this))
35 , m_results(new DeeListModel(this))
35{
36{
@@ -44,6 +45,7 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
44 , m_id(id)
45 , m_id(id)
45 , m_name(name)
46 , m_name(name)
46 , m_visible(visible)
47 , m_visible(visible)
48+ , m_searching(false)
47 , m_categories(new Categories(this))
49 , m_categories(new Categories(this))
48 , m_results(new DeeListModel(this))
50 , m_results(new DeeListModel(this))
49{
51{
@@ -85,6 +87,10 @@ bool Scope::connected() const {
85 return true;
87 return true;
86}
88}
87
89
90+bool Scope::searchInProgress() const {
91+ return m_searching;
92+}
93+
88Categories* Scope::categories() const {
94Categories* Scope::categories() const {
89 return m_categories;
95 return m_categories;
90}
96}
tests/mocks/Unity/fake_scope.h+4−1
@@ -32,6 +32,7 @@ class Scope : public QObject
32 Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
32 Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
33 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
33 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
34 Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
34 Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
35+ Q_PROPERTY(bool searchInProgress READ searchInProgress NOTIFY searchInProgressChanged)
35 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
36 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
36 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
37 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
37 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
38 Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
@@ -54,6 +55,7 @@ public:
54 bool visible() const;
55 bool visible() const;
55 QString shortcut() const;
56 QString shortcut() const;
56 bool connected() const;
57 bool connected() const;
58+ bool searchInProgress() const;
57 Categories* categories() const;
59 Categories* categories() const;
58 QString searchQuery() const;
60 QString searchQuery() const;
59 QString noResultsHint() const;
61 QString noResultsHint() const;
@@ -78,11 +80,11 @@ Q_SIGNALS:
78 void iconHintChanged(const QString&);
80 void iconHintChanged(const QString&);
79 void descriptionChanged(const QString&);
81 void descriptionChanged(const QString&);
80 void searchHintChanged(const QString&);
82 void searchHintChanged(const QString&);
83+ void searchInProgressChanged();
81 void visibleChanged(bool);
84 void visibleChanged(bool);
82 void shortcutChanged(const QString&);
85 void shortcutChanged(const QString&);
83 void connectedChanged(bool);
86 void connectedChanged(bool);
84 void categoriesChanged();
87 void categoriesChanged();
85− void searchFinished(const QString&);
86 void searchQueryChanged();
88 void searchQueryChanged();
87 void noResultsHintChanged();
89 void noResultsHintChanged();
88 void formFactorChanged();
90 void formFactorChanged();
@@ -103,6 +105,7 @@ protected:
103 QString m_noResultsHint;
105 QString m_noResultsHint;
104 QString m_formFactor;
106 QString m_formFactor;
105 bool m_visible;
107 bool m_visible;
108+ bool m_searching;
106
109
107 Categories* m_categories;
110 Categories* m_categories;
108 DeeListModel* m_results;
111 DeeListModel* m_results;
tests/qmltests/Components/tst_PageHeader.qml+128−128
@@ -26,174 +26,174 @@ Item {
26 width: units.gu(110)
26 width: units.gu(110)
27 height: units.gu(30)
27 height: units.gu(30)
28
28
29− Scopes {
29+ Scope {
30− id: scopes
30+ id: scopeMock
31 }
31 }
32
32
33− ScopeView {
33+ UT.UnityTestCase {
34− id: scopeView
34+ name: "PageHeaderTest"
35− anchors.fill: parent
35+ when: windowShown
36
36
37− UT.UnityTestCase {
37+ property alias searchEnabled : pageHeader.searchEntryEnabled
38− name: "PageHeaderTest"
38+ property alias searchQuery : pageHeader.searchQuery
39− when: scopes.loaded
40
39
41− property alias searchEnabled : pageHeader.searchEntryEnabled
40+ function test_search_disabled() {
42− property alias searchQuery : pageHeader.searchQuery
41+ searchEnabled = false
42+ pageHeader.resetSearch()
43
43
44− function init() {
44+ pageHeader.triggerSearch()
45− scopeView.scope = scopes.get(0)
45+ keyClick(Qt.Key_S)
46− }
47
46
48− function test_search_disabled() {
47+ compare(searchQuery, "", "Search entry not disabled properly (could still type in textfield).")
49− searchEnabled = false
48+ }
50− pageHeader.resetSearch()
51
49
50+ function test_search_enable() {
51+ searchEnabled = true
52− pageHeader.triggerSearch()
52+ pageHeader.resetSearch()
53− keyClick(Qt.Key_S)
54
53
55− compare(searchQuery, "", "Search entry not disabled properly (could still type in textfield).")
54+ pageHeader.triggerSearch()
56− }
55+ typeString("test")
57
56
58− function test_search_enable() {
57+ compare(searchQuery, "test", "Typing in the search field did not change searchQuery")
59− searchEnabled = true
58+ }
60− pageHeader.resetSearch()
61
59
60+ function test_search_hard_coded() {
61+ searchEnabled = true
62− pageHeader.triggerSearch()
62+ pageHeader.triggerSearch()
63+ searchQuery = "test1"
63− typeString("test")
64+ typeString("test2")
65+ compare(searchQuery, "test1test2", "Setting searchQuery text does not update the TextField")
66+ }
64
67
65− compare(searchQuery, "test", "Typing in the search field did not change searchQuery")
68+ function test_reset_search() {
66− }
69+ searchEnabled = true
70+ pageHeader.resetSearch()
67
71
68− function test_search_hard_coded() {
69− searchEnabled = true
70− pageHeader.triggerSearch()
72+ pageHeader.triggerSearch()
71− searchQuery = "test1"
73+ keyClick(Qt.Key_S)
72− typeString("test2")
73− compare(searchQuery, "test1test2", "Setting searchQuery text does not update the TextField")
74− }
75
74
76− function test_reset_search() {
75+ compare(searchQuery, "s", "Could not type in TextField.")
77− searchEnabled = true
78− pageHeader.resetSearch()
79
76
80− pageHeader.triggerSearch()
77+ pageHeader.resetSearch()
81− keyClick(Qt.Key_S)
78+ compare(searchQuery, "", "Reset search did not reset searchQuery correctly.")
79+ }
82
80
83− compare(searchQuery, "s", "Could not type in TextField.")
81+ function test_move_search_by_width()
82+ {
83+ searchEnabled = true
84+ pageHeader.resetSearch()
84
85
85− pageHeader.resetSearch()
86+ var searchContainer = findChild(pageHeader, "searchContainer")
86− compare(searchQuery, "", "Reset search did not reset searchQuery correctly.")
87− }
88
87
89− function test_move_search_by_width()
88+ parent.width = units.gu(40)
90− {
91− searchEnabled = true
92− pageHeader.resetSearch()
93
89
94− var searchContainer = findChild(pageHeader, "searchContainer")
90+ verify(searchContainer !== undefined)
91+ verify(searchContainer.y <= 0)
95
92
96− parent.width = units.gu(40)
93+ pageHeader.triggerSearch()
94+ verify(searchContainer.y >= 0)
97
95
98− verify(searchContainer !== undefined)
96+ pageHeader.resetSearch()
99− verify(searchContainer.y <= 0)
97+ verify(searchContainer.y <= 0)
100
98
101− pageHeader.triggerSearch()
99+ parent.width = units.gu(110)
102− verify(searchContainer.y >= 0)
100+ verify(searchContainer.y >= 0)
103
101
104− pageHeader.resetSearch()
102+ pageHeader.triggerSearch()
103+ tryCompare(searchContainer, "narrowMode", false)
104+ tryCompare(searchContainer, "state", "active")
105− verify(searchContainer.y <= 0)
105+ tryCompare(searchContainer, "width", units.gu(40))
106+ }
106
107
107− parent.width = units.gu(110)
108+ function test_history() {
108− verify(searchContainer.y >= 0)
109+ pageHeader.searchHistory.clear()
110+ compare(pageHeader.searchHistory.count, 0)
109
111
110− pageHeader.triggerSearch()
112+ pageHeader.triggerSearch()
111− tryCompare(searchContainer, "narrowMode", false)
113+ typeString("humppa1")
112− tryCompare(searchContainer, "state", "active")
114+ pageHeader.resetSearch()
113− tryCompare(searchContainer, "width", units.gu(40))
114− }
115
115
116− function test_history() {
117− pageHeader.searchHistory.clear()
118− compare(pageHeader.searchHistory.count, 0)
116+ compare(pageHeader.searchHistory.count, 1)
117+ compare(pageHeader.searchHistory.get(0).query, "humppa1")
119
118
120− pageHeader.triggerSearch()
119+ pageHeader.triggerSearch()
121− typeString("humppa1")
120+ typeString("humppa2")
122− pageHeader.resetSearch()
121+ pageHeader.resetSearch()
123
122
124− compare(pageHeader.searchHistory.count, 1)
123+ compare(pageHeader.searchHistory.count, 2)
125− compare(pageHeader.searchHistory.get(0).query, "humppa1")
124+ compare(pageHeader.searchHistory.get(0).query, "humppa2")
126
125
127− pageHeader.triggerSearch()
126+ pageHeader.triggerSearch()
128− typeString("humppa2")
127+ typeString("humppa3")
129− pageHeader.resetSearch()
128+ pageHeader.resetSearch()
130
129
131− compare(pageHeader.searchHistory.count, 2)
130+ compare(pageHeader.searchHistory.count, 3)
132− compare(pageHeader.searchHistory.get(0).query, "humppa2")
131+ compare(pageHeader.searchHistory.get(0).query, "humppa3")
133
132
134− pageHeader.triggerSearch()
133+ pageHeader.triggerSearch()
135− typeString("humppa3")
134+ typeString("humppa4")
136− pageHeader.resetSearch()
135+ pageHeader.resetSearch()
137
136
138− compare(pageHeader.searchHistory.count, 3)
137+ compare(pageHeader.searchHistory.count, 3)
139− compare(pageHeader.searchHistory.get(0).query, "humppa3")
138+ compare(pageHeader.searchHistory.get(0).query, "humppa4")
139+ }
140
140
141+ function test_search_indicator() {
141− pageHeader.triggerSearch()
142+ pageHeader.triggerSearch()
142− typeString("humppa4")
143+ typeString("test")
144+ tryCompare(pageHeader, "searchInProgress", true)
143− pageHeader.resetSearch()
145+ pageHeader.resetSearch()
146+ }
147+ }
148+
149+ Column {
150+ anchors.fill: parent
151+ spacing: units.gu(1)
144
152
153+ PageHeader {
145− compare(pageHeader.searchHistory.count, 3)
154+ id: pageHeader
146− compare(pageHeader.searchHistory.get(0).query, "humppa4")
155+ anchors {
156+ left: parent.left
157+ right: parent.right
147 }
158 }
148− }
149
159
150− Column {
160+ scope: scopeMock
151− anchors.fill: parent
152− spacing: units.gu(1)
153
161
154− PageHeader {
162+ searchEntryEnabled: true
155− id: pageHeader
163+ text: "%^$%^%^&%^&%^$%GHR%"
156− anchors {
157− left: parent.left
158− right: parent.right
159− }
164+ }
160
165
161− searchEntryEnabled: true
166+ Row {
162− text: "%^$%^%^&%^&%^$%GHR%"
167+ spacing: units.gu(1)
168+ anchors {
169+ left: parent.left
170+ right: parent.right
163 }
171 }
164−
165− Row {
166− spacing: units.gu(1)
167− anchors {
168− left: parent.left
169− right: parent.right
170− }
171− Button {
172+ Button {
172− text: "Set search query programmatically"
173+ text: "Set search query programmatically"
173− onClicked: pageHeader.searchQuery = "testsearch"
174+ onClicked: pageHeader.searchQuery = "testsearch"
174− width: units.gu(40)
175+ width: units.gu(40)
175− }
176+ }
176− Label {
177+ Label {
177− text: "searchQuery: \"" + pageHeader.searchQuery + "\""
178+ text: "searchQuery: \"" + pageHeader.searchQuery + "\""
178− anchors.verticalCenter: parent.verticalCenter
179+ anchors.verticalCenter: parent.verticalCenter
179− }
180 }
180 }
181+ }
181
182
182− Row {
183+ Row {
183− spacing: units.gu(1)
184+ spacing: units.gu(1)
184− anchors {
185+ anchors {
185− left: parent.left
186+ left: parent.left
186− right: parent.right
187+ right: parent.right
187− }
188+ }
188− Button {
189+ Button {
189− text: "Clear history model"
190+ text: "Clear history model"
190− onClicked: pageHeader.searchHistory.clear()
191+ onClicked: pageHeader.searchHistory.clear()
191− width: units.gu(40)
192+ width: units.gu(40)
192− }
193+ }
193− Label {
194+ Label {
194− text: "History count: " + pageHeader.searchHistory.count
195+ text: "History count: " + pageHeader.searchHistory.count
195− anchors.verticalCenter: parent.verticalCenter
196+ anchors.verticalCenter: parent.verticalCenter
196− }
197 }
197 }
198 }
198 }
199 }
199 }