Merge lp:~dobey/ubuntuone-control-panel/update-4-2 into lp:ubuntuone-control-panel/stable-4-2
- update-4-2
- Merge into stable-4-2
Proposed by
dobey
Status: | Merged |
---|---|
Approved by: | dobey |
Approved revision: | 383 |
Merged at revision: | 383 |
Proposed branch: | lp:~dobey/ubuntuone-control-panel/update-4-2 |
Merge into: | lp:ubuntuone-control-panel/stable-4-2 |
Diff against target: |
429 lines (+133/-141) 6 files modified
ubuntuone/controlpanel/gui/qt/controlpanel.py (+5/-0) ubuntuone/controlpanel/gui/qt/share_links.py (+6/-1) ubuntuone/controlpanel/gui/qt/share_links_search.py (+9/-16) ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py (+42/-2) ubuntuone/controlpanel/gui/qt/tests/test_share_links.py (+8/-0) ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py (+63/-122) |
To merge this branch: | bzr merge lp:~dobey/ubuntuone-control-panel/update-4-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Review via email: mp+155611@code.launchpad.net |
Description of the change
To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ubuntuone/controlpanel/gui/qt/controlpanel.py' | |||
2 | --- ubuntuone/controlpanel/gui/qt/controlpanel.py 2012-10-18 21:45:05 +0000 | |||
3 | +++ ubuntuone/controlpanel/gui/qt/controlpanel.py 2013-03-26 20:55:24 +0000 | |||
4 | @@ -79,6 +79,11 @@ | |||
5 | 79 | self.ui.tab_widget.setTabText( | 79 | self.ui.tab_widget.setTabText( |
6 | 80 | self.ui.tab_widget.indexOf(self.ui.share_links_tab), | 80 | self.ui.tab_widget.indexOf(self.ui.share_links_tab), |
7 | 81 | MAIN_SHARE_LINKS_TAB) | 81 | MAIN_SHARE_LINKS_TAB) |
8 | 82 | |||
9 | 83 | # Workaround for bug LP: 1152388 | ||
10 | 84 | handler = self.ui.share_links_tab.handle_current_tab_changed | ||
11 | 85 | self.ui.tab_widget.currentChanged.connect(handler) | ||
12 | 86 | |||
13 | 82 | self.ui.tab_widget.setTabText( | 87 | self.ui.tab_widget.setTabText( |
14 | 83 | self.ui.tab_widget.indexOf(self.ui.devices_tab), MAIN_DEVICES_TAB) | 88 | self.ui.tab_widget.indexOf(self.ui.devices_tab), MAIN_DEVICES_TAB) |
15 | 84 | self.ui.tab_widget.setTabText( | 89 | self.ui.tab_widget.setTabText( |
16 | 85 | 90 | ||
17 | === modified file 'ubuntuone/controlpanel/gui/qt/share_links.py' | |||
18 | --- ubuntuone/controlpanel/gui/qt/share_links.py 2012-11-02 17:15:15 +0000 | |||
19 | +++ ubuntuone/controlpanel/gui/qt/share_links.py 2013-03-26 20:55:24 +0000 | |||
20 | @@ -1,6 +1,6 @@ | |||
21 | 1 | # -*- coding: utf-8 *-* | 1 | # -*- coding: utf-8 *-* |
22 | 2 | 2 | ||
24 | 3 | # Copyright 2012 Canonical Ltd. | 3 | # Copyright 2012-2013 Canonical Ltd. |
25 | 4 | # | 4 | # |
26 | 5 | # This program is free software: you can redistribute it and/or modify it | 5 | # This program is free software: you can redistribute it and/or modify it |
27 | 6 | # under the terms of the GNU General Public License version 3, as published | 6 | # under the terms of the GNU General Public License version 3, as published |
28 | @@ -107,6 +107,11 @@ | |||
29 | 107 | self.get_public_files() | 107 | self.get_public_files() |
30 | 108 | self._enhanced_line.btn_operation.hide() | 108 | self._enhanced_line.btn_operation.hide() |
31 | 109 | 109 | ||
32 | 110 | def handle_current_tab_changed(self, index): | ||
33 | 111 | """Workaround for bug LP: 1152388""" | ||
34 | 112 | self.ui.line_search.clearFocus() | ||
35 | 113 | self.ui.line_search.popup.hide() | ||
36 | 114 | |||
37 | 110 | @inlineCallbacks | 115 | @inlineCallbacks |
38 | 111 | def share_file(self, file_path): | 116 | def share_file(self, file_path): |
39 | 112 | """Clean the previous file share details and publish file_path.""" | 117 | """Clean the previous file share details and publish file_path.""" |
40 | 113 | 118 | ||
41 | === modified file 'ubuntuone/controlpanel/gui/qt/share_links_search.py' | |||
42 | --- ubuntuone/controlpanel/gui/qt/share_links_search.py 2013-01-24 21:35:59 +0000 | |||
43 | +++ ubuntuone/controlpanel/gui/qt/share_links_search.py 2013-03-26 20:55:24 +0000 | |||
44 | @@ -36,6 +36,7 @@ | |||
45 | 36 | HOME_DIR = '' | 36 | HOME_DIR = '' |
46 | 37 | AVOID_SECOND_ITEM = 2 | 37 | AVOID_SECOND_ITEM = 2 |
47 | 38 | NORMAL_INCREMENT = 1 | 38 | NORMAL_INCREMENT = 1 |
48 | 39 | SEARCH_TYPING_DELAY = 100 # msec | ||
49 | 39 | 40 | ||
50 | 40 | 41 | ||
51 | 41 | def get_system_icon_for_filename(file_path): | 42 | def get_system_icon_for_filename(file_path): |
52 | @@ -63,7 +64,6 @@ | |||
53 | 63 | self.current_results = [] | 64 | self.current_results = [] |
54 | 64 | self.page_index = 0 | 65 | self.page_index = 0 |
55 | 65 | self.page_size = 20 | 66 | self.page_size = 20 |
56 | 66 | self.pending_call = None | ||
57 | 67 | self._post_key_event = { | 67 | self._post_key_event = { |
58 | 68 | QtCore.Qt.Key_Escape: lambda *args: self.popup.hide(), | 68 | QtCore.Qt.Key_Escape: lambda *args: self.popup.hide(), |
59 | 69 | QtCore.Qt.Key_Down: self._key_down_pressed, | 69 | QtCore.Qt.Key_Down: self._key_down_pressed, |
60 | @@ -76,6 +76,10 @@ | |||
61 | 76 | self.popup.list_widget.verticalScrollBar().valueChanged.connect( | 76 | self.popup.list_widget.verticalScrollBar().valueChanged.connect( |
62 | 77 | self._scroll_fetch_more) | 77 | self._scroll_fetch_more) |
63 | 78 | self.textChanged.connect(self.handle_text_changed) | 78 | self.textChanged.connect(self.handle_text_changed) |
64 | 79 | self._do_search_timer = QtCore.QTimer() | ||
65 | 80 | self._do_search_timer.timeout.connect(self._do_search) | ||
66 | 81 | self._do_search_timer.setInterval(SEARCH_TYPING_DELAY) | ||
67 | 82 | self._do_search_timer.setSingleShot(True) | ||
68 | 79 | 83 | ||
69 | 80 | self._get_home_path() | 84 | self._get_home_path() |
70 | 81 | 85 | ||
71 | @@ -94,30 +98,19 @@ | |||
72 | 94 | def handle_text_changed(self, text): | 98 | def handle_text_changed(self, text): |
73 | 95 | """Use delayed IPC to search for filenames after user stops typing.""" | 99 | """Use delayed IPC to search for filenames after user stops typing.""" |
74 | 96 | 100 | ||
75 | 97 | # Import here to avoid getting the wrong reactor due to import | ||
76 | 98 | # order. Save in class var to ease patching for tests: | ||
77 | 99 | if not self.qtreactor: | ||
78 | 100 | self.qtreactor = __import__('twisted').internet.reactor | ||
79 | 101 | text = unicode(text) | 101 | text = unicode(text) |
80 | 102 | self.page_index = 0 | 102 | self.page_index = 0 |
81 | 103 | 103 | ||
82 | 104 | if text == '': | 104 | if text == '': |
83 | 105 | self.popup.hide() | 105 | self.popup.hide() |
93 | 106 | if self.pending_call and self.pending_call.active(): | 106 | self._do_search_timer.stop() |
94 | 107 | self.pending_call.cancel() | 107 | return |
95 | 108 | return | 108 | |
96 | 109 | 109 | self._do_search_timer.start(SEARCH_TYPING_DELAY) | |
88 | 110 | if self.pending_call and self.pending_call.active(): | ||
89 | 111 | self.pending_call.reset(0.1) | ||
90 | 112 | return | ||
91 | 113 | |||
92 | 114 | self.pending_call = self.qtreactor.callLater(0.1, self._do_search) | ||
97 | 115 | 110 | ||
98 | 116 | @inlineCallbacks | 111 | @inlineCallbacks |
99 | 117 | def _do_search(self): | 112 | def _do_search(self): |
100 | 118 | 113 | ||
101 | 119 | self.pending_call = None | ||
102 | 120 | |||
103 | 121 | search_text = unicode(self.text()) | 114 | search_text = unicode(self.text()) |
104 | 122 | results = yield self.backend.search_files(search_text) | 115 | results = yield self.backend.search_files(search_text) |
105 | 123 | 116 | ||
106 | 124 | 117 | ||
107 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py' | |||
108 | --- ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2012-10-17 07:21:28 +0000 | |||
109 | +++ ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2013-03-26 20:55:24 +0000 | |||
110 | @@ -1,6 +1,6 @@ | |||
111 | 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
112 | 2 | # | 2 | # |
114 | 3 | # Copyright 2011-2012 Canonical Ltd. | 3 | # Copyright 2011-2013 Canonical Ltd. |
115 | 4 | # | 4 | # |
116 | 5 | # This program is free software: you can redistribute it and/or modify it | 5 | # This program is free software: you can redistribute it and/or modify it |
117 | 6 | # under the terms of the GNU General Public License version 3, as published | 6 | # under the terms of the GNU General Public License version 3, as published |
118 | @@ -19,10 +19,17 @@ | |||
119 | 19 | from __future__ import division | 19 | from __future__ import division |
120 | 20 | 20 | ||
121 | 21 | from twisted.internet import defer | 21 | from twisted.internet import defer |
122 | 22 | from PyQt4 import QtCore | ||
123 | 23 | |||
124 | 24 | from ubuntuone.controlpanel import backend, cache | ||
125 | 25 | from ubuntuone.controlpanel.tests import TestCase | ||
126 | 26 | from mock import call, Mock | ||
127 | 27 | |||
128 | 28 | from ubuntuone.controlpanel.gui.qt import share_links | ||
129 | 22 | 29 | ||
130 | 23 | from ubuntuone.controlpanel.gui.qt import controlpanel as gui | 30 | from ubuntuone.controlpanel.gui.qt import controlpanel as gui |
131 | 24 | from ubuntuone.controlpanel.gui.qt.tests import ( | 31 | from ubuntuone.controlpanel.gui.qt.tests import ( |
133 | 25 | SAMPLE_ACCOUNT_INFO, SAMPLE_NAME, | 32 | FakedControlPanelBackend, SAMPLE_ACCOUNT_INFO, SAMPLE_NAME, |
134 | 26 | ) | 33 | ) |
135 | 27 | from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import ( | 34 | from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import ( |
136 | 28 | UbuntuOneBinTestCase, | 35 | UbuntuOneBinTestCase, |
137 | @@ -204,6 +211,39 @@ | |||
138 | 204 | self.ui.ui.wizard.pages[self.ui.ui.wizard.license_page]) | 211 | self.ui.ui.wizard.pages[self.ui.ui.wizard.license_page]) |
139 | 205 | 212 | ||
140 | 206 | 213 | ||
141 | 214 | class ControlPanelConnectionTestCase(TestCase): | ||
142 | 215 | """Test qt signal connections from controlpanel.""" | ||
143 | 216 | |||
144 | 217 | @defer.inlineCallbacks | ||
145 | 218 | def setUp(self): | ||
146 | 219 | cache.Cache._shared_objects = {} | ||
147 | 220 | yield super(ControlPanelConnectionTestCase, self).setUp() | ||
148 | 221 | self.patch(backend, 'ControlBackend', FakedControlPanelBackend) | ||
149 | 222 | |||
150 | 223 | self.mock_handler = Mock(name='handle_current_tab_changed') | ||
151 | 224 | self.patch(share_links.ShareLinksPanel, 'handle_current_tab_changed', | ||
152 | 225 | self.mock_handler) | ||
153 | 226 | |||
154 | 227 | self.ui = gui.ControlPanel() | ||
155 | 228 | self.ui.show() | ||
156 | 229 | self.addCleanup(self.ui.hide) | ||
157 | 230 | #self.addCleanup(self.ui.deleteLater) | ||
158 | 231 | self.addCleanup(QtCore.QCoreApplication.instance().processEvents) | ||
159 | 232 | |||
160 | 233 | if getattr(self.ui, 'backend', None) is not None: | ||
161 | 234 | self.addCleanup(self.ui.backend._called.clear) | ||
162 | 235 | |||
163 | 236 | def test_popup_hides_when_switching_tab(self): | ||
164 | 237 | """Test that the share_links_tab gets the signal for changed tabs""" | ||
165 | 238 | folders_index = self.ui.ui.tab_widget.indexOf(self.ui.ui.folders_tab) | ||
166 | 239 | share_index = self.ui.ui.tab_widget.indexOf(self.ui.ui.share_links_tab) | ||
167 | 240 | self.ui.ui.tab_widget.setCurrentIndex(share_index) | ||
168 | 241 | self.ui.ui.tab_widget.setCurrentIndex(folders_index) | ||
169 | 242 | |||
170 | 243 | self.assertEqual(self.mock_handler.mock_calls, | ||
171 | 244 | [call(share_index), call(folders_index)]) | ||
172 | 245 | |||
173 | 246 | |||
174 | 207 | class ExternalLinkButtonsTestCase(ControlPanelTestCase): | 247 | class ExternalLinkButtonsTestCase(ControlPanelTestCase): |
175 | 208 | """The link in the go-to-web buttons are correct.""" | 248 | """The link in the go-to-web buttons are correct.""" |
176 | 209 | 249 | ||
177 | 210 | 250 | ||
178 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_share_links.py' | |||
179 | --- ubuntuone/controlpanel/gui/qt/tests/test_share_links.py 2012-11-02 17:15:15 +0000 | |||
180 | +++ ubuntuone/controlpanel/gui/qt/tests/test_share_links.py 2013-03-26 20:55:24 +0000 | |||
181 | @@ -254,6 +254,14 @@ | |||
182 | 254 | os.path.basename(file_path)) | 254 | os.path.basename(file_path)) |
183 | 255 | self.assertEqual(widget.ui.lbl_path.text(), file_path) | 255 | self.assertEqual(widget.ui.lbl_path.text(), file_path) |
184 | 256 | 256 | ||
185 | 257 | def test_hide_popup_on_tab_changed(self): | ||
186 | 258 | """Test that the popup is hidden by the tab changed signal.""" | ||
187 | 259 | |||
188 | 260 | self.ui.ui.line_search.popup.show() | ||
189 | 261 | self.ui.handle_current_tab_changed(0) | ||
190 | 262 | self.assertFalse(self.ui.ui.line_search.popup.isVisible()) | ||
191 | 263 | self.assertFalse(self.ui.ui.line_search.hasFocus()) | ||
192 | 264 | |||
193 | 257 | 265 | ||
194 | 258 | class ActionsButtonsTestCase(BaseTestCase): | 266 | class ActionsButtonsTestCase(BaseTestCase): |
195 | 259 | """Test the Actions Buttons.""" | 267 | """Test the Actions Buttons.""" |
196 | 260 | 268 | ||
197 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py' | |||
198 | --- ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py 2013-01-24 21:35:59 +0000 | |||
199 | +++ ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py 2013-03-26 20:55:24 +0000 | |||
200 | @@ -24,7 +24,7 @@ | |||
201 | 24 | from ubuntuone.controlpanel.gui.qt import share_links_search as gui | 24 | from ubuntuone.controlpanel.gui.qt import share_links_search as gui |
202 | 25 | from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase | 25 | from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase |
203 | 26 | 26 | ||
205 | 27 | from mock import call, patch | 27 | from mock import patch |
206 | 28 | 28 | ||
207 | 29 | # pylint: disable=W0212 | 29 | # pylint: disable=W0212 |
208 | 30 | 30 | ||
209 | @@ -175,7 +175,7 @@ | |||
210 | 175 | 175 | ||
211 | 176 | 176 | ||
212 | 177 | class SearchingTestCase(BaseTestCase): | 177 | class SearchingTestCase(BaseTestCase): |
214 | 178 | """test _do_search by itself and with multiple calls to handle_text.""" | 178 | """Set up patches used by subclasses.""" |
215 | 179 | class_ui = gui.SearchBox | 179 | class_ui = gui.SearchBox |
216 | 180 | 180 | ||
217 | 181 | @defer.inlineCallbacks | 181 | @defer.inlineCallbacks |
218 | @@ -208,6 +208,9 @@ | |||
219 | 208 | self.mock_load_items = self.load_items_patch.start() | 208 | self.mock_load_items = self.load_items_patch.start() |
220 | 209 | self.addCleanup(self.load_items_patch.stop) | 209 | self.addCleanup(self.load_items_patch.stop) |
221 | 210 | 210 | ||
222 | 211 | |||
223 | 212 | class DoSearchTestCase(SearchingTestCase): | ||
224 | 213 | """A subclass so that MultipleSearchingTestCase doesn't also call these.""" | ||
225 | 211 | @defer.inlineCallbacks | 214 | @defer.inlineCallbacks |
226 | 212 | def test_do_search_text_same(self): | 215 | def test_do_search_text_same(self): |
227 | 213 | """If searchbox text same after search_files call, call load_items.""" | 216 | """If searchbox text same after search_files call, call load_items.""" |
228 | @@ -231,11 +234,37 @@ | |||
229 | 231 | yield d | 234 | yield d |
230 | 232 | self.assertFalse(self.mock_load_items.called) | 235 | self.assertFalse(self.mock_load_items.called) |
231 | 233 | 236 | ||
232 | 237 | |||
233 | 238 | class MultipleSearchingTestCase(SearchingTestCase): | ||
234 | 239 | """Test multiple fast calls to handle_text.""" | ||
235 | 240 | |||
236 | 241 | @defer.inlineCallbacks | ||
237 | 242 | def setUp(self): | ||
238 | 243 | # do all this before calling super, because ui._do_search is | ||
239 | 244 | # connected to a Qt signal in the __init__ of the ui class, | ||
240 | 245 | # and we need to connect our patched version: | ||
241 | 246 | self.do_search_ended = defer.DeferredQueue() | ||
242 | 247 | # save unbound function because self.ui won't exist yet: | ||
243 | 248 | self.orig_do_search = gui.SearchBox._do_search | ||
244 | 249 | |||
245 | 250 | @defer.inlineCallbacks | ||
246 | 251 | def do_search_later(): | ||
247 | 252 | # call unbound function with now-existing self.ui: | ||
248 | 253 | yield self.orig_do_search(self.ui) | ||
249 | 254 | self.do_search_ended.put("done") | ||
250 | 255 | |||
251 | 256 | self.do_search_patch = patch.object(gui.SearchBox, '_do_search') | ||
252 | 257 | self.do_search_mock = self.do_search_patch.start() | ||
253 | 258 | self.do_search_mock.side_effect = do_search_later | ||
254 | 259 | self.addCleanup(self.do_search_patch.stop) | ||
255 | 260 | |||
256 | 261 | yield super(MultipleSearchingTestCase, self).setUp() | ||
257 | 262 | |||
258 | 234 | @defer.inlineCallbacks | 263 | @defer.inlineCallbacks |
259 | 235 | def test_multiple_searches_while_waiting(self): | 264 | def test_multiple_searches_while_waiting(self): |
260 | 236 | """Only call load_items once despite multiple quick text changes.""" | 265 | """Only call load_items once despite multiple quick text changes.""" |
261 | 237 | 266 | ||
263 | 238 | # This test checks the case not covered in other tests, where | 267 | # This test checks a case not covered earlier, where |
264 | 239 | # text changes once, then the text changes again, after | 268 | # text changes once, then the text changes again, after |
265 | 240 | # _do_search is called but before search_files has returned. | 269 | # _do_search is called but before search_files has returned. |
266 | 241 | 270 | ||
267 | @@ -243,48 +272,37 @@ | |||
268 | 243 | # be called twice, but _load_items should only be called once, | 272 | # be called twice, but _load_items should only be called once, |
269 | 244 | # by the last call to _do_search. | 273 | # by the last call to _do_search. |
270 | 245 | 274 | ||
313 | 246 | self.do_search_ended = defer.DeferredQueue() | 275 | # call once with original query |
314 | 247 | self.orig_do_search = self.ui._do_search | 276 | self.mock_text.return_value = 'query' |
315 | 248 | 277 | self.ui.handle_text_changed('query') | |
316 | 249 | @defer.inlineCallbacks | 278 | |
317 | 250 | def do_search_later(): | 279 | # wait for the first delayed do_search call to call |
318 | 251 | yield self.orig_do_search() | 280 | # search_files and check its arg for good measure |
319 | 252 | self.do_search_ended.put("done") | 281 | search_files_query = yield self.search_files_started_q.get() |
320 | 253 | 282 | self.assertEqual('query', search_files_query) | |
321 | 254 | with patch.object(self.ui, '_do_search') as mock_do_search: | 283 | |
322 | 255 | mock_do_search.side_effect = do_search_later | 284 | # first call to search_files is paused waiting for |
323 | 256 | 285 | # search_files_done_q, simulating a long IPC call. | |
324 | 257 | # call once with original query | 286 | # the delayed call to do_search is no longer active. |
325 | 258 | self.mock_text.return_value = 'query' | 287 | |
326 | 259 | self.ui.handle_text_changed('query') | 288 | # while we wait for search_files, the user changes the |
327 | 260 | 289 | # query, scheduling a new delayed call to do_search: | |
328 | 261 | # wait for the first delayed do_search call to call | 290 | self.mock_text.return_value = 'query2' |
329 | 262 | # search_files and check its arg for good measure | 291 | self.ui.handle_text_changed('query2') |
330 | 263 | search_files_query = yield self.search_files_started_q.get() | 292 | |
331 | 264 | self.assertEqual('query', search_files_query) | 293 | # release both calls to search_files: |
332 | 265 | 294 | self.search_files_done_q.put(['result1']) | |
333 | 266 | # first call to search_files is paused waiting for | 295 | self.search_files_done_q.put(['result2']) |
334 | 267 | # search_files_done_q, simulating a long IPC call. | 296 | |
335 | 268 | # the delayed call to do_search is no longer active. | 297 | # wait for first delayed call to do_search to finish: |
336 | 269 | 298 | yield self.do_search_ended.get() | |
337 | 270 | # while we wait for search_files, the user changes the | 299 | |
338 | 271 | # query, scheduling a new delayed call to do_search: | 300 | # check that the second call to search_files got the right |
339 | 272 | self.mock_text.return_value = 'query2' | 301 | # text: |
340 | 273 | self.ui.handle_text_changed('query2') | 302 | search_files_query = yield self.search_files_started_q.get() |
341 | 274 | 303 | self.assertEqual('query2', search_files_query) | |
342 | 275 | # release both calls to search_files: | 304 | # wait for second do_search to end |
343 | 276 | self.search_files_done_q.put(['result1']) | 305 | yield self.do_search_ended.get() |
302 | 277 | self.search_files_done_q.put(['result2']) | ||
303 | 278 | |||
304 | 279 | # wait for first delayed call to do_search to finish: | ||
305 | 280 | yield self.do_search_ended.get() | ||
306 | 281 | |||
307 | 282 | # check that the second call to search_files got the right | ||
308 | 283 | # text: | ||
309 | 284 | search_files_query = yield self.search_files_started_q.get() | ||
310 | 285 | self.assertEqual('query2', search_files_query) | ||
311 | 286 | # wait for second do_search to end | ||
312 | 287 | yield self.do_search_ended.get() | ||
344 | 288 | 306 | ||
345 | 289 | # check that _load_items is only called once, and that it's | 307 | # check that _load_items is only called once, and that it's |
346 | 290 | # using only the results from the last call to search_files: | 308 | # using only the results from the last call to search_files: |
347 | @@ -292,83 +310,6 @@ | |||
348 | 292 | self.assertEqual(['result2'], self.ui.current_results) | 310 | self.assertEqual(['result2'], self.ui.current_results) |
349 | 293 | 311 | ||
350 | 294 | 312 | ||
351 | 295 | class TextChangedTestCase(BaseTestCase): | ||
352 | 296 | """Test handle_text_changed scheduling pending calls.""" | ||
353 | 297 | |||
354 | 298 | class_ui = gui.SearchBox | ||
355 | 299 | |||
356 | 300 | @defer.inlineCallbacks | ||
357 | 301 | def setUp(self): | ||
358 | 302 | yield super(TextChangedTestCase, self).setUp() | ||
359 | 303 | |||
360 | 304 | # patch this way instead of using decorators because we need | ||
361 | 305 | # to patch self.ui.popup, which isn't defined yet when the | ||
362 | 306 | # decorators run. | ||
363 | 307 | self.qtreactor_patch = patch.object(gui.SearchBox, 'qtreactor') | ||
364 | 308 | self.mock_qtreactor = self.qtreactor_patch.start() | ||
365 | 309 | self.addCleanup(self.qtreactor_patch.stop) | ||
366 | 310 | |||
367 | 311 | self.popup_patch = patch.object(self.ui, 'popup') | ||
368 | 312 | self.mock_popup = self.popup_patch.start() | ||
369 | 313 | self.addCleanup(self.popup_patch.stop) | ||
370 | 314 | |||
371 | 315 | def test_empty_text_no_pending(self): | ||
372 | 316 | """arg='' with no pending call only hides the popup.""" | ||
373 | 317 | self.ui.handle_text_changed('') | ||
374 | 318 | self.mock_popup.hide.assert_called_once_with() | ||
375 | 319 | self.assertFalse(self.mock_qtreactor.callLater.called) | ||
376 | 320 | |||
377 | 321 | def test_empty_text_with_pending(self): | ||
378 | 322 | """arg='' with a pending call hides the popup and cancels pending.""" | ||
379 | 323 | with patch.object(self.ui, 'pending_call') as mock_pending_call: | ||
380 | 324 | mock_pending_call.active.return_value = True | ||
381 | 325 | self.ui.handle_text_changed('') | ||
382 | 326 | mock_pending_call.active.assert_called_once_with() | ||
383 | 327 | mock_pending_call.cancel.assert_called_once_with() | ||
384 | 328 | self.mock_popup.hide.assert_called_once_with() | ||
385 | 329 | self.assertFalse(self.mock_qtreactor.callLater.called) | ||
386 | 330 | |||
387 | 331 | def test_empty_text_with_inactive_pending(self): | ||
388 | 332 | """arg='' with a pending call hides the popup and cancels pending.""" | ||
389 | 333 | with patch.object(self.ui, 'pending_call') as mock_pending_call: | ||
390 | 334 | mock_pending_call.active.return_value = False | ||
391 | 335 | self.ui.handle_text_changed('') | ||
392 | 336 | mock_pending_call.active.assert_called_once_with() | ||
393 | 337 | self.assertFalse(mock_pending_call.cancel.called) | ||
394 | 338 | self.mock_popup.hide.assert_called_once_with() | ||
395 | 339 | self.assertFalse(self.mock_qtreactor.callLater.called) | ||
396 | 340 | |||
397 | 341 | def test_nonempty_text_with_no_pending(self): | ||
398 | 342 | """arg='b' with no pending call schedules a call.""" | ||
399 | 343 | self.ui.handle_text_changed('b') | ||
400 | 344 | self.assertEqual([call(0.1, self.ui._do_search)], | ||
401 | 345 | self.mock_qtreactor.callLater.mock_calls) | ||
402 | 346 | |||
403 | 347 | def test_nonempty_text_with_inactive_pending(self): | ||
404 | 348 | """call an inactive (called already) call schedules another call.""" | ||
405 | 349 | with patch.object(self.ui, 'pending_call') as mock_pending_call: | ||
406 | 350 | mock_pending_call.active.return_value = False | ||
407 | 351 | self.ui.handle_text_changed('b') | ||
408 | 352 | mock_pending_call.active.assert_called_once_with() | ||
409 | 353 | self.assertFalse(mock_pending_call.reset.called) | ||
410 | 354 | |||
411 | 355 | self.assertFalse(self.mock_popup.hide.called) | ||
412 | 356 | |||
413 | 357 | self.assertEqual([call(0.1, self.ui._do_search)], | ||
414 | 358 | self.mock_qtreactor.callLater.mock_calls) | ||
415 | 359 | |||
416 | 360 | def test_nonempty_text_with_pending(self): | ||
417 | 361 | """arg='' with a pending call hides the popup and resets pending.""" | ||
418 | 362 | with patch.object(self.ui, 'pending_call') as mock_pending_call: | ||
419 | 363 | mock_pending_call.active.return_value = True | ||
420 | 364 | self.ui.handle_text_changed('b') | ||
421 | 365 | mock_pending_call.active.assert_called_once_with() | ||
422 | 366 | mock_pending_call.reset.assert_called_once_with(0.1) | ||
423 | 367 | |||
424 | 368 | self.assertFalse(self.mock_popup.hide.called) | ||
425 | 369 | self.assertFalse(self.mock_qtreactor.callLater.called) | ||
426 | 370 | |||
427 | 371 | |||
428 | 372 | class FileItemTestCase(BaseTestCase): | 313 | class FileItemTestCase(BaseTestCase): |
429 | 373 | """Test the File Item.""" | 314 | """Test the File Item.""" |
430 | 374 | 315 |