Merge lp:~xavi-garcia-mena/indicator-sound/test-branch-gmenuharness into lp:indicator-sound/15.10
- test-branch-gmenuharness
- Merge into trunk.15.10
Status: | Superseded |
---|---|
Proposed branch: | lp:~xavi-garcia-mena/indicator-sound/test-branch-gmenuharness |
Merge into: | lp:indicator-sound/15.10 |
Prerequisite: | lp:~xavi-garcia-mena/indicator-sound/next-play-prev-buttons-bug-1373313 |
Diff against target: |
5638 lines (+5002/-121) 56 files modified
debian/control (+11/-0) include/CMakeLists.txt (+1/-0) include/unity/CMakeLists.txt (+1/-0) include/unity/gmenuharness/MatchResult.h (+66/-0) include/unity/gmenuharness/MatchUtils.h (+42/-0) include/unity/gmenuharness/MenuItemMatcher.h (+143/-0) include/unity/gmenuharness/MenuMatcher.h (+95/-0) src/CMakeLists.txt (+10/-9) src/gmenuharness/CMakeLists.txt (+17/-0) src/gmenuharness/MatchResult.cpp (+187/-0) src/gmenuharness/MatchUtils.cpp (+77/-0) src/gmenuharness/MenuItemMatcher.cpp (+1008/-0) src/gmenuharness/MenuMatcher.cpp (+208/-0) src/media-player-mpris.vala (+1/-1) src/volume-control-pulse.vala (+5/-4) tests/CMakeLists.txt (+113/-107) tests/dbus-types/CMakeLists.txt (+48/-0) tests/dbus-types/com.ubuntu.AccountsService.Sound.xml (+9/-0) tests/dbus-types/dbus-types.h (+44/-0) tests/dbus-types/org.PulseAudio.Ext.StreamRestore1.xml (+7/-0) tests/dbus-types/org.freedesktop.Accounts.xml (+8/-0) tests/dbus-types/org.freedesktop.DBus.Properties.xml (+22/-0) tests/dbus-types/org.gtk.Actions.xml (+13/-0) tests/dbus-types/pulseaudio-volume.cpp (+156/-0) tests/dbus-types/pulseaudio-volume.h (+69/-0) tests/integration/CMakeLists.txt (+132/-0) tests/integration/indicator-sound-test-base.cpp (+411/-0) tests/integration/indicator-sound-test-base.h (+105/-0) tests/integration/main.cpp (+58/-0) tests/integration/test-indicator.cpp (+637/-0) tests/integration/touch-stream-restore.table (+4/-0) tests/integration/utils/dbus-pulse-volume.cpp (+232/-0) tests/integration/utils/dbus-pulse-volume.h (+57/-0) tests/integration/utils/get-volume.cpp (+33/-0) tests/integration/utils/set-volume.cpp (+36/-0) tests/service-mocks/CMakeLists.txt (+2/-0) tests/service-mocks/DBusPropertiesNotifier.cpp (+41/-0) tests/service-mocks/DBusPropertiesNotifier.h (+48/-0) tests/service-mocks/accounts-mock/AccountsDefs.h (+37/-0) tests/service-mocks/accounts-mock/AccountsMock.cpp (+40/-0) tests/service-mocks/accounts-mock/AccountsMock.h (+50/-0) tests/service-mocks/accounts-mock/AccountsServiceSoundMock.cpp (+48/-0) tests/service-mocks/accounts-mock/AccountsServiceSoundMock.h (+58/-0) tests/service-mocks/accounts-mock/CMakeLists.txt (+42/-0) tests/service-mocks/accounts-mock/com.ubuntu.AccountsService.Sound.Mock.xml (+6/-0) tests/service-mocks/accounts-mock/main.cpp (+63/-0) tests/service-mocks/accounts-mock/org.freedesktop.Accounts.Mock.xml (+13/-0) tests/service-mocks/media-player-mpris-mock/CMakeLists.txt (+63/-0) tests/service-mocks/media-player-mpris-mock/MediaPlayerMprisDefs.h (+37/-0) tests/service-mocks/media-player-mpris-mock/MediaPlayerMprisMock.cpp (+103/-0) tests/service-mocks/media-player-mpris-mock/MediaPlayerMprisMock.h (+77/-0) tests/service-mocks/media-player-mpris-mock/applications/testplayer1.desktop (+21/-0) tests/service-mocks/media-player-mpris-mock/main.cpp (+64/-0) tests/service-mocks/media-player-mpris-mock/org.mpris.MediaPlayer2.Player.xml (+24/-0) tests/service-mocks/media-player-mpris-mock/org.mpris.MediaPlayer2.xml (+6/-0) tests/service-mocks/media-player-mpris-mock/player-update.cpp (+93/-0) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/indicator-sound/test-branch-gmenuharness |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Xavi Garcia | Pending | ||
Review via email: mp+272243@code.launchpad.net |
This proposal supersedes a proposal from 2015-09-07.
This proposal has been superseded by a proposal from 2015-10-13.
Commit message
THIS BRANCH IS FOR TESTING ONLY, PLEASE DO NOT REVIEW YET.
Description of the change
THIS BRANCH IS FOR TESTING ONLY, PLEASE DO NOT REVIEW YET.
Test for gmenuharness.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:506
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:507
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:508
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:509
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:509
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:509
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:511
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:512
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:513
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:514
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:515
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:516
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 517. By Xavi Garcia
-
Added attribute_not_set to gmenuharness, added tests for player control buttons
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:517
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 518. By Xavi Garcia
-
added mechanism to wait for the gmenu to change. Added player test for the phone profile
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:518
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 519. By Xavi Garcia
-
fixed typo in comment
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:519
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Unmerged revisions
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2015-02-27 17:52:05 +0000 |
3 | +++ debian/control 2015-10-01 13:45:49 +0000 |
4 | @@ -5,11 +5,13 @@ |
5 | XSBC-Original-Maintainer: Conor Curran <conor.curran@canonical.com> |
6 | Build-Depends: debhelper (>= 9.0), |
7 | cmake, |
8 | + cmake-extras (>= 0.4), |
9 | dbus, |
10 | dbus-test-runner (>> 14.04.0+14.04.20150120.1), |
11 | dh-translations, |
12 | gir1.2-accountsservice-1.0, |
13 | gnome-common, |
14 | + google-mock (>= 1.6.0+svn437), |
15 | gsettings-ubuntu-schemas, |
16 | autotools-dev, |
17 | valac (>= 0.20), |
18 | @@ -18,13 +20,22 @@ |
19 | libgirepository1.0-dev, |
20 | libglib2.0-dev (>= 2.22.3), |
21 | libgtest-dev, |
22 | + libqtdbusmock1-dev (>= 0.3), |
23 | + libqtdbustest1-dev, |
24 | + libunity-api-dev, |
25 | liburl-dispatcher1-dev, |
26 | libpulse-dev (>= 1:4.0-0ubuntu21), |
27 | libpulse-mainloop-glib0 (>= 0.9.18), |
28 | libnotify-dev, |
29 | libgee-dev, |
30 | libxml2-dev, |
31 | + pulseaudio, |
32 | python3-dbusmock, |
33 | + qt5-default, |
34 | + qtbase5-dev, |
35 | + qtbase5-dev-tools, |
36 | + qtdeclarative5-dev, |
37 | + qtdeclarative5-dev-tools, |
38 | Standards-Version: 3.9.4 |
39 | Homepage: https://launchpad.net/indicator-sound |
40 | # If you aren't a member of ~indicator-applet-developers but need to upload |
41 | |
42 | === added directory 'include' |
43 | === added file 'include/CMakeLists.txt' |
44 | --- include/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
45 | +++ include/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
46 | @@ -0,0 +1,1 @@ |
47 | +add_subdirectory(unity) |
48 | |
49 | === added directory 'include/unity' |
50 | === added file 'include/unity/CMakeLists.txt' |
51 | --- include/unity/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
52 | +++ include/unity/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
53 | @@ -0,0 +1,1 @@ |
54 | +add_subdirectory(gmenuharness) |
55 | |
56 | === added directory 'include/unity/gmenuharness' |
57 | === added file 'include/unity/gmenuharness/MatchResult.h' |
58 | --- include/unity/gmenuharness/MatchResult.h 1970-01-01 00:00:00 +0000 |
59 | +++ include/unity/gmenuharness/MatchResult.h 2015-10-01 13:45:49 +0000 |
60 | @@ -0,0 +1,66 @@ |
61 | +/* |
62 | + * Copyright © 2014 Canonical Ltd. |
63 | + * |
64 | + * This program is free software: you can redistribute it and/or modify it |
65 | + * under the terms of the GNU Lesser General Public License version 3, |
66 | + * as published by the Free Software Foundation. |
67 | + * |
68 | + * This program is distributed in the hope that it will be useful, |
69 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
70 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
71 | + * GNU Lesser General Public License for more details. |
72 | + * |
73 | + * You should have received a copy of the GNU Lesser General Public License |
74 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
75 | + * |
76 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
77 | + */ |
78 | + |
79 | +#pragma once |
80 | + |
81 | +#include <vector> |
82 | +#include <memory> |
83 | +#include <string> |
84 | + |
85 | +namespace unity |
86 | +{ |
87 | + |
88 | +namespace gmenuharness |
89 | +{ |
90 | + |
91 | +class MatchResult |
92 | +{ |
93 | +public: |
94 | + MatchResult(); |
95 | + |
96 | + MatchResult(MatchResult&& other); |
97 | + |
98 | + MatchResult(const MatchResult& other); |
99 | + |
100 | + MatchResult& operator=(const MatchResult& other); |
101 | + |
102 | + MatchResult& operator=(MatchResult&& other); |
103 | + |
104 | + ~MatchResult() = default; |
105 | + |
106 | + MatchResult createChild() const; |
107 | + |
108 | + void failure(const std::vector<unsigned int>& location, const std::string& message); |
109 | + |
110 | + void merge(const MatchResult& other); |
111 | + |
112 | + bool success() const; |
113 | + |
114 | + bool hasTimedOut() const; |
115 | + |
116 | + std::string concat_failures() const; |
117 | + |
118 | +protected: |
119 | + struct Priv; |
120 | + |
121 | + std::shared_ptr<Priv> p; |
122 | +}; |
123 | + |
124 | +} // namespace gmenuharness |
125 | + |
126 | +} // namespace unity |
127 | |
128 | === added file 'include/unity/gmenuharness/MatchUtils.h' |
129 | --- include/unity/gmenuharness/MatchUtils.h 1970-01-01 00:00:00 +0000 |
130 | +++ include/unity/gmenuharness/MatchUtils.h 2015-10-01 13:45:49 +0000 |
131 | @@ -0,0 +1,42 @@ |
132 | +/* |
133 | + * Copyright © 2014 Canonical Ltd. |
134 | + * |
135 | + * This program is free software: you can redistribute it and/or modify it |
136 | + * under the terms of the GNU Lesser General Public License version 3, |
137 | + * as published by the Free Software Foundation. |
138 | + * |
139 | + * This program is distributed in the hope that it will be useful, |
140 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
141 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
142 | + * GNU Lesser General Public License for more details. |
143 | + * |
144 | + * You should have received a copy of the GNU Lesser General Public License |
145 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
146 | + * |
147 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
148 | + */ |
149 | + |
150 | +#pragma once |
151 | + |
152 | +#include <memory> |
153 | +#include <string> |
154 | + |
155 | +#include <gio/gio.h> |
156 | + |
157 | +namespace unity |
158 | +{ |
159 | + |
160 | +namespace gmenuharness |
161 | +{ |
162 | + |
163 | +void waitForCore(GObject* obj, const std::string& signalName, unsigned int timeout = 10); |
164 | + |
165 | +void menuWaitForItems(const std::shared_ptr<GMenuModel>& menu, unsigned int timeout = 10); |
166 | + |
167 | +void g_object_deleter(gpointer object); |
168 | + |
169 | +void gvariant_deleter(GVariant* varptr); |
170 | + |
171 | +} //namespace gmenuharness |
172 | + |
173 | +} // namespace unity |
174 | |
175 | === added file 'include/unity/gmenuharness/MenuItemMatcher.h' |
176 | --- include/unity/gmenuharness/MenuItemMatcher.h 1970-01-01 00:00:00 +0000 |
177 | +++ include/unity/gmenuharness/MenuItemMatcher.h 2015-10-01 13:45:49 +0000 |
178 | @@ -0,0 +1,143 @@ |
179 | +/* |
180 | + * Copyright © 2014 Canonical Ltd. |
181 | + * |
182 | + * This program is free software: you can redistribute it and/or modify it |
183 | + * under the terms of the GNU Lesser General Public License version 3, |
184 | + * as published by the Free Software Foundation. |
185 | + * |
186 | + * This program is distributed in the hope that it will be useful, |
187 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
188 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
189 | + * GNU Lesser General Public License for more details. |
190 | + * |
191 | + * You should have received a copy of the GNU Lesser General Public License |
192 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
193 | + * |
194 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
195 | + */ |
196 | + |
197 | +#pragma once |
198 | + |
199 | +#include <map> |
200 | +#include <memory> |
201 | +#include <string> |
202 | + |
203 | +#include <gio/gio.h> |
204 | + |
205 | +namespace unity |
206 | +{ |
207 | + |
208 | +namespace gmenuharness |
209 | +{ |
210 | + |
211 | +class MatchResult; |
212 | + |
213 | +class MenuItemMatcher |
214 | +{ |
215 | +public: |
216 | + enum class Mode |
217 | + { |
218 | + all, |
219 | + starts_with, |
220 | + ends_with |
221 | + }; |
222 | + |
223 | + enum class Type |
224 | + { |
225 | + plain, |
226 | + checkbox, |
227 | + radio |
228 | + }; |
229 | + |
230 | + static MenuItemMatcher checkbox(); |
231 | + |
232 | + static MenuItemMatcher radio(); |
233 | + |
234 | + MenuItemMatcher(); |
235 | + |
236 | + ~MenuItemMatcher(); |
237 | + |
238 | + MenuItemMatcher(const MenuItemMatcher& other); |
239 | + |
240 | + MenuItemMatcher(MenuItemMatcher&& other); |
241 | + |
242 | + MenuItemMatcher& operator=(const MenuItemMatcher& other); |
243 | + |
244 | + MenuItemMatcher& operator=(MenuItemMatcher&& other); |
245 | + |
246 | + MenuItemMatcher& type(Type type); |
247 | + |
248 | + MenuItemMatcher& label(const std::string& label); |
249 | + |
250 | + MenuItemMatcher& action(const std::string& action); |
251 | + |
252 | + MenuItemMatcher& state_icons(const std::vector<std::string>& state); |
253 | + |
254 | + MenuItemMatcher& icon(const std::string& icon); |
255 | + |
256 | + MenuItemMatcher& themed_icon(const std::string& iconName, const std::vector<std::string>& icons); |
257 | + |
258 | + MenuItemMatcher& widget(const std::string& widget); |
259 | + |
260 | + MenuItemMatcher& pass_through_attribute(const std::string& actionName, const std::shared_ptr<GVariant>& value); |
261 | + |
262 | + MenuItemMatcher& pass_through_boolean_attribute(const std::string& actionName, bool value); |
263 | + |
264 | + MenuItemMatcher& pass_through_string_attribute(const std::string& actionName, const std::string& value); |
265 | + |
266 | + MenuItemMatcher& pass_through_double_attribute(const std::string& actionName, double value); |
267 | + |
268 | + MenuItemMatcher& round_doubles(double maxDifference); |
269 | + |
270 | + MenuItemMatcher& attribute(const std::string& name, const std::shared_ptr<GVariant>& value); |
271 | + |
272 | + MenuItemMatcher& boolean_attribute(const std::string& name, bool value); |
273 | + |
274 | + MenuItemMatcher& string_attribute(const std::string& name, const std::string& value); |
275 | + |
276 | + MenuItemMatcher& int32_attribute(const std::string& name, int value); |
277 | + |
278 | + MenuItemMatcher& int64_attribute(const std::string& name, int value); |
279 | + |
280 | + MenuItemMatcher& double_attribute(const std::string& name, double value); |
281 | + |
282 | + MenuItemMatcher& attribute_not_set(const std::string& name); |
283 | + |
284 | + MenuItemMatcher& toggled(bool toggled); |
285 | + |
286 | + MenuItemMatcher& mode(Mode mode); |
287 | + |
288 | + MenuItemMatcher& submenu(); |
289 | + |
290 | + MenuItemMatcher& section(); |
291 | + |
292 | + MenuItemMatcher& is_empty(); |
293 | + |
294 | + MenuItemMatcher& has_exactly(std::size_t children); |
295 | + |
296 | + MenuItemMatcher& item(const MenuItemMatcher& item); |
297 | + |
298 | + MenuItemMatcher& item(MenuItemMatcher&& item); |
299 | + |
300 | + MenuItemMatcher& pass_through_activate(const std::string& action, const std::shared_ptr<GVariant>& parameter = nullptr); |
301 | + |
302 | + MenuItemMatcher& activate(const std::shared_ptr<GVariant>& parameter = nullptr); |
303 | + |
304 | + MenuItemMatcher& set_pass_through_action_state(const std::string& action, const std::shared_ptr<GVariant>& state); |
305 | + |
306 | + MenuItemMatcher& set_action_state(const std::shared_ptr<GVariant>& state); |
307 | + |
308 | + void match(MatchResult& matchResult, const std::vector<unsigned int>& location, |
309 | + const std::shared_ptr<GMenuModel>& menu, |
310 | + std::map<std::string, std::shared_ptr<GActionGroup>>& actions, |
311 | + int index) const; |
312 | + |
313 | +protected: |
314 | + struct Priv; |
315 | + |
316 | + std::shared_ptr<Priv> p; |
317 | +}; |
318 | + |
319 | +} // namespace gmenuharness |
320 | + |
321 | +} // namespace unity |
322 | |
323 | === added file 'include/unity/gmenuharness/MenuMatcher.h' |
324 | --- include/unity/gmenuharness/MenuMatcher.h 1970-01-01 00:00:00 +0000 |
325 | +++ include/unity/gmenuharness/MenuMatcher.h 2015-10-01 13:45:49 +0000 |
326 | @@ -0,0 +1,95 @@ |
327 | +/* |
328 | + * Copyright © 2014 Canonical Ltd. |
329 | + * |
330 | + * This program is free software: you can redistribute it and/or modify it |
331 | + * under the terms of the GNU Lesser General Public License version 3, |
332 | + * as published by the Free Software Foundation. |
333 | + * |
334 | + * This program is distributed in the hope that it will be useful, |
335 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
336 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
337 | + * GNU Lesser General Public License for more details. |
338 | + * |
339 | + * You should have received a copy of the GNU Lesser General Public License |
340 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
341 | + * |
342 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
343 | + */ |
344 | + |
345 | +#pragma once |
346 | + |
347 | +#define EXPECT_MATCHRESULT(statement) \ |
348 | +do {\ |
349 | + auto result = (statement);\ |
350 | + GTEST_TEST_BOOLEAN_(result.success(), #statement, false, true, \ |
351 | + GTEST_NONFATAL_FAILURE_) << result.concat_failures().c_str(); \ |
352 | +} while (0) |
353 | + |
354 | +#include <unity/gmenuharness/MatchResult.h> |
355 | +#include <unity/gmenuharness/MenuItemMatcher.h> |
356 | + |
357 | +#include <memory> |
358 | +#include <vector> |
359 | + |
360 | +namespace unity |
361 | +{ |
362 | + |
363 | +namespace gmenuharness |
364 | +{ |
365 | + |
366 | +class MenuMatcher |
367 | +{ |
368 | +public: |
369 | + class Parameters |
370 | + { |
371 | + public: |
372 | + Parameters( |
373 | + const std::string& busName, |
374 | + const std::vector<std::pair<std::string, std::string>>& actions, |
375 | + const std::string& menuObjectPath); |
376 | + |
377 | + ~Parameters(); |
378 | + |
379 | + Parameters(const Parameters& other); |
380 | + |
381 | + Parameters(Parameters&& other); |
382 | + |
383 | + Parameters& operator=(const Parameters& other); |
384 | + |
385 | + Parameters& operator=(Parameters&& other); |
386 | + |
387 | + protected: |
388 | + friend MenuMatcher; |
389 | + |
390 | + struct Priv; |
391 | + |
392 | + std::shared_ptr<Priv> p; |
393 | + }; |
394 | + |
395 | + MenuMatcher(const Parameters& parameters); |
396 | + |
397 | + ~MenuMatcher(); |
398 | + |
399 | + MenuMatcher(const MenuMatcher& other) = delete; |
400 | + |
401 | + MenuMatcher(MenuMatcher&& other) = delete; |
402 | + |
403 | + MenuMatcher& operator=(const MenuMatcher& other) = delete; |
404 | + |
405 | + MenuMatcher& operator=(MenuMatcher&& other) = delete; |
406 | + |
407 | + MenuMatcher& item(const MenuItemMatcher& item); |
408 | + |
409 | + MatchResult match() const; |
410 | + |
411 | + void match(MatchResult& matchResult) const; |
412 | + |
413 | +protected: |
414 | + struct Priv; |
415 | + |
416 | + std::shared_ptr<Priv> p; |
417 | +}; |
418 | + |
419 | +} // gmenuharness |
420 | + |
421 | +} // unity |
422 | |
423 | === modified file 'src/CMakeLists.txt' |
424 | --- src/CMakeLists.txt 2015-02-19 16:23:01 +0000 |
425 | +++ src/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
426 | @@ -8,12 +8,12 @@ |
427 | set(VAPI_PATH "${CMAKE_CURRENT_BINARY_DIR}/indicator-sound-service.vapi") |
428 | |
429 | vapi_gen(accounts-service |
430 | - LIBRARY |
431 | - accounts-service |
432 | - PACKAGES |
433 | - gio-2.0 |
434 | - INPUT |
435 | - /usr/share/gir-1.0/AccountsService-1.0.gir |
436 | + LIBRARY |
437 | + accounts-service |
438 | + PACKAGES |
439 | + gio-2.0 |
440 | + INPUT |
441 | + /usr/share/gir-1.0/AccountsService-1.0.gir |
442 | ) |
443 | |
444 | vala_init(indicator-sound-service |
445 | @@ -70,7 +70,7 @@ |
446 | media-player-user.vala |
447 | DEPENDS |
448 | media-player |
449 | - accounts-service-sound-settings |
450 | + accounts-service-sound-settings |
451 | greeter-broadcast |
452 | ) |
453 | vala_add(indicator-sound-service |
454 | @@ -164,8 +164,8 @@ |
455 | ) |
456 | |
457 | add_library( |
458 | - indicator-sound-service-lib STATIC |
459 | - ${INDICATOR_SOUND_SOURCES} |
460 | + indicator-sound-service-lib STATIC |
461 | + ${INDICATOR_SOUND_SOURCES} |
462 | ) |
463 | |
464 | target_link_libraries( |
465 | @@ -206,3 +206,4 @@ |
466 | RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/indicator-sound/ |
467 | ) |
468 | |
469 | +add_subdirectory(gmenuharness) |
470 | |
471 | === added directory 'src/gmenuharness' |
472 | === added file 'src/gmenuharness/CMakeLists.txt' |
473 | --- src/gmenuharness/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
474 | +++ src/gmenuharness/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
475 | @@ -0,0 +1,17 @@ |
476 | +pkg_check_modules(UNITY_API libunity-api>=0.1.3 REQUIRED) |
477 | +include_directories(${UNITY_API_INCLUDE_DIRS}) |
478 | + |
479 | +include_directories("${CMAKE_SOURCE_DIR}/include") |
480 | + |
481 | +add_library( |
482 | + gmenuharness-shared SHARED |
483 | + MatchResult.cpp |
484 | + MatchUtils.cpp |
485 | + MenuItemMatcher.cpp |
486 | + MenuMatcher.cpp |
487 | +) |
488 | + |
489 | +target_link_libraries( |
490 | + gmenuharness-shared |
491 | + ${GLIB_LDFLAGS} |
492 | +) |
493 | |
494 | === added file 'src/gmenuharness/MatchResult.cpp' |
495 | --- src/gmenuharness/MatchResult.cpp 1970-01-01 00:00:00 +0000 |
496 | +++ src/gmenuharness/MatchResult.cpp 2015-10-01 13:45:49 +0000 |
497 | @@ -0,0 +1,187 @@ |
498 | +/* |
499 | + * Copyright © 2014 Canonical Ltd. |
500 | + * |
501 | + * This program is free software: you can redistribute it and/or modify it |
502 | + * under the terms of the GNU Lesser General Public License version 3, |
503 | + * as published by the Free Software Foundation. |
504 | + * |
505 | + * This program is distributed in the hope that it will be useful, |
506 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
507 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
508 | + * GNU Lesser General Public License for more details. |
509 | + * |
510 | + * You should have received a copy of the GNU Lesser General Public License |
511 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
512 | + * |
513 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
514 | + */ |
515 | + |
516 | +#include <unity/gmenuharness/MatchResult.h> |
517 | + |
518 | +#include <chrono> |
519 | +#include <map> |
520 | +#include <sstream> |
521 | +#include <iostream> |
522 | + |
523 | +using namespace std; |
524 | + |
525 | +namespace unity |
526 | +{ |
527 | + |
528 | +namespace gmenuharness |
529 | +{ |
530 | + |
531 | +namespace |
532 | +{ |
533 | + |
534 | + |
535 | +static void printLocation(ostream& ss, const vector<unsigned int>& location, bool first) |
536 | +{ |
537 | + for (int i : location) |
538 | + { |
539 | + ss << " "; |
540 | + if (first) |
541 | + { |
542 | + ss << i; |
543 | + } |
544 | + else |
545 | + { |
546 | + ss << " "; |
547 | + } |
548 | + } |
549 | + ss << " "; |
550 | +} |
551 | + |
552 | +struct compare_vector |
553 | +{ |
554 | + bool operator()(const vector<unsigned int>& a, |
555 | + const vector<unsigned int>& b) const |
556 | + { |
557 | + auto p1 = a.begin(); |
558 | + auto p2 = b.begin(); |
559 | + |
560 | + while (p1 != a.end()) |
561 | + { |
562 | + if (p2 == b.end()) |
563 | + { |
564 | + return false; |
565 | + } |
566 | + if (*p2 > *p1) |
567 | + { |
568 | + return true; |
569 | + } |
570 | + if (*p1 > *p2) |
571 | + { |
572 | + return false; |
573 | + } |
574 | + |
575 | + ++p1; |
576 | + ++p2; |
577 | + } |
578 | + |
579 | + if (p2 != b.end()) |
580 | + { |
581 | + return true; |
582 | + } |
583 | + |
584 | + return false; |
585 | + } |
586 | +}; |
587 | +} |
588 | + |
589 | +struct MatchResult::Priv |
590 | +{ |
591 | + bool m_success = true; |
592 | + |
593 | + map<vector<unsigned int>, vector<string>, compare_vector> m_failures; |
594 | + |
595 | + chrono::time_point<chrono::system_clock> m_timeout = chrono::system_clock::now() + chrono::seconds(10); |
596 | +}; |
597 | + |
598 | +MatchResult::MatchResult() : |
599 | + p(new Priv) |
600 | +{ |
601 | +} |
602 | + |
603 | +MatchResult::MatchResult(MatchResult&& other) |
604 | +{ |
605 | + *this = move(other); |
606 | +} |
607 | + |
608 | +MatchResult::MatchResult(const MatchResult& other) : |
609 | + p(new Priv) |
610 | +{ |
611 | + *this = other; |
612 | +} |
613 | + |
614 | +MatchResult& MatchResult::operator=(const MatchResult& other) |
615 | +{ |
616 | + p->m_success = other.p->m_success; |
617 | + p->m_failures= other.p->m_failures; |
618 | + return *this; |
619 | +} |
620 | + |
621 | +MatchResult& MatchResult::operator=(MatchResult&& other) |
622 | +{ |
623 | + p = move(other.p); |
624 | + return *this; |
625 | +} |
626 | + |
627 | +MatchResult MatchResult::createChild() const |
628 | +{ |
629 | + MatchResult child; |
630 | + child.p->m_timeout = p->m_timeout; |
631 | + return child; |
632 | +} |
633 | + |
634 | +void MatchResult::failure(const vector<unsigned int>& location, const string& message) |
635 | +{ |
636 | + p->m_success = false; |
637 | + auto it = p->m_failures.find(location); |
638 | + if (it == p->m_failures.end()) |
639 | + { |
640 | + it = p->m_failures.insert(make_pair(location, vector<string>())).first; |
641 | + } |
642 | + it->second.emplace_back(message); |
643 | +} |
644 | + |
645 | +void MatchResult::merge(const MatchResult& other) |
646 | +{ |
647 | + p->m_success &= other.p->m_success; |
648 | + for (const auto& e : other.p->m_failures) |
649 | + { |
650 | + p->m_failures.insert(make_pair(e.first, e.second)); |
651 | + } |
652 | +} |
653 | + |
654 | +bool MatchResult::success() const |
655 | +{ |
656 | + return p->m_success; |
657 | +} |
658 | + |
659 | +bool MatchResult::hasTimedOut() const |
660 | +{ |
661 | + auto now = chrono::system_clock::now(); |
662 | + return (now >= p->m_timeout); |
663 | +} |
664 | + |
665 | +string MatchResult::concat_failures() const |
666 | +{ |
667 | + stringstream ss; |
668 | + ss << "Failed expectations:" << endl; |
669 | + for (const auto& failure : p->m_failures) |
670 | + { |
671 | + bool first = true; |
672 | + for (const string& s: failure.second) |
673 | + { |
674 | + printLocation(ss, failure.first, first); |
675 | + first = false; |
676 | + ss << s << endl; |
677 | + } |
678 | + } |
679 | + return ss.str(); |
680 | +} |
681 | + |
682 | +} // namespace gmenuharness |
683 | + |
684 | +} // namespace unity |
685 | |
686 | === added file 'src/gmenuharness/MatchUtils.cpp' |
687 | --- src/gmenuharness/MatchUtils.cpp 1970-01-01 00:00:00 +0000 |
688 | +++ src/gmenuharness/MatchUtils.cpp 2015-10-01 13:45:49 +0000 |
689 | @@ -0,0 +1,77 @@ |
690 | +/* |
691 | + * Copyright © 2014 Canonical Ltd. |
692 | + * |
693 | + * This program is free software: you can redistribute it and/or modify it |
694 | + * under the terms of the GNU Lesser General Public License version 3, |
695 | + * as published by the Free Software Foundation. |
696 | + * |
697 | + * This program is distributed in the hope that it will be useful, |
698 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
699 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
700 | + * GNU Lesser General Public License for more details. |
701 | + * |
702 | + * You should have received a copy of the GNU Lesser General Public License |
703 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
704 | + * |
705 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
706 | + */ |
707 | + |
708 | +#include <unity/gmenuharness/MatchUtils.h> |
709 | + |
710 | +#include <unity/util/ResourcePtr.h> |
711 | + |
712 | +using namespace std; |
713 | +namespace util = unity::util; |
714 | + |
715 | +namespace unity |
716 | +{ |
717 | + |
718 | +namespace gmenuharness |
719 | +{ |
720 | + |
721 | +void waitForCore (GObject * obj, const string& signalName, unsigned int timeout) { |
722 | + shared_ptr<GMainLoop> loop(g_main_loop_new(nullptr, false), &g_main_loop_unref); |
723 | + |
724 | + /* Our two exit criteria */ |
725 | + util::ResourcePtr<gulong, function<void(gulong)>> signal( |
726 | + g_signal_connect_swapped(obj, signalName.c_str(), |
727 | + G_CALLBACK(g_main_loop_quit), loop.get()), |
728 | + [obj](gulong s) |
729 | + { |
730 | + g_signal_handler_disconnect(obj, s); |
731 | + }); |
732 | + |
733 | + util::ResourcePtr<guint, function<void(guint)>> timer(g_timeout_add(timeout, |
734 | + [](gpointer user_data) -> gboolean |
735 | + { |
736 | + g_main_loop_quit((GMainLoop *)user_data); |
737 | + return G_SOURCE_CONTINUE; |
738 | + }, |
739 | + loop.get()), |
740 | + &g_source_remove); |
741 | + |
742 | + /* Wait for sync */ |
743 | + g_main_loop_run(loop.get()); |
744 | +} |
745 | + |
746 | +void menuWaitForItems(const shared_ptr<GMenuModel>& menu, unsigned int timeout) |
747 | +{ |
748 | + waitForCore(G_OBJECT(menu.get()), "items-changed", timeout); |
749 | +} |
750 | + |
751 | +void g_object_deleter(gpointer object) |
752 | +{ |
753 | + g_clear_object(&object); |
754 | +} |
755 | + |
756 | +void gvariant_deleter(GVariant* varptr) |
757 | +{ |
758 | + if (varptr != nullptr) |
759 | + { |
760 | + g_variant_unref(varptr); |
761 | + } |
762 | +} |
763 | + |
764 | +} // namespace gmenuharness |
765 | + |
766 | +} // namespace unity |
767 | |
768 | === added file 'src/gmenuharness/MenuItemMatcher.cpp' |
769 | --- src/gmenuharness/MenuItemMatcher.cpp 1970-01-01 00:00:00 +0000 |
770 | +++ src/gmenuharness/MenuItemMatcher.cpp 2015-10-01 13:45:49 +0000 |
771 | @@ -0,0 +1,1008 @@ |
772 | +/* |
773 | + * Copyright © 2014 Canonical Ltd. |
774 | + * |
775 | + * This program is free software: you can redistribute it and/or modify it |
776 | + * under the terms of the GNU Lesser General Public License version 3, |
777 | + * as published by the Free Software Foundation. |
778 | + * |
779 | + * This program is distributed in the hope that it will be useful, |
780 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
781 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
782 | + * GNU Lesser General Public License for more details. |
783 | + * |
784 | + * You should have received a copy of the GNU Lesser General Public License |
785 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
786 | + * |
787 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
788 | + */ |
789 | + |
790 | +#include <unity/gmenuharness/MatchResult.h> |
791 | +#include <unity/gmenuharness/MatchUtils.h> |
792 | +#include <unity/gmenuharness/MenuItemMatcher.h> |
793 | + |
794 | +#include <iostream> |
795 | +#include <vector> |
796 | +#include <map> |
797 | + |
798 | +using namespace std; |
799 | + |
800 | +namespace unity |
801 | +{ |
802 | + |
803 | +namespace gmenuharness |
804 | +{ |
805 | + |
806 | +namespace |
807 | +{ |
808 | + |
809 | +enum class LinkType |
810 | +{ |
811 | + any, |
812 | + section, |
813 | + submenu |
814 | +}; |
815 | + |
816 | +static string bool_to_string(bool value) |
817 | +{ |
818 | + return value? "true" : "false"; |
819 | +} |
820 | + |
821 | +static shared_ptr<GVariant> get_action_group_attribute(const shared_ptr<GActionGroup>& actionGroup, const gchar* attribute) |
822 | +{ |
823 | + shared_ptr<GVariant> value( |
824 | + g_action_group_get_action_state(actionGroup.get(), attribute), |
825 | + &gvariant_deleter); |
826 | + return value; |
827 | +} |
828 | + |
829 | +static shared_ptr<GVariant> get_attribute(const shared_ptr<GMenuItem> menuItem, const gchar* attribute) |
830 | +{ |
831 | + shared_ptr<GVariant> value( |
832 | + g_menu_item_get_attribute_value(menuItem.get(), attribute, nullptr), |
833 | + &gvariant_deleter); |
834 | + return value; |
835 | +} |
836 | + |
837 | +static string get_string_attribute(const shared_ptr<GMenuItem> menuItem, const gchar* attribute) |
838 | +{ |
839 | + string result; |
840 | + char* temp = nullptr; |
841 | + if (g_menu_item_get_attribute(menuItem.get(), attribute, "s", &temp)) |
842 | + { |
843 | + result = temp; |
844 | + g_free(temp); |
845 | + } |
846 | + return result; |
847 | +} |
848 | + |
849 | +static pair<string, string> split_action(const string& action) |
850 | +{ |
851 | + auto index = action.find('.'); |
852 | + |
853 | + if (index == string::npos) |
854 | + { |
855 | + return make_pair(string(), action); |
856 | + } |
857 | + |
858 | + return make_pair(action.substr(0, index), action.substr(index + 1, action.size())); |
859 | +} |
860 | + |
861 | +static string type_to_string(MenuItemMatcher::Type type) |
862 | +{ |
863 | + switch(type) |
864 | + { |
865 | + case MenuItemMatcher::Type::plain: |
866 | + return "plain"; |
867 | + case MenuItemMatcher::Type::checkbox: |
868 | + return "checkbox"; |
869 | + case MenuItemMatcher::Type::radio: |
870 | + return "radio"; |
871 | + } |
872 | + |
873 | + return string(); |
874 | +} |
875 | +} |
876 | + |
877 | +struct MenuItemMatcher::Priv |
878 | +{ |
879 | + void all(MatchResult& matchResult, const vector<unsigned int>& location, |
880 | + const shared_ptr<GMenuModel>& menu, |
881 | + map<string, shared_ptr<GActionGroup>>& actions) |
882 | + { |
883 | + int count = g_menu_model_get_n_items(menu.get()); |
884 | + |
885 | + if (m_items.size() != (unsigned int) count) |
886 | + { |
887 | + matchResult.failure( |
888 | + location, |
889 | + "Expected " + to_string(m_items.size()) |
890 | + + " children, but found " + to_string(count)); |
891 | + return; |
892 | + } |
893 | + |
894 | + for (size_t i = 0; i < m_items.size(); ++i) |
895 | + { |
896 | + const auto& matcher = m_items.at(i); |
897 | + matcher.match(matchResult, location, menu, actions, i); |
898 | + } |
899 | + } |
900 | + |
901 | + void startsWith(MatchResult& matchResult, const vector<unsigned int>& location, |
902 | + const shared_ptr<GMenuModel>& menu, |
903 | + map<string, shared_ptr<GActionGroup>>& actions) |
904 | + { |
905 | + int count = g_menu_model_get_n_items(menu.get()); |
906 | + if (m_items.size() > (unsigned int) count) |
907 | + { |
908 | + matchResult.failure( |
909 | + location, |
910 | + "Expected at least " + to_string(m_items.size()) |
911 | + + " children, but found " + to_string(count)); |
912 | + return; |
913 | + } |
914 | + |
915 | + for (size_t i = 0; i < m_items.size(); ++i) |
916 | + { |
917 | + const auto& matcher = m_items.at(i); |
918 | + matcher.match(matchResult, location, menu, actions, i); |
919 | + } |
920 | + } |
921 | + |
922 | + void endsWith(MatchResult& matchResult, const vector<unsigned int>& location, |
923 | + const shared_ptr<GMenuModel>& menu, |
924 | + map<string, shared_ptr<GActionGroup>>& actions) |
925 | + { |
926 | + int count = g_menu_model_get_n_items(menu.get()); |
927 | + if (m_items.size() > (unsigned int) count) |
928 | + { |
929 | + matchResult.failure( |
930 | + location, |
931 | + "Expected at least " + to_string(m_items.size()) |
932 | + + " children, but found " + to_string(count)); |
933 | + return; |
934 | + } |
935 | + |
936 | + // match the last N items |
937 | + size_t j; |
938 | + for (size_t i = count - m_items.size(), j = 0; i < count && j < m_items.size(); ++i, ++j) |
939 | + { |
940 | + const auto& matcher = m_items.at(j); |
941 | + matcher.match(matchResult, location, menu, actions, i); |
942 | + } |
943 | + } |
944 | + |
945 | + Type m_type = Type::plain; |
946 | + |
947 | + Mode m_mode = Mode::all; |
948 | + |
949 | + LinkType m_linkType = LinkType::any; |
950 | + |
951 | + shared_ptr<size_t> m_expectedSize; |
952 | + |
953 | + shared_ptr<string> m_label; |
954 | + |
955 | + shared_ptr<string> m_icon; |
956 | + |
957 | + map<shared_ptr<string>, vector<std::string>> m_themed_icons; |
958 | + |
959 | + shared_ptr<string> m_action; |
960 | + |
961 | + vector<std::string> m_state_icons; |
962 | + |
963 | + vector<pair<string, shared_ptr<GVariant>>> m_attributes; |
964 | + |
965 | + vector<string> m_not_exist_attributes; |
966 | + |
967 | + vector<pair<string, shared_ptr<GVariant>>> m_pass_through_attributes; |
968 | + |
969 | + shared_ptr<bool> m_isToggled; |
970 | + |
971 | + vector<MenuItemMatcher> m_items; |
972 | + |
973 | + vector<pair<string, shared_ptr<GVariant>>> m_activations; |
974 | + |
975 | + vector<pair<string, shared_ptr<GVariant>>> m_setActionStates; |
976 | + |
977 | + double m_maxDifference = 0.0; |
978 | +}; |
979 | + |
980 | +MenuItemMatcher MenuItemMatcher::checkbox() |
981 | +{ |
982 | + MenuItemMatcher matcher; |
983 | + matcher.type(Type::checkbox); |
984 | + return matcher; |
985 | +} |
986 | + |
987 | +MenuItemMatcher MenuItemMatcher::radio() |
988 | +{ |
989 | + MenuItemMatcher matcher; |
990 | + matcher.type(Type::radio); |
991 | + return matcher; |
992 | +} |
993 | + |
994 | +MenuItemMatcher::MenuItemMatcher() : |
995 | + p(new Priv) |
996 | +{ |
997 | +} |
998 | + |
999 | +MenuItemMatcher::~MenuItemMatcher() |
1000 | +{ |
1001 | +} |
1002 | + |
1003 | +MenuItemMatcher::MenuItemMatcher(const MenuItemMatcher& other) : |
1004 | + p(new Priv) |
1005 | +{ |
1006 | + *this = other; |
1007 | +} |
1008 | + |
1009 | +MenuItemMatcher::MenuItemMatcher(MenuItemMatcher&& other) |
1010 | +{ |
1011 | + *this = move(other); |
1012 | +} |
1013 | + |
1014 | +MenuItemMatcher& MenuItemMatcher::operator=(const MenuItemMatcher& other) |
1015 | +{ |
1016 | + p->m_type = other.p->m_type; |
1017 | + p->m_mode = other.p->m_mode; |
1018 | + p->m_expectedSize = other.p->m_expectedSize; |
1019 | + p->m_label = other.p->m_label; |
1020 | + p->m_icon = other.p->m_icon; |
1021 | + p->m_themed_icons = other.p->m_themed_icons; |
1022 | + p->m_action = other.p->m_action; |
1023 | + p->m_state_icons = other.p->m_state_icons; |
1024 | + p->m_attributes = other.p->m_attributes; |
1025 | + p->m_not_exist_attributes = other.p->m_not_exist_attributes; |
1026 | + p->m_pass_through_attributes = other.p->m_pass_through_attributes; |
1027 | + p->m_isToggled = other.p->m_isToggled; |
1028 | + p->m_linkType = other.p->m_linkType; |
1029 | + p->m_items = other.p->m_items; |
1030 | + p->m_activations = other.p->m_activations; |
1031 | + p->m_setActionStates = other.p->m_setActionStates; |
1032 | + p->m_maxDifference = other.p->m_maxDifference; |
1033 | + return *this; |
1034 | +} |
1035 | + |
1036 | +MenuItemMatcher& MenuItemMatcher::operator=(MenuItemMatcher&& other) |
1037 | +{ |
1038 | + p = move(other.p); |
1039 | + return *this; |
1040 | +} |
1041 | + |
1042 | +MenuItemMatcher& MenuItemMatcher::type(Type type) |
1043 | +{ |
1044 | + p->m_type = type; |
1045 | + return *this; |
1046 | +} |
1047 | + |
1048 | +MenuItemMatcher& MenuItemMatcher::label(const string& label) |
1049 | +{ |
1050 | + p->m_label = make_shared<string>(label); |
1051 | + return *this; |
1052 | +} |
1053 | + |
1054 | +MenuItemMatcher& MenuItemMatcher::action(const string& action) |
1055 | +{ |
1056 | + p->m_action = make_shared<string>(action); |
1057 | + return *this; |
1058 | +} |
1059 | + |
1060 | +MenuItemMatcher& MenuItemMatcher::state_icons(const std::vector<std::string>& state_icons) |
1061 | +{ |
1062 | + p->m_state_icons = state_icons; |
1063 | + return *this; |
1064 | +} |
1065 | + |
1066 | +MenuItemMatcher& MenuItemMatcher::icon(const string& icon) |
1067 | +{ |
1068 | + p->m_icon = make_shared<string>(icon); |
1069 | + return *this; |
1070 | +} |
1071 | + |
1072 | +MenuItemMatcher& MenuItemMatcher::themed_icon(const std::string& iconName, const std::vector<std::string>& icons) |
1073 | +{ |
1074 | + p->m_themed_icons[make_shared<string>(iconName)] = icons; |
1075 | + return *this; |
1076 | +} |
1077 | + |
1078 | +MenuItemMatcher& MenuItemMatcher::widget(const string& widget) |
1079 | +{ |
1080 | + return string_attribute("x-canonical-type", widget); |
1081 | +} |
1082 | + |
1083 | +MenuItemMatcher& MenuItemMatcher::pass_through_attribute(const string& actionName, const shared_ptr<GVariant>& value) |
1084 | +{ |
1085 | + p->m_pass_through_attributes.emplace_back(actionName, value); |
1086 | + return *this; |
1087 | +} |
1088 | + |
1089 | +MenuItemMatcher& MenuItemMatcher::pass_through_boolean_attribute(const string& actionName, bool value) |
1090 | +{ |
1091 | + return pass_through_attribute( |
1092 | + actionName, |
1093 | + shared_ptr<GVariant>(g_variant_new_boolean(value), |
1094 | + &gvariant_deleter)); |
1095 | +} |
1096 | + |
1097 | +MenuItemMatcher& MenuItemMatcher::pass_through_string_attribute(const string& actionName, const string& value) |
1098 | +{ |
1099 | + return pass_through_attribute( |
1100 | + actionName, |
1101 | + shared_ptr<GVariant>(g_variant_new_string(value.c_str()), |
1102 | + &gvariant_deleter)); |
1103 | +} |
1104 | + |
1105 | +MenuItemMatcher& MenuItemMatcher::pass_through_double_attribute(const std::string& actionName, double value) |
1106 | +{ |
1107 | + return pass_through_attribute( |
1108 | + actionName, |
1109 | + shared_ptr<GVariant>(g_variant_new_double(value), |
1110 | + &gvariant_deleter)); |
1111 | +} |
1112 | + |
1113 | +MenuItemMatcher& MenuItemMatcher::round_doubles(double maxDifference) |
1114 | +{ |
1115 | + p->m_maxDifference = maxDifference; |
1116 | + return *this; |
1117 | +} |
1118 | + |
1119 | +MenuItemMatcher& MenuItemMatcher::attribute(const string& name, const shared_ptr<GVariant>& value) |
1120 | +{ |
1121 | + p->m_attributes.emplace_back(name, value); |
1122 | + return *this; |
1123 | +} |
1124 | + |
1125 | +MenuItemMatcher& MenuItemMatcher::boolean_attribute(const string& name, bool value) |
1126 | +{ |
1127 | + return attribute( |
1128 | + name, |
1129 | + shared_ptr<GVariant>(g_variant_new_boolean(value), |
1130 | + &gvariant_deleter)); |
1131 | +} |
1132 | + |
1133 | +MenuItemMatcher& MenuItemMatcher::string_attribute(const string& name, const string& value) |
1134 | +{ |
1135 | + return attribute( |
1136 | + name, |
1137 | + shared_ptr<GVariant>(g_variant_new_string(value.c_str()), |
1138 | + &gvariant_deleter)); |
1139 | +} |
1140 | + |
1141 | +MenuItemMatcher& MenuItemMatcher::int32_attribute(const std::string& name, int value) |
1142 | +{ |
1143 | + return attribute( |
1144 | + name, |
1145 | + shared_ptr<GVariant>(g_variant_new_int32 (value), |
1146 | + &gvariant_deleter)); |
1147 | +} |
1148 | + |
1149 | +MenuItemMatcher& MenuItemMatcher::int64_attribute(const std::string& name, int value) |
1150 | +{ |
1151 | + return attribute( |
1152 | + name, |
1153 | + shared_ptr<GVariant>(g_variant_new_int64 (value), |
1154 | + &gvariant_deleter)); |
1155 | +} |
1156 | + |
1157 | +MenuItemMatcher& MenuItemMatcher::double_attribute(const std::string& name, double value) |
1158 | +{ |
1159 | + return attribute( |
1160 | + name, |
1161 | + shared_ptr<GVariant>(g_variant_new_double (value), |
1162 | + &gvariant_deleter)); |
1163 | +} |
1164 | + |
1165 | +MenuItemMatcher& MenuItemMatcher::attribute_not_set(const std::string& name) |
1166 | +{ |
1167 | + p->m_not_exist_attributes.emplace_back (name); |
1168 | + return *this; |
1169 | +} |
1170 | + |
1171 | +MenuItemMatcher& MenuItemMatcher::toggled(bool isToggled) |
1172 | +{ |
1173 | + p->m_isToggled = make_shared<bool>(isToggled); |
1174 | + return *this; |
1175 | +} |
1176 | + |
1177 | +MenuItemMatcher& MenuItemMatcher::mode(Mode mode) |
1178 | +{ |
1179 | + p->m_mode = mode; |
1180 | + return *this; |
1181 | +} |
1182 | + |
1183 | +MenuItemMatcher& MenuItemMatcher::submenu() |
1184 | +{ |
1185 | + p->m_linkType = LinkType::submenu; |
1186 | + return *this; |
1187 | +} |
1188 | + |
1189 | +MenuItemMatcher& MenuItemMatcher::section() |
1190 | +{ |
1191 | + p->m_linkType = LinkType::section; |
1192 | + return *this; |
1193 | +} |
1194 | + |
1195 | +MenuItemMatcher& MenuItemMatcher::is_empty() |
1196 | +{ |
1197 | + return has_exactly(0); |
1198 | +} |
1199 | + |
1200 | +MenuItemMatcher& MenuItemMatcher::has_exactly(size_t children) |
1201 | +{ |
1202 | + p->m_expectedSize = make_shared<size_t>(children); |
1203 | + return *this; |
1204 | +} |
1205 | + |
1206 | +MenuItemMatcher& MenuItemMatcher::item(const MenuItemMatcher& item) |
1207 | +{ |
1208 | + p->m_items.emplace_back(item); |
1209 | + return *this; |
1210 | +} |
1211 | + |
1212 | +MenuItemMatcher& MenuItemMatcher::item(MenuItemMatcher&& item) |
1213 | +{ |
1214 | + p->m_items.emplace_back(item); |
1215 | + return *this; |
1216 | +} |
1217 | + |
1218 | +MenuItemMatcher& MenuItemMatcher::pass_through_activate(std::string const& action, const shared_ptr<GVariant>& parameter) |
1219 | +{ |
1220 | + p->m_activations.emplace_back(action, parameter); |
1221 | + return *this; |
1222 | +} |
1223 | + |
1224 | +MenuItemMatcher& MenuItemMatcher::activate(const shared_ptr<GVariant>& parameter) |
1225 | +{ |
1226 | + p->m_activations.emplace_back(string(), parameter); |
1227 | + return *this; |
1228 | +} |
1229 | + |
1230 | +MenuItemMatcher& MenuItemMatcher::set_pass_through_action_state(const std::string& action, const std::shared_ptr<GVariant>& state) |
1231 | +{ |
1232 | + p->m_setActionStates.emplace_back(action, state); |
1233 | + return *this; |
1234 | +} |
1235 | + |
1236 | +MenuItemMatcher& MenuItemMatcher::set_action_state(const std::shared_ptr<GVariant>& state) |
1237 | +{ |
1238 | + p->m_setActionStates.emplace_back("", state); |
1239 | + return *this; |
1240 | +} |
1241 | + |
1242 | +void MenuItemMatcher::match( |
1243 | + MatchResult& matchResult, |
1244 | + const vector<unsigned int>& parentLocation, |
1245 | + const shared_ptr<GMenuModel>& menu, |
1246 | + map<string, shared_ptr<GActionGroup>>& actions, |
1247 | + int index) const |
1248 | +{ |
1249 | + shared_ptr<GMenuItem> menuItem(g_menu_item_new_from_model(menu.get(), index), &g_object_deleter); |
1250 | + |
1251 | + vector<unsigned int> location(parentLocation); |
1252 | + location.emplace_back(index); |
1253 | + |
1254 | + string action = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_ACTION); |
1255 | + |
1256 | + bool isCheckbox = false; |
1257 | + bool isRadio = false; |
1258 | + bool isToggled = false; |
1259 | + |
1260 | + pair<string, string> idPair; |
1261 | + shared_ptr<GActionGroup> actionGroup; |
1262 | + shared_ptr<GVariant> state; |
1263 | + |
1264 | + if (!action.empty()) |
1265 | + { |
1266 | + idPair = split_action(action); |
1267 | + actionGroup = actions[idPair.first]; |
1268 | + state = shared_ptr<GVariant>(g_action_group_get_action_state(actionGroup.get(), |
1269 | + idPair.second.c_str()), |
1270 | + &gvariant_deleter); |
1271 | + auto attributeTarget = get_attribute(menuItem, G_MENU_ATTRIBUTE_TARGET); |
1272 | + |
1273 | + if (attributeTarget && state) |
1274 | + { |
1275 | + isToggled = g_variant_equal(state.get(), attributeTarget.get()); |
1276 | + isRadio = true; |
1277 | + } |
1278 | + else if (state |
1279 | + && g_variant_is_of_type(state.get(), G_VARIANT_TYPE_BOOLEAN)) |
1280 | + { |
1281 | + isToggled = g_variant_get_boolean(state.get()); |
1282 | + isCheckbox = true; |
1283 | + } |
1284 | + } |
1285 | + |
1286 | + Type actualType = Type::plain; |
1287 | + if (isCheckbox) |
1288 | + { |
1289 | + actualType = Type::checkbox; |
1290 | + } |
1291 | + else if (isRadio) |
1292 | + { |
1293 | + actualType = Type::radio; |
1294 | + } |
1295 | + |
1296 | + if (actualType != p->m_type) |
1297 | + { |
1298 | + matchResult.failure( |
1299 | + location, |
1300 | + "Expected " + type_to_string(p->m_type) + ", found " |
1301 | + + type_to_string(actualType)); |
1302 | + } |
1303 | + |
1304 | + // check themed icons |
1305 | + map<shared_ptr<string>, vector<string>>::iterator iter; |
1306 | + for (iter = p->m_themed_icons.begin(); iter != p->m_themed_icons.end(); ++iter) |
1307 | + { |
1308 | + auto icon_val = g_menu_item_get_attribute_value(menuItem.get(), (*iter).first->c_str(), nullptr); |
1309 | + if (!icon_val) |
1310 | + { |
1311 | + matchResult.failure( |
1312 | + location, |
1313 | + "Expected themed icon " + (*(*iter).first) + " was not found"); |
1314 | + } |
1315 | + |
1316 | + auto gicon = g_icon_deserialize(icon_val); |
1317 | + if (!gicon || !G_IS_THEMED_ICON(gicon)) |
1318 | + { |
1319 | + matchResult.failure( |
1320 | + location, |
1321 | + "Expected attribute " + (*(*iter).first) + " is not a themed icon"); |
1322 | + } |
1323 | + auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); |
1324 | + int nb_icons = 0; |
1325 | + while(iconNames[nb_icons]) |
1326 | + { |
1327 | + ++nb_icons; |
1328 | + } |
1329 | + |
1330 | + if (nb_icons != (*iter).second.size()) |
1331 | + { |
1332 | + matchResult.failure( |
1333 | + location, |
1334 | + "Expected " + to_string((*iter).second.size()) + |
1335 | + " icons for themed icon [" + (*(*iter).first) + |
1336 | + "], but " + to_string(nb_icons) + " were found."); |
1337 | + } |
1338 | + else |
1339 | + { |
1340 | + // now compare all the icons |
1341 | + for (int i = 0; i < nb_icons; ++i) |
1342 | + { |
1343 | + if (string(iconNames[i]) != (*iter).second[i]) |
1344 | + { |
1345 | + matchResult.failure( |
1346 | + location, |
1347 | + "Icon at position " + to_string(i) + |
1348 | + " for themed icon [" + (*(*iter).first) + |
1349 | + "], mismatchs. Expected: " + iconNames[i] + " but found " + (*iter).second[i]); |
1350 | + } |
1351 | + } |
1352 | + } |
1353 | + g_object_unref(gicon); |
1354 | + } |
1355 | + |
1356 | + string label = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_LABEL); |
1357 | + if (p->m_label && (*p->m_label) != label) |
1358 | + { |
1359 | + matchResult.failure( |
1360 | + location, |
1361 | + "Expected label '" + *p->m_label + "', but found '" + label |
1362 | + + "'"); |
1363 | + } |
1364 | + |
1365 | + string icon = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_ICON); |
1366 | + if (p->m_icon && (*p->m_icon) != icon) |
1367 | + { |
1368 | + matchResult.failure( |
1369 | + location, |
1370 | + "Expected icon '" + *p->m_icon + "', but found '" + icon + "'"); |
1371 | + } |
1372 | + |
1373 | + if (p->m_action && (*p->m_action) != action) |
1374 | + { |
1375 | + matchResult.failure( |
1376 | + location, |
1377 | + "Expected action '" + *p->m_action + "', but found '" + action |
1378 | + + "'"); |
1379 | + } |
1380 | + |
1381 | + if (!p->m_state_icons.empty() && !state) |
1382 | + { |
1383 | + matchResult.failure( |
1384 | + location, |
1385 | + "Expected state icons but no state was found"); |
1386 | + } |
1387 | + else if (!p->m_state_icons.empty() && state && |
1388 | + !g_variant_is_of_type(state.get(), G_VARIANT_TYPE_VARDICT)) |
1389 | + { |
1390 | + matchResult.failure( |
1391 | + location, |
1392 | + "Expected state icons vardict, found " |
1393 | + + type_to_string(actualType)); |
1394 | + } |
1395 | + else if (!p->m_state_icons.empty() && state && |
1396 | + g_variant_is_of_type(state.get(), G_VARIANT_TYPE_VARDICT)) |
1397 | + { |
1398 | + std::vector<std::string> actual_state_icons; |
1399 | + GVariantIter it; |
1400 | + gchar* key; |
1401 | + GVariant* value; |
1402 | + |
1403 | + g_variant_iter_init(&it, state.get()); |
1404 | + while (g_variant_iter_loop(&it, "{sv}", &key, &value)) |
1405 | + { |
1406 | + if (std::string(key) == "icon") { |
1407 | + auto gicon = g_icon_deserialize(value); |
1408 | + if (gicon && G_IS_THEMED_ICON(gicon)) |
1409 | + { |
1410 | + auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); |
1411 | + // Just take the first icon in the list (there is only ever one) |
1412 | + actual_state_icons.push_back(iconNames[0]); |
1413 | + g_object_unref(gicon); |
1414 | + } |
1415 | + } |
1416 | + else if (std::string(key) == "icons" && g_variant_is_of_type(value, G_VARIANT_TYPE("av"))) |
1417 | + { |
1418 | + // If we find "icons" in the map, clear any icons we may have found in "icon", |
1419 | + // then break from the loop as we have found all icons now. |
1420 | + actual_state_icons.clear(); |
1421 | + GVariantIter icon_it; |
1422 | + GVariant* icon_value; |
1423 | + |
1424 | + g_variant_iter_init(&icon_it, value); |
1425 | + while (g_variant_iter_loop(&icon_it, "v", &icon_value)) |
1426 | + { |
1427 | + auto gicon = g_icon_deserialize(icon_value); |
1428 | + if (gicon && G_IS_THEMED_ICON(gicon)) |
1429 | + { |
1430 | + auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); |
1431 | + // Just take the first icon in the list (there is only ever one) |
1432 | + actual_state_icons.push_back(iconNames[0]); |
1433 | + g_object_unref(gicon); |
1434 | + } |
1435 | + } |
1436 | + // We're breaking out of g_variant_iter_loop here so clean up |
1437 | + g_variant_unref(value); |
1438 | + g_free(key); |
1439 | + break; |
1440 | + } |
1441 | + } |
1442 | + |
1443 | + if (p->m_state_icons != actual_state_icons) |
1444 | + { |
1445 | + std::string expected_icons; |
1446 | + for (unsigned int i = 0; i < p->m_state_icons.size(); ++i) |
1447 | + { |
1448 | + expected_icons += i == 0 ? p->m_state_icons[i] : ", " + p->m_state_icons[i]; |
1449 | + } |
1450 | + std::string actual_icons; |
1451 | + for (unsigned int i = 0; i < actual_state_icons.size(); ++i) |
1452 | + { |
1453 | + actual_icons += i == 0 ? actual_state_icons[i] : ", " + actual_state_icons[i]; |
1454 | + } |
1455 | + matchResult.failure( |
1456 | + location, |
1457 | + "Expected state_icons == {" + expected_icons |
1458 | + + "} but found {" + actual_icons + "}"); |
1459 | + } |
1460 | + } |
1461 | + |
1462 | + for (const auto& e: p->m_pass_through_attributes) |
1463 | + { |
1464 | + string actionName = get_string_attribute(menuItem, e.first.c_str()); |
1465 | + if (actionName.empty()) |
1466 | + { |
1467 | + matchResult.failure( |
1468 | + location, |
1469 | + "Could not find action name '" + e.first + "'"); |
1470 | + } |
1471 | + else |
1472 | + { |
1473 | + auto passThroughIdPair = split_action(actionName); |
1474 | + auto actionGroup = actions[passThroughIdPair.first]; |
1475 | + if (actionGroup) |
1476 | + { |
1477 | + auto value = get_action_group_attribute( |
1478 | + actionGroup, passThroughIdPair.second.c_str()); |
1479 | + if (!value) |
1480 | + { |
1481 | + matchResult.failure( |
1482 | + location, |
1483 | + "Expected pass-through attribute '" + e.first |
1484 | + + "' was not present"); |
1485 | + } |
1486 | + else if (!g_variant_is_of_type(e.second.get(), g_variant_get_type(value.get()))) |
1487 | + { |
1488 | + std::string expectedType = g_variant_get_type_string(e.second.get()); |
1489 | + std::string actualType = g_variant_get_type_string(value.get()); |
1490 | + matchResult.failure( |
1491 | + location, |
1492 | + "Expected pass-through attribute type '" + expectedType |
1493 | + + "' but found '" + actualType + "'"); |
1494 | + } |
1495 | + else if (g_variant_compare(e.second.get(), value.get())) |
1496 | + { |
1497 | + bool reportMismatch = true; |
1498 | + if (g_strcmp0(g_variant_get_type_string(value.get()),"d") == 0 && p->m_maxDifference) |
1499 | + { |
1500 | + auto actualDouble = g_variant_get_double(value.get()); |
1501 | + auto expectedDouble = g_variant_get_double(e.second.get()); |
1502 | + auto difference = actualDouble-expectedDouble; |
1503 | + if (difference < 0) difference = difference * -1.0; |
1504 | + if (difference <= p->m_maxDifference) |
1505 | + { |
1506 | + reportMismatch = false; |
1507 | + } |
1508 | + } |
1509 | + if (reportMismatch) |
1510 | + { |
1511 | + gchar* expectedString = g_variant_print(e.second.get(), true); |
1512 | + gchar* actualString = g_variant_print(value.get(), true); |
1513 | + matchResult.failure( |
1514 | + location, |
1515 | + "Expected pass-through attribute '" + e.first |
1516 | + + "' == " + expectedString + " but found " |
1517 | + + actualString); |
1518 | + |
1519 | + g_free(expectedString); |
1520 | + g_free(actualString); |
1521 | + } |
1522 | + } |
1523 | + } |
1524 | + else |
1525 | + { |
1526 | + matchResult.failure(location, "Could not find action group for ID '" + passThroughIdPair.first + "'"); |
1527 | + } |
1528 | + } |
1529 | + } |
1530 | + |
1531 | + for (const auto& e: p->m_attributes) |
1532 | + { |
1533 | + auto value = get_attribute(menuItem, e.first.c_str()); |
1534 | + if (!value) |
1535 | + { |
1536 | + matchResult.failure(location, |
1537 | + "Expected attribute '" + e.first |
1538 | + + "' could not be found"); |
1539 | + } |
1540 | + else if (!g_variant_is_of_type(e.second.get(), g_variant_get_type(value.get()))) |
1541 | + { |
1542 | + std::string expectedType = g_variant_get_type_string(e.second.get()); |
1543 | + std::string actualType = g_variant_get_type_string(value.get()); |
1544 | + matchResult.failure( |
1545 | + location, |
1546 | + "Expected attribute type '" + expectedType |
1547 | + + "' but found '" + actualType + "'"); |
1548 | + } |
1549 | + else if (g_variant_compare(e.second.get(), value.get())) |
1550 | + { |
1551 | + gchar* expectedString = g_variant_print(e.second.get(), true); |
1552 | + gchar* actualString = g_variant_print(value.get(), true); |
1553 | + matchResult.failure( |
1554 | + location, |
1555 | + "Expected attribute '" + e.first + "' == " + expectedString |
1556 | + + ", but found " + actualString); |
1557 | + g_free(expectedString); |
1558 | + g_free(actualString); |
1559 | + } |
1560 | + } |
1561 | + |
1562 | + for (const auto& e: p->m_not_exist_attributes) |
1563 | + { |
1564 | + auto value = get_attribute(menuItem, e.c_str()); |
1565 | + if (value) |
1566 | + { |
1567 | + matchResult.failure(location, |
1568 | + "Not expected attribute '" + e |
1569 | + + "' was found"); |
1570 | + } |
1571 | + } |
1572 | + |
1573 | + if (p->m_isToggled && (*p->m_isToggled) != isToggled) |
1574 | + { |
1575 | + matchResult.failure( |
1576 | + location, |
1577 | + "Expected toggled = " + bool_to_string(*p->m_isToggled) |
1578 | + + ", but found " + bool_to_string(isToggled)); |
1579 | + } |
1580 | + |
1581 | + if (!matchResult.success()) |
1582 | + { |
1583 | + return; |
1584 | + } |
1585 | + |
1586 | + if (!p->m_items.empty() || p->m_expectedSize) |
1587 | + { |
1588 | + shared_ptr<GMenuModel> link; |
1589 | + |
1590 | + switch (p->m_linkType) |
1591 | + { |
1592 | + case LinkType::any: |
1593 | + { |
1594 | + link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SUBMENU), &g_object_deleter); |
1595 | + if (!link) |
1596 | + { |
1597 | + link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SECTION), &g_object_deleter); |
1598 | + } |
1599 | + break; |
1600 | + } |
1601 | + case LinkType::submenu: |
1602 | + { |
1603 | + link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SUBMENU), &g_object_deleter); |
1604 | + break; |
1605 | + } |
1606 | + case LinkType::section: |
1607 | + { |
1608 | + link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SECTION), &g_object_deleter); |
1609 | + break; |
1610 | + } |
1611 | + } |
1612 | + |
1613 | + |
1614 | + if (!link) |
1615 | + { |
1616 | + if (p->m_expectedSize) |
1617 | + { |
1618 | + matchResult.failure( |
1619 | + location, |
1620 | + "Expected " + to_string(*p->m_expectedSize) |
1621 | + + " children, but found none"); |
1622 | + } |
1623 | + else |
1624 | + { |
1625 | + matchResult.failure( |
1626 | + location, |
1627 | + "Expected " + to_string(p->m_items.size()) |
1628 | + + " children, but found none"); |
1629 | + } |
1630 | + return; |
1631 | + } |
1632 | + else |
1633 | + { |
1634 | + while (true) |
1635 | + { |
1636 | + MatchResult childMatchResult(matchResult.createChild()); |
1637 | + |
1638 | + if (p->m_expectedSize |
1639 | + && *p->m_expectedSize |
1640 | + != (unsigned int) g_menu_model_get_n_items( |
1641 | + link.get())) |
1642 | + { |
1643 | + childMatchResult.failure( |
1644 | + location, |
1645 | + "Expected " + to_string(*p->m_expectedSize) |
1646 | + + " child items, but found " |
1647 | + + to_string( |
1648 | + g_menu_model_get_n_items( |
1649 | + link.get()))); |
1650 | + } |
1651 | + else if (!p->m_items.empty()) |
1652 | + { |
1653 | + switch (p->m_mode) |
1654 | + { |
1655 | + case Mode::all: |
1656 | + p->all(childMatchResult, location, link, actions); |
1657 | + break; |
1658 | + case Mode::starts_with: |
1659 | + p->startsWith(childMatchResult, location, link, actions); |
1660 | + break; |
1661 | + case Mode::ends_with: |
1662 | + p->endsWith(childMatchResult, location, link, actions); |
1663 | + break; |
1664 | + } |
1665 | + } |
1666 | + |
1667 | + if (childMatchResult.success()) |
1668 | + { |
1669 | + matchResult.merge(childMatchResult); |
1670 | + break; |
1671 | + } |
1672 | + else |
1673 | + { |
1674 | + if (matchResult.hasTimedOut()) |
1675 | + { |
1676 | + matchResult.merge(childMatchResult); |
1677 | + break; |
1678 | + } |
1679 | + menuWaitForItems(link); |
1680 | + } |
1681 | + } |
1682 | + } |
1683 | + } |
1684 | + |
1685 | + |
1686 | + for (const auto& a: p->m_setActionStates) |
1687 | + { |
1688 | + auto stateAction = action; |
1689 | + auto stateIdPair = idPair; |
1690 | + auto stateActionGroup = actionGroup; |
1691 | + if (!a.first.empty()) |
1692 | + { |
1693 | + stateAction = get_string_attribute(menuItem, a.first.c_str());; |
1694 | + stateIdPair = split_action(stateAction); |
1695 | + stateActionGroup = actions[stateIdPair.first]; |
1696 | + } |
1697 | + |
1698 | + if (stateAction.empty()) |
1699 | + { |
1700 | + matchResult.failure( |
1701 | + location, |
1702 | + "Tried to set action state, but no action was found"); |
1703 | + } |
1704 | + else if(!stateActionGroup) |
1705 | + { |
1706 | + matchResult.failure( |
1707 | + location, |
1708 | + "Tried to set action state for action group '" + stateIdPair.first |
1709 | + + "', but action group wasn't found"); |
1710 | + } |
1711 | + else if (!g_action_group_has_action(stateActionGroup.get(), stateIdPair.second.c_str())) |
1712 | + { |
1713 | + matchResult.failure( |
1714 | + location, |
1715 | + "Tried to set action state for action '" + stateAction |
1716 | + + "', but action was not found"); |
1717 | + } |
1718 | + else |
1719 | + { |
1720 | + g_action_group_change_action_state(stateActionGroup.get(), stateIdPair.second.c_str(), |
1721 | + g_variant_ref(a.second.get())); |
1722 | + } |
1723 | + |
1724 | + // FIXME this is a dodgy way to ensure the action state change gets dispatched |
1725 | + menuWaitForItems(menu, 100); |
1726 | + } |
1727 | + |
1728 | + for (const auto& a: p->m_activations) |
1729 | + { |
1730 | + string tmpAction = action; |
1731 | + auto tmpIdPair = idPair; |
1732 | + auto tmpActionGroup = actionGroup; |
1733 | + if (!a.first.empty()) |
1734 | + { |
1735 | + tmpAction = get_string_attribute(menuItem, a.first.c_str()); |
1736 | + tmpIdPair = split_action(tmpAction); |
1737 | + tmpActionGroup = actions[tmpIdPair.first]; |
1738 | + } |
1739 | + |
1740 | + if (tmpAction.empty()) |
1741 | + { |
1742 | + matchResult.failure( |
1743 | + location, |
1744 | + "Tried to activate action, but no action was found"); |
1745 | + } |
1746 | + else if(!tmpActionGroup) |
1747 | + { |
1748 | + matchResult.failure( |
1749 | + location, |
1750 | + "Tried to activate action group '" + tmpIdPair.first |
1751 | + + "', but action group wasn't found"); |
1752 | + } |
1753 | + else if (!g_action_group_has_action(tmpActionGroup.get(), tmpIdPair.second.c_str())) |
1754 | + { |
1755 | + matchResult.failure( |
1756 | + location, |
1757 | + "Tried to activate action '" + tmpAction + "', but action was not found"); |
1758 | + } |
1759 | + else |
1760 | + { |
1761 | + if (a.second) |
1762 | + { |
1763 | + g_action_group_activate_action(tmpActionGroup.get(), tmpIdPair.second.c_str(), |
1764 | + g_variant_ref(a.second.get())); |
1765 | + } |
1766 | + else |
1767 | + { |
1768 | + g_action_group_activate_action(tmpActionGroup.get(), tmpIdPair.second.c_str(), nullptr); |
1769 | + } |
1770 | + |
1771 | + // FIXME this is a dodgy way to ensure the activation gets dispatched |
1772 | + menuWaitForItems(menu, 100); |
1773 | + } |
1774 | + } |
1775 | +} |
1776 | + |
1777 | +} // namepsace gmenuharness |
1778 | + |
1779 | +} // namespace unity |
1780 | |
1781 | === added file 'src/gmenuharness/MenuMatcher.cpp' |
1782 | --- src/gmenuharness/MenuMatcher.cpp 1970-01-01 00:00:00 +0000 |
1783 | +++ src/gmenuharness/MenuMatcher.cpp 2015-10-01 13:45:49 +0000 |
1784 | @@ -0,0 +1,208 @@ |
1785 | +/* |
1786 | + * Copyright © 2014 Canonical Ltd. |
1787 | + * |
1788 | + * This program is free software: you can redistribute it and/or modify it |
1789 | + * under the terms of the GNU Lesser General Public License version 3, |
1790 | + * as published by the Free Software Foundation. |
1791 | + * |
1792 | + * This program is distributed in the hope that it will be useful, |
1793 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1794 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1795 | + * GNU Lesser General Public License for more details. |
1796 | + * |
1797 | + * You should have received a copy of the GNU Lesser General Public License |
1798 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1799 | + * |
1800 | + * Authored by: Pete Woods <pete.woods@canonical.com> |
1801 | + */ |
1802 | + |
1803 | +#include <unity/gmenuharness/MenuMatcher.h> |
1804 | +#include <unity/gmenuharness/MatchUtils.h> |
1805 | + |
1806 | +#include <iostream> |
1807 | + |
1808 | +#include <gio/gio.h> |
1809 | + |
1810 | +using namespace std; |
1811 | + |
1812 | +namespace unity |
1813 | +{ |
1814 | + |
1815 | +namespace gmenuharness |
1816 | +{ |
1817 | + |
1818 | +namespace |
1819 | +{ |
1820 | + |
1821 | +static void gdbus_connection_deleter(GDBusConnection* connection) |
1822 | +{ |
1823 | +// if (!g_dbus_connection_is_closed(connection)) |
1824 | +// { |
1825 | +// g_dbus_connection_close_sync(connection, nullptr, nullptr); |
1826 | +// } |
1827 | + g_clear_object(&connection); |
1828 | +} |
1829 | +} |
1830 | + |
1831 | +struct MenuMatcher::Parameters::Priv |
1832 | +{ |
1833 | + string m_busName; |
1834 | + |
1835 | + vector<pair<string, string>> m_actions; |
1836 | + |
1837 | + string m_menuObjectPath; |
1838 | +}; |
1839 | + |
1840 | +MenuMatcher::Parameters::Parameters(const string& busName, |
1841 | + const vector<pair<string, string>>& actions, |
1842 | + const string& menuObjectPath) : |
1843 | + p(new Priv) |
1844 | +{ |
1845 | + p->m_busName = busName; |
1846 | + p->m_actions = actions; |
1847 | + p->m_menuObjectPath = menuObjectPath; |
1848 | +} |
1849 | + |
1850 | +MenuMatcher::Parameters::~Parameters() |
1851 | +{ |
1852 | +} |
1853 | + |
1854 | +MenuMatcher::Parameters::Parameters(const Parameters& other) : |
1855 | + p(new Priv) |
1856 | +{ |
1857 | + *this = other; |
1858 | +} |
1859 | + |
1860 | +MenuMatcher::Parameters::Parameters(Parameters&& other) |
1861 | +{ |
1862 | + *this = move(other); |
1863 | +} |
1864 | + |
1865 | +MenuMatcher::Parameters& MenuMatcher::Parameters::operator=(const Parameters& other) |
1866 | +{ |
1867 | + p->m_busName = other.p->m_busName; |
1868 | + p->m_actions = other.p->m_actions; |
1869 | + p->m_menuObjectPath = other.p->m_menuObjectPath; |
1870 | + return *this; |
1871 | +} |
1872 | + |
1873 | +MenuMatcher::Parameters& MenuMatcher::Parameters::operator=(Parameters&& other) |
1874 | +{ |
1875 | + p = move(other.p); |
1876 | + return *this; |
1877 | +} |
1878 | + |
1879 | +struct MenuMatcher::Priv |
1880 | +{ |
1881 | + Priv(const Parameters& parameters) : |
1882 | + m_parameters(parameters) |
1883 | + { |
1884 | + } |
1885 | + |
1886 | + Parameters m_parameters; |
1887 | + |
1888 | + vector<MenuItemMatcher> m_items; |
1889 | + |
1890 | + shared_ptr<GDBusConnection> m_system; |
1891 | + |
1892 | + shared_ptr<GDBusConnection> m_session; |
1893 | + |
1894 | + shared_ptr<GMenuModel> m_menu; |
1895 | + |
1896 | + map<string, shared_ptr<GActionGroup>> m_actions; |
1897 | +}; |
1898 | + |
1899 | +MenuMatcher::MenuMatcher(const Parameters& parameters) : |
1900 | + p(new Priv(parameters)) |
1901 | +{ |
1902 | + p->m_system.reset(g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr), |
1903 | + &gdbus_connection_deleter); |
1904 | + g_dbus_connection_set_exit_on_close(p->m_system.get(), false); |
1905 | + |
1906 | + p->m_session.reset(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr), |
1907 | + &gdbus_connection_deleter); |
1908 | + g_dbus_connection_set_exit_on_close(p->m_session.get(), false); |
1909 | + |
1910 | + p->m_menu.reset( |
1911 | + G_MENU_MODEL( |
1912 | + g_dbus_menu_model_get( |
1913 | + p->m_session.get(), |
1914 | + p->m_parameters.p->m_busName.c_str(), |
1915 | + p->m_parameters.p->m_menuObjectPath.c_str())), |
1916 | + &g_object_deleter); |
1917 | + |
1918 | + for (const auto& action : p->m_parameters.p->m_actions) |
1919 | + { |
1920 | + shared_ptr<GActionGroup> actionGroup( |
1921 | + G_ACTION_GROUP( |
1922 | + g_dbus_action_group_get( |
1923 | + p->m_session.get(), |
1924 | + p->m_parameters.p->m_busName.c_str(), |
1925 | + action.second.c_str())), |
1926 | + &g_object_deleter); |
1927 | + p->m_actions[action.first] = actionGroup; |
1928 | + } |
1929 | +} |
1930 | + |
1931 | +MenuMatcher::~MenuMatcher() |
1932 | +{ |
1933 | +} |
1934 | + |
1935 | +MenuMatcher& MenuMatcher::item(const MenuItemMatcher& item) |
1936 | +{ |
1937 | + p->m_items.emplace_back(item); |
1938 | + return *this; |
1939 | +} |
1940 | + |
1941 | +void MenuMatcher::match(MatchResult& matchResult) const |
1942 | +{ |
1943 | + vector<unsigned int> location; |
1944 | + |
1945 | + while (true) |
1946 | + { |
1947 | + MatchResult childMatchResult(matchResult.createChild()); |
1948 | + |
1949 | + int menuSize = g_menu_model_get_n_items(p->m_menu.get()); |
1950 | + if (p->m_items.size() > (unsigned int) menuSize) |
1951 | + { |
1952 | + childMatchResult.failure( |
1953 | + location, |
1954 | + "Row count mismatch, expected " + to_string(p->m_items.size()) |
1955 | + + " but found " + to_string(menuSize)); |
1956 | + } |
1957 | + else |
1958 | + { |
1959 | + for (size_t i = 0; i < p->m_items.size(); ++i) |
1960 | + { |
1961 | + const auto& matcher = p->m_items.at(i); |
1962 | + matcher.match(childMatchResult, location, p->m_menu, p->m_actions, i); |
1963 | + } |
1964 | + } |
1965 | + |
1966 | + if (childMatchResult.success()) |
1967 | + { |
1968 | + matchResult.merge(childMatchResult); |
1969 | + break; |
1970 | + } |
1971 | + else |
1972 | + { |
1973 | + if (matchResult.hasTimedOut()) |
1974 | + { |
1975 | + matchResult.merge(childMatchResult); |
1976 | + break; |
1977 | + } |
1978 | + menuWaitForItems(p->m_menu); |
1979 | + } |
1980 | + } |
1981 | +} |
1982 | + |
1983 | +MatchResult MenuMatcher::match() const |
1984 | +{ |
1985 | + MatchResult matchResult; |
1986 | + match(matchResult); |
1987 | + return matchResult; |
1988 | +} |
1989 | + |
1990 | +} // namespace gmenuharness |
1991 | + |
1992 | +} // namespace unity |
1993 | |
1994 | === modified file 'src/media-player-mpris.vala' |
1995 | --- src/media-player-mpris.vala 2015-10-01 13:45:48 +0000 |
1996 | +++ src/media-player-mpris.vala 2015-10-01 13:45:49 +0000 |
1997 | @@ -290,7 +290,7 @@ |
1998 | if (changed_properties.lookup ("PlaybackStatus", "s", null)) { |
1999 | this.state = this.proxy.PlaybackStatus != null ? this.proxy.PlaybackStatus : "Unknown"; |
2000 | } |
2001 | - if (changed_properties.lookup ("CanGoNext", "b", null) || changed_properties.lookup ("CanGoPrev", "b", null)) { |
2002 | + if (changed_properties.lookup ("CanGoNext", "b", null) || changed_properties.lookup ("CanGoPrevious", "b", null)) { |
2003 | this.playbackstatus_changed (); |
2004 | } |
2005 | |
2006 | |
2007 | === modified file 'src/volume-control-pulse.vala' |
2008 | --- src/volume-control-pulse.vala 2015-08-12 18:16:40 +0000 |
2009 | +++ src/volume-control-pulse.vala 2015-10-01 13:45:49 +0000 |
2010 | @@ -275,7 +275,7 @@ |
2011 | } |
2012 | |
2013 | /* We only care about signals if our internal count is zero */ |
2014 | - if (sig_count == 0) { |
2015 | + //if (sig_count == 0) { |
2016 | /* Extract volume and make sure it's not a side effect of us setting it */ |
2017 | Variant body = message.get_body (); |
2018 | Variant varray = body.get_child_value (0); |
2019 | @@ -293,7 +293,7 @@ |
2020 | vol.reason = VolumeControl.VolumeReasons.PULSE_CHANGE; |
2021 | this.volume = vol; |
2022 | } |
2023 | - } |
2024 | + //} |
2025 | } |
2026 | } |
2027 | |
2028 | @@ -478,7 +478,8 @@ |
2029 | this.context = new PulseAudio.Context (loop.get_api(), null, props); |
2030 | this.context.set_state_callback (context_state_callback); |
2031 | |
2032 | - if (context.connect(null, Context.Flags.NOFAIL, null) < 0) |
2033 | + var server_string = Environment.get_variable("PULSE_SERVER"); |
2034 | + if (context.connect(server_string, Context.Flags.NOFAIL, null) < 0) |
2035 | warning( "pa_context_connect() failed: %s\n", PulseAudio.strerror(context.errno())); |
2036 | } |
2037 | |
2038 | @@ -627,7 +628,7 @@ |
2039 | } |
2040 | set { |
2041 | var volume_changed = (value.volume != _volume.volume); |
2042 | - debug("Setting volume to %f for profile %d because %d", value.volume, _active_sink_input, value.reason); |
2043 | + warning("Setting volume to %f for profile %d because %d", value.volume, _active_sink_input, value.reason); |
2044 | |
2045 | _volume = value; |
2046 | |
2047 | |
2048 | === modified file 'tests/CMakeLists.txt' |
2049 | --- tests/CMakeLists.txt 2015-08-11 21:42:20 +0000 |
2050 | +++ tests/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
2051 | @@ -5,10 +5,10 @@ |
2052 | |
2053 | include_directories(${GTEST_INCLUDE_DIR}) |
2054 | |
2055 | -add_library (gtest STATIC |
2056 | +add_library (gtest-static STATIC |
2057 | ${GTEST_SOURCE_DIR}/gtest-all.cc |
2058 | ${GTEST_SOURCE_DIR}/gtest_main.cc) |
2059 | -target_link_libraries(gtest ${GTEST_LIBS}) |
2060 | +target_link_libraries(gtest-static ${GTEST_LIBS}) |
2061 | |
2062 | ########################### |
2063 | # GSettings Schema |
2064 | @@ -22,7 +22,8 @@ |
2065 | # GSettings: |
2066 | # compile the indicator-sound schema into a gschemas.compiled file in this directory, |
2067 | # and help the tests to find that file by setting -DSCHEMA_DIR |
2068 | -set (SCHEMA_DIR "${CMAKE_CURRENT_BINARY_DIR}/gsettings-schemas") |
2069 | +set (XDG_DATA_DIRS "${CMAKE_CURRENT_BINARY_DIR}/gsettings-schemas") |
2070 | +set (SCHEMA_DIR "${XDG_DATA_DIRS}/glib-2.0/schemas") |
2071 | add_definitions(-DSCHEMA_DIR="${SCHEMA_DIR}") |
2072 | execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas |
2073 | OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE |
2074 | @@ -31,6 +32,7 @@ |
2075 | DEPENDS ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.sound.gschema.xml |
2076 | COMMAND mkdir -p ${SCHEMA_DIR} |
2077 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/data/*gschema.xml ${SCHEMA_DIR} |
2078 | + COMMAND cp -f /usr/share/glib-2.0/schemas/com.ubuntu.sound.gschema.xml ${SCHEMA_DIR} |
2079 | COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${SCHEMA_DIR}) |
2080 | |
2081 | ########################### |
2082 | @@ -41,74 +43,74 @@ |
2083 | set(VALA_MOCKS_SYMBOLS_PATH "${CMAKE_CURRENT_BINARY_DIR}/vala-mocks.def") |
2084 | |
2085 | vala_init(vala-mocks |
2086 | - DEPENDS |
2087 | - indicator-sound-service-lib |
2088 | - PACKAGES |
2089 | - config |
2090 | - gio-2.0 |
2091 | - gio-unix-2.0 |
2092 | - libxml-2.0 |
2093 | - libpulse |
2094 | - libpulse-mainloop-glib |
2095 | - libnotify |
2096 | - accounts-service |
2097 | - indicator-sound-service |
2098 | - OPTIONS |
2099 | - --ccode |
2100 | - --thread |
2101 | - --vapidir=${CMAKE_BINARY_DIR}/src/ |
2102 | - --vapidir=${CMAKE_SOURCE_DIR}/vapi/ |
2103 | - --vapidir=. |
2104 | -) |
2105 | - |
2106 | -vala_add(vala-mocks |
2107 | - media-player-mock.vala |
2108 | -) |
2109 | - |
2110 | -vala_add(vala-mocks |
2111 | - media-player-list-mock.vala |
2112 | -) |
2113 | - |
2114 | -vala_add(vala-mocks |
2115 | - volume-control-mock.vala |
2116 | + DEPENDS |
2117 | + indicator-sound-service-lib |
2118 | + PACKAGES |
2119 | + config |
2120 | + gio-2.0 |
2121 | + gio-unix-2.0 |
2122 | + libxml-2.0 |
2123 | + libpulse |
2124 | + libpulse-mainloop-glib |
2125 | + libnotify |
2126 | + accounts-service |
2127 | + indicator-sound-service |
2128 | + OPTIONS |
2129 | + --ccode |
2130 | + --thread |
2131 | + --vapidir=${CMAKE_BINARY_DIR}/src/ |
2132 | + --vapidir=${CMAKE_SOURCE_DIR}/vapi/ |
2133 | + --vapidir=. |
2134 | +) |
2135 | + |
2136 | +vala_add(vala-mocks |
2137 | + media-player-mock.vala |
2138 | +) |
2139 | + |
2140 | +vala_add(vala-mocks |
2141 | + media-player-list-mock.vala |
2142 | +) |
2143 | + |
2144 | +vala_add(vala-mocks |
2145 | + volume-control-mock.vala |
2146 | ) |
2147 | |
2148 | vala_finish(vala-mocks |
2149 | - SOURCES |
2150 | - vala_mocks_VALA_SOURCES |
2151 | - OUTPUTS |
2152 | - vala_mocks_VALA_C |
2153 | - GENERATE_HEADER |
2154 | - ${VALA_MOCKS_HEADER_PATH} |
2155 | - GENERATE_SYMBOLS |
2156 | - ${VALA_MOCKS_SYMBOLS_PATH} |
2157 | + SOURCES |
2158 | + vala_mocks_VALA_SOURCES |
2159 | + OUTPUTS |
2160 | + vala_mocks_VALA_C |
2161 | + GENERATE_HEADER |
2162 | + ${VALA_MOCKS_HEADER_PATH} |
2163 | + GENERATE_SYMBOLS |
2164 | + ${VALA_MOCKS_SYMBOLS_PATH} |
2165 | ) |
2166 | |
2167 | set_source_files_properties( |
2168 | - ${vala_mocks_VALA_SOURCES} |
2169 | - PROPERTIES |
2170 | - HEADER_FILE_ONLY TRUE |
2171 | + ${vala_mocks_VALA_SOURCES} |
2172 | + PROPERTIES |
2173 | + HEADER_FILE_ONLY TRUE |
2174 | ) |
2175 | |
2176 | set( |
2177 | - VALA_MOCKS_SOURCES |
2178 | - ${vala_mocks_VALA_SOURCES} |
2179 | - ${vala_mocks_VALA_C} |
2180 | - ${VALA_MOCKS_SYMBOLS_PATH} |
2181 | + VALA_MOCKS_SOURCES |
2182 | + ${vala_mocks_VALA_SOURCES} |
2183 | + ${vala_mocks_VALA_C} |
2184 | + ${VALA_MOCKS_SYMBOLS_PATH} |
2185 | ) |
2186 | |
2187 | add_definitions( |
2188 | - -Wno-unused-but-set-variable |
2189 | + -Wno-unused-but-set-variable |
2190 | ) |
2191 | |
2192 | add_library( |
2193 | - vala-mocks-lib STATIC |
2194 | - ${VALA_MOCKS_SOURCES} |
2195 | + vala-mocks-lib STATIC |
2196 | + ${VALA_MOCKS_SOURCES} |
2197 | ) |
2198 | |
2199 | target_link_libraries( |
2200 | - vala-mocks-lib |
2201 | - indicator-sound-service-lib |
2202 | + vala-mocks-lib |
2203 | + indicator-sound-service-lib |
2204 | ) |
2205 | |
2206 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
2207 | @@ -118,9 +120,9 @@ |
2208 | ########################### |
2209 | |
2210 | add_library( |
2211 | - pulse-mock |
2212 | - SHARED |
2213 | - pa-mock.cpp |
2214 | + pulse-mock |
2215 | + SHARED |
2216 | + pa-mock.cpp |
2217 | ) |
2218 | |
2219 | target_link_libraries (pulse-mock ${PULSEAUDIO_LIBRARIES}) |
2220 | @@ -131,7 +133,7 @@ |
2221 | |
2222 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2223 | add_executable (name-watch-test name-watch-test.cc ${CMAKE_SOURCE_DIR}/src/bus-watch-namespace.c) |
2224 | -target_link_libraries (name-watch-test gtest ${SOUNDSERVICE_LIBRARIES}) |
2225 | +target_link_libraries (name-watch-test gtest-static ${SOUNDSERVICE_LIBRARIES}) |
2226 | add_test(name-watch-test name-watch-test) |
2227 | |
2228 | ########################### |
2229 | @@ -141,21 +143,21 @@ |
2230 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2231 | add_executable (accounts-service-user-test accounts-service-user.cc) |
2232 | target_link_libraries ( |
2233 | - accounts-service-user-test |
2234 | - indicator-sound-service-lib |
2235 | - vala-mocks-lib |
2236 | - gtest |
2237 | - ${SOUNDSERVICE_LIBRARIES} |
2238 | - ${TEST_LIBRARIES} |
2239 | + accounts-service-user-test |
2240 | + indicator-sound-service-lib |
2241 | + vala-mocks-lib |
2242 | + gtest-static |
2243 | + ${SOUNDSERVICE_LIBRARIES} |
2244 | + ${TEST_LIBRARIES} |
2245 | ) |
2246 | |
2247 | # Split tests to work around libaccountservice sucking |
2248 | add_test(accounts-service-user-test-basic |
2249 | - accounts-service-user-test --gtest_filter=AccountsServiceUserTest.BasicObject |
2250 | + accounts-service-user-test --gtest_filter=AccountsServiceUserTest.BasicObject |
2251 | ) |
2252 | |
2253 | add_test(accounts-service-user-test-player |
2254 | - accounts-service-user-test --gtest_filter=AccountsServiceUserTest.SetMediaPlayer |
2255 | + accounts-service-user-test --gtest_filter=AccountsServiceUserTest.SetMediaPlayer |
2256 | ) |
2257 | |
2258 | ########################### |
2259 | @@ -165,11 +167,11 @@ |
2260 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2261 | add_executable (volume-control-test volume-control-test.cc gschemas.compiled) |
2262 | target_link_libraries ( |
2263 | - volume-control-test |
2264 | - indicator-sound-service-lib |
2265 | - pulse-mock |
2266 | - gtest |
2267 | - ${TEST_LIBRARIES} |
2268 | + volume-control-test |
2269 | + indicator-sound-service-lib |
2270 | + pulse-mock |
2271 | + gtest-static |
2272 | + ${TEST_LIBRARIES} |
2273 | ) |
2274 | |
2275 | add_test(volume-control-test volume-control-test) |
2276 | @@ -181,12 +183,12 @@ |
2277 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2278 | add_executable (sound-menu-test sound-menu.cc) |
2279 | target_link_libraries ( |
2280 | - sound-menu-test |
2281 | - indicator-sound-service-lib |
2282 | - vala-mocks-lib |
2283 | - gtest |
2284 | - ${SOUNDSERVICE_LIBRARIES} |
2285 | - ${TEST_LIBRARIES} |
2286 | + sound-menu-test |
2287 | + indicator-sound-service-lib |
2288 | + vala-mocks-lib |
2289 | + gtest-static |
2290 | + ${SOUNDSERVICE_LIBRARIES} |
2291 | + ${TEST_LIBRARIES} |
2292 | ) |
2293 | |
2294 | add_test(sound-menu-test sound-menu-test) |
2295 | @@ -198,13 +200,13 @@ |
2296 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2297 | add_executable (notifications-test notifications-test.cc) |
2298 | target_link_libraries ( |
2299 | - notifications-test |
2300 | - indicator-sound-service-lib |
2301 | - vala-mocks-lib |
2302 | - pulse-mock |
2303 | - gtest |
2304 | - ${SOUNDSERVICE_LIBRARIES} |
2305 | - ${TEST_LIBRARIES} |
2306 | + notifications-test |
2307 | + indicator-sound-service-lib |
2308 | + vala-mocks-lib |
2309 | + pulse-mock |
2310 | + gtest-static |
2311 | + ${SOUNDSERVICE_LIBRARIES} |
2312 | + ${TEST_LIBRARIES} |
2313 | ) |
2314 | |
2315 | add_test(notifications-test notifications-test) |
2316 | @@ -216,23 +218,23 @@ |
2317 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2318 | add_executable (media-player-user-test media-player-user.cc) |
2319 | target_link_libraries ( |
2320 | - media-player-user-test |
2321 | - indicator-sound-service-lib |
2322 | - vala-mocks-lib |
2323 | - gtest |
2324 | - ${SOUNDSERVICE_LIBRARIES} |
2325 | - ${TEST_LIBRARIES} |
2326 | + media-player-user-test |
2327 | + indicator-sound-service-lib |
2328 | + vala-mocks-lib |
2329 | + gtest-static |
2330 | + ${SOUNDSERVICE_LIBRARIES} |
2331 | + ${TEST_LIBRARIES} |
2332 | ) |
2333 | |
2334 | # Split tests to work around libaccountservice sucking |
2335 | add_test(media-player-user-test-basic |
2336 | - media-player-user-test --gtest_filter=MediaPlayerUserTest.BasicObject |
2337 | + media-player-user-test --gtest_filter=MediaPlayerUserTest.BasicObject |
2338 | ) |
2339 | add_test(media-player-user-test-dataset |
2340 | - media-player-user-test --gtest_filter=MediaPlayerUserTest.DataSet |
2341 | + media-player-user-test --gtest_filter=MediaPlayerUserTest.DataSet |
2342 | ) |
2343 | add_test(media-player-user-test-timeout |
2344 | - media-player-user-test --gtest_filter=MediaPlayerUserTest.TimeoutTest |
2345 | + media-player-user-test --gtest_filter=MediaPlayerUserTest.TimeoutTest |
2346 | ) |
2347 | |
2348 | ########################### |
2349 | @@ -242,20 +244,20 @@ |
2350 | include_directories(${CMAKE_SOURCE_DIR}/src) |
2351 | add_executable (greeter-list-test greeter-list.cc) |
2352 | target_link_libraries ( |
2353 | - greeter-list-test |
2354 | - indicator-sound-service-lib |
2355 | - vala-mocks-lib |
2356 | - gtest |
2357 | - ${SOUNDSERVICE_LIBRARIES} |
2358 | - ${TEST_LIBRARIES} |
2359 | + greeter-list-test |
2360 | + indicator-sound-service-lib |
2361 | + vala-mocks-lib |
2362 | + gtest-static |
2363 | + ${SOUNDSERVICE_LIBRARIES} |
2364 | + ${TEST_LIBRARIES} |
2365 | ) |
2366 | |
2367 | # Split tests to work around libaccountservice sucking |
2368 | add_test(greeter-list-test-basic |
2369 | - greeter-list-test --gtest_filter=GreeterListTest.BasicObject |
2370 | + greeter-list-test --gtest_filter=GreeterListTest.BasicObject |
2371 | ) |
2372 | add_test(greeter-list-test-iterator |
2373 | - greeter-list-test --gtest_filter=GreeterListTest.BasicIterator |
2374 | + greeter-list-test --gtest_filter=GreeterListTest.BasicIterator |
2375 | ) |
2376 | |
2377 | ########################### |
2378 | @@ -263,18 +265,22 @@ |
2379 | ########################### |
2380 | |
2381 | add_definitions( |
2382 | - -DINDICATOR_SOUND_SERVICE_BINARY="${CMAKE_BINARY_DIR}/src/indicator-sound-service" |
2383 | - -DPA_MOCK_LIB="${CMAKE_CURRENT_BINARY_DIR}/libpulse-mock.so" |
2384 | + -DINDICATOR_SOUND_SERVICE_BINARY="${CMAKE_BINARY_DIR}/src/indicator-sound-service" |
2385 | + -DPA_MOCK_LIB="${CMAKE_CURRENT_BINARY_DIR}/libpulse-mock.so" |
2386 | ) |
2387 | add_executable (indicator-test indicator-test.cc gschemas.compiled) |
2388 | target_link_libraries ( |
2389 | - indicator-test |
2390 | - gtest |
2391 | - ${SOUNDSERVICE_LIBRARIES} |
2392 | - ${TEST_LIBRARIES} |
2393 | + indicator-test |
2394 | + gtest-static |
2395 | + ${SOUNDSERVICE_LIBRARIES} |
2396 | + ${TEST_LIBRARIES} |
2397 | ) |
2398 | |
2399 | # Split tests to work around libaccountservice sucking |
2400 | add_test(indcator-test |
2401 | - indicator-test |
2402 | + indicator-test |
2403 | ) |
2404 | + |
2405 | +add_subdirectory(integration) |
2406 | +add_subdirectory(dbus-types) |
2407 | +add_subdirectory(service-mocks) |
2408 | \ No newline at end of file |
2409 | |
2410 | === added directory 'tests/dbus-types' |
2411 | === added file 'tests/dbus-types/CMakeLists.txt' |
2412 | --- tests/dbus-types/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
2413 | +++ tests/dbus-types/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
2414 | @@ -0,0 +1,48 @@ |
2415 | +set(CMAKE_AUTOMOC ON) |
2416 | +set(CMAKE_INCLUDE_CURRENT_DIR ON) |
2417 | + |
2418 | +find_package(Qt5DBus REQUIRED) |
2419 | +include_directories(${Qt5DBus_INCLUDE_DIRS}) |
2420 | + |
2421 | +add_definitions(-DQT_NO_KEYWORDS=1) |
2422 | + |
2423 | +set(dbusinterface_streamrestore_xml "org.PulseAudio.Ext.StreamRestore1.xml") |
2424 | +set_source_files_properties(${dbusinterface_streamrestore_xml} PROPERTIES |
2425 | + CLASSNAME StreamRestoreInterface) |
2426 | + |
2427 | +set(dbusinterface_accounts_xml "org.freedesktop.Accounts.xml") |
2428 | +set_source_files_properties(${dbusinterface_accounts_xml} PROPERTIES |
2429 | + CLASSNAME AccountsInterface) |
2430 | + |
2431 | +set(dbusinterface_accountssound_xml "com.ubuntu.AccountsService.Sound.xml") |
2432 | +set_source_files_properties(${dbusinterface_accountssound_xml} PROPERTIES |
2433 | + CLASSNAME AccountsSoundInterface) |
2434 | + |
2435 | +set(dbusinterface_properties_xml "org.freedesktop.DBus.Properties.xml") |
2436 | +set_source_files_properties(${dbusinterface_properties_xml} PROPERTIES |
2437 | + CLASSNAME DBusPropertiesInterface |
2438 | + NO_NAMESPACE YES |
2439 | + INCLUDE "dbus-types.h") |
2440 | + |
2441 | +set(dbusinterface_actions_xml "org.gtk.Actions.xml") |
2442 | +set_source_files_properties(${dbusinterface_actions_xml} PROPERTIES |
2443 | + CLASSNAME MenusInterface) |
2444 | + |
2445 | +qt5_add_dbus_interface(interface_files ${dbusinterface_streamrestore_xml} stream_restore_interface) |
2446 | +qt5_add_dbus_interface(interface_files ${dbusinterface_properties_xml} dbus_properties_interface) |
2447 | +qt5_add_dbus_interface(interface_files ${dbusinterface_accounts_xml} dbus_accounts_interface) |
2448 | +qt5_add_dbus_interface(interface_files ${dbusinterface_accountssound_xml} dbus_accountssound_interface) |
2449 | +qt5_add_dbus_interface(interface_files ${dbusinterface_actions_xml} dbus_menus_interface) |
2450 | + |
2451 | +add_library( |
2452 | + sound-indicator-dbus-interfaces |
2453 | + STATIC |
2454 | + ${interface_files} |
2455 | + pulseaudio-volume.cpp |
2456 | +) |
2457 | + |
2458 | +qt5_use_modules( |
2459 | + sound-indicator-dbus-interfaces |
2460 | + Core |
2461 | + DBus |
2462 | +) |
2463 | |
2464 | === added file 'tests/dbus-types/com.ubuntu.AccountsService.Sound.xml' |
2465 | --- tests/dbus-types/com.ubuntu.AccountsService.Sound.xml 1970-01-01 00:00:00 +0000 |
2466 | +++ tests/dbus-types/com.ubuntu.AccountsService.Sound.xml 2015-10-01 13:45:49 +0000 |
2467 | @@ -0,0 +1,9 @@ |
2468 | +<node> |
2469 | + <interface name="com.ubuntu.AccountsService.Sound"> |
2470 | + <method name="Set"> |
2471 | + <arg direction="in" type="s" name="interface" /> |
2472 | + <arg direction="in" type="s" name="property" /> |
2473 | + <arg direction="out" type="o" name="path" /> |
2474 | + </method> |
2475 | + </interface> |
2476 | +</node> |
2477 | |
2478 | === added file 'tests/dbus-types/dbus-types.h' |
2479 | --- tests/dbus-types/dbus-types.h 1970-01-01 00:00:00 +0000 |
2480 | +++ tests/dbus-types/dbus-types.h 2015-10-01 13:45:49 +0000 |
2481 | @@ -0,0 +1,44 @@ |
2482 | +/* |
2483 | + * Copyright (C) 2015 Canonical, Ltd. |
2484 | + * |
2485 | + * This program is free software: you can redistribute it and/or modify it |
2486 | + * under the terms of the GNU General Public License version 3, as published |
2487 | + * by the Free Software Foundation. |
2488 | + * |
2489 | + * This program is distributed in the hope that it will be useful, but |
2490 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2491 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2492 | + * PURPOSE. See the GNU General Public License for more details. |
2493 | + * |
2494 | + * You should have received a copy of the GNU General Public License along |
2495 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2496 | + * |
2497 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
2498 | + */ |
2499 | +#pragma once |
2500 | + |
2501 | +#include <QDBusMetaType> |
2502 | +#include "pulseaudio-volume.h" |
2503 | + |
2504 | +namespace DBusTypes |
2505 | +{ |
2506 | + inline void registerMetaTypes() |
2507 | + { |
2508 | + PulseaudioVolume::registerMetaType(); |
2509 | + PulseaudioVolumeArray::registerMetaType(); |
2510 | + } |
2511 | + |
2512 | + static constexpr char const* DBUS_NAME = "com.canonical.indicator.sound"; |
2513 | + |
2514 | + static constexpr char const* DBUS_PULSE = "org.PulseAudio1"; |
2515 | + |
2516 | + static constexpr char const* ACCOUNTS_SERVICE = "org.freedesktop.Accounts"; |
2517 | + |
2518 | + static constexpr char const* STREAM_RESTORE_NAME = "org.PulseAudio.Ext.StreamRestore1"; |
2519 | + |
2520 | + static constexpr char const* STREAM_RESTORE_PATH = "/org/pulseaudio/stream_restore1"; |
2521 | + |
2522 | + static constexpr char const* STREAM_RESTORE_ENTRY_NAME = "org.PulseAudio.Ext.StreamRestore1.RestoreEntry"; |
2523 | + |
2524 | +} // namespace DBusTypes |
2525 | + |
2526 | |
2527 | === added file 'tests/dbus-types/org.PulseAudio.Ext.StreamRestore1.xml' |
2528 | --- tests/dbus-types/org.PulseAudio.Ext.StreamRestore1.xml 1970-01-01 00:00:00 +0000 |
2529 | +++ tests/dbus-types/org.PulseAudio.Ext.StreamRestore1.xml 2015-10-01 13:45:49 +0000 |
2530 | @@ -0,0 +1,7 @@ |
2531 | +<node> |
2532 | + <interface name="org.PulseAudio.Ext.StreamRestore1"> |
2533 | + <method name="GetEntryByName"> |
2534 | + <arg direction="in" type="s" name="entry" /> |
2535 | + <arg direction="out" type="o" name="value" /> |
2536 | + </interface> |
2537 | +</node> |
2538 | |
2539 | === added file 'tests/dbus-types/org.freedesktop.Accounts.xml' |
2540 | --- tests/dbus-types/org.freedesktop.Accounts.xml 1970-01-01 00:00:00 +0000 |
2541 | +++ tests/dbus-types/org.freedesktop.Accounts.xml 2015-10-01 13:45:49 +0000 |
2542 | @@ -0,0 +1,8 @@ |
2543 | +<node> |
2544 | + <interface name="org.freedesktop.Accounts"> |
2545 | + <method name="FindUserByName"> |
2546 | + <arg direction="in" type="s" name="user" /> |
2547 | + <arg direction="out" type="o" name="path" /> |
2548 | + </method> |
2549 | + </interface> |
2550 | +</node> |
2551 | |
2552 | === added file 'tests/dbus-types/org.freedesktop.DBus.Properties.xml' |
2553 | --- tests/dbus-types/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000 |
2554 | +++ tests/dbus-types/org.freedesktop.DBus.Properties.xml 2015-10-01 13:45:49 +0000 |
2555 | @@ -0,0 +1,22 @@ |
2556 | +<node> |
2557 | + <interface name="org.freedesktop.DBus.Properties"> |
2558 | + <method name="Set"> |
2559 | + <arg direction="in" type="s" name="entry" /> |
2560 | + <arg direction="in" type="s" name="property" /> |
2561 | + <arg direction="in" type="v" name="value" /> |
2562 | + </method> |
2563 | + |
2564 | + <method name="Get"> |
2565 | + <arg direction="in" type="s" name="entry" /> |
2566 | + <arg direction="in" type="s" name="property" /> |
2567 | + <arg direction="out" type="v" name="value" /> |
2568 | + </method> |
2569 | + |
2570 | + <signal name="PropertiesChanged"> |
2571 | + <arg type="s" name="interface_name"/> |
2572 | + <arg type="a{sv}" name="changed_properties"/> |
2573 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
2574 | + <arg type="as" name="invalidated_properties"/> |
2575 | + </signal> |
2576 | + </interface> |
2577 | +</node> |
2578 | |
2579 | === added file 'tests/dbus-types/org.gtk.Actions.xml' |
2580 | --- tests/dbus-types/org.gtk.Actions.xml 1970-01-01 00:00:00 +0000 |
2581 | +++ tests/dbus-types/org.gtk.Actions.xml 2015-10-01 13:45:49 +0000 |
2582 | @@ -0,0 +1,13 @@ |
2583 | +<node> |
2584 | + <interface name="org.gtk.Actions"> |
2585 | + <signal name="Changed"> |
2586 | + <arg name="removedActions" type="as" direction="in" /> |
2587 | + <arg name="actionsFlags" type="a{sb}" direction="in" /> |
2588 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
2589 | + <arg name="actionsChanged" type="a{sv}" direction="in" /> |
2590 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/> |
2591 | + <arg name="actionsAdded" type="a{s(bgav)}" direction="in" /> |
2592 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QVariantMap"/> |
2593 | + </signal> |
2594 | + </interface> |
2595 | +</node> |
2596 | |
2597 | === added file 'tests/dbus-types/pulseaudio-volume.cpp' |
2598 | --- tests/dbus-types/pulseaudio-volume.cpp 1970-01-01 00:00:00 +0000 |
2599 | +++ tests/dbus-types/pulseaudio-volume.cpp 2015-10-01 13:45:49 +0000 |
2600 | @@ -0,0 +1,156 @@ |
2601 | +/* |
2602 | + * Copyright (C) 2015 Canonical, Ltd. |
2603 | + * |
2604 | + * This program is free software: you can redistribute it and/or modify it |
2605 | + * under the terms of the GNU General Public License version 3, as published |
2606 | + * by the Free Software Foundation. |
2607 | + * |
2608 | + * This program is distributed in the hope that it will be useful, but |
2609 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2610 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2611 | + * PURPOSE. See the GNU General Public License for more details. |
2612 | + * |
2613 | + * You should have received a copy of the GNU General Public License along |
2614 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2615 | + * |
2616 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
2617 | + */ |
2618 | +#include "dbus-types.h" |
2619 | + |
2620 | +PulseaudioVolume::PulseaudioVolume() : |
2621 | + type_(0), |
2622 | + volume_(10) |
2623 | +{ |
2624 | +} |
2625 | + |
2626 | +PulseaudioVolume::PulseaudioVolume(unsigned int type, unsigned int volume) : |
2627 | + type_(type) |
2628 | + , volume_(volume) |
2629 | +{ |
2630 | +} |
2631 | + |
2632 | +PulseaudioVolume::PulseaudioVolume(const PulseaudioVolume &other) : |
2633 | + type_(other.type_), |
2634 | + volume_(other.volume_) |
2635 | +{ |
2636 | +} |
2637 | + |
2638 | +PulseaudioVolume& PulseaudioVolume::operator=(const PulseaudioVolume &other) |
2639 | +{ |
2640 | + type_ = other.type_; |
2641 | + volume_ = other.volume_; |
2642 | + |
2643 | + return *this; |
2644 | +} |
2645 | + |
2646 | +PulseaudioVolume::~PulseaudioVolume() |
2647 | +{ |
2648 | +} |
2649 | + |
2650 | +unsigned int PulseaudioVolume::getType() const |
2651 | +{ |
2652 | + return type_; |
2653 | +} |
2654 | + |
2655 | +unsigned int PulseaudioVolume::getVolume() const |
2656 | +{ |
2657 | + return volume_; |
2658 | +} |
2659 | + |
2660 | +void PulseaudioVolume::registerMetaType() |
2661 | +{ |
2662 | + qRegisterMetaType<PulseaudioVolume>("PulseaudioVolume"); |
2663 | + |
2664 | + qDBusRegisterMetaType<PulseaudioVolume>(); |
2665 | +} |
2666 | + |
2667 | +QDBusArgument &operator<<(QDBusArgument &argument, const PulseaudioVolume& volume) |
2668 | +{ |
2669 | + argument.beginStructure(); |
2670 | + argument << volume.type_; |
2671 | + argument << volume.volume_; |
2672 | + argument.endStructure(); |
2673 | + |
2674 | + return argument; |
2675 | +} |
2676 | + |
2677 | +const QDBusArgument &operator>>(const QDBusArgument &argument, PulseaudioVolume &volume) |
2678 | +{ |
2679 | + argument.beginStructure(); |
2680 | + argument >> volume.type_; |
2681 | + argument >> volume.volume_; |
2682 | + argument.endStructure(); |
2683 | + |
2684 | + return argument; |
2685 | +} |
2686 | + |
2687 | +PulseaudioVolumeArray::PulseaudioVolumeArray() |
2688 | +{ |
2689 | +} |
2690 | + |
2691 | +PulseaudioVolumeArray::PulseaudioVolumeArray(const PulseaudioVolumeArray &other) : |
2692 | + volume_array_(other.volume_array_) |
2693 | +{ |
2694 | +} |
2695 | + |
2696 | +PulseaudioVolumeArray& PulseaudioVolumeArray::operator=(const PulseaudioVolumeArray &other) |
2697 | +{ |
2698 | + volume_array_ = other.volume_array_; |
2699 | + |
2700 | + return *this; |
2701 | +} |
2702 | + |
2703 | +PulseaudioVolumeArray::~PulseaudioVolumeArray() |
2704 | +{ |
2705 | +} |
2706 | + |
2707 | +int PulseaudioVolumeArray::getNumItems() const |
2708 | +{ |
2709 | + return volume_array_.size(); |
2710 | +} |
2711 | + |
2712 | +PulseaudioVolume PulseaudioVolumeArray::getItem(int i) const |
2713 | +{ |
2714 | + if (i < volume_array_.size()) |
2715 | + { |
2716 | + return volume_array_[i]; |
2717 | + } |
2718 | + return PulseaudioVolume(); |
2719 | +} |
2720 | + |
2721 | +void PulseaudioVolumeArray::addItem(PulseaudioVolume const &item) |
2722 | +{ |
2723 | + volume_array_.push_back(item); |
2724 | +} |
2725 | + |
2726 | +void PulseaudioVolumeArray::registerMetaType() |
2727 | +{ |
2728 | + qRegisterMetaType<PulseaudioVolumeArray>("PulseaudioVolumeArray"); |
2729 | + |
2730 | + qDBusRegisterMetaType<PulseaudioVolumeArray>(); |
2731 | +} |
2732 | + |
2733 | +QDBusArgument &operator<<(QDBusArgument &argument, const PulseaudioVolumeArray& volume) |
2734 | +{ |
2735 | + argument.beginArray( qMetaTypeId<PulseaudioVolume>() ); |
2736 | + for (int i = 0; i < volume.volume_array_.size(); ++ i) |
2737 | + { |
2738 | + PulseaudioVolume item = volume.getItem(i); |
2739 | + argument << item; |
2740 | + } |
2741 | + argument.endArray(); |
2742 | + return argument; |
2743 | +} |
2744 | + |
2745 | +const QDBusArgument &operator>>(const QDBusArgument &argument, PulseaudioVolumeArray &volume) |
2746 | +{ |
2747 | + argument.beginArray(); |
2748 | + while ( !argument.atEnd() ) { |
2749 | + PulseaudioVolume item; |
2750 | + argument >> item; |
2751 | + volume.volume_array_.push_back(item); |
2752 | + } |
2753 | + argument.endArray(); |
2754 | + |
2755 | + return argument; |
2756 | +} |
2757 | |
2758 | === added file 'tests/dbus-types/pulseaudio-volume.h' |
2759 | --- tests/dbus-types/pulseaudio-volume.h 1970-01-01 00:00:00 +0000 |
2760 | +++ tests/dbus-types/pulseaudio-volume.h 2015-10-01 13:45:49 +0000 |
2761 | @@ -0,0 +1,69 @@ |
2762 | +/* |
2763 | + * Copyright (C) 2015 Canonical, Ltd. |
2764 | + * |
2765 | + * This program is free software: you can redistribute it and/or modify it |
2766 | + * under the terms of the GNU General Public License version 3, as published |
2767 | + * by the Free Software Foundation. |
2768 | + * |
2769 | + * This program is distributed in the hope that it will be useful, but |
2770 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2771 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2772 | + * PURPOSE. See the GNU General Public License for more details. |
2773 | + * |
2774 | + * You should have received a copy of the GNU General Public License along |
2775 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2776 | + * |
2777 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
2778 | + */ |
2779 | +#pragma once |
2780 | + |
2781 | +#include <QtDBus> |
2782 | + |
2783 | +class PulseaudioVolume |
2784 | +{ |
2785 | +public: |
2786 | + PulseaudioVolume(); |
2787 | + PulseaudioVolume(unsigned int type, unsigned int volume); |
2788 | + PulseaudioVolume(const PulseaudioVolume &other); |
2789 | + PulseaudioVolume& operator=(const PulseaudioVolume &other); |
2790 | + ~PulseaudioVolume(); |
2791 | + |
2792 | + friend QDBusArgument &operator<<(QDBusArgument &argument, PulseaudioVolume const & volume); |
2793 | + friend const QDBusArgument &operator>>(QDBusArgument const & argument, PulseaudioVolume &volume); |
2794 | + |
2795 | + unsigned int getType() const; |
2796 | + unsigned int getVolume() const; |
2797 | + |
2798 | + //register Message with the Qt type system |
2799 | + static void registerMetaType(); |
2800 | + |
2801 | +private: |
2802 | + unsigned int type_; |
2803 | + unsigned int volume_; |
2804 | +}; |
2805 | + |
2806 | +class PulseaudioVolumeArray |
2807 | +{ |
2808 | +public: |
2809 | + PulseaudioVolumeArray(); |
2810 | + PulseaudioVolumeArray(QString const &interface, QString const &property, QDBusVariant const& value); |
2811 | + PulseaudioVolumeArray(const PulseaudioVolumeArray &other); |
2812 | + PulseaudioVolumeArray& operator=(const PulseaudioVolumeArray &other); |
2813 | + ~PulseaudioVolumeArray(); |
2814 | + |
2815 | + friend QDBusArgument &operator<<(QDBusArgument &argument, PulseaudioVolumeArray const & volume); |
2816 | + friend const QDBusArgument &operator>>(QDBusArgument const & argument, PulseaudioVolumeArray &volume); |
2817 | + |
2818 | + int getNumItems() const; |
2819 | + PulseaudioVolume getItem(int i) const; |
2820 | + void addItem(PulseaudioVolume const &item); |
2821 | + |
2822 | + //register Message with the Qt type system |
2823 | + static void registerMetaType(); |
2824 | + |
2825 | +private: |
2826 | + QVector<PulseaudioVolume> volume_array_; |
2827 | +}; |
2828 | + |
2829 | +Q_DECLARE_METATYPE(PulseaudioVolume) |
2830 | +Q_DECLARE_METATYPE(PulseaudioVolumeArray) |
2831 | |
2832 | === added directory 'tests/integration' |
2833 | === added file 'tests/integration/CMakeLists.txt' |
2834 | --- tests/integration/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
2835 | +++ tests/integration/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
2836 | @@ -0,0 +1,132 @@ |
2837 | +set(CMAKE_AUTOMOC ON) |
2838 | +set(CMAKE_INCLUDE_CURRENT_DIR ON) |
2839 | + |
2840 | +include(FindGMock) |
2841 | + |
2842 | +#pkg_check_modules(GMENUHARNESS REQUIRED libgmenuharness REQUIRED) |
2843 | +#include_directories(${GMENUHARNESS_INCLUDE_DIRS}) |
2844 | +include_directories("${CMAKE_SOURCE_DIR}/include") |
2845 | + |
2846 | +pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1 REQUIRED) |
2847 | +include_directories(${QTDBUSTEST_INCLUDE_DIRS}) |
2848 | + |
2849 | +pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1 REQUIRED) |
2850 | +include_directories(${QTDBUSMOCK_INCLUDE_DIRS}) |
2851 | + |
2852 | +find_package(Qt5Test REQUIRED) |
2853 | +include_directories(${Qt5Test_INCLUDE_DIRS}) |
2854 | + |
2855 | +find_package(Qt5DBus REQUIRED) |
2856 | +include_directories(${Qt5DBus_INCLUDE_DIRS}) |
2857 | + |
2858 | +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) |
2859 | +include_directories(${GMOCK_INCLUDE_DIRS}) |
2860 | +include_directories(${GTEST_INCLUDE_DIRS}) |
2861 | + |
2862 | +include_directories("${CMAKE_SOURCE_DIR}/tests/dbus-types") |
2863 | +include_directories("${CMAKE_BINARY_DIR}/tests/dbus-types") |
2864 | + |
2865 | +add_definitions(-DSOUND_SERVICE_BIN="${CMAKE_BINARY_DIR}/src/indicator-sound-service" |
2866 | + -DSTREAM_RESTORE_TABLE="${CMAKE_SOURCE_DIR}/tests/integration/touch-stream-restore.table" |
2867 | + -DVOLUME_SET_BIN="${CMAKE_BINARY_DIR}/tests/integration/set-volume" |
2868 | + -DACCOUNTS_SERVICE_BIN="${CMAKE_BINARY_DIR}/tests/service-mocks/accounts-mock/accounts-service-sound" |
2869 | + -DMEDIA_PLAYER_MPRIS_BIN="${CMAKE_BINARY_DIR}/tests/service-mocks/media-player-mpris-mock/media-player-mpris-mock" |
2870 | + -DMEDIA_PLAYER_MPRIS_UPDATE_BIN="${CMAKE_BINARY_DIR}/tests/service-mocks/media-player-mpris-mock/media-player-mpris-mock-update" |
2871 | + -DTEST_SOUND="${CMAKE_SOURCE_DIR}/tests/integration/test-sound.wav" |
2872 | + -DQT_NO_KEYWORDS=1 |
2873 | + -DXDG_DATA_DIRS="${XDG_DATA_DIRS}" |
2874 | +) |
2875 | + |
2876 | +set(GLIB_REQUIRED_VERSION 2.26) |
2877 | + |
2878 | +pkg_check_modules( |
2879 | + GLIB REQUIRED |
2880 | + glib-2.0>=${GLIB_REQUIRED_VERSION} |
2881 | + gio-2.0>=${GLIB_REQUIRED_VERSION} |
2882 | +) |
2883 | +include_directories(${GLIB_INCLUDE_DIRS}) |
2884 | + |
2885 | +set( |
2886 | + INTEGRATION_TESTS_SRC |
2887 | + indicator-sound-test-base.cpp |
2888 | + test-indicator.cpp |
2889 | + utils/dbus-pulse-volume.cpp |
2890 | + main.cpp |
2891 | +) |
2892 | + |
2893 | +add_executable( |
2894 | + integration-tests |
2895 | + ${INTEGRATION_TESTS_SRC} |
2896 | +) |
2897 | + |
2898 | +qt5_use_modules( |
2899 | + integration-tests |
2900 | + Core |
2901 | + DBus |
2902 | + Test |
2903 | +) |
2904 | + |
2905 | +target_link_libraries( |
2906 | + integration-tests |
2907 | + sound-indicator-dbus-interfaces |
2908 | + ${QTDBUSMOCK_LDFLAGS} |
2909 | + ${QTDBUSTEST_LDFLAGS} |
2910 | + ${GTEST_LIBRARIES} |
2911 | + ${GMOCK_LIBRARIES} |
2912 | +# ${GMENUHARNESS_LDFLAGS} |
2913 | + ${GLIB_LDFLAGS} |
2914 | + gmenuharness-shared |
2915 | +) |
2916 | + |
2917 | +add_test( |
2918 | + integration-tests |
2919 | + integration-tests |
2920 | +) |
2921 | + |
2922 | +set( |
2923 | + SET-VOLUME-SRC |
2924 | + utils/dbus-pulse-volume.cpp |
2925 | + utils/set-volume.cpp |
2926 | +) |
2927 | + |
2928 | +set( |
2929 | + GET-VOLUME-SRC |
2930 | + utils/dbus-pulse-volume.cpp |
2931 | + utils/get-volume.cpp |
2932 | +) |
2933 | + |
2934 | +add_executable( |
2935 | + set-volume |
2936 | + ${SET-VOLUME-SRC} |
2937 | +) |
2938 | + |
2939 | +add_executable( |
2940 | + get-volume |
2941 | + ${GET-VOLUME-SRC} |
2942 | +) |
2943 | + |
2944 | +qt5_use_modules( |
2945 | + set-volume |
2946 | + Core |
2947 | + DBus |
2948 | + Test |
2949 | +) |
2950 | + |
2951 | +qt5_use_modules( |
2952 | + get-volume |
2953 | + Core |
2954 | + DBus |
2955 | + Test |
2956 | +) |
2957 | + |
2958 | +target_link_libraries( |
2959 | + get-volume |
2960 | + sound-indicator-dbus-interfaces |
2961 | +) |
2962 | + |
2963 | +target_link_libraries( |
2964 | + set-volume |
2965 | + sound-indicator-dbus-interfaces |
2966 | +) |
2967 | + |
2968 | +#add_subdirectory(utils) |
2969 | \ No newline at end of file |
2970 | |
2971 | === added file 'tests/integration/Copy of test-sound.wav' |
2972 | Binary files tests/integration/Copy of test-sound.wav 1970-01-01 00:00:00 +0000 and tests/integration/Copy of test-sound.wav 2015-10-01 13:45:49 +0000 differ |
2973 | === added file 'tests/integration/indicator-sound-test-base.cpp' |
2974 | --- tests/integration/indicator-sound-test-base.cpp 1970-01-01 00:00:00 +0000 |
2975 | +++ tests/integration/indicator-sound-test-base.cpp 2015-10-01 13:45:49 +0000 |
2976 | @@ -0,0 +1,411 @@ |
2977 | +/* |
2978 | + * Copyright (C) 2015 Canonical, Ltd. |
2979 | + * |
2980 | + * This program is free software: you can redistribute it and/or modify it |
2981 | + * under the terms of the GNU General Public License version 3, as published |
2982 | + * by the Free Software Foundation. |
2983 | + * |
2984 | + * This program is distributed in the hope that it will be useful, but |
2985 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2986 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2987 | + * PURPOSE. See the GNU General Public License for more details. |
2988 | + * |
2989 | + * You should have received a copy of the GNU General Public License along |
2990 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2991 | + * |
2992 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
2993 | + */ |
2994 | + |
2995 | +#include "indicator-sound-test-base.h" |
2996 | + |
2997 | +#include "dbus_menus_interface.h" |
2998 | +#include "dbus_properties_interface.h" |
2999 | +#include "dbus_accounts_interface.h" |
3000 | +#include "dbus_accountssound_interface.h" |
3001 | +#include "dbus-types.h" |
3002 | + |
3003 | +#include <gio/gio.h> |
3004 | + |
3005 | +#include <QSignalSpy> |
3006 | +#include "utils/dbus-pulse-volume.h" |
3007 | + |
3008 | +using namespace QtDBusTest; |
3009 | +using namespace QtDBusMock; |
3010 | +using namespace std; |
3011 | +using namespace testing; |
3012 | +namespace mh = unity::gmenuharness; |
3013 | + |
3014 | +IndicatorSoundTestBase::IndicatorSoundTestBase() : |
3015 | + dbusMock(dbusTestRunner) |
3016 | +{ |
3017 | +} |
3018 | + |
3019 | +IndicatorSoundTestBase::~IndicatorSoundTestBase() |
3020 | +{ |
3021 | + |
3022 | +} |
3023 | + |
3024 | +bool IndicatorSoundTestBase::setStreamRestoreVolume(QString const &role, double volume) |
3025 | +{ |
3026 | + QProcess setVolume; |
3027 | + setVolume.start(VOLUME_SET_BIN, QStringList() |
3028 | + << role |
3029 | + << QString("%1").arg(volume)); |
3030 | + if (!setVolume.waitForStarted()) |
3031 | + return false; |
3032 | + |
3033 | + if (!setVolume.waitForFinished()) |
3034 | + return false; |
3035 | + |
3036 | + return setVolume.exitCode() == 0; |
3037 | +} |
3038 | + |
3039 | +bool IndicatorSoundTestBase::setSinkVolume(double volume) |
3040 | +{ |
3041 | + QString volume_percentage = QString("%1\%").arg(volume*100); |
3042 | + QProcess setVolume; |
3043 | + setVolume.start("pactl", QStringList() |
3044 | + << "-s" |
3045 | + << "127.0.0.1" |
3046 | + << "set-sink-volume" |
3047 | + << "0" |
3048 | + << volume_percentage); |
3049 | + if (!setVolume.waitForStarted()) |
3050 | + return false; |
3051 | + |
3052 | + if (!setVolume.waitForFinished()) |
3053 | + return false; |
3054 | + |
3055 | + return setVolume.exitCode() == 0; |
3056 | +} |
3057 | + |
3058 | +bool IndicatorSoundTestBase::clearGSettingsPlayers() |
3059 | +{ |
3060 | + QProcess clearPlayers; |
3061 | + |
3062 | + clearPlayers.start("gsettings", QStringList() |
3063 | + << "set" |
3064 | + << "com.canonical.indicator.sound" |
3065 | + << "interested-media-players" |
3066 | + << "[]"); |
3067 | + if (!clearPlayers.waitForStarted()) |
3068 | + return false; |
3069 | + |
3070 | + if (!clearPlayers.waitForFinished()) |
3071 | + return false; |
3072 | + |
3073 | + return clearPlayers.exitCode() == 0; |
3074 | +} |
3075 | + |
3076 | +bool IndicatorSoundTestBase::startTestMprisPlayer(QString const& playerName) |
3077 | +{ |
3078 | + testPlayer1.terminate(); |
3079 | + testPlayer1.start(MEDIA_PLAYER_MPRIS_BIN, QStringList() |
3080 | + << playerName); |
3081 | + if (!testPlayer1.waitForStarted()) |
3082 | + return false; |
3083 | + |
3084 | + |
3085 | + return true; |
3086 | +} |
3087 | + |
3088 | +bool IndicatorSoundTestBase::setTestMprisPlayerProperty(QString const &testPlayer, QString const &property, bool value) |
3089 | +{ |
3090 | + QProcess setProperty; |
3091 | + QString strValue; |
3092 | + strValue = value ? "true" : "false"; |
3093 | + |
3094 | + setProperty.start(MEDIA_PLAYER_MPRIS_UPDATE_BIN, QStringList() |
3095 | + << testPlayer |
3096 | + << property |
3097 | + << strValue); |
3098 | + if (!setProperty.waitForStarted()) |
3099 | + return false; |
3100 | + |
3101 | + if (!setProperty.waitForFinished()) |
3102 | + return false; |
3103 | + |
3104 | + return setProperty.exitCode() == 0; |
3105 | +} |
3106 | + |
3107 | +bool IndicatorSoundTestBase::startTestSound(QString const &role) |
3108 | +{ |
3109 | + testSoundProcess.terminate(); |
3110 | + testSoundProcess.start("paplay", QStringList() |
3111 | + << "-s" |
3112 | + << "127.0.0.1" |
3113 | + << TEST_SOUND |
3114 | + << QString("--property=media.role=%1").arg(role)); |
3115 | + |
3116 | + if (!testSoundProcess.waitForStarted()) |
3117 | + return false; |
3118 | + |
3119 | + return true; |
3120 | +} |
3121 | + |
3122 | +void IndicatorSoundTestBase::stopTestSound() |
3123 | +{ |
3124 | + testSoundProcess.terminate(); |
3125 | +} |
3126 | + |
3127 | +void IndicatorSoundTestBase::startPulseDesktop() |
3128 | +{ |
3129 | + try |
3130 | + { |
3131 | + pulseaudio.reset( |
3132 | + new QProcessDBusService(DBusTypes::DBUS_PULSE, |
3133 | + QDBusConnection::SessionBus, |
3134 | + "pulseaudio", |
3135 | + QStringList() << "--start" |
3136 | + << "-vvvv" |
3137 | + << "--disable-shm=true" |
3138 | + << "--daemonize=false" |
3139 | + << "--use-pid-file=false" |
3140 | + << "--system=false" |
3141 | + << "--exit-idle-time=-1" |
3142 | + << "-n" |
3143 | + << "--load=module-null-sink" |
3144 | + << "--log-target=file:/tmp/pulse-daemon.log" |
3145 | + << "--load=module-dbus-protocol" |
3146 | + << "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1" |
3147 | + )); |
3148 | + pulseaudio->start(dbusTestRunner.sessionConnection()); |
3149 | + } |
3150 | + catch (exception const& e) |
3151 | + { |
3152 | + cout << "pulseaudio(): " << e.what() << endl; |
3153 | + throw; |
3154 | + } |
3155 | +} |
3156 | + |
3157 | +void IndicatorSoundTestBase::startPulsePhone() |
3158 | +{ |
3159 | + try |
3160 | + { |
3161 | + pulseaudio.reset( |
3162 | + new QProcessDBusService(DBusTypes::DBUS_PULSE, |
3163 | + QDBusConnection::SessionBus, |
3164 | + "pulseaudio", |
3165 | + QStringList() << "--start" |
3166 | + << "-vvvv" |
3167 | + << "--disable-shm=true" |
3168 | + << "--daemonize=false" |
3169 | + << "--use-pid-file=false" |
3170 | + << "--system=false" |
3171 | + << "--exit-idle-time=-1" |
3172 | + << "-n" |
3173 | + << "--load=module-null-sink" |
3174 | + << "--log-target=file:/tmp/pulse-daemon.log" |
3175 | + << QString("--load=module-stream-restore restore_device=false restore_muted=false fallback_table=%1").arg(STREAM_RESTORE_TABLE) |
3176 | + << "--load=module-dbus-protocol" |
3177 | + << "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1" |
3178 | + )); |
3179 | + pulseaudio->start(dbusTestRunner.sessionConnection()); |
3180 | + } |
3181 | + catch (exception const& e) |
3182 | + { |
3183 | + cout << "pulseaudio(): " << e.what() << endl; |
3184 | + throw; |
3185 | + } |
3186 | +} |
3187 | + |
3188 | +void IndicatorSoundTestBase::startAccountsService() |
3189 | +{ |
3190 | + try |
3191 | + { |
3192 | + accountsService.reset( |
3193 | + new QProcessDBusService(DBusTypes::ACCOUNTS_SERVICE, |
3194 | + QDBusConnection::SystemBus, |
3195 | + ACCOUNTS_SERVICE_BIN, |
3196 | + QStringList())); |
3197 | + accountsService->start(dbusTestRunner.systemConnection()); |
3198 | + |
3199 | + initializeAccountsInterface(); |
3200 | + } |
3201 | + catch (exception const& e) |
3202 | + { |
3203 | + cout << "accountsService(): " << e.what() << endl; |
3204 | + throw; |
3205 | + } |
3206 | +} |
3207 | + |
3208 | +void IndicatorSoundTestBase::startIndicator() |
3209 | +{ |
3210 | + try |
3211 | + { |
3212 | + setenv("PULSE_SERVER", "127.0.0.1", true); |
3213 | + indicator.reset( |
3214 | + new QProcessDBusService(DBusTypes::DBUS_NAME, |
3215 | + QDBusConnection::SessionBus, |
3216 | + SOUND_SERVICE_BIN, |
3217 | + QStringList())); |
3218 | + indicator->start(dbusTestRunner.sessionConnection()); |
3219 | + } |
3220 | + catch (exception const& e) |
3221 | + { |
3222 | + cout << "startIndicator(): " << e.what() << endl; |
3223 | + throw; |
3224 | + } |
3225 | +} |
3226 | + |
3227 | +mh::MenuMatcher::Parameters IndicatorSoundTestBase::desktopParameters() |
3228 | +{ |
3229 | + return mh::MenuMatcher::Parameters( |
3230 | + "com.canonical.indicator.sound", |
3231 | + { { "indicator", "/com/canonical/indicator/sound" } }, |
3232 | + "/com/canonical/indicator/sound/desktop"); |
3233 | +} |
3234 | + |
3235 | +mh::MenuMatcher::Parameters IndicatorSoundTestBase::phoneParameters() |
3236 | +{ |
3237 | + return mh::MenuMatcher::Parameters( |
3238 | + "com.canonical.indicator.sound", |
3239 | + { { "indicator", "/com/canonical/indicator/sound" } }, |
3240 | + "/com/canonical/indicator/sound/phone"); |
3241 | +} |
3242 | + |
3243 | +void IndicatorSoundTestBase::SetUp() |
3244 | +{ |
3245 | + setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, true); |
3246 | + setenv("DBUS_SYSTEM_BUS_ADDRESS", dbusTestRunner.systemBus().toStdString().c_str(), true); |
3247 | +} |
3248 | + |
3249 | +void IndicatorSoundTestBase::TearDown() |
3250 | +{ |
3251 | + unsetenv("XDG_DATA_DIRS"); |
3252 | + unsetenv("PULSE_SERVER"); |
3253 | + unsetenv("DBUS_SYSTEM_BUS_ADDRESS"); |
3254 | +} |
3255 | + |
3256 | +void gvariant_deleter(GVariant* varptr) |
3257 | +{ |
3258 | + if (varptr != nullptr) |
3259 | + { |
3260 | + g_variant_unref(varptr); |
3261 | + } |
3262 | +} |
3263 | + |
3264 | +std::shared_ptr<GVariant> IndicatorSoundTestBase::volume_variant(double volume) |
3265 | +{ |
3266 | + GVariantBuilder builder; |
3267 | + |
3268 | + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
3269 | + g_variant_builder_add(&builder, |
3270 | + "{sv}", |
3271 | + "title", |
3272 | + g_variant_new_string("_Sound")); |
3273 | + |
3274 | + g_variant_builder_add(&builder, |
3275 | + "{sv}", |
3276 | + "accessible-desc", |
3277 | + g_variant_new_string("_Sound")); |
3278 | + |
3279 | + auto icon = g_themed_icon_new("icon"); |
3280 | + g_variant_builder_add(&builder, |
3281 | + "{sv}", |
3282 | + "icon", |
3283 | + g_icon_serialize(icon)); |
3284 | + |
3285 | + g_variant_builder_add(&builder, |
3286 | + "{sv}", |
3287 | + "visible", |
3288 | + g_variant_new_boolean(true)); |
3289 | + return shared_ptr<GVariant>(g_variant_builder_end(&builder), &gvariant_deleter); |
3290 | +} |
3291 | + |
3292 | +unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::volumeSlider(double volume) |
3293 | +{ |
3294 | + return mh::MenuItemMatcher().radio() |
3295 | + .label("Volume") |
3296 | + .round_doubles(0.1) |
3297 | + .int32_attribute("target", 0) |
3298 | + .double_attribute("min-value", 0.0) |
3299 | + .double_attribute("max-value", 1.0) |
3300 | + .double_attribute("step", 0.01) |
3301 | + .string_attribute("x-canonical-type", "com.canonical.unity.slider") |
3302 | + .themed_icon("max-icon", {"audio-volume-high-panel", "audio-volume-high", "audio-volume", "audio"}) |
3303 | + .themed_icon("min-icon", {"audio-volume-low-zero-panel", "audio-volume-low-zero", "audio-volume-low", "audio-volume", "audio"}) |
3304 | + .pass_through_double_attribute("action", volume); |
3305 | +} |
3306 | + |
3307 | +unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::silentModeSwitch(bool toggled) |
3308 | +{ |
3309 | + return mh::MenuItemMatcher::checkbox() |
3310 | + .label("Silent Mode") |
3311 | + .action("indicator.silent-mode") |
3312 | + .toggled(toggled); |
3313 | +} |
3314 | + |
3315 | +bool IndicatorSoundTestBase::waitMenuChange() |
3316 | +{ |
3317 | + if (signal_spy_menu_changed_) |
3318 | + { |
3319 | + return signal_spy_menu_changed_->wait(); |
3320 | + } |
3321 | + return false; |
3322 | +} |
3323 | + |
3324 | +bool IndicatorSoundTestBase::initializeMenuChangedSignal() |
3325 | +{ |
3326 | + if (!menu_interface_) |
3327 | + { |
3328 | + menu_interface_.reset(new MenusInterface("com.canonical.indicator.sound", |
3329 | + "/com/canonical/indicator/sound", |
3330 | + dbusTestRunner.sessionConnection(), 0)); |
3331 | + } |
3332 | + if (menu_interface_) |
3333 | + { |
3334 | + qDebug() << "Waiting for signal"; |
3335 | + signal_spy_menu_changed_.reset(new QSignalSpy(menu_interface_.get(), &MenusInterface::Changed)); |
3336 | + } |
3337 | + if (!menu_interface_ || !signal_spy_menu_changed_) |
3338 | + { |
3339 | + return false; |
3340 | + } |
3341 | + return true; |
3342 | +} |
3343 | + |
3344 | +bool IndicatorSoundTestBase::waitVolumeChangedInIndicator() |
3345 | +{ |
3346 | + if (signal_spy_volume_changed_) |
3347 | + { |
3348 | + return signal_spy_volume_changed_->wait(); |
3349 | + } |
3350 | + return false; |
3351 | +} |
3352 | + |
3353 | +void IndicatorSoundTestBase::initializeAccountsInterface() |
3354 | +{ |
3355 | + auto username = qgetenv("USER"); |
3356 | + if (username != "") |
3357 | + { |
3358 | + std::unique_ptr<AccountsInterface> accountsInterface(new AccountsInterface("org.freedesktop.Accounts", |
3359 | + "/org/freedesktop/Accounts", |
3360 | + dbusTestRunner.systemConnection(), 0)); |
3361 | + |
3362 | + QDBusReply<QDBusObjectPath> userResp = accountsInterface->call(QLatin1String("FindUserByName"), |
3363 | + QLatin1String(username)); |
3364 | + |
3365 | + if (!userResp.isValid()) |
3366 | + { |
3367 | + qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << userResp.error().message(); |
3368 | + } |
3369 | + |
3370 | + auto userPath = userResp.value().path(); |
3371 | + if (userPath != "") |
3372 | + { |
3373 | + std::unique_ptr<AccountsSoundInterface> soundInterface(new AccountsSoundInterface("org.freedesktop.Accounts", |
3374 | + userPath, |
3375 | + dbusTestRunner.systemConnection(), 0)); |
3376 | + |
3377 | + accounts_interface_.reset(new DBusPropertiesInterface("org.freedesktop.Accounts", |
3378 | + userPath, |
3379 | + dbusTestRunner.systemConnection(), 0)); |
3380 | + if (!accounts_interface_->isValid()) |
3381 | + { |
3382 | + qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << accounts_interface_->lastError().message(); |
3383 | + } |
3384 | + signal_spy_volume_changed_.reset(new QSignalSpy(accounts_interface_.get(),&DBusPropertiesInterface::PropertiesChanged)); |
3385 | + } |
3386 | + } |
3387 | +} |
3388 | |
3389 | === added file 'tests/integration/indicator-sound-test-base.h' |
3390 | --- tests/integration/indicator-sound-test-base.h 1970-01-01 00:00:00 +0000 |
3391 | +++ tests/integration/indicator-sound-test-base.h 2015-10-01 13:45:49 +0000 |
3392 | @@ -0,0 +1,105 @@ |
3393 | +/* |
3394 | + * Copyright (C) 2015 Canonical, Ltd. |
3395 | + * |
3396 | + * This program is free software: you can redistribute it and/or modify it |
3397 | + * under the terms of the GNU General Public License version 3, as published |
3398 | + * by the Free Software Foundation. |
3399 | + * |
3400 | + * This program is distributed in the hope that it will be useful, but |
3401 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3402 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3403 | + * PURPOSE. See the GNU General Public License for more details. |
3404 | + * |
3405 | + * You should have received a copy of the GNU General Public License along |
3406 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3407 | + * |
3408 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
3409 | + */ |
3410 | + |
3411 | +#pragma once |
3412 | + |
3413 | +#include <libqtdbustest/DBusTestRunner.h> |
3414 | +#include <libqtdbustest/QProcessDBusService.h> |
3415 | +#include <libqtdbusmock/DBusMock.h> |
3416 | + |
3417 | +#include <unity/gmenuharness/MatchUtils.h> |
3418 | +#include <unity/gmenuharness/MenuMatcher.h> |
3419 | + |
3420 | +#include <gmock/gmock.h> |
3421 | +#include <gtest/gtest.h> |
3422 | + |
3423 | +class MenusInterface; |
3424 | +class DBusPulseVolume; |
3425 | +class DBusPropertiesInterface; |
3426 | +class QSignalSpy; |
3427 | + |
3428 | +class IndicatorSoundTestBase: public testing::Test |
3429 | +{ |
3430 | +public: |
3431 | + IndicatorSoundTestBase(); |
3432 | + |
3433 | + ~IndicatorSoundTestBase(); |
3434 | + |
3435 | +protected: |
3436 | + void SetUp() override; |
3437 | + void TearDown() override; |
3438 | + |
3439 | + void startIndicator(); |
3440 | + void startPulseDesktop(); |
3441 | + void startPulsePhone(); |
3442 | + void startAccountsService(); |
3443 | + |
3444 | + bool clearGSettingsPlayers(); |
3445 | + |
3446 | + bool startTestMprisPlayer(QString const& playerName); |
3447 | + |
3448 | + bool setTestMprisPlayerProperty(QString const &testPlayer, QString const &property, bool value); |
3449 | + |
3450 | + bool setStreamRestoreVolume(QString const &role, double volume); |
3451 | + |
3452 | + bool setSinkVolume(double volume); |
3453 | + |
3454 | + bool startTestSound(QString const &role); |
3455 | + |
3456 | + void stopTestSound(); |
3457 | + |
3458 | + static std::shared_ptr<GVariant> volume_variant(double volume); |
3459 | + |
3460 | + static unity::gmenuharness::MenuMatcher::Parameters desktopParameters(); |
3461 | + |
3462 | + static unity::gmenuharness::MenuMatcher::Parameters phoneParameters(); |
3463 | + |
3464 | + static unity::gmenuharness::MenuItemMatcher volumeSlider(double volume); |
3465 | + |
3466 | + static unity::gmenuharness::MenuItemMatcher silentModeSwitch(bool toggled); |
3467 | + |
3468 | + bool waitMenuChange(); |
3469 | + |
3470 | + bool initializeMenuChangedSignal(); |
3471 | + |
3472 | + bool waitVolumeChangedInIndicator(); |
3473 | + |
3474 | + void initializeAccountsInterface(); |
3475 | + |
3476 | + QtDBusTest::DBusTestRunner dbusTestRunner; |
3477 | + |
3478 | + QtDBusMock::DBusMock dbusMock; |
3479 | + |
3480 | + QtDBusTest::DBusServicePtr indicator; |
3481 | + |
3482 | + QtDBusTest::DBusServicePtr pulseaudio; |
3483 | + |
3484 | + QtDBusTest::DBusServicePtr accountsService; |
3485 | + |
3486 | + QProcess testSoundProcess; |
3487 | + |
3488 | + QProcess testPlayer1; |
3489 | + |
3490 | + std::unique_ptr<MenusInterface> menu_interface_; |
3491 | + |
3492 | + std::unique_ptr<DBusPropertiesInterface> accounts_interface_; |
3493 | + |
3494 | + std::unique_ptr<QSignalSpy> signal_spy_volume_changed_; |
3495 | + |
3496 | + std::unique_ptr<QSignalSpy> signal_spy_menu_changed_; |
3497 | +}; |
3498 | |
3499 | === added file 'tests/integration/main.cpp' |
3500 | --- tests/integration/main.cpp 1970-01-01 00:00:00 +0000 |
3501 | +++ tests/integration/main.cpp 2015-10-01 13:45:49 +0000 |
3502 | @@ -0,0 +1,58 @@ |
3503 | +/* |
3504 | + * Copyright © 2014 Canonical Ltd. |
3505 | + * |
3506 | + * This program is free software: you can redistribute it and/or modify it |
3507 | + * under the terms of the GNU Lesser General Public License version 3, |
3508 | + * as published by the Free Software Foundation. |
3509 | + * |
3510 | + * This program is distributed in the hope that it will be useful, |
3511 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3512 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3513 | + * GNU Lesser General Public License for more details. |
3514 | + * |
3515 | + * You should have received a copy of the GNU Lesser General Public License |
3516 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3517 | + * |
3518 | + * Authors: |
3519 | + * Pete Woods <pete.woods@canonical.com> |
3520 | + */ |
3521 | + |
3522 | +//#include <config.h> |
3523 | + |
3524 | +#include <QCoreApplication> |
3525 | +#include <QTimer> |
3526 | +#include <gtest/gtest.h> |
3527 | + |
3528 | +#include <libqtdbusmock/DBusMock.h> |
3529 | + |
3530 | +#include "dbus-types.h" |
3531 | + |
3532 | +using namespace QtDBusMock; |
3533 | + |
3534 | +class Runner: public QObject |
3535 | +{ |
3536 | + Q_OBJECT |
3537 | +public Q_SLOTS: |
3538 | + void run() |
3539 | + { |
3540 | + QCoreApplication::exit(RUN_ALL_TESTS()); |
3541 | + } |
3542 | +}; |
3543 | + |
3544 | +int main(int argc, char **argv) |
3545 | +{ |
3546 | + qputenv("LANG", "C.UTF-8"); |
3547 | + unsetenv("LC_ALL"); |
3548 | + |
3549 | + QCoreApplication application(argc, argv); |
3550 | + DBusMock::registerMetaTypes(); |
3551 | + DBusTypes::registerMetaTypes(); |
3552 | + ::testing::InitGoogleTest(&argc, argv); |
3553 | + |
3554 | + Runner runner; |
3555 | + QTimer::singleShot(0, &runner, SLOT(run())); |
3556 | + |
3557 | + return application.exec(); |
3558 | +} |
3559 | + |
3560 | +#include "main.moc" |
3561 | |
3562 | === added file 'tests/integration/test-indicator.cpp' |
3563 | --- tests/integration/test-indicator.cpp 1970-01-01 00:00:00 +0000 |
3564 | +++ tests/integration/test-indicator.cpp 2015-10-01 13:45:49 +0000 |
3565 | @@ -0,0 +1,637 @@ |
3566 | +/* |
3567 | + * Copyright (C) 2015 Canonical, Ltd. |
3568 | + * |
3569 | + * This program is free software: you can redistribute it and/or modify it |
3570 | + * under the terms of the GNU General Public License version 3, as published |
3571 | + * by the Free Software Foundation. |
3572 | + * |
3573 | + * This program is distributed in the hope that it will be useful, but |
3574 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3575 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3576 | + * PURPOSE. See the GNU General Public License for more details. |
3577 | + * |
3578 | + * You should have received a copy of the GNU General Public License along |
3579 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3580 | + * |
3581 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
3582 | + */ |
3583 | + |
3584 | +#include <indicator-sound-test-base.h> |
3585 | + |
3586 | +#include <QDebug> |
3587 | +#include <QTestEventLoop> |
3588 | +#include <QSignalSpy> |
3589 | + |
3590 | +using namespace std; |
3591 | +using namespace testing; |
3592 | +namespace mh = unity::gmenuharness; |
3593 | +namespace |
3594 | +{ |
3595 | + |
3596 | +class TestIndicator: public IndicatorSoundTestBase |
3597 | +{ |
3598 | +}; |
3599 | + |
3600 | +TEST_F(TestIndicator, PhoneChangeRoleVolume) |
3601 | +{ |
3602 | + double INITIAL_VOLUME = 0.0; |
3603 | + |
3604 | + ASSERT_NO_THROW(startAccountsService()); |
3605 | + ASSERT_NO_THROW(startPulsePhone()); |
3606 | + |
3607 | + // initialize volumes in pulseaudio |
3608 | + EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3609 | + |
3610 | + // start now the indicator, so it picks the new volumes |
3611 | + ASSERT_NO_THROW(startIndicator()); |
3612 | + |
3613 | + // Generate a random volume |
3614 | + QTime now = QTime::currentTime(); |
3615 | + qsrand(now.msec()); |
3616 | + int randInt = qrand() % 100; |
3617 | + double randomVolume = randInt / 100.0; |
3618 | + |
3619 | + // set an initial volume to the alert role |
3620 | + setStreamRestoreVolume("alert", 1.0); |
3621 | + EXPECT_TRUE(waitVolumeChangedInIndicator()); |
3622 | + |
3623 | + // play a test sound, it should change the role in the indicator |
3624 | + EXPECT_TRUE(startTestSound("multimedia")); |
3625 | + EXPECT_TRUE(waitVolumeChangedInIndicator()); |
3626 | + |
3627 | + // set the random volume to the multimedia role |
3628 | + EXPECT_TRUE(setStreamRestoreVolume("multimedia", randomVolume)); |
3629 | + if (randomVolume != INITIAL_VOLUME) |
3630 | + { |
3631 | + EXPECT_TRUE(waitVolumeChangedInIndicator()); |
3632 | + } |
3633 | + |
3634 | + // check the indicator |
3635 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3636 | + .item(mh::MenuItemMatcher() |
3637 | + .action("indicator.root") |
3638 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3639 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
3640 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3641 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
3642 | + .mode(mh::MenuItemMatcher::Mode::starts_with) |
3643 | + .submenu() |
3644 | + .item(mh::MenuItemMatcher() |
3645 | + .section() |
3646 | + .item(silentModeSwitch(false)) |
3647 | + .item(volumeSlider(randomVolume)) |
3648 | + ) |
3649 | + ).match()); |
3650 | + |
3651 | + // check that the last item is Sound Settings |
3652 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3653 | + .item(mh::MenuItemMatcher() |
3654 | + .action("indicator.root") |
3655 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3656 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3657 | + .mode(mh::MenuItemMatcher::Mode::ends_with) |
3658 | + .submenu() |
3659 | + .item(mh::MenuItemMatcher() |
3660 | + .label("Sound Settings…") |
3661 | + .action("indicator.phone-settings") |
3662 | + ) |
3663 | + ).match()); |
3664 | + |
3665 | + // stop the test sound, the role should change again to alert |
3666 | + stopTestSound(); |
3667 | + if (randomVolume != 1.0) |
3668 | + { |
3669 | + // we only wait if the volume in the alert and the |
3670 | + // one set in the multimedia roles differ |
3671 | + EXPECT_TRUE(waitVolumeChangedInIndicator()); |
3672 | + } |
3673 | + |
3674 | + // check the initial volume for the alert role |
3675 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3676 | + .item(mh::MenuItemMatcher() |
3677 | + .action("indicator.root") |
3678 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3679 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
3680 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3681 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
3682 | + .mode(mh::MenuItemMatcher::Mode::starts_with) |
3683 | + .submenu() |
3684 | + .item(mh::MenuItemMatcher() |
3685 | + .section() |
3686 | + .item(silentModeSwitch(false)) |
3687 | + .item(volumeSlider(1.0)) |
3688 | + ) |
3689 | + ).match()); |
3690 | + |
3691 | + // check that the last item is Sound Settings |
3692 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3693 | + .item(mh::MenuItemMatcher() |
3694 | + .action("indicator.root") |
3695 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3696 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3697 | + .mode(mh::MenuItemMatcher::Mode::ends_with) |
3698 | + .submenu() |
3699 | + .item(mh::MenuItemMatcher() |
3700 | + .label("Sound Settings…") |
3701 | + .action("indicator.phone-settings") |
3702 | + ) |
3703 | + ).match()); |
3704 | +} |
3705 | + |
3706 | +TEST_F(TestIndicator, PhoneBasicInitialVolume) |
3707 | +{ |
3708 | + double INITIAL_VOLUME = 0.0; |
3709 | + |
3710 | + ASSERT_NO_THROW(startAccountsService()); |
3711 | + EXPECT_TRUE(clearGSettingsPlayers()); |
3712 | + ASSERT_NO_THROW(startPulsePhone()); |
3713 | + |
3714 | + // initialize volumes in pulseaudio |
3715 | + EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3716 | + |
3717 | + // start now the indicator, so it picks the new volumes |
3718 | + ASSERT_NO_THROW(startIndicator()); |
3719 | + |
3720 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3721 | + .item(mh::MenuItemMatcher() |
3722 | + .action("indicator.root") |
3723 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3724 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
3725 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3726 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
3727 | + .mode(mh::MenuItemMatcher::Mode::all) |
3728 | + .submenu() |
3729 | + .item(mh::MenuItemMatcher() |
3730 | + .section() |
3731 | + .item(silentModeSwitch(false)) |
3732 | + .item(volumeSlider(INITIAL_VOLUME)) |
3733 | + ) |
3734 | + .item(mh::MenuItemMatcher() |
3735 | + .label("Sound Settings…") |
3736 | + .action("indicator.phone-settings") |
3737 | + ) |
3738 | + ).match()); |
3739 | +} |
3740 | + |
3741 | +TEST_F(TestIndicator, PhoneAddMprisPlayer) |
3742 | +{ |
3743 | + double INITIAL_VOLUME = 0.0; |
3744 | + |
3745 | + ASSERT_NO_THROW(startAccountsService()); |
3746 | + EXPECT_TRUE(clearGSettingsPlayers()); |
3747 | + ASSERT_NO_THROW(startPulsePhone()); |
3748 | + |
3749 | + // initialize volumes in pulseaudio |
3750 | + EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3751 | + |
3752 | + // start now the indicator, so it picks the new volumes |
3753 | + ASSERT_NO_THROW(startIndicator()); |
3754 | + |
3755 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3756 | + .item(mh::MenuItemMatcher() |
3757 | + .action("indicator.root") |
3758 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3759 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
3760 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3761 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
3762 | + .mode(mh::MenuItemMatcher::Mode::all) |
3763 | + .submenu() |
3764 | + .item(mh::MenuItemMatcher() |
3765 | + .section() |
3766 | + .item(silentModeSwitch(false)) |
3767 | + .item(volumeSlider(INITIAL_VOLUME)) |
3768 | + ) |
3769 | + .item(mh::MenuItemMatcher() |
3770 | + .label("Sound Settings…") |
3771 | + .action("indicator.phone-settings") |
3772 | + ) |
3773 | + ).match()); |
3774 | + |
3775 | + // initialize the signal spy |
3776 | + EXPECT_TRUE(initializeMenuChangedSignal()); |
3777 | + |
3778 | + // start the test player |
3779 | + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); |
3780 | + |
3781 | + // wait for the menu change |
3782 | + EXPECT_TRUE(waitMenuChange()); |
3783 | + |
3784 | + // finally verify that the player is added |
3785 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
3786 | + .item(mh::MenuItemMatcher() |
3787 | + .action("indicator.root") |
3788 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3789 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
3790 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3791 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
3792 | + .mode(mh::MenuItemMatcher::Mode::all) |
3793 | + .submenu() |
3794 | + .item(mh::MenuItemMatcher() |
3795 | + .section() |
3796 | + .item(silentModeSwitch(false)) |
3797 | + .item(volumeSlider(INITIAL_VOLUME)) |
3798 | + ) |
3799 | + .item(mh::MenuItemMatcher() |
3800 | + .section() |
3801 | + .item(mh::MenuItemMatcher() |
3802 | + .action("indicator.testplayer1.desktop") |
3803 | + .label("TestPlayer1") |
3804 | + .themed_icon("icon", {"testplayer"}) |
3805 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
3806 | + ) |
3807 | + .item(mh::MenuItemMatcher() |
3808 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
3809 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
3810 | + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") |
3811 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
3812 | + ) |
3813 | + ) |
3814 | + .item(mh::MenuItemMatcher() |
3815 | + .label("Sound Settings…") |
3816 | + .action("indicator.phone-settings") |
3817 | + ) |
3818 | + ).match()); |
3819 | +} |
3820 | + |
3821 | +TEST_F(TestIndicator, DesktopBasicInitialVolume) |
3822 | +{ |
3823 | + double INITIAL_VOLUME = 0.0; |
3824 | + |
3825 | + ASSERT_NO_THROW(startAccountsService()); |
3826 | + EXPECT_TRUE(clearGSettingsPlayers()); |
3827 | + ASSERT_NO_THROW(startPulseDesktop()); |
3828 | + |
3829 | + // initialize volumes in pulseaudio |
3830 | + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3831 | + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); |
3832 | + |
3833 | + // start the test player |
3834 | + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); |
3835 | + |
3836 | + // start now the indicator, so it picks the new volumes |
3837 | + ASSERT_NO_THROW(startIndicator()); |
3838 | + |
3839 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
3840 | + .item(mh::MenuItemMatcher() |
3841 | + .action("indicator.root") |
3842 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3843 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3844 | + .mode(mh::MenuItemMatcher::Mode::all) |
3845 | + .submenu() |
3846 | + .item(mh::MenuItemMatcher() |
3847 | + .section() |
3848 | + .item(mh::MenuItemMatcher().checkbox() |
3849 | + .label("Mute") |
3850 | + ) |
3851 | + .item(volumeSlider(INITIAL_VOLUME)) |
3852 | + ) |
3853 | + .item(mh::MenuItemMatcher() |
3854 | + .section() |
3855 | + .item(mh::MenuItemMatcher() |
3856 | + .action("indicator.testplayer1.desktop") |
3857 | + .label("TestPlayer1") |
3858 | + .themed_icon("icon", {"testplayer"}) |
3859 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
3860 | + ) |
3861 | + .item(mh::MenuItemMatcher() |
3862 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
3863 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
3864 | + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") |
3865 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
3866 | + ) |
3867 | + ) |
3868 | + .item(mh::MenuItemMatcher() |
3869 | + .label("Sound Settings…") |
3870 | + ) |
3871 | + ).match()); |
3872 | +} |
3873 | + |
3874 | +TEST_F(TestIndicator, DesktopAddMprisPlayer) |
3875 | +{ |
3876 | + double INITIAL_VOLUME = 0.0; |
3877 | + |
3878 | + ASSERT_NO_THROW(startAccountsService()); |
3879 | + EXPECT_TRUE(clearGSettingsPlayers()); |
3880 | + ASSERT_NO_THROW(startPulseDesktop()); |
3881 | + |
3882 | + // initialize volumes in pulseaudio |
3883 | + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3884 | + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); |
3885 | + |
3886 | + // start the test player |
3887 | + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); |
3888 | + |
3889 | + // start now the indicator, so it picks the new volumes |
3890 | + ASSERT_NO_THROW(startIndicator()); |
3891 | + |
3892 | + // check that the player is added |
3893 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
3894 | + .item(mh::MenuItemMatcher() |
3895 | + .action("indicator.root") |
3896 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3897 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3898 | + .mode(mh::MenuItemMatcher::Mode::all) |
3899 | + .submenu() |
3900 | + .item(mh::MenuItemMatcher() |
3901 | + .section() |
3902 | + .item(mh::MenuItemMatcher().checkbox() |
3903 | + .label("Mute") |
3904 | + ) |
3905 | + .item(volumeSlider(INITIAL_VOLUME)) |
3906 | + ) |
3907 | + .item(mh::MenuItemMatcher() |
3908 | + .section() |
3909 | + .item(mh::MenuItemMatcher() |
3910 | + .action("indicator.testplayer1.desktop") |
3911 | + .label("TestPlayer1") |
3912 | + .themed_icon("icon", {"testplayer"}) |
3913 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
3914 | + ) |
3915 | + .item(mh::MenuItemMatcher() |
3916 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
3917 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
3918 | + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") |
3919 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
3920 | + ) |
3921 | + ) |
3922 | + .item(mh::MenuItemMatcher() |
3923 | + .label("Sound Settings…") |
3924 | + ) |
3925 | + ).match()); |
3926 | +} |
3927 | + |
3928 | +TEST_F(TestIndicator, DesktopMprisPlayerButtonsState) |
3929 | +{ |
3930 | + double INITIAL_VOLUME = 0.0; |
3931 | + |
3932 | + ASSERT_NO_THROW(startAccountsService()); |
3933 | + EXPECT_TRUE(clearGSettingsPlayers()); |
3934 | + ASSERT_NO_THROW(startPulseDesktop()); |
3935 | + |
3936 | + // initialize volumes in pulseaudio |
3937 | + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
3938 | + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); |
3939 | + |
3940 | + // start the test player |
3941 | + EXPECT_TRUE(startTestMprisPlayer("testplayer1")); |
3942 | + |
3943 | + // start now the indicator, so it picks the new volumes |
3944 | + ASSERT_NO_THROW(startIndicator()); |
3945 | + |
3946 | + // check that the player is added |
3947 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
3948 | + .item(mh::MenuItemMatcher() |
3949 | + .action("indicator.root") |
3950 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3951 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3952 | + .mode(mh::MenuItemMatcher::Mode::all) |
3953 | + .submenu() |
3954 | + .item(mh::MenuItemMatcher() |
3955 | + .section() |
3956 | + .item(mh::MenuItemMatcher().checkbox() |
3957 | + .label("Mute") |
3958 | + ) |
3959 | + .item(volumeSlider(INITIAL_VOLUME)) |
3960 | + ) |
3961 | + .item(mh::MenuItemMatcher() |
3962 | + .section() |
3963 | + .item(mh::MenuItemMatcher() |
3964 | + .action("indicator.testplayer1.desktop") |
3965 | + .label("TestPlayer1") |
3966 | + .themed_icon("icon", {"testplayer"}) |
3967 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
3968 | + ) |
3969 | + .item(mh::MenuItemMatcher() |
3970 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
3971 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
3972 | + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") |
3973 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
3974 | + ) |
3975 | + ) |
3976 | + .item(mh::MenuItemMatcher() |
3977 | + .label("Sound Settings…") |
3978 | + ) |
3979 | + ).match()); |
3980 | + |
3981 | + // change the state of CanGoNext |
3982 | + EXPECT_TRUE(setTestMprisPlayerProperty("testplayer1", "CanGoNext", false)); |
3983 | + |
3984 | + // verify that the action changes |
3985 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
3986 | + .item(mh::MenuItemMatcher() |
3987 | + .action("indicator.root") |
3988 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
3989 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
3990 | + .mode(mh::MenuItemMatcher::Mode::all) |
3991 | + .submenu() |
3992 | + .item(mh::MenuItemMatcher() |
3993 | + .section() |
3994 | + .item(mh::MenuItemMatcher().checkbox() |
3995 | + .label("Mute") |
3996 | + ) |
3997 | + .item(volumeSlider(INITIAL_VOLUME)) |
3998 | + ) |
3999 | + .item(mh::MenuItemMatcher() |
4000 | + .section() |
4001 | + .item(mh::MenuItemMatcher() |
4002 | + .action("indicator.testplayer1.desktop") |
4003 | + .label("TestPlayer1") |
4004 | + .themed_icon("icon", {"testplayer"}) |
4005 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
4006 | + ) |
4007 | + .item(mh::MenuItemMatcher() |
4008 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
4009 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
4010 | + .attribute_not_set("x-canonical-next-action") |
4011 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
4012 | + ) |
4013 | + ) |
4014 | + .item(mh::MenuItemMatcher() |
4015 | + .label("Sound Settings…") |
4016 | + ) |
4017 | + ).match()); |
4018 | + |
4019 | + |
4020 | + // change the state of CanGoPrevious |
4021 | + EXPECT_TRUE(setTestMprisPlayerProperty("testplayer1", "CanGoPrevious", false)); |
4022 | + |
4023 | + // verify that the action changes |
4024 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
4025 | + .item(mh::MenuItemMatcher() |
4026 | + .action("indicator.root") |
4027 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4028 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4029 | + .mode(mh::MenuItemMatcher::Mode::all) |
4030 | + .submenu() |
4031 | + .item(mh::MenuItemMatcher() |
4032 | + .section() |
4033 | + .item(mh::MenuItemMatcher().checkbox() |
4034 | + .label("Mute") |
4035 | + ) |
4036 | + .item(volumeSlider(INITIAL_VOLUME)) |
4037 | + ) |
4038 | + .item(mh::MenuItemMatcher() |
4039 | + .section() |
4040 | + .item(mh::MenuItemMatcher() |
4041 | + .action("indicator.testplayer1.desktop") |
4042 | + .label("TestPlayer1") |
4043 | + .themed_icon("icon", {"testplayer"}) |
4044 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
4045 | + ) |
4046 | + .item(mh::MenuItemMatcher() |
4047 | + .attribute_not_set("x-canonical-previous-action") |
4048 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
4049 | + .attribute_not_set("x-canonical-next-action") |
4050 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
4051 | + ) |
4052 | + ) |
4053 | + .item(mh::MenuItemMatcher() |
4054 | + .label("Sound Settings…") |
4055 | + ) |
4056 | + ).match()); |
4057 | + |
4058 | + // set back both to true |
4059 | + EXPECT_TRUE(setTestMprisPlayerProperty("testplayer1", "CanGoNext", true)); |
4060 | + EXPECT_TRUE(setTestMprisPlayerProperty("testplayer1", "CanGoPrevious", true)); |
4061 | + |
4062 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
4063 | + .item(mh::MenuItemMatcher() |
4064 | + .action("indicator.root") |
4065 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4066 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4067 | + .mode(mh::MenuItemMatcher::Mode::all) |
4068 | + .submenu() |
4069 | + .item(mh::MenuItemMatcher() |
4070 | + .section() |
4071 | + .item(mh::MenuItemMatcher().checkbox() |
4072 | + .label("Mute") |
4073 | + ) |
4074 | + .item(volumeSlider(INITIAL_VOLUME)) |
4075 | + ) |
4076 | + .item(mh::MenuItemMatcher() |
4077 | + .section() |
4078 | + .item(mh::MenuItemMatcher() |
4079 | + .action("indicator.testplayer1.desktop") |
4080 | + .label("TestPlayer1") |
4081 | + .themed_icon("icon", {"testplayer"}) |
4082 | + .string_attribute("x-canonical-type", "com.canonical.unity.media-player") |
4083 | + ) |
4084 | + .item(mh::MenuItemMatcher() |
4085 | + .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") |
4086 | + .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") |
4087 | + .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") |
4088 | + .string_attribute("x-canonical-type","com.canonical.unity.playback-item") |
4089 | + ) |
4090 | + ) |
4091 | + .item(mh::MenuItemMatcher() |
4092 | + .label("Sound Settings…") |
4093 | + ) |
4094 | + ).match()); |
4095 | +} |
4096 | + |
4097 | +TEST_F(TestIndicator, DesktopChangeRoleVolume) |
4098 | +{ |
4099 | + double INITIAL_VOLUME = 0.0; |
4100 | + |
4101 | + ASSERT_NO_THROW(startAccountsService()); |
4102 | + ASSERT_NO_THROW(startPulseDesktop()); |
4103 | + |
4104 | + // initialize volumes in pulseaudio |
4105 | + // expect false for stream restore, because the module |
4106 | + // is not loaded in the desktop pulseaudio instance |
4107 | + EXPECT_FALSE(setStreamRestoreVolume("mutimedia", INITIAL_VOLUME)); |
4108 | + EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); |
4109 | + |
4110 | + EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); |
4111 | + |
4112 | + // start now the indicator, so it picks the new volumes |
4113 | + ASSERT_NO_THROW(startIndicator()); |
4114 | + |
4115 | + // Generate a random volume |
4116 | + QTime now = QTime::currentTime(); |
4117 | + qsrand(now.msec()); |
4118 | + int randInt = qrand() % 100; |
4119 | + double randomVolume = randInt / 100.0; |
4120 | + |
4121 | + // play a test sound, it should NOT change the role in the indicator |
4122 | + EXPECT_TRUE(startTestSound("multimedia")); |
4123 | + EXPECT_FALSE(waitVolumeChangedInIndicator()); |
4124 | + |
4125 | + // set the random volume |
4126 | + EXPECT_TRUE(setSinkVolume(randomVolume)); |
4127 | + if (randomVolume != INITIAL_VOLUME) |
4128 | + { |
4129 | + EXPECT_TRUE(waitVolumeChangedInIndicator()); |
4130 | + } |
4131 | + |
4132 | + // check the indicator |
4133 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
4134 | + .item(mh::MenuItemMatcher() |
4135 | + .action("indicator.root") |
4136 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4137 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4138 | + .mode(mh::MenuItemMatcher::Mode::starts_with) |
4139 | + .submenu() |
4140 | + .item(mh::MenuItemMatcher() |
4141 | + .section() |
4142 | + .item(mh::MenuItemMatcher().checkbox() |
4143 | + .label("Mute") |
4144 | + ) |
4145 | + .item(volumeSlider(randomVolume)) |
4146 | + ) |
4147 | + ).match()); |
4148 | + |
4149 | + // check that the last item is Sound Settings |
4150 | + EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) |
4151 | + .item(mh::MenuItemMatcher() |
4152 | + .action("indicator.root") |
4153 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4154 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4155 | + .mode(mh::MenuItemMatcher::Mode::ends_with) |
4156 | + .submenu() |
4157 | + .item(mh::MenuItemMatcher() |
4158 | + .label("Sound Settings…") |
4159 | + ) |
4160 | + ).match()); |
4161 | + |
4162 | + // stop the test sound, the role should change again to alert |
4163 | + stopTestSound(); |
4164 | + |
4165 | + // although we were playing something in the multimedia role |
4166 | + // the server does not have the streamrestore module, so |
4167 | + // the volume does not change (the role does not change) |
4168 | + EXPECT_FALSE(waitVolumeChangedInIndicator()); |
4169 | + |
4170 | + // check the initial volume for the alert role |
4171 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
4172 | + .item(mh::MenuItemMatcher() |
4173 | + .action("indicator.root") |
4174 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4175 | + .string_attribute("x-canonical-scroll-action", "indicator.scroll") |
4176 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4177 | + .string_attribute("submenu-action", "indicator.indicator-shown") |
4178 | + .mode(mh::MenuItemMatcher::Mode::starts_with) |
4179 | + .submenu() |
4180 | + .item(mh::MenuItemMatcher() |
4181 | + .section() |
4182 | + .item(silentModeSwitch(false)) |
4183 | + .item(volumeSlider(randomVolume)) |
4184 | + ) |
4185 | + ).match()); |
4186 | + |
4187 | + // check that the last item is Sound Settings |
4188 | + EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters()) |
4189 | + .item(mh::MenuItemMatcher() |
4190 | + .action("indicator.root") |
4191 | + .string_attribute("x-canonical-type", "com.canonical.indicator.root") |
4192 | + .string_attribute("x-canonical-secondary-action", "indicator.mute") |
4193 | + .mode(mh::MenuItemMatcher::Mode::ends_with) |
4194 | + .submenu() |
4195 | + .item(mh::MenuItemMatcher() |
4196 | + .label("Sound Settings…") |
4197 | + .action("indicator.phone-settings") |
4198 | + ) |
4199 | + ).match()); |
4200 | +} |
4201 | + |
4202 | +} // namespace |
4203 | |
4204 | === added file 'tests/integration/test-sound.wav' |
4205 | Binary files tests/integration/test-sound.wav 1970-01-01 00:00:00 +0000 and tests/integration/test-sound.wav 2015-10-01 13:45:49 +0000 differ |
4206 | === added file 'tests/integration/touch-stream-restore.table' |
4207 | --- tests/integration/touch-stream-restore.table 1970-01-01 00:00:00 +0000 |
4208 | +++ tests/integration/touch-stream-restore.table 2015-10-01 13:45:49 +0000 |
4209 | @@ -0,0 +1,4 @@ |
4210 | +sink-input-by-media-role:multimedia -8 |
4211 | +sink-input-by-media-role:alert -8 |
4212 | +sink-input-by-media-role:alarm -8 |
4213 | +sink-input-by-media-role:phone -15 |
4214 | |
4215 | === added directory 'tests/integration/utils' |
4216 | === added file 'tests/integration/utils/dbus-pulse-volume.cpp' |
4217 | --- tests/integration/utils/dbus-pulse-volume.cpp 1970-01-01 00:00:00 +0000 |
4218 | +++ tests/integration/utils/dbus-pulse-volume.cpp 2015-10-01 13:45:49 +0000 |
4219 | @@ -0,0 +1,232 @@ |
4220 | +/* |
4221 | + * Copyright (C) 2015 Canonical, Ltd. |
4222 | + * |
4223 | + * This program is free software: you can redistribute it and/or modify it |
4224 | + * under the terms of the GNU General Public License version 3, as published |
4225 | + * by the Free Software Foundation. |
4226 | + * |
4227 | + * This program is distributed in the hope that it will be useful, but |
4228 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4229 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4230 | + * PURPOSE. See the GNU General Public License for more details. |
4231 | + * |
4232 | + * You should have received a copy of the GNU General Public License along |
4233 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4234 | + * |
4235 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4236 | + */ |
4237 | + |
4238 | +#include "dbus-pulse-volume.h" |
4239 | + |
4240 | +#include "dbus_properties_interface.h" |
4241 | +#include "dbus_accounts_interface.h" |
4242 | +#include "dbus_accountssound_interface.h" |
4243 | +#include "stream_restore_interface.h" |
4244 | + |
4245 | +#include <pulse/volume.h> |
4246 | + |
4247 | +#include <QSignalSpy> |
4248 | + |
4249 | +unsigned int volumeDoubleToUint(double volume) |
4250 | +{ |
4251 | + double tmp = (double)(PA_VOLUME_NORM - PA_VOLUME_MUTED) * volume; |
4252 | + return (unsigned int)tmp + PA_VOLUME_MUTED; |
4253 | +} |
4254 | + |
4255 | +double volumeUIntToDoulbe(uint volume) |
4256 | +{ |
4257 | + double tmp = (double)(volume - PA_VOLUME_MUTED); |
4258 | + return tmp / (double)(PA_VOLUME_NORM - PA_VOLUME_MUTED); |
4259 | +} |
4260 | + |
4261 | +DBusPulseVolume::DBusPulseVolume() : |
4262 | + QObject() |
4263 | +{ |
4264 | + std::unique_ptr<DBusPropertiesInterface> basicConnectionInterface(new DBusPropertiesInterface("org.PulseAudio1", |
4265 | + "/org/pulseaudio/server_lookup1", |
4266 | + QDBusConnection::sessionBus(), 0)); |
4267 | + |
4268 | + QDBusReply<QVariant> connection_string = basicConnectionInterface->call(QLatin1String("Get"), |
4269 | + QLatin1String("org.PulseAudio.ServerLookup1"), |
4270 | + QLatin1String("Address")); |
4271 | + |
4272 | + if (!connection_string.isValid()) |
4273 | + { |
4274 | + qWarning() << "DBusPulseVolume::DBusPulseVolume(): D-Bus error: " << connection_string.error().message(); |
4275 | + } |
4276 | + |
4277 | + connection_.reset(new QDBusConnection(QDBusConnection::connectToPeer(connection_string.value().toString(), "set-volume"))); |
4278 | + |
4279 | + if (connection_->isConnected()) |
4280 | + { |
4281 | + interface_paths_.reset(new StreamRestoreInterface("org.PulseAudio.Ext.StreamRestore1", |
4282 | + "/org/pulseaudio/stream_restore1", |
4283 | + *(connection_.get()), 0)); |
4284 | + if (interface_paths_) |
4285 | + { |
4286 | + // get the role paths |
4287 | + fillRolePath("multimedia"); |
4288 | + fillRolePath("alert"); |
4289 | + fillRolePath("alarm"); |
4290 | + fillRolePath("phone"); |
4291 | + } |
4292 | + |
4293 | + initializeAccountsInterface(); |
4294 | + } |
4295 | + else |
4296 | + { |
4297 | + qWarning() << "DBusPulseVolume::DBusPulseVolume(): Error connecting: " << connection_->lastError().message(); |
4298 | + } |
4299 | +} |
4300 | + |
4301 | +DBusPulseVolume::~DBusPulseVolume() |
4302 | +{ |
4303 | +} |
4304 | + |
4305 | +QString DBusPulseVolume::fillRolePath(QString const &role) |
4306 | +{ |
4307 | + QString role_complete_name = QString("sink-input-by-media-role:") + role; |
4308 | + // get the role paths |
4309 | + QDBusReply<QDBusObjectPath> objectPath = interface_paths_->call(QLatin1String("GetEntryByName"), role_complete_name); |
4310 | + if (!objectPath.isValid()) |
4311 | + { |
4312 | + qWarning() << "SetVolume::fillRolePath(): D-Bus error: " << objectPath.error().message(); |
4313 | + return ""; |
4314 | + } |
4315 | + |
4316 | + auto role_info = std::make_shared<RoleInformation>(); |
4317 | + role_info->interface_.reset(new DBusPropertiesInterface("org.PulseAudio.Ext.StreamRestore1.RestoreEntry", |
4318 | + objectPath.value().path(), |
4319 | + *(connection_.get()), 0)); |
4320 | + if (!role_info->interface_) |
4321 | + { |
4322 | + qWarning() << "SetVolume::fillRolePath() - Error obtaining properties interface"; |
4323 | + return ""; |
4324 | + } |
4325 | + role_info->path_ = objectPath.value().path(); |
4326 | + roles_map_[role] = role_info; |
4327 | + return role_info->path_; |
4328 | +} |
4329 | + |
4330 | +bool DBusPulseVolume::setVolume(QString const & role, double volume) |
4331 | +{ |
4332 | + if (!interface_paths_) |
4333 | + { |
4334 | + qWarning() << "SetVolume::setVolume(): error: Volume interfaces are not initialized"; |
4335 | + return false; |
4336 | + } |
4337 | + |
4338 | + RolesMap::const_iterator iter = roles_map_.find(role); |
4339 | + if (iter != roles_map_.end()) |
4340 | + { |
4341 | + QVariant var; |
4342 | + PulseaudioVolumeArray t; |
4343 | + PulseaudioVolume vv(0, volumeDoubleToUint(volume)); |
4344 | + t.addItem(vv); |
4345 | + var.setValue(t); |
4346 | + QDBusVariant dbusVar(var); |
4347 | + QDBusReply<void> set_vol = (*iter).second->interface_->call(QLatin1String("Set"), |
4348 | + QVariant::fromValue(QString("org.PulseAudio.Ext.StreamRestore1.RestoreEntry")), |
4349 | + QVariant::fromValue(QString("Volume")), |
4350 | + QVariant::fromValue(dbusVar)); |
4351 | + |
4352 | + if (!set_vol.isValid()) |
4353 | + { |
4354 | + qWarning() << "SetVolume::setVolume(): D-Bus error: " << set_vol.error().message(); |
4355 | + return false; |
4356 | + } |
4357 | + |
4358 | + if (accounts_interface_) |
4359 | + { |
4360 | + QDBusVariant dbusVar(QVariant::fromValue(volume)); |
4361 | + QDBusReply<void> set_vol = accounts_interface_->call(QLatin1String("Set"), |
4362 | + QVariant::fromValue(QString("com.ubuntu.AccountsService.Sound")), |
4363 | + QVariant::fromValue(QString("Volume")), |
4364 | + QVariant::fromValue(dbusVar)); |
4365 | + if (!set_vol.isValid()) |
4366 | + { |
4367 | + qWarning() << "SetVolume::setVolume(): D-Bus error: " << set_vol.error().message(); |
4368 | + return false; |
4369 | + } |
4370 | + } |
4371 | + } |
4372 | + else |
4373 | + { |
4374 | + qWarning() << "SetVolume::setVolume(): role " << role << " was not found."; |
4375 | + return false; |
4376 | + } |
4377 | + return true; |
4378 | +} |
4379 | + |
4380 | +double DBusPulseVolume::getVolume(QString const & role) |
4381 | +{ |
4382 | + if (interface_paths_) |
4383 | + { |
4384 | + RolesMap::const_iterator iter = roles_map_.find(role); |
4385 | + if (iter != roles_map_.end()) |
4386 | + { |
4387 | + QDBusReply<QVariant> prev_vol = (*iter).second->interface_->call(QLatin1String("Get"), |
4388 | + QLatin1String("org.PulseAudio.Ext.StreamRestore1.RestoreEntry"), |
4389 | + QLatin1String("Volume")); |
4390 | + |
4391 | + if (!prev_vol.isValid()) |
4392 | + { |
4393 | + qWarning() << "SetVolume::setVolume(): D-Bus error: " << prev_vol.error().message(); |
4394 | + } |
4395 | + QDBusArgument arg = prev_vol.value().value<QDBusArgument>(); |
4396 | + PulseaudioVolumeArray element; |
4397 | + arg >> element; |
4398 | + return volumeUIntToDoulbe(element.getItem(0).getVolume()); |
4399 | + } |
4400 | + } |
4401 | + return -1.0; |
4402 | +} |
4403 | + |
4404 | +void DBusPulseVolume::initializeAccountsInterface() |
4405 | +{ |
4406 | + auto username = qgetenv("USER"); |
4407 | + if (username != "") |
4408 | + { |
4409 | + qDebug() << "Setting Accounts interface for user: " << username; |
4410 | + std::unique_ptr<AccountsInterface> setInterface(new AccountsInterface("org.freedesktop.Accounts", |
4411 | + "/org/freedesktop/Accounts", |
4412 | + QDBusConnection::systemBus(), 0)); |
4413 | + |
4414 | + QDBusReply<QDBusObjectPath> userResp = setInterface->call(QLatin1String("FindUserByName"), |
4415 | + QLatin1String(username)); |
4416 | + |
4417 | + if (!userResp.isValid()) |
4418 | + { |
4419 | + qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << userResp.error().message(); |
4420 | + } |
4421 | + auto userPath = userResp.value().path(); |
4422 | + if (userPath != "") |
4423 | + { |
4424 | + std::unique_ptr<AccountsSoundInterface> soundInterface(new AccountsSoundInterface("org.freedesktop.Accounts", |
4425 | + userPath, |
4426 | + QDBusConnection::systemBus(), 0)); |
4427 | + |
4428 | + accounts_interface_.reset(new DBusPropertiesInterface("org.freedesktop.Accounts", |
4429 | + userPath, |
4430 | + soundInterface->connection(), 0)); |
4431 | + if (!accounts_interface_->isValid()) |
4432 | + { |
4433 | + qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << accounts_interface_->lastError().message(); |
4434 | + } |
4435 | + signal_spy_volume_changed_.reset(new QSignalSpy(accounts_interface_.get(),&DBusPropertiesInterface::PropertiesChanged)); |
4436 | + } |
4437 | + } |
4438 | +} |
4439 | + |
4440 | +bool DBusPulseVolume::waitForVolumeChangedInAccountsService() |
4441 | +{ |
4442 | + if (signal_spy_volume_changed_) |
4443 | + { |
4444 | + return signal_spy_volume_changed_->wait(); |
4445 | + } |
4446 | + else |
4447 | + { |
4448 | + qWarning() << "DBusPulseVolume::waitForVolumeChangedInAccountsService(): signal was not instantiated"; |
4449 | + } |
4450 | + return false; |
4451 | +} |
4452 | |
4453 | === added file 'tests/integration/utils/dbus-pulse-volume.h' |
4454 | --- tests/integration/utils/dbus-pulse-volume.h 1970-01-01 00:00:00 +0000 |
4455 | +++ tests/integration/utils/dbus-pulse-volume.h 2015-10-01 13:45:49 +0000 |
4456 | @@ -0,0 +1,57 @@ |
4457 | +/* |
4458 | + * Copyright (C) 2015 Canonical, Ltd. |
4459 | + * |
4460 | + * This program is free software: you can redistribute it and/or modify it |
4461 | + * under the terms of the GNU General Public License version 3, as published |
4462 | + * by the Free Software Foundation. |
4463 | + * |
4464 | + * This program is distributed in the hope that it will be useful, but |
4465 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4466 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4467 | + * PURPOSE. See the GNU General Public License for more details. |
4468 | + * |
4469 | + * You should have received a copy of the GNU General Public License along |
4470 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4471 | + * |
4472 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4473 | + */ |
4474 | +#pragma once |
4475 | + |
4476 | +#include <QObject> |
4477 | +#include <QDBusConnection> |
4478 | + |
4479 | +#include <map> |
4480 | +#include <memory> |
4481 | + |
4482 | +class StreamRestoreInterface; |
4483 | +class DBusPropertiesInterface; |
4484 | +class AccountsInterface; |
4485 | +class AccountsSoundInterface; |
4486 | +class QSignalSpy; |
4487 | + |
4488 | +struct RoleInformation |
4489 | +{ |
4490 | + std::unique_ptr<DBusPropertiesInterface> interface_; |
4491 | + QString path_; |
4492 | +}; |
4493 | + |
4494 | +class DBusPulseVolume : public QObject |
4495 | +{ |
4496 | +public: |
4497 | + DBusPulseVolume(); |
4498 | + ~DBusPulseVolume(); |
4499 | + |
4500 | + bool setVolume(QString const & role, double volume); |
4501 | + double getVolume(QString const & role); |
4502 | + bool waitForVolumeChangedInAccountsService(); |
4503 | + |
4504 | +protected: |
4505 | + QString fillRolePath(QString const &role); |
4506 | + void initializeAccountsInterface(); |
4507 | + std::unique_ptr<QDBusConnection> connection_; |
4508 | + std::unique_ptr<StreamRestoreInterface> interface_paths_; |
4509 | + typedef std::map<QString, std::shared_ptr<RoleInformation>> RolesMap; |
4510 | + RolesMap roles_map_; |
4511 | + std::unique_ptr<DBusPropertiesInterface> accounts_interface_; |
4512 | + std::unique_ptr<QSignalSpy> signal_spy_volume_changed_; |
4513 | +}; |
4514 | |
4515 | === added file 'tests/integration/utils/get-volume.cpp' |
4516 | --- tests/integration/utils/get-volume.cpp 1970-01-01 00:00:00 +0000 |
4517 | +++ tests/integration/utils/get-volume.cpp 2015-10-01 13:45:49 +0000 |
4518 | @@ -0,0 +1,33 @@ |
4519 | +/* |
4520 | + * Copyright (C) 2015 Canonical, Ltd. |
4521 | + * |
4522 | + * This program is free software: you can redistribute it and/or modify it |
4523 | + * under the terms of the GNU General Public License version 3, as published |
4524 | + * by the Free Software Foundation. |
4525 | + * |
4526 | + * This program is distributed in the hope that it will be useful, but |
4527 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4528 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4529 | + * PURPOSE. See the GNU General Public License for more details. |
4530 | + * |
4531 | + * You should have received a copy of the GNU General Public License along |
4532 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4533 | + * |
4534 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4535 | + */ |
4536 | + |
4537 | +#include "dbus-types.h" |
4538 | + |
4539 | +#include <string> |
4540 | +#include "dbus-pulse-volume.h" |
4541 | + |
4542 | +int main(int argc, char **argv) |
4543 | +{ |
4544 | + DBusTypes::registerMetaTypes(); |
4545 | + if (argc == 2) |
4546 | + { |
4547 | + DBusPulseVolume volume; |
4548 | + volume.getVolume(argv[1]); |
4549 | + } |
4550 | + return 0; |
4551 | +} |
4552 | |
4553 | === added file 'tests/integration/utils/set-volume.cpp' |
4554 | --- tests/integration/utils/set-volume.cpp 1970-01-01 00:00:00 +0000 |
4555 | +++ tests/integration/utils/set-volume.cpp 2015-10-01 13:45:49 +0000 |
4556 | @@ -0,0 +1,36 @@ |
4557 | +/* |
4558 | + * Copyright (C) 2015 Canonical, Ltd. |
4559 | + * |
4560 | + * This program is free software: you can redistribute it and/or modify it |
4561 | + * under the terms of the GNU General Public License version 3, as published |
4562 | + * by the Free Software Foundation. |
4563 | + * |
4564 | + * This program is distributed in the hope that it will be useful, but |
4565 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4566 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4567 | + * PURPOSE. See the GNU General Public License for more details. |
4568 | + * |
4569 | + * You should have received a copy of the GNU General Public License along |
4570 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4571 | + * |
4572 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4573 | + */ |
4574 | + |
4575 | +#include "dbus-types.h" |
4576 | + |
4577 | +#include <string> |
4578 | +#include "dbus-pulse-volume.h" |
4579 | + |
4580 | +int main(int argc, char **argv) |
4581 | +{ |
4582 | + DBusTypes::registerMetaTypes(); |
4583 | + if (argc == 3) |
4584 | + { |
4585 | + DBusPulseVolume volume; |
4586 | + if(!volume.setVolume(argv[1], std::stod(argv[2]))) |
4587 | + { |
4588 | + return 1; |
4589 | + } |
4590 | + } |
4591 | + return 0; |
4592 | +} |
4593 | |
4594 | === added directory 'tests/service-mocks' |
4595 | === added file 'tests/service-mocks/CMakeLists.txt' |
4596 | --- tests/service-mocks/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4597 | +++ tests/service-mocks/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
4598 | @@ -0,0 +1,2 @@ |
4599 | +add_subdirectory(accounts-mock) |
4600 | +add_subdirectory(media-player-mpris-mock) |
4601 | |
4602 | === added file 'tests/service-mocks/DBusPropertiesNotifier.cpp' |
4603 | --- tests/service-mocks/DBusPropertiesNotifier.cpp 1970-01-01 00:00:00 +0000 |
4604 | +++ tests/service-mocks/DBusPropertiesNotifier.cpp 2015-10-01 13:45:49 +0000 |
4605 | @@ -0,0 +1,41 @@ |
4606 | +/* |
4607 | + * Copyright (C) 2015 Canonical, Ltd. |
4608 | + * |
4609 | + * This program is free software: you can redistribute it and/or modify it |
4610 | + * under the terms of the GNU General Public License version 3, as published |
4611 | + * by the Free Software Foundation. |
4612 | + * |
4613 | + * This program is distributed in the hope that it will be useful, but |
4614 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4615 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4616 | + * PURPOSE. See the GNU General Public License for more details. |
4617 | + * |
4618 | + * You should have received a copy of the GNU General Public License along |
4619 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4620 | + * |
4621 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4622 | + */ |
4623 | + |
4624 | +#include "DBusPropertiesNotifier.h" |
4625 | + |
4626 | +#include <QDBusMessage> |
4627 | + |
4628 | +using namespace ubuntu::indicators::testing; |
4629 | + |
4630 | +void DBusPropertiesNotifier::notifyPropertyChanged(QDBusConnection const & connection, |
4631 | + QString const & interface, |
4632 | + QString const & path, |
4633 | + QString const & propertyName, |
4634 | + QVariant const & propertyValue) |
4635 | +{ |
4636 | + QDBusMessage signal = QDBusMessage::createSignal( |
4637 | + path, |
4638 | + "org.freedesktop.DBus.Properties", |
4639 | + "PropertiesChanged"); |
4640 | + signal << interface; |
4641 | + QVariantMap changedProps; |
4642 | + changedProps.insert(propertyName, propertyValue); |
4643 | + signal << changedProps; |
4644 | + signal << QStringList(); |
4645 | + connection.send(signal); |
4646 | +} |
4647 | |
4648 | === added file 'tests/service-mocks/DBusPropertiesNotifier.h' |
4649 | --- tests/service-mocks/DBusPropertiesNotifier.h 1970-01-01 00:00:00 +0000 |
4650 | +++ tests/service-mocks/DBusPropertiesNotifier.h 2015-10-01 13:45:49 +0000 |
4651 | @@ -0,0 +1,48 @@ |
4652 | +/* |
4653 | + * Copyright (C) 2015 Canonical, Ltd. |
4654 | + * |
4655 | + * This program is free software: you can redistribute it and/or modify it |
4656 | + * under the terms of the GNU General Public License version 3, as published |
4657 | + * by the Free Software Foundation. |
4658 | + * |
4659 | + * This program is distributed in the hope that it will be useful, but |
4660 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4661 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4662 | + * PURPOSE. See the GNU General Public License for more details. |
4663 | + * |
4664 | + * You should have received a copy of the GNU General Public License along |
4665 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4666 | + * |
4667 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4668 | + */ |
4669 | +#pragma once |
4670 | + |
4671 | +#include <QDBusConnection> |
4672 | + |
4673 | +namespace ubuntu |
4674 | +{ |
4675 | + |
4676 | +namespace indicators |
4677 | +{ |
4678 | + |
4679 | +namespace testing |
4680 | +{ |
4681 | + |
4682 | +class DBusPropertiesNotifier |
4683 | +{ |
4684 | +public: |
4685 | + DBusPropertiesNotifier() = default; |
4686 | + ~DBusPropertiesNotifier() = default; |
4687 | + |
4688 | + void notifyPropertyChanged(QDBusConnection const & connection, |
4689 | + QString const & interface, |
4690 | + QString const & path, |
4691 | + QString const & propertyName, |
4692 | + QVariant const & propertyValue); |
4693 | +}; |
4694 | + |
4695 | +} // namespace testing |
4696 | + |
4697 | +} // namespace indicators |
4698 | + |
4699 | +} // namespace ubuntu |
4700 | |
4701 | === added directory 'tests/service-mocks/accounts-mock' |
4702 | === added file 'tests/service-mocks/accounts-mock/AccountsDefs.h' |
4703 | --- tests/service-mocks/accounts-mock/AccountsDefs.h 1970-01-01 00:00:00 +0000 |
4704 | +++ tests/service-mocks/accounts-mock/AccountsDefs.h 2015-10-01 13:45:49 +0000 |
4705 | @@ -0,0 +1,37 @@ |
4706 | +/* |
4707 | + * Copyright (C) 2015 Canonical, Ltd. |
4708 | + * |
4709 | + * This program is free software: you can redistribute it and/or modify it |
4710 | + * under the terms of the GNU General Public License version 3, as published |
4711 | + * by the Free Software Foundation. |
4712 | + * |
4713 | + * This program is distributed in the hope that it will be useful, but |
4714 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4715 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4716 | + * PURPOSE. See the GNU General Public License for more details. |
4717 | + * |
4718 | + * You should have received a copy of the GNU General Public License along |
4719 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4720 | + * |
4721 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4722 | + */ |
4723 | +#pragma once |
4724 | + |
4725 | +namespace ubuntu |
4726 | +{ |
4727 | + |
4728 | +namespace indicators |
4729 | +{ |
4730 | + |
4731 | +namespace testing |
4732 | +{ |
4733 | + constexpr const char ACCOUNTS_SERVICE[] = "org.freedesktop.Accounts"; |
4734 | + constexpr const char USER_PATH[] = "/org/freedesktop/Accounts/UserTest"; |
4735 | + constexpr const char ACCOUNTS_PATH[] = "/org/freedesktop/Accounts"; |
4736 | + constexpr const char ACCOUNTS_SOUND_INTERFACE[] = "com.ubuntu.AccountsService.Sound"; |
4737 | +} // namespace testing |
4738 | + |
4739 | +} // namespace indicators |
4740 | + |
4741 | +} // namespace ubuntu |
4742 | + |
4743 | |
4744 | === added file 'tests/service-mocks/accounts-mock/AccountsMock.cpp' |
4745 | --- tests/service-mocks/accounts-mock/AccountsMock.cpp 1970-01-01 00:00:00 +0000 |
4746 | +++ tests/service-mocks/accounts-mock/AccountsMock.cpp 2015-10-01 13:45:49 +0000 |
4747 | @@ -0,0 +1,40 @@ |
4748 | +/* |
4749 | + * Copyright (C) 2015 Canonical, Ltd. |
4750 | + * |
4751 | + * This program is free software: you can redistribute it and/or modify it |
4752 | + * under the terms of the GNU General Public License version 3, as published |
4753 | + * by the Free Software Foundation. |
4754 | + * |
4755 | + * This program is distributed in the hope that it will be useful, but |
4756 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4757 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4758 | + * PURPOSE. See the GNU General Public License for more details. |
4759 | + * |
4760 | + * You should have received a copy of the GNU General Public License along |
4761 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4762 | + * |
4763 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4764 | + */ |
4765 | +#include <QDebug> |
4766 | + |
4767 | +#include "AccountsMock.h" |
4768 | +#include "AccountsDefs.h" |
4769 | + |
4770 | +using namespace ubuntu::indicators::testing; |
4771 | + |
4772 | +AccountsMock::AccountsMock(QObject* parent) |
4773 | + : QObject(parent) |
4774 | +{ |
4775 | +} |
4776 | + |
4777 | +AccountsMock::~AccountsMock() = default; |
4778 | + |
4779 | +QDBusObjectPath AccountsMock::FindUserByName(QString const & username) const |
4780 | +{ |
4781 | + return QDBusObjectPath(USER_PATH); |
4782 | +} |
4783 | + |
4784 | +QDBusObjectPath AccountsMock::FindUserById(int64_t uid) const |
4785 | +{ |
4786 | + return QDBusObjectPath(USER_PATH); |
4787 | +} |
4788 | |
4789 | === added file 'tests/service-mocks/accounts-mock/AccountsMock.h' |
4790 | --- tests/service-mocks/accounts-mock/AccountsMock.h 1970-01-01 00:00:00 +0000 |
4791 | +++ tests/service-mocks/accounts-mock/AccountsMock.h 2015-10-01 13:45:49 +0000 |
4792 | @@ -0,0 +1,50 @@ |
4793 | +/* |
4794 | + * Copyright (C) 2015 Canonical, Ltd. |
4795 | + * |
4796 | + * This program is free software: you can redistribute it and/or modify it |
4797 | + * under the terms of the GNU General Public License version 3, as published |
4798 | + * by the Free Software Foundation. |
4799 | + * |
4800 | + * This program is distributed in the hope that it will be useful, but |
4801 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4802 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4803 | + * PURPOSE. See the GNU General Public License for more details. |
4804 | + * |
4805 | + * You should have received a copy of the GNU General Public License along |
4806 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4807 | + * |
4808 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4809 | + */ |
4810 | +#pragma once |
4811 | + |
4812 | +#include <QDBusContext> |
4813 | +#include <QDBusObjectPath> |
4814 | +#include <QObject> |
4815 | + |
4816 | +namespace ubuntu |
4817 | +{ |
4818 | + |
4819 | +namespace indicators |
4820 | +{ |
4821 | + |
4822 | +namespace testing |
4823 | +{ |
4824 | + |
4825 | +class AccountsMock : public QObject, protected QDBusContext |
4826 | +{ |
4827 | + Q_OBJECT |
4828 | + |
4829 | +public Q_SLOTS: |
4830 | + QDBusObjectPath FindUserByName(QString const & username) const; |
4831 | + QDBusObjectPath FindUserById(int64_t uid) const; |
4832 | + |
4833 | +public: |
4834 | + AccountsMock(QObject* parent = 0); |
4835 | + virtual ~AccountsMock(); |
4836 | +}; |
4837 | + |
4838 | +} // namespace testing |
4839 | + |
4840 | +} // namespace indicators |
4841 | + |
4842 | +} // namespace ubuntu |
4843 | |
4844 | === added file 'tests/service-mocks/accounts-mock/AccountsServiceSoundMock.cpp' |
4845 | --- tests/service-mocks/accounts-mock/AccountsServiceSoundMock.cpp 1970-01-01 00:00:00 +0000 |
4846 | +++ tests/service-mocks/accounts-mock/AccountsServiceSoundMock.cpp 2015-10-01 13:45:49 +0000 |
4847 | @@ -0,0 +1,48 @@ |
4848 | +/* |
4849 | + * Copyright (C) 2015 Canonical, Ltd. |
4850 | + * |
4851 | + * This program is free software: you can redistribute it and/or modify it |
4852 | + * under the terms of the GNU General Public License version 3, as published |
4853 | + * by the Free Software Foundation. |
4854 | + * |
4855 | + * This program is distributed in the hope that it will be useful, but |
4856 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4857 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4858 | + * PURPOSE. See the GNU General Public License for more details. |
4859 | + * |
4860 | + * You should have received a copy of the GNU General Public License along |
4861 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4862 | + * |
4863 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4864 | + */ |
4865 | +#include <QDebug> |
4866 | +#include <QDBusMessage> |
4867 | +#include <QDBusConnection> |
4868 | + |
4869 | +#include "AccountsServiceSoundMock.h" |
4870 | +#include "AccountsDefs.h" |
4871 | + |
4872 | +using namespace ubuntu::indicators::testing; |
4873 | + |
4874 | +AccountsServiceSoundMock::AccountsServiceSoundMock(QObject* parent) |
4875 | + : QObject(parent) |
4876 | + , volume_(0.0) |
4877 | +{ |
4878 | +} |
4879 | + |
4880 | +AccountsServiceSoundMock::~AccountsServiceSoundMock() = default; |
4881 | + |
4882 | +double AccountsServiceSoundMock::volume() const |
4883 | +{ |
4884 | + return volume_; |
4885 | +} |
4886 | + |
4887 | +void AccountsServiceSoundMock::setVolume(double volume) |
4888 | +{ |
4889 | + volume_ = volume; |
4890 | + notifier_.notifyPropertyChanged(QDBusConnection::systemBus(), |
4891 | + ACCOUNTS_SOUND_INTERFACE, |
4892 | + USER_PATH, |
4893 | + "Volume", |
4894 | + property("Volume")); |
4895 | +} |
4896 | |
4897 | === added file 'tests/service-mocks/accounts-mock/AccountsServiceSoundMock.h' |
4898 | --- tests/service-mocks/accounts-mock/AccountsServiceSoundMock.h 1970-01-01 00:00:00 +0000 |
4899 | +++ tests/service-mocks/accounts-mock/AccountsServiceSoundMock.h 2015-10-01 13:45:49 +0000 |
4900 | @@ -0,0 +1,58 @@ |
4901 | +/* |
4902 | + * Copyright (C) 2015 Canonical, Ltd. |
4903 | + * |
4904 | + * This program is free software: you can redistribute it and/or modify it |
4905 | + * under the terms of the GNU General Public License version 3, as published |
4906 | + * by the Free Software Foundation. |
4907 | + * |
4908 | + * This program is distributed in the hope that it will be useful, but |
4909 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4910 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4911 | + * PURPOSE. See the GNU General Public License for more details. |
4912 | + * |
4913 | + * You should have received a copy of the GNU General Public License along |
4914 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4915 | + * |
4916 | + * Author: Xavi Garcia <xavi.garcia.mena@canonical.com> |
4917 | + */ |
4918 | +#pragma once |
4919 | + |
4920 | +#include <QDBusContext> |
4921 | +#include <QObject> |
4922 | + |
4923 | +#include "DBusPropertiesNotifier.h" |
4924 | + |
4925 | +namespace ubuntu |
4926 | +{ |
4927 | + |
4928 | +namespace indicators |
4929 | +{ |
4930 | + |
4931 | +namespace testing |
4932 | +{ |
4933 | + |
4934 | +class DBusPropertiesNotifier; |
4935 | + |
4936 | +class AccountsServiceSoundMock : public QObject, protected QDBusContext |
4937 | +{ |
4938 | + Q_OBJECT |
4939 | + Q_PROPERTY(double Volume READ volume WRITE setVolume) |
4940 | + |
4941 | +public Q_SLOTS: |
4942 | + double volume() const; |
4943 | + void setVolume(double volume); |
4944 | + |
4945 | +public: |
4946 | + AccountsServiceSoundMock(QObject* parent = 0); |
4947 | + virtual ~AccountsServiceSoundMock(); |
4948 | + |
4949 | +private: |
4950 | + double volume_; |
4951 | + DBusPropertiesNotifier notifier_; |
4952 | +}; |
4953 | + |
4954 | +} // namespace testing |
4955 | + |
4956 | +} // namespace indicators |
4957 | + |
4958 | +} // namespace ubuntu |
4959 | |
4960 | === added file 'tests/service-mocks/accounts-mock/CMakeLists.txt' |
4961 | --- tests/service-mocks/accounts-mock/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4962 | +++ tests/service-mocks/accounts-mock/CMakeLists.txt 2015-10-01 13:45:49 +0000 |
4963 | @@ -0,0 +1,42 @@ |
4964 | +set(CMAKE_AUTOMOC ON) |
4965 | +set(CMAKE_INCLUDE_CURRENT_DIR ON) |
4966 | + |
4967 | +find_package(Qt5DBus REQUIRED) |
4968 | +include_directories(${Qt5DBus_INCLUDE_DIRS} |
4969 | + "${CMAKE_SOURCE_DIR}/tests/service-mocks") |
4970 | + |
4971 | +add_definitions(-DQT_NO_KEYWORDS=1) |
4972 | + |
4973 | +set(dbusinterface_sound_xml "com.ubuntu.AccountsService.Sound.Mock.xml") |
4974 | +set_source_files_properties(${dbusinterface_sound_xml} PROPERTIES |
4975 | + CLASSNAME AccountsServiceSoundMockInterface) |
4976 | + |
4977 | +qt5_add_dbus_interface(interface_files ${dbusinterface_sound_xml} accountsservice_sound_interface) |
4978 | + |
4979 | +qt5_add_dbus_adaptor(adaptor_files |
4980 | + com.ubuntu.AccountsService.Sound.Mock.xml |
4981 | + AccountsServiceSoundMock.h |
4982 | + ubuntu::indicators::testing::AccountsServiceSoundMock |
4983 | + AccountsServiceSoundMockAdaptor) |
4984 | + |
4985 | +qt5_add_dbus_adaptor(adaptor_files |
4986 | + org.freedesktop.Accounts.Mock.xml |
4987 | + AccountsMock.h |
4988 | + ubuntu::indicators::testing::AccountsMock |
4989 | + AccountsMockAdaptor) |
4990 | + |
4991 | +add_executable( |
4992 | + accounts-service-sound |
4993 | + ${interface_files} |
4994 | + ${adaptor_files} |
4995 | + AccountsServiceSoundMock.cpp |
4996 | + AccountsMock.cpp |
4997 | + ${CMAKE_SOURCE_DIR}/tests/service-mocks/DBusPropertiesNotifier.cpp |
4998 | + main.cpp |
4999 | +) |
5000 | + |
FAILED: Continuous integration, rev:504 jenkins. qa.ubuntu. com/job/ indicator- sound-ci/ 240/ jenkins. qa.ubuntu. com/job/ indicator- sound-wily- amd64-ci/ 16/console jenkins. qa.ubuntu. com/job/ indicator- sound-wily- armhf-ci/ 16/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/indicator- sound-ci/ 240/rebuild
http://