Merge lp:~stolowski/unity-scope-home/phone-disable-filters into lp:unity-scope-home
- phone-disable-filters
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Francis Ginther | ||||
Approved revision: | 183 | ||||
Merged at revision: | 174 | ||||
Proposed branch: | lp:~stolowski/unity-scope-home/phone-disable-filters | ||||
Merge into: | lp:unity-scope-home | ||||
Diff against target: |
954 lines (+519/-154) 13 files modified
configure.ac (+1/-1) src/platform-info.vala (+14/-11) src/scope-registry.vala (+2/-1) src/scope.vala (+18/-6) src/search-util.vala (+0/-11) tests/fake-server/samples/remote-scopes-minimal.txt (+1/-0) tests/unit/Makefile.am (+14/-3) tests/unit/data/unity/scopes/masterscope_a.scope (+2/-2) tests/unit/data/unity/scopes/masterscope_b.scope (+2/-2) tests/unit/data/unity/scopes/more_suggestions.scope (+17/-0) tests/unit/data/unity/scopes/reference.scope (+33/-0) tests/unit/test-home-scope.vala (+221/-117) tests/unit/test-utils.vala (+194/-0) |
||||
To merge this branch: | bzr merge lp:~stolowski/unity-scope-home/phone-disable-filters | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Michal Hruby (community) | Approve | ||
Review via email: mp+187021@code.launchpad.net |
Commit message
Disable filter updates if phone factor is not 'desktop'.
Description of the change
Disable filter updates if phone factor is not 'desktop' (i.e. currently displayed categores are not reflected in the filters of Home view). This is required because UI in Unity 8 support single selection filters only (any selection made by the user will narrow results to single category in Home).
In addition, sort scope registry by scope id to give more sensible default order on the phone, until real category sorting works there.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:170
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Paweł Stołowski (stolowski) wrote : | # |
> Could we see some tests for this? Not updating the filters seems a bit scary,
> does changing the query still reset them etc? Those things should be ensured
> by a test.
Right, that was a bug; fixed.
As much as I'd love to add a test for it, I don't see a way to do it with a reasonable amount of effort due to the number of prerequisites or mocks needed.
The point of this change is to disable updates of filters in the UI from the backend (which only Home Scope does). The logic that sets scopes to query from SSS recommendations, always-search scopes or default view stays.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:171
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:176
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:177
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:179
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:180
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michal Hruby (mhr3) wrote : | # |
222 + echo $(nodist_
Would be nice to get rid of it :)
418 + Process.close_pid (server_pid);
I think this frees the handle on some systems, yet it's used later in stop(), fortunately it's a noop on linux, anyway, better remove it (or move to destructor to have super-clean code).
519 + var proxy = acquire_test_proxy (HOME_SCOPE_
520 + var channel_id = open_channel (proxy, ChannelType.GLOBAL, null);
521 +
522 + assert (channel_id != null);
Looks like something that should go into setup() + close_channel() in teardown().
80 + string? form_factor = scope_search.
Micro-optimisation - turn this into unowned string.
I know this was a hard fight, but it really opens doors to have more thorough testing of the entire home-scope codebase... Well done! :)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:182
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:183
http://
Executed test runs:
SUCCESS: http://
SUCCESS: 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:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
Francis Ginther (fginther) wrote : | # |
Autolanding failure caused by catching the archive in the middle of an update (hash sum mismatch). Re-approved.
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2013-09-27 14:33:11 +0000 |
3 | +++ configure.ac 2013-10-01 10:06:09 +0000 |
4 | @@ -104,7 +104,7 @@ |
5 | #################################################################### |
6 | AC_ARG_ENABLE([headless-tests], |
7 | AS_HELP_STRING([--enable-headless-tests=@<:@no/yes@:>@],[enable headless test suite (requires Xvfb) @<:@default=no@:>@]),, |
8 | - [enable_headless_tests=no]) |
9 | + [enable_headless_tests=yes]) |
10 | |
11 | AM_CONDITIONAL([ENABLE_HEADLESS_TESTS],[test "x$enable_headless_tests" != "xno"]) |
12 | |
13 | |
14 | === modified file 'src/platform-info.vala' |
15 | --- src/platform-info.vala 2013-08-28 14:24:07 +0000 |
16 | +++ src/platform-info.vala 2013-10-01 10:06:09 +0000 |
17 | @@ -92,17 +92,20 @@ |
18 | try |
19 | { |
20 | is_ready = false; |
21 | - var connection = yield Bus.get (BusType.SYSTEM, null); |
22 | - var reply = yield connection.call ("org.ofono", "/ril_0", |
23 | - "org.ofono.SimManager", |
24 | - "GetProperties", null, |
25 | - new VariantType ("(a{sv})"), |
26 | - DBusCallFlags.NONE, -1, null); |
27 | - reply = reply.get_child_value (0); |
28 | - var mcc_v = reply.lookup_value ("MobileCountryCode", VariantType.STRING); |
29 | - var mnc_v = reply.lookup_value ("MobileNetworkCode", VariantType.STRING); |
30 | - if (mcc_v != null) country_code = mcc_v.get_string (); |
31 | - if (mnc_v != null) network_code = mnc_v.get_string (); |
32 | + if (Environment.get_variable ("HOME_SCOPE_IGNORE_OFONO") == null) |
33 | + { |
34 | + var connection = yield Bus.get (BusType.SYSTEM, null); |
35 | + var reply = yield connection.call ("org.ofono", "/ril_0", |
36 | + "org.ofono.SimManager", |
37 | + "GetProperties", null, |
38 | + new VariantType ("(a{sv})"), |
39 | + DBusCallFlags.NONE, -1, null); |
40 | + reply = reply.get_child_value (0); |
41 | + var mcc_v = reply.lookup_value ("MobileCountryCode", VariantType.STRING); |
42 | + var mnc_v = reply.lookup_value ("MobileNetworkCode", VariantType.STRING); |
43 | + if (mcc_v != null) country_code = mcc_v.get_string (); |
44 | + if (mnc_v != null) network_code = mnc_v.get_string (); |
45 | + } |
46 | } |
47 | catch (Error err) |
48 | { |
49 | |
50 | === modified file 'src/scope-registry.vala' |
51 | --- src/scope-registry.vala 2013-09-04 10:28:06 +0000 |
52 | +++ src/scope-registry.vala 2013-10-01 10:06:09 +0000 |
53 | @@ -119,7 +119,8 @@ |
54 | // with remote scopes; we would need to wait for remote-scopes query to finish to know if |
55 | // if this master is needed for remote results. |
56 | |
57 | - this.registry.append (node); |
58 | + // sort master scopes by scope_id |
59 | + this.registry.insert_sorted (node, (node_a, node_b) => { return strcmp (node_a.scope_info.id, node_b.scope_info.id); }); |
60 | master_to_node.insert (node.scope_info.id, node); |
61 | } |
62 | else |
63 | |
64 | === modified file 'src/scope.vala' |
65 | --- src/scope.vala 2013-09-20 16:40:39 +0000 |
66 | +++ src/scope.vala 2013-10-01 10:06:09 +0000 |
67 | @@ -42,7 +42,7 @@ |
68 | private FilterState filter_state = new FilterState (); |
69 | private KeywordSearch keywords_search = new KeywordSearch (); |
70 | private bool smart_scopes_initialized = false; |
71 | - private bool smart_scopes_ready = false; |
72 | + public bool smart_scopes_ready { get; internal set; default = false; } |
73 | private SmartScopes.SmartScopeClientInterface sss_client = null; |
74 | private SmartScopes.ChannelIdMap channel_id_map = new SmartScopes.ChannelIdMap (); |
75 | private uint metrics_timer; |
76 | @@ -616,6 +616,13 @@ |
77 | uint num_scopes = 0; |
78 | |
79 | bool flushing_enabled = false; |
80 | + unowned string? form_factor = scope_search.search_context.search_metadata.form_factor; |
81 | + if (form_factor == null) |
82 | + form_factor = "unknown"; // set to 'unknown' as it's sent with smart scopes request |
83 | + bool disable_filter_updates = (form_factor != "desktop"); |
84 | + |
85 | + if (disable_filter_updates) |
86 | + debug ("Filter updates disabled, form factor is %s", form_factor); |
87 | |
88 | // ids of scopes recommended by Smart Scope Service |
89 | var recommended_search_scopes = new List<SmartScopes.RecommendedScope?> (); |
90 | @@ -711,6 +718,8 @@ |
91 | unowned Unity.OptionsFilter categories_filter = scope_search.get_filter ("categories") as Unity.OptionsFilter; |
92 | unowned Unity.OptionsFilter sources_filter = scope_search.get_filter ("sources") as Unity.OptionsFilter; |
93 | |
94 | + bool relations_changed = false; |
95 | + |
96 | // if query is empty but it's not just a filter change (i.e. state is REMOVES_FROM_PREVIOUS_QUERY or NEW_QUERY), |
97 | // then apply default user filters. |
98 | if (empty_query && search_query_changed != SearchQueryChange.NOT_CHANGED) |
99 | @@ -724,8 +733,12 @@ |
100 | default_view = true; |
101 | } |
102 | |
103 | - debug ("Updating filter interrelationships"); |
104 | - bool relations_changed = filter_state.update_filter_relations (scope_search.channel_id, categories_filter, sources_filter); |
105 | + if (!disable_filter_updates) { |
106 | + debug ("Updating filter interrelationships"); |
107 | + relations_changed = filter_state.update_filter_relations (scope_search.channel_id, categories_filter, sources_filter); |
108 | + } else { |
109 | + needs_filter_update = false; //reset filter update flag if on the phone |
110 | + } |
111 | |
112 | // caution: push_filter_settings may get cancelled if we ever yield before; |
113 | // in such case internal filter state must be updated later (at the end of search). |
114 | @@ -888,7 +901,6 @@ |
115 | } |
116 | |
117 | sss_query_started = true; |
118 | - var form_factor = SearchUtil.get_form_factor (scope_search); |
119 | sss_client.search.begin (search_string, form_factor, session_id, remote_scopes_to_query, scope_mgr.disabled_scopes, |
120 | (scope_id, row) => |
121 | { |
122 | @@ -1024,7 +1036,7 @@ |
123 | use_recommended_scopes = true; |
124 | |
125 | // only update filters with searched scopes when not in the default view, otherwise default view filters may get de-selected |
126 | - if (!default_view) |
127 | + if (!default_view && !disable_filter_updates) |
128 | { |
129 | debug ("Updating filter state"); |
130 | needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, |
131 | @@ -1108,7 +1120,7 @@ |
132 | } |
133 | |
134 | // update filter state again, but this time check result counts and send the update only if any of the highlighted masters has no results |
135 | - if (!default_view) |
136 | + if (!default_view && !disable_filter_updates) |
137 | needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, scope_search, filter_change_only == false); |
138 | |
139 | if (needs_filter_update) |
140 | |
141 | === modified file 'src/search-util.vala' |
142 | --- src/search-util.vala 2013-06-14 15:49:21 +0000 |
143 | +++ src/search-util.vala 2013-10-01 10:06:09 +0000 |
144 | @@ -317,15 +317,4 @@ |
145 | } |
146 | return found; |
147 | } |
148 | - |
149 | - public string get_form_factor (Unity.AggregatedScopeSearch scope_search) |
150 | - { |
151 | - const string FORM_FACTOR_HINT = "form-factor"; |
152 | - unowned Variant? hint = scope_search.hints[FORM_FACTOR_HINT]; |
153 | - if (hint != null && hint.is_of_type (VariantType.STRING)) |
154 | - { |
155 | - return hint.get_string (); |
156 | - } |
157 | - return "unknown"; |
158 | - } |
159 | } |
160 | |
161 | === added file 'tests/fake-server/samples/remote-scopes-minimal.txt' |
162 | --- tests/fake-server/samples/remote-scopes-minimal.txt 1970-01-01 00:00:00 +0000 |
163 | +++ tests/fake-server/samples/remote-scopes-minimal.txt 2013-10-01 10:06:09 +0000 |
164 | @@ -0,0 +1,1 @@ |
165 | +[{"description": "This is an Ubuntu search plugin that enables information from Ubuntu One Music Store to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/7XpGFTkSugUON0PEsBBYHK", "name": "Ubuntu One Music Search", "keywords": ["u1ms", "u1", "ubuntuone"], "id": "more_suggestions-u1ms.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-u1.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Skimlinks to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/3VvxS1Dri9CKKloEzBs2lT", "name": "Skimlinks", "keywords": ["skimlinks"], "id": "more_suggestions-skimlinks.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/group-treat-yourself.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Wikipedia to be searched and displayed in the Dash underneath the Reference header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/4QiCFcHJS3fmDCMFvgi9lo", "name": "Wikipedia", "keywords": ["wikipedia", "wiki"], "id": "reference-wikipedia.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-wikipedia.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Wordnik to be searched and displayed in the Dash underneath the Reference header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/15gptcYAwD6vk53cUtOrvX", "name": "Dictionary", "keywords": ["define"], "id": "reference-dictionary.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-wordnik.svg"}, {"description": "Find themoviedb.org items", "screenshot": null, "name": "themoviedb.org", "keywords": ["themoviedb", "movie", "db", "actor", "cinema"], "id": "reference-themoviedb.scope", "icon": null}, {"description": "This is an Ubuntu search plugin that enables information from Amazon to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/5apoKe0t8OOj1BQkWKnfWi", "name": "Amazon", "keywords": ["amazon"], "id": "more_suggestions-amazon.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-amazon.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Etsy to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.", "screenshot": null, "name": "Etsy", "keywords": ["etsy"], "id": "more_suggestions-etsy.scope", "icon": null}, {"description": "This is an Ubuntu search plugin that enables information from eBay to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.", "screenshot": null, "name": "eBay", "keywords": ["ebay"], "id": "more_suggestions-ebay.scope", "icon": null}, {"description": "Find Stackexchange items", "screenshot": null, "name": "Stackexchange", "keywords": ["stackexchange"], "id": "reference-stackexchange.scope", "icon": null}] |
166 | |
167 | === modified file 'tests/unit/Makefile.am' |
168 | --- tests/unit/Makefile.am 2013-06-11 15:36:38 +0000 |
169 | +++ tests/unit/Makefile.am 2013-10-01 10:06:09 +0000 |
170 | @@ -19,6 +19,7 @@ |
171 | --pkg glib-2.0 \ |
172 | --pkg json-glib-1.0 \ |
173 | --pkg gee-1.0 \ |
174 | + --pkg unity-extras \ |
175 | --vapidir $(srcdir) \ |
176 | --vapidir $(top_srcdir)/vapi \ |
177 | --target-glib=2.26 \ |
178 | @@ -36,7 +37,6 @@ |
179 | |
180 | AM_CPPFLAGS = \ |
181 | -DDATADIR=\"$(DATADIR)\" \ |
182 | - -DPKGDATADIR=\"$(PKGDATADIR)\" \ |
183 | -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ |
184 | -DG_LOG_DOMAIN=\"unity-scope-home\" \ |
185 | $(HOME_SCOPE_CFLAGS) \ |
186 | @@ -49,7 +49,7 @@ |
187 | AM_CPPFLAGS += -w |
188 | endif |
189 | |
190 | -test_home_scope_VALASOURCES = \ |
191 | +MAINSOURCES = \ |
192 | ../../src/scope.vala \ |
193 | ../../src/scope-manager.vala \ |
194 | ../../src/keyword-search.vala \ |
195 | @@ -74,11 +74,21 @@ |
196 | ../../src/markup-cleaner.vala \ |
197 | ../../src/master-scopes.vala \ |
198 | ../../src/smart-scopes-preview-parser.vala \ |
199 | + $(NULL) |
200 | + |
201 | +TEST_SOURCES = \ |
202 | config-tests.vala \ |
203 | + test-utils.vala \ |
204 | test-home-scope.vala \ |
205 | $(NULL) |
206 | |
207 | -nodist_test_home_scope_SOURCES = $(test_home_scope_VALASOURCES:.vala=.c) |
208 | +test_home_scope_VALASOURCES = $(TEST_SOURCES) $(MAINSOURCES) |
209 | + |
210 | +# the patsubst rule below and objects override are needed to force dependency on *.c files |
211 | +# generated in current test dir rather than on those from ../../src |
212 | +nodist_test_home_scope_SOURCES = $(TEST_SOURCES:.vala=.c) $(patsubst ../../src/%,%,$(MAINSOURCES:.vala=.c)) |
213 | +nodist_test_home_scope_OBJECTS = $(nodist_test_home_scope_SOURCES:.c=.o) |
214 | + |
215 | |
216 | CLEANFILES = *.stamp \ |
217 | *.c \ |
218 | @@ -96,6 +106,7 @@ |
219 | $(AM_V_GEN)$(VALAC) -C $(AM_VALAFLAGS) $(VALAFLAGS) $^ |
220 | @touch $@ |
221 | |
222 | + |
223 | # START HEADLESS TESTS |
224 | if ENABLE_HEADLESS_TESTS |
225 | test-headless: |
226 | |
227 | === renamed file 'tests/unit/data/client-scopes.json' => 'tests/unit/data/unity/client-scopes.json' |
228 | === modified file 'tests/unit/data/unity/scopes/masterscope_a.scope' |
229 | --- tests/unit/data/unity/scopes/masterscope_a.scope 2013-01-23 10:48:55 +0000 |
230 | +++ tests/unit/data/unity/scopes/masterscope_a.scope 2013-10-01 10:06:09 +0000 |
231 | @@ -1,6 +1,6 @@ |
232 | [Scope] |
233 | -DBusName=com.canonical.Unity.Scope.MasterA |
234 | -DBusPath=/com/canonical/unity/scope/mastera |
235 | +DBusName=com.canonical.Unity.Scope.HomeTest |
236 | +DBusPath=/com/canonical/unity/masterscopes/mastera |
237 | Icon=/usr/share/unity/6/icon1.svg |
238 | IsMaster=true |
239 | RequiredMetadata=some_id[s];foo[s];bar[y]; |
240 | |
241 | === modified file 'tests/unit/data/unity/scopes/masterscope_b.scope' |
242 | --- tests/unit/data/unity/scopes/masterscope_b.scope 2013-01-23 10:48:55 +0000 |
243 | +++ tests/unit/data/unity/scopes/masterscope_b.scope 2013-10-01 10:06:09 +0000 |
244 | @@ -1,6 +1,6 @@ |
245 | [Scope] |
246 | -DBusName=com.canonical.Unity.Scope.MasterB |
247 | -DBusPath=/com/canonical/unity/scope/masterb |
248 | +DBusName=com.canonical.Unity.Scope.HomeTest |
249 | +DBusPath=/com/canonical/unity/masterscopes/masterb |
250 | Icon=/usr/share/unity/6/icon2.svg |
251 | IsMaster=true |
252 | RequiredMetadata=bid[s];a[s];b[y]; |
253 | |
254 | === added file 'tests/unit/data/unity/scopes/more_suggestions.scope' |
255 | --- tests/unit/data/unity/scopes/more_suggestions.scope 1970-01-01 00:00:00 +0000 |
256 | +++ tests/unit/data/unity/scopes/more_suggestions.scope 2013-10-01 10:06:09 +0000 |
257 | @@ -0,0 +1,17 @@ |
258 | +[Scope] |
259 | +DBusName=com.canonical.Unity.Scope.HomeTest |
260 | +DBusPath=/com/canonical/unity/masterscope/moresuggestions |
261 | +Icon= |
262 | +CategoryIcon=/usr/share/icons/unity-icon-theme/places/svg/group-treat-yourself.svg |
263 | +Name=More suggestions |
264 | +Type=moresug |
265 | +IsMaster=true |
266 | + |
267 | +[Desktop Entry] |
268 | +X-Ubuntu-Gettext-Domain=unity-scope-home |
269 | + |
270 | +[Category more_suggestions] |
271 | +Name=More suggestions |
272 | +Icon= |
273 | +SortField=uri |
274 | + |
275 | |
276 | === added file 'tests/unit/data/unity/scopes/reference.scope' |
277 | --- tests/unit/data/unity/scopes/reference.scope 1970-01-01 00:00:00 +0000 |
278 | +++ tests/unit/data/unity/scopes/reference.scope 2013-10-01 10:06:09 +0000 |
279 | @@ -0,0 +1,33 @@ |
280 | +[Scope] |
281 | +DBusName=com.canonical.Unity.Scope.HomeTest |
282 | +DBusPath=/com/canonical/unity/masterscope/reference |
283 | +Icon= |
284 | +CategoryIcon=/usr/share/icons/unity-icon-theme/places/svg/group-reference.svg |
285 | +Name=Reference |
286 | +Type=reference |
287 | +IsMaster=true |
288 | +Keywords=reference; |
289 | + |
290 | +[Desktop Entry] |
291 | +X-Ubuntu-Gettext-Domain=unity-scope-home |
292 | + |
293 | +[Category encyclopedia] |
294 | +Name=Encyclopedia |
295 | +Icon= |
296 | +DedupField=uri |
297 | + |
298 | +[Category vocabulary] |
299 | +Name=Vocabulary |
300 | +Icon= |
301 | +DedupField=uri |
302 | + |
303 | +[Category scholar] |
304 | +Name=Scholar |
305 | +Icon= |
306 | +DedupField=uri |
307 | + |
308 | +[Category sources] |
309 | +Name=Sources |
310 | +Icon= |
311 | +DedupField=uri |
312 | + |
313 | |
314 | === modified file 'tests/unit/test-home-scope.vala' |
315 | --- tests/unit/test-home-scope.vala 2013-09-19 15:22:33 +0000 |
316 | +++ tests/unit/test-home-scope.vala 2013-10-01 10:06:09 +0000 |
317 | @@ -17,55 +17,77 @@ |
318 | */ |
319 | |
320 | using Unity.HomeScope.SmartScopes; |
321 | +using Unity.Protocol; |
322 | |
323 | namespace Unity.HomeScope |
324 | { |
325 | |
326 | + static const string HOME_SCOPE_DBUS_NAME = "com.canonical.Unity.Scope.HomeTest"; |
327 | + static const string HOME_SCOPE_DBUS_PATH = "/com/canonical/unity/home"; |
328 | + |
329 | bool verbose_debug = false; |
330 | + |
331 | + HomeScope? scope = null; |
332 | + Application? app = null; |
333 | |
334 | - /* A bit of magic to get proper-ish fixture support */ |
335 | - public interface Fixture : Object |
336 | - { |
337 | - class DelegateWrapper |
338 | - { |
339 | - TestDataFunc func; |
340 | - public DelegateWrapper (owned TestDataFunc f) { func = (owned) f; } |
341 | - } |
342 | - |
343 | - public virtual void setup () {} |
344 | - public virtual void teardown () {} |
345 | - |
346 | - [CCode (has_target = false)] |
347 | - public delegate void Callback<T> (T ptr); |
348 | - |
349 | - private static List<DelegateWrapper> _tests; |
350 | - |
351 | - public static unowned TestDataFunc create<F> (Callback<void*> cb) |
352 | - requires (typeof (F).is_a (typeof (Fixture))) |
353 | - { |
354 | - TestDataFunc functor = () => |
355 | - { |
356 | - var type = typeof (F); |
357 | - var instance = Object.new (type) as Fixture; |
358 | - instance.setup (); |
359 | - cb (instance); |
360 | - instance.teardown (); |
361 | - }; |
362 | - unowned TestDataFunc copy = functor; |
363 | - _tests.append (new DelegateWrapper ((owned) functor)); |
364 | - return copy; |
365 | - } |
366 | - public static unowned TestDataFunc create_static<F> (Callback<F> cb) |
367 | - { |
368 | - return create<F> ((Callback<void*>) cb); |
369 | - } |
370 | - } |
371 | - |
372 | private KeywordSearch kw; |
373 | const string[] RESULTS_SCHEMA = {"s", "s", "u", "u", "s", "s", "s", "s", "a{sv}"}; //TODO use schema def from libunity when it's public |
374 | |
375 | + public class FakeSmartScopesServer |
376 | + { |
377 | + private Rand rand = new Rand (); |
378 | + private Pid server_pid; |
379 | + public int server_port { get; internal set; } |
380 | + |
381 | + public void start () throws SpawnError |
382 | + { |
383 | + server_port = rand.int_range (1024, 9000); |
384 | + |
385 | + Process.spawn_async (null, {Config.TOPSRCDIR + "/tests/fake-server/fake-sss-server.py", |
386 | + "--scopes", Config.TOPSRCDIR + "/tests/fake-server/samples/remote-scopes-minimal.txt", |
387 | + "--search", Config.TESTRUNDATADIR + "/search.dump", |
388 | + "--feedback", Config.TESTRUNDATADIR + "/feedback.dump", |
389 | + "--requests", "6", |
390 | + "--timeout", "15", |
391 | + "--port", server_port.to_string (), |
392 | + Config.TOPSRCDIR + "/tests/unit/data/search_results1.txt"}, |
393 | + null, 0, null, out server_pid); |
394 | + |
395 | + Socket socket = new Socket (SocketFamily.IPV4, SocketType.STREAM, SocketProtocol.TCP); |
396 | + assert (socket != null); |
397 | + |
398 | + InetAddress addr = new InetAddress.from_bytes ({127, 0, 0, 1}, SocketFamily.IPV4); |
399 | + InetSocketAddress server_addr = new InetSocketAddress (addr, (uint16)server_port); |
400 | + |
401 | + bool conn = false; |
402 | + int retry = 5; |
403 | + while (!conn && retry > 0) |
404 | + { |
405 | + try |
406 | + { |
407 | + conn = socket.connect (server_addr); |
408 | + } |
409 | + catch (Error e) {} |
410 | + if (!conn) |
411 | + Thread.usleep (1*1000000); // sleep for 1 second |
412 | + --retry; |
413 | + } |
414 | + } |
415 | + |
416 | + public void stop () |
417 | + { |
418 | + Posix.kill (server_pid, Posix.SIGTERM); |
419 | + Process.close_pid (server_pid); |
420 | + } |
421 | + } |
422 | + |
423 | + FakeSmartScopesServer fake_server; |
424 | + |
425 | public static int main (string[] args) |
426 | { |
427 | + Environment.set_variable ("GSETTINGS_BACKEND", "memory", true); |
428 | + Environment.set_variable ("HOME_SCOPE_IGNORE_OFONO", "1", true); |
429 | + |
430 | var xdg_data_dirs = Environment.get_variable ("XDG_DATA_DIRS"); |
431 | if (xdg_data_dirs == null) xdg_data_dirs = "/usr/share"; |
432 | Environment.set_variable ("XDG_DATA_DIRS", |
433 | @@ -74,10 +96,14 @@ |
434 | Environment.set_variable ("LIBUNITY_SCOPE_DIRECTORIES", |
435 | "%s/unity/scopes".printf (Config.TESTDATADIR), |
436 | true); |
437 | + |
438 | + fake_server = new FakeSmartScopesServer (); |
439 | + fake_server.start (); |
440 | + |
441 | kw = new KeywordSearch (); |
442 | |
443 | Test.init (ref args); |
444 | - |
445 | + |
446 | Test.add_data_func ("/Unit/Search/ScopeRegistry", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_registry)); |
447 | Test.add_data_func ("/Unit/Search/KeywordSearch", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_keyword_search)); |
448 | Test.add_data_func ("/Unit/Search/SearchQueryState", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_search_query_state)); |
449 | @@ -131,37 +157,153 @@ |
450 | Test.add_data_func ("/Unit/MarkupCleaner/UnsupportedEntitiesAreRaw", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_unsupported_entities_are_raw)); |
451 | Test.add_data_func ("/Unit/MarkupCleaner/NumericEntitiesArePreserved", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_num_entities_are_preserved)); |
452 | |
453 | - var ml = new MainLoop (); |
454 | - ScopeRegistry.instance ().find_scopes.begin ((obj, res) => |
455 | + Test.add_data_func ("/Unit/HomeScopeInstance/PhoneFilters", Fixture.create<HomeScopeInstanceTester> (HomeScopeInstanceTester.test_phone_filters)); |
456 | + Test.add_data_func ("/Unit/HomeScopeInstance/DesktopFilters", Fixture.create<HomeScopeInstanceTester> (HomeScopeInstanceTester.test_desktop_filters)); |
457 | + |
458 | + Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true); |
459 | + |
460 | + HomeScope.discover_scopes_sync (); |
461 | + |
462 | + app = Extras.dbus_own_name (HOME_SCOPE_DBUS_NAME, () => |
463 | { |
464 | - ScopeRegistry.instance ().find_scopes.end (res); |
465 | - kw.rebuild (); |
466 | - ml.quit (); |
467 | + scope = new HomeScope (); |
468 | }); |
469 | - ml.run (); |
470 | - MetaScopeRegistry.instance ().update (ScopeRegistry.instance (), null); |
471 | + kw.rebuild (); |
472 | |
473 | Test.run (); |
474 | |
475 | + fake_server.stop (); |
476 | + |
477 | return 0; |
478 | } |
479 | - |
480 | - public static bool run_with_timeout (MainLoop ml, uint timeout_ms = 5000) |
481 | + |
482 | + class HomeScopeInstanceTester: Object, Fixture |
483 | { |
484 | - bool timeout_reached = false; |
485 | - var t_id = Timeout.add (timeout_ms, () => |
486 | - { |
487 | - timeout_reached = true; |
488 | - debug ("Timeout reached"); |
489 | - ml.quit (); |
490 | - return false; |
491 | - }); |
492 | - |
493 | - ml.run (); |
494 | - |
495 | - if (!timeout_reached) Source.remove (t_id); |
496 | - |
497 | - return !timeout_reached; |
498 | + ScopeProxy? proxy = null; |
499 | + string channel_id; |
500 | + |
501 | + private void setup () |
502 | + { |
503 | + if (!scope.smart_scopes_ready) { |
504 | + var ml = new MainLoop (); |
505 | + scope.notify["smart_scopes_ready"].connect(() => { ml.quit (); }); |
506 | + run_with_timeout (ml, 8); |
507 | + } |
508 | + |
509 | + proxy = acquire_test_proxy (HOME_SCOPE_DBUS_NAME, HOME_SCOPE_DBUS_PATH); |
510 | + channel_id = open_channel (proxy, ChannelType.GLOBAL, null); |
511 | + assert (channel_id != null); |
512 | + } |
513 | + |
514 | + private void teardown () |
515 | + { |
516 | + proxy.close_channel (channel_id, null); |
517 | + proxy = null; |
518 | + } |
519 | + |
520 | + internal void test_phone_filters () |
521 | + { |
522 | + // ignore warnings |
523 | + Test.log_set_fatal_handler (() => { return false; }); |
524 | + |
525 | + bool got_filters_update = false; |
526 | + |
527 | + proxy.filter_settings_changed.connect ((chid, filter_rows) => { |
528 | + got_filters_update = true; |
529 | + }); |
530 | + |
531 | + var hints = new HashTable<string, Variant> (str_hash, str_equal); |
532 | + hints["form-factor"] = "phone"; |
533 | + perform_search (proxy, channel_id, "metallica", hints, null); |
534 | + |
535 | + assert (got_filters_update == false); // we expect no filter updates on the phone |
536 | + } |
537 | + |
538 | + internal void test_desktop_filters () |
539 | + { |
540 | + // ignore warnings |
541 | + Test.log_set_fatal_handler (() => { return false; }); |
542 | + |
543 | + int got_filters_update = 0; |
544 | + |
545 | + Variant? filters = null; |
546 | + proxy.filter_settings_changed.connect ((chid, filter_rows) => { |
547 | + got_filters_update += 1; |
548 | + // note: there are 2 filter updates during search, but we care about the final value of filters |
549 | + filters = filter_rows; |
550 | + }); |
551 | + |
552 | + assert (channel_id != null); |
553 | + assert (got_filters_update == 0); |
554 | + |
555 | + wait_for_synchronization (proxy.filters_model); |
556 | + assert (proxy.filters_model.get_n_rows () == 2); |
557 | + |
558 | + // verify all filter options are initially inactive |
559 | + int option_count = 0; |
560 | + for (var iter = proxy.filters_model.get_first_iter (); iter != proxy.filters_model.get_last_iter (); iter = proxy.filters_model.next (iter)) |
561 | + { |
562 | + var opts = proxy.filters_model.get_row (iter)[4].lookup_value ("options", null); |
563 | + for (int i = 0; i<opts.n_children (); i++) |
564 | + { |
565 | + option_count += 1; |
566 | + var opt = opts.get_child_value(i); |
567 | + assert (opt.get_child_value (3).get_boolean () == false); |
568 | + } |
569 | + } |
570 | + |
571 | + assert (option_count == 17); |
572 | + |
573 | + var hints = new HashTable<string, Variant> (str_hash, str_equal); |
574 | + hints["form-factor"] = "desktop"; |
575 | + perform_search (proxy, channel_id, "iron maiden", hints, null); |
576 | + |
577 | + assert (got_filters_update == 2); |
578 | + assert (filters.n_children() == 2); // two filters ('sources' and 'categories') |
579 | + var src_filter = filters.get_child_value(0); |
580 | + var cat_filter = filters.get_child_value(1); |
581 | + |
582 | + // verify 'sources' filter |
583 | + var opts = src_filter.get_child_value (4).lookup_value ("options", null); |
584 | + var option_flags = new HashTable<string, bool>(str_hash, str_equal); |
585 | + |
586 | + for (int i = 0; i<opts.n_children (); i++) // create scopeid -> enabled flag lookup for sources filter |
587 | + { |
588 | + var opt = opts.get_child_value(i); |
589 | + option_flags[opt.get_child_value (0).get_string ()] = opt.get_child_value (3).get_boolean (); |
590 | + } |
591 | + |
592 | + assert (option_flags["reference-stackexchange.scope"] == false); |
593 | + assert (option_flags["reference-dictionary.scope"] == false); |
594 | + assert (option_flags["reference-themoviedb.scope"] == false); |
595 | + assert (option_flags["masterscope_b-subscope1.scope"] == false); |
596 | + assert (option_flags["masterscope_b-subscope2.scope"] == false); |
597 | + assert (option_flags["masterscope_a-subscope1.scope"] == false); |
598 | + assert (option_flags["masterscope_a-subscope2.scope"] == false); |
599 | + assert (option_flags["more_suggestions-amazon.scope"] == false); |
600 | + assert (option_flags["more_suggestions-etsy.scope"] == false); |
601 | + assert (option_flags["more_suggestions-ebay.scope"] == false); |
602 | + assert (option_flags["more_suggestions-skimlinks.scope"] == false); |
603 | + |
604 | + assert (option_flags["more_suggestions-u1ms.scope"] == true); |
605 | + assert (option_flags["reference-wikipedia.scope"] == true); |
606 | + |
607 | + // verify 'categories' filter |
608 | + opts = cat_filter.get_child_value (4).lookup_value ("options", null); |
609 | + option_flags = new HashTable<string, bool>(str_hash, str_equal); |
610 | + |
611 | + for (int i = 0; i<opts.n_children (); i++) // create scopeid -> enabled flag lookup for categories filter |
612 | + { |
613 | + var opt = opts.get_child_value(i); |
614 | + option_flags[opt.get_child_value (0).get_string ()] = opt.get_child_value (3).get_boolean (); |
615 | + } |
616 | + |
617 | + assert (option_flags["masterscope_a.scope"] == false); |
618 | + assert (option_flags["masterscope_b.scope"] == false); |
619 | + |
620 | + assert (option_flags["more_suggestions.scope"] == true); |
621 | + assert (option_flags["reference.scope"] == true); |
622 | + } |
623 | } |
624 | |
625 | class HomeScopeSearchTester: Object, Fixture |
626 | @@ -178,7 +320,7 @@ |
627 | // scope registry is a singleton and is initialized in main on start |
628 | var registry = ScopeRegistry.instance (); |
629 | var scopes = registry.flatten (); |
630 | - assert (scopes.size == 6); |
631 | + assert (scopes.size == 8); |
632 | assert (scopes.contains ("masterscope_a.scope")); |
633 | assert (scopes.contains ("masterscope_b.scope")); |
634 | assert (scopes.contains ("masterscope_a-subscope1.scope")); |
635 | @@ -189,7 +331,7 @@ |
636 | |
637 | internal void test_keyword_search () |
638 | { |
639 | - assert (kw.num_of_mappings == 8); |
640 | + assert (kw.num_of_mappings == 9); |
641 | string new_search_string; |
642 | |
643 | assert (kw.process_query ("abcd: foobar", out new_search_string) == null); //unknown keyword, leave query as is |
644 | @@ -652,6 +794,7 @@ |
645 | internal void test_smart_scopes_parse () |
646 | { |
647 | CategoryManager.instance ().register ("more_suggestions.scope"); |
648 | + CategoryManager.instance ().register ("reference.scope"); |
649 | |
650 | int row_count = 0; |
651 | int recommend_count = 0; |
652 | @@ -783,6 +926,8 @@ |
653 | internal void test_smart_scopes_on_chunk_data () |
654 | { |
655 | CategoryManager.instance ().register ("more_suggestions.scope"); |
656 | + CategoryManager.instance ().register ("reference.scope"); |
657 | + |
658 | int recommend_count = 0; |
659 | int result_count = 0; |
660 | |
661 | @@ -1003,7 +1148,7 @@ |
662 | installed.add ("scope2.scope"); |
663 | installed.add ("scope4.scope"); |
664 | |
665 | - var clinfo = ClientScopesInfo.from_file (Config.TOPSRCDIR + "/tests/unit/data/client-scopes.json", installed); |
666 | + var clinfo = ClientScopesInfo.from_file (Config.TOPSRCDIR + "/tests/unit/data/unity/client-scopes.json", installed); |
667 | var added = clinfo.get_added_scopes (); |
668 | var removed = clinfo.get_removed_scopes (); |
669 | |
670 | @@ -1062,59 +1207,12 @@ |
671 | |
672 | class SmartScopesInterfaceTester: Object, Fixture |
673 | { |
674 | - private Rand rand = new Rand (); |
675 | - private Pid server_pid; |
676 | - private int server_port; |
677 | - |
678 | - private void start_fake_server () throws SpawnError |
679 | - { |
680 | - server_port = rand.int_range (1024, 9000); |
681 | - |
682 | - Process.spawn_async (null, {Config.TOPSRCDIR + "/tests/fake-server/fake-sss-server.py", |
683 | - "--scopes", Config.TOPSRCDIR + "/tests/fake-server/samples/remote-scopes.txt", |
684 | - "--search", Config.TESTRUNDATADIR + "/search.dump", |
685 | - "--feedback", Config.TESTRUNDATADIR + "/feedback.dump", |
686 | - "--requests", "2", |
687 | - "--timeout", "5", |
688 | - "--port", server_port.to_string (), |
689 | - Config.TOPSRCDIR + "/tests/unit/data/search_results1.txt"}, |
690 | - null, 0, null, out server_pid); |
691 | - |
692 | - Socket socket = new Socket (SocketFamily.IPV4, SocketType.STREAM, SocketProtocol.TCP); |
693 | - assert (socket != null); |
694 | - |
695 | - InetAddress addr = new InetAddress.from_bytes ({127, 0, 0, 1}, SocketFamily.IPV4); |
696 | - InetSocketAddress server_addr = new InetSocketAddress (addr, (uint16)server_port); |
697 | - |
698 | - bool conn = false; |
699 | - int retry = 5; |
700 | - while (!conn && retry > 0) |
701 | - { |
702 | - try |
703 | - { |
704 | - conn = socket.connect (server_addr); |
705 | - } |
706 | - catch (Error e) {} |
707 | - if (!conn) |
708 | - Thread.usleep (1*1000000); // sleep for 1 second |
709 | - --retry; |
710 | - } |
711 | - Process.close_pid (server_pid); |
712 | - } |
713 | - |
714 | - private void setup () |
715 | - { |
716 | - start_fake_server (); |
717 | - } |
718 | - |
719 | - private void teardown () |
720 | - { |
721 | - Posix.kill (server_pid, Posix.SIGTERM); |
722 | - } |
723 | - |
724 | internal void test_smart_scopes_client_iface_search () |
725 | { |
726 | - Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (server_port), true); |
727 | + // ignore warnings |
728 | + Test.log_set_fatal_handler (() => { return false; }); |
729 | + |
730 | + Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true); |
731 | var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"}); |
732 | var client = new SmartScopes.SmartScopesClient (pinfo); |
733 | var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a"; |
734 | @@ -1159,7 +1257,10 @@ |
735 | |
736 | internal void test_smart_scopes_client_iface_metrics () |
737 | { |
738 | - Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (server_port), true); |
739 | + // ignore warnings |
740 | + Test.log_set_fatal_handler (() => { return false; }); |
741 | + |
742 | + Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true); |
743 | var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"}); |
744 | var client = new SmartScopes.SmartScopesClient (pinfo); |
745 | var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a"; |
746 | @@ -1245,6 +1346,9 @@ |
747 | |
748 | internal void test_smart_scopes_client_iface_error () |
749 | { |
750 | + // ignore warnings |
751 | + Test.log_set_fatal_handler (() => { return false; }); |
752 | + |
753 | Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:9999", true); // non-existing server (connection failure) |
754 | var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"}); |
755 | var client = new SmartScopes.SmartScopesClient (pinfo); |
756 | |
757 | === added file 'tests/unit/test-utils.vala' |
758 | --- tests/unit/test-utils.vala 1970-01-01 00:00:00 +0000 |
759 | +++ tests/unit/test-utils.vala 2013-10-01 10:06:09 +0000 |
760 | @@ -0,0 +1,194 @@ |
761 | +/* |
762 | + * Copyright (C) 2011-2013 Canonical Ltd |
763 | + * |
764 | + * This program is free software: you can redistribute it and/or modify |
765 | + * it under the terms of the GNU General Public License version 3 as |
766 | + * published by the Free Software Foundation. |
767 | + * |
768 | + * This program is distributed in the hope that it will be useful, |
769 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
770 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
771 | + * GNU General Public License for more details. |
772 | + * |
773 | + * You should have received a copy of the GNU General Public License |
774 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
775 | + * |
776 | + * Authored by Michal Hruby <michal.hruby@canonical.com> |
777 | + * |
778 | + */ |
779 | + |
780 | +using Unity.Protocol; |
781 | + |
782 | +public static bool run_with_timeout (MainLoop ml, uint timeout_ms = 5000) |
783 | +{ |
784 | + bool timeout_reached = false; |
785 | + var t_id = Timeout.add (timeout_ms, () => |
786 | + { |
787 | + timeout_reached = true; |
788 | + debug ("Timeout reached"); |
789 | + ml.quit (); |
790 | + return false; |
791 | + }); |
792 | + |
793 | + ml.run (); |
794 | + |
795 | + if (!timeout_reached) Source.remove (t_id); |
796 | + |
797 | + return !timeout_reached; |
798 | +} |
799 | + |
800 | +/* A bit of magic to get proper-ish fixture support */ |
801 | +public interface Fixture : Object |
802 | +{ |
803 | + class DelegateWrapper |
804 | + { |
805 | + TestDataFunc func; |
806 | + public DelegateWrapper (owned TestDataFunc f) { func = (owned) f; } |
807 | + } |
808 | + |
809 | + public virtual void setup () {} |
810 | + public virtual void teardown () {} |
811 | + |
812 | + [CCode (has_target = false)] |
813 | + public delegate void Callback<T> (T ptr); |
814 | + |
815 | + private static List<DelegateWrapper> _tests; |
816 | + |
817 | + public static unowned TestDataFunc create<F> (Callback<void*> cb) |
818 | + requires (typeof (F).is_a (typeof (Fixture))) |
819 | + { |
820 | + TestDataFunc functor = () => |
821 | + { |
822 | + var type = typeof (F); |
823 | + var instance = Object.new (type) as Fixture; |
824 | + instance.setup (); |
825 | + cb (instance); |
826 | + instance.teardown (); |
827 | + }; |
828 | + unowned TestDataFunc copy = functor; |
829 | + _tests.append (new DelegateWrapper ((owned) functor)); |
830 | + return copy; |
831 | + } |
832 | + public static unowned TestDataFunc create_static<F> (Callback<F> cb) |
833 | + { |
834 | + return create<F> ((Callback<void*>) cb); |
835 | + } |
836 | +} |
837 | + |
838 | +// this will auto-disconnect signals when it goes out of scope |
839 | +public class SignalWrapper |
840 | +{ |
841 | + unowned Object obj; |
842 | + ulong sig_id; |
843 | + |
844 | + public SignalWrapper (Object o, ulong signal_id) |
845 | + { |
846 | + obj = o; |
847 | + sig_id = signal_id; |
848 | + } |
849 | + |
850 | + ~SignalWrapper () |
851 | + { |
852 | + SignalHandler.disconnect (obj, sig_id); |
853 | + } |
854 | +} |
855 | + |
856 | +public static ScopeProxy? acquire_test_proxy (string name, string path) |
857 | +{ |
858 | + var ml = new MainLoop (); |
859 | + ScopeProxy? proxy = null; |
860 | + ScopeProxy.new_from_dbus.begin (name, path, null, (obj, res) => |
861 | + { |
862 | + try |
863 | + { |
864 | + proxy = ScopeProxy.new_from_dbus.end (res); |
865 | + } |
866 | + catch (Error e) {} |
867 | + ml.quit (); |
868 | + }); |
869 | + assert (run_with_timeout (ml)); |
870 | + return proxy; |
871 | +} |
872 | + |
873 | +public static void wait_for_synchronization (Dee.Model model) |
874 | +{ |
875 | + var shared_model = model as Dee.SharedModel; |
876 | + if (shared_model == null) return; |
877 | + |
878 | + if (shared_model.is_synchronized ()) return; |
879 | + SignalWrapper[] signals = {}; |
880 | + var ml = new MainLoop (); |
881 | + |
882 | + signals += new SignalWrapper (shared_model, |
883 | + shared_model.notify["synchronized"].connect (() => |
884 | + { |
885 | + ml.quit (); |
886 | + })); |
887 | + |
888 | + run_with_timeout (ml); |
889 | +} |
890 | + |
891 | +public static string open_channel (ScopeProxy proxy, |
892 | + ChannelType channel_type, |
893 | + out Dee.SerializableModel model, |
894 | + bool wait_for_sync = false, |
895 | + ChannelFlags flags = 0) |
896 | +{ |
897 | + string? channel_id = null; |
898 | + Dee.Model? real_model = null; |
899 | + var ml = new MainLoop (); |
900 | + /* Need to use PRIVATE channel, cause standard SharedModel won't |
901 | + * synchronize properly when trying to connect to the model |
902 | + * from the same process (/bus address) */ |
903 | + proxy.open_channel.begin (channel_type, |
904 | + flags | ChannelFlags.PRIVATE, |
905 | + null, |
906 | + (obj, res) => |
907 | + { |
908 | + try |
909 | + { |
910 | + channel_id = proxy.open_channel.end (res, out real_model); |
911 | + if (wait_for_sync) |
912 | + { |
913 | + wait_for_synchronization (real_model); |
914 | + } |
915 | + ml.quit (); |
916 | + } |
917 | + catch (Error err) |
918 | + { |
919 | + ml.quit (); |
920 | + } |
921 | + }); |
922 | + |
923 | + assert (run_with_timeout (ml)); |
924 | + assert (channel_id != null); |
925 | + model = real_model as Dee.SerializableModel; |
926 | + return channel_id; |
927 | +} |
928 | + |
929 | +public static HashTable<string, Variant> perform_search ( |
930 | + ScopeProxy proxy, string channel_id, string query, |
931 | + HashTable<string, Variant>? hints = null, |
932 | + Dee.SerializableModel? model = null) |
933 | +{ |
934 | + var ml = new MainLoop (); |
935 | + HashTable<string, Variant>? reply_dict = null; |
936 | + proxy.search.begin (channel_id, query, |
937 | + hints ?? new HashTable<string, Variant> (null, null), |
938 | + null, |
939 | + (obj, res) => |
940 | + { |
941 | + try |
942 | + { |
943 | + reply_dict = proxy.search.end (res); |
944 | + } |
945 | + catch (Error err) {} |
946 | + ml.quit (); |
947 | + }); |
948 | + |
949 | + bool got_search_signal = false; |
950 | + |
951 | + assert (run_with_timeout (ml, 10000)); |
952 | + assert (reply_dict != null); |
953 | + return reply_dict; |
954 | +} |
Could we see some tests for this? Not updating the filters seems a bit scary, does changing the query still reset them etc? Those things should be ensured by a test.