Merge lp:~diegosarmentero/ubuntu-sso-client/reset-password-page into lp:ubuntu-sso-client
- reset-password-page
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Natalia Bidart |
Approved revision: | 778 |
Merged at revision: | 772 |
Proposed branch: | lp:~diegosarmentero/ubuntu-sso-client/reset-password-page |
Merge into: | lp:ubuntu-sso-client |
Diff against target: |
748 lines (+604/-56) 5 files modified
data/qt/reset_password.ui (+130/-54) ubuntu_sso/qt/common.py (+94/-0) ubuntu_sso/qt/gui.py (+47/-2) ubuntu_sso/qt/tests/test_common.py (+234/-0) ubuntu_sso/qt/tests/test_reset_password.py (+99/-0) |
To merge this branch: | bzr merge lp:~diegosarmentero/ubuntu-sso-client/reset-password-page |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Natalia Bidart (community) | Approve | ||
Roberto Alsina (community) | Approve | ||
Review via email: mp+73522@code.launchpad.net |
Commit message
Reset Password Page Complete.
Description of the change
Reset Password Page Complete.
Natalia Bidart (nataliabidart) wrote : | # |
We need to maintain a strict separation between the modules where, all the QT related stuff end inside the gui/qt python package. So all the new addings to ubuntu_
So, we can't have QT-specific markup such as BAD, GOOD, NORMAL nor any of the password_* or check_* methods. If you need a common place, I would advice gui/qt/__init__.py or a gui/qt/common.py module.
Of course tests should be moved too.
For reference, when running the non-qt suite, I'm having a crash like this:
LineEditStyle
test_
Aborted
because if no -qt switch is given, we use the glib reactor (and we want to keep that suite running with that reactor).
- 774. By Diego Sarmentero
-
Added Qt common functionality to common.py module.
Natalia Bidart (nataliabidart) wrote : | # |
* ubuntu_
82: [W0212, SetupAccountTes
85: [W0212, SetupAccountTes
93: [W0212, SetupAccountTes
96: [W0212, SetupAccountTes
* Question: should showEvent and hideEvent call super()?
* Silly fix: ubuntu_
* This is not valid style for our project!
+from ubuntu_
+ check_as_valid,
+ password_
+ password_
+ BAD,
+ GOOD,
+ NORMAL,
+ PASSWORD_DIGIT,
+ PASSWORD_LENGTH,
+ PASSWORD_MATCH,
+ PASSWORD_UPPER)
+
it should be:
+from ubuntu_
+ check_as_valid,
+ password_
+ password_
+ BAD,
+ GOOD,
+ NORMAL,
+ PASSWORD_DIGIT,
+ PASSWORD_LENGTH,
+ PASSWORD_MATCH,
+ PASSWORD_UPPER,
+)
* I advice to use twisted TestCase instead of unittest's.
* I think there is no need to cut off some sentences like:
+ password_
+ label_assistance)
can you please check the rest?
* Can we have this moved to a setUp? seems to be used in every test:
+ line_edit = QtGui.QLineEdit()
+ label_assistance = QtGui.QLabel()
* This two should be together by alphabetical order:
+from PyQt4 import QtCore, QtGui
+from twisted.
It looks really good! Big applause for all the tests!
- 775. By Diego Sarmentero
-
Fixed to follow some coding guidelines.
- 776. By Diego Sarmentero
-
Fixed lint issues
- 777. By Diego Sarmentero
-
Added bug number.
Moving button to the bottom right.
Natalia Bidart (nataliabidart) wrote : | # |
Looks good!
- 778. By Diego Sarmentero
-
Changed import order for PyQt4 modules to avoid some issues.
Preview Diff
1 | === modified file 'data/qt/reset_password.ui' |
2 | --- data/qt/reset_password.ui 2011-08-05 14:37:00 +0000 |
3 | +++ data/qt/reset_password.ui 2011-09-02 11:41:29 +0000 |
4 | @@ -6,7 +6,7 @@ |
5 | <rect> |
6 | <x>0</x> |
7 | <y>0</y> |
8 | - <width>476</width> |
9 | + <width>580</width> |
10 | <height>262</height> |
11 | </rect> |
12 | </property> |
13 | @@ -17,25 +17,37 @@ |
14 | <item> |
15 | <layout class="QHBoxLayout" name="horizontalLayout"> |
16 | <item> |
17 | - <spacer name="horizontalSpacer_2"> |
18 | - <property name="orientation"> |
19 | - <enum>Qt::Horizontal</enum> |
20 | - </property> |
21 | - <property name="sizeHint" stdset="0"> |
22 | - <size> |
23 | - <width>40</width> |
24 | - <height>20</height> |
25 | - </size> |
26 | - </property> |
27 | - </spacer> |
28 | - </item> |
29 | - <item> |
30 | <layout class="QVBoxLayout" name="verticalLayout_2"> |
31 | <item> |
32 | - <widget class="QLineEdit" name="reset_code_line_edit"/> |
33 | + <widget class="QLineEdit" name="reset_code_line_edit"> |
34 | + <property name="minimumSize"> |
35 | + <size> |
36 | + <width>300</width> |
37 | + <height>0</height> |
38 | + </size> |
39 | + </property> |
40 | + <property name="maximumSize"> |
41 | + <size> |
42 | + <width>300</width> |
43 | + <height>16777215</height> |
44 | + </size> |
45 | + </property> |
46 | + </widget> |
47 | </item> |
48 | <item> |
49 | <widget class="QLineEdit" name="password_line_edit"> |
50 | + <property name="minimumSize"> |
51 | + <size> |
52 | + <width>300</width> |
53 | + <height>0</height> |
54 | + </size> |
55 | + </property> |
56 | + <property name="maximumSize"> |
57 | + <size> |
58 | + <width>300</width> |
59 | + <height>16777215</height> |
60 | + </size> |
61 | + </property> |
62 | <property name="echoMode"> |
63 | <enum>QLineEdit::Password</enum> |
64 | </property> |
65 | @@ -43,46 +55,31 @@ |
66 | </item> |
67 | <item> |
68 | <widget class="QLineEdit" name="confirm_password_line_edit"> |
69 | + <property name="minimumSize"> |
70 | + <size> |
71 | + <width>300</width> |
72 | + <height>0</height> |
73 | + </size> |
74 | + </property> |
75 | + <property name="maximumSize"> |
76 | + <size> |
77 | + <width>300</width> |
78 | + <height>16777215</height> |
79 | + </size> |
80 | + </property> |
81 | <property name="echoMode"> |
82 | <enum>QLineEdit::Password</enum> |
83 | </property> |
84 | </widget> |
85 | </item> |
86 | <item> |
87 | - <layout class="QHBoxLayout" name="horizontalLayout_3"> |
88 | - <item> |
89 | - <spacer name="horizontalSpacer_4"> |
90 | - <property name="orientation"> |
91 | - <enum>Qt::Horizontal</enum> |
92 | - </property> |
93 | - <property name="sizeHint" stdset="0"> |
94 | - <size> |
95 | - <width>40</width> |
96 | - <height>20</height> |
97 | - </size> |
98 | - </property> |
99 | - </spacer> |
100 | - </item> |
101 | - <item> |
102 | - <widget class="QPushButton" name="reset_password_button"> |
103 | - <property name="enabled"> |
104 | - <bool>false</bool> |
105 | - </property> |
106 | - <property name="text"> |
107 | - <string/> |
108 | - </property> |
109 | - </widget> |
110 | - </item> |
111 | - </layout> |
112 | - </item> |
113 | - <item> |
114 | <spacer name="verticalSpacer"> |
115 | <property name="orientation"> |
116 | <enum>Qt::Vertical</enum> |
117 | </property> |
118 | <property name="sizeHint" stdset="0"> |
119 | <size> |
120 | - <width>379</width> |
121 | + <width>300</width> |
122 | <height>222</height> |
123 | </size> |
124 | </property> |
125 | @@ -91,17 +88,96 @@ |
126 | </layout> |
127 | </item> |
128 | <item> |
129 | - <spacer name="horizontalSpacer"> |
130 | - <property name="orientation"> |
131 | - <enum>Qt::Horizontal</enum> |
132 | - </property> |
133 | - <property name="sizeHint" stdset="0"> |
134 | - <size> |
135 | - <width>40</width> |
136 | - <height>20</height> |
137 | - </size> |
138 | - </property> |
139 | - </spacer> |
140 | + <layout class="QVBoxLayout" name="verticalLayout_3"> |
141 | + <item> |
142 | + <widget class="QLabel" name="password_assistance"> |
143 | + <property name="minimumSize"> |
144 | + <size> |
145 | + <width>250</width> |
146 | + <height>100</height> |
147 | + </size> |
148 | + </property> |
149 | + <property name="maximumSize"> |
150 | + <size> |
151 | + <width>300</width> |
152 | + <height>16777215</height> |
153 | + </size> |
154 | + </property> |
155 | + <property name="text"> |
156 | + <string>password_assistance</string> |
157 | + </property> |
158 | + <property name="indent"> |
159 | + <number>20</number> |
160 | + </property> |
161 | + </widget> |
162 | + </item> |
163 | + <item> |
164 | + <spacer name="verticalSpacer_2"> |
165 | + <property name="orientation"> |
166 | + <enum>Qt::Vertical</enum> |
167 | + </property> |
168 | + <property name="sizeHint" stdset="0"> |
169 | + <size> |
170 | + <width>20</width> |
171 | + <height>40</height> |
172 | + </size> |
173 | + </property> |
174 | + </spacer> |
175 | + </item> |
176 | + <item> |
177 | + <spacer name="horizontalSpacer"> |
178 | + <property name="orientation"> |
179 | + <enum>Qt::Horizontal</enum> |
180 | + </property> |
181 | + <property name="sizeType"> |
182 | + <enum>QSizePolicy::Fixed</enum> |
183 | + </property> |
184 | + <property name="sizeHint" stdset="0"> |
185 | + <size> |
186 | + <width>250</width> |
187 | + <height>0</height> |
188 | + </size> |
189 | + </property> |
190 | + </spacer> |
191 | + </item> |
192 | + </layout> |
193 | + </item> |
194 | + </layout> |
195 | + </item> |
196 | + <item> |
197 | + <layout class="QHBoxLayout" name="horizontalLayout_2"> |
198 | + <item> |
199 | + <layout class="QHBoxLayout" name="horizontalLayout_3"> |
200 | + <property name="rightMargin"> |
201 | + <number>0</number> |
202 | + </property> |
203 | + <item> |
204 | + <spacer name="horizontalSpacer_4"> |
205 | + <property name="orientation"> |
206 | + <enum>Qt::Horizontal</enum> |
207 | + </property> |
208 | + <property name="sizeType"> |
209 | + <enum>QSizePolicy::Expanding</enum> |
210 | + </property> |
211 | + <property name="sizeHint" stdset="0"> |
212 | + <size> |
213 | + <width>40</width> |
214 | + <height>20</height> |
215 | + </size> |
216 | + </property> |
217 | + </spacer> |
218 | + </item> |
219 | + <item> |
220 | + <widget class="QPushButton" name="reset_password_button"> |
221 | + <property name="enabled"> |
222 | + <bool>false</bool> |
223 | + </property> |
224 | + <property name="text"> |
225 | + <string/> |
226 | + </property> |
227 | + </widget> |
228 | + </item> |
229 | + </layout> |
230 | </item> |
231 | </layout> |
232 | </item> |
233 | |
234 | === added file 'ubuntu_sso/qt/common.py' |
235 | --- ubuntu_sso/qt/common.py 1970-01-01 00:00:00 +0000 |
236 | +++ ubuntu_sso/qt/common.py 2011-09-02 11:41:29 +0000 |
237 | @@ -0,0 +1,94 @@ |
238 | +# -*- coding: utf-8 -*- |
239 | +# |
240 | +# Author: Diego Sarmentero <diego.sarmentero@canonical.com> |
241 | +# |
242 | +# Copyright 2011 Canonical Ltd. |
243 | +# |
244 | +# This program is free software: you can redistribute it and/or modify it |
245 | +# under the terms of the GNU General Public License version 3, as published |
246 | +# by the Free Software Foundation. |
247 | +# |
248 | +# This program is distributed in the hope that it will be useful, but |
249 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
250 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
251 | +# PURPOSE. See the GNU General Public License for more details. |
252 | +# |
253 | +# You should have received a copy of the GNU General Public License along |
254 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
255 | +"""Common functionality used by the UI modules.""" |
256 | + |
257 | +import re |
258 | +import gettext |
259 | + |
260 | +gettext.textdomain('ubuntu-sso-client') |
261 | +_ = gettext.gettext |
262 | + |
263 | +# all the text + styles that are used in the gui |
264 | +BAD = u'<img src=":/password_hint_warning.png" /><font> %s </font>' |
265 | +GOOD = u'<img src=":/password_hint_ok.png" /><font> %s </font>' |
266 | +NORMAL = u'<font> %s </font>' |
267 | +PASSWORD_DIGIT = _("At least one number") |
268 | +PASSWORD_LENGTH = _("At least 8 characters") |
269 | +PASSWORD_MATCH = _("Passwords don't match") |
270 | +PASSWORD_MUST_CONTAIN = _("Your password must contain") |
271 | +PASSWORD_UPPER = _("At least one uppercase letter") |
272 | + |
273 | + |
274 | +def password_assistance(line_edit, assistance, icon_type=BAD): |
275 | + """Show help for the password field.""" |
276 | + text1 = unicode(line_edit.text()) |
277 | + label_text = ["<b>%s</b>" % PASSWORD_MUST_CONTAIN, ] |
278 | + |
279 | + if len(text1) < 8: |
280 | + sign = icon_type |
281 | + else: |
282 | + sign = GOOD |
283 | + label_text.append(sign % PASSWORD_LENGTH) |
284 | + |
285 | + if re.search('[A-Z]', text1) is None: |
286 | + sign = icon_type |
287 | + else: |
288 | + sign = GOOD |
289 | + label_text.append(sign % PASSWORD_UPPER) |
290 | + |
291 | + if re.search('[\d+]', text1) is None: |
292 | + sign = icon_type |
293 | + else: |
294 | + sign = GOOD |
295 | + label_text.append(sign % PASSWORD_DIGIT) |
296 | + |
297 | + assistance.setText("<br>".join(label_text)) |
298 | + |
299 | + |
300 | +def password_check_match(line_edit, line_edit_confirm, assistance): |
301 | + """Check if passwords match, otherwise show a message.""" |
302 | + password_assistance(line_edit, assistance) |
303 | + label_text = unicode(assistance.text()) |
304 | + text1 = unicode(line_edit.text()) |
305 | + text2 = unicode(line_edit_confirm.text()) |
306 | + if text1 != text2: |
307 | + label_text += "<br>" + BAD % PASSWORD_MATCH |
308 | + assistance.setText(label_text) |
309 | + |
310 | + |
311 | +def password_default_assistance(assistance): |
312 | + """Show default help for the password field.""" |
313 | + label_text = ["<b>%s</b>" % PASSWORD_MUST_CONTAIN, ] |
314 | + label_text.append(NORMAL % PASSWORD_LENGTH) |
315 | + label_text.append(NORMAL % PASSWORD_UPPER) |
316 | + label_text.append(NORMAL % PASSWORD_DIGIT) |
317 | + assistance.setText("<br>".join(label_text)) |
318 | + |
319 | + |
320 | +def check_as_invalid(line_edit): |
321 | + """Set QLineEdit's formError property as True, refresh the style.""" |
322 | + line_edit.setProperty("formError", True) |
323 | + line_edit.style().unpolish(line_edit) |
324 | + line_edit.style().polish(line_edit) |
325 | + |
326 | + |
327 | +def check_as_valid(line_edit): |
328 | + """Set QLineEdit's formError property as False, refresh the style.""" |
329 | + line_edit.setProperty("formError", False) |
330 | + line_edit.style().unpolish(line_edit) |
331 | + line_edit.style().polish(line_edit) |
332 | |
333 | === modified file 'ubuntu_sso/qt/gui.py' |
334 | --- ubuntu_sso/qt/gui.py 2011-08-26 18:21:29 +0000 |
335 | +++ ubuntu_sso/qt/gui.py 2011-09-02 11:41:29 +0000 |
336 | @@ -16,8 +16,7 @@ |
337 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
338 | """Qt implementation of the UI.""" |
339 | |
340 | -from PyQt4.QtCore import pyqtSignal |
341 | -from PyQt4.QtCore import Qt |
342 | +from PyQt4.QtCore import pyqtSignal, Qt, SIGNAL |
343 | from PyQt4.QtGui import ( |
344 | QApplication, |
345 | QWidget, |
346 | @@ -31,6 +30,7 @@ |
347 | QLabel) |
348 | |
349 | from ubuntu_sso.logger import setup_logging |
350 | +from ubuntu_sso.qt import common |
351 | # pylint: disable=F0401,E0611 |
352 | from ubuntu_sso.qt.choose_sign_in_ui import Ui_ChooseSignInPage |
353 | from ubuntu_sso.qt.current_user_sign_in_ui import Ui_CurrentUserSignInPage |
354 | @@ -289,6 +289,51 @@ |
355 | def __init__(self, ui, controller, parent=None): |
356 | """Create a new instance.""" |
357 | SSOWizardEnhancedEditPage.__init__(self, ui, controller, parent) |
358 | + self.ui.password_line_edit.textEdited.connect( |
359 | + lambda: common.password_assistance(self.ui.password_line_edit, |
360 | + self.ui.password_assistance, |
361 | + common.NORMAL)) |
362 | + self.ui.confirm_password_line_edit.textEdited.connect( |
363 | + lambda: common.password_check_match(self.ui.password_line_edit, |
364 | + self.ui.confirm_password_line_edit, |
365 | + self.ui.password_assistance)) |
366 | + |
367 | + def focus_changed(self, old, now): |
368 | + """Check who has the focus to activate password popups if necessary.""" |
369 | + if now == self.ui.password_line_edit: |
370 | + self.ui.password_assistance.setVisible(True) |
371 | + common.password_default_assistance(self.ui.password_assistance) |
372 | + elif now == self.ui.confirm_password_line_edit: |
373 | + common.password_check_match(self.ui.password_line_edit, |
374 | + self.ui.confirm_password_line_edit, |
375 | + self.ui.password_assistance) |
376 | + |
377 | + # Invalid name "initializePage" |
378 | + # pylint: disable=C0103 |
379 | + |
380 | + def initializePage(self): |
381 | + super(ResetPasswordPage, self).initializePage() |
382 | + common.password_default_assistance(self.ui.password_assistance) |
383 | + self.ui.password_assistance.setVisible(False) |
384 | + |
385 | + def showEvent(self, event): |
386 | + """Connect focusChanged signal from the application.""" |
387 | + super(ResetPasswordPage, self).showEvent(event) |
388 | + self.connect(QApplication.instance(), |
389 | + SIGNAL("focusChanged(QWidget*, QWidget*)"), |
390 | + self.focus_changed) |
391 | + |
392 | + def hideEvent(self, event): |
393 | + """Disconnect the focusChanged signal when the page change.""" |
394 | + super(ResetPasswordPage, self).hideEvent(event) |
395 | + try: |
396 | + self.disconnect(QApplication.instance(), |
397 | + SIGNAL("focusChanged(QWidget*, QWidget*)"), |
398 | + self.focus_changed) |
399 | + except TypeError: |
400 | + pass |
401 | + |
402 | + # pylint: enable=C0103 |
403 | |
404 | |
405 | class SetupAccountPage(SSOWizardEnhancedEditPage): |
406 | |
407 | === added file 'ubuntu_sso/qt/tests/test_common.py' |
408 | --- ubuntu_sso/qt/tests/test_common.py 1970-01-01 00:00:00 +0000 |
409 | +++ ubuntu_sso/qt/tests/test_common.py 2011-09-02 11:41:29 +0000 |
410 | @@ -0,0 +1,234 @@ |
411 | +# -*- coding: utf-8 -*- |
412 | +# Author: Diego Sarmentero <diego.sarmentero@canonical.com> |
413 | +# |
414 | +# Copyright 2011 Canonical Ltd. |
415 | +# |
416 | +# This program is free software: you can redistribute it and/or modify it |
417 | +# under the terms of the GNU General Public License version 3, as published |
418 | +# by the Free Software Foundation. |
419 | +# |
420 | +# This program is distributed in the hope that it will be useful, but |
421 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
422 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
423 | +# PURPOSE. See the GNU General Public License for more details. |
424 | +# |
425 | +# You should have received a copy of the GNU General Public License along |
426 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
427 | +"""Test the common functions.""" |
428 | + |
429 | +from PyQt4 import QtGui |
430 | +from twisted.trial.unittest import TestCase |
431 | + |
432 | +from ubuntu_sso.qt.common import (check_as_invalid, |
433 | + check_as_valid, |
434 | + password_assistance, |
435 | + password_check_match, |
436 | + BAD, |
437 | + GOOD, |
438 | + NORMAL, |
439 | + PASSWORD_DIGIT, |
440 | + PASSWORD_LENGTH, |
441 | + PASSWORD_MATCH, |
442 | + PASSWORD_UPPER) |
443 | + |
444 | + |
445 | +class PasswordTestCase(TestCase): |
446 | + """Test passwords conditions.""" |
447 | + |
448 | + def setUp(self): |
449 | + """Setup tests.""" |
450 | + super(PasswordTestCase, self).setUp() |
451 | + self.line_edit = QtGui.QLineEdit() |
452 | + self.line_edit_confirm = QtGui.QLineEdit() |
453 | + self.label_assistance = QtGui.QLabel() |
454 | + |
455 | + def test_short_password(self): |
456 | + """Status with short password. |
457 | + |
458 | + * Password assistance contains the right message. |
459 | + """ |
460 | + self.line_edit.setText("foobar") |
461 | + password_assistance(self.line_edit, self.label_assistance) |
462 | + self.assertIn( |
463 | + BAD % PASSWORD_LENGTH, |
464 | + unicode(self.label_assistance.text()), |
465 | + ) |
466 | + |
467 | + def test_long_password(self): |
468 | + """Status with long password. |
469 | + |
470 | + * Password assistance contains the right message. |
471 | + """ |
472 | + self.line_edit.setText("foobarbaz") |
473 | + password_assistance(self.line_edit, self.label_assistance) |
474 | + self.assertIn( |
475 | + GOOD % PASSWORD_LENGTH, |
476 | + unicode(self.label_assistance.text()), |
477 | + ) |
478 | + |
479 | + def test_no_number_password(self): |
480 | + """Status with password without a number. |
481 | + |
482 | + * Password assistance contains the right message. |
483 | + """ |
484 | + self.line_edit.setText("foobarbaz") |
485 | + password_assistance(self.line_edit, self.label_assistance) |
486 | + self.assertIn( |
487 | + BAD % PASSWORD_DIGIT, |
488 | + unicode(self.label_assistance.text()), |
489 | + ) |
490 | + |
491 | + def test_number_password(self): |
492 | + """Status with password with a number. |
493 | + |
494 | + * Password assistance contains the right message. |
495 | + """ |
496 | + self.line_edit.setText("foobarba7") |
497 | + password_assistance(self.line_edit, self.label_assistance) |
498 | + self.assertIn( |
499 | + GOOD % PASSWORD_DIGIT, |
500 | + unicode(self.label_assistance.text()), |
501 | + ) |
502 | + |
503 | + def test_no_uppercase_password(self): |
504 | + """Status with password without uppercase letters. |
505 | + |
506 | + * Password assistance contains the right message. |
507 | + """ |
508 | + self.line_edit.setText("foobarbaz") |
509 | + password_assistance(self.line_edit, self.label_assistance) |
510 | + self.assertIn( |
511 | + BAD % PASSWORD_UPPER, |
512 | + unicode(self.label_assistance.text()), |
513 | + ) |
514 | + |
515 | + def test_upper_password(self): |
516 | + """Status with password with uppercase letters. |
517 | + |
518 | + * Password assistance contains the right message. |
519 | + """ |
520 | + self.line_edit.setText("Foobarba7") |
521 | + password_assistance(self.line_edit, self.label_assistance) |
522 | + self.assertIn( |
523 | + GOOD % PASSWORD_UPPER, |
524 | + unicode(self.label_assistance.text()), |
525 | + ) |
526 | + |
527 | + def test_matching_passwords(self): |
528 | + """Status when the passwords match. |
529 | + |
530 | + * Password assistance doesn't contain the message. |
531 | + """ |
532 | + self.line_edit.setText("Foobarba7") |
533 | + self.line_edit_confirm.setText("Foobarba7") |
534 | + password_check_match(self.line_edit, |
535 | + self.line_edit_confirm, self.label_assistance) |
536 | + self.assertNotIn( |
537 | + BAD % PASSWORD_MATCH, |
538 | + unicode(self.label_assistance.text())) |
539 | + |
540 | + def test_not_matching_passwords(self): |
541 | + """Status when the passwords not match. |
542 | + |
543 | + * Password assistance contains the right message. |
544 | + """ |
545 | + self.line_edit.setText("Foobarba7") |
546 | + self.line_edit_confirm.setText("BazBarFo0") |
547 | + password_check_match(self.line_edit, |
548 | + self.line_edit_confirm, self.label_assistance) |
549 | + self.assertIn( |
550 | + BAD % PASSWORD_MATCH, |
551 | + unicode(self.label_assistance.text()), |
552 | + ) |
553 | + |
554 | + def test_password_assistance_in_focus_length_correct(self): |
555 | + """Check the QLineEdit for password when the length is correct.""" |
556 | + self.line_edit.setText("aaaaaaaaa") |
557 | + self.line_edit_confirm.setText("") |
558 | + password_assistance(self.line_edit, self.label_assistance, NORMAL) |
559 | + self.assertIn( |
560 | + GOOD % PASSWORD_LENGTH, |
561 | + unicode(self.label_assistance.text()), |
562 | + ) |
563 | + self.assertIn( |
564 | + NORMAL % PASSWORD_UPPER, |
565 | + unicode(self.label_assistance.text()), |
566 | + ) |
567 | + self.assertIn( |
568 | + NORMAL % PASSWORD_DIGIT, |
569 | + unicode(self.label_assistance.text()), |
570 | + ) |
571 | + |
572 | + def test_password_assistance_in_focus_with_upper(self): |
573 | + """Check the QLineEdit for password when it has an upper case char.""" |
574 | + self.line_edit.setText("AAa") |
575 | + self.line_edit_confirm.setText("") |
576 | + password_assistance(self.line_edit, self.label_assistance, NORMAL) |
577 | + self.assertIn( |
578 | + NORMAL % PASSWORD_LENGTH, |
579 | + unicode(self.label_assistance.text()), |
580 | + ) |
581 | + self.assertIn( |
582 | + GOOD % PASSWORD_UPPER, |
583 | + unicode(self.label_assistance.text()), |
584 | + ) |
585 | + self.assertIn( |
586 | + NORMAL % PASSWORD_DIGIT, |
587 | + unicode(self.label_assistance.text()), |
588 | + ) |
589 | + |
590 | + def test_password_assistance_in_focus_with_number(self): |
591 | + """Check the QLineEdit for password when it contains numbers.""" |
592 | + self.line_edit.setText("a123") |
593 | + self.line_edit_confirm.setText("") |
594 | + password_assistance(self.line_edit, self.label_assistance, NORMAL) |
595 | + self.assertIn( |
596 | + NORMAL % PASSWORD_LENGTH, |
597 | + unicode(self.label_assistance.text()), |
598 | + ) |
599 | + self.assertIn( |
600 | + NORMAL % PASSWORD_UPPER, |
601 | + unicode(self.label_assistance.text()), |
602 | + ) |
603 | + self.assertIn( |
604 | + GOOD % PASSWORD_DIGIT, |
605 | + unicode(self.label_assistance.text()), |
606 | + ) |
607 | + |
608 | + def test_password_assistance_in_focus_all_ok(self): |
609 | + """Check the QLineEdit for password when all the condition are ok.""" |
610 | + self.line_edit.setText("T3st3rqw") |
611 | + self.line_edit_confirm.setText("T3st3rqw") |
612 | + password_assistance(self.line_edit, self.label_assistance, NORMAL) |
613 | + self.assertIn( |
614 | + GOOD % PASSWORD_LENGTH, |
615 | + unicode(self.label_assistance.text()), |
616 | + ) |
617 | + self.assertIn( |
618 | + GOOD % PASSWORD_UPPER, |
619 | + unicode(self.label_assistance.text()), |
620 | + ) |
621 | + self.assertIn( |
622 | + GOOD % PASSWORD_DIGIT, |
623 | + unicode(self.label_assistance.text()), |
624 | + ) |
625 | + self.assertNotIn( |
626 | + NORMAL % PASSWORD_MATCH, |
627 | + unicode(self.label_assistance.text()), |
628 | + ) |
629 | + |
630 | + |
631 | +class LineEditStyleTestCase(TestCase): |
632 | + """Test QLineEdit styles for errors.""" |
633 | + |
634 | + def test_check_valid(self): |
635 | + """Check the propery value of a QLineEdit marked as valid.""" |
636 | + line_edit = QtGui.QLineEdit() |
637 | + check_as_valid(line_edit) |
638 | + self.assertFalse(line_edit.property("formError").toBool()) |
639 | + |
640 | + def test_check_invalid(self): |
641 | + """Check the propery value of a QLineEdit marked as invalid.""" |
642 | + line_edit = QtGui.QLineEdit() |
643 | + check_as_invalid(line_edit) |
644 | + self.assertTrue(line_edit.property("formError").toBool()) |
645 | |
646 | === added file 'ubuntu_sso/qt/tests/test_reset_password.py' |
647 | --- ubuntu_sso/qt/tests/test_reset_password.py 1970-01-01 00:00:00 +0000 |
648 | +++ ubuntu_sso/qt/tests/test_reset_password.py 2011-09-02 11:41:29 +0000 |
649 | @@ -0,0 +1,99 @@ |
650 | +# -*- coding: utf-8 -*- |
651 | +# Author: Manuel de la Pena <manuel@canonical.com> |
652 | +# |
653 | +# Copyright 2011 Canonical Ltd. |
654 | +# |
655 | +# This program is free software: you can redistribute it and/or modify it |
656 | +# under the terms of the GNU General Public License version 3, as published |
657 | +# by the Free Software Foundation. |
658 | +# |
659 | +# This program is distributed in the hope that it will be useful, but |
660 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
661 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
662 | +# PURPOSE. See the GNU General Public License for more details. |
663 | +# |
664 | +# You should have received a copy of the GNU General Public License along |
665 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
666 | +"""Test the Reset Password Page.""" |
667 | + |
668 | +from PyQt4 import QtGui, QtCore |
669 | +from twisted.trial.unittest import TestCase |
670 | + |
671 | +from ubuntu_sso.qt import common |
672 | +from ubuntu_sso.qt.gui import ResetPasswordPage |
673 | +from ubuntu_sso.qt.reset_password_ui import Ui_ResetPasswordPage |
674 | + |
675 | + |
676 | +class FakePasswordAssistance(object): |
677 | + """Fake password_assistance_* calls.""" |
678 | + |
679 | + _called = False |
680 | + |
681 | + def call(self, *args, **kwargs): |
682 | + """Check if the method was called.""" |
683 | + FakePasswordAssistance._called = True |
684 | + |
685 | + def clenaup(self): |
686 | + """Clean up the variable.""" |
687 | + FakePasswordAssistance._called = False |
688 | + |
689 | + |
690 | +class SetupAccountTestCase(TestCase): |
691 | + """Test the ResetPasswordPage code.""" |
692 | + |
693 | + def setUp(self): |
694 | + super(SetupAccountTestCase, self).setUp() |
695 | + self.page = ResetPasswordPage(Ui_ResetPasswordPage(), |
696 | + None, |
697 | + None) |
698 | + self.fake = FakePasswordAssistance() |
699 | + |
700 | + def test_init(self): |
701 | + """Check the initial state of ResetPassword.""" |
702 | + self.assertEqual(self.page.ui.password_line_edit.receivers( |
703 | + QtCore.SIGNAL('textEdited(QString)')), 1) |
704 | + self.assertEqual(self.page.ui.confirm_password_line_edit.receivers( |
705 | + QtCore.SIGNAL('textEdited(QString)')), 1) |
706 | + |
707 | + def test_focus_changed_password_visibility(self): |
708 | + """Check visibility changes when focus_changed() is executed.""" |
709 | + self.page.show() |
710 | + self.addCleanup(self.page.hide) |
711 | + self.page.focus_changed(None, self.page.ui.password_line_edit) |
712 | + self.assertTrue(self.page.ui.password_assistance.isVisible()) |
713 | + |
714 | + def test_show_hide_event(self): |
715 | + """Check connections to focusChanged on show and hide event.""" |
716 | + self.page.show() |
717 | + self.addCleanup(self.page.hide) |
718 | + self.assertEqual(QtGui.QApplication.instance().receivers( |
719 | + QtCore.SIGNAL("focusChanged(QWidget*, QWidget*)")), 1) |
720 | + self.page.hide() |
721 | + self.assertEqual(QtGui.QApplication.instance().receivers( |
722 | + QtCore.SIGNAL("focusChanged(QWidget*, QWidget*)")), 0) |
723 | + |
724 | + # pylint: disable=W0212 |
725 | + |
726 | + def test_focus_changed_1(self): |
727 | + """Check functions execution when focus_changed() is executed.""" |
728 | + self.patch(common, 'password_default_assistance', self.fake.call) |
729 | + self.addCleanup(self.fake.clenaup) |
730 | + self.page.show() |
731 | + self.addCleanup(self.page.hide) |
732 | + self.assertFalse(FakePasswordAssistance._called) |
733 | + self.page.focus_changed(None, self.page.ui.password_line_edit) |
734 | + self.assertTrue(self.page.ui.password_assistance.isVisible()) |
735 | + self.assertTrue(FakePasswordAssistance._called) |
736 | + |
737 | + def test_focus_changed_2(self): |
738 | + """Check functions execution when focus_changed() is executed.""" |
739 | + self.patch(common, 'password_check_match', self.fake.call) |
740 | + self.addCleanup(self.fake.clenaup) |
741 | + self.page.show() |
742 | + self.addCleanup(self.page.hide) |
743 | + self.assertFalse(FakePasswordAssistance._called) |
744 | + self.page.focus_changed(None, self.page.ui.confirm_password_line_edit) |
745 | + self.assertTrue(self.page.ui.password_assistance.isVisible()) |
746 | + self.assertTrue(FakePasswordAssistance._called) |
747 | + |
748 | + # pylint: enable=W0212 |
+1 looks good!