Fixed various bugs in the songbeamer chord import, and added a test.

This commit is contained in:
Tomas Groth 2016-08-19 16:51:23 +02:00
parent b35d300708
commit c463c46cf6
4 changed files with 147 additions and 69 deletions

View File

@ -116,12 +116,12 @@ class SongBeamerImport(SongImport):
file_name = os.path.split(import_file)[1]
if os.path.isfile(import_file):
# Detect the encoding
self.input_file_encoding = get_file_encoding(file_name)['encoding']
self.input_file_encoding = get_file_encoding(import_file)['encoding']
# The encoding should only be ANSI (cp1251), UTF-8, Unicode, Big-Endian-Unicode.
# So if it doesn't start with 'u' we default to cp1251. See:
# So if it doesn't start with 'u' we default to cp1252. See:
# https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
if self.input_file_encoding.lower().startswith('u'):
self.input_file_encoding = 'cp1251'
if not self.input_file_encoding.lower().startswith('u'):
self.input_file_encoding = 'cp1252'
infile = open(import_file, 'rt', encoding=self.input_file_encoding)
song_data = infile.readlines()
infile.close()
@ -133,9 +133,10 @@ class SongBeamerImport(SongImport):
line_number = -1
for line in song_data:
line = line.rstrip()
stripped_line = line.strip()
if line.startswith('#') and not read_verses:
self.parse_tags(line)
elif line.startswith('---'):
elif stripped_line.startswith('---'):
# '---' is a verse breaker
if self.current_verse:
self.replace_html_tags()
@ -150,19 +151,19 @@ class SongBeamerImport(SongImport):
if first_line:
self.current_verse = first_line.strip() + '\n'
line_number += 1
elif line.startswith('--'):
elif stripped_line.startswith('--'):
# '--' is a page breaker, we convert to optional page break
self.current_verse += '[---]\n'
line_number += 1
elif read_verses:
line = self.insert_chords(line_number, line)
if verse_start:
verse_start = False
if not self.check_verse_marks(line):
self.current_verse += line.strip() + '\n'
else:
line = self.insert_chords(line_number, line)
self.current_verse += line.strip() + '\n'
line_number += 1
line_number += 1
if self.current_verse:
self.replace_html_tags()
self.add_verse(self.current_verse, self.current_verse_type)

View File

