Merge lp:~raoul-snyman/openlp/fix-importers-2.4 into lp:openlp/2.4
- fix-importers-2.4
- Merge into 2.4
Proposed by
Raoul Snyman
Status: | Merged |
---|---|
Merged at revision: | 2675 |
Proposed branch: | lp:~raoul-snyman/openlp/fix-importers-2.4 |
Merge into: | lp:openlp/2.4 |
Diff against target: |
420 lines (+149/-54) 9 files modified
openlp/core/__init__.py (+1/-1) openlp/plugins/songs/lib/importers/openlp.py (+8/-2) openlp/plugins/songs/lib/importers/presentationmanager.py (+33/-10) openlp/plugins/songs/lib/songselect.py (+16/-3) tests/functional/openlp_core/test_init.py (+32/-18) tests/functional/openlp_plugins/remotes/test_router.py (+9/-5) tests/functional/openlp_plugins/songs/test_songselect.py (+42/-7) tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py (+7/-7) tests/resources/presentationmanagersongs/Agnus Dei.sng (+1/-1) |
To merge this branch: | bzr merge lp:~raoul-snyman/openlp/fix-importers-2.4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Approve | ||
Review via email: mp+318838@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-02.
Commit message
Description of the change
- Fix SongSelect so that it detects the login URL
- Fix PresentationManager importer to handle weird XML
- Pull in OpenLP song importer fixes from Olli's branch
To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/core/__init__.py' | |||
2 | --- openlp/core/__init__.py 2017-01-22 20:01:53 +0000 | |||
3 | +++ openlp/core/__init__.py 2017-03-02 21:00:50 +0000 | |||
4 | @@ -317,7 +317,7 @@ | |||
5 | 317 | return QtWidgets.QApplication.event(self, event) | 317 | return QtWidgets.QApplication.event(self, event) |
6 | 318 | 318 | ||
7 | 319 | 319 | ||
9 | 320 | def parse_options(args): | 320 | def parse_options(args=None): |
10 | 321 | """ | 321 | """ |
11 | 322 | Parse the command line arguments | 322 | Parse the command line arguments |
12 | 323 | 323 | ||
13 | 324 | 324 | ||
14 | === modified file 'openlp/plugins/songs/lib/importers/openlp.py' | |||
15 | --- openlp/plugins/songs/lib/importers/openlp.py 2016-12-31 11:05:48 +0000 | |||
16 | +++ openlp/plugins/songs/lib/importers/openlp.py 2017-03-02 21:00:50 +0000 | |||
17 | @@ -221,11 +221,17 @@ | |||
18 | 221 | if not existing_book: | 221 | if not existing_book: |
19 | 222 | existing_book = Book.populate(name=entry.songbook.name, publisher=entry.songbook.publisher) | 222 | existing_book = Book.populate(name=entry.songbook.name, publisher=entry.songbook.publisher) |
20 | 223 | new_song.add_songbook_entry(existing_book, entry.entry) | 223 | new_song.add_songbook_entry(existing_book, entry.entry) |
22 | 224 | elif song.book: | 224 | elif hasattr(song, 'book') and song.book: |
23 | 225 | existing_book = self.manager.get_object_filtered(Book, Book.name == song.book.name) | 225 | existing_book = self.manager.get_object_filtered(Book, Book.name == song.book.name) |
24 | 226 | if not existing_book: | 226 | if not existing_book: |
25 | 227 | existing_book = Book.populate(name=song.book.name, publisher=song.book.publisher) | 227 | existing_book = Book.populate(name=song.book.name, publisher=song.book.publisher) |
27 | 228 | new_song.add_songbook_entry(existing_book, '') | 228 | # Get the song_number from "songs" table "song_number" field. (This is db structure from 2.2.1) |
28 | 229 | # If there's a number, add it to the song, otherwise it will be "". | ||
29 | 230 | existing_number = song.song_number if hasattr(song, 'song_number') else '' | ||
30 | 231 | if existing_number: | ||
31 | 232 | new_song.add_songbook_entry(existing_book, existing_number) | ||
32 | 233 | else: | ||
33 | 234 | new_song.add_songbook_entry(existing_book, "") | ||
34 | 229 | # Find or create all the media files and add them to the new song object | 235 | # Find or create all the media files and add them to the new song object |
35 | 230 | if has_media_files and song.media_files: | 236 | if has_media_files and song.media_files: |
36 | 231 | for media_file in song.media_files: | 237 | for media_file in song.media_files: |
37 | 232 | 238 | ||
38 | === modified file 'openlp/plugins/songs/lib/importers/presentationmanager.py' | |||
39 | --- openlp/plugins/songs/lib/importers/presentationmanager.py 2016-12-31 11:05:48 +0000 | |||
40 | +++ openlp/plugins/songs/lib/importers/presentationmanager.py 2017-03-02 21:00:50 +0000 | |||
41 | @@ -23,7 +23,7 @@ | |||
42 | 23 | The :mod:`presentationmanager` module provides the functionality for importing | 23 | The :mod:`presentationmanager` module provides the functionality for importing |
43 | 24 | Presentationmanager song files into the current database. | 24 | Presentationmanager song files into the current database. |
44 | 25 | """ | 25 | """ |
46 | 26 | 26 | import logging | |
47 | 27 | import os | 27 | import os |
48 | 28 | import re | 28 | import re |
49 | 29 | import chardet | 29 | import chardet |
50 | @@ -32,6 +32,8 @@ | |||
51 | 32 | from openlp.core.ui.wizard import WizardStrings | 32 | from openlp.core.ui.wizard import WizardStrings |
52 | 33 | from .songimport import SongImport | 33 | from .songimport import SongImport |
53 | 34 | 34 | ||
54 | 35 | log = logging.getLogger(__name__) | ||
55 | 36 | |||
56 | 35 | 37 | ||
57 | 36 | class PresentationManagerImport(SongImport): | 38 | class PresentationManagerImport(SongImport): |
58 | 37 | """ | 39 | """ |
59 | @@ -62,15 +64,36 @@ | |||
60 | 62 | 'File is not in XML-format, which is the only format supported.')) | 64 | 'File is not in XML-format, which is the only format supported.')) |
61 | 63 | continue | 65 | continue |
62 | 64 | root = objectify.fromstring(etree.tostring(tree)) | 66 | root = objectify.fromstring(etree.tostring(tree)) |
66 | 65 | self.process_song(root) | 67 | self.process_song(root, file_path) |
67 | 66 | 68 | ||
68 | 67 | def process_song(self, root): | 69 | def _get_attr(self, elem, name): |
69 | 70 | """ | ||
70 | 71 | Due to PresentationManager's habit of sometimes capitilising the first letter of an element, we have to do | ||
71 | 72 | some gymnastics. | ||
72 | 73 | """ | ||
73 | 74 | if hasattr(elem, name): | ||
74 | 75 | log.debug('%s: %s', name, getattr(elem, name)) | ||
75 | 76 | return str(getattr(elem, name)) | ||
76 | 77 | name = name[0].upper() + name[1:] | ||
77 | 78 | if hasattr(elem, name): | ||
78 | 79 | log.debug('%s: %s', name, getattr(elem, name)) | ||
79 | 80 | return str(getattr(elem, name)) | ||
80 | 81 | else: | ||
81 | 82 | return '' | ||
82 | 83 | |||
83 | 84 | def process_song(self, root, file_path): | ||
84 | 68 | self.set_defaults() | 85 | self.set_defaults() |
90 | 69 | self.title = str(root.attributes.title) | 86 | attrs = None |
91 | 70 | self.add_author(str(root.attributes.author)) | 87 | if hasattr(root, 'attributes'): |
92 | 71 | self.copyright = str(root.attributes.copyright) | 88 | attrs = root.attributes |
93 | 72 | self.ccli_number = str(root.attributes.ccli_number) | 89 | elif hasattr(root, 'Attributes'): |
94 | 73 | self.comments = str(root.attributes.comments) | 90 | attrs = root.Attributes |
95 | 91 | if attrs is not None: | ||
96 | 92 | self.title = self._get_attr(root.attributes, 'title') | ||
97 | 93 | self.add_author(self._get_attr(root.attributes, 'author')) | ||
98 | 94 | self.copyright = self._get_attr(root.attributes, 'copyright') | ||
99 | 95 | self.ccli_number = self._get_attr(root.attributes, 'ccli_number') | ||
100 | 96 | self.comments = str(root.attributes.comments) if hasattr(root.attributes, 'comments') else None | ||
101 | 74 | verse_order_list = [] | 97 | verse_order_list = [] |
102 | 75 | verse_count = {} | 98 | verse_count = {} |
103 | 76 | duplicates = [] | 99 | duplicates = [] |
104 | @@ -102,4 +125,4 @@ | |||
105 | 102 | 125 | ||
106 | 103 | self.verse_order_list = verse_order_list | 126 | self.verse_order_list = verse_order_list |
107 | 104 | if not self.finish(): | 127 | if not self.finish(): |
109 | 105 | self.log_error(self.import_source) | 128 | self.log_error(os.path.basename(file_path)) |
110 | 106 | 129 | ||
111 | === modified file 'openlp/plugins/songs/lib/songselect.py' | |||
112 | --- openlp/plugins/songs/lib/songselect.py 2016-12-31 11:05:48 +0000 | |||
113 | +++ openlp/plugins/songs/lib/songselect.py 2017-03-02 21:00:50 +0000 | |||
114 | @@ -47,7 +47,7 @@ | |||
115 | 47 | BASE_URL = 'https://songselect.ccli.com' | 47 | BASE_URL = 'https://songselect.ccli.com' |
116 | 48 | LOGIN_PAGE = 'https://profile.ccli.com/account/signin?appContext=SongSelect&returnUrl=' \ | 48 | LOGIN_PAGE = 'https://profile.ccli.com/account/signin?appContext=SongSelect&returnUrl=' \ |
117 | 49 | 'https%3a%2f%2fsongselect.ccli.com%2f' | 49 | 'https%3a%2f%2fsongselect.ccli.com%2f' |
119 | 50 | LOGIN_URL = 'https://profile.ccli.com/' | 50 | LOGIN_URL = 'https://profile.ccli.com' |
120 | 51 | LOGOUT_URL = BASE_URL + '/account/logout' | 51 | LOGOUT_URL = BASE_URL + '/account/logout' |
121 | 52 | SEARCH_URL = BASE_URL + '/search/results' | 52 | SEARCH_URL = BASE_URL + '/search/results' |
122 | 53 | 53 | ||
123 | @@ -97,14 +97,27 @@ | |||
124 | 97 | 'password': password, | 97 | 'password': password, |
125 | 98 | 'RememberMe': 'false' | 98 | 'RememberMe': 'false' |
126 | 99 | }) | 99 | }) |
127 | 100 | login_form = login_page.find('form') | ||
128 | 101 | if login_form: | ||
129 | 102 | login_url = login_form.attrs['action'] | ||
130 | 103 | else: | ||
131 | 104 | login_url = '/Account/SignIn' | ||
132 | 105 | if not login_url.startswith('http'): | ||
133 | 106 | if login_url[0] != '/': | ||
134 | 107 | login_url = '/' + login_url | ||
135 | 108 | login_url = LOGIN_URL + login_url | ||
136 | 100 | try: | 109 | try: |
138 | 101 | posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml') | 110 | posted_page = BeautifulSoup(self.opener.open(login_url, data.encode('utf-8')).read(), 'lxml') |
139 | 102 | except (TypeError, URLError) as error: | 111 | except (TypeError, URLError) as error: |
140 | 103 | log.exception('Could not login to SongSelect, %s', error) | 112 | log.exception('Could not login to SongSelect, %s', error) |
141 | 104 | return False | 113 | return False |
142 | 105 | if callback: | 114 | if callback: |
143 | 106 | callback() | 115 | callback() |
145 | 107 | return posted_page.find('input', id='SearchText') is not None | 116 | if posted_page.find('input', id='SearchText') is not None: |
146 | 117 | return True | ||
147 | 118 | else: | ||
148 | 119 | log.debug(posted_page) | ||
149 | 120 | return False | ||
150 | 108 | 121 | ||
151 | 109 | def logout(self): | 122 | def logout(self): |
152 | 110 | """ | 123 | """ |
153 | 111 | 124 | ||
154 | === added file 'tests/functional/openlp_core/__init__.py' | |||
155 | === modified file 'tests/functional/openlp_core/test_init.py' | |||
156 | --- tests/functional/openlp_core/test_init.py 2016-12-31 11:05:48 +0000 | |||
157 | +++ tests/functional/openlp_core/test_init.py 2017-03-02 21:00:50 +0000 | |||
158 | @@ -22,12 +22,12 @@ | |||
159 | 22 | 22 | ||
160 | 23 | import sys | 23 | import sys |
161 | 24 | from unittest import TestCase | 24 | from unittest import TestCase |
168 | 25 | 25 | from unittest.mock import MagicMock, patch | |
169 | 26 | from openlp.core import parse_options | 26 | |
170 | 27 | from tests.helpers.testmixin import TestMixin | 27 | from openlp.core import OpenLP, parse_options |
171 | 28 | 28 | ||
172 | 29 | 29 | ||
173 | 30 | class TestInitFunctions(TestMixin, TestCase): | 30 | class TestInitFunctions(TestCase): |
174 | 31 | 31 | ||
175 | 32 | def parse_options_basic_test(self): | 32 | def parse_options_basic_test(self): |
176 | 33 | """ | 33 | """ |
177 | @@ -116,7 +116,7 @@ | |||
178 | 116 | 116 | ||
179 | 117 | def parse_options_file_and_debug_test(self): | 117 | def parse_options_file_and_debug_test(self): |
180 | 118 | """ | 118 | """ |
182 | 119 | Test the parse options process works with a file | 119 | Test the parse options process works with a file and the debug log level |
183 | 120 | 120 | ||
184 | 121 | """ | 121 | """ |
185 | 122 | # GIVEN: a a set of system arguments. | 122 | # GIVEN: a a set of system arguments. |
186 | @@ -131,14 +131,28 @@ | |||
187 | 131 | self.assertEquals(args.style, None, 'There are no style flags to be processed') | 131 | self.assertEquals(args.style, None, 'There are no style flags to be processed') |
188 | 132 | self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank') | 132 | self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank') |
189 | 133 | 133 | ||
201 | 134 | def parse_options_two_files_test(self): | 134 | |
202 | 135 | """ | 135 | class TestOpenLP(TestCase): |
203 | 136 | Test the parse options process works with a file | 136 | """ |
204 | 137 | 137 | Test the OpenLP app class | |
205 | 138 | """ | 138 | """ |
206 | 139 | # GIVEN: a a set of system arguments. | 139 | @patch('openlp.core.QtWidgets.QApplication.exec') |
207 | 140 | sys.argv[1:] = ['dummy_temp', 'dummy_temp2'] | 140 | def test_exec(self, mocked_exec): |
208 | 141 | # WHEN: We we parse them to expand to options | 141 | """ |
209 | 142 | args = parse_options() | 142 | Test the exec method |
210 | 143 | # THEN: the following fields will have been extracted. | 143 | """ |
211 | 144 | self.assertEquals(args, None, 'The args should be None') | 144 | # GIVEN: An app |
212 | 145 | app = OpenLP([]) | ||
213 | 146 | app.shared_memory = MagicMock() | ||
214 | 147 | mocked_exec.return_value = False | ||
215 | 148 | |||
216 | 149 | # WHEN: exec() is called | ||
217 | 150 | result = app.exec() | ||
218 | 151 | |||
219 | 152 | # THEN: The right things should be called | ||
220 | 153 | assert app.is_event_loop_active is True | ||
221 | 154 | mocked_exec.assert_called_once_with() | ||
222 | 155 | app.shared_memory.detach.assert_called_once_with() | ||
223 | 156 | assert result is False | ||
224 | 157 | |||
225 | 158 | del app | ||
226 | 145 | 159 | ||
227 | === modified file 'tests/functional/openlp_plugins/remotes/test_router.py' | |||
228 | --- tests/functional/openlp_plugins/remotes/test_router.py 2016-12-31 11:05:48 +0000 | |||
229 | +++ tests/functional/openlp_plugins/remotes/test_router.py 2017-03-02 21:00:50 +0000 | |||
230 | @@ -25,11 +25,11 @@ | |||
231 | 25 | import os | 25 | import os |
232 | 26 | import urllib.request | 26 | import urllib.request |
233 | 27 | from unittest import TestCase | 27 | from unittest import TestCase |
234 | 28 | from unittest.mock import MagicMock, patch, mock_open | ||
235 | 28 | 29 | ||
236 | 29 | from openlp.core.common import Settings, Registry | 30 | from openlp.core.common import Settings, Registry |
237 | 30 | from openlp.core.ui import ServiceManager | 31 | from openlp.core.ui import ServiceManager |
238 | 31 | from openlp.plugins.remotes.lib.httpserver import HttpRouter | 32 | from openlp.plugins.remotes.lib.httpserver import HttpRouter |
239 | 32 | from tests.functional import MagicMock, patch, mock_open | ||
240 | 33 | from tests.helpers.testmixin import TestMixin | 33 | from tests.helpers.testmixin import TestMixin |
241 | 34 | 34 | ||
242 | 35 | __default_settings__ = { | 35 | __default_settings__ = { |
243 | @@ -313,11 +313,13 @@ | |||
244 | 313 | with patch.object(self.service_manager, 'setup_ui'), \ | 313 | with patch.object(self.service_manager, 'setup_ui'), \ |
245 | 314 | patch.object(self.router, 'do_json_header'): | 314 | patch.object(self.router, 'do_json_header'): |
246 | 315 | self.service_manager.bootstrap_initialise() | 315 | self.service_manager.bootstrap_initialise() |
248 | 316 | self.app.processEvents() | 316 | # Not sure why this is here, it doesn't make sense in the test |
249 | 317 | # self.app.processEvents() | ||
250 | 317 | 318 | ||
251 | 318 | # WHEN: Remote next is received | 319 | # WHEN: Remote next is received |
252 | 319 | self.router.service(action='next') | 320 | self.router.service(action='next') |
254 | 320 | self.app.processEvents() | 321 | # Not sure why this is here, it doesn't make sense in the test |
255 | 322 | # self.app.processEvents() | ||
256 | 321 | 323 | ||
257 | 322 | # THEN: service_manager.next_item() should have been called | 324 | # THEN: service_manager.next_item() should have been called |
258 | 323 | self.assertTrue(mocked_next_item.called, 'next_item() should have been called in service_manager') | 325 | self.assertTrue(mocked_next_item.called, 'next_item() should have been called in service_manager') |
259 | @@ -334,11 +336,13 @@ | |||
260 | 334 | with patch.object(self.service_manager, 'setup_ui'), \ | 336 | with patch.object(self.service_manager, 'setup_ui'), \ |
261 | 335 | patch.object(self.router, 'do_json_header'): | 337 | patch.object(self.router, 'do_json_header'): |
262 | 336 | self.service_manager.bootstrap_initialise() | 338 | self.service_manager.bootstrap_initialise() |
264 | 337 | self.app.processEvents() | 339 | # Not sure why this is here, it doesn't make sense in the test |
265 | 340 | # self.app.processEvents() | ||
266 | 338 | 341 | ||
267 | 339 | # WHEN: Remote next is received | 342 | # WHEN: Remote next is received |
268 | 340 | self.router.service(action='previous') | 343 | self.router.service(action='previous') |
270 | 341 | self.app.processEvents() | 344 | # Not sure why this is here, it doesn't make sense in the test |
271 | 345 | # self.app.processEvents() | ||
272 | 342 | 346 | ||
273 | 343 | # THEN: service_manager.next_item() should have been called | 347 | # THEN: service_manager.next_item() should have been called |
274 | 344 | self.assertTrue(mocked_previous_item.called, 'previous_item() should have been called in service_manager') | 348 | self.assertTrue(mocked_previous_item.called, 'previous_item() should have been called in service_manager') |
275 | 345 | 349 | ||
276 | === modified file 'tests/functional/openlp_plugins/songs/test_songselect.py' | |||
277 | --- tests/functional/openlp_plugins/songs/test_songselect.py 2016-12-31 11:05:48 +0000 | |||
278 | +++ tests/functional/openlp_plugins/songs/test_songselect.py 2017-03-02 21:00:50 +0000 | |||
279 | @@ -32,7 +32,7 @@ | |||
280 | 32 | from openlp.core import Registry | 32 | from openlp.core import Registry |
281 | 33 | from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker | 33 | from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker |
282 | 34 | from openlp.plugins.songs.lib import Song | 34 | from openlp.plugins.songs.lib import Song |
284 | 35 | from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGOUT_URL, BASE_URL | 35 | from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGIN_PAGE, LOGOUT_URL, BASE_URL |
285 | 36 | 36 | ||
286 | 37 | from tests.functional import MagicMock, patch, call | 37 | from tests.functional import MagicMock, patch, call |
287 | 38 | from tests.helpers.songfileimport import SongImportTestHelper | 38 | from tests.helpers.songfileimport import SongImportTestHelper |
288 | @@ -81,7 +81,7 @@ | |||
289 | 81 | 81 | ||
290 | 82 | # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned | 82 | # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned |
291 | 83 | self.assertEqual(2, mock_callback.call_count, 'callback should have been called 3 times') | 83 | self.assertEqual(2, mock_callback.call_count, 'callback should have been called 3 times') |
293 | 84 | self.assertEqual(1, mocked_login_page.find.call_count, 'find should have been called twice') | 84 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice') |
294 | 85 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') | 85 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') |
295 | 86 | self.assertFalse(result, 'The login method should have returned False') | 86 | self.assertFalse(result, 'The login method should have returned False') |
296 | 87 | 87 | ||
297 | @@ -96,7 +96,9 @@ | |||
298 | 96 | mocked_build_opener.return_value = mocked_opener | 96 | mocked_build_opener.return_value = mocked_opener |
299 | 97 | mocked_login_page = MagicMock() | 97 | mocked_login_page = MagicMock() |
300 | 98 | mocked_login_page.find.side_effect = [{'value': 'blah'}, None] | 98 | mocked_login_page.find.side_effect = [{'value': 'blah'}, None] |
302 | 99 | MockedBeautifulSoup.return_value = mocked_login_page | 99 | mocked_posted_page = MagicMock() |
303 | 100 | mocked_posted_page.find.return_value = None | ||
304 | 101 | MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] | ||
305 | 100 | mock_callback = MagicMock() | 102 | mock_callback = MagicMock() |
306 | 101 | importer = SongSelectImport(None) | 103 | importer = SongSelectImport(None) |
307 | 102 | 104 | ||
308 | @@ -105,7 +107,8 @@ | |||
309 | 105 | 107 | ||
310 | 106 | # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned | 108 | # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned |
311 | 107 | self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times') | 109 | self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times') |
313 | 108 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice') | 110 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice on the login page') |
314 | 111 | self.assertEqual(1, mocked_posted_page.find.call_count, 'find should have been called once on the posted page') | ||
315 | 109 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') | 112 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') |
316 | 110 | self.assertFalse(result, 'The login method should have returned False') | 113 | self.assertFalse(result, 'The login method should have returned False') |
317 | 111 | 114 | ||
318 | @@ -136,8 +139,10 @@ | |||
319 | 136 | mocked_opener = MagicMock() | 139 | mocked_opener = MagicMock() |
320 | 137 | mocked_build_opener.return_value = mocked_opener | 140 | mocked_build_opener.return_value = mocked_opener |
321 | 138 | mocked_login_page = MagicMock() | 141 | mocked_login_page = MagicMock() |
324 | 139 | mocked_login_page.find.side_effect = [{'value': 'blah'}, MagicMock()] | 142 | mocked_login_page.find.side_effect = [{'value': 'blah'}, None] |
325 | 140 | MockedBeautifulSoup.return_value = mocked_login_page | 143 | mocked_posted_page = MagicMock() |
326 | 144 | mocked_posted_page.find.return_value = MagicMock() | ||
327 | 145 | MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] | ||
328 | 141 | mock_callback = MagicMock() | 146 | mock_callback = MagicMock() |
329 | 142 | importer = SongSelectImport(None) | 147 | importer = SongSelectImport(None) |
330 | 143 | 148 | ||
331 | @@ -146,11 +151,41 @@ | |||
332 | 146 | 151 | ||
333 | 147 | # THEN: callback was called 3 times, open was called twice, find was called twice, and True was returned | 152 | # THEN: callback was called 3 times, open was called twice, find was called twice, and True was returned |
334 | 148 | self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times') | 153 | self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times') |
336 | 149 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice') | 154 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice on the login page') |
337 | 155 | self.assertEqual(1, mocked_posted_page.find.call_count, 'find should have been called once on the posted page') | ||
338 | 150 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') | 156 | self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice') |
339 | 151 | self.assertTrue(result, 'The login method should have returned True') | 157 | self.assertTrue(result, 'The login method should have returned True') |
340 | 152 | 158 | ||
341 | 153 | @patch('openlp.plugins.songs.lib.songselect.build_opener') | 159 | @patch('openlp.plugins.songs.lib.songselect.build_opener') |
342 | 160 | @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') | ||
343 | 161 | def login_url_from_form_test(self, MockedBeautifulSoup, mocked_build_opener): | ||
344 | 162 | """ | ||
345 | 163 | Test that the login URL is from the form | ||
346 | 164 | """ | ||
347 | 165 | # GIVEN: A bunch of mocked out stuff and an importer object | ||
348 | 166 | mocked_opener = MagicMock() | ||
349 | 167 | mocked_build_opener.return_value = mocked_opener | ||
350 | 168 | mocked_form = MagicMock() | ||
351 | 169 | mocked_form.attrs = {'action': 'do/login'} | ||
352 | 170 | mocked_login_page = MagicMock() | ||
353 | 171 | mocked_login_page.find.side_effect = [{'value': 'blah'}, mocked_form] | ||
354 | 172 | mocked_posted_page = MagicMock() | ||
355 | 173 | mocked_posted_page.find.return_value = MagicMock() | ||
356 | 174 | MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] | ||
357 | 175 | mock_callback = MagicMock() | ||
358 | 176 | importer = SongSelectImport(None) | ||
359 | 177 | |||
360 | 178 | # WHEN: The login method is called after being rigged to fail | ||
361 | 179 | result = importer.login('username', 'password', mock_callback) | ||
362 | 180 | |||
363 | 181 | # THEN: callback was called 3 times, open was called twice, find was called twice, and True was returned | ||
364 | 182 | self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times') | ||
365 | 183 | self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice on the login page') | ||
366 | 184 | self.assertEqual(1, mocked_posted_page.find.call_count, 'find should have been called once on the posted page') | ||
367 | 185 | self.assertEqual('https://profile.ccli.com/do/login', mocked_opener.open.call_args_list[1][0][0]) | ||
368 | 186 | self.assertTrue(result, 'The login method should have returned True') | ||
369 | 187 | |||
370 | 188 | @patch('openlp.plugins.songs.lib.songselect.build_opener') | ||
371 | 154 | def logout_test(self, mocked_build_opener): | 189 | def logout_test(self, mocked_build_opener): |
372 | 155 | """ | 190 | """ |
373 | 156 | Test that when the logout method is called, it logs the user out of SongSelect | 191 | Test that when the logout method is called, it logs the user out of SongSelect |
374 | 157 | 192 | ||
375 | === added file 'tests/interfaces/openlp_plugins/bibles/forms/__init__.py' | |||
376 | === modified file 'tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py' | |||
377 | --- tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2016-12-31 11:05:48 +0000 | |||
378 | +++ tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2017-03-02 21:00:50 +0000 | |||
379 | @@ -22,7 +22,7 @@ | |||
380 | 22 | """ | 22 | """ |
381 | 23 | Package to test the openlp.plugins.bibles.forms.bibleimportform package. | 23 | Package to test the openlp.plugins.bibles.forms.bibleimportform package. |
382 | 24 | """ | 24 | """ |
384 | 25 | from unittest import TestCase | 25 | from unittest import TestCase, skip |
385 | 26 | 26 | ||
386 | 27 | from PyQt5 import QtWidgets | 27 | from PyQt5 import QtWidgets |
387 | 28 | 28 | ||
388 | @@ -48,12 +48,12 @@ | |||
389 | 48 | Registry().register('main_window', self.main_window) | 48 | Registry().register('main_window', self.main_window) |
390 | 49 | self.form = BibleImportForm(self.main_window, MagicMock(), MagicMock()) | 49 | self.form = BibleImportForm(self.main_window, MagicMock(), MagicMock()) |
391 | 50 | 50 | ||
398 | 51 | def tearDown(self): | 51 | # def tearDown(self): |
399 | 52 | """ | 52 | # """ |
400 | 53 | Delete all the C++ objects at the end so that we don't have a segfault | 53 | # Delete all the C++ objects at the end so that we don't have a segfault |
401 | 54 | """ | 54 | # """ |
402 | 55 | del self.form | 55 | # del self.form |
403 | 56 | del self.main_window | 56 | # del self.main_window |
404 | 57 | 57 | ||
405 | 58 | @patch('openlp.plugins.bibles.forms.bibleimportform.CWExtract.get_bibles_from_http') | 58 | @patch('openlp.plugins.bibles.forms.bibleimportform.CWExtract.get_bibles_from_http') |
406 | 59 | @patch('openlp.plugins.bibles.forms.bibleimportform.BGExtract.get_bibles_from_http') | 59 | @patch('openlp.plugins.bibles.forms.bibleimportform.BGExtract.get_bibles_from_http') |
407 | 60 | 60 | ||
408 | === added file 'tests/interfaces/openlp_plugins/songusage/__init__.py' | |||
409 | === modified file 'tests/resources/presentationmanagersongs/Agnus Dei.sng' | |||
410 | --- tests/resources/presentationmanagersongs/Agnus Dei.sng 2014-10-13 11:38:13 +0000 | |||
411 | +++ tests/resources/presentationmanagersongs/Agnus Dei.sng 2017-03-02 21:00:50 +0000 | |||
412 | @@ -1,7 +1,7 @@ | |||
413 | 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
414 | 2 | <song xmlns="creativelifestyles/song"> | 2 | <song xmlns="creativelifestyles/song"> |
415 | 3 | <attributes> | 3 | <attributes> |
417 | 4 | <title>Agnus Dei</title> | 4 | <Title>Agnus Dei</Title> |
418 | 5 | <author></author> | 5 | <author></author> |
419 | 6 | <copyright></copyright> | 6 | <copyright></copyright> |
420 | 7 | <ccli_number></ccli_number> | 7 | <ccli_number></ccli_number> |