Merge lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update into lp:ubuntu/maverick/magicicada

Proposed by Facundo Batista
Status: Merged
Merged at revision: 4
Proposed branch: lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update
Merge into: lp:ubuntu/maverick/magicicada
Diff against target: 956 lines (+334/-196)
9 files modified
PKG-INFO (+1/-1)
README.txt (+21/-5)
data/ui/gui.glade (+82/-155)
debian/changelog (+6/-0)
magicicada/__init__.py (+63/-15)
magicicada/syncdaemon.py (+5/-0)
magicicada/tests/test_magicicada.py (+147/-19)
magicicada/tests/test_syncdaemon.py (+8/-0)
setup.py (+1/-1)
To merge this branch: bzr merge lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update
Reviewer Review Type Date Requested Status
Ubuntu Sponsors Pending
Review via email: mp+31425@code.launchpad.net

Description of the change

0.1.3 release

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

On Fri, 30 Jul 2010 20:32:43 -0000, Facundo Batista <email address hidden> wrote:
> + * bzr get lp:ubuntu/magicicada
> + * cd magicicada
> + * uscan --verbose --rename (this gets the new upstream release from launchpad)
> + * bzr merge-package ../magicicada_0.1.2.orig.tar.gz --version=0.1.2

You mean merge-upstream I think?

Also, you can pass a URL and it will do the download and rename for you.

I will be adding uscan support so that those two steps are just

  bzr merge-upstream

at some point.

Thanks,

James

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'PKG-INFO'
2--- PKG-INFO 2010-07-09 18:14:53 +0000
3+++ PKG-INFO 2010-07-30 20:32:43 +0000
4@@ -1,6 +1,6 @@
5 Metadata-Version: 1.1
6 Name: magicicada
7-Version: 0.1.2
8+Version: 0.1.3
9 Summary: A GTK+ frontend for the "Chicharra" part of Ubuntu One.
10 Home-page: https://launchpad.net/magicicada
11 Author: Natalia Bidart
12
13=== modified file 'README.txt'
14--- README.txt 2010-07-09 18:14:53 +0000
15+++ README.txt 2010-07-30 20:32:43 +0000
16@@ -2,15 +2,31 @@
17
18 A GTK+ frontend for the "Chicharra" part of Ubuntu One client.
19
20------------
21-HOWTO do a source release:
22+
23+
24+HOWTO do a source release
25+-------------------------
26
27 * edit setup.py and increment the version number.
28 * 'python setup.py sdist'
29 * look at the contents of the tarball created in dist/ to be sure they are ok
30+ * step into the dist directory for the following commands
31 * sign the tarball by a command like:
32- gpg -a --detach-sign magicicada-0.2.tar.gz
33- this should create a file like magicicada-0.2.tar.gz.asc
34+ gpg -a --detach-sign magicicada-VERSION.tar.gz
35+ this should create a file like magicicada-VERSION.tar.gz.asc
36 * Upload the new release to launchpad with a command like:
37- lp-project-upload magicicada 0.2 magicicada-0.2.tar.gz
38+ lp-project-upload magicicada VERSION magicicada-VERSION.tar.gz
39 * Announce the release, ping someone to build updated packages for the PPA and Ubuntu.
40+
41+
42+HOWTO prepare an updated Ubuntu package
43+---------------------------------------
44+
45+ * bzr get lp:ubuntu/magicicada
46+ * cd magicicada
47+ * uscan --verbose --rename (this gets the new upstream release from launchpad)
48+ * bzr merge-package ../magicicada_0.1.2.orig.tar.gz --version=0.1.2
49+ * vim debian/changelog, check version, distro, and changes are correct.
50+ * you will need to build versions for lucid (for the PPA) and for the current dev release of Ubuntu. For example, if you are working on updating to release 0.1.2 of magicicada, and you want to build a package for lucid in the chicharreros PPA, the version number would be magicicada-0.1.2-0ubuntu1~lucid1. Then for the maverick version in the PPA, the version number would be magicicada-0.1.2-0ubuntu1~maverick1. And, for the version you upload to ubuntu universe, the version number would be magicicada-0.1.2-0ubuntu1.
51+ * To upload to the chicharreros PPA: do dput ppa:chicharreros/ppa <source.changes>
52+ * To get an upload into Ubuntu, prepare the source package and ask for a sponsor.
53
54=== modified file 'data/ui/gui.glade'
55--- data/ui/gui.glade 2010-07-09 18:14:53 +0000
56+++ data/ui/gui.glade 2010-07-30 20:32:43 +0000
57@@ -2,85 +2,85 @@
58 <interface>
59 <requires lib="gtk+" version="2.16"/>
60 <!-- interface-naming-policy project-wide -->
61+ <object class="GtkListStore" id="contentq_store">
62+ <columns>
63+ <!-- column-name operation -->
64+ <column type="gchararray"/>
65+ <!-- column-name path -->
66+ <column type="gchararray"/>
67+ <!-- column-name share -->
68+ <column type="gchararray"/>
69+ <!-- column-name node -->
70+ <column type="gchararray"/>
71+ </columns>
72+ </object>
73+ <object class="GtkListStore" id="metaq_store">
74+ <columns>
75+ <!-- column-name operation -->
76+ <column type="gchararray"/>
77+ <!-- column-name path -->
78+ <column type="gchararray"/>
79+ <!-- column-name share -->
80+ <column type="gchararray"/>
81+ <!-- column-name node -->
82+ <column type="gchararray"/>
83+ </columns>
84+ </object>
85 <object class="GtkListStore" id="folders_store">
86 <columns>
87- <!-- column-name node -->
88- <column type="gchararray"/>
89 <!-- column-name path -->
90 <column type="gchararray"/>
91 <!-- column-name suggested_path -->
92 <column type="gchararray"/>
93 <!-- column-name subscribed -->
94 <column type="gboolean"/>
95- <!-- column-name volume -->
96- <column type="gchararray"/>
97- </columns>
98- </object>
99- <object class="GtkListStore" id="contentq_store">
100- <columns>
101- <!-- column-name operation -->
102- <column type="gchararray"/>
103- <!-- column-name path -->
104- <column type="gchararray"/>
105- <!-- column-name share -->
106- <column type="gchararray"/>
107- <!-- column-name node -->
108- <column type="gchararray"/>
109- </columns>
110- </object>
111- <object class="GtkListStore" id="metaq_store">
112- <columns>
113- <!-- column-name operation -->
114- <column type="gchararray"/>
115- <!-- column-name path -->
116- <column type="gchararray"/>
117- <!-- column-name share -->
118- <column type="gchararray"/>
119- <!-- column-name node -->
120+ <!-- column-name node -->
121+ <column type="gchararray"/>
122+ <!-- column-name volume -->
123+ <column type="gchararray"/>
124+ </columns>
125+ </object>
126+ <object class="GtkListStore" id="shares_to_others_store">
127+ <columns>
128+ <!-- column-name name -->
129+ <column type="gchararray"/>
130+ <!-- column-name other_visible_name -->
131+ <column type="gchararray"/>
132+ <!-- column-name accepted -->
133+ <column type="gboolean"/>
134+ <!-- column-name access_level -->
135+ <column type="gchararray"/>
136+ <!-- column-name free_bytes -->
137+ <column type="gchararray"/>
138+ <!-- column-name path -->
139+ <column type="gchararray"/>
140+ <!-- column-name other_username -->
141+ <column type="gchararray"/>
142+ <!-- column-name node -->
143+ <column type="gchararray"/>
144+ <!-- column-name volume -->
145 <column type="gchararray"/>
146 </columns>
147 </object>
148 <object class="GtkListStore" id="shares_to_me_store">
149 <columns>
150- <!-- column-name accepted -->
151- <column type="gboolean"/>
152- <!-- column-name access_level -->
153- <column type="gchararray"/>
154- <!-- column-name free_bytes -->
155- <column type="gchararray"/>
156- <!-- column-name name -->
157- <column type="gchararray"/>
158- <!-- column-name node_id -->
159- <column type="gchararray"/>
160- <!-- column-name other_username -->
161- <column type="gchararray"/>
162- <!-- column-name other_visible_name -->
163- <column type="gchararray"/>
164- <!-- column-name path -->
165- <column type="gchararray"/>
166- <!-- column-name volume_id -->
167- <column type="gchararray"/>
168- </columns>
169- </object>
170- <object class="GtkListStore" id="shares_to_others_store">
171- <columns>
172- <!-- column-name accepted -->
173- <column type="gboolean"/>
174- <!-- column-name access_level -->
175- <column type="gchararray"/>
176- <!-- column-name free_bytes -->
177- <column type="gchararray"/>
178- <!-- column-name name -->
179- <column type="gchararray"/>
180- <!-- column-name node_id -->
181- <column type="gchararray"/>
182- <!-- column-name other_username -->
183- <column type="gchararray"/>
184- <!-- column-name other_visible_name -->
185- <column type="gchararray"/>
186- <!-- column-name path -->
187- <column type="gchararray"/>
188- <!-- column-name volume_id -->
189+ <!-- column-name name -->
190+ <column type="gchararray"/>
191+ <!-- column-name other_visible_name -->
192+ <column type="gchararray"/>
193+ <!-- column-name accepted -->
194+ <column type="gboolean"/>
195+ <!-- column-name access_level -->
196+ <column type="gchararray"/>
197+ <!-- column-name free_bytes -->
198+ <column type="gchararray"/>
199+ <!-- column-name path -->
200+ <column type="gchararray"/>
201+ <!-- column-name other_username -->
202+ <column type="gchararray"/>
203+ <!-- column-name node -->
204+ <column type="gchararray"/>
205+ <!-- column-name volume -->
206 <column type="gchararray"/>
207 </columns>
208 </object>
209@@ -627,7 +627,7 @@
210 <child>
211 <object class="GtkCellRendererText" id="cellrenderertext10"/>
212 <attributes>
213- <attribute name="text">1</attribute>
214+ <attribute name="text">0</attribute>
215 </attributes>
216 </child>
217 </object>
218@@ -640,7 +640,7 @@
219 <child>
220 <object class="GtkCellRendererText" id="cellrenderertext11"/>
221 <attributes>
222- <attribute name="text">2</attribute>
223+ <attribute name="text">1</attribute>
224 </attributes>
225 </child>
226 </object>
227@@ -653,33 +653,7 @@
228 <child>
229 <object class="GtkCellRendererToggle" id="cellrenderertoggle1"/>
230 <attributes>
231- <attribute name="active">3</attribute>
232- </attributes>
233- </child>
234- </object>
235- </child>
236- <child>
237- <object class="GtkTreeViewColumn" id="folders_node">
238- <property name="resizable">True</property>
239- <property name="title">Node</property>
240- <property name="expand">True</property>
241- <child>
242- <object class="GtkCellRendererText" id="cellrenderertext9"/>
243- <attributes>
244- <attribute name="text">0</attribute>
245- </attributes>
246- </child>
247- </object>
248- </child>
249- <child>
250- <object class="GtkTreeViewColumn" id="folders_volume">
251- <property name="resizable">True</property>
252- <property name="title">Volume</property>
253- <property name="expand">True</property>
254- <child>
255- <object class="GtkCellRendererText" id="cellrenderertext12"/>
256- <attributes>
257- <attribute name="text">4</attribute>
258+ <attribute name="active">2</attribute>
259 </attributes>
260 </child>
261 </object>
262@@ -758,7 +732,7 @@
263 <child>
264 <object class="GtkCellRendererText" id="cellrenderertext15"/>
265 <attributes>
266- <attribute name="text">3</attribute>
267+ <attribute name="text">0</attribute>
268 </attributes>
269 </child>
270 </object>
271@@ -770,7 +744,7 @@
272 <child>
273 <object class="GtkCellRendererText" id="cellrenderertext19"/>
274 <attributes>
275- <attribute name="text">6</attribute>
276+ <attribute name="text">1</attribute>
277 </attributes>
278 </child>
279 </object>
280@@ -782,7 +756,7 @@
281 <child>
282 <object class="GtkCellRendererToggle" id="cellrenderertoggle2"/>
283 <attributes>
284- <attribute name="active">0</attribute>
285+ <attribute name="active">2</attribute>
286 </attributes>
287 </child>
288 </object>
289@@ -794,7 +768,7 @@
290 <child>
291 <object class="GtkCellRendererText" id="cellrenderertext13"/>
292 <attributes>
293- <attribute name="text">1</attribute>
294+ <attribute name="text">3</attribute>
295 </attributes>
296 </child>
297 </object>
298@@ -806,7 +780,7 @@
299 <child>
300 <object class="GtkCellRendererText" id="cellrenderertext14"/>
301 <attributes>
302- <attribute name="text">2</attribute>
303+ <attribute name="text">4</attribute>
304 </attributes>
305 </child>
306 </object>
307@@ -818,31 +792,7 @@
308 <child>
309 <object class="GtkCellRendererText" id="cellrenderertext18"/>
310 <attributes>
311- <attribute name="text">7</attribute>
312- </attributes>
313- </child>
314- </object>
315- </child>
316- <child>
317- <object class="GtkTreeViewColumn" id="shares_to_me_node">
318- <property name="title">Node</property>
319- <property name="expand">True</property>
320- <child>
321- <object class="GtkCellRendererText" id="cellrenderertext16"/>
322- <attributes>
323- <attribute name="text">4</attribute>
324- </attributes>
325- </child>
326- </object>
327- </child>
328- <child>
329- <object class="GtkTreeViewColumn" id="shares_to_me_volume">
330- <property name="title">Volume</property>
331- <property name="expand">True</property>
332- <child>
333- <object class="GtkCellRendererText" id="cellrenderertext17"/>
334- <attributes>
335- <attribute name="text">8</attribute>
336+ <attribute name="text">5</attribute>
337 </attributes>
338 </child>
339 </object>
340@@ -923,7 +873,7 @@
341 <child>
342 <object class="GtkCellRendererText" id="cellrenderertext20"/>
343 <attributes>
344- <attribute name="text">3</attribute>
345+ <attribute name="text">0</attribute>
346 </attributes>
347 </child>
348 </object>
349@@ -935,7 +885,7 @@
350 <child>
351 <object class="GtkCellRendererText" id="cellrenderertext21"/>
352 <attributes>
353- <attribute name="text">6</attribute>
354+ <attribute name="text">1</attribute>
355 </attributes>
356 </child>
357 </object>
358@@ -947,7 +897,7 @@
359 <child>
360 <object class="GtkCellRendererToggle" id="cellrenderertoggle3"/>
361 <attributes>
362- <attribute name="active">0</attribute>
363+ <attribute name="active">2</attribute>
364 </attributes>
365 </child>
366 </object>
367@@ -959,7 +909,7 @@
368 <child>
369 <object class="GtkCellRendererText" id="cellrenderertext22"/>
370 <attributes>
371- <attribute name="text">1</attribute>
372+ <attribute name="text">3</attribute>
373 </attributes>
374 </child>
375 </object>
376@@ -971,7 +921,7 @@
377 <child>
378 <object class="GtkCellRendererText" id="cellrenderertext23"/>
379 <attributes>
380- <attribute name="text">2</attribute>
381+ <attribute name="text">4</attribute>
382 </attributes>
383 </child>
384 </object>
385@@ -983,31 +933,7 @@
386 <child>
387 <object class="GtkCellRendererText" id="cellrenderertext24"/>
388 <attributes>
389- <attribute name="text">7</attribute>
390- </attributes>
391- </child>
392- </object>
393- </child>
394- <child>
395- <object class="GtkTreeViewColumn" id="shares_to_others_node">
396- <property name="title">Node</property>
397- <property name="expand">True</property>
398- <child>
399- <object class="GtkCellRendererText" id="cellrenderertext25"/>
400- <attributes>
401- <attribute name="text">4</attribute>
402- </attributes>
403- </child>
404- </object>
405- </child>
406- <child>
407- <object class="GtkTreeViewColumn" id="shares_to_others_volume">
408- <property name="title">Volume</property>
409- <property name="expand">True</property>
410- <child>
411- <object class="GtkCellRendererText" id="cellrenderertext26"/>
412- <attributes>
413- <attribute name="text">8</attribute>
414+ <attribute name="text">5</attribute>
415 </attributes>
416 </child>
417 </object>
418@@ -1058,6 +984,7 @@
419 <property name="has_separator">False</property>
420 <property name="create_folders">False</property>
421 <signal name="file_activated" handler="on_file_chooser_open_clicked"/>
422+ <signal name="show" handler="on_file_chooser_show"/>
423 <child internal-child="vbox">
424 <object class="GtkVBox" id="dialog-vbox7">
425 <property name="visible">True</property>
426
427=== modified file 'debian/changelog'
428--- debian/changelog 2010-07-09 18:28:07 +0000
429+++ debian/changelog 2010-07-30 20:32:43 +0000
430@@ -1,3 +1,9 @@
431+magicicada (0.1.3-0ubuntu1) maverick; urgency=low
432+
433+ * New upstream release.
434+
435+ -- Facundo Batista <facundo@ubuntu.com> Thu, 29 Jul 2010 09:47:11 -0300
436+
437 magicicada (0.1.2-0ubuntu1) maverick; urgency=low
438
439 * New upstream release.
440
441=== modified file 'magicicada/__init__.py'
442--- magicicada/__init__.py 2010-07-09 18:14:53 +0000
443+++ magicicada/__init__.py 2010-07-30 20:32:43 +0000
444@@ -49,9 +49,12 @@
445 # set up the logging for all the project
446 logger_helper.set_up()
447 logger = logging.getLogger('magicicada.ui')
448-console = logging.StreamHandler()
449-console.setLevel(logging.DEBUG)
450-#logger.addHandler(console)
451+
452+DEBUG = os.getenv('DEBUG')
453+if DEBUG:
454+ console = logging.StreamHandler()
455+ console.setLevel(logging.DEBUG)
456+ logger.addHandler(console)
457
458
459 class MagicicadaUI(object):
460@@ -63,6 +66,8 @@
461 'initial': _('Service is not started, click Start to continue.'),
462 }
463
464+ _u1_root = UBUNTU_ONE_ROOT
465+
466 def __init__(self, on_destroy=NO_OP,
467 syncdaemon_class=syncdaemon.SyncDaemon):
468 """Init."""
469@@ -87,11 +92,12 @@
470 widgets = (
471 'start', 'stop', 'connect', 'disconnect', # toolbar buttons
472 'folders', 'folders_dialog', # folders
473- 'folders_store', 'folders_close',
474+ 'folders_view', 'folders_store', 'folders_close',
475 'shares_to_me', 'shares_to_me_dialog', # shares_to_me
476- 'shares_to_me_store', 'shares_to_me_close',
477+ 'shares_to_me_view', 'shares_to_me_store', 'shares_to_me_close',
478 'shares_to_others', 'shares_to_others_dialog', # shares_to_others
479- 'shares_to_others_store', 'shares_to_others_close',
480+ 'shares_to_others_view', 'shares_to_others_store',
481+ 'shares_to_others_close',
482 'raw_metadata', # raw metadata
483 'is_started', 'is_connected', 'is_online', # status bar images
484 'status_label', 'status_icon', # status label and systray icon
485@@ -106,6 +112,11 @@
486 setattr(self, widget, obj)
487 assert obj is not None, '%s must not be None' % widget
488
489+ self._sorting_order = {}
490+ self._make_view_sortable('folders')
491+ self._make_view_sortable('shares_to_me')
492+ self._make_view_sortable('shares_to_others')
493+
494 self.raw_metadata_dialog = self._new_metadata_dialog()
495 self.volumes = (self.folders, self.shares_to_me, self.shares_to_others)
496 self.windows = (self.main_window, self.about_dialog,
497@@ -135,10 +146,19 @@
498 self.widget_is_visible = lambda w: w.get_property('visible')
499 self.widget_enabled = lambda w: self.widget_is_visible(w) and \
500 w.is_sensitive()
501- self.file_chooser.set_current_folder(UBUNTU_ONE_ROOT)
502 self.last_metadata_path = None
503 self.update()
504
505+ def _make_view_sortable(self, view_name):
506+ """Set up view so columns are sortable."""
507+ store = getattr(self, '%s_store' % view_name)
508+ view = getattr(self, '%s_view' % view_name)
509+ self._sorting_order[store] = {}
510+ for i, col in enumerate(view.get_columns()):
511+ col.set_clickable(True)
512+ col.connect('clicked', self.on_store_sort_column_changed, i, store)
513+ self._sorting_order[store][i] = gtk.SORT_ASCENDING
514+
515 def _new_metadata_dialog(self):
516 """Return a new metadata dialog."""
517 dialog = gtk.Dialog(title='Raw metadata', parent=self.main_window,
518@@ -165,7 +185,7 @@
519 dialog.get_child().add(text_view)
520 setattr(self, 'raw_metadata_view', text_view)
521
522- dialog.hide() # XXX to be fixed later
523+ dialog.hide() # XXX to be fixed later
524 return dialog
525
526 # GTK callbacks
527@@ -227,8 +247,8 @@
528
529 self.folders_store.clear()
530 for item in items:
531- row = (item.node, item.path, item.suggested_path,
532- item.subscribed, item.volume)
533+ row = (item.path, item.suggested_path, item.subscribed,
534+ item.node, item.volume)
535 self.folders_store.append(row)
536
537 self.folders_dialog.run()
538@@ -247,11 +267,13 @@
539 store.clear()
540 for item in items:
541 free_bytes = item.free_bytes
542- if isinstance(free_bytes, int):
543- free_bytes = humanize_bytes(free_bytes, precision=2)
544- row = (item.accepted, item.access_level, free_bytes, item.name,
545- item.node_id, item.other_username, item.other_visible_name,
546- item.path, item.volume_id)
547+ try:
548+ free_bytes = humanize_bytes(int(free_bytes), precision=2)
549+ except (ValueError, TypeError):
550+ logger.exception('Error while humanizing bytes')
551+ row = (item.name, item.other_visible_name, item.accepted,
552+ item.access_level, free_bytes, item.path,
553+ item.other_username, item.node_id, item.volume_id)
554 store.append(row)
555
556 dialog.run()
557@@ -277,6 +299,11 @@
558 """Close the file_chooser dialog."""
559 self.file_chooser.response(gtk.FILE_CHOOSER_ACTION_OPEN)
560
561+ def on_file_chooser_show(self, widget, data=None):
562+ """Close the file_chooser dialog."""
563+ if self.last_metadata_path is None:
564+ self.file_chooser.set_current_folder(self._u1_root)
565+
566 def on_raw_metadata_close_clicked(self, widget, data=None):
567 """Close the raw_metadata dialog."""
568 self.raw_metadata_dialog.hide()
569@@ -302,6 +329,27 @@
570 else:
571 self.main_window.show()
572
573+ def on_store_sort_column_changed(self, column, col_index, store):
574+ """Store sort requested."""
575+ order = self._sorting_order[store][col_index]
576+ last_col = self._sorting_order[store].get('last_col')
577+ if last_col is not None:
578+ last_col.set_sort_indicator(False)
579+ logger.debug('Sorting col index %s, named %s, with order %s',
580+ col_index, column.get_name(), order)
581+
582+ store.set_sort_column_id(col_index, order)
583+ column.set_sort_indicator(True)
584+ column.set_sort_order(order)
585+ self._sorting_order[store]['last_col'] = column
586+
587+ # change order
588+ if order == gtk.SORT_ASCENDING:
589+ order = gtk.SORT_DESCENDING
590+ else:
591+ order = gtk.SORT_ASCENDING
592+ self._sorting_order[store][col_index] = order
593+
594 # SyncDaemon callbacks
595
596 def on_started(self, *args, **kwargs):
597
598=== modified file 'magicicada/syncdaemon.py'
599--- magicicada/syncdaemon.py 2010-07-09 18:14:53 +0000
600+++ magicicada/syncdaemon.py 2010-07-30 20:32:43 +0000
601@@ -107,6 +107,7 @@
602 self.on_shares_to_me_changed_callback = NO_OP
603 self.on_shares_to_others_changed_callback = NO_OP
604 self.on_metadata_ready_callback = None # mandatory
605+ self.on_initial_data_ready_callback = NO_OP
606
607 # mq needs to be polled to know progress
608 self._mqcaller = None
609@@ -147,6 +148,10 @@
610 self.shares_to_me = yield self.dbus.get_shares_to_me()
611 self.shares_to_others = yield self.dbus.get_shares_to_others()
612
613+ # let frontend know that we have all the initial data
614+ logger.info("All initial data is ready")
615+ self.on_initial_data_ready_callback()
616+
617 @defer.inlineCallbacks
618 def on_sd_shares_changed(self):
619 """Shares changed, ask for new information."""
620
621=== modified file 'magicicada/tests/test_magicicada.py'
622--- magicicada/tests/test_magicicada.py 2010-07-09 18:14:53 +0000
623+++ magicicada/tests/test_magicicada.py 2010-07-30 20:32:43 +0000
624@@ -19,6 +19,7 @@
625 """Tests for magicicada."""
626
627 import logging
628+import os
629 import sys
630
631 from functools import wraps
632@@ -111,12 +112,37 @@
633 self.called = False
634 self.response = None
635 self.set_called = lambda *args, **kwargs: setattr(self, 'called', True)
636+ self._failed_test = False
637
638 def tearDown(self):
639 """Cleanup."""
640 self.ui.on_main_window_destroy(self.ui.main_window)
641 self.called = False
642
643+ if self._failed_test:
644+ # no, I'm not raising a bool. pylint: disable-msg=E0702
645+ raise self._failed_test
646+
647+ def __getattribute__(self, name):
648+ """Overwrite the assert methods with safer ones.
649+
650+ This way if a test called by gobject in the future fails, it
651+ makes the whole test suite fail.
652+ """
653+ if name.startswith('assert') and hasattr(TestCase, name):
654+
655+ def proxy(*args, **kwargs):
656+ """Function that will call the real assert."""
657+ real_assert = getattr(TestCase, name)
658+ try:
659+ real_assert(self, *args, **kwargs)
660+ except Exception, e:
661+ self._failed_test = e
662+ raise
663+ return proxy
664+ else:
665+ return TestCase.__getattribute__(self, name)
666+
667 def do_start(self):
668 """Simulate that start fully happened."""
669 self.ui.on_start_clicked(self.ui.start)
670@@ -137,7 +163,7 @@
671 result.append(data_type(**kwargs))
672 return result
673
674- def assert_store_correct(self, store, items, markup=None):
675+ def assert_store_correct(self, store, items, mapping, markup=None):
676 """Test that 'store' has 'items' as content."""
677 msg = 'amount of rows for %s must be %s (got %s).'
678 self.assertEqual(len(store), len(items),
679@@ -150,7 +176,7 @@
680 msg = "column %i ('%s') must be '%s' (got '%s' instead)"
681 while tree_iter is not None:
682 head = tmp.pop()
683- for i, field in enumerate(head._fields):
684+ for i, field in mapping:
685 actual, = store.get(tree_iter, i)
686 expected = getattr(head, field)
687 if store.get_column_type(i).name == 'gboolean':
688@@ -426,7 +452,8 @@
689
690 def assert_store_correct(self, store, items):
691 """Test that 'store' has 'items' as content."""
692- args = (store, items, self.expected_markup)
693+ mapping = enumerate(['operation', 'path', 'share', 'node'])
694+ args = (store, items, mapping, self.expected_markup)
695 super(_MagicicadaUIQueueTestCase, self).assert_store_correct(*args)
696
697 @skip_abstract_class
698@@ -826,6 +853,7 @@
699
700 name = None
701 data_type = None
702+ mapping = []
703
704 def setUp(self):
705 """Init."""
706@@ -834,6 +862,7 @@
707 return
708 self.volume = getattr(self.ui, self.name)
709 self.volume_store = getattr(self.ui, '%s_store' % self.name)
710+ self.volume_view = getattr(self.ui, '%s_view' % self.name)
711 self.volume_dialog_name = '%s_dialog' % self.name
712 self.volume_dialog = getattr(self.ui, self.volume_dialog_name)
713 self.on_volume_clicked = getattr(self.ui, 'on_%s_clicked' % self.name)
714@@ -845,11 +874,48 @@
715 r = super(_MagicicadaUIVolumeTestCase, self).build_some_data(**kwargs)
716 return r
717
718+ def assert_store_correct(self, store, items):
719+ """Test that 'store' has 'items' as content."""
720+ args = (store, items, self.mapping)
721+ super(_MagicicadaUIVolumeTestCase, self).assert_store_correct(*args)
722+
723 def assert_widget_availability(self, enabled=True):
724 """Check volume availability according to 'enabled'."""
725 s = super(_MagicicadaUIVolumeTestCase, self)
726 s.assert_widget_availability(self.name, enabled)
727
728+ def assert_sort_order_correct(self, column, i, expected_order):
729+ """Check that sort order is correctly set."""
730+ msg0 = 'Store sort id must be %r (got %r instead).'
731+ msg1 = 'Store sort order must be %r (got %r instead).'
732+ msg3 = 'Column sort order must be %r (got %r instead).'
733+
734+ actual_id, actual_order = self.volume_store.get_sort_column_id()
735+
736+ # store sort column id and order
737+ self.assertEqual(i, actual_id, msg0 % (i, actual_id))
738+ self.assertEqual(expected_order, actual_order,
739+ msg1 % (expected_order, actual_order))
740+
741+ # column sort order
742+ actual_order = column.get_sort_order()
743+ self.assertEqual(expected_order, actual_order,
744+ msg3 % (expected_order, actual_order))
745+
746+ def assert_sort_indicator_correct(self, column):
747+ """Check that sort indicator is correctly set."""
748+ msg = 'Column %s must have sort indicator %s.'
749+ colname = column.get_name()
750+ # column sort indicator
751+ self.assertTrue(column.get_sort_indicator(), msg % (colname, 'on'))
752+
753+ # all the other columns must not have the sort indicator on
754+ for other_column in self.volume_view.get_columns():
755+ if other_column.get_name() == colname:
756+ continue
757+ self.assertFalse(other_column.get_sort_indicator(),
758+ msg % (other_column.get_name(), 'off'))
759+
760 @skip_abstract_class
761 def test_volume_are_disabled_until_started(self):
762 """Folders and shares are disabled until online."""
763@@ -955,33 +1021,72 @@
764 self.assert_dialog_properties(dialog_name=self.volume_dialog_name,
765 title=title)
766
767+ @skip_abstract_class
768+ def test_volume_columns_not_sorted_at_start(self):
769+ """Test volume columns are not sorted at start."""
770+ msg = 'Column %s must not have the sort indicator on.'
771+ for col in self.volume_view.get_columns():
772+ self.assertFalse(col.get_sort_indicator(), msg % col.get_name())
773+
774+ @skip_abstract_class
775+ def test_volume_columns_are_clickable(self):
776+ """Test volume columns are clickable."""
777+ msg = 'Column %s must be clickable.'
778+ for col in self.volume_view.get_columns():
779+ self.assertTrue(col.get_clickable(), msg % col.get_name())
780+
781+ @skip_abstract_class
782+ def test_volume_columns_clicked_signal(self):
783+ """Test volume columns clicks signal is properly connected."""
784+ msg = 'Column %s must be connected to on_store_sort_column_changed.'
785+ for col in self.volume_view.get_columns():
786+ self.assertTrue(col.get_clickable(), msg % col.get_name())
787+
788+ @skip_abstract_class
789+ def test_volume_sorting(self):
790+ """Test volume panel can be re-sorted."""
791+ for i, col in enumerate(self.volume_view.get_columns()):
792+ col.clicked() # click on the column
793+ self.assert_sort_order_correct(col, i, gtk.SORT_ASCENDING)
794+ self.assert_sort_indicator_correct(col)
795+
796+ col.clicked() # click on the column, sort order must change
797+ self.assert_sort_order_correct(col, i, gtk.SORT_DESCENDING)
798+
799+ col.clicked() # click again, sort order must be the first one
800+ self.assert_sort_order_correct(col, i, gtk.SORT_ASCENDING)
801+
802
803 class MagicicadaUIFoldersTestCase(_MagicicadaUIVolumeTestCase):
804 """UI test cases for folders."""
805
806 name = 'folders'
807- data_type = FolderData # node path suggested_path subscribed volume
808+ data_type = FolderData
809+ mapping = enumerate(['path', 'suggested_path', 'subscribed',
810+ 'node', 'volume'])
811
812
813 class _MagicicadaUISharesTestCase(_MagicicadaUIVolumeTestCase):
814 """UI test cases for shares_to_me."""
815
816- data_type = ShareData # accepted access_level free_bytes name node_id
817- # other_username other_visible_name path volume_id
818+ data_type = ShareData
819+ mapping = enumerate(['name', 'other_visible_name', 'accepted',
820+ 'access_level', 'free_bytes', 'path',
821+ 'other_username', 'node_id', 'volume_id'])
822
823- @skip_abstract_class
824- def test_bytes_are_humanized(self):
825+ def assert_correct_free_bytes(self, free_bytes):
826 """Free bytes are shown humanized."""
827 attrs = self.data_type._fields
828 kwargs = dict([(attr, str(attr)) for attr in attrs])
829- kwargs['free_bytes'] = 10000
830+ kwargs['free_bytes'] = free_bytes
831 item = self.data_type(**kwargs)
832 setattr(self.ui.sd, self.name, [item])
833
834 def test():
835 """Perform the test per se before closing the dialog."""
836- kwargs['free_bytes'] = humanize_bytes(kwargs['free_bytes'],
837- precision=2)
838+ if kwargs['free_bytes'] is not None:
839+ i = int(kwargs['free_bytes'])
840+ kwargs['free_bytes'] = humanize_bytes(i, precision=2)
841 item = self.data_type(**kwargs)
842 self.assert_store_correct(self.volume_store, [item])
843
844@@ -989,6 +1094,21 @@
845 (self.volume_dialog, test))
846 self.on_volume_clicked(self.volume)
847
848+ @skip_abstract_class
849+ def test_bytes_are_humanized(self):
850+ """Free bytes are shown humanized."""
851+ self.assert_correct_free_bytes(free_bytes=10000)
852+
853+ @skip_abstract_class
854+ def test_bytes_are_humanized_even_when_string(self):
855+ """Free bytes are shown humanized even if they are string."""
856+ self.assert_correct_free_bytes(free_bytes='10000')
857+
858+ @skip_abstract_class
859+ def test_bytes_are_humanized_even_when_none(self):
860+ """Free bytes are shown humanized even if they are None."""
861+ self.assert_correct_free_bytes(free_bytes=None)
862+
863
864 class MagicicadaUISharesToMeTestCase(_MagicicadaUISharesTestCase):
865 """UI test cases for shares_to_me."""
866@@ -1085,6 +1205,8 @@
867
868 def test_on_raw_metadata_clicked(self):
869 """Test on_raw_metadata_clicked."""
870+ self.ui._u1_root = os.path.dirname(self.path)
871+
872 self.assertFalse(self.ui.widget_is_visible(
873 self.ui.raw_metadata_dialog),
874 'raw_metadata_dialog should not be visible.')
875@@ -1127,6 +1249,19 @@
876 self.ui.raw_metadata_dialog),
877 'raw_metadata_dialog should not be visible.')
878
879+ def test_file_chooser_folder_is_u1root_when_visible(self):
880+ """File chooser folder is ~/Ubuntu One only when visible."""
881+ self.assertNotEqual(self.ui.file_chooser.get_current_folder(),
882+ UBUNTU_ONE_ROOT,
883+ "shouldn't have U1 folder before becoming visible")
884+
885+ gobject.timeout_add(100, self.ui.file_chooser_open.clicked)
886+ self.ui.on_raw_metadata_clicked(self.ui.raw_metadata)
887+
888+ self.assertEqual(self.ui.file_chooser.get_current_folder(),
889+ UBUNTU_ONE_ROOT,
890+ 'should have U1 folder after becoming visible')
891+
892 def test_raw_metadata_dialog_properties(self):
893 """The raw_metadata dialog has correct properties."""
894 title = self.name.replace('_', ' ').capitalize()
895@@ -1148,14 +1283,6 @@
896 self.assertFalse(self.ui.widget_is_visible(self.ui.file_chooser),
897 'file_chooser must be hidden by default.')
898
899- def test_file_chooser_current_folder_is_ubuntu_one_root(self):
900- """File chooser default folder is ~/Ubuntu One."""
901- process_gtk_pendings() # WOW! Needed to get proper value below
902- actual = self.ui.file_chooser.get_current_folder()
903- msg = 'file_chooser default folder must be %s (got %s instead).'
904- self.assertEqual(actual, UBUNTU_ONE_ROOT,
905- msg % (UBUNTU_ONE_ROOT, actual))
906-
907 def test_filename_is_used_only_if_open_clicked(self):
908 """Filename is used only if user clicked open."""
909 self.patch(self.ui.sd, 'get_metadata', self.set_called)
910@@ -1170,6 +1297,7 @@
911 """Filename is stored as 'last_metadata_path' if user clicked open."""
912 self.assertTrue(self.ui.last_metadata_path is None,
913 'last_metadata_path must be None.')
914+ self.ui._u1_root = os.path.dirname(self.path)
915 self.ui.file_chooser.set_filename(self.path)
916 gobject.timeout_add(100, test_and_click,
917 (self.ui.file_chooser_open, NO_OP))
918
919=== modified file 'magicicada/tests/test_syncdaemon.py'
920--- magicicada/tests/test_syncdaemon.py 2010-07-09 18:14:53 +0000
921+++ magicicada/tests/test_syncdaemon.py 2010-07-30 20:32:43 +0000
922@@ -700,6 +700,13 @@
923 False, 'queues', 'connection')
924 self.assertTrue(self.called)
925
926+ @defer.inlineCallbacks
927+ def test_on_initial_data_ready(self):
928+ """Called when SD gets all the initial data."""
929+ self.flag_called(self.sd, 'on_initial_data_ready_callback')
930+ yield self.sd._get_initial_data()
931+ self.assertTrue(self.called)
932+
933
934 class TestLogs(unittest.TestCase):
935 """Test logging."""
936@@ -730,6 +737,7 @@
937 """Log the initial filling."""
938 yield self.sd._get_initial_data()
939 self.assertTrue(self.hdlr.check_info("Getting initial data"))
940+ self.assertTrue(self.hdlr.check_info("All initial data is ready"))
941
942 def test_start(self):
943 """Log the call to start."""
944
945=== modified file 'setup.py'
946--- setup.py 2010-07-09 18:14:53 +0000
947+++ setup.py 2010-07-30 20:32:43 +0000
948@@ -86,7 +86,7 @@
949
950 DistUtilsExtra.auto.setup(
951 name='magicicada',
952- version='0.1.2',
953+ version='0.1.3',
954 license='GPL-3',
955 author='Natalia Bidart',
956 author_email='natalia.bidart@ubuntu.com',

Subscribers

People subscribed via source and target branches

to all changes: