Merge lp:~xavi-garcia-mena/indicator-sound/bug-1213907-active-players-playback-control-unit-tests into lp:indicator-sound/15.10
- bug-1213907-active-players-playback-control-unit-tests
- Merge into trunk.15.10
Status: | Needs review |
---|---|
Proposed branch: | lp:~xavi-garcia-mena/indicator-sound/bug-1213907-active-players-playback-control-unit-tests |
Merge into: | lp:indicator-sound/15.10 |
Diff against target: |
750 lines (+682/-0) 7 files modified
tests/integration/CMakeLists.txt (+1/-0) tests/integration/indicator-sound-test-base.cpp (+5/-0) tests/integration/indicator-sound-test-base.h (+1/-0) tests/integration/test-indicator.cpp (+274/-0) tests/integration/utils/gobj_memory.h (+200/-0) tests/integration/utils/gsettings.cpp (+149/-0) tests/integration/utils/gsettings.h (+52/-0) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/indicator-sound/bug-1213907-active-players-playback-control-unit-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charles Kerr (community) | Needs Information | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+286183@code.launchpad.net |
Commit message
This branch adds extra integration tests to the recently landed branch https:/
It adds GSettings tests and checks the last-running-player property.
Description of the change
This branch adds extra integration tests to the recently landed branch https:/
It adds GSettings tests and checks the last-running-player property.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 529. By Xavi Garcia
-
Integration test moved
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:529
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Charles Kerr (charlesk) wrote : | # |
Comments inline
Unmerged revisions
- 529. By Xavi Garcia
-
Integration test moved
- 528. By Xavi Garcia
-
Added integration tests
Preview Diff
1 | === modified file 'tests/integration/CMakeLists.txt' | |||
2 | --- tests/integration/CMakeLists.txt 2015-12-23 13:35:46 +0000 | |||
3 | +++ tests/integration/CMakeLists.txt 2016-02-17 09:23:14 +0000 | |||
4 | @@ -51,6 +51,7 @@ | |||
5 | 51 | indicator-sound-test-base.cpp | 51 | indicator-sound-test-base.cpp |
6 | 52 | test-indicator.cpp | 52 | test-indicator.cpp |
7 | 53 | utils/dbus-pulse-volume.cpp | 53 | utils/dbus-pulse-volume.cpp |
8 | 54 | utils/gsettings.cpp | ||
9 | 54 | main.cpp | 55 | main.cpp |
10 | 55 | ) | 56 | ) |
11 | 56 | 57 | ||
12 | 57 | 58 | ||
13 | === modified file 'tests/integration/indicator-sound-test-base.cpp' | |||
14 | --- tests/integration/indicator-sound-test-base.cpp 2016-01-29 11:16:34 +0000 | |||
15 | +++ tests/integration/indicator-sound-test-base.cpp 2016-02-17 09:23:14 +0000 | |||
16 | @@ -380,6 +380,11 @@ | |||
17 | 380 | } | 380 | } |
18 | 381 | } | 381 | } |
19 | 382 | 382 | ||
20 | 383 | void IndicatorSoundTestBase::stopIndicator() | ||
21 | 384 | { | ||
22 | 385 | indicator.reset(); | ||
23 | 386 | } | ||
24 | 387 | |||
25 | 383 | mh::MenuMatcher::Parameters IndicatorSoundTestBase::desktopParameters() | 388 | mh::MenuMatcher::Parameters IndicatorSoundTestBase::desktopParameters() |
26 | 384 | { | 389 | { |
27 | 385 | return mh::MenuMatcher::Parameters( | 390 | return mh::MenuMatcher::Parameters( |
28 | 386 | 391 | ||
29 | === modified file 'tests/integration/indicator-sound-test-base.h' | |||
30 | --- tests/integration/indicator-sound-test-base.h 2016-01-29 11:16:34 +0000 | |||
31 | +++ tests/integration/indicator-sound-test-base.h 2016-02-17 09:23:14 +0000 | |||
32 | @@ -72,6 +72,7 @@ | |||
33 | 72 | void TearDown() override; | 72 | void TearDown() override; |
34 | 73 | 73 | ||
35 | 74 | void startIndicator(); | 74 | void startIndicator(); |
36 | 75 | void stopIndicator(); | ||
37 | 75 | void startPulseDesktop(DevicePortType speakerPort=WIRED, DevicePortType headphonesPort=WIRED); | 76 | void startPulseDesktop(DevicePortType speakerPort=WIRED, DevicePortType headphonesPort=WIRED); |
38 | 76 | void startPulsePhone(DevicePortType speakerPort=WIRED, DevicePortType headphonesPort=WIRED); | 77 | void startPulsePhone(DevicePortType speakerPort=WIRED, DevicePortType headphonesPort=WIRED); |
39 | 77 | void startAccountsService(); | 78 | void startAccountsService(); |
40 | 78 | 79 | ||
41 | === modified file 'tests/integration/test-indicator.cpp' | |||
42 | --- tests/integration/test-indicator.cpp 2016-02-10 13:08:49 +0000 | |||
43 | +++ tests/integration/test-indicator.cpp 2016-02-17 09:23:14 +0000 | |||
44 | @@ -17,11 +17,15 @@ | |||
45 | 17 | */ | 17 | */ |
46 | 18 | 18 | ||
47 | 19 | #include <indicator-sound-test-base.h> | 19 | #include <indicator-sound-test-base.h> |
48 | 20 | #include <utils/gsettings.h> | ||
49 | 20 | 21 | ||
50 | 21 | #include <QDebug> | 22 | #include <QDebug> |
51 | 22 | #include <QTestEventLoop> | 23 | #include <QTestEventLoop> |
52 | 23 | #include <QSignalSpy> | 24 | #include <QSignalSpy> |
53 | 24 | 25 | ||
54 | 26 | #include <chrono> | ||
55 | 27 | #include <thread> | ||
56 | 28 | |||
57 | 25 | using namespace std; | 29 | using namespace std; |
58 | 26 | using namespace testing; | 30 | using namespace testing; |
59 | 27 | namespace mh = unity::gmenuharness; | 31 | namespace mh = unity::gmenuharness; |
60 | @@ -1553,4 +1557,274 @@ | |||
61 | 1553 | checkPortDevicesLabels(HDMI, HDMI); | 1557 | checkPortDevicesLabels(HDMI, HDMI); |
62 | 1554 | } | 1558 | } |
63 | 1555 | 1559 | ||
64 | 1560 | TEST_F(TestIndicator, DesktopMprisPlayersPlaybackControlsActive) | ||
65 | 1561 | { | ||
66 | 1562 | double INITIAL_VOLUME = 0.0; | ||
67 | 1563 | |||
68 | 1564 | ASSERT_NO_THROW(startAccountsService()); | ||
69 | 1565 | EXPECT_TRUE(clearGSettingsPlayers()); | ||
70 | 1566 | ASSERT_NO_THROW(startPulseDesktop()); | ||
71 | 1567 | |||
72 | 1568 | // initialize volumes in pulseaudio | ||
73 | 1569 | EXPECT_FALSE(setStreamRestoreVolume("alert", INITIAL_VOLUME)); | ||
74 | 1570 | EXPECT_TRUE(setSinkVolume(INITIAL_VOLUME)); | ||
75 | 1571 | |||
76 | 1572 | // start the test player | ||
77 | 1573 | EXPECT_TRUE(startTestMprisPlayer("testplayer1")); | ||
78 | 1574 | |||
79 | 1575 | // start now the indicator, so it picks the new volumes | ||
80 | 1576 | ASSERT_NO_THROW(startIndicator()); | ||
81 | 1577 | |||
82 | 1578 | // check that the player is added | ||
83 | 1579 | EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) | ||
84 | 1580 | .item(mh::MenuItemMatcher() | ||
85 | 1581 | .action("indicator.root") | ||
86 | 1582 | .string_attribute("x-canonical-type", "com.canonical.indicator.root") | ||
87 | 1583 | .string_attribute("x-canonical-secondary-action", "indicator.mute") | ||
88 | 1584 | .mode(mh::MenuItemMatcher::Mode::all) | ||
89 | 1585 | .submenu() | ||
90 | 1586 | .item(mh::MenuItemMatcher() | ||
91 | 1587 | .section() | ||
92 | 1588 | .item(mh::MenuItemMatcher().checkbox() | ||
93 | 1589 | .label("Mute") | ||
94 | 1590 | ) | ||
95 | 1591 | .item(volumeSlider(INITIAL_VOLUME, "Volume")) | ||
96 | 1592 | ) | ||
97 | 1593 | .item(mh::MenuItemMatcher() | ||
98 | 1594 | .section() | ||
99 | 1595 | .item(mh::MenuItemMatcher() | ||
100 | 1596 | .action("indicator.testplayer1.desktop") | ||
101 | 1597 | .label("TestPlayer1") | ||
102 | 1598 | .themed_icon("icon", {"testplayer"}) | ||
103 | 1599 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
104 | 1600 | ) | ||
105 | 1601 | .item(mh::MenuItemMatcher() | ||
106 | 1602 | .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") | ||
107 | 1603 | .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") | ||
108 | 1604 | .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") | ||
109 | 1605 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
110 | 1606 | ) | ||
111 | 1607 | ) | ||
112 | 1608 | .item(mh::MenuItemMatcher() | ||
113 | 1609 | .label("Sound Settingsā¦") | ||
114 | 1610 | ) | ||
115 | 1611 | ).match()); | ||
116 | 1612 | |||
117 | 1613 | // start the second test player | ||
118 | 1614 | EXPECT_TRUE(startTestMprisPlayer("testplayer2")); | ||
119 | 1615 | |||
120 | 1616 | // check that the player is added | ||
121 | 1617 | EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) | ||
122 | 1618 | .item(mh::MenuItemMatcher() | ||
123 | 1619 | .action("indicator.root") | ||
124 | 1620 | .string_attribute("x-canonical-type", "com.canonical.indicator.root") | ||
125 | 1621 | .string_attribute("x-canonical-secondary-action", "indicator.mute") | ||
126 | 1622 | .mode(mh::MenuItemMatcher::Mode::all) | ||
127 | 1623 | .submenu() | ||
128 | 1624 | .item(mh::MenuItemMatcher() | ||
129 | 1625 | .section() | ||
130 | 1626 | .item(mh::MenuItemMatcher().checkbox() | ||
131 | 1627 | .label("Mute") | ||
132 | 1628 | ) | ||
133 | 1629 | .item(volumeSlider(INITIAL_VOLUME, "Volume")) | ||
134 | 1630 | ) | ||
135 | 1631 | .item(mh::MenuItemMatcher() | ||
136 | 1632 | .section() | ||
137 | 1633 | .item(mh::MenuItemMatcher() | ||
138 | 1634 | .action("indicator.testplayer1.desktop") | ||
139 | 1635 | .label("TestPlayer1") | ||
140 | 1636 | .themed_icon("icon", {"testplayer"}) | ||
141 | 1637 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
142 | 1638 | ) | ||
143 | 1639 | .item(mh::MenuItemMatcher() | ||
144 | 1640 | .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") | ||
145 | 1641 | .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") | ||
146 | 1642 | .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") | ||
147 | 1643 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
148 | 1644 | ) | ||
149 | 1645 | ) | ||
150 | 1646 | .item(mh::MenuItemMatcher() | ||
151 | 1647 | .section() | ||
152 | 1648 | .item(mh::MenuItemMatcher() | ||
153 | 1649 | .action("indicator.testplayer2.desktop") | ||
154 | 1650 | .label("TestPlayer2") | ||
155 | 1651 | .themed_icon("icon", {"testplayer"}) | ||
156 | 1652 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
157 | 1653 | ) | ||
158 | 1654 | .item(mh::MenuItemMatcher() | ||
159 | 1655 | .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") | ||
160 | 1656 | .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") | ||
161 | 1657 | .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") | ||
162 | 1658 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
163 | 1659 | ) | ||
164 | 1660 | ) | ||
165 | 1661 | .item(mh::MenuItemMatcher() | ||
166 | 1662 | .label("Sound Settingsā¦") | ||
167 | 1663 | ) | ||
168 | 1664 | ).match()); | ||
169 | 1665 | |||
170 | 1666 | // stop the first player | ||
171 | 1667 | EXPECT_TRUE(stopTestMprisPlayer("testplayer1")); | ||
172 | 1668 | |||
173 | 1669 | // check that the player's playback controls are removed | ||
174 | 1670 | EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) | ||
175 | 1671 | .item(mh::MenuItemMatcher() | ||
176 | 1672 | .action("indicator.root") | ||
177 | 1673 | .string_attribute("x-canonical-type", "com.canonical.indicator.root") | ||
178 | 1674 | .string_attribute("x-canonical-secondary-action", "indicator.mute") | ||
179 | 1675 | .mode(mh::MenuItemMatcher::Mode::all) | ||
180 | 1676 | .submenu() | ||
181 | 1677 | .item(mh::MenuItemMatcher() | ||
182 | 1678 | .section() | ||
183 | 1679 | .item(mh::MenuItemMatcher().checkbox() | ||
184 | 1680 | .label("Mute") | ||
185 | 1681 | ) | ||
186 | 1682 | .item(volumeSlider(INITIAL_VOLUME, "Volume")) | ||
187 | 1683 | ) | ||
188 | 1684 | .item(mh::MenuItemMatcher() | ||
189 | 1685 | .section() | ||
190 | 1686 | .item(mh::MenuItemMatcher() | ||
191 | 1687 | .action("indicator.testplayer1.desktop") | ||
192 | 1688 | .label("TestPlayer1") | ||
193 | 1689 | .themed_icon("icon", {"testplayer"}) | ||
194 | 1690 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
195 | 1691 | ) | ||
196 | 1692 | ) | ||
197 | 1693 | .item(mh::MenuItemMatcher() | ||
198 | 1694 | .section() | ||
199 | 1695 | .item(mh::MenuItemMatcher() | ||
200 | 1696 | .action("indicator.testplayer2.desktop") | ||
201 | 1697 | .label("TestPlayer2") | ||
202 | 1698 | .themed_icon("icon", {"testplayer"}) | ||
203 | 1699 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
204 | 1700 | ) | ||
205 | 1701 | .item(mh::MenuItemMatcher() | ||
206 | 1702 | .string_attribute("x-canonical-previous-action","indicator.previous.testplayer2.desktop") | ||
207 | 1703 | .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") | ||
208 | 1704 | .string_attribute("x-canonical-next-action","indicator.next.testplayer2.desktop") | ||
209 | 1705 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
210 | 1706 | ) | ||
211 | 1707 | ) | ||
212 | 1708 | .item(mh::MenuItemMatcher() | ||
213 | 1709 | .label("Sound Settingsā¦") | ||
214 | 1710 | ) | ||
215 | 1711 | ).match()); | ||
216 | 1712 | |||
217 | 1713 | // stop the second player (it should be the last running one) | ||
218 | 1714 | EXPECT_TRUE(stopTestMprisPlayer("testplayer2")); | ||
219 | 1715 | |||
220 | 1716 | // verify the players with gsettings | ||
221 | 1717 | Settings settings; | ||
222 | 1718 | |||
223 | 1719 | int timeout = 1000; | ||
224 | 1720 | while (settings.get_last_running_player() != "testplayer2.desktop" && timeout) | ||
225 | 1721 | { | ||
226 | 1722 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
227 | 1723 | timeout -= 500; | ||
228 | 1724 | } | ||
229 | 1725 | EXPECT_EQ("testplayer2.desktop", settings.get_last_running_player()); | ||
230 | 1726 | |||
231 | 1727 | timeout = 1000; | ||
232 | 1728 | while (settings.get_interested_media_players() != "[[ testplayer1.desktop ][ testplayer2.desktop ]]" && timeout) | ||
233 | 1729 | { | ||
234 | 1730 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
235 | 1731 | timeout -= 500; | ||
236 | 1732 | } | ||
237 | 1733 | EXPECT_EQ("[[ testplayer1.desktop ][ testplayer2.desktop ]]", settings.get_interested_media_players()); | ||
238 | 1734 | |||
239 | 1735 | // restart the indicator | ||
240 | 1736 | // we should get the player 2 as the one with playback constrols. | ||
241 | 1737 | // In this case we only have the play button as the player is not running yet. | ||
242 | 1738 | startIndicator(); | ||
243 | 1739 | |||
244 | 1740 | // check that the player 2 has the playback controls with play set. | ||
245 | 1741 | EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) | ||
246 | 1742 | .item(mh::MenuItemMatcher() | ||
247 | 1743 | .action("indicator.root") | ||
248 | 1744 | .string_attribute("x-canonical-type", "com.canonical.indicator.root") | ||
249 | 1745 | .string_attribute("x-canonical-secondary-action", "indicator.mute") | ||
250 | 1746 | .mode(mh::MenuItemMatcher::Mode::all) | ||
251 | 1747 | .submenu() | ||
252 | 1748 | .item(mh::MenuItemMatcher() | ||
253 | 1749 | .section() | ||
254 | 1750 | .item(mh::MenuItemMatcher().checkbox() | ||
255 | 1751 | .label("Mute") | ||
256 | 1752 | ) | ||
257 | 1753 | .item(volumeSlider(INITIAL_VOLUME, "Volume")) | ||
258 | 1754 | ) | ||
259 | 1755 | .item(mh::MenuItemMatcher() | ||
260 | 1756 | .section() | ||
261 | 1757 | .item(mh::MenuItemMatcher() | ||
262 | 1758 | .action("indicator.testplayer1.desktop") | ||
263 | 1759 | .label("TestPlayer1") | ||
264 | 1760 | .themed_icon("icon", {"testplayer"}) | ||
265 | 1761 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
266 | 1762 | ) | ||
267 | 1763 | ) | ||
268 | 1764 | .item(mh::MenuItemMatcher() | ||
269 | 1765 | .section() | ||
270 | 1766 | .item(mh::MenuItemMatcher() | ||
271 | 1767 | .action("indicator.testplayer2.desktop") | ||
272 | 1768 | .label("TestPlayer2") | ||
273 | 1769 | .themed_icon("icon", {"testplayer"}) | ||
274 | 1770 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
275 | 1771 | ) | ||
276 | 1772 | .item(mh::MenuItemMatcher() | ||
277 | 1773 | .string_attribute("x-canonical-play-action","indicator.play.testplayer2.desktop") | ||
278 | 1774 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
279 | 1775 | ) | ||
280 | 1776 | ) | ||
281 | 1777 | .item(mh::MenuItemMatcher() | ||
282 | 1778 | .label("Sound Settingsā¦") | ||
283 | 1779 | ) | ||
284 | 1780 | ).match()); | ||
285 | 1781 | |||
286 | 1782 | // now start the other player. | ||
287 | 1783 | // that should change the playback controls shown from player 2 to player 1 | ||
288 | 1784 | EXPECT_TRUE(startTestMprisPlayer("testplayer1")); | ||
289 | 1785 | |||
290 | 1786 | EXPECT_MATCHRESULT(mh::MenuMatcher(desktopParameters()) | ||
291 | 1787 | .item(mh::MenuItemMatcher() | ||
292 | 1788 | .action("indicator.root") | ||
293 | 1789 | .string_attribute("x-canonical-type", "com.canonical.indicator.root") | ||
294 | 1790 | .string_attribute("x-canonical-secondary-action", "indicator.mute") | ||
295 | 1791 | .mode(mh::MenuItemMatcher::Mode::all) | ||
296 | 1792 | .submenu() | ||
297 | 1793 | .item(mh::MenuItemMatcher() | ||
298 | 1794 | .section() | ||
299 | 1795 | .item(mh::MenuItemMatcher().checkbox() | ||
300 | 1796 | .label("Mute") | ||
301 | 1797 | ) | ||
302 | 1798 | .item(volumeSlider(INITIAL_VOLUME, "Volume")) | ||
303 | 1799 | ) | ||
304 | 1800 | .item(mh::MenuItemMatcher() | ||
305 | 1801 | .section() | ||
306 | 1802 | .item(mh::MenuItemMatcher() | ||
307 | 1803 | .action("indicator.testplayer1.desktop") | ||
308 | 1804 | .label("TestPlayer1") | ||
309 | 1805 | .themed_icon("icon", {"testplayer"}) | ||
310 | 1806 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
311 | 1807 | ) | ||
312 | 1808 | .item(mh::MenuItemMatcher() | ||
313 | 1809 | .string_attribute("x-canonical-previous-action","indicator.previous.testplayer1.desktop") | ||
314 | 1810 | .string_attribute("x-canonical-play-action","indicator.play.testplayer1.desktop") | ||
315 | 1811 | .string_attribute("x-canonical-next-action","indicator.next.testplayer1.desktop") | ||
316 | 1812 | .string_attribute("x-canonical-type","com.canonical.unity.playback-item") | ||
317 | 1813 | ) | ||
318 | 1814 | ) | ||
319 | 1815 | .item(mh::MenuItemMatcher() | ||
320 | 1816 | .section() | ||
321 | 1817 | .item(mh::MenuItemMatcher() | ||
322 | 1818 | .action("indicator.testplayer2.desktop") | ||
323 | 1819 | .label("TestPlayer2") | ||
324 | 1820 | .themed_icon("icon", {"testplayer"}) | ||
325 | 1821 | .string_attribute("x-canonical-type", "com.canonical.unity.media-player") | ||
326 | 1822 | ) | ||
327 | 1823 | ) | ||
328 | 1824 | .item(mh::MenuItemMatcher() | ||
329 | 1825 | .label("Sound Settingsā¦") | ||
330 | 1826 | ) | ||
331 | 1827 | ).match()); | ||
332 | 1828 | } | ||
333 | 1829 | |||
334 | 1556 | } // namespace | 1830 | } // namespace |
335 | 1557 | 1831 | ||
336 | === added file 'tests/integration/utils/gobj_memory.h' | |||
337 | --- tests/integration/utils/gobj_memory.h 1970-01-01 00:00:00 +0000 | |||
338 | +++ tests/integration/utils/gobj_memory.h 2016-02-17 09:23:14 +0000 | |||
339 | @@ -0,0 +1,200 @@ | |||
340 | 1 | /* | ||
341 | 2 | * Copyright (C) 2013 Canonical Ltd. | ||
342 | 3 | * | ||
343 | 4 | * This program is free software: you can redistribute it and/or modify | ||
344 | 5 | * it under the terms of the GNU Lesser General Public License version 3 as | ||
345 | 6 | * published by the Free Software Foundation. | ||
346 | 7 | * | ||
347 | 8 | * This program is distributed in the hope that it will be useful, | ||
348 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
349 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
350 | 11 | * GNU Lesser General Public License for more details. | ||
351 | 12 | * | ||
352 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
353 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
354 | 15 | * | ||
355 | 16 | * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com> | ||
356 | 17 | */ | ||
357 | 18 | |||
358 | 19 | #pragma once | ||
359 | 20 | |||
360 | 21 | #include <stdexcept> | ||
361 | 22 | |||
362 | 23 | #pragma GCC diagnostic push | ||
363 | 24 | #pragma GCC diagnostic ignored "-Wold-style-cast" | ||
364 | 25 | #pragma GCC diagnostic ignored "-Wcast-qual" | ||
365 | 26 | #include <glib-object.h> | ||
366 | 27 | |||
367 | 28 | #include <iostream> | ||
368 | 29 | |||
369 | 30 | /** | ||
370 | 31 | * This class is meant for automatically managing the lifetime of C objects derived | ||
371 | 32 | * from gobject. Its API perfectly mirrors the API of unique_ptr except that you | ||
372 | 33 | * can't define your own deleter function as it is always g_object_unref. | ||
373 | 34 | * | ||
374 | 35 | * API/ABI stability is not guaranteed. If you need to pass the object across an ABI | ||
375 | 36 | * boundary, pass the plain gobject. | ||
376 | 37 | * | ||
377 | 38 | * This is how you would use gobj_ptr 99% of the time: | ||
378 | 39 | * | ||
379 | 40 | * gobj_ptr<GSomeType> o(g_some_type_new(...)); | ||
380 | 41 | * | ||
381 | 42 | * More specifically, the object will decrement the gobject reference count | ||
382 | 43 | * of the object it points to when it goes out of scope. It will never increment it. | ||
383 | 44 | * Thus you should only assign to it when already holding a reference. gobj_ptr | ||
384 | 45 | * will then take ownership of that particular reference. | ||
385 | 46 | * | ||
386 | 47 | * Floating gobjects can not be put in this container as they are meant to be put | ||
387 | 48 | * into native gobject aware containers immediately upon construction. Trying to insert | ||
388 | 49 | * a floating gobject into a gobj_ptr will throw an invalid_argument exception. To | ||
389 | 50 | * prevent accidental memory leaks, the floating gobject is unreffed in this case. | ||
390 | 51 | */ | ||
391 | 52 | template <typename T> | ||
392 | 53 | class gobj_ptr final | ||
393 | 54 | { | ||
394 | 55 | private: | ||
395 | 56 | T* u; | ||
396 | 57 | |||
397 | 58 | void validate_float(T* t) | ||
398 | 59 | { | ||
399 | 60 | if (t != nullptr && g_object_is_floating(G_OBJECT(t))) | ||
400 | 61 | { | ||
401 | 62 | // LCOV_EXCL_START // False negative from gcovr. | ||
402 | 63 | throw std::invalid_argument("Tried to add a floating gobject into a gobj_ptr."); | ||
403 | 64 | // LCOV_EXCL_STOP | ||
404 | 65 | } | ||
405 | 66 | } | ||
406 | 67 | |||
407 | 68 | public: | ||
408 | 69 | typedef T element_type; | ||
409 | 70 | typedef T* pointer; | ||
410 | 71 | typedef decltype(g_object_unref) deleter_type; | ||
411 | 72 | |||
412 | 73 | constexpr gobj_ptr() noexcept : u(nullptr) | ||
413 | 74 | { | ||
414 | 75 | } | ||
415 | 76 | explicit gobj_ptr(T* t) | ||
416 | 77 | : u(t) | ||
417 | 78 | { | ||
418 | 79 | // What should we do if validate throws? Unreffing unknown objs | ||
419 | 80 | // is dodgy but not unreffing runs the risk of | ||
420 | 81 | // memory leaks. Currently unrefs as u is destroyed | ||
421 | 82 | // when this exception is thrown. | ||
422 | 83 | validate_float(t); | ||
423 | 84 | } | ||
424 | 85 | constexpr gobj_ptr(std::nullptr_t) noexcept : u(nullptr){}; | ||
425 | 86 | gobj_ptr(gobj_ptr&& o) noexcept | ||
426 | 87 | { | ||
427 | 88 | u = o.u; | ||
428 | 89 | o.u = nullptr; | ||
429 | 90 | } | ||
430 | 91 | gobj_ptr(const gobj_ptr& o) | ||
431 | 92 | : u(nullptr) | ||
432 | 93 | { | ||
433 | 94 | *this = o; | ||
434 | 95 | } | ||
435 | 96 | gobj_ptr& operator=(const gobj_ptr& o) | ||
436 | 97 | { | ||
437 | 98 | if (o.u != nullptr) | ||
438 | 99 | { | ||
439 | 100 | g_object_ref(o.u); | ||
440 | 101 | } | ||
441 | 102 | reset(o.u); | ||
442 | 103 | return *this; | ||
443 | 104 | } | ||
444 | 105 | ~gobj_ptr() | ||
445 | 106 | { | ||
446 | 107 | reset(); | ||
447 | 108 | } | ||
448 | 109 | |||
449 | 110 | deleter_type& get_deleter() noexcept | ||
450 | 111 | { | ||
451 | 112 | return g_object_unref; | ||
452 | 113 | } | ||
453 | 114 | deleter_type& get_deleter() const noexcept | ||
454 | 115 | { | ||
455 | 116 | return g_object_unref; | ||
456 | 117 | } | ||
457 | 118 | |||
458 | 119 | void swap(gobj_ptr<T>& o) noexcept | ||
459 | 120 | { | ||
460 | 121 | T* tmp = u; | ||
461 | 122 | u = o.u; | ||
462 | 123 | o.u = tmp; | ||
463 | 124 | } | ||
464 | 125 | void reset(pointer p = pointer()) | ||
465 | 126 | { | ||
466 | 127 | if (u != nullptr) | ||
467 | 128 | { | ||
468 | 129 | g_object_unref(G_OBJECT(u)); | ||
469 | 130 | u = nullptr; | ||
470 | 131 | } | ||
471 | 132 | // Same throw dilemma as in pointer constructor. | ||
472 | 133 | u = p; | ||
473 | 134 | validate_float(p); | ||
474 | 135 | } | ||
475 | 136 | |||
476 | 137 | T* release() noexcept | ||
477 | 138 | { | ||
478 | 139 | T* r = u; | ||
479 | 140 | u = nullptr; | ||
480 | 141 | return r; | ||
481 | 142 | } | ||
482 | 143 | T* get() const noexcept | ||
483 | 144 | { | ||
484 | 145 | return u; | ||
485 | 146 | } | ||
486 | 147 | |||
487 | 148 | T& operator*() const | ||
488 | 149 | { | ||
489 | 150 | return *u; | ||
490 | 151 | } | ||
491 | 152 | T* operator->() const noexcept | ||
492 | 153 | { | ||
493 | 154 | return u; | ||
494 | 155 | } | ||
495 | 156 | explicit operator bool() const noexcept | ||
496 | 157 | { | ||
497 | 158 | return u != nullptr; | ||
498 | 159 | } | ||
499 | 160 | |||
500 | 161 | gobj_ptr& operator=(gobj_ptr&& o) noexcept | ||
501 | 162 | { | ||
502 | 163 | reset(); | ||
503 | 164 | u = o.u; | ||
504 | 165 | o.u = nullptr; | ||
505 | 166 | return *this; | ||
506 | 167 | } | ||
507 | 168 | gobj_ptr& operator=(std::nullptr_t) noexcept | ||
508 | 169 | { | ||
509 | 170 | reset(); | ||
510 | 171 | return *this; | ||
511 | 172 | } | ||
512 | 173 | bool operator==(const gobj_ptr<T>& o) const noexcept | ||
513 | 174 | { | ||
514 | 175 | return u == o.u; | ||
515 | 176 | } | ||
516 | 177 | bool operator!=(const gobj_ptr<T>& o) const noexcept | ||
517 | 178 | { | ||
518 | 179 | return u != o.u; | ||
519 | 180 | } | ||
520 | 181 | bool operator<(const gobj_ptr<T>& o) const noexcept | ||
521 | 182 | { | ||
522 | 183 | return u < o.u; | ||
523 | 184 | } | ||
524 | 185 | bool operator<=(const gobj_ptr<T>& o) const noexcept | ||
525 | 186 | { | ||
526 | 187 | return u <= o.u; | ||
527 | 188 | } | ||
528 | 189 | bool operator>(const gobj_ptr<T>& o) const noexcept | ||
529 | 190 | { | ||
530 | 191 | return u > o.u; | ||
531 | 192 | } | ||
532 | 193 | bool operator>=(const gobj_ptr<T>& o) const noexcept | ||
533 | 194 | { | ||
534 | 195 | return u >= o.u; | ||
535 | 196 | } | ||
536 | 197 | }; | ||
537 | 198 | |||
538 | 199 | #pragma GCC diagnostic pop | ||
539 | 200 | |||
540 | 0 | 201 | ||
541 | === added file 'tests/integration/utils/gsettings.cpp' | |||
542 | --- tests/integration/utils/gsettings.cpp 1970-01-01 00:00:00 +0000 | |||
543 | +++ tests/integration/utils/gsettings.cpp 2016-02-17 09:23:14 +0000 | |||
544 | @@ -0,0 +1,149 @@ | |||
545 | 1 | /* | ||
546 | 2 | * Copyright (C) 2016 Canonical Ltd. | ||
547 | 3 | * | ||
548 | 4 | * This program is free software: you can redistribute it and/or modify | ||
549 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
550 | 6 | * published by the Free Software Foundation. | ||
551 | 7 | * | ||
552 | 8 | * This program is distributed in the hope that it will be useful, | ||
553 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
554 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
555 | 11 | * GNU General Public License for more details. | ||
556 | 12 | * | ||
557 | 13 | * You should have received a copy of the GNU General Public License | ||
558 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
559 | 15 | * | ||
560 | 16 | * Authored by: Xavi Garcia <xavi.garcia.mena@canonical.com> | ||
561 | 17 | */ | ||
562 | 18 | |||
563 | 19 | #include "gsettings.h" | ||
564 | 20 | |||
565 | 21 | //#include "settings-defaults.h" | ||
566 | 22 | |||
567 | 23 | #pragma GCC diagnostic push | ||
568 | 24 | #pragma GCC diagnostic ignored "-Wold-style-cast" | ||
569 | 25 | #pragma GCC diagnostic ignored "-Wcast-qual" | ||
570 | 26 | #include <gio/gio.h> | ||
571 | 27 | #pragma GCC diagnostic pop | ||
572 | 28 | #include <QDebug> | ||
573 | 29 | |||
574 | 30 | #include <memory> | ||
575 | 31 | |||
576 | 32 | using namespace std; | ||
577 | 33 | |||
578 | 34 | Settings::Settings() | ||
579 | 35 | : Settings("com.canonical.indicator.sound") | ||
580 | 36 | { | ||
581 | 37 | } | ||
582 | 38 | |||
583 | 39 | Settings::Settings(string const& schema_name) | ||
584 | 40 | : schema_(nullptr, &g_settings_schema_unref) | ||
585 | 41 | , schema_name_(schema_name) | ||
586 | 42 | { | ||
587 | 43 | GSettingsSchemaSource* src = g_settings_schema_source_get_default(); | ||
588 | 44 | schema_.reset(g_settings_schema_source_lookup(src, schema_name.c_str(), true)); | ||
589 | 45 | if (schema_) | ||
590 | 46 | { | ||
591 | 47 | settings_.reset(g_settings_new(schema_name.c_str())); | ||
592 | 48 | } | ||
593 | 49 | else | ||
594 | 50 | { | ||
595 | 51 | qCritical() << "The schema" << schema_name.c_str() << "is missing"; | ||
596 | 52 | } | ||
597 | 53 | } | ||
598 | 54 | |||
599 | 55 | Settings::~Settings() = default; | ||
600 | 56 | |||
601 | 57 | string Settings::get_last_running_player() const | ||
602 | 58 | { | ||
603 | 59 | return get_string("last-running-player", ""); | ||
604 | 60 | } | ||
605 | 61 | |||
606 | 62 | string Settings::get_interested_media_players() const | ||
607 | 63 | { | ||
608 | 64 | return get_string_array_as_string("interested-media-players", ""); | ||
609 | 65 | } | ||
610 | 66 | |||
611 | 67 | string Settings::get_string(char const* key, string const& default_value) const | ||
612 | 68 | { | ||
613 | 69 | if (!settings_ || !g_settings_schema_has_key(schema_.get(), key)) | ||
614 | 70 | { | ||
615 | 71 | return default_value; | ||
616 | 72 | } | ||
617 | 73 | |||
618 | 74 | char *value = g_settings_get_string(settings_.get(), key); | ||
619 | 75 | if (value) | ||
620 | 76 | { | ||
621 | 77 | string result = value; | ||
622 | 78 | g_free(value); | ||
623 | 79 | return result; | ||
624 | 80 | } | ||
625 | 81 | return default_value; // LCOV_EXCL_LINE | ||
626 | 82 | } | ||
627 | 83 | |||
628 | 84 | int Settings::get_positive_int(char const* key, int default_value) const | ||
629 | 85 | { | ||
630 | 86 | int i = get_int(key, default_value); | ||
631 | 87 | if (i <= 0) | ||
632 | 88 | { | ||
633 | 89 | throw domain_error(string("Settings::get_positive_int(): invalid zero or negative value for ") | ||
634 | 90 | + key + ": " + to_string(i) + " in schema " + schema_name_); | ||
635 | 91 | } | ||
636 | 92 | return i; | ||
637 | 93 | } | ||
638 | 94 | |||
639 | 95 | int Settings::get_positive_or_zero_int(char const* key, int default_value) const | ||
640 | 96 | { | ||
641 | 97 | int i = get_int(key, default_value); | ||
642 | 98 | if (i < 0) | ||
643 | 99 | { | ||
644 | 100 | throw domain_error(string("Settings::get_positive_or_zero_int(): invalid negative value for ") | ||
645 | 101 | + key + ": " + to_string(i) + " in schema " + schema_name_); | ||
646 | 102 | } | ||
647 | 103 | return i; | ||
648 | 104 | } | ||
649 | 105 | |||
650 | 106 | int Settings::get_int(char const* key, int default_value) const | ||
651 | 107 | { | ||
652 | 108 | if (!settings_ || !g_settings_schema_has_key(schema_.get(), key)) | ||
653 | 109 | { | ||
654 | 110 | return default_value; | ||
655 | 111 | } | ||
656 | 112 | |||
657 | 113 | return g_settings_get_int(settings_.get(), key); | ||
658 | 114 | } | ||
659 | 115 | |||
660 | 116 | bool Settings::get_bool(char const* key, bool default_value) const | ||
661 | 117 | { | ||
662 | 118 | if (!settings_ || !g_settings_schema_has_key(schema_.get(), key)) | ||
663 | 119 | { | ||
664 | 120 | return default_value; | ||
665 | 121 | } | ||
666 | 122 | |||
667 | 123 | return g_settings_get_boolean(settings_.get(), key); | ||
668 | 124 | } | ||
669 | 125 | |||
670 | 126 | std::string Settings::get_string_array_as_string(char const* key, std::string const& default_value) const | ||
671 | 127 | { | ||
672 | 128 | if (!settings_ || !g_settings_schema_has_key(schema_.get(), key)) | ||
673 | 129 | { | ||
674 | 130 | return default_value; | ||
675 | 131 | } | ||
676 | 132 | gchar **values; | ||
677 | 133 | values = g_settings_get_strv(settings_.get(), key); | ||
678 | 134 | if (!values) | ||
679 | 135 | { | ||
680 | 136 | return default_value; | ||
681 | 137 | } | ||
682 | 138 | int length = 0; | ||
683 | 139 | std::string res = "["; | ||
684 | 140 | while (((gpointer*) values)[length]) | ||
685 | 141 | { | ||
686 | 142 | std::string test(values[length]); | ||
687 | 143 | length++; | ||
688 | 144 | res += "[ " + test + " ]"; | ||
689 | 145 | } | ||
690 | 146 | res += "]"; | ||
691 | 147 | |||
692 | 148 | return res; | ||
693 | 149 | } | ||
694 | 0 | 150 | ||
695 | === added file 'tests/integration/utils/gsettings.h' | |||
696 | --- tests/integration/utils/gsettings.h 1970-01-01 00:00:00 +0000 | |||
697 | +++ tests/integration/utils/gsettings.h 2016-02-17 09:23:14 +0000 | |||
698 | @@ -0,0 +1,52 @@ | |||
699 | 1 | /* | ||
700 | 2 | * Copyright (C) 2016 Canonical Ltd. | ||
701 | 3 | * | ||
702 | 4 | * This program is free software: you can redistribute it and/or modify | ||
703 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
704 | 6 | * published by the Free Software Foundation. | ||
705 | 7 | * | ||
706 | 8 | * This program is distributed in the hope that it will be useful, | ||
707 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
708 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
709 | 11 | * GNU General Public License for more details. | ||
710 | 12 | * | ||
711 | 13 | * You should have received a copy of the GNU General Public License | ||
712 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
713 | 15 | * | ||
714 | 16 | * Authored by: Xavi Garcia <xavi.garcia.mena@canonical.com> | ||
715 | 17 | */ | ||
716 | 18 | |||
717 | 19 | #pragma once | ||
718 | 20 | |||
719 | 21 | #include "gobj_memory.h" | ||
720 | 22 | |||
721 | 23 | #include <memory> | ||
722 | 24 | #include <string> | ||
723 | 25 | |||
724 | 26 | typedef struct _GSettings GSettings; | ||
725 | 27 | typedef struct _GSettingsSchema GSettingsSchema; | ||
726 | 28 | |||
727 | 29 | class Settings | ||
728 | 30 | { | ||
729 | 31 | public: | ||
730 | 32 | Settings(); | ||
731 | 33 | // This constructor is only for use in the tests. | ||
732 | 34 | explicit Settings(std::string const& schema_name); | ||
733 | 35 | ~Settings(); | ||
734 | 36 | |||
735 | 37 | std::string get_last_running_player() const; | ||
736 | 38 | |||
737 | 39 | std::string get_interested_media_players() const; | ||
738 | 40 | |||
739 | 41 | private: | ||
740 | 42 | std::string get_string(char const* key, std::string const& default_value) const; | ||
741 | 43 | int get_positive_int(char const* key, int default_value) const; | ||
742 | 44 | int get_positive_or_zero_int(char const* key, int default_value) const; | ||
743 | 45 | int get_int(char const* key, int default_value) const; | ||
744 | 46 | bool get_bool(char const* key, bool default_value) const; | ||
745 | 47 | std::string get_string_array_as_string(char const* key, std::string const& default_value) const; | ||
746 | 48 | |||
747 | 49 | std::unique_ptr<GSettingsSchema, void(*)(GSettingsSchema*)> schema_; | ||
748 | 50 | std::string schema_name_; | ||
749 | 51 | gobj_ptr<GSettings> settings_; | ||
750 | 52 | }; |
FAILED: Continuous integration, rev:528 jenkins. qa.ubuntu. com/job/ indicator- sound-ci/ 310/ jenkins. qa.ubuntu. com/job/ indicator- sound-wily- amd64-ci/ 85/console jenkins. qa.ubuntu. com/job/ indicator- sound-wily- armhf-ci/ 86/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/indicator- sound-ci/ 310/rebuild
http://