mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-07-22 02:03:01 +02:00
More browse tests.
This commit is contained in:
@@ -8,6 +8,14 @@ import borgmatic.actions.browse.paths
|
||||
|
||||
|
||||
def make_next_panel(focused_panel, option_id):
|
||||
'''
|
||||
Given a focused panel widget and the selected option ID, return the next panel corresponding to
|
||||
that selection. This is the mechanism by which the user can successively drill down from
|
||||
configuration file to repository to archive to root directory to non-root directory or file.
|
||||
|
||||
If the particular option ID on the focused panel doesn't have a supported next panel, then
|
||||
return None.
|
||||
'''
|
||||
if isinstance(focused_panel, borgmatic.actions.browse.panels.Configuration_files_list):
|
||||
return borgmatic.actions.browse.panels.Repositories_list(
|
||||
config=focused_panel.configs[option_id]
|
||||
@@ -101,7 +109,7 @@ class Carousel(textual.containers.Horizontal):
|
||||
next_panel = make_next_panel(self.focused_panel, option_id)
|
||||
|
||||
if next_panel is None:
|
||||
self.notify('Cannot load this content', severity='warning')
|
||||
self.notify('Cannot display this content', severity='warning')
|
||||
return
|
||||
|
||||
self.panels.append(next_panel)
|
||||
@@ -125,7 +133,7 @@ class Carousel(textual.containers.Horizontal):
|
||||
An option has been selected, so advance to the next panel—unless the option selected is
|
||||
"..", in which case go to the previous panel.
|
||||
'''
|
||||
if event.option_list != self.focused_panel or event.option_id == 'loading-indicator':
|
||||
if event.option_list != self.focused_panel or event.option_id == 'loading-indicator': # pragma: no cover
|
||||
return
|
||||
|
||||
if event.option_id == '..':
|
||||
|
||||
@@ -61,8 +61,6 @@ def log_to_widget(logs_widget):
|
||||
logger.setLevel(min(handler.level for handler in logger.handlers))
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Remove the console log handler so it doesn't try to log all over our UI; we have our own
|
||||
# log handler for surfacing logs within the UI.
|
||||
with contextlib.suppress(StopIteration):
|
||||
console_handler = next(
|
||||
handler
|
||||
|
||||
@@ -59,9 +59,10 @@ def add_archive_files(
|
||||
)
|
||||
|
||||
for path_type, file_path, link_target in file_type_paths:
|
||||
pieces = (borgmatic.actions.browse.paths.PATH_TYPE_ICONS.get(path_type, '❓'), file_path) + (
|
||||
('→', link_target) if link_target else ()
|
||||
)
|
||||
pieces = (
|
||||
borgmatic.actions.browse.paths.PATH_TYPE_ICONS.get(path_type, '❓'),
|
||||
file_path,
|
||||
) + (('→', link_target) if link_target else ())
|
||||
highlighted_option = directory_list.highlighted_option
|
||||
sorted_options = sorted(
|
||||
[
|
||||
@@ -91,7 +92,9 @@ def load_file_preview(browse_app, file_preview, config, repository, archive_name
|
||||
browse_app.call_from_thread(file_preview.clear)
|
||||
|
||||
if file_content is None:
|
||||
browse_app.call_from_thread(file_preview.write, 'Cannot load a preview for this file')
|
||||
browse_app.call_from_thread(file_preview.write, 'Cannot display a preview for this file')
|
||||
else:
|
||||
syntax_lexer = rich.syntax.Syntax.guess_lexer(file_path, file_content)
|
||||
browse_app.call_from_thread(file_preview.write, rich.syntax.Syntax(file_content, syntax_lexer))
|
||||
browse_app.call_from_thread(
|
||||
file_preview.write, rich.syntax.Syntax(file_content, syntax_lexer)
|
||||
)
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ namespaces = false
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = "tests"
|
||||
addopts = "--cov-report term-missing:skip-covered --cov=borgmatic --no-cov-on-fail --cov-fail-under=100 --ignore=tests/end-to-end --timeout=120"
|
||||
addopts = "--cov-report term-missing:skip-covered --cov=borgmatic --no-cov-on-fail --cov-fail-under=100 --ignore=tests/end-to-end --timeout=120 --asyncio-mode=auto"
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
@@ -27,5 +27,6 @@ requests-oauthlib
|
||||
rich
|
||||
rpds-py
|
||||
ruamel-yaml>0.15.0
|
||||
textual
|
||||
typing-extensions
|
||||
urllib3
|
||||
|
||||
@@ -13,13 +13,16 @@ idna==3.16 # via requests, -r test_requirements.in
|
||||
iniconfig==2.3.0 # via pytest, -r test_requirements.in
|
||||
jsonschema==4.26.0 # via -r test_requirements.in
|
||||
jsonschema-specifications==2025.9.1 # via jsonschema, -r test_requirements.in
|
||||
linkify-it-py==2.1.0 # via markdown-it-py
|
||||
markdown==3.10.2 # via apprise, -r test_requirements.in
|
||||
markdown-it-py==4.2.0 # via rich
|
||||
markdown-it-py==4.2.0 # via mdit-py-plugins, rich, textual
|
||||
mdit-py-plugins==0.6.1 # via textual
|
||||
mdurl==0.1.2 # via markdown-it-py
|
||||
oauthlib==3.3.1 # via requests-oauthlib, -r test_requirements.in
|
||||
packaging==26.2 # via pytest, -r test_requirements.in
|
||||
platformdirs==4.9.6 # via textual
|
||||
pluggy==1.6.0 # via pytest, pytest-cov, -r test_requirements.in
|
||||
pygments==2.20.0 # via pytest, rich, -r test_requirements.in
|
||||
pygments==2.20.0 # via pytest, rich, textual, -r test_requirements.in
|
||||
pytest==9.0.3 # via pytest-asyncio, pytest-cov, pytest-timeout, -r test_requirements.in
|
||||
pytest-asyncio==1.3.0 # via -r test_requirements.in
|
||||
pytest-cov==7.1.0 # via -r test_requirements.in
|
||||
@@ -28,8 +31,10 @@ pyyaml>5.0.0
|
||||
referencing==0.37.0 # via jsonschema, jsonschema-specifications, -r test_requirements.in
|
||||
requests==2.34.2 # via apprise, requests-oauthlib, -r test_requirements.in
|
||||
requests-oauthlib==2.0.0 # via apprise, -r test_requirements.in
|
||||
rich==15.0.0 # via -r test_requirements.in
|
||||
rich==15.0.0 # via textual, -r test_requirements.in
|
||||
rpds-py==0.30.0 # via jsonschema, referencing, -r test_requirements.in
|
||||
ruamel-yaml>0.15.0
|
||||
typing-extensions==4.15.0 # via -r test_requirements.in
|
||||
textual==8.2.7 # via -r test_requirements.in
|
||||
typing-extensions==4.15.0 # via textual, -r test_requirements.in
|
||||
uc-micro-py==2.0.0 # via linkify-it-py
|
||||
urllib3==2.7.0 # via requests, -r test_requirements.in
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import asyncio
|
||||
|
||||
import borgmatic.actions.browse.app
|
||||
import borgmatic.actions.browse.panels
|
||||
|
||||
@@ -7,10 +5,6 @@ import pytest
|
||||
from flexmock import flexmock
|
||||
|
||||
|
||||
pytestmark = pytest.mark.asyncio(loop_scope='module')
|
||||
loop: asyncio.AbstractEventLoop
|
||||
|
||||
|
||||
async def test_browse_app_with_multiple_configs_uses_configuration_files_list():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
|
||||
@@ -1,19 +1,182 @@
|
||||
import asyncio
|
||||
|
||||
import borgmatic.actions.browse.app
|
||||
import borgmatic.actions.browse.carousel
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.logs
|
||||
import borgmatic.actions.browse.panels
|
||||
import borgmatic.actions.browse.workers
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from flexmock import flexmock
|
||||
|
||||
import textual.widgets.option_list
|
||||
from borgmatic.actions.browse import carousel as module
|
||||
|
||||
|
||||
pytestmark = pytest.mark.asyncio(loop_scope='module')
|
||||
loop: asyncio.AbstractEventLoop
|
||||
def test_make_next_panel_with_configuration_files_list_returns_repositories_list():
|
||||
configs = {'test.yaml': {'repositories': [{'path': 'test.borg'}]}}
|
||||
|
||||
repositories_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.panels.Configuration_files_list(configs),
|
||||
option_id='test.yaml',
|
||||
)
|
||||
|
||||
assert isinstance(repositories_list, borgmatic.actions.browse.panels.Repositories_list)
|
||||
assert repositories_list.config == configs['test.yaml']
|
||||
|
||||
|
||||
def test_make_next_panel_with_repositories_list_returns_archives_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(borgmatic.actions.browse.panels.Archives_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
|
||||
archives_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.panels.Repositories_list(config),
|
||||
option_id=0,
|
||||
)
|
||||
|
||||
assert isinstance(archives_list, borgmatic.actions.browse.panels.Archives_list)
|
||||
assert archives_list.config == config
|
||||
assert archives_list.repository == config['repositories'][0]
|
||||
|
||||
|
||||
def test_make_next_panel_with_archives_list_returns_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.panels.Archives_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
|
||||
directory_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.panels.Archives_list(
|
||||
config, config['repositories'][0]
|
||||
),
|
||||
option_id='archive',
|
||||
)
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.panels.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
|
||||
|
||||
def test_make_next_panel_with_root_directory_list_and_selected_directory_option_returns_new_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.panels.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📁 etc'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='etc')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.panels.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.path_components == ('etc',)
|
||||
|
||||
|
||||
def test_make_next_panel_with_non_root_directory_list_and_selected_directory_option_returns_new_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.panels.Directory_list(
|
||||
config, config['repositories'][0], 'archive', path_components=('etc',),
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📁 borgmatic'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='borgmatic')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.panels.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.path_components == ('etc', 'borgmatic')
|
||||
|
||||
|
||||
def test_make_next_panel_with_root_directory_list_and_selected_file_option_returns_new_file_preview():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.panels.File_preview).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.panels.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📄 config.yaml'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.panels.File_preview)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.file_path == 'config.yaml'
|
||||
|
||||
|
||||
def test_make_next_panel_with_non_root_directory_list_and_selected_file_option_returns_new_file_preview():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.panels.File_preview).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.panels.Directory_list(
|
||||
config, config['repositories'][0], 'archive', path_components=('etc', 'borgmatic'),
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📄 config.yaml'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.panels.File_preview)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.file_path == 'etc/borgmatic/config.yaml'
|
||||
|
||||
|
||||
def test_make_next_panel_with_unsupported_focused_panel_returns_none():
|
||||
assert module.make_next_panel(focused_panel=flexmock(), option_id='hmmm') is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', ('🔗', '🚰', '🐙'))
|
||||
def test_make_next_panel_with_directory_list_and_unsupported_selected_option_returns_none(icon):
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_archive_files')
|
||||
flexmock(borgmatic.actions.browse.panels.Directory_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.panels.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt=f'{icon} config.yaml'))
|
||||
|
||||
assert module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml') is None
|
||||
|
||||
|
||||
async def test_carousel_previous_action_with_multiple_configs_does_not_raise():
|
||||
@@ -41,7 +204,7 @@ async def test_carousel_previous_action_with_one_config_does_not_raise():
|
||||
await pilot.press('left')
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_multiple_configs_advances_panels():
|
||||
async def test_carousel_next_action_with_multiple_configs_advances_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
@@ -67,7 +230,7 @@ async def test_carousel_next_action_with_multiple_configs_advances_panels():
|
||||
assert app.focused == carousel.panels[1]
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_one_config_advances_to_next_panel():
|
||||
async def test_carousel_next_action_with_one_config_advances_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
@@ -91,6 +254,27 @@ async def test_carousel_next_action_with_one_config_advances_to_next_panel():
|
||||
assert app.focused == carousel.panels[1]
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_no_next_panel_does_not_advance():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module).should_receive('make_next_panel')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(carousel.panels[0], borgmatic.actions.browse.panels.Repositories_list)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_next_action_and_previous_action_returns_to_original_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
|
||||
Reference in New Issue
Block a user