songs2slides

A tool that automatically finds song lyrics and creates lyric slideshows
git clone https://git.ashermorgan.net/songs2slides/
Log | Files | Refs | README

test_core.py (11095B)


      1 import pytest
      2 
      3 from songs2slides import core
      4 
      5 def test_filter_lyrics_inline():
      6     # Declare raw lyrics and expected cleaned lyrics
      7     lyrics = 'A[remove]B\nC(remove)D'
      8     expected = 'AB\nCD'
      9 
     10     # Clean lyrics
     11     result = core.filter_lyrics(lyrics)
     12 
     13     # Assert slides are correct
     14     assert result == expected
     15 
     16 def test_filter_lyrics_whole_lines():
     17     # Declare raw lyrics and expected cleaned lyrics
     18     lyrics = 'A\n[remove]\nB\n(remove)\nC'
     19     expected = 'A\nB\nC'
     20 
     21     # Clean lyrics
     22     result = core.filter_lyrics(lyrics)
     23 
     24     # Assert slides are correct
     25     assert result == expected
     26 
     27 def test_filter_lyrics_multiple_lines():
     28     # Declare raw lyrics and expected cleaned lyrics
     29     lyrics = 'A\n[re\nmove]\nB\n(re\nmove)\nC'
     30     expected = 'A\nB\nC'
     31 
     32     # Clean lyrics
     33     result = core.filter_lyrics(lyrics)
     34 
     35     # Assert slides are correct
     36     assert result == expected
     37 
     38 def test_filter_lyrics_blank_lines():
     39     # Declare raw lyrics and expected cleaned lyrics
     40     lyrics = 'A\n[remove]\n\n(remove)\nB'
     41     expected = 'A\n\nB'
     42 
     43     # Clean lyrics
     44     result = core.filter_lyrics(lyrics)
     45 
     46     # Assert slides are correct
     47     assert result == expected
     48 
     49 def test_filter_lyrics_all():
     50     # Declare raw lyrics and expected cleaned lyrics
     51     lyrics = 'A[remove]B\n[remove]\n\nC(remove)D\n(re\nmove)'
     52     expected = 'AB\n\nCD'
     53 
     54     # Clean lyrics
     55     result = core.filter_lyrics(lyrics)
     56 
     57     # Assert slides are correct
     58     assert result == expected
     59 
     60 def test_filter_lyrics_empty_string():
     61     # Clean lyrics
     62     result = core.filter_lyrics('')
     63 
     64     # Assert slides are correct
     65     assert result == ''
     66 
     67 def test_get_song_data_success(mocker):
     68     # Mock os.getenv, requests.get, and filter_lyrics
     69     mocker.patch('songs2slides.core.os.getenv')
     70     mocker.patch('songs2slides.core.requests.get')
     71     mocker.patch('songs2slides.core.filter_lyrics')
     72     core.os.getenv.side_effect = [
     73         'api://lyrics/{artist}/{title}',
     74         'Bearer secrettoken'
     75     ]
     76     core.requests.get.return_value.json.return_value = {
     77         'lyrics': 'raw',
     78         'title': 'Foo',
     79         'artist': 'Bar',
     80     }
     81     core.requests.get.return_value.status_code = 200
     82     core.filter_lyrics.return_value = 'clean'
     83 
     84     # Get song data
     85     song_data = core.get_song_data('foo', 'bar')
     86 
     87     # Assert mocked methods were used correctly
     88     core.os.getenv.assert_has_calls([
     89         mocker.call('API_URL'),
     90         mocker.call('API_AUTH', None)
     91     ])
     92     core.requests.get.assert_called_with('api://lyrics/bar/foo', headers={
     93         'Authorization': 'Bearer secrettoken'
     94     })
     95     core.filter_lyrics.assert_called_with('raw')
     96 
     97     # Assert song data is correct
     98     assert song_data.title == 'Foo'
     99     assert song_data.artist == 'Bar'
    100     assert song_data.lyrics == 'clean'
    101 
    102 def test_get_song_data_no_auth_header(mocker):
    103     # Mock os.getenv, requests.get, and filter_lyrics
    104     mocker.patch('songs2slides.core.os.getenv')
    105     mocker.patch('songs2slides.core.requests.get')
    106     mocker.patch('songs2slides.core.filter_lyrics')
    107     core.os.getenv.side_effect = [
    108         'api://lyrics/{artist}/{title}',
    109         None,
    110     ]
    111     core.requests.get.return_value.json.return_value = {
    112         'lyrics': 'raw',
    113         'title': 'Foo',
    114         'artist': 'Bar',
    115     }
    116     core.requests.get.return_value.status_code = 200
    117     core.filter_lyrics.return_value = 'clean'
    118 
    119     # Get song data
    120     song_data = core.get_song_data('foo', 'bar')
    121 
    122     # Assert mocked methods were used correctly
    123     core.os.getenv.assert_has_calls([
    124         mocker.call('API_URL'),
    125         mocker.call('API_AUTH', None)
    126     ])
    127     core.requests.get.assert_called_with('api://lyrics/bar/foo', headers={})
    128     core.filter_lyrics.assert_called_with('raw')
    129 
    130     # Assert song data is correct
    131     assert song_data.title == 'Foo'
    132     assert song_data.artist == 'Bar'
    133     assert song_data.lyrics == 'clean'
    134 
    135 def test_get_song_data_no_url(mocker):
    136     # Mock os.getenv and requests.get
    137     mocker.patch('songs2slides.core.os.getenv')
    138     mocker.patch('songs2slides.core.requests.get')
    139     core.os.getenv.return_value = None
    140     core.requests.get.return_value.text = b'{}'
    141     core.requests.get.return_value.status_code = 200
    142 
    143     # Try to get song data
    144     with pytest.raises(Exception):
    145         song_data = core.get_song_data('foo', 'bar')
    146 
    147     # Assert request was not called
    148     core.requests.get.assert_not_called()
    149 
    150 def test_get_song_data_not_found(mocker):
    151     # Mock os.getenv and requests.get
    152     mocker.patch('songs2slides.core.os.getenv')
    153     mocker.patch('songs2slides.core.requests.get')
    154     core.os.getenv.side_effect = [
    155         'api://lyrics/{artist}/{title}',
    156         'Bearer secrettoken'
    157     ]
    158     core.requests.get.return_value.text = b'{}'
    159     core.requests.get.return_value.status_code = 200
    160 
    161     # Try to get song data
    162     with pytest.raises(Exception):
    163         song_data = core.get_song_data('foo', 'bar')
    164 
    165     # Assert request was called
    166     core.requests.get.assert_called_with('api://lyrics/bar/foo', headers={
    167         'Authorization': 'Bearer secrettoken'
    168     })
    169 
    170 def test_parse_song_lyrics_basic():
    171     # Declare song data and expected slides
    172     lyrics = 'A\nB\nC\nD\nE\nF\n\nG\nH'
    173     expected = ['A\nB\nC\nD', 'E\nF', 'G\nH']
    174 
    175     # Get slide content
    176     result = core.parse_song_lyrics(lyrics, 4)
    177 
    178     # Assert slides are correct
    179     assert result == expected
    180 
    181 def test_parse_song_lyrics_3_lines_per_slide():
    182     # Declare song data and expected slides
    183     lyrics = 'A\nB\nC\nD\nE\nF\n\nG\nH'
    184     expected = ['A\nB\nC', 'D\nE\nF', 'G\nH']
    185 
    186     # Get slide content
    187     result = core.parse_song_lyrics(lyrics, 3)
    188 
    189     # Assert slides are correct
    190     assert result == expected
    191 
    192 def test_parse_song_lyrics_empty_string():
    193     # Declare song data and expected slides
    194     lyrics = ''
    195     expected = []
    196 
    197     # Get slide content
    198     result = core.parse_song_lyrics(lyrics, 4)
    199 
    200     # Assert slides are correct
    201     assert result == expected
    202 
    203 def test_parse_song_lyrics_one_line():
    204     # Declare song data and expected slides
    205     lyrics = 'A'
    206     expected = ['A']
    207 
    208     # Get slide content
    209     result = core.parse_song_lyrics(lyrics, 4)
    210 
    211     # Assert slides are correct
    212     assert result == expected
    213 
    214 def test_parse_song_lyrics_one_slide():
    215     # Declare song data and expected slides
    216     lyrics = 'A\nB\nC\nD'
    217     expected = ['A\nB\nC\nD']
    218 
    219     # Get slide content
    220     result = core.parse_song_lyrics(lyrics, 4)
    221 
    222     # Assert slides are correct
    223     assert result == expected
    224 
    225 def test_parse_song_lyrics_tripple_newlines():
    226     # Declare song data and expected slides
    227     lyrics = 'A\nB\n\n\nC\nD'
    228     expected = ['A\nB', '', 'C\nD']
    229 
    230     # Get slide content
    231     result = core.parse_song_lyrics(lyrics, 4)
    232 
    233     # Assert slides are correct
    234     assert result == expected
    235 
    236 def test_parse_song_lyrics_extra_whitespace():
    237     # Declare song data and expected slides
    238     lyrics = ' A\n B \nC D\nE '
    239     expected = ['A\nB\nC D\nE']
    240 
    241     # Get slide content
    242     result = core.parse_song_lyrics(lyrics, 4)
    243 
    244     # Assert slides are correct
    245     assert result == expected
    246 
    247 def test_parse_song_lyrics_extra_newlines():
    248     # Declare song data and expected slides
    249     lyrics = '\n\n\nA\n\n\n\n\nB\n\n\n'
    250     expected = ['A', '', 'B']
    251 
    252     # Get slide content
    253     result = core.parse_song_lyrics(lyrics, 4)
    254 
    255     # Assert slides are correct
    256     assert result == expected
    257 
    258 def test_assemble_slides_calls_parse_song_lyrics(mocker):
    259     # Mock parse_song_lyrics
    260     mocker.patch('songs2slides.core.parse_song_lyrics')
    261     core.parse_song_lyrics.side_effect = [['aaa'], ['b1', 'b2']]
    262 
    263     # Declare song data and expected slides
    264     songs = [
    265         core.SongData('T1', 'A1', 'l1'),
    266         core.SongData('T2', 'A3', 'l2'),
    267         ]
    268     expected = ['T1', 'aaa', '', 'T2', 'b1', 'b2']
    269 
    270     # Get slides
    271     slides = core.assemble_slides(songs)
    272 
    273     # Assert slides are correct
    274     assert slides == expected
    275 
    276     # Assert parse_song_lyrics called
    277     core.parse_song_lyrics.assert_has_calls([
    278         mocker.call('L1', 4), mocker.call('L2', 4)
    279     ])
    280 
    281 def test_assemble_slides_default():
    282     # Declare song data and expected slides
    283     songs = [
    284         core.SongData('t1', 'a1', 'l1\nl2\nl3\nl4\nl5'),
    285         core.SongData('T2', 'A3', 'L6\nL7\n\nL8\n\n\nL9'),
    286     ]
    287     expected = [
    288         'T1', 'L1\nL2\nL3\nL4', 'L5', '',
    289         'T2', 'L6\nL7', 'L8', '', 'L9',
    290     ]
    291 
    292     # Get slides
    293     slides = core.assemble_slides(songs)
    294 
    295     # Assert slides are correct
    296     assert slides == expected
    297 
    298 def test_assemble_slides_custom_lines_per_slide(mocker):
    299     # Mock parse_song_lyrics
    300     mocker.patch('songs2slides.core.parse_song_lyrics')
    301     core.parse_song_lyrics.side_effect = [['aaa'], ['b1', 'b2']]
    302 
    303     # Declare song data and expected slides
    304     songs = [
    305         core.SongData('T1', 'A1', 'l1'),
    306         core.SongData('T2', 'A3', 'l2'),
    307         ]
    308     expected = ['T1', 'aaa', '', 'T2', 'b1', 'b2']
    309 
    310     # Get slides
    311     slides = core.assemble_slides(songs, lines_per_slide = 3)
    312 
    313     # Assert slides are correct
    314     assert slides == expected
    315 
    316     # Assert parse_song_lyrics called correctly
    317     core.parse_song_lyrics.assert_has_calls([
    318         mocker.call('L1', 3), mocker.call('L2', 3)
    319     ])
    320 
    321 def test_assemble_slides_no_title_slides():
    322     # Declare song data and expected slides
    323     songs = [
    324         core.SongData('t1', 'a1', 'l1\nl2\nl3\nl4\nl5'),
    325         core.SongData('T2', 'A3', 'L6\nL7\n\nL8\n\n\nL9'),
    326     ]
    327     expected = [
    328         'L1\nL2\nL3\nL4', 'L5', '',
    329         'L6\nL7', 'L8', '', 'L9',
    330     ]
    331 
    332     # Get slides
    333     slides = core.assemble_slides(songs, title_slides = False)
    334 
    335     # Assert slides are correct
    336     assert slides == expected
    337 
    338 def test_assemble_slides_no_blank_slides():
    339     # Declare song data and expected slides
    340     songs = [
    341         core.SongData('t1', 'a1', 'l1\nl2\nl3\nl4\nl5'),
    342         core.SongData('T2', 'A3', 'L6\nL7\n\nL8\n\n\nL9'),
    343     ]
    344     expected = [
    345         'T1', 'L1\nL2\nL3\nL4', 'L5',
    346         'T2', 'L6\nL7', 'L8', '', 'L9',
    347     ]
    348 
    349     # Get slides
    350     slides = core.assemble_slides(songs, blank_slides = False)
    351 
    352     # Assert slides are correct
    353     assert slides == expected
    354 
    355 def test_assemble_slides_no_extra_slides():
    356     # Declare song data and expected slides
    357     songs = [
    358         core.SongData('t1', 'a1', 'l1\nl2\nl3\nl4\nl5'),
    359         core.SongData('T2', 'A3', 'L6\nL7\n\nL8\n\n\nL9'),
    360     ]
    361     expected = [
    362         'L1\nL2\nL3\nL4', 'L5',
    363         'L6\nL7', 'L8', '', 'L9',
    364     ]
    365 
    366     # Get slides
    367     slides = core.assemble_slides(songs, title_slides = False, blank_slides = False)
    368 
    369     # Assert slides are correct
    370     assert slides == expected
    371 
    372 def test_assemble_slides_no_songs():
    373     # Declare expected slides
    374     expected = []
    375 
    376     # Get slides
    377     slides = core.assemble_slides([])
    378 
    379     # Assert slides are correct
    380     assert slides == expected
    381 
    382 def test_create_pptx(mocker):
    383     # Mock Presentation.save
    384     mocker.patch('songs2slides.core.pptx.presentation.Presentation.save')
    385 
    386     # Create PowerPoint
    387     core.create_pptx(['A', 'B\nC', 'D'], 'test.pptx')
    388 
    389     # Assert PowerPoint was saved
    390     core.pptx.presentation.Presentation.save.assert_called_with('test.pptx')