Merge remote-tracking branch 'origin/pr/3950'
This commit is contained in:
commit
91ae86db62
@ -135,11 +135,12 @@ def create_full_filename(basename, filename):
|
|||||||
Return:
|
Return:
|
||||||
The full absolute path, or None if filename creation was not possible.
|
The full absolute path, or None if filename creation was not possible.
|
||||||
"""
|
"""
|
||||||
|
basename = utils.sanitize_filename(basename)
|
||||||
|
# Filename can be a full path so don't use sanitize_filename on it.
|
||||||
# Remove chars which can't be encoded in the filename encoding.
|
# Remove chars which can't be encoded in the filename encoding.
|
||||||
# See https://github.com/qutebrowser/qutebrowser/issues/427
|
# See https://github.com/qutebrowser/qutebrowser/issues/427
|
||||||
encoding = sys.getfilesystemencoding()
|
encoding = sys.getfilesystemencoding()
|
||||||
filename = utils.force_encoding(filename, encoding)
|
filename = utils.force_encoding(filename, encoding)
|
||||||
basename = utils.force_encoding(basename, encoding)
|
|
||||||
if os.path.isabs(filename) and (os.path.isdir(filename) or
|
if os.path.isabs(filename) and (os.path.isdir(filename) or
|
||||||
filename.endswith(os.sep)):
|
filename.endswith(os.sep)):
|
||||||
# We got an absolute directory from the user, so we save it under
|
# We got an absolute directory from the user, so we save it under
|
||||||
@ -160,8 +161,7 @@ def get_filename_question(*, suggested_filename, url, parent=None):
|
|||||||
url: The URL the download originated from.
|
url: The URL the download originated from.
|
||||||
parent: The parent of the question (a QObject).
|
parent: The parent of the question (a QObject).
|
||||||
"""
|
"""
|
||||||
encoding = sys.getfilesystemencoding()
|
suggested_filename = utils.sanitize_filename(suggested_filename)
|
||||||
suggested_filename = utils.force_encoding(suggested_filename, encoding)
|
|
||||||
|
|
||||||
q = usertypes.Question(parent)
|
q = usertypes.Question(parent)
|
||||||
q.title = "Save file to:"
|
q.title = "Save file to:"
|
||||||
@ -1260,8 +1260,7 @@ class TempDownloadManager:
|
|||||||
A tempfile.NamedTemporaryFile that should be used to save the file.
|
A tempfile.NamedTemporaryFile that should be used to save the file.
|
||||||
"""
|
"""
|
||||||
tmpdir = self.get_tmpdir()
|
tmpdir = self.get_tmpdir()
|
||||||
encoding = sys.getfilesystemencoding()
|
suggested_name = utils.sanitize_filename(suggested_name)
|
||||||
suggested_name = utils.force_encoding(suggested_name, encoding)
|
|
||||||
# Make sure that the filename is not too long
|
# Make sure that the filename is not too long
|
||||||
suggested_name = utils.elide_filename(suggested_name, 50)
|
suggested_name = utils.elide_filename(suggested_name, 50)
|
||||||
fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False,
|
fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False,
|
||||||
|
@ -500,10 +500,22 @@ def sanitize_filename(name, replacement='_'):
|
|||||||
"""
|
"""
|
||||||
if replacement is None:
|
if replacement is None:
|
||||||
replacement = ''
|
replacement = ''
|
||||||
# Bad characters taken from Windows, there are even fewer on Linux
|
|
||||||
|
# Remove chars which can't be encoded in the filename encoding.
|
||||||
|
# See https://github.com/qutebrowser/qutebrowser/issues/427
|
||||||
|
encoding = sys.getfilesystemencoding()
|
||||||
|
name = force_encoding(name, encoding)
|
||||||
|
|
||||||
# See also
|
# See also
|
||||||
# https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
|
# https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
|
||||||
|
if is_windows:
|
||||||
bad_chars = '\\/:*?"<>|'
|
bad_chars = '\\/:*?"<>|'
|
||||||
|
elif is_mac:
|
||||||
|
# Colons can be confusing in finder https://superuser.com/a/326627
|
||||||
|
bad_chars = '/:'
|
||||||
|
else:
|
||||||
|
bad_chars = '/'
|
||||||
|
|
||||||
for bad_char in bad_chars:
|
for bad_char in bad_chars:
|
||||||
name = name.replace(bad_char, replacement)
|
name = name.replace(bad_char, replacement)
|
||||||
return name
|
return name
|
||||||
|
@ -515,16 +515,35 @@ def mode_manager(win_registry, config_stub, key_config_stub, qapp):
|
|||||||
objreg.delete('mode-manager', scope='window', window=0)
|
objreg.delete('mode-manager', scope='window', window=0)
|
||||||
|
|
||||||
|
|
||||||
|
def standarddir_tmpdir(folder, monkeypatch, tmpdir):
|
||||||
|
"""Set tmpdir/config as the configdir.
|
||||||
|
|
||||||
|
Use this to avoid creating a 'real' config dir (~/.config/qute_test).
|
||||||
|
"""
|
||||||
|
confdir = tmpdir / folder
|
||||||
|
confdir.ensure(dir=True)
|
||||||
|
if hasattr(standarddir, folder):
|
||||||
|
monkeypatch.setattr(standarddir, folder,
|
||||||
|
lambda **_kwargs: str(confdir))
|
||||||
|
return confdir
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def download_tmpdir(monkeypatch, tmpdir):
|
||||||
|
"""Set tmpdir/download as the downloaddir.
|
||||||
|
|
||||||
|
Use this to avoid creating a 'real' download dir (~/.config/qute_test).
|
||||||
|
"""
|
||||||
|
return standarddir_tmpdir('download', monkeypatch, tmpdir)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def config_tmpdir(monkeypatch, tmpdir):
|
def config_tmpdir(monkeypatch, tmpdir):
|
||||||
"""Set tmpdir/config as the configdir.
|
"""Set tmpdir/config as the configdir.
|
||||||
|
|
||||||
Use this to avoid creating a 'real' config dir (~/.config/qute_test).
|
Use this to avoid creating a 'real' config dir (~/.config/qute_test).
|
||||||
"""
|
"""
|
||||||
confdir = tmpdir / 'config'
|
return standarddir_tmpdir('config', monkeypatch, tmpdir)
|
||||||
confdir.ensure(dir=True)
|
|
||||||
monkeypatch.setattr(standarddir, 'config', lambda auto=False: str(confdir))
|
|
||||||
return confdir
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -533,10 +552,7 @@ def data_tmpdir(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
Use this to avoid creating a 'real' data dir (~/.local/share/qute_test).
|
Use this to avoid creating a 'real' data dir (~/.local/share/qute_test).
|
||||||
"""
|
"""
|
||||||
datadir = tmpdir / 'data'
|
return standarddir_tmpdir('data', monkeypatch, tmpdir)
|
||||||
datadir.ensure(dir=True)
|
|
||||||
monkeypatch.setattr(standarddir, 'data', lambda system=False: str(datadir))
|
|
||||||
return datadir
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -545,10 +561,7 @@ def runtime_tmpdir(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
Use this to avoid creating a 'real' runtime dir.
|
Use this to avoid creating a 'real' runtime dir.
|
||||||
"""
|
"""
|
||||||
runtimedir = tmpdir / 'runtime'
|
return standarddir_tmpdir('runtime', monkeypatch, tmpdir)
|
||||||
runtimedir.ensure(dir=True)
|
|
||||||
monkeypatch.setattr(standarddir, 'runtime', lambda: str(runtimedir))
|
|
||||||
return runtimedir
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -557,10 +570,7 @@ def cache_tmpdir(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
Use this to avoid creating a 'real' cache dir (~/.cache/qute_test).
|
Use this to avoid creating a 'real' cache dir (~/.cache/qute_test).
|
||||||
"""
|
"""
|
||||||
cachedir = tmpdir / 'cache'
|
return standarddir_tmpdir('cache', monkeypatch, tmpdir)
|
||||||
cachedir.ensure(dir=True)
|
|
||||||
monkeypatch.setattr(standarddir, 'cache', lambda: str(cachedir))
|
|
||||||
return cachedir
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -22,6 +22,14 @@ import pytest
|
|||||||
from qutebrowser.browser import downloads, qtnetworkdownloads
|
from qutebrowser.browser import downloads, qtnetworkdownloads
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def is_platform(monkeypatch, platform="windows"):
|
||||||
|
for p in ["mac", "linux", "posix", "windows"]:
|
||||||
|
monkeypatch.setattr(
|
||||||
|
'qutebrowser.utils.utils.is_{}'.format(p),
|
||||||
|
p == platform)
|
||||||
|
|
||||||
|
|
||||||
def test_download_model(qapp, qtmodeltester, config_stub, cookiejar_and_cache,
|
def test_download_model(qapp, qtmodeltester, config_stub, cookiejar_and_cache,
|
||||||
fake_args):
|
fake_args):
|
||||||
"""Simple check for download model internals."""
|
"""Simple check for download model internals."""
|
||||||
@ -92,3 +100,27 @@ class TestDownloadTarget:
|
|||||||
])
|
])
|
||||||
def test_class_hierarchy(self, obj):
|
def test_class_hierarchy(self, obj):
|
||||||
assert isinstance(obj, downloads._DownloadTarget)
|
assert isinstance(obj, downloads._DownloadTarget)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('raw, platform, expected', [
|
||||||
|
('http://foo/bar', 'windows', 'bar'),
|
||||||
|
('A *|<>\\: bear!', 'windows', 'A ______ bear!'),
|
||||||
|
('A *|<>\\: bear!', 'posix', 'A *|<>\\: bear!')
|
||||||
|
])
|
||||||
|
def test_sanitized_filenames(raw, platform, expected, config_stub,
|
||||||
|
download_tmpdir, monkeypatch):
|
||||||
|
is_platform(monkeypatch, platform)
|
||||||
|
manager = downloads.AbstractDownloadManager()
|
||||||
|
target = downloads.FileDownloadTarget(str(download_tmpdir))
|
||||||
|
item = downloads.AbstractDownloadItem()
|
||||||
|
|
||||||
|
# Don't try to start a timer outside of a QThread
|
||||||
|
manager._update_timer.isActive = lambda: True
|
||||||
|
|
||||||
|
# Abstract methods
|
||||||
|
item._ensure_can_set_filename = lambda *args: True
|
||||||
|
item._after_set_filename = lambda *args: True
|
||||||
|
|
||||||
|
manager._init_item(item, True, raw)
|
||||||
|
item.set_target(target)
|
||||||
|
assert item._filename.endswith(expected)
|
||||||
|
@ -113,6 +113,14 @@ class TestElidingFilenames:
|
|||||||
assert utils.elide_filename(filename, length) == expected
|
assert utils.elide_filename(filename, length) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def is_platform(monkeypatch, platform="windows"):
|
||||||
|
for p in ["mac", "linux", "posix", "windows"]:
|
||||||
|
monkeypatch.setattr(
|
||||||
|
'qutebrowser.utils.utils.is_{}'.format(p),
|
||||||
|
p == platform)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=[True, False])
|
@pytest.fixture(params=[True, False])
|
||||||
def freezer(request, monkeypatch):
|
def freezer(request, monkeypatch):
|
||||||
if request.param and not getattr(sys, 'frozen', False):
|
if request.param and not getattr(sys, 'frozen', False):
|
||||||
@ -633,12 +641,15 @@ def test_force_encoding(inp, enc, expected):
|
|||||||
assert utils.force_encoding(inp, enc) == expected
|
assert utils.force_encoding(inp, enc) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('inp, expected', [
|
@pytest.mark.parametrize('inp, platform, expected', [
|
||||||
('normal.txt', 'normal.txt'),
|
('normal.txt', 'windows', 'normal.txt'),
|
||||||
('user/repo issues.mht', 'user_repo issues.mht'),
|
('user/repo issues.mht', 'windows', 'user_repo issues.mht'),
|
||||||
('<Test\\File> - "*?:|', '_Test_File_ - _____'),
|
('<Test\\File> - "*?:|', 'windows', '_Test_File_ - _____'),
|
||||||
|
('<Test\\File> - "*?:|', 'mac', '<Test\\File> - "*?_|'),
|
||||||
|
('<Test\\File> - "*?:|', 'posix', '<Test\\File> - "*?:|'),
|
||||||
])
|
])
|
||||||
def test_sanitize_filename(inp, expected):
|
def test_sanitize_filename(inp, platform, expected, monkeypatch):
|
||||||
|
is_platform(monkeypatch, platform)
|
||||||
assert utils.sanitize_filename(inp) == expected
|
assert utils.sanitize_filename(inp) == expected
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user