@ -42,10 +42,17 @@ class TestSongBeamerFileImport(SongImportTestHelper):
self.importer_module_name = 'songbeamer'
super(TestSongBeamerFileImport, self).__init__(*args, **kwargs)
def test_song_import(self):
@patch('openlp.plugins.songs.lib.importers.songbeamer.Settings')
def test_song_import(self, mocked_settings):
"""
Test that loading an OpenSong file works correctly on various files
"""
# Mock out the settings - always return False
mocked_returned_settings = MagicMock()
mocked_returned_settings.value.return_value = False
mocked_settings.return_value = mocked_returned_settings
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sng')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
self.file_import([os.path.join(TEST_PATH, 'Lobsinget dem Herrn.sng')],
self.load_external_result_data(os.path.join(TEST_PATH, 'Lobsinget dem Herrn.json')))
@ -59,6 +66,16 @@ class TestSongBeamerImport(TestCase):
Create the registry
"""
Registry.create()
self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport')
self.song_import_patcher.start()
mocked_manager = MagicMock()
self.importer = SongBeamerImport(mocked_manager, filenames=[])
def tearDown(self):
"""
Clean up
"""
self.song_import_patcher.stop()
def test_create_importer(self):
"""
@ -78,43 +95,37 @@ class TestSongBeamerImport(TestCase):
"""
Test SongBeamerImport.do_import handles different invalid import_source values
"""
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
mocked_manager = MagicMock()
mocked_import_wizard = MagicMock()
importer = SongBeamerImport(mocked_manager, filenames=[])
importer.import_wizard = mocked_import_wizard
importer.stop_import_flag = True
# GIVEN: A mocked out import wizard
mocked_import_wizard = MagicMock()
self.importer.import_wizard = mocked_import_wizard
self.importer.stop_import_flag = True
# WHEN: Import source is not a list
for source in ['not a list', 0]:
importer.import_source = source
# WHEN: Import source is not a list
for source in ['not a list', 0]:
self.importer.import_source = source
# THEN: do_import should return none and the progress bar maximum should not be set.
self.assertIsNone(importer.do_import(), 'do_import should return None when import_source is not a list')
self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False,
'setMaxium on import_wizard.progress_bar should not have been called')
# THEN: do_import should return none and the progress bar maximum should not be set.
self.assertIsNone(self.importer.do_import(), 'do_import should return None when import_source is not a list')
self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False,
'setMaxium on import_wizard.progress_bar should not have been called')
def test_valid_import_source(self):
"""
Test SongBeamerImport.do_import handles different invalid import_source values
"""
# GIVEN: A mocked out SongImport class, and a mocked out "manager"
with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'):
mocked_manager = MagicMock()
mocked_import_wizard = MagicMock()
importer = SongBeamerImport(mocked_manager, filenames=[])
importer.import_wizard = mocked_import_wizard
importer.stop_import_flag = True
# GIVEN: A mocked out import wizard
mocked_import_wizard = MagicMock()
self.importer.import_wizard = mocked_import_wizard
self.importer.stop_import_flag = True
# WHEN: Import source is a list
importer.import_source = ['List', 'of', 'files']
# WHEN: Import source is a list
self.importer.import_source = ['List', 'of', 'files']
# THEN: do_import should return none and the progress bar setMaximum should be called with the length of
# import_source.
self.assertIsNone(importer.do_import(),
'do_import should return None when import_source is a list and stop_import_flag is True')
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source))
# THEN: do_import should return none and the progress bar setMaximum should be called with the length of
# import_source.
self.assertIsNone(self.importer.do_import(),
'do_import should return None when import_source is a list and stop_import_flag is True')
mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(self.importer.import_source))
def test_check_verse_marks(self):
"""
@ -123,75 +134,75 @@ class TestSongBeamerImport(TestCase):
# GIVEN: line with unnumbered verse-type
line = 'Refrain'
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back true and c as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back true and c as self.importer.current_verse_type
self.assertTrue(result, 'Versemark for <Refrain> should be found, value true')
self.assertEqual(self.current_verse_type, 'c', '<Refrain> should be interpreted as <c>')
self.assertEqual(self.importer.current_verse_type, 'c', '<Refrain> should be interpreted as <c>')
# GIVEN: line with unnumbered verse-type and trailing space
line = 'ReFrain '
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back true and c as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back true and c as self.importer.current_verse_type
self.assertTrue(result, 'Versemark for <ReFrain > should be found, value true')
self.assertEqual(self.current_verse_type, 'c', '<ReFrain > should be interpreted as <c>')
self.assertEqual(self.importer.current_verse_type, 'c', '<ReFrain > should be interpreted as <c>')
# GIVEN: line with numbered verse-type
line = 'VersE 1'
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back true and v1 as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back true and v1 as self.importer.current_verse_type
self.assertTrue(result, 'Versemark for <VersE 1> should be found, value true')
self.assertEqual(self.current_verse_type, 'v1', u'<VersE 1> should be interpreted as <v1>')
self.assertEqual(self.importer.current_verse_type, 'v1', u'<VersE 1> should be interpreted as <v1>')
# GIVEN: line with special unnumbered verse-mark (used in Songbeamer to allow usage of non-supported tags)
line = '$$M=special'
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back true and o as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back true and o as self.importer.current_verse_type
self.assertTrue(result, 'Versemark for <$$M=special> should be found, value true')
self.assertEqual(self.current_verse_type, 'o', u'<$$M=special> should be interpreted as <o>')
self.assertEqual(self.importer.current_verse_type, 'o', u'<$$M=special> should be interpreted as <o>')
# GIVEN: line with song-text with 3 words
line = 'Jesus my saviour'
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back false and none as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back false and none as self.importer.current_verse_type
self.assertFalse(result, 'No versemark for <Jesus my saviour> should be found, value false')
self.assertIsNone(self.current_verse_type, '<Jesus my saviour> should be interpreted as none versemark')
self.assertIsNone(self.importer.current_verse_type, '<Jesus my saviour> should be interpreted as none versemark')
# GIVEN: line with song-text with 2 words
line = 'Praise him'
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back false and none as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back false and none as self.importer.current_verse_type
self.assertFalse(result, 'No versemark for <Praise him> should be found, value false')
self.assertIsNone(self.current_verse_type, '<Praise him> should be interpreted as none versemark')
self.assertIsNone(self.importer.current_verse_type, '<Praise him> should be interpreted as none versemark')
# GIVEN: line with only a space (could occur, nothing regular)
line = ' '
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back false and none as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back false and none as self.importer.current_verse_type
self.assertFalse(result, 'No versemark for < > should be found, value false')
self.assertIsNone(self.current_verse_type, '< > should be interpreted as none versemark')
self.assertIsNone(self.importer.current_verse_type, '< > should be interpreted as none versemark')
# GIVEN: blank line (could occur, nothing regular)
line = ''
self.current_verse_type = None
self.importer.current_verse_type = None
# WHEN: line is being checked for verse marks
result = SongBeamerImport.check_verse_marks(self, line)
# THEN: we should get back false and none as self.current_verse_type
result = self.importer.check_verse_marks(line)
# THEN: we should get back false and none as self.importer.current_verse_type
self.assertFalse(result, 'No versemark for <> should be found, value false')
self.assertIsNone(self.current_verse_type, '<> should be interpreted as none versemark')
self.assertIsNone(self.importer.current_verse_type, '<> should be interpreted as none versemark')
def test_verse_marks_defined_in_lowercase(self):
"""

View File

@ -0,0 +1,29 @@
{
"authors": [
"John Newton"
],
"title": "Amazing grace",
"verse_order_list": ["v1", "v2", "v3", "v4", "v5"],
"verses": [
[
"[D]Amazing gr[D7]ace how [G]sweet the [D]sound\nThat saved a [E7]wretch like [A7]me\nI [D]once was [D7]lost but [G]now im [D]found\nWas b[E7]lind but no[A7]w i [D]see [A7]\n",
"v1"
],
[
"T'was [D]grace that [D7]taught my [G]heart to [D]fear\nAnd grace my [E7]fears [A7]relieved\nHow [D]precious [D7]did that [G]Grace [D]appear\nThe [E7]hour I [A7]first bel[D]ieved.[A7]\n",
"v2"
],
[
"Through [D]many [D7]dangers, [G]toils and [D]snares\nI have [E7]already [A7]come;\n'Tis [D]Grace that [D7]brought me [G]safe thus [D]far\nand [E7]Grace will [A7]lead me [D]home. [A7]\n",
"v3"
],
[
"When we[D]'ve been here[D7] ten thous[G]and y[D]ears\nBright shining [E7]as the [A7]sun.\nWe've [D]no less [D7]days to s[G]ing God's p[D]raise\nThan w[E7]hen we've [A7]first [D]begun.[A7]\n",
"v4"
],
[
"[D]Amazing gr[D7]ace how [G]sweet the [D]sound\nThat saved a [E7]wretch like [A7]me\nI [D]once was [D7]lost but [G]now im [D]found\nWas b[E7]lind but no[A7]w i [D]see [A]\n",
"v5"
]
]
}

View File

@ -0,0 +1,37 @@
#LangCount=1
#Title=Amazing grace
#Chords=MCwwLEQNMTAsMCxENw0xOCwwLEcNMjgsMCxEDTEzLDEsRTcNMjUsMSxBNw0yLDIsRA0xMSwyLEQ3DTIwLDIsRw0yNywyLEQNNSwzLEU3DTE2LDMsQTcNMjAsMyxEDTI0LDMsQTcNNiw1LEQNMTcsNSxENw0yNyw1LEcNMzYsNSxEDTEzLDYsRTcNMTksNixBNw00LDcsRA0xMyw3LEQ3DTIyLDcsRw0yOCw3LEQNNCw4LEU3DTExLDgsQTcNMjAsOCxEDTI2LDgsQTcNOCwxMCxEDTEzLDEwLEQ3DTIyLDEwLEcNMzIsMTAsRA03LDExLEU3DTE1LDExLEE3DTUsMTIsRA0xNiwxMixENw0yNywxMixHDTM3LDEyLEQNNCwxMyxFNw0xNSwxMyxBNw0yMywxMyxEDTI5LDEzLEE3DTcsMTUsRA0yMCwxNSxENw0zMCwxNSxHDTM1LDE1LEQNMTUsMTYsRTcNMjIsMTYsQTcNNiwxNyxEDTE0LDE3LEQ3DTIzLDE3LEcNMzQsMTcsRA02LDE4LEU3DTE2LDE4LEE3DTIyLDE4LEQNMjgsMTgsQTcNMCwyMCxEDTEwLDIwLEQ3DTE4LDIwLEcNMjgsMjAsRA0xMywyMSxFNw0yNSwyMSxBNw0yLDIyLEQNMTEsMjIsRDcNMjAsMjIsRw0yNywyMixEDTUsMjMsRTcNMTYsMjMsQTcNMjAsMjMsRA0yNCwyMyxBDQ==
#Author=John Newton
#Editor=SongBeamer 4.37a
#Version=3
#VerseOrder=Verse 1,Verse 2,Verse 3,Verse 4,Verse 5
---
Verse 1
Amazing grace how sweet the sound
That saved a wretch like me
I once was lost but now im found
Was blind but now i see
---
Verse 2
T'was grace that taught my heart to fear
And grace my fears relieved
How precious did that Grace appear
The hour I first believed.
---
Verse 3
Through many dangers, toils and snares
I have already come;
'Tis Grace that brought me safe thus far
and Grace will lead me home.
---
Verse 4
When we've been here ten thousand years
Bright shining as the sun.
We've no less days to sing God's praise
Than when we've first begun.
---
Verse 5
Amazing grace how sweet the sound
That saved a wretch like me
I once was lost but now im found
Was blind but now i see