1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
# SPDX-FileCopyrightText: Daniel Schadt
# SPDX-FileCopyrightText: Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""Test the built-in directory browser."""
import pathlib
import dataclasses
import pytest
import bs4
from qutebrowser.qt.core import QUrl
from qutebrowser.utils import urlutils
from helpers import testutils
pytestmark = pytest.mark.qtwebengine_skip("Title is empty when parsing for "
"some reason?")
class DirLayout:
"""Provide a fake directory layout to test dirbrowser."""
LAYOUT = [
'folder0/file00',
'folder0/file01',
'folder1/folder10/file100',
'folder1/file10',
'folder1/file11',
'file0',
'file1',
]
@classmethod
def layout_folders(cls):
"""Return all folders in the root directory of the layout."""
folders = set()
for path in cls.LAYOUT:
parts = path.split('/')
if len(parts) > 1:
folders.add(parts[0])
folders = list(folders)
folders.sort()
return folders
@classmethod
def get_folder_content(cls, name):
"""Return (folders, files) for the given folder in the root dir."""
folders = set()
files = set()
for path in cls.LAYOUT:
if not path.startswith(name + '/'):
continue
parts = path.split('/')
if len(parts) == 2:
files.add(parts[1])
else:
folders.add(parts[1])
folders = list(folders)
folders.sort()
files = list(files)
files.sort()
return (folders, files)
def __init__(self, factory):
self._factory = factory
self.base = factory.getbasetemp()
self.layout = factory.mktemp('layout')
self._mklayout()
def _mklayout(self):
for filename in self.LAYOUT:
path = self.layout / filename
path.parent.mkdir(exist_ok=True, parents=True)
path.touch()
def file_url(self):
"""Return a file:// link to the directory."""
return urlutils.file_url(str(self.layout))
def path(self, *parts):
"""Return the path to the given file inside the layout folder."""
return self.layout.joinpath(*parts)
def base_path(self):
"""Return the path of the base temporary folder."""
return self.base
@dataclasses.dataclass
class Parsed:
path: str
parent: str
folders: list[str]
files: list[str]
@dataclasses.dataclass
class Item:
path: str
link: str
text: str
def parse(quteproc):
"""Parse the dirbrowser content from the given quteproc.
Args:
quteproc: The quteproc fixture.
"""
html = quteproc.get_content(plain=False)
soup = bs4.BeautifulSoup(html, 'html.parser')
with testutils.ignore_bs4_warning():
print(soup.prettify())
title_prefix = 'Browse directory: '
# Strip off the title prefix to obtain the path of the folder that
# we're browsing
path = pathlib.Path(soup.title.string.removeprefix(title_prefix))
container = soup('div', id='dirbrowserContainer')[0]
parent_elem = container('ul', class_='parent')
if not parent_elem:
parent = None
else:
parent = pathlib.Path(QUrl(parent_elem[0].li.a['href']).toLocalFile())
folders = []
files = []
for css_class, list_ in [('folders', folders), ('files', files)]:
for li in container('ul', class_=css_class)[0]('li'):
item_path = pathlib.Path(QUrl(li.a['href']).toLocalFile())
list_.append(Item(path=item_path, link=li.a['href'],
text=str(li.a.string)))
return Parsed(path=path, parent=parent, folders=folders, files=files)
@pytest.fixture(scope='module')
def dir_layout(tmp_path_factory):
return DirLayout(tmp_path_factory)
def test_parent_folder(dir_layout, quteproc):
quteproc.open_url(dir_layout.file_url())
page = parse(quteproc)
assert page.parent == dir_layout.base_path()
def test_parent_with_slash(dir_layout, quteproc):
"""Test the parent link with a URL that has a trailing slash."""
quteproc.open_url(dir_layout.file_url() + '/')
page = parse(quteproc)
assert page.parent == dir_layout.base_path()
def test_parent_in_root_dir(dir_layout, quteproc):
# This actually works on windows
urlstr = urlutils.file_url(str(pathlib.Path('/')))
quteproc.open_url(urlstr)
page = parse(quteproc)
assert page.parent is None
def test_enter_folder_smoke(dir_layout, quteproc):
quteproc.open_url(dir_layout.file_url())
quteproc.send_cmd(':hint all normal')
# a is the parent link, s is the first listed folder/file
quteproc.send_cmd(':hint-follow s')
expected_url = urlutils.file_url(str(dir_layout.path('folder0')))
quteproc.wait_for_load_finished_url(expected_url)
page = parse(quteproc)
assert page.path == dir_layout.path('folder0')
@pytest.mark.parametrize('folder', DirLayout.layout_folders())
def test_enter_folder(dir_layout, quteproc, folder):
quteproc.open_url(dir_layout.file_url())
quteproc.click_element_by_text(text=folder)
expected_url = urlutils.file_url(str(dir_layout.path(folder)))
quteproc.wait_for_load_finished_url(expected_url)
page = parse(quteproc)
assert page.path == dir_layout.path(folder)
assert page.parent == dir_layout.path()
folders, files = DirLayout.get_folder_content(folder)
foldernames = [item.text for item in page.folders]
assert foldernames == folders
filenames = [item.text for item in page.files]
assert filenames == files
|