diff --git a/httpie/output/ui/man_pages.py b/httpie/output/ui/man_pages.py index 0ba4974578..6cba3fed1d 100644 --- a/httpie/output/ui/man_pages.py +++ b/httpie/output/ui/man_pages.py @@ -2,6 +2,7 @@ import subprocess import os +import sys from httpie.context import Environment @@ -18,7 +19,7 @@ def is_available(program: str) -> bool: Check whether `program`'s man pages are available on this system. """ - if NO_MAN_PAGES or os.system == 'nt': + if NO_MAN_PAGES or sys.platform == "win32": return False try: process = subprocess.run( diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 62814161ed..4affecc75b 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -4,6 +4,7 @@ """ import pytest import responses +from charset_normalizer import from_bytes from charset_normalizer.constant import TOO_SMALL_SEQUENCE from httpie.cli.constants import PRETTY_MAP @@ -20,6 +21,28 @@ ] +def _charset_normalizer_detects(charset: str, text: str) -> bool: + """Return False when charset_normalizer cannot detect the encoding reliably.""" + if charset == UTF8: + return True + match = from_bytes(text.encode(charset)).best() + if not match or not match.encoding: + return False + detected = match.encoding.lower().replace('_', '-') + expected = charset.lower().replace('_', '-') + return detected == expected or detected.startswith(expected.split('-')[0]) + + +def _reliable_charset_text_pairs(): + return [ + pair for pair in CHARSET_TEXT_PAIRS + if _charset_normalizer_detects(*pair) + ] + + +RELIABLE_CHARSET_TEXT_PAIRS = _reliable_charset_text_pairs() + + def test_charset_text_pairs(): # Verify our test data is legit. for charset, text in CHARSET_TEXT_PAIRS: @@ -134,7 +157,7 @@ def test_unicode_digest_auth(httpbin): f'{httpbin}/digest-auth/auth/test/{UNICODE}') -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @responses.activate def test_terminal_output_response_charset_detection(text, charset): responses.add( @@ -147,7 +170,7 @@ def test_terminal_output_response_charset_detection(text, charset): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @responses.activate def test_terminal_output_response_content_type_charset(charset, text): responses.add( @@ -160,7 +183,7 @@ def test_terminal_output_response_content_type_charset(charset, text): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) @responses.activate def test_terminal_output_response_content_type_charset_with_stream(charset, text, pretty): @@ -175,7 +198,7 @@ def test_terminal_output_response_content_type_charset_with_stream(charset, text assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) @responses.activate def test_terminal_output_response_charset_override(charset, text, pretty): @@ -194,7 +217,7 @@ def test_terminal_output_response_charset_override(charset, text, pretty): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) def test_terminal_output_request_content_type_charset(charset, text): r = http( '--offline', @@ -208,7 +231,7 @@ def test_terminal_output_request_content_type_charset(charset, text): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) def test_terminal_output_request_charset_detection(charset, text): r = http( '--offline', diff --git a/tests/test_man_pages.py b/tests/test_man_pages.py new file mode 100644 index 0000000000..ef5f6f4c44 --- /dev/null +++ b/tests/test_man_pages.py @@ -0,0 +1,48 @@ +from httpie.output.ui.man_pages import is_available + + +def test_is_available_returns_false_on_windows(monkeypatch): + monkeypatch.setattr("httpie.output.ui.man_pages.sys.platform", "win32") + assert is_available("http") is False + + +def test_is_available_honors_no_man_pages_env(monkeypatch): + monkeypatch.setattr("httpie.output.ui.man_pages.NO_MAN_PAGES", True) + monkeypatch.setattr("httpie.output.ui.man_pages.sys.platform", "linux") + assert is_available("http") is False + + +def test_is_available_returns_true_when_man_succeeds(monkeypatch): + monkeypatch.setattr("httpie.output.ui.man_pages.sys.platform", "linux") + + class CompletedProcess: + returncode = 0 + + monkeypatch.setattr( + "httpie.output.ui.man_pages.subprocess.run", + lambda *args, **kwargs: CompletedProcess(), + ) + assert is_available("http") is True + + +def test_is_available_returns_false_when_man_fails(monkeypatch): + monkeypatch.setattr("httpie.output.ui.man_pages.sys.platform", "linux") + + class CompletedProcess: + returncode = 1 + + monkeypatch.setattr( + "httpie.output.ui.man_pages.subprocess.run", + lambda *args, **kwargs: CompletedProcess(), + ) + assert is_available("http") is False + + +def test_is_available_returns_false_when_man_raises(monkeypatch): + monkeypatch.setattr("httpie.output.ui.man_pages.sys.platform", "linux") + + def raise_error(*args, **kwargs): + raise OSError("no man") + + monkeypatch.setattr("httpie.output.ui.man_pages.subprocess.run", raise_error) + assert is_available("http") is False