Merge lp:~nataliabidart/magicicada-gui/set-initial-state into lp:magicicada-gui
- set-initial-state
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Facundo Batista | ||||||||
Approved revision: | 26 | ||||||||
Merged at revision: | 23 | ||||||||
Proposed branch: | lp:~nataliabidart/magicicada-gui/set-initial-state | ||||||||
Merge into: | lp:magicicada-gui | ||||||||
Diff against target: |
520 lines (+169/-100) 3 files modified
magicicada/__init__.py (+60/-35) magicicada/syncdaemon.py (+7/-0) magicicada/tests/test_magicicada.py (+102/-65) |
||||||||
To merge this branch: | bzr merge lp:~nataliabidart/magicicada-gui/set-initial-state | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
chicharreros | Pending | ||
Review via email: mp+25834@code.launchpad.net |
Commit message
Description of the change
GUI updates the initial state based on syncdaemon.
Also fixed some glitches on buttons sensitivity and visibility.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'magicicada/__init__.py' |
2 | --- magicicada/__init__.py 2010-05-22 03:19:12 +0000 |
3 | +++ magicicada/__init__.py 2010-05-23 10:42:26 +0000 |
4 | @@ -29,7 +29,7 @@ |
5 | gtk2reactor.install() |
6 | |
7 | from magicicada import syncdaemon |
8 | -from magicicada.helpers import get_data_file, get_builder, NO_OP |
9 | +from magicicada.helpers import get_data_file, get_builder, NO_OP, print_debug |
10 | |
11 | CONTENT_QUEUE = 'content' |
12 | META_QUEUE = 'meta' |
13 | @@ -39,7 +39,6 @@ |
14 | STATUS = { |
15 | 'started': _('Service started, click Connect to continue.'), |
16 | 'connected': _('Service connected. Doing internal synchronization...'), |
17 | - 'online': _('Service reached Nirvana.'), |
18 | } |
19 | |
20 | def __init__(self, launchpad_available=False, on_destroy=NO_OP, |
21 | @@ -96,6 +95,8 @@ |
22 | self.widget_enabled = lambda w: \ |
23 | w.get_property('visible') and w.is_sensitive() |
24 | |
25 | + self.update() |
26 | + |
27 | # GTK callbacks |
28 | |
29 | def on_main_window_destroy(self, widget, data=None): |
30 | @@ -118,10 +119,8 @@ |
31 | def on_start_clicked(self, widget, data=None): |
32 | """Start syncdaemon.""" |
33 | self.sd.start() |
34 | - self.start.hide() |
35 | - self.stop.set_sensitive(False) |
36 | - self.stop.show() |
37 | - self.start_loading(self.is_started) |
38 | + self.start.set_sensitive(False) |
39 | + self._start_loading(self.is_started) |
40 | |
41 | def on_stop_clicked(self, widget, data=None): |
42 | """Stop syncdaemon.""" |
43 | @@ -129,28 +128,21 @@ |
44 | self.on_disconnect_clicked(self.disconnect) |
45 | self.connect.set_sensitive(False) |
46 | |
47 | - self.start.show() |
48 | - self.start.set_sensitive(False) |
49 | - self.stop.hide() |
50 | - |
51 | + self.stop.set_sensitive(False) |
52 | self.sd.quit() |
53 | |
54 | def on_connect_clicked(self, widget, data=None): |
55 | """Connect syncdaemon.""" |
56 | self.sd.connect() |
57 | - self.connect.hide() |
58 | - self.disconnect.set_sensitive(False) |
59 | - self.disconnect.show() |
60 | - self.start_loading(self.is_connected) |
61 | + self.connect.set_sensitive(False) |
62 | + self._start_loading(self.is_connected) |
63 | |
64 | def on_disconnect_clicked(self, widget, data=None): |
65 | """Disconnect syncdaemon.""" |
66 | - self.connect.show() |
67 | - self.connect.set_sensitive(False) |
68 | - self.disconnect.hide() |
69 | - |
70 | + self.disconnect.set_sensitive(False) |
71 | self.sd.disconnect() |
72 | |
73 | + @print_debug |
74 | def on_status_icon_activate(self, widget, data=None): |
75 | """Systray icon was clicked.""" |
76 | if self.main_window.get_property('visible'): |
77 | @@ -158,48 +150,60 @@ |
78 | else: |
79 | self.main_window.show() |
80 | |
81 | - # DBus callbacks |
82 | + # SyncDaemon callbacks |
83 | |
84 | def on_started(self, *args, **kwargs): |
85 | """Callback'ed when syncadaemon is started.""" |
86 | + self.start.hide() |
87 | + self.stop.show() |
88 | self.stop.set_sensitive(True) |
89 | - self.activate_indicator(self.is_started) |
90 | + self._activate_indicator(self.is_started) |
91 | self.connect.set_sensitive(True) |
92 | |
93 | def on_stopped(self, *args, **kwargs): |
94 | """Callback'ed when syncadaemon is stopped.""" |
95 | + self.stop.hide() |
96 | + self.start.show() |
97 | self.start.set_sensitive(True) |
98 | + self.connect.set_sensitive(False) |
99 | |
100 | - self.activate_indicator(self.is_started, sensitive=False) |
101 | - self.activate_indicator(self.is_connected, sensitive=False) |
102 | - self.activate_indicator(self.is_online, sensitive=False) |
103 | + self._activate_indicator(self.is_started, sensitive=False) |
104 | + self._activate_indicator(self.is_connected, sensitive=False) |
105 | + self._activate_indicator(self.is_online, sensitive=False) |
106 | |
107 | def on_connected(self, *args, **kwargs): |
108 | """Callback'ed when syncadaemon is connected.""" |
109 | + self.connect.hide() |
110 | + self.disconnect.show() |
111 | self.disconnect.set_sensitive(True) |
112 | - self.activate_indicator(self.is_connected) |
113 | - self.start_loading(self.is_online) |
114 | - self.start_loading(self.is_online) |
115 | + self._activate_indicator(self.is_connected) |
116 | + self._start_loading(self.is_online) |
117 | + self._start_loading(self.is_online) |
118 | |
119 | def on_disconnected(self, *args, **kwargs): |
120 | """Callback'ed when syncadaemon is disconnected.""" |
121 | + self.disconnect.hide() |
122 | + self.connect.show() |
123 | self.connect.set_sensitive(True) |
124 | |
125 | - self.activate_indicator(self.is_connected, sensitive=False) |
126 | - self.activate_indicator(self.is_online, sensitive=False) |
127 | + self._activate_indicator(self.is_connected, sensitive=False) |
128 | + self._activate_indicator(self.is_online, sensitive=False) |
129 | |
130 | def on_online(self, *args, **kwargs): |
131 | """Callback'ed when syncadaemon is online.""" |
132 | self.is_online.set_sensitive(True) |
133 | - self.activate_indicator(self.is_online) |
134 | + self._activate_indicator(self.is_online) |
135 | |
136 | def on_offline(self, *args, **kwargs): |
137 | """Callback'ed when syncadaemon is offline.""" |
138 | - self.activate_indicator(self.is_online, sensitive=False) |
139 | + self._activate_indicator(self.is_online, sensitive=False) |
140 | |
141 | - def on_status_changed(self, name, description, is_error, is_connected, |
142 | - is_online, queues, connection): |
143 | + def on_status_changed(self, name=None, description=None, |
144 | + is_error=False, is_connected=True, |
145 | + is_online=True, queues=None, connection=None): |
146 | """Callback'ed when the SD status changed.""" |
147 | + if description is None: |
148 | + description = '' |
149 | self.status_label.set_text(description) |
150 | |
151 | def _on_queue_changed(self, queue_name, items, *args, **kwargs): |
152 | @@ -211,7 +215,7 @@ |
153 | row = (item.operation, item.path, item.node, item.share) |
154 | queue_store.append(row) |
155 | |
156 | - if not queue_view.is_sensitive(): |
157 | + if not queue_view.is_sensitive() and len(items) > 0: |
158 | queue_view.set_sensitive(True) |
159 | |
160 | def on_content_queue_changed(self, items, *args, **kwargs): |
161 | @@ -224,12 +228,33 @@ |
162 | |
163 | # custom |
164 | |
165 | - def start_loading(self, what): |
166 | + def _start_loading(self, what): |
167 | """Set a loader animation on 'what'.""" |
168 | what.set_sensitive(True) |
169 | what.set_from_animation(self.loading_animation) |
170 | |
171 | - def activate_indicator(self, what, sensitive=True): |
172 | + def _activate_indicator(self, what, sensitive=True): |
173 | """Set ready pixbuf on 'what' and make it 'sensitive'.""" |
174 | what.set_sensitive(sensitive) |
175 | what.set_from_pixbuf(self.active_indicator) |
176 | + |
177 | + def update(self): |
178 | + """Update UI based on SD current state.""" |
179 | + current_state = self.sd.current_state |
180 | + |
181 | + self._activate_indicator(self.is_online, |
182 | + sensitive=current_state.is_online) |
183 | + |
184 | + if current_state.is_started: |
185 | + self.on_started() |
186 | + if current_state.is_connected: |
187 | + self.on_connected() |
188 | + else: |
189 | + self.on_disconnected() |
190 | + else: |
191 | + self.on_disconnected() |
192 | + self.on_stopped() |
193 | + |
194 | + self.on_meta_queue_changed(self.sd.meta_queue) |
195 | + self.on_content_queue_changed(self.sd.content_queue) |
196 | + self.on_status_changed(description=current_state.description) |
197 | |
198 | === modified file 'magicicada/syncdaemon.py' |
199 | --- magicicada/syncdaemon.py 2010-05-22 20:27:11 +0000 |
200 | +++ magicicada/syncdaemon.py 2010-05-23 10:42:26 +0000 |
201 | @@ -85,6 +85,13 @@ |
202 | raise AttributeError("Name not in _attrs: %r" % name) |
203 | self.__dict__[name] = value |
204 | |
205 | + def __str__(self): |
206 | + """String representation.""" |
207 | + result = [] |
208 | + for attr in self._attrs: |
209 | + result.append("%s=%s" % (attr, getattr(self, attr))) |
210 | + return "<%s>" % ", ".join(result) |
211 | + |
212 | |
213 | class SyncDaemon(object): |
214 | """Interface to Ubuntu One's SyncDaemon.""" |
215 | |
216 | === modified file 'magicicada/tests/test_magicicada.py' |
217 | --- magicicada/tests/test_magicicada.py 2010-05-22 03:19:12 +0000 |
218 | +++ magicicada/tests/test_magicicada.py 2010-05-23 10:42:26 +0000 |
219 | @@ -18,28 +18,10 @@ |
220 | |
221 | """Tests for magicicada.""" |
222 | |
223 | -import gobject |
224 | -import gtk |
225 | -import unittest |
226 | - |
227 | -from functools import wraps |
228 | - |
229 | from twisted.trial.unittest import TestCase |
230 | |
231 | from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon |
232 | -from magicicada.helpers import get_builder, NO_OP |
233 | - |
234 | -DEFAULT_TIMEOUT = 200 |
235 | - |
236 | -def close_window_after(a_test): |
237 | - """Decorator to close the main window after executing f.""" |
238 | - @wraps(a_test) |
239 | - def inner(*args, **kwargs): |
240 | - """Inner function.""" |
241 | - #gobject.timeout_add(DEFAULT_TIMEOUT, a_test) |
242 | - #self.ui.run() |
243 | - |
244 | - return inner |
245 | +from magicicada.helpers import NO_OP |
246 | |
247 | |
248 | class FakedSyncdaemon(object): |
249 | @@ -61,13 +43,16 @@ |
250 | self.connect = NO_OP |
251 | self.disconnect = NO_OP |
252 | |
253 | + self.current_state = syncdaemon.State() |
254 | + self.meta_queue = [] |
255 | + self.content_queue = [] |
256 | + |
257 | |
258 | class MagicicadaUITestCase(TestCase): |
259 | """UI test cases for Magicicada UI.""" |
260 | |
261 | def setUp(self): |
262 | """Init.""" |
263 | - self.builder = get_builder('gui.glade') |
264 | self.ui = MagicicadaUI(syncdaemon_class=FakedSyncdaemon) |
265 | self._called = False |
266 | self.set_called = lambda *_: setattr(self, '_called', True) |
267 | @@ -76,7 +61,6 @@ |
268 | """Cleanup.""" |
269 | self.ui.on_main_window_destroy(self.ui.main_window) |
270 | self._called = False |
271 | - self.builder = None |
272 | |
273 | def assert_indicator_disabled(self, indicator): |
274 | """Test that 'indicator' is not sensitive.""" |
275 | @@ -136,8 +120,11 @@ |
276 | self.assertFalse(self.ui.is_online.is_sensitive()) |
277 | |
278 | def test_update_is_correct(self): |
279 | - """Update updates.""" |
280 | - # XXX: TODO |
281 | + """Update is called at startup.""" |
282 | + self.patch(MagicicadaUI, 'update', self.set_called) |
283 | + self.ui = MagicicadaUI(syncdaemon_class=FakedSyncdaemon) |
284 | + self.assertTrue(self._called, |
285 | + 'update was called at startup.') |
286 | |
287 | |
288 | class MagicicadaUIClickedTestCase(MagicicadaUITestCase): |
289 | @@ -147,9 +134,9 @@ |
290 | """Test on_start_clicked.""" |
291 | self.ui.on_start_clicked(self.ui.start) |
292 | |
293 | - self.assertFalse(self.ui.start.get_property('visible')) |
294 | - self.assertTrue(self.ui.stop.get_property('visible')) |
295 | - self.assertFalse(self.ui.stop.is_sensitive()) |
296 | + self.assertTrue(self.ui.start.get_property('visible')) |
297 | + self.assertFalse(self.ui.start.is_sensitive()) |
298 | + self.assertFalse(self.ui.stop.get_property('visible')) |
299 | |
300 | self.assert_indicator_loading(self.ui.is_started) |
301 | self.assert_indicator_disabled(self.ui.is_connected) |
302 | @@ -167,9 +154,9 @@ |
303 | self.ui.on_started() |
304 | self.ui.on_connect_clicked(self.ui.connect) |
305 | |
306 | - self.assertFalse(self.ui.connect.get_property('visible')) |
307 | - self.assertTrue(self.ui.disconnect.get_property('visible')) |
308 | - self.assertFalse(self.ui.disconnect.is_sensitive()) |
309 | + self.assertTrue(self.ui.connect.get_property('visible')) |
310 | + self.assertFalse(self.ui.connect.is_sensitive()) |
311 | + self.assertFalse(self.ui.disconnect.get_property('visible')) |
312 | |
313 | self.assert_indicator_ready(self.ui.is_started) |
314 | self.assert_indicator_loading(self.ui.is_connected) |
315 | @@ -191,9 +178,9 @@ |
316 | |
317 | self.assertFalse(self._called, 'on_disconnect_clicked was not called.') |
318 | |
319 | - self.assertTrue(self.ui.start.get_property('visible')) |
320 | - self.assertFalse(self.ui.start.is_sensitive()) |
321 | - self.assertFalse(self.ui.stop.get_property('visible')) |
322 | + self.assertFalse(self.ui.start.get_property('visible')) |
323 | + self.assertTrue(self.ui.stop.get_property('visible')) |
324 | + self.assertFalse(self.ui.stop.is_sensitive()) |
325 | |
326 | self.assertTrue(self.ui.connect.get_property('visible')) |
327 | self.assertFalse(self.ui.connect.is_sensitive()) |
328 | @@ -224,9 +211,9 @@ |
329 | self.ui.on_connected() |
330 | self.ui.on_disconnect_clicked(self.ui.disconnect) |
331 | |
332 | - self.assertTrue(self.ui.connect.get_property('visible')) |
333 | - self.assertFalse(self.ui.connect.is_sensitive()) |
334 | - self.assertFalse(self.ui.disconnect.get_property('visible')) |
335 | + self.assertFalse(self.ui.connect.get_property('visible')) |
336 | + self.assertTrue(self.ui.disconnect.get_property('visible')) |
337 | + self.assertFalse(self.ui.disconnect.is_sensitive()) |
338 | |
339 | def test_on_disconnect_clicked_disconnects_syncdaemon(self): |
340 | """Test on_disconnect_clicked.""" |
341 | @@ -268,7 +255,7 @@ |
342 | self.queue_view = getattr(self.ui, '%sq_view' % self.queue) |
343 | |
344 | def build_some_data(self, limit=5): |
345 | - """Build some data to pass to queue changed callback.""" |
346 | + """Build some data to pass to queue changed callback and related.""" |
347 | items = [] |
348 | for i in xrange(limit): |
349 | cq = syncdaemon.QueueData(operation='operation %i' % i, |
350 | @@ -277,6 +264,25 @@ |
351 | items.append(cq) |
352 | return items |
353 | |
354 | + def assert_queue_store_correct(self, queue_store, items): |
355 | + """Test that 'queue_store' has 'items' as content.""" |
356 | + msg = 'amount of rows for %s must be %s (got %s).' |
357 | + self.assertEqual(len(queue_store), len(items), |
358 | + msg % (queue_store, len(items), len(queue_store))) |
359 | + # assert rows content equal to items content |
360 | + tree_iter = queue_store.get_iter_root() |
361 | + tmp = list(reversed(items)) |
362 | + while tree_iter is not None: |
363 | + expected = tmp.pop() |
364 | + |
365 | + op, path, node, share = queue_store.get(tree_iter, 0, 1, 2, 3) |
366 | + self.assertEqual(expected.operation, op) |
367 | + self.assertEqual(expected.path, path) |
368 | + self.assertEqual(expected.node, node) |
369 | + self.assertEqual(expected.share, share) |
370 | + |
371 | + tree_iter = queue_store.iter_next(tree_iter) |
372 | + |
373 | def test_callback_is_connected(self): |
374 | """Queue changed callback is connected.""" |
375 | self.assertEqual(self.sd_changed, self.ui_changed, |
376 | @@ -293,22 +299,7 @@ |
377 | """On queue changed the view is updated.""" |
378 | items = self.build_some_data() |
379 | self.sd_changed(items) |
380 | - |
381 | - self.assertEqual(len(self.queue_store), len(items)) |
382 | - |
383 | - # assert rows content equal to items content |
384 | - tree_iter = self.queue_store.get_iter_root() |
385 | - tmp = list(reversed(items)) |
386 | - while tree_iter is not None: |
387 | - expected = tmp.pop() |
388 | - |
389 | - op, path, node, share = self.queue_store.get(tree_iter, 0, 1, 2, 3) |
390 | - self.assertEqual(expected.operation, op) |
391 | - self.assertEqual(expected.path, path) |
392 | - self.assertEqual(expected.node, node) |
393 | - self.assertEqual(expected.share, share) |
394 | - |
395 | - tree_iter = self.queue_store.iter_next(tree_iter) |
396 | + self.assert_queue_store_correct(self.queue_store, items) |
397 | |
398 | def test_model_is_cleared_before_updating(self): |
399 | """The model is cleared before upadting with a new set of data.""" |
400 | @@ -329,6 +320,15 @@ |
401 | self.assertTrue(self.queue_view.is_sensitive(), |
402 | 'Tree view must be enabled on changed.') |
403 | |
404 | + def test_update_is_correct_for_queue(self): |
405 | + """Correctly updates the queue state.""" |
406 | + data = self.build_some_data() |
407 | + setattr(self.ui.sd, '%s_queue' % self.queue, data) |
408 | + |
409 | + self.ui.update() |
410 | + |
411 | + self.assert_queue_store_correct(self.queue_store, data) |
412 | + |
413 | |
414 | class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase): |
415 | """UI test cases for content queue view.""" |
416 | @@ -345,10 +345,6 @@ |
417 | class MagicicadaUIStatusTestCase(MagicicadaUITestCase): |
418 | """UI test cases for the status label.""" |
419 | |
420 | - def setUp(self): |
421 | - """Init.""" |
422 | - super(MagicicadaUIStatusTestCase, self).setUp() |
423 | - |
424 | def test_callback_is_connected(self): |
425 | """Status callback is connected.""" |
426 | self.assertEqual(self.ui.sd.status_changed_callback, |
427 | @@ -363,13 +359,53 @@ |
428 | self.ui.on_status_changed(**kwargs) |
429 | self.assertEqual(self.ui.status_label.get_text(), kwargs['description']) |
430 | |
431 | + def test_update_is_correct_for_status_label(self): |
432 | + """Correctly updates the status label.""" |
433 | + expected = 'dummy test' |
434 | + self.ui.sd.current_state._set(description=expected) |
435 | + |
436 | + self.ui.update() |
437 | + |
438 | + self.assertEqual(expected, self.ui.status_label.get_text()) |
439 | + |
440 | |
441 | class MagicicadaUIConnectionTestCase(MagicicadaUITestCase): |
442 | """UI test cases for.""" |
443 | |
444 | - def setUp(self): |
445 | - """Init.""" |
446 | - super(MagicicadaUIConnectionTestCase, self).setUp() |
447 | + def assert_indicator_is_updated_correctly(self, indicator): |
448 | + """Test that correctly updates the 'indicator'.""" |
449 | + cs = self.ui.sd.current_state |
450 | + for expected in (True, False): |
451 | + cs._set(**{indicator: expected}) |
452 | + |
453 | + self.ui.update() |
454 | + |
455 | + self.assertEqual(self.ui.widget_enabled(self.ui.start), |
456 | + not cs.is_started, |
457 | + 'start must be enabled if not started.') |
458 | + self.assertEqual(self.ui.widget_enabled(self.ui.stop), |
459 | + cs.is_started, |
460 | + 'stop must be enabled if started.') |
461 | + |
462 | + if cs.is_started: |
463 | + actual = self.ui.widget_enabled(getattr(self.ui, indicator)) |
464 | + self.assertEqual(expected, actual, |
465 | + '%s must be %s' % (indicator, expected)) |
466 | + |
467 | + self.assertEqual(self.ui.widget_enabled(self.ui.connect), |
468 | + not cs.is_connected, |
469 | + 'connect must be enabled if not connected.') |
470 | + self.assertEqual(self.ui.widget_enabled(self.ui.disconnect), |
471 | + cs.is_connected, |
472 | + 'disconnect must be enabled if connected.') |
473 | + else: |
474 | + self.assertFalse(self.ui.connect.is_sensitive(), |
475 | + 'connect must be disabled when %s' % cs) |
476 | + self.assertTrue(self.ui.connect.get_property('visible'), |
477 | + 'connect must be visible when %s' % cs) |
478 | + actual = self.ui.widget_enabled(getattr(self.ui, indicator)) |
479 | + self.assertFalse(actual, |
480 | + '%s must be disabled' % (indicator,)) |
481 | |
482 | def test_all_disabled_at_startup(self): |
483 | """Indicators are all disabled at startup.""" |
484 | @@ -391,13 +427,11 @@ |
485 | """On SD started, the UI enables connect and indicator.""" |
486 | # must have click start first |
487 | self.ui.on_start_clicked(self.ui.start) |
488 | - assert not self.ui.stop.is_sensitive() |
489 | - assert not self.ui.connect.is_sensitive() |
490 | |
491 | self.ui.on_started() |
492 | |
493 | - self.assertTrue(self.ui.stop.is_sensitive()) |
494 | - self.assertTrue(self.ui.connect.is_sensitive()) |
495 | + self.assertTrue(self.ui.widget_enabled(self.ui.stop)) |
496 | + self.assertTrue(self.ui.widget_enabled(self.ui.connect)) |
497 | self.assert_indicator_ready(self.ui.is_started) |
498 | self.assert_indicator_disabled(self.ui.is_connected) |
499 | self.assert_indicator_disabled(self.ui.is_online) |
500 | @@ -407,11 +441,10 @@ |
501 | self.ui.on_start_clicked(self.ui.start) |
502 | self.ui.on_started() |
503 | self.ui.on_connect_clicked(self.ui.start) |
504 | - assert not self.ui.disconnect.is_sensitive() |
505 | |
506 | self.ui.on_connected() |
507 | |
508 | - self.assertTrue(self.ui.disconnect.is_sensitive()) |
509 | + self.assertTrue(self.ui.widget_enabled(self.ui.disconnect)) |
510 | self.assert_indicator_ready(self.ui.is_started) |
511 | self.assert_indicator_ready(self.ui.is_connected) |
512 | self.assert_indicator_loading(self.ui.is_online) |
513 | @@ -471,3 +504,7 @@ |
514 | self.assert_indicator_ready(self.ui.is_connected) |
515 | self.assert_indicator_disabled(self.ui.is_online) |
516 | |
517 | + def test_update_is_correct_for_indicators_and_buttons(self): |
518 | + """Correctly updates the indicators and buttons state.""" |
519 | + for i in ('is_started', 'is_connected', 'is_online'): |
520 | + self.assert_indicator_is_updated_correctly(i) |