mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-07-22 02:03:01 +02:00
Yet more tests.
This commit is contained in:
@@ -10,9 +10,18 @@ import borgmatic.actions.browse.workers
|
||||
|
||||
|
||||
class Archives_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a single Borg archive from among the archives in a repository. The item
|
||||
selection event is handled in a Carousel instance, the parent widget of an Archives_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, config, repository):
|
||||
'''
|
||||
Given a configuration dict and a repository dict, start loading the archives from the
|
||||
repository for eventual display in this widget.
|
||||
'''
|
||||
self.config = config
|
||||
self.repository = repository
|
||||
|
||||
@@ -31,5 +40,10 @@ class Archives_list(textual.widgets.OptionList):
|
||||
)
|
||||
|
||||
def on_option_list_option_highlighted(self, event):
|
||||
'''
|
||||
When the highlighted option changes, record that fact. This flag is consumed in
|
||||
borgmatic.actions.browse.workers.add_repository_archives() in order to retain the
|
||||
highlighted option even as other options load around it.
|
||||
'''
|
||||
if self.highlighted not in {None, 0}:
|
||||
self.highlighted_option_changed = True
|
||||
|
||||
@@ -14,11 +14,14 @@ import borgmatic.actions.browse.workers
|
||||
def get_relative_archive_path_components(archive_path, current_directory_path_components):
|
||||
'''
|
||||
Given an Archive_path instance and a tuple of path components for the currently browsed
|
||||
directory, get the path components for the archive path relative to that directory.
|
||||
directory, get the path components as a tuple for the archive path relative to that directory.
|
||||
|
||||
If the archive path is not actually relative to that directory, return None.
|
||||
For instance, given an archive path with a path of 'foo/bar/baz/quux.txt' and current
|
||||
directory path components of ('foo', 'bar'), return ('baz', 'quux.txt').
|
||||
|
||||
If the archive path is not actually relative to the current directory, return None.
|
||||
'''
|
||||
archive_path_components = archive_path.file_path.split(os.path.sep)
|
||||
archive_path_components = tuple(archive_path.file_path.split(os.path.sep))
|
||||
|
||||
if not current_directory_path_components:
|
||||
return archive_path_components
|
||||
@@ -35,15 +38,20 @@ def get_relative_archive_path_components(archive_path, current_directory_path_co
|
||||
return archive_path_components[len(current_directory_path_components) :]
|
||||
|
||||
|
||||
def make_directory_list_option(archive_path, archive_path_components):
|
||||
def make_directory_list_option(archive_path, relative_path_components):
|
||||
'''
|
||||
Given an Archive_path instance and a tuple of relative path components for it, make a
|
||||
textual.widgets.option_list.Option for the path. Use an the icon based on whether this looks
|
||||
like a terminal filename or a directory.
|
||||
'''
|
||||
pieces = (
|
||||
borgmatic.actions.browse.icons.PATH_TYPE_ICONS.get(
|
||||
archive_path.path_type if len(archive_path_components) == 1 else 'd', '❓'
|
||||
archive_path.path_type if len(relative_path_components) == 1 else 'd', '❓'
|
||||
),
|
||||
archive_path_components[0],
|
||||
relative_path_components[0],
|
||||
) + (('→', archive_path.link_target) if archive_path.link_target else ())
|
||||
|
||||
return textual.widgets.option_list.Option(' '.join(pieces), id=archive_path_components[0])
|
||||
return textual.widgets.option_list.Option(prompt=' '.join(pieces), id=relative_path_components[0])
|
||||
|
||||
|
||||
def add_archive_paths(
|
||||
@@ -60,16 +68,16 @@ def add_archive_paths(
|
||||
(
|
||||
*directory_list.options,
|
||||
*(
|
||||
make_directory_list_option(archive_path, archive_path_components)
|
||||
make_directory_list_option(archive_path, relative_path_components)
|
||||
for archive_path in archive_paths
|
||||
for archive_path_components in (
|
||||
for relative_path_components in (
|
||||
get_relative_archive_path_components(
|
||||
archive_path,
|
||||
directory_list.path_components,
|
||||
),
|
||||
)
|
||||
if archive_path_components
|
||||
if not archive_path_components[0] in directory_list._id_to_option
|
||||
if relative_path_components
|
||||
if not relative_path_components[0] in directory_list._id_to_option
|
||||
),
|
||||
),
|
||||
key=lambda option: ((option.id == 'loading-indicator'), option.prompt),
|
||||
|
||||
@@ -4,13 +4,15 @@ import os
|
||||
import textual.binding
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.archive
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.icons
|
||||
import borgmatic.actions.browse.workers
|
||||
|
||||
|
||||
class File_preview(textual.widgets.RichLog):
|
||||
'''
|
||||
A widget for extracting and previewing the contents of a file stored in a Borg archive.
|
||||
'''
|
||||
|
||||
BINDINGS = [
|
||||
*textual.widgets.RichLog.BINDINGS,
|
||||
textual.binding.Binding(
|
||||
@@ -28,21 +30,17 @@ class File_preview(textual.widgets.RichLog):
|
||||
]
|
||||
|
||||
def __init__(self, config, repository, archive_name, file_path):
|
||||
'''
|
||||
Given a configuration dict, a repository dict, an archive name, and the path of a file in
|
||||
the archive, start loading the file's contents for eventual display in this widget.
|
||||
'''
|
||||
self.config = config
|
||||
self.repository = repository
|
||||
self.archive_name = archive_name
|
||||
self.file_path = file_path
|
||||
|
||||
super().__init__(classes='panel')
|
||||
self.border_title = ' '.join(
|
||||
(
|
||||
borgmatic.actions.browse.icons.PATH_TYPE_ICONS[
|
||||
borgmatic.actions.browse.archive.Path_type.FILE.value
|
||||
],
|
||||
self.file_path,
|
||||
'preview',
|
||||
)
|
||||
)
|
||||
self.border_title = ' '.join(('📄', self.file_path, 'preview'))
|
||||
self.auto_scroll = False
|
||||
|
||||
timer = borgmatic.actions.browse.loading.add_inline_loading_indicator(self)
|
||||
|
||||
@@ -10,9 +10,18 @@ import borgmatic.actions.browse.workers
|
||||
|
||||
|
||||
class Repositories_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a single Borg repository from among the repositories in a borgmatic
|
||||
configuratin file. The item selection event is handled in a Carousel instance, the parent widget
|
||||
of a Repositories_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, config):
|
||||
'''
|
||||
Given a configuration dict, populate the repositories in this widget.
|
||||
'''
|
||||
self.config = config
|
||||
self.repositories = config['repositories']
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ def add_repository_archives(browse_app, archives_list, config, repository, timer
|
||||
loading_option,
|
||||
),
|
||||
)
|
||||
|
||||
# Retain the highlighted option position even as other options load around it.
|
||||
archives_list.highlighted = (
|
||||
archives_list.get_option_index(highlighted_option.id)
|
||||
if highlighted_option and archives_list.highlighted_option_changed
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
from borgmatic.actions.browse import archives_list as module
|
||||
|
||||
from flexmock import flexmock
|
||||
import textual.widgets.option_list
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_none_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module.borgmatic.actions.browse.archives_list.Archives_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.highlighted = None
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_zero_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module.borgmatic.actions.browse.archives_list.Archives_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.highlighted = 0
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_zero_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module.borgmatic.actions.browse.archives_list.Archives_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
archives_list.highlighted = 0
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_non_zero_marks_it_changed():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module.borgmatic.actions.browse.archives_list.Archives_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
archives_list.add_option(textual.widgets.option_list.Option('one', id='one'))
|
||||
archives_list.highlighted = 1
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is True
|
||||
@@ -0,0 +1,14 @@
|
||||
from borgmatic.actions.browse import file_preview as module
|
||||
|
||||
from flexmock import flexmock
|
||||
import textual.widgets.option_list
|
||||
|
||||
|
||||
def test_file_preview_does_not_raise():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
flexmock(module.borgmatic.actions.browse.repositories_list.Repositories_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
module.Repositories_list(config=flexmock())
|
||||
@@ -0,0 +1,14 @@
|
||||
from borgmatic.actions.browse import repositories_list as module
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
|
||||
def test_repositories_list_populates_options():
|
||||
config = {'repositories': [{'path': 'test1.borg'}, {'path': 'test2.borg', 'label': 'two'}]}
|
||||
|
||||
repositories_list = module.Repositories_list(config=config)
|
||||
assert len(repositories_list.options) == 2
|
||||
assert repositories_list.options[0].prompt == 'test1.borg'
|
||||
assert repositories_list.options[0].id == 0
|
||||
assert repositories_list.options[1].prompt == 'two'
|
||||
assert repositories_list.options[1].id == 1
|
||||
@@ -0,0 +1,90 @@
|
||||
from borgmatic.actions.browse import directory_list as module
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_strips_off_current_directory():
|
||||
assert module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ('foo', 'bar')
|
||||
) == ('baz', 'quux.txt')
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_with_root_current_directory_strips_off_nothing():
|
||||
assert module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ()
|
||||
) == ('foo', 'bar', 'baz', 'quux.txt')
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_with_non_matching_paths_returns_none():
|
||||
assert (
|
||||
module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ('etc',)
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_file_path_makes_file_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='-', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '📄 baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_directory_path_makes_directory_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='d', file_path='foo/bar/baz', link_target=''), ('baz',)
|
||||
)
|
||||
|
||||
assert option.prompt == '📁 baz'
|
||||
assert option.id == 'baz'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_contained_file_path_makes_directory_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='d', file_path='foo/bar/baz.txt', link_target=''), ('bar', 'baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '📁 bar'
|
||||
assert option.id == 'bar'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_link_path_makes_link_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='l', file_path='foo/bar/baz.txt', link_target='quux.txt'), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '🔗 baz.txt → quux.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_pipe_path_makes_pipe_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='p', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '🚰 baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_unknown_path_makes_unknown_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='wtf', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '❓ baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
@@ -2132,7 +2132,6 @@ def test_collect_highlander_action_summary_logs_error_on_run_browse_failure():
|
||||
assert {log.levelno for log in logs} == {logging.CRITICAL}
|
||||
|
||||
|
||||
|
||||
def test_collect_configuration_run_summary_logs_info_for_success():
|
||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
||||
flexmock(module.command).should_receive('filter_hooks').with_args(
|
||||
|
||||
Reference in New Issue
Block a user