diff --git a/.travis.yml b/.travis.yml
index 25ea960..7df677a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ install:
 
 script:
   - pipenv run tox
-  - pipenv run coverage run -m py.test
+  - pipenv run coverage run --branch -m py.test
   - pipenv run coverage report -m
 
 after_success:
diff --git a/cdparacord/albumdata.py b/cdparacord/albumdata.py
index 6815658..757f422 100644
--- a/cdparacord/albumdata.py
+++ b/cdparacord/albumdata.py
@@ -181,8 +181,11 @@ class Albumdata:
                 return [cls._albumdata_from_cdstub(result['cdstub'])]
             elif 'disc' in result:
                 return cls._albumdata_from_disc(result['disc'])
-        except musicbrainzngs.MusicBrainzError:  # pragma: no cover
-            return []
+        except musicbrainzngs.MusicBrainzError:
+            pass
+        # If we hit the exception or there's *neither* cdstub *nor*
+        # disc, we get here.
+        return []
 
     @classmethod
     def _albumdata_from_previous_rip(cls, albumdata_file):
@@ -223,19 +226,24 @@ class Albumdata:
                 extract_next = True
 
     @classmethod
-    def _select_albumdata(cls, results, track_count):
+    def _select_albumdata(cls, results):
         max_width, max_height = shutil.get_terminal_size()
 
         state = 0
         while True:
             # State 0 is the first screen, other ones are the options
+
+            # There should be no way for state to escape these
+            # constraints.
+            assert 0 <= state <= len(results)
+
             if state == 0:
                 print('=' * max_width)
                 print('Albumdata sources available:')
                 for i in range(1, len(results) + 1):
                     print('{}) {}'.format(i, results[i - 1]['source']))
                 print('=' * max_width)
-            elif state <= track_count:
+            else:
                 print('Source {}: {}'.format(
                     state, results[state - 1]['source']))
                 cls._print_albumdata(results[state - 1])
@@ -309,8 +317,13 @@ class Albumdata:
                 s[key] = ''.join(
                     c for c in s[key] if unicodedata.category(c) in
                         ('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nd', 'Nl', 'No'))
-            elif safetyfilter != 'remove_restricted':
-                # This is the only valid option if it's nothing else
+            elif safetyfilter == 'remove_restricted':
+                # This is the only valid option if it's nothing else. We
+                # can safely pass because this filter is always applied
+                # at the end.
+                pass
+            else:
+                # Raise an error if *no* valid filter is found
                 raise AlbumdataError(
                     'Invalid safety filter {}'.format(safetyfilter))
 
@@ -457,6 +470,9 @@ class Albumdata:
 
         track_count = cls._get_track_count(deps.cdparanoia)
 
+        if track_count is None:
+            raise AlbumdataError('Could not figure out track count')
+
         # Data to be merged to the albumdata we select
         common_albumdata = {
             'discid': str(disc),
@@ -521,7 +537,7 @@ class Albumdata:
         # Actually drop results that have the wrong amount of tracks
         results = [r for r in results if r not in dropped]
 
-        selected = cls._select_albumdata(results, track_count)
+        selected = cls._select_albumdata(results)
 
         # Edit albumdata
         return cls._edit_albumdata(selected, track_count, deps.editor, config)

diff --git a/tests/test_albumdata.py b/tests/test_albumdata.py
index e6bb73f..8867a8c 100644
--- a/tests/test_albumdata.py
+++ b/tests/test_albumdata.py
@@ -191,7 +191,8 @@ def test_cdstub_result(monkeypatch, albumdata):
 
 def test_disc_result(monkeypatch, albumdata):
     """Test that disc result is processed correctly."""
-    monkeypatch.setattr('musicbrainzngs.get_releases_by_discid',
+    monkeypatch.setattr(
+        'musicbrainzngs.get_releases_by_discid',
         lambda x, includes: testdata_disc_result)
 
     a = albumdata.Albumdata._albumdata_from_musicbrainz('test')[0]
@@ -203,6 +204,33 @@ def test_disc_result(monkeypatch, albumdata):
     assert a['tracks'][0]['artist'] == 'Test Artist'
 
 
+def test_musicbrainzerror_result(monkeypatch, albumdata):
+    """Test that getting no MusicBrainz result at all works."""
+    def fake_get_releases(*x, **y):
+        import musicbrainzngs
+        raise musicbrainzngs.MusicBrainzError("test")
+
+    monkeypatch.setattr(
+        'musicbrainzngs.get_releases_by_discid',
+        fake_get_releases)
+    a = albumdata.Albumdata._albumdata_from_musicbrainz('test')
+    assert a == []
+
+
+def test_weird_nothing_result(monkeypatch, albumdata):
+    """Test a weird implausible MusicBrainz result.
+
+    Specifically, a case where we get neither cdstub nor disc which
+    shouldn't happen will hit its own branch that should be treated as
+    "no MusicBrainz result".
+    """
+    monkeypatch.setattr(
+        'musicbrainzngs.get_releases_by_discid',
+        lambda *x, **y: {})
+    a = albumdata.Albumdata._albumdata_from_musicbrainz('test')
+    assert a == []
+
+
 def test_initialise_track(albumdata):
     """Test that track is correctly initialised."""
     t = albumdata.Track(testdata['tracks'][0])
@@ -293,6 +321,22 @@ TOTAL   1150 [00:11.50]        (audio only)
     monkeypatch.setattr('subprocess.run', lambda *x, **y: obj)
     assert albumdata.Albumdata._get_track_count('') == 1
 
+
+def test_get_no_track_count(monkeypatch, albumdata):
+    """Test track count getting with empty cdparanoia output."""
+    class FakeProcess:
+        def check_returncode(self):
+            pass
+        
+        @property
+        def stdout(self):
+            return ''
+
+    obj = FakeProcess()
+    monkeypatch.setattr('subprocess.run', lambda *x, **y: obj)
+    assert albumdata.Albumdata._get_track_count('') == None
+
+
 def test_select_albumdata(capsys, monkeypatch, albumdata):
     """Test that the albumdata selection works as expected.
 
@@ -436,7 +480,7 @@ a: abort
             except StopIteration:
                 return 
         monkeypatch.setattr('builtins.input', fake_input)
-        albumdata.Albumdata._select_albumdata([testdata], 1)
+        albumdata.Albumdata._select_albumdata([testdata])
         out, err = capsys.readouterr()
 
         assert out == expected[test_index]
@@ -461,6 +505,13 @@ def test_invalid_previous_result(monkeypatch, albumdata):
         a = albumdata.Albumdata._albumdata_from_previous_rip('')
 
 
+def test_no_previous_result(monkeypatch, albumdata):
+    """Test that previous rip not existing works."""
+    monkeypatch.setattr('os.path.isfile', lambda *x: False)
+
+    a = albumdata.Albumdata._albumdata_from_previous_rip('')
+    assert a is None
+
 def test_from_user_input(monkeypatch, albumdata):
     monkeypatch.setattr('discid.read', lambda: 'test')
     monkeypatch.setattr('os.getuid', lambda: 1000)
@@ -495,6 +546,10 @@ def test_from_user_input(monkeypatch, albumdata):
     config.dict['reuse_albumdata'] = True
     assert albumdata.Albumdata.from_user_input(deps, config) is None
 
+    # Same config but this time previous albumdata is None
+    monkeypatch.setattr('cdparacord.albumdata.Albumdata._albumdata_from_previous_rip', lambda *x: None)
+    assert albumdata.Albumdata.from_user_input(deps, config) is None
+
     config.dict['use_musicbrainz'] = True
     config.dict['reuse_albumdata'] = False
     assert albumdata.Albumdata.from_user_input(deps, config) is None
@@ -503,6 +558,13 @@ def test_from_user_input(monkeypatch, albumdata):
     config.dict['reuse_albumdata'] = False
     assert albumdata.Albumdata.from_user_input(deps, config) is None
 
+    # It's plausible that we would get None here
+    config.dict['use_musicbrainz'] = False
+    config.dict['reuse_albumdata'] = True
+    monkeypatch.setattr('cdparacord.albumdata.Albumdata._get_track_count', lambda *x: None)
+    with pytest.raises(albumdata.AlbumdataError):
+        albumdata.Albumdata.from_user_input(deps, config)
+
 
 def test_edit_albumdata(monkeypatch, albumdata):
     """Test _edit_albumdata."""
@@ -563,6 +625,8 @@ def test_generate_filename(monkeypatch, albumdata):
     assert '!äbc-de' == albumdata.Albumdata._generate_filename(testdata, testdata['tracks'][0], 1, config)
     config.dict['safetyfilter'] = 'unicode_letternumber'
     assert 'äbcde' == albumdata.Albumdata._generate_filename(testdata, testdata['tracks'][0], 1, config)
+    config.dict['safetyfilter'] = 'remove_restricted'
+    assert '!äbc-de' == albumdata.Albumdata._generate_filename(testdata, testdata['tracks'][0], 1, config)
 
     # Test that it fails when we given an invalid filter
     config.dict['safetyfilter'] = 'fake and not real'
diff --git a/tests/test_config.py b/tests/test_config.py
index 1a85588..5c42f51 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -187,6 +187,27 @@ def test_update_config_unknown_keys(mock_temp_home, capsys):
     out, err = capsys.readouterr()
     assert err == 'Warning: Unknown configuration key invalid_key\n'
 
+
+def test_update_config_with_none(mock_temp_home, capsys):
+    from cdparacord import config
+
+    c = config.Config()
+    c.update({'keep_ripdir': None}, quiet_ignore=False)
+
+    out, err = capsys.readouterr()
+    assert err == ""
+
+
+def test_update_config_quiet_ignore(mock_temp_home, capsys):
+    from cdparacord import config
+
+    c = config.Config()
+    c.update({'invalid_key': True}, quiet_ignore=True)
+
+    out, err = capsys.readouterr()
+    assert err == ''
+
+
 def test_ensure_default_encoder_keys_are_strings(mock_temp_home):
     """Test default encoder configuration."""
     from cdparacord import config
diff --git a/tests/test_rip.py b/tests/test_rip.py
index 5bc2c85..78b6ed7 100644
--- a/tests/test_rip.py
+++ b/tests/test_rip.py
@@ -8,6 +8,7 @@ def get_fake_config():
         def __init__(self):
             self.fail_one = False
             self.fail_all = False
+            self.always_tag_albumartist = False
 
         def get(self, key):
             if key in ('post_rip', 'post_encode'):
@@ -28,7 +29,7 @@ def get_fake_config():
                 else:
                     return {'echo': ['${one_file}', '${out_file}']}
             elif key == 'always_tag_albumartist':
-                return True
+                return self.always_tag_albumartist
             else:
                 return ''
     yield FakeConfig
@@ -293,10 +294,13 @@ def test_tag_track(monkeypatch, get_fake_config):
     monkeypatch.setattr('mutagen.easyid3.EasyID3', FakeFile2)
     monkeypatch.setattr('mutagen.File', FakeFile)
 
-    loop = asyncio.new_event_loop()
-    asyncio.set_event_loop(loop)
-    loop.run_until_complete(r._tag_track(fake_track, fake_track.filename))
-    loop.close()
+    # Both skip and don't skip the albumartist branch
+    for always_tag in (True, False):
+        fake_config.always_tag_albumartist = always_tag
+        loop = asyncio.new_event_loop()
+        asyncio.set_event_loop(loop)
+        loop.run_until_complete(r._tag_track(fake_track, fake_track.filename))
+        loop.close()
 
-    # Assert we got the filename put in the dict
-    assert r._tagged_files[fake_track.filename] == fake_track.filename
+        # Assert we got the filename put in the dict
+        assert r._tagged_files[fake_track.filename] == fake_track.filename

Add branch coverage measurements
Add branch coverage (if our test system supports it) and then also ensure that we have total branch coverage in addition to total line coverage.
tests/test_albumdata.py::test_weird_nothing_result tests/test_albumdata.py::test_select_albumdata
tests/test_albumdata.py::test_cdstub_result tests/test_albumdata.py::test_disc_result tests/test_albumdata.py::test_musicbrainzerror_result tests/test_albumdata.py::test_initialise_track tests/test_albumdata.py::test_albumdata_tracks tests/test_albumdata.py::test_initialise_albumdata tests/test_albumdata.py::test_print_albumdata_80 tests/test_albumdata.py::test_print_albumdata_60 tests/test_albumdata.py::test_get_track_count tests/test_albumdata.py::test_get_no_track_count tests/test_albumdata.py::test_previous_result tests/test_albumdata.py::test_invalid_previous_result tests/test_albumdata.py::test_no_previous_result tests/test_albumdata.py::test_edit_albumdata tests/test_albumdata.py::test_generate_filename tests/test_albumdata.py::test_disc_result_no_date tests/test_config.py::test_create_config tests/test_config.py::test_get_encoder tests/test_config.py::test_fail_to_get_variable tests/test_config.py::test_read_config_file tests/test_config.py::test_read_invalid_config tests/test_config.py::test_update_config_no_unknown_keys tests/test_config.py::test_update_config_unknown_keys tests/test_config.py::test_update_config_with_none tests/test_config.py::test_update_config_quiet_ignore tests/test_config.py::test_ensure_default_encoder_keys_are_strings tests/test_config.py::test_ensure_default_postaction_keys_are_strings tests/test_rip.py::test_construct_rip tests/test_rip.py::test_rip_pipeline tests/test_rip.py::test_rip_track tests/test_rip.py::test_encode_track tests/test_rip.py::test_tag_track