From 2ab5a07b003dc8ec77efcc7cd917480877a19ef8 Mon Sep 17 00:00:00 2001 From: Alexander Wainwright Date: Tue, 24 Jun 2025 12:23:10 +1000 Subject: [PATCH] Update list tests --- test/test_list.py | 120 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 15 deletions(-) diff --git a/test/test_list.py b/test/test_list.py index 4e1588b..e34f8b9 100644 --- a/test/test_list.py +++ b/test/test_list.py @@ -5,48 +5,99 @@ import pytest from locutus.list import run_list -def make_args(config, profile): +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_success(mock_subproc, mock_config, capsys): +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 = {} - # Simulate borg list output with three archives - mock_subproc.return_value.stdout = ( - 'auto-2024-06-22T123456\nauto-2024-06-21T101112\nfoo\n' - ) + # 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 - assert ' 2: auto-2024-06-22T123456' in out - assert ' 1: auto-2024-06-21T101112' in out - assert ' 0: foo' in out + 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_empty(mock_subproc, mock_config, capsys): +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 = {} - mock_subproc.return_value.stdout = '' - mock_subproc.return_value.returncode = 0 + # 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') + args = make_args('dummy.toml', 'dummy.rc', target='0') rc = run_list(args) assert rc == 0 out = capsys.readouterr().out - assert 'No archives found' in 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') @@ -87,3 +138,42 @@ def test_list_calledprocesserror(mock_subproc, mock_config, capsys): 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