Merge lp:~ralsina/ubuntuone-windows-installer/fix_800383 into lp:ubuntuone-windows-installer

Proposed by Roberto Alsina
Status: Merged
Approved by: Roberto Alsina
Approved revision: 30
Merged at revision: 7
Proposed branch: lp:~ralsina/ubuntuone-windows-installer/fix_800383
Merge into: lp:ubuntuone-windows-installer
Diff against target: 827 lines (+674/-21)
10 files modified
data/qt/congratulations.ui (+103/-0)
pylintrc (+305/-0)
run-tests (+1/-1)
ubuntuone_installer/__init__.py (+1/-1)
ubuntuone_installer/gui/qt/__init__.py (+0/-1)
ubuntuone_installer/gui/qt/gui.py (+52/-18)
ubuntuone_installer/gui/qt/tests/__init__.py (+68/-0)
ubuntuone_installer/gui/qt/tests/test_gui.py (+61/-0)
ubuntuone_installer/gui/tests/__init__.py (+45/-0)
ubuntuone_installer/tests/__init__.py (+38/-0)
To merge this branch: bzr merge lp:~ralsina/ubuntuone-windows-installer/fix_800383
Reviewer Review Type Date Requested Status
dobey (community) Approve
Natalia Bidart (community) Approve
Review via email: mp+65416@code.launchpad.net

Commit message

Beginning of the implementation of the congratulations page.

Description of the change

Beginning of the implementation of this page.

Even after this branch lands:

* Need correct artwork from design
* The optional "syncing" message depends on a previous page

To test (on Linux):

PYTHONPATH=. python bin/ubuntuone-installer-qt

You should have two pages on the wizard.
The "Open Ubuntu One Dashboard" button on the final page should open the control panel.

To post a comment you must log in.
Revision history for this message
dobey (dobey) wrote :

+ subprocess.Popen(["ubuntuone-control-panel-gtk",])

Should this not be ubuntuone-control-panel-qt, given that we're running it from a qt gui? Also, should we not rely on IPC activation to just start the correct one for the user's environment, instead of running it directly?

review: Needs Information
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

I'm marking this as needs fixing so we have can have at least a minimal test suite for this widgets that are now starting to have some logic.

Thanks!

review: Needs Fixing
12. By Roberto Alsina

style fixes

13. By Roberto Alsina

Basic testing stuff copied from control panel, with 4 tests which fail

14. By Roberto Alsina

The main UI is not loaded using loadUI

15. By Roberto Alsina

Re-add some things that should not have been removed

16. By Roberto Alsina

closer to making testing itself work

17. By Roberto Alsina

use done() instead of closeEvent()

18. By Roberto Alsina

This is as far as I managed to monkeypatch, and I have a problem. I will ask for help now.

19. By Roberto Alsina

Make tests work using the reactor as mandel said

20. By Roberto Alsina

style fixes

21. By Roberto Alsina

Don't start the control panel on the tests

22. By Roberto Alsina

whitespace fixes, pylintrc

23. By Roberto Alsina

added tests for the 'start control panel' logic

24. By Roberto Alsina

add build step to run-tests

25. By Roberto Alsina

Style fix

26. By Roberto Alsina

use .ui instead of .page_ui for consistency

27. By Roberto Alsina

changed method name to be PEP8-alike

28. By Roberto Alsina

style issues

29. By Roberto Alsina

Make it more like control panel's

Revision history for this message
Natalia Bidart (nataliabidart) :
review: Approve
30. By Roberto Alsina

switch t the -qt version of control panel

