Merge lp:~stolowski/unity-scopes-shell/model-update-crashfix into lp:unity-scopes-shell

Proposed by Paweł Stołowski
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 296
Merged at revision: 289
Proposed branch: lp:~stolowski/unity-scopes-shell/model-update-crashfix
Merge into: lp:unity-scopes-shell
Diff against target: 718 lines (+580/-14)
7 files modified
src/Unity/resultsmap.cpp (+11/-6)
src/Unity/resultsmap.h (+3/-1)
src/Unity/resultsmodel.cpp (+5/-2)
src/Unity/resultsmodel.h (+2/-2)
src/Unity/scope.cpp (+2/-2)
tests/data/mock-scope-manyresults/mock-scope-manyresults.cpp (+188/-1)
tests/resultstest.cpp (+369/-0)
To merge this branch: bzr merge lp:~stolowski/unity-scopes-shell/model-update-crashfix
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Michi Henning (community) Approve
Review via email: mp+286069@code.launchpad.net

Commit message

Fix crash on duplicated results - de-duplicate results (duplicates are ignored). Add stress tests for results model updates.

Description of the change

Fix crash on duplicated results. Add stress tests for results model updates (the test with "duplicated_results" search query triggers the crash without the fix).

To post a comment you must log in.
Revision history for this message
Michi Henning (michihenning) wrote :

I'm not fond of the constructor that modifies its argument via a non-const reference.

But, seeing that this fixes this for now, I'm good with it.

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

Top-approving (agreed with Michi).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Unity/resultsmap.cpp'
--- src/Unity/resultsmap.cpp 2015-10-06 14:35:18 +0000
+++ src/Unity/resultsmap.cpp 2016-02-16 08:14:59 +0000
@@ -25,14 +25,19 @@
25 rebuild(results);25 rebuild(results);
26}26}
2727
28ResultsMap::ResultsMap(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const &results)28ResultsMap::ResultsMap(QList<std::shared_ptr<unity::scopes::CategorisedResult>> &results)
29{29{
30 int pos = 0;30 int pos = 0;
31 for (auto result: results) {31 for (auto it = results.begin(); it != results.end(); ) {
32 std::shared_ptr<unity::scopes::Result> res = result;32 std::shared_ptr<unity::scopes::Result> result = *it;
33 assert(res);33 assert(result);
34 const ResultPos rpos { res, pos++ };34 if (find(result) < 0) {
35 m_results.insert({result->uri(), rpos });35 const ResultPos rpos { result, pos++ };
36 m_results.insert({result->uri(), rpos });
37 ++it;
38 } else {
39 it = results.erase(it);
40 }
36 }41 }
37}42}
3843
3944
=== modified file 'src/Unity/resultsmap.h'
--- src/Unity/resultsmap.h 2015-10-06 14:35:18 +0000
+++ src/Unity/resultsmap.h 2016-02-16 08:14:59 +0000
@@ -33,7 +33,9 @@
33{33{
34 public:34 public:
35 ResultsMap(QList<std::shared_ptr<unity::scopes::Result>> const &results);35 ResultsMap(QList<std::shared_ptr<unity::scopes::Result>> const &results);
36 ResultsMap(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const &results);36
37 // note: this constructor modifies the input results list (de-duplicates it).
38 ResultsMap(QList<std::shared_ptr<unity::scopes::CategorisedResult>> &results);
37 int find(std::shared_ptr<unity::scopes::Result> const& result) const;39 int find(std::shared_ptr<unity::scopes::Result> const& result) const;
3840
39 void rebuild(QList<std::shared_ptr<unity::scopes::Result>> const &results);41 void rebuild(QList<std::shared_ptr<unity::scopes::Result>> const &results);
4042
=== modified file 'src/Unity/resultsmodel.cpp'
--- src/Unity/resultsmodel.cpp 2015-11-30 09:23:32 +0000
+++ src/Unity/resultsmodel.cpp 2016-02-16 08:14:59 +0000
@@ -73,7 +73,7 @@
73 m_maxAttributes = count;73 m_maxAttributes = count;
74}74}
7575
76void ResultsModel::addUpdateResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const& results)76void ResultsModel::addUpdateResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>& results)
77{77{
78 if (results.count() == 0) {78 if (results.count() == 0) {
79 return;79 return;
@@ -129,7 +129,7 @@
129 }129 }
130}130}
131131
132void ResultsModel::addResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const& results)132void ResultsModel::addResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>& results)
133{133{
134 if (results.count() == 0) {134 if (results.count() == 0) {
135 return;135 return;
@@ -137,6 +137,9 @@
137137
138 m_purge = false;138 m_purge = false;
139139
140 ResultsMap newResultsMap(results); // deduplicate results
141 Q_UNUSED(newResultsMap);
142
140 beginInsertRows(QModelIndex(), m_results.count(), m_results.count() + results.count() - 1);143 beginInsertRows(QModelIndex(), m_results.count(), m_results.count() + results.count() - 1);
141 Q_FOREACH(std::shared_ptr<scopes::CategorisedResult> const& result, results) {144 Q_FOREACH(std::shared_ptr<scopes::CategorisedResult> const& result, results) {
142 m_results.append(result);145 m_results.append(result);
143146
=== modified file 'src/Unity/resultsmodel.h'
--- src/Unity/resultsmodel.h 2015-10-06 14:35:18 +0000
+++ src/Unity/resultsmodel.h 2016-02-16 08:14:59 +0000
@@ -44,8 +44,8 @@
44 int rowCount(const QModelIndex& parent = QModelIndex()) const override;44 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
45 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;45 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
4646
47 void addResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const&);47 void addResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>&);
48 void addUpdateResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>> const&);48 void addUpdateResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>&);
49 void clearResults();49 void clearResults();
5050
51 /* getters */51 /* getters */
5252
=== modified file 'src/Unity/scope.cpp'
--- src/Unity/scope.cpp 2015-11-30 09:23:32 +0000
+++ src/Unity/scope.cpp 2016-02-16 08:14:59 +0000
@@ -595,11 +595,11 @@
595 if (category_model == nullptr) {595 if (category_model == nullptr) {
596 category_model.reset(new ResultsModel(m_categories.data()));596 category_model.reset(new ResultsModel(m_categories.data()));
597 category_model->setCategoryId(QString::fromStdString(category->id()));597 category_model->setCategoryId(QString::fromStdString(category->id()));
598 category_model->addResults(m_category_results[category->id()]);598 category_model->addResults(m_category_results[category->id()]); // de-duplicates m_category_results
599 m_categories->registerCategory(category, category_model);599 m_categories->registerCategory(category, category_model);
600 } else {600 } else {
601 m_categories->registerCategory(category, QSharedPointer<ResultsModel>());601 m_categories->registerCategory(category, QSharedPointer<ResultsModel>());
602 category_model->addUpdateResults(m_category_results[category->id()]);602 category_model->addUpdateResults(m_category_results[category->id()]); // de-duplicates m_category_results
603 m_categories->updateResultCount(category_model);603 m_categories->updateResultCount(category_model);
604 }604 }
605 }605 }
606606
=== modified file 'tests/data/mock-scope-manyresults/mock-scope-manyresults.cpp'
--- tests/data/mock-scope-manyresults/mock-scope-manyresults.cpp 2015-10-12 14:48:41 +0000
+++ tests/data/mock-scope-manyresults/mock-scope-manyresults.cpp 2016-02-16 08:14:59 +0000
@@ -21,6 +21,8 @@
2121
22#include <iostream>22#include <iostream>
23#include <thread>23#include <thread>
24#include <cstdlib>
25#include <chrono>
2426
25#define EXPORT __attribute__ ((visibility ("default")))27#define EXPORT __attribute__ ((visibility ("default")))
2628
@@ -53,6 +55,21 @@
53 auto cat1 = reply->register_category("cat1", "Category 1", "", meta_rndr);55 auto cat1 = reply->register_category("cat1", "Category 1", "", meta_rndr);
54 auto cat2 = reply->register_category("cat2", "Category 2", "", meta_rndr);56 auto cat2 = reply->register_category("cat2", "Category 2", "", meta_rndr);
5557
58 if (query_ == "")
59 {
60 // 2000 items
61 for (int i = 0; i<200; i++)
62 {
63 CategorisedResult res(cat1);
64 res.set_uri("cat1_uri" + std::to_string(i));
65 res.set_title("result5 for: \"" + query_ + "\"");
66 reply->push(res);
67
68 if (i % 100 == 0) {
69 std::this_thread::sleep_for(std::chrono::milliseconds(40));
70 }
71 }
72 }
56 if (query_ == "search1")73 if (query_ == "search1")
57 {74 {
58 // five results with uris 0..4 in a single category cat175 // five results with uris 0..4 in a single category cat1
@@ -114,7 +131,177 @@
114 reply->push(res);131 reply->push(res);
115 }132 }
116 }133 }
117134 else if (query_ == "lots_of_results")
135 {
136 // 2000 items
137 for (int i = 0; i<2000; i++)
138 {
139 CategorisedResult res(cat1);
140 res.set_uri("cat1_uri" + std::to_string(i));
141 res.set_title("result5 for: \"" + query_ + "\"");
142 reply->push(res);
143
144 if (i % 100 == 0) {
145 std::this_thread::sleep_for(std::chrono::milliseconds(40));
146 }
147 }
148 }
149 else if (query_ == "lots_of_results_reversed")
150 {
151 // 2000 items, in the reversed order of search5
152 for (int i = 1999; i>=0; i--)
153 {
154 CategorisedResult res(cat1);
155 res.set_uri("cat1_uri" + std::to_string(i));
156 res.set_title("result5 for: \"" + query_ + "\"");
157 reply->push(res);
158
159 if (i % 100 == 0) {
160 std::this_thread::sleep_for(std::chrono::milliseconds(40));
161 }
162 }
163 }
164 else if (query_ == "lots_of_results_reversed_plus_some")
165 {
166 // 2100 items, in the reversed order of search5, plus 100 extra results
167 for (int i = 2099; i>=0; i--)
168 {
169 CategorisedResult res(cat1);
170 res.set_uri("cat1_uri" + std::to_string(i));
171 res.set_title("result5 for: \"" + query_ + "\"");
172 reply->push(res);
173
174 if (i % 100 == 0) {
175 std::this_thread::sleep_for(std::chrono::milliseconds(40));
176 }
177 }
178 }
179 else if (query_ == "lots_of_results_half_of_them_missing")
180 {
181 // 1000 items with uris matching every other item from previous search
182 for (int i = 0; i<1000; i++)
183 {
184 CategorisedResult res(cat1);
185 res.set_uri("cat1_uri" + std::to_string(i*2));
186 res.set_title("result5 for: \"" + query_ + "\"");
187 reply->push(res);
188
189 if (i % 100 == 0) {
190 std::this_thread::sleep_for(std::chrono::milliseconds(40));
191 }
192 }
193 }
194 else if (query_ == "lots_of_results_2")
195 {
196 // 2000 items, all different than in previous searches
197 for (int i = 0; i<2000; i++)
198 {
199 CategorisedResult res(cat1);
200 res.set_uri("cat1_uri" + std::to_string(5000 + i));
201 res.set_title("result5 for: \"" + query_ + "\"");
202 reply->push(res);
203
204 if (i % 100 == 0) {
205 std::this_thread::sleep_for(std::chrono::milliseconds(40));
206 }
207 }
208 }
209 else if (query_ == "lots_of_results_fast")
210 {
211 // 100 items
212 for (int i = 0; i<10; i++)
213 {
214 CategorisedResult res(cat1);
215 res.set_uri("cat1_uri" + std::to_string(i));
216 res.set_title("result5 for: \"" + query_ + "\"");
217 reply->push(res);
218 }
219 }
220 else if (query_ == "lots_of_results_reversed_fast")
221 {
222 // 100 items, in the reversed order of search5
223 for (int i = 9; i>=0; i--)
224 {
225 CategorisedResult res(cat1);
226 res.set_uri("cat1_uri" + std::to_string(i));
227 res.set_title("result5 for: \"" + query_ + "\"");
228 reply->push(res);
229 }
230 }
231 else if (query_ == "duplicated_uris1")
232 {
233 for (int i = 0; i<10; i++)
234 {
235 CategorisedResult res(cat1);
236 res.set_uri("uri");
237 res.set_title("result " + std::to_string(i));
238 reply->push(res);
239 }
240 }
241 else if (query_ == "duplicated_uris2")
242 {
243 for (int i = 0; i<10; i++)
244 {
245 CategorisedResult res(cat1);
246 if (i % 2 == 0) { // every other result uses same uri
247 res.set_uri("uri");
248 } else {
249 res.set_uri("uri" + std::to_string(i));
250 }
251 res.set_title("result " + std::to_string(i));
252 reply->push(res);
253 }
254 }
255 else if (query_ == "duplicated_results")
256 {
257 for (int i = 0; i<2; i++)
258 {
259 CategorisedResult res(cat1);
260 res.set_uri("uri");
261 res.set_title("result");
262 reply->push(res);
263 }
264 }
265 else if (query_ == "two-categories")
266 {
267 auto cat3 = reply->register_category("cat3", "Category 3", "", meta_rndr);
268 for (int i = 0; i<10; i++)
269 {
270 CategorisedResult res(cat1);
271 res.set_uri("uri" + std::to_string(i));
272 res.set_title("result " + std::to_string(i));
273 reply->push(res);
274
275 CategorisedResult res2(cat3);
276 res2.set_uri("uri" + std::to_string(i));
277 res2.set_title("result " + std::to_string(i));
278 reply->push(res2);
279 }
280 }
281 else if (query_ == "two-categories-second-gone")
282 {
283 for (int i = 0; i<10; i++)
284 {
285 CategorisedResult res(cat1);
286 res.set_uri("uri" + std::to_string(i));
287 res.set_title("result " + std::to_string(i));
288 reply->push(res);
289 }
290 }
291 else if (query_.find("random") == 0) // "random", followed by an int for the number of results
292 {
293 auto rand_start = rand() % 30;
294 for (int i = 0; i<std::stoi(query_.substr(6)); i++)
295 {
296 CategorisedResult res(cat1);
297 res.set_uri("cat1_uri" + std::to_string(rand_start + i));
298 res.set_title("result" + std::to_string(i));
299 reply->push(res);
300 if (i % 2 == 0) {
301 std::this_thread::sleep_for(std::chrono::milliseconds(40));
302 }
303 }
304 }
118 }305 }
119306
120private:307private:
121308
=== modified file 'tests/resultstest.cpp'
--- tests/resultstest.cpp 2015-10-12 15:42:50 +0000
+++ tests/resultstest.cpp 2016-02-16 08:14:59 +0000
@@ -22,7 +22,10 @@
22#include <QTimer>22#include <QTimer>
23#include <QSignalSpy>23#include <QSignalSpy>
24#include <QDBusConnection>24#include <QDBusConnection>
25#include <QDebug>
2526
27#include <chrono>
28#include <cstdlib>
26#include <Unity/resultsmodel.h>29#include <Unity/resultsmodel.h>
2730
28#include <unity/shell/scopes/CategoriesInterface.h>31#include <unity/shell/scopes/CategoriesInterface.h>
@@ -97,6 +100,7 @@
97 void initTestCase()100 void initTestCase()
98 {101 {
99 qputenv("UNITY_SCOPES_NO_WAIT_LOCATION", "1");102 qputenv("UNITY_SCOPES_NO_WAIT_LOCATION", "1");
103 qputenv("UNITY_SCOPES_CARDINALITY_OVERRIDE", "9999");
100 m_harness = sh::ScopeHarness::newFromScopeList(104 m_harness = sh::ScopeHarness::newFromScopeList(
101 shr::CustomRegistry::Parameters({105 shr::CustomRegistry::Parameters({
102 TEST_DATA_DIR "mock-scope/mock-scope.ini",106 TEST_DATA_DIR "mock-scope/mock-scope.ini",
@@ -1063,6 +1067,371 @@
1063 .match(resultsView->categories())1067 .match(resultsView->categories())
1064 );1068 );
1065 }1069 }
1070
1071 void testResultsModelChangesWithDuplicatedUris()
1072 {
1073 auto resultsView = m_harness->resultsView();
1074 resultsView->setActiveScope("mock-scope-manyresults");
1075
1076 // first search run
1077 {
1078 resultsView->setQuery("duplicated_uris1");
1079 QVERIFY_MATCHRESULT(
1080 shm::CategoryListMatcher()
1081 .hasExactly(1)
1082 .category(shm::CategoryMatcher("cat1")
1083 .hasAtLeast(10)
1084 )
1085 .match(resultsView->categories())
1086 );
1087
1088 auto const results = resultsView->category("cat1").results();
1089 QCOMPARE(static_cast<unsigned long>(results.size()), 10UL);
1090 for (unsigned i = 0; i<results.size(); i++) {
1091 QCOMPARE(
1092 QString::fromStdString(results[i].uri()),
1093 QString::fromStdString("uri")
1094 );
1095 }
1096 }
1097
1098 // second search run
1099 {
1100 resultsView->setQuery("duplicated_uris2");
1101 QVERIFY_MATCHRESULT(
1102 shm::CategoryListMatcher()
1103 .hasExactly(1)
1104 .category(shm::CategoryMatcher("cat1")
1105 .hasAtLeast(10)
1106 )
1107 .match(resultsView->categories())
1108 );
1109
1110 auto const results = resultsView->category("cat1").results();
1111 QCOMPARE(static_cast<unsigned long>(results.size()), 10UL);
1112 for (unsigned i = 0; i<results.size(); i++) {
1113 QCOMPARE(
1114 QString::fromStdString(results[i].uri()),
1115 (i % 2 == 0) ? QString::fromStdString("uri") : QString::fromStdString("uri" + std::to_string(i))
1116 );
1117 }
1118 }
1119 }
1120
1121 void testResultsModelChangesWithDuplicatedResults()
1122 {
1123 auto resultsView = m_harness->resultsView();
1124 resultsView->setActiveScope("mock-scope-manyresults");
1125
1126 {
1127 resultsView->setQuery("duplicated_results");
1128 QVERIFY_MATCHRESULT(
1129 shm::CategoryListMatcher()
1130 .hasExactly(1)
1131 .category(shm::CategoryMatcher("cat1")
1132 .hasAtLeast(1)
1133 )
1134 .match(resultsView->categories())
1135 );
1136
1137 auto const results = resultsView->category("cat1").results();
1138 QCOMPARE(static_cast<unsigned long>(results.size()), 1UL);
1139 }
1140 }
1141
1142 void testResultsMassiveModelChanges()
1143 {
1144 auto resultsView = m_harness->resultsView();
1145 resultsView->setActiveScope("mock-scope-manyresults");
1146
1147 // first search run
1148 {
1149 auto const start = std::chrono::system_clock::now();
1150
1151 resultsView->setQuery("lots_of_results");
1152 QVERIFY_MATCHRESULT(
1153 shm::CategoryListMatcher()
1154 .hasExactly(1)
1155 .category(shm::CategoryMatcher("cat1")
1156 .hasAtLeast(2000)
1157 )
1158 .match(resultsView->categories())
1159 );
1160 auto end = std::chrono::system_clock::now();
1161 auto search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1162 qDebug() << "Search #1 duration: " << search_dur;
1163
1164 auto const results = resultsView->category("cat1").results();
1165 QCOMPARE(static_cast<unsigned long>(results.size()), 2000UL);
1166 for (unsigned i = 0; i<results.size(); i++) {
1167 QCOMPARE(
1168 QString::fromStdString(results[i].uri()),
1169 QString::fromStdString("cat1_uri" + std::to_string(i))
1170 );
1171 }
1172 }
1173
1174 // second search run, reversed order of results
1175 {
1176 auto const start = std::chrono::system_clock::now();
1177
1178 resultsView->setQuery("lots_of_results_reversed_plus_some");
1179 QVERIFY_MATCHRESULT(
1180 shm::CategoryListMatcher()
1181 .hasExactly(1)
1182 .category(shm::CategoryMatcher("cat1")
1183 .hasAtLeast(2100)
1184 )
1185 .match(resultsView->categories())
1186 );
1187
1188 auto const end = std::chrono::system_clock::now();
1189 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1190 qDebug() << "Search #2 duration: " << search_dur;
1191
1192 auto const results = resultsView->category("cat1").results();
1193 QCOMPARE(static_cast<unsigned long>(results.size()), 2100UL);
1194 for (unsigned i = 0; i<results.size(); i++) {
1195 QCOMPARE(
1196 QString::fromStdString(results[i].uri()),
1197 QString::fromStdString("cat1_uri" + std::to_string(2099-i))
1198 );
1199 }
1200 }
1201
1202 // second search run, reversed order of results
1203 {
1204 auto const start = std::chrono::system_clock::now();
1205
1206 resultsView->setQuery("lots_of_results_reversed");
1207 QVERIFY_MATCHRESULT(
1208 shm::CategoryListMatcher()
1209 .hasExactly(1)
1210 .category(shm::CategoryMatcher("cat1")
1211 .hasAtLeast(2000)
1212 )
1213 .match(resultsView->categories())
1214 );
1215
1216 auto const end = std::chrono::system_clock::now();
1217 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1218 qDebug() << "Search #3 duration: " << search_dur;
1219
1220 auto const results = resultsView->category("cat1").results();
1221 QCOMPARE(static_cast<unsigned long>(results.size()), 2000UL);
1222 for (unsigned i = 0; i<results.size(); i++) {
1223 QCOMPARE(
1224 QString::fromStdString(results[i].uri()),
1225 QString::fromStdString("cat1_uri" + std::to_string(1999-i))
1226 );
1227 }
1228 }
1229
1230 // 1000 results, every other matches previous set
1231 {
1232 auto const start = std::chrono::system_clock::now();
1233
1234 resultsView->setQuery("lots_of_results_half_of_them_missing");
1235 QVERIFY_MATCHRESULT(
1236 shm::CategoryListMatcher()
1237 .hasExactly(1)
1238 .category(shm::CategoryMatcher("cat1")
1239 .hasAtLeast(1000)
1240 )
1241 .match(resultsView->categories())
1242 );
1243
1244 auto const end = std::chrono::system_clock::now();
1245 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1246 qDebug() << "Search #4 duration: " << search_dur;
1247
1248 auto const results = resultsView->category("cat1").results();
1249 QCOMPARE(static_cast<unsigned long>(results.size()), 1000UL);
1250 for (unsigned i = 0; i<results.size(); i++) {
1251 QCOMPARE(
1252 QString::fromStdString(results[i].uri()),
1253 QString::fromStdString("cat1_uri" + std::to_string(i*2))
1254 );
1255 }
1256 }
1257
1258 // third search run, different result set
1259 {
1260 auto const start = std::chrono::system_clock::now();
1261
1262 resultsView->setQuery("lots_of_results_2");
1263 QVERIFY_MATCHRESULT(
1264 shm::CategoryListMatcher()
1265 .hasExactly(1)
1266 .category(shm::CategoryMatcher("cat1")
1267 .hasAtLeast(2000)
1268 )
1269 .match(resultsView->categories())
1270 );
1271
1272 auto const end = std::chrono::system_clock::now();
1273 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1274 qDebug() << "Search #5 duration: " << search_dur;
1275
1276 auto const results = resultsView->category("cat1").results();
1277 QCOMPARE(static_cast<unsigned long>(results.size()), 2000UL);
1278 for (unsigned i = 0; i<results.size(); i++) {
1279 QCOMPARE(
1280 QString::fromStdString(results[i].uri()),
1281 QString::fromStdString("cat1_uri" + std::to_string(5000+i))
1282 );
1283 }
1284 }
1285
1286 // fourth search run, no delays in the scope
1287 {
1288 auto const start = std::chrono::system_clock::now();
1289
1290 resultsView->setQuery("lots_of_results_fast");
1291 QVERIFY_MATCHRESULT(
1292 shm::CategoryListMatcher()
1293 .hasExactly(1)
1294 .category(shm::CategoryMatcher("cat1")
1295 .hasAtLeast(10)
1296 )
1297 .match(resultsView->categories())
1298 );
1299 auto end = std::chrono::system_clock::now();
1300 auto search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1301 qDebug() << "Search #6 duration: " << search_dur;
1302
1303 auto const results = resultsView->category("cat1").results();
1304 QCOMPARE(static_cast<unsigned long>(results.size()), 10UL);
1305 for (unsigned i = 0; i<results.size(); i++) {
1306 QCOMPARE(
1307 QString::fromStdString(results[i].uri()),
1308 QString::fromStdString("cat1_uri" + std::to_string(i))
1309 );
1310 }
1311 }
1312
1313 // fifth search run, reversed order of results, no delays in the scope
1314 {
1315 auto const start = std::chrono::system_clock::now();
1316
1317 resultsView->setQuery("lots_of_results_reversed_fast");
1318 QVERIFY_MATCHRESULT(
1319 shm::CategoryListMatcher()
1320 .hasExactly(1)
1321 .category(shm::CategoryMatcher("cat1")
1322 .hasAtLeast(10)
1323 )
1324 .match(resultsView->categories())
1325 );
1326
1327 auto const end = std::chrono::system_clock::now();
1328 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1329 qDebug() << "Search #7 duration: " << search_dur;
1330
1331 auto const results = resultsView->category("cat1").results();
1332 QCOMPARE(static_cast<unsigned long>(results.size()), 10UL);
1333 for (unsigned i = 0; i<results.size(); i++) {
1334 QCOMPARE(
1335 QString::fromStdString(results[i].uri()),
1336 QString::fromStdString("cat1_uri" + std::to_string(9-i))
1337 );
1338 }
1339 }
1340 // search with empty string
1341 {
1342 auto const start = std::chrono::system_clock::now();
1343
1344 resultsView->setQuery("");
1345 QVERIFY_MATCHRESULT(
1346 shm::CategoryListMatcher()
1347 .hasExactly(1)
1348 .category(shm::CategoryMatcher("cat1")
1349 .hasAtLeast(200)
1350 )
1351 .match(resultsView->categories())
1352 );
1353
1354 auto const end = std::chrono::system_clock::now();
1355 auto const search_dur = std::chrono::duration_cast<std::chrono::seconds>(end.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(start.time_since_epoch()).count();
1356 qDebug() << "Search #8 duration: " << search_dur;
1357
1358 auto const results = resultsView->category("cat1").results();
1359 QCOMPARE(static_cast<unsigned long>(results.size()), 200UL);
1360 for (unsigned i = 0; i<results.size(); i++) {
1361 QCOMPARE(
1362 QString::fromStdString(results[i].uri()),
1363 QString::fromStdString("cat1_uri" + std::to_string(i))
1364 );
1365 }
1366 }
1367
1368 }
1369
1370 void testResultsModelUpdatesRandomSearches()
1371 {
1372 // the aim of this test is to ensure no crashes; results art random and not verified
1373 auto resultsView = m_harness->resultsView();
1374 resultsView->setActiveScope("mock-scope-manyresults");
1375
1376 for (int i = 0; i<10; i++)
1377 {
1378 const unsigned long n = 1 + rand() % 100; // up to 100 results
1379
1380 resultsView->setQuery("random" + std::to_string(n));
1381 QVERIFY_MATCHRESULT(
1382 shm::CategoryListMatcher()
1383 .hasExactly(1)
1384 .category(shm::CategoryMatcher("cat1")
1385 .hasAtLeast(n)
1386 )
1387 .match(resultsView->categories())
1388 );
1389
1390 auto const results = resultsView->category("cat1").results();
1391 QCOMPARE(static_cast<unsigned long>(results.size()), n);
1392 }
1393 }
1394
1395 void testResultsModelUpdatesTwoCategories()
1396 {
1397 auto resultsView = m_harness->resultsView();
1398 resultsView->setActiveScope("mock-scope-manyresults");
1399
1400 {
1401 resultsView->setQuery("two-categories");
1402 QVERIFY_MATCHRESULT(
1403 shm::CategoryListMatcher()
1404 .hasExactly(2)
1405 .category(shm::CategoryMatcher("cat1")
1406 .hasAtLeast(10)
1407 )
1408 .category(shm::CategoryMatcher("cat3")
1409 .hasAtLeast(10)
1410 )
1411 .match(resultsView->categories())
1412 );
1413
1414 auto const results1 = resultsView->category("cat1").results();
1415 QCOMPARE(static_cast<unsigned long>(results1.size()), 10UL);
1416
1417 auto const results2 = resultsView->category("cat3").results();
1418 QCOMPARE(static_cast<unsigned long>(results2.size()), 10UL);
1419 }
1420 {
1421 resultsView->setQuery("two-categories-second-gone");
1422 QVERIFY_MATCHRESULT(
1423 shm::CategoryListMatcher()
1424 .hasExactly(1)
1425 .category(shm::CategoryMatcher("cat1")
1426 .hasAtLeast(10)
1427 )
1428 .match(resultsView->categories())
1429 );
1430
1431 auto const results1 = resultsView->category("cat1").results();
1432 QCOMPARE(static_cast<unsigned long>(results1.size()), 10UL);
1433 }
1434 }
1066};1435};
10671436
1068QTEST_GUILESS_MAIN(ResultsTest)1437QTEST_GUILESS_MAIN(ResultsTest)

Subscribers

People subscribed via source and target branches

to all changes: