pip/tests/unit/test_compat.py

125 lines
3.9 KiB
Python

import locale
import os
import sys
import pytest
import pip._internal.utils.compat as pip_compat
from pip._internal.utils.compat import console_to_str, get_path_uid, str_to_display
def test_get_path_uid():
path = os.getcwd()
assert get_path_uid(path) == os.stat(path).st_uid
@pytest.mark.skipif("not hasattr(os, 'O_NOFOLLOW')")
def test_get_path_uid_without_NOFOLLOW(monkeypatch):
monkeypatch.delattr("os.O_NOFOLLOW")
path = os.getcwd()
assert get_path_uid(path) == os.stat(path).st_uid
# Skip unconditionally on Windows, as symlinks need admin privs there
@pytest.mark.skipif("sys.platform == 'win32'")
@pytest.mark.skipif("not hasattr(os, 'symlink')")
def test_get_path_uid_symlink(tmpdir):
f = tmpdir / "symlink" / "somefile"
f.parent.mkdir()
f.write_text("content")
fs = f + '_link'
os.symlink(f, fs)
with pytest.raises(OSError):
get_path_uid(fs)
@pytest.mark.skipif("not hasattr(os, 'O_NOFOLLOW')")
@pytest.mark.skipif("not hasattr(os, 'symlink')")
def test_get_path_uid_symlink_without_NOFOLLOW(tmpdir, monkeypatch):
monkeypatch.delattr("os.O_NOFOLLOW")
f = tmpdir / "symlink" / "somefile"
f.parent.mkdir()
f.write_text("content")
fs = f + '_link'
os.symlink(f, fs)
with pytest.raises(OSError):
get_path_uid(fs)
@pytest.mark.parametrize('data, expected', [
('abc', 'abc'),
# Test text input with non-ascii characters.
('déf', 'déf'),
])
def test_str_to_display(data, expected):
actual = str_to_display(data)
assert actual == expected, (
# Show the encoding for easier troubleshooting.
f'encoding: {locale.getpreferredencoding()!r}'
)
@pytest.mark.parametrize('data, encoding, expected', [
# Test str input with non-ascii characters.
('déf', 'utf-8', 'déf'),
# Test bytes input with non-ascii characters:
('déf'.encode('utf-8'), 'utf-8', 'déf'),
# Test a Windows encoding.
('déf'.encode('cp1252'), 'cp1252', 'déf'),
# Test a Windows encoding with incompatibly encoded text.
('déf'.encode('utf-8'), 'cp1252', 'déf'),
])
def test_str_to_display__encoding(monkeypatch, data, encoding, expected):
monkeypatch.setattr(locale, 'getpreferredencoding', lambda: encoding)
actual = str_to_display(data)
assert actual == expected, (
# Show the encoding for easier troubleshooting.
f'encoding: {locale.getpreferredencoding()!r}'
)
def test_str_to_display__decode_error(monkeypatch, caplog):
monkeypatch.setattr(locale, 'getpreferredencoding', lambda: 'utf-8')
# Encode with an incompatible encoding.
data = 'ab'.encode('utf-16')
actual = str_to_display(data)
# Keep the expected value endian safe
if sys.byteorder == "little":
expected = "\\xff\\xfea\x00b\x00"
elif sys.byteorder == "big":
expected = "\\xfe\\xff\x00a\x00b"
assert actual == expected, (
# Show the encoding for easier troubleshooting.
f'encoding: {locale.getpreferredencoding()!r}'
)
assert len(caplog.records) == 1
record = caplog.records[0]
assert record.levelname == 'WARNING'
assert record.message == (
'Bytes object does not appear to be encoded as utf-8'
)
def test_console_to_str(monkeypatch):
some_bytes = b"a\xE9\xC3\xE9b"
encodings = ('ascii', 'utf-8', 'iso-8859-1', 'iso-8859-5',
'koi8_r', 'cp850')
for e in encodings:
monkeypatch.setattr(locale, 'getpreferredencoding', lambda: e)
result = console_to_str(some_bytes)
assert result.startswith("a")
assert result.endswith("b")
def test_console_to_str_warning(monkeypatch):
some_bytes = b"a\xE9b"
def check_warning(msg, *args, **kwargs):
assert 'does not appear to be encoded as' in msg
assert args[0] == 'Subprocess output'
monkeypatch.setattr(locale, 'getpreferredencoding', lambda: 'utf-8')
monkeypatch.setattr(pip_compat.logger, 'warning', check_warning)
console_to_str(some_bytes)