Revision history for this message
dobey (dobey) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/qt/congratulations.ui'
2--- data/qt/congratulations.ui 1970-01-01 00:00:00 +0000
3+++ data/qt/congratulations.ui 2011-06-22 14:18:49 +0000
4@@ -0,0 +1,103 @@
5+<?xml version="1.0" encoding="UTF-8"?>
6+<ui version="4.0">
7+ <class>Form</class>
8+ <widget class="QWidget" name="Form">
9+ <property name="geometry">
10+ <rect>
11+ <x>0</x>
12+ <y>0</y>
13+ <width>426</width>
14+ <height>387</height>
15+ </rect>
16+ </property>
17+ <property name="windowTitle">
18+ <string>Form</string>
19+ </property>
20+ <layout class="QVBoxLayout" name="verticalLayout_2">
21+ <property name="spacing">
22+ <number>24</number>
23+ </property>
24+ <item>
25+ <widget class="QLabel" name="label">
26+ <property name="font">
27+ <font>
28+ <pointsize>14</pointsize>
29+ <weight>75</weight>
30+ <bold>true</bold>
31+ </font>
32+ </property>
33+ <property name="text">
34+ <string>Congratulation!</string>
35+ </property>
36+ </widget>
37+ </item>
38+ <item>
39+ <widget class="QLabel" name="label_2">
40+ <property name="text">
41+ <string>Nice picture goes here</string>
42+ </property>
43+ </widget>
44+ </item>
45+ <item>
46+ <widget class="QLabel" name="label_3">
47+ <property name="text">
48+ <string>Ubuntu One is installed, set up and is ready to go!</string>
49+ </property>
50+ </widget>
51+ </item>
52+ <item>
53+ <layout class="QHBoxLayout" name="horizontalLayout">
54+ <item>
55+ <widget class="QLabel" name="label_4">
56+ <property name="text">
57+ <string>IMAGE GOES HERE?</string>
58+ </property>
59+ </widget>
60+ </item>
61+ <item>
62+ <layout class="QVBoxLayout" name="verticalLayout">
63+ <item>
64+ <widget class="QLabel" name="label_5">
65+ <property name="font">
66+ <font>
67+ <weight>75</weight>
68+ <bold>true</bold>
69+ </font>
70+ </property>
71+ <property name="text">
72+ <string>Sync in progress...</string>
73+ </property>
74+ </widget>
75+ </item>
76+ <item>
77+ <widget class="QLabel" name="label_6">
78+ <property name="text">
79+ <string>Your folders have started to sync in the background, launch the dahboard to get more information about the sync in progress</string>
80+ </property>
81+ <property name="wordWrap">
82+ <bool>true</bool>
83+ </property>
84+ </widget>
85+ </item>
86+ </layout>
87+ </item>
88+ </layout>
89+ </item>
90+ <item>
91+ <spacer name="verticalSpacer">
92+ <property name="orientation">
93+ <enum>Qt::Vertical</enum>
94+ </property>
95+ <property name="sizeHint" stdset="0">
96+ <size>
97+ <width>20</width>
98+ <height>40</height>
99+ </size>
100+ </property>
101+ </spacer>
102+ </item>
103+ </layout>
104+ </widget>
105+ <resources/>
106+ <connections/>
107+</ui>
108
109=== added file 'pylintrc'
110--- pylintrc 1970-01-01 00:00:00 +0000
111+++ pylintrc 2011-06-22 14:18:49 +0000
112@@ -0,0 +1,305 @@
113+# lint Python modules using external checkers.
114+#
115+# This is the main checker controlling the other ones and the reports
116+# generation. It is itself both a raw checker and an astng checker in order
117+# to:
118+# * handle message activation / deactivation at the module level
119+# * handle some basic but necessary stats'data (number of classes, methods...)
120+#
121+[MASTER]
122+
123+# Specify a configuration file.
124+#rcfile=
125+
126+# Python code to execute, usually for sys.path manipulation such as
127+# pygtk.require().
128+#init-hook=
129+
130+# Profiled execution.
131+profile=no
132+
133+# Add <file or directory> to the black list. It should be a base name, not a
134+# path. You may set this option multiple times.
135+ignore=ui,qtreactor
136+
137+# Pickle collected data for later comparisons.
138+persistent=no
139+
140+# List of plugins (as comma separated values of python modules names) to load,
141+# usually to register additional checkers.
142+load-plugins=
143+
144+
145+[MESSAGES CONTROL]
146+
147+# Enable only checker(s) with the given id(s). This option conflicts with the
148+# disable-checker option
149+#enable-checker=
150+
151+# Enable all checker(s) except those with the given id(s). This option
152+# conflicts with the enable-checker option
153+#disable-checker=
154+
155+# Enable all messages in the listed categories.
156+#enable-cat=
157+
158+# Disable all messages in the listed categories.
159+#disable-cat=
160+
161+# Disable the message(s) with the given id(s) or categories
162+# W0142: Used * or ** magic
163+# W0613: Unused argument 'yyy'
164+disable=R,I,W0142,W0613,W0511
165+
166+
167+[REPORTS]
168+
169+# Set the output format. Available formats are text, parseable, colorized, msvs
170+# (visual studio) and html
171+output-format=colorized
172+
173+# Include message's id in output
174+include-ids=yes
175+
176+# Put messages in a separate file for each module / package specified on the
177+# command line instead of printing them on stdout. Reports (if any) will be
178+# written in a file name "pylint_global.[txt|html]".
179+files-output=no
180+
181+# Tells whether to display a full report or only the messages
182+reports=no
183+
184+# Python expression which should return a note less than 10 (10 is the highest
185+# note). You have access to the variables errors warning, statement which
186+# respectively contain the number of errors / warnings messages and the total
187+# number of statements analyzed. This is used by the global evaluation report
188+# (R0004).
189+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
190+
191+# Add a comment according to your evaluation note. This is used by the global
192+# evaluation report (R0004).
193+comment=no
194+
195+# Enable the report(s) with the given id(s).
196+#enable-report=
197+
198+# Disable the report(s) with the given id(s).
199+#disable-report=
200+
201+
202+# try to find bugs in the code using type inference
203+#
204+[TYPECHECK]
205+
206+# Tells whether missing members accessed in mixin class should be ignored. A
207+# mixin class is detected if its name ends with "mixin" (case insensitive).
208+ignore-mixin-members=yes
209+
210+# List of classes names for which member attributes should not be checked
211+# (useful for classes with attributes dynamically set).
212+ignored-classes=
213+
214+# When zope mode is activated, add a predefined set of Zope acquired attributes
215+# to generated-members.
216+zope=no
217+
218+# List of members which are set dynamically and missed by pylint inference
219+# system, and so shouldn't trigger E0201 when accessed.
220+generated-members=REQUEST,acl_users,aq_parent
221+
222+
223+# checks for
224+# * unused variables / imports
225+# * undefined variables
226+# * redefinition of variable from builtins or from an outer scope
227+# * use of variable before assignment
228+#
229+[VARIABLES]
230+
231+# Tells whether we should check for unused import in __init__ files.
232+init-import=yes
233+
234+# A regular expression matching names used for dummy variables (i.e. not used).
235+dummy-variables-rgx=_|dummy
236+
237+# List of additional names supposed to be defined in builtins. Remember that
238+# you should avoid to define new builtins when possible.
239+additional-builtins=
240+
241+
242+# checks for :
243+# * doc strings
244+# * modules / classes / functions / methods / arguments / variables name
245+# * number of arguments, local variables, branches, returns and statements in
246+# functions, methods
247+# * required module attributes
248+# * dangerous default values as arguments
249+# * redefinition of function / method / class
250+# * uses of the global statement
251+#
252+[BASIC]
253+
254+# Required attributes for module, separated by a comma
255+required-attributes=
256+
257+# Regular expression which should only match functions or classes name which do
258+# not require a docstring
259+no-docstring-rgx=(__.*__|setUp|tearDown)
260+
261+# Regular expression which should only match correct module names
262+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
263+
264+# Regular expression which should only match correct module level names
265+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
266+
267+# Regular expression which should only match correct class names
268+class-rgx=[A-Z_][a-zA-Z0-9]+$
269+
270+# Regular expression which should only match correct function names
271+function-rgx=[a-z_][a-z0-9_]{2,79}$
272+
273+# Regular expression which should only match correct method names
274+method-rgx=([a-z_][a-z0-9_]{2,79}$|setUp|tearDown)
275+
276+# Regular expression which should only match correct instance attribute names
277+attr-rgx=[a-z_][a-z0-9_]{1,30}$
278+
279+# Regular expression which should only match correct argument names
280+argument-rgx=[a-z_][a-z0-9_]{1,30}$
281+
282+# Regular expression which should only match correct variable names
283+variable-rgx=[a-z_][a-z0-9_]{1,30}$
284+
285+# Regular expression which should only match correct list comprehension /
286+# generator expression variable names
287+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
288+
289+# Good variable names which should always be accepted, separated by a comma
290+good-names=d,e,f,g,i,j,k,ex,logger,Run,_
291+
292+# Bad variable names which should always be refused, separated by a comma
293+bad-names=foo,bar,baz,toto,tutu,tata
294+
295+# List of builtins function names that should not be used, separated by a comma
296+bad-functions=apply,input,reduce
297+
298+
299+# checks for sign of poor/misdesign:
300+# * number of methods, attributes, local variables...
301+# * size, complexity of functions, methods
302+#
303+[DESIGN]
304+
305+# Maximum number of arguments for function / method
306+max-args=5
307+
308+# Maximum number of locals for function / method body
309+max-locals=15
310+
311+# Maximum number of return / yield for function / method body
312+max-returns=6
313+
314+# Maximum number of branch for function / method body
315+max-branchs=12
316+
317+# Maximum number of statements in function / method body
318+max-statements=50
319+
320+# Maximum number of parents for a class (see R0901).
321+max-parents=7
322+
323+# Maximum number of attributes for a class (see R0902).
324+max-attributes=7
325+
326+# Minimum number of public methods for a class (see R0903).
327+min-public-methods=2
328+
329+# Maximum number of public methods for a class (see R0904).
330+max-public-methods=20
331+
332+
333+# checks for :
334+# * methods without self as first argument
335+# * overridden methods signature
336+# * access only to existent members via self
337+# * attributes not defined in the __init__ method
338+# * supported interfaces implementation
339+# * unreachable code
340+#
341+[CLASSES]
342+
343+# List of interface methods to ignore, separated by a comma. This is used for
344+# instance to not check methods defines in Zopes Interface base class.
345+#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by,providedBy
346+
347+# List of method names used to declare (i.e. assign) instance attributes.
348+defining-attr-methods=__init__,__new__,setUp
349+
350+
351+# checks for
352+# * external modules dependencies
353+# * relative / wildcard imports
354+# * cyclic imports
355+# * uses of deprecated modules
356+#
357+[IMPORTS]
358+
359+# Deprecated modules which should not be used, separated by a comma
360+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
361+
362+# Create a graph of every (i.e. internal and external) dependencies in the
363+# given file (report RP0402 must not be disabled)
364+import-graph=
365+
366+# Create a graph of external dependencies in the given file (report RP0402 must
367+# not be disabled)
368+ext-import-graph=
369+
370+# Create a graph of internal dependencies in the given file (report RP0402 must
371+# not be disabled)
372+int-import-graph=
373+
374+
375+# checks for :
376+# * unauthorized constructions
377+# * strict indentation
378+# * line length
379+# * use of <> instead of !=
380+#
381+[FORMAT]
382+
383+# Maximum number of characters on a single line.
384+max-line-length=79
385+
386+# Maximum number of lines in a module
387+max-module-lines=2500
388+
389+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
390+# tab).
391+indent-string=' '
392+
393+
394+# checks for similarities and duplicated code. This computation may be
395+# memory / CPU intensive, so you should disable it if you experiments some
396+# problems.
397+#
398+[SIMILARITIES]
399+
400+# Minimum lines number of a similarity.
401+min-similarity-lines=4
402+
403+# Ignore comments when computing similarities.
404+ignore-comments=yes
405+
406+# Ignore docstrings when computing similarities.
407+ignore-docstrings=yes
408+
409+
410+# checks for:
411+# * warning notes in the code like FIXME, XXX
412+# * PEP 263: source code with non ascii character but no encoding declaration
413+#
414+[MISCELLANEOUS]
415+
416+# List of note tags to take in consideration, separated by a comma.
417+notes=FIXME,XXX,TODO,fixme,xxx,todo
418
419=== modified file 'run-tests'
420--- run-tests 2011-06-21 20:01:26 +0000
421+++ run-tests 2011-06-22 14:18:49 +0000
422@@ -37,7 +37,7 @@
423
424 ./setup.py build
425 echo "Running test suite for ""$MODULE"
426-`which xvfb-run` u1trial "$MODULE"
427+`which xvfb-run` u1trial --reactor=qt4 --gui "$MODULE"
428 style_check
429 rm -rf _trial_temp
430 rm -rf build
431
432=== modified file 'ubuntuone_installer/__init__.py'
433--- ubuntuone_installer/__init__.py 2011-06-21 15:41:55 +0000
434+++ ubuntuone_installer/__init__.py 2011-06-22 14:18:49 +0000
435@@ -19,7 +19,7 @@
436
437 """The windows installer for Ubuntu One.
438
439-The installer is a wizard that sets up the basic account and configuration for
440+The installer is a wizard that sets up the basic account and configuration for
441 a Ubuntu One user on windows.
442 """
443
444
445=== modified file 'ubuntuone_installer/gui/qt/__init__.py'
446--- ubuntuone_installer/gui/qt/__init__.py 2011-06-21 18:18:33 +0000
447+++ ubuntuone_installer/gui/qt/__init__.py 2011-06-22 14:18:49 +0000
448@@ -17,4 +17,3 @@
449 # with this program. If not, see <http://www.gnu.org/licenses/>.
450
451 """The Qt graphical interface for the Ubuntu One Installer."""
452-
453
454=== modified file 'ubuntuone_installer/gui/qt/gui.py'
455--- ubuntuone_installer/gui/qt/gui.py 2011-06-21 19:46:39 +0000
456+++ ubuntuone_installer/gui/qt/gui.py 2011-06-22 14:18:49 +0000
457@@ -19,32 +19,37 @@
458
459 """The user interface for the Ubuntu One Installer."""
460
461+import subprocess
462
463 from PyQt4 import QtGui
464
465 from ubuntuone_installer.logger import setup_logging
466-from ubuntuone_installer.gui.qt.ui import license_ui
467+from ubuntuone_installer.gui.qt.ui import (
468+ license_ui,
469+ congratulations_ui,
470+)
471
472 import gettext
473
474 _ = gettext.gettext
475
476+# Invalid name logger
477+# pylint: disable=C0103
478 logger = setup_logging('qt.gui')
479+# pylint: enable=C0103
480
481
482 class LicensePage(QtGui.QWizardPage):
483 """Wizard Page that displays the license info and links to the GPL"""
484
485- # Invalid constant names and Qt-inherited methods
486- # pylint: disable=C0103
487-
488- LICENSE_PAGE = 0
489-
490 def __init__(self, parent=None):
491 QtGui.QWizardPage.__init__(self, parent)
492 self.ui = license_ui.Ui_Form()
493 self.ui.setupUi(self)
494
495+ # Invalid names of Qt-inherited methods
496+ # pylint: disable=C0103
497+
498 def initializePage(self):
499 """Setup UI details"""
500
501@@ -55,50 +60,79 @@
502 # Set the right texts and connections for buttons
503 self.setButtonText(QtGui.QWizard.NextButton, _("Agree && Install"))
504 self.setButtonText(QtGui.QWizard.CancelButton,
505- _("Disagree && Cancel"))
506- self.setButtonText(QtGui.QWizard.CustomButton1, _("&Print"))
507- self.wizard().customButtonClicked.connect(self.printDocument)
508-
509- def printDocument(self, button_id):
510+ _("Disagree && Cancel"))
511+ self.setButtonText(QtGui.QWizard.CustomButton1, _("&Print"))
512+ self.wizard().customButtonClicked.connect(self.print_document)
513+
514+ def print_document(self, button_id):
515 """Print the document displayed in textBrowser"""
516-
517+
518 if button_id == QtGui.QWizard.CustomButton1:
519 document = self.ui.textBrowser.document()
520 printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
521
522 dialog = QtGui.QPrintDialog(printer, self)
523-
524+
525 dialog.setWindowTitle(_("Send to printer"))
526 if dialog.exec_() != QtGui.QDialog.Accepted:
527 return
528 printer.setFullPage(True)
529 printer.setPageSize(QtGui.QPrinter.A4)
530 document.print_(printer)
531-
532+
533+
534+class CongratulationsPage(QtGui.QWizardPage):
535+ """Final page of the wizard"""
536+
537+ def __init__(self, parent=None):
538+ QtGui.QWizardPage.__init__(self, parent)
539+ self.ui = congratulations_ui.Ui_Form()
540+ self.ui.setupUi(self)
541+
542+ # Invalid names of Qt-inherited methods
543+ # pylint: disable=C0103
544+
545+ def initializePage(self):
546+ """Setup UI details"""
547+
548+ # We need custom buttons
549+ self.wizard().setButtonText(QtGui.QWizard.FinishButton,
550+ _("Go to my Ubuntu One dashboard"))
551+ self.wizard().setOption(QtGui.QWizard.HaveCustomButton1, False)
552+ self.wizard().setOption(QtGui.QWizard.NoCancelButton, True)
553+
554
555 class MainWindow(QtGui.QWizard):
556 """The Main Window of the Installer wizard."""
557
558+ # Invalid constant names and Qt-inherited methods
559+ # pylint: disable=C0103
560+
561+ LICENSE_PAGE = 0
562+ CONGRATULATIONS_PAGE = 1
563+
564 def __init__(self, close_callback=None):
565 """Initialize this instance with the UI layout."""
566+
567 QtGui.QWizard.__init__(self)
568 self.close_callback = close_callback
569
570 self.setOption(self.NoBackButtonOnStartPage, True)
571-
572+ self.setOption(self.DisabledBackButtonOnLastPage, True)
573 # PyQt doesn't support the (int, page) version of addPage
574 # Add the pages in the right order
575-
576+
577 # pylint: disable=C0103
578 self.LICENSE_PAGE = self.addPage(LicensePage())
579- # Dummy page to have a "Next"
580- self.addPage(QtGui.QWizardPage())
581+ self.CONGRATULATIONS_PAGE = self.addPage(CongratulationsPage())
582
583 # Invalid name "closeEvent"
584 # pylint: disable=C0103
585
586 def done(self, result):
587 """The main window is being closed, call any custom callback."""
588+ if result == 1: # Finished, not cancelled
589+ subprocess.Popen(["ubuntuone-control-panel-qt", ])
590 if self.close_callback is not None:
591 self.close_callback()
592 QtGui.QWizard.done(self, result)
593
594=== added directory 'ubuntuone_installer/gui/qt/tests'
595=== added file 'ubuntuone_installer/gui/qt/tests/__init__.py'
596--- ubuntuone_installer/gui/qt/tests/__init__.py 1970-01-01 00:00:00 +0000
597+++ ubuntuone_installer/gui/qt/tests/__init__.py 2011-06-22 14:18:49 +0000
598@@ -0,0 +1,68 @@
599+# -*- coding: utf-8 -*-
600+
601+# Authors: Alejandro J. Cura <alecu@canonical.com>
602+#
603+# Copyright 2011 Canonical Ltd.
604+#
605+# This program is free software: you can redistribute it and/or modify it
606+# under the terms of the GNU General Public License version 3, as published
607+# by the Free Software Foundation.
608+#
609+# This program is distributed in the hope that it will be useful, but
610+# WITHOUT ANY WARRANTY; without even the implied warranties of
611+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
612+# PURPOSE. See the GNU General Public License for more details.
613+#
614+# You should have received a copy of the GNU General Public License along
615+# with this program. If not, see <http://www.gnu.org/licenses/>.
616+
617+"""The test suite for the Qt UI of the Ubuntu One Installer."""
618+
619+from ubuntuone_installer.tests import TestCase
620+from ubuntuone_installer.gui.tests import FakedObject
621+
622+# Attribute 'yyy' defined outside __init__, access to a protected member
623+# pylint: disable=W0201, W0212
624+
625+
626+NO_OP = lambda *args: None
627+
628+
629+def skip_if_abstract_class(test):
630+ """Decorator to skip a test if is an abstract class."""
631+
632+ def inner(instance):
633+ """Skip a test if is an abstract class."""
634+ abstract = instance.class_ui is None
635+ result = None
636+ if not abstract:
637+ result = test(instance)
638+
639+ return result
640+
641+ return inner
642+
643+
644+class FakeUi(FakedObject):
645+ """A fake Ui object."""
646+
647+ exposed_methods = ['setupUi']
648+
649+
650+class BaseTestCase(TestCase):
651+ """Base Test Case."""
652+
653+ class_ui = None
654+ kwargs = {}
655+
656+ @skip_if_abstract_class
657+ def setUp(self):
658+ super(BaseTestCase, self).setUp()
659+ # self.class_ui is not callable
660+ # pylint: disable=E1102
661+ # pylint: disable=C0103
662+ self.ui = self.class_ui(**self.kwargs)
663+
664+ if hasattr(self.ui, 'backend'):
665+ # clean backend calls
666+ self.ui.backend._called.clear()
667
668=== added file 'ubuntuone_installer/gui/qt/tests/test_gui.py'
669--- ubuntuone_installer/gui/qt/tests/test_gui.py 1970-01-01 00:00:00 +0000
670+++ ubuntuone_installer/gui/qt/tests/test_gui.py 2011-06-22 14:18:49 +0000
671@@ -0,0 +1,61 @@
672+# -*- coding: utf-8 -*-
673+
674+# Authors: Alejandro J. Cura <alecu@canonical.com>
675+# Roberto Alsina <roberto.alsina@canonical.com>
676+#
677+# Copyright 2011 Canonical Ltd.
678+#
679+# This program is free software: you can redistribute it and/or modify it
680+# under the terms of the GNU General Public License version 3, as published
681+# by the Free Software Foundation.
682+#
683+# This program is distributed in the hope that it will be useful, but
684+# WITHOUT ANY WARRANTY; without even the implied warranties of
685+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
686+# PURPOSE. See the GNU General Public License for more details.
687+#
688+# You should have received a copy of the GNU General Public License along
689+# with this program. If not, see <http://www.gnu.org/licenses/>.
690+
691+"""Tests for the Qt UI."""
692+
693+from ubuntuone_installer.gui.qt import gui
694+from ubuntuone_installer.gui.qt.tests import BaseTestCase
695+
696+
697+class MainWindowTestCase(BaseTestCase):
698+ """Test the qt main window."""
699+
700+ class_ui = gui.MainWindow
701+
702+ def setUp(self):
703+ """Initialize this test instance."""
704+ super(MainWindowTestCase, self).setUp()
705+
706+ def test_done_calls_custom_close_callback(self):
707+ """When closing the window, close_callback is called."""
708+ self.ui.close_callback = self._set_called
709+ self.ui.done(result=0)
710+ self.assertEqual(self._called,
711+ ((), {}), 'close_callback called.')
712+
713+ def test_close_callback_can_be_none(self):
714+ """The close_callback can be None."""
715+ self.ui.close_callback = None
716+ self.ui.done(result=0)
717+ # world did not explode
718+
719+ def test_start_control_panel_on_finishing(self):
720+ """If done is called with result=1, the control panel
721+ should be called"""
722+ self.patch(gui.subprocess, "Popen", self._set_called)
723+ self.ui.done(result=1)
724+ self.assertEqual(self._called,
725+ ((['ubuntuone-control-panel-qt'],), {}))
726+
727+ def test_not_start_control_panel_on_cancel(self):
728+ """If done is called with result=0, the control panel
729+ should NOT be called"""
730+ self.patch(gui.subprocess, "Popen", self._set_called)
731+ self.ui.done(result=0)
732+ self.assertEqual(self._called, False)
733
734=== added directory 'ubuntuone_installer/gui/tests'
735=== added file 'ubuntuone_installer/gui/tests/__init__.py'
736--- ubuntuone_installer/gui/tests/__init__.py 1970-01-01 00:00:00 +0000
737+++ ubuntuone_installer/gui/tests/__init__.py 2011-06-22 14:18:49 +0000
738@@ -0,0 +1,45 @@
739+# -*- coding: utf-8 -*-
740+
741+# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
742+# Roberto Alsina <roberto.alsina@canonical.com>
743+#
744+# Copyright 2011 Canonical Ltd.
745+#
746+# This program is free software: you can redistribute it and/or modify it
747+# under the terms of the GNU General Public License version 3, as published
748+# by the Free Software Foundation.
749+#
750+# This program is distributed in the hope that it will be useful, but
751+# WITHOUT ANY WARRANTY; without even the implied warranties of
752+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
753+# PURPOSE. See the GNU General Public License for more details.
754+#
755+# You should have received a copy of the GNU General Public License along
756+# with this program. If not, see <http://www.gnu.org/licenses/>.
757+
758+"""The test suite for the Ubuntu One Installer."""
759+
760+# Attribute 'yyy' defined outside __init__, access to a protected member
761+# pylint: disable=W0201, W0212
762+
763+
764+class FakedObject(object):
765+ """Fake an object, record every call."""
766+
767+ exposed_methods = []
768+
769+ def __init__(self, *args, **kwargs):
770+ self._args = args
771+ self._kwargs = kwargs
772+ self._called = {}
773+ for i in self.exposed_methods:
774+ setattr(self, i, self._record_call(i))
775+
776+ def _record_call(self, func_name):
777+ """Store values when calling 'func_name'."""
778+
779+ def inner(*args, **kwargs):
780+ """Fake 'func_name'."""
781+ self._called[func_name] = (args, kwargs)
782+
783+ return inner
784
785=== added directory 'ubuntuone_installer/tests'
786=== added file 'ubuntuone_installer/tests/__init__.py'
787--- ubuntuone_installer/tests/__init__.py 1970-01-01 00:00:00 +0000
788+++ ubuntuone_installer/tests/__init__.py 2011-06-22 14:18:49 +0000
789@@ -0,0 +1,38 @@
790+# -*- coding: utf-8 -*-
791+
792+# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
793+# Roberto Alsina <roberto.alsina@canonical.com>
794+#
795+# Copyright 2010-2011 Canonical Ltd.
796+#
797+# This program is free software: you can redistribute it and/or modify it
798+# under the terms of the GNU General Public License version 3, as published
799+# by the Free Software Foundation.
800+#
801+# This program is distributed in the hope that it will be useful, but
802+# WITHOUT ANY WARRANTY; without even the implied warranties of
803+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
804+# PURPOSE. See the GNU General Public License for more details.
805+#
806+# You should have received a copy of the GNU General Public License along
807+# with this program. If not, see <http://www.gnu.org/licenses/>.
808+
809+"""The test suite for the Ubuntu One Installer"""
810+
811+from ubuntuone.devtools.testcase import TestCase as BaseTestCase
812+
813+
814+class TestCase(BaseTestCase):
815+ """Basics for testing."""
816+
817+ assertIs = BaseTestCase.assertIdentical
818+
819+ def setUp(self):
820+ self._called = False
821+
822+ def tearDown(self):
823+ self._called = False
824+
825+ def _set_called(self, *args, **kwargs):
826+ """Store 'args' and 'kwargs' for test assertions."""
827+ self._called = (args, kwargs)

Subscribers

People subscribed via source and target branches