import argparse from unittest import mock import pytest from locutus.list import run_list def make_args(config, profile, target=None): args = argparse.Namespace() args.config = config args.profile = profile if target is not None: args.target = target return args @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_prints_chrono_and_numbers_reverse( mock_subproc, mock_config, capsys ): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} # Oldest to newest archives = ['archA', 'archB', 'archC'] mock_subproc.return_value.stdout = '\n'.join(archives) + '\n' mock_subproc.return_value.returncode = 0 args = make_args('dummy.toml', 'dummy.rc') rc = run_list(args) assert rc == 0 out = capsys.readouterr().out.strip().splitlines() # Should print: # 2: archA # 1: archB # 0: archC assert out[0].strip() == '2: archA' assert out[1].strip() == '1: archB' assert out[2].strip() == '0: archC' @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_by_index_most_recent(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} # Oldest to newest archives = ['oldest', 'middle', 'newest'] # First subprocess.run: get archives (reversed in code) mock_subproc.side_effect = [ mock.Mock(stdout='\n'.join(archives) + '\n', returncode=0), mock.Mock(stdout='file1\nfile2\n', returncode=0), ] args = make_args('dummy.toml', 'dummy.rc', target='0') rc = run_list(args) assert rc == 0 out = capsys.readouterr().out # Should show file list for "newest" assert 'file1' in out and 'file2' in out call_args = mock_subproc.call_args_list[1][0][0] # Should call borg list ...::newest assert call_args == ['borg', 'list', '/repo::newest'] @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_by_index_out_of_range(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} archives = ['archA', 'archB'] mock_subproc.return_value.stdout = '\n'.join(archives) + '\n' mock_subproc.return_value.returncode = 0 args = make_args('dummy.toml', 'dummy.rc', target='3') # out of range rc = run_list(args) assert rc == 1 err = capsys.readouterr().err assert 'Archive index out of range' in err @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_by_name(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} # Only need one subprocess.run (direct by name) mock_subproc.return_value.stdout = 'filex\nfiley\n' mock_subproc.return_value.returncode = 0 args = make_args('dummy.toml', 'dummy.rc', target='archive-explicit') rc = run_list(args) assert rc == 0 out = capsys.readouterr().out assert 'filex' in out and 'filey' in out call_args = mock_subproc.call_args[0][0] assert call_args == ['borg', 'list', '/repo::archive-explicit'] @mock.patch('locutus.list.LocutusConfig') def test_list_no_repo(mock_config, capsys): mock_config.return_value.get_repo.return_value = None mock_config.return_value.env = {} args = make_args('dummy.toml', 'dummy.rc') rc = run_list(args) assert rc == 1 err = capsys.readouterr().err assert 'No BORG_REPO configured' in err @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run', side_effect=Exception('fail')) def test_list_unexpected_exception(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} args = make_args('dummy.toml', 'dummy.rc') rc = run_list(args) assert rc == 1 err = capsys.readouterr().err assert 'borg list failed' in err @mock.patch('locutus.list.LocutusConfig') @mock.patch( 'subprocess.run', side_effect=pytest.importorskip('subprocess').CalledProcessError( 1, ['borg', 'list'] ), ) def test_list_calledprocesserror(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} args = make_args('dummy.toml', 'dummy.rc') rc = run_list(args) assert rc == 1 err = capsys.readouterr().err assert 'borg list failed' in err @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_no_archives(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} mock_subproc.return_value.stdout = '' mock_subproc.return_value.returncode @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_no_archives_main(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} mock_subproc.return_value.stdout = '' # No archives mock_subproc.return_value.returncode = 0 args = make_args('dummy.toml', 'dummy.rc') rc = run_list(args) assert rc == 0 out = capsys.readouterr().out assert 'No archives found' in out @mock.patch('locutus.list.LocutusConfig') @mock.patch('subprocess.run') def test_list_by_index_no_archives(mock_subproc, mock_config, capsys): mock_config.return_value.get_repo.return_value = '/repo' mock_config.return_value.env = {} mock_subproc.return_value.stdout = '' # No archives mock_subproc.return_value.returncode = 0 args = make_args('dummy.toml', 'dummy.rc', target='0') rc = run_list(args) assert rc == 1 out = capsys.readouterr().out assert 'No archives found' in out