highlevel tests import io from unittest import mock import pytest import httpie import httpie main from fixtures import filecontent filepath from httpie cli exceptions import parseerror from httpie context import environment from httpie encoding import utf8 from httpie status import exitstatus from utils import httpok mockenvironment stdinbytesio http def testmainentrypoint patch stdin to bypass pytest capture with mock patch objectenvironment stdin io stringio assert httpie main main exitstatus error value mock patch httpie core main def testmainentrypointkeyboardinterruptmain main sideeffect keyboardinterrupt with mock patch objectenvironment stdin io stringio assert httpie main main exitstatus errorctrlc value def testdebug r http debug assert r exitstatus exitstatus success assert f httpie httpie version in r stderr def testhelp r http help tolerateerrorexitstatustrue assert r exitstatus exitstatus success assert https github comhttpiecliissues in r def testversion r http version tolerateerrorexitstatustrue assert r exitstatus exitstatus success assert httpie version r strip def testgethttpbinboth r http get httpbinboth get assert httpok in r def testpathdotnormalization r http offline example org etcpassword paramvalue assert get etcpassword paramvalue in r def testpathasis r http offline pathasis example org etcpassword paramvalue assert get etcpassword paramvalue in r def testdeletehttpbinboth r http delete httpbinboth delete assert httpok in r def testputhttpbinboth r http put httpbinboth put foobar assert httpok in r assert r json json foo bar def testpostjsondatahttpbinboth r http post httpbinboth post foobar assert httpok in r assert r json json foo bar def testpostformhttpbinboth r http form post httpbinboth post foobar assert httpok in r assert foo bar in r def testpostformmultiplevalueshttpbinboth r http form post httpbinboth post foobar foobaz assert httpok in r assert r json form foo bar baz def testpostrawhttpbinboth r http raw foo bar post httpbinboth post assert httpok in r assert foo bar in r def testpoststdinhttpbinboth env mockenvironment stdinstdinbytesiofilepath readbytes stdinisattyfalse r http form post httpbinboth post envenv assert httpok in r assert filecontent in r def testpostfilehttpbinboth r http form post httpbinboth post f filefilepath assert httpok in r assert filecontent in r def testformpostfileredirectedstdinhttpbin with openfilepath encodingutf8 r http form post httpbin post f filefilepath tolerateerrorexitstatustrue envmockenvironment stdinstdinbytesiofilepath readbytes stdinisattyfalse assert r exitstatus exitstatus error assert cannot be mixed in r stderr def testrawpostkeyvaluessuppliedhttpbin r http raw foo bar post httpbin post foobar tolerateerrorexitstatustrue assert r exitstatus exitstatus error assert cannot be mixed in r stderr def testrawpostredirectedstdinhttpbin r http raw foo bar post httpbin post tolerateerrorexitstatustrue envmockenvironment stdin somevalue stdinisattyfalse assert r exitstatus exitstatus error assert cannot be mixed in r stderr def testheadershttpbinboth r http get httpbinboth headers foo bar assert httpok in r assert useragent httpie in r r assert foo bar in r def testheadersunsethttpbinboth r http get httpbinboth headers assert accept in r json headers default accept present r http get httpbinboth headers accept assert accept not in r json headers default accept unset pytest mark skip unimplemented def testunsethostheaderhttpbinboth r http get httpbinboth headers assert host in r json headers default host present r http get httpbinboth headers host assert host not in r json headers default host unset def testunsetuseragentheaderhttpbinboth r http get httpbinboth headers assert useragent in r json headers default useragent present r http get httpbinboth headers useragent assert useragent not in r json headers default useragent unset def testheadersemptyvaluehttpbinboth r http get httpbinboth headers assert r json headers accept default accept has value r http get httpbinboth headers accept assert r json headers accept accept has no value def testheadersemptyvaluewithvaluegiveserrorhttpbin with pytest raisesparseerror http get httpbin headers accept syntaxerror def testheadersomithttpbinboth r http get httpbinboth headers accept assert accept not in r json headers def testheadersmultipleomithttpbinboth r http get httpbinboth headers foo bar bar baz foo baz quux assert foo not in r json headers assert r json headers bar baz assert r json headers baz quux def testheaderssameafteromithttpbinboth r http get httpbinboth headers foo bar foo foo quux assert r json headers foo quux def testheadersfullyomithttpbinboth r http get httpbinboth headers foo bar foo baz foo assert foo not in r json headers def testheadersmultiplevalueshttpbinboth r http get httpbinboth headers foo bar foo baz assert r json headers foo bar baz def testheadersmultiplevaluesrepeatedhttpbinboth r http get httpbinboth headers foo bar foo baz foo bar assert r json headers foo bar baz bar pytest mark parametrizeheaders expected foo foo bar bar foo bar foo bar foo bar foo foo baz bar baz def testheadersmultiplevalueswithemptyhttpbinboth headers expected r http get httpbinboth headers headers assert r json headers foo expected def testheadersmultiplevaluesmixedhttpbinboth r http get httpbinboth headers foo bar vary xxx foo baz vary yyy foo quux assert r json headers vary xxx yyy assert r json headers foo bar baz quux def testheaderspreservepreparedheadershttpbinboth r http post httpbinboth post contentlength 0 raw foo assert r json headers contentlength 3 pytest mark parametrize pretty format none def testheadersmultipleheadersrepresentationhttpbinboth pretty r http offline pretty pretty example org a a a b a c b a b b c c c c assert a a in r assert a b in r assert a c in r assert b a in r assert b b in r assert c c in r assert c c in r def testresponseheadersmultiplehttpserver r http get httpserver headers foo bar foo baz assert foo bar in r assert foo baz in r def testresponseheadersmultiplerepeatedhttpserver r http get httpserver headers foo bar foo baz foo bar assert r count foo bar 2 assert foo baz in r pytest mark parametrize pretty format none def testresponseheadersmultiplerepresentationhttpserver pretty r http pretty pretty httpserver headers a a a b a c b a b b c c c c assert a a in r assert a b in r assert a c in r assert b a in r assert b b in r assert c c in r assert c c in r def testjsoninputpreserveorderhttpbinboth r http patch httpbinboth patch order map 1 first 2 second assert httpok in r assert r json data order map 1 first 2 second pytest mark parametrize extraargs expectedcontentlength contentlength 0 0 contentlength xxx xxx rawdata 4 queryparamsomething 33 def testoptionscontentlengthpreservationhttpbin extraargs expectedcontentlength r http offline options httpbin anything extraargs assert f contentlength expectedcontentlength in r pytest mark parametrize method options options options def testoptionsdroppingredundantcontentlengthhttpbin method r http offline method httpbin anything assert contentlength not in r patch stdin to bypass pytest capture https github com httpie cli issues 840 default accept present default accept unset default host present default host unset default user agent present default user agent unset default accept has value accept has no value
import io
from unittest import mock

import pytest

import httpie
import httpie.__main__
from .fixtures import FILE_CONTENT, FILE_PATH
from httpie.cli.exceptions import ParseError
from httpie.context import Environment
from httpie.encoding import UTF8
from httpie.status import ExitStatus
from .utils import HTTP_OK, MockEnvironment, StdinBytesIO, http


def test_main_entry_point():
    
    with mock.patch.object(Environment, 'stdin', io.StringIO()):
        assert httpie.__main__.main() == ExitStatus.ERROR.value


@mock.patch('httpie.core.main')
def test_main_entry_point_keyboard_interrupt(main):
    main.side_effect = KeyboardInterrupt()
    with mock.patch.object(Environment, 'stdin', io.StringIO()):
        assert httpie.__main__.main() == ExitStatus.ERROR_CTRL_C.value


def test_debug():
    r = http('--debug')
    assert r.exit_status == ExitStatus.SUCCESS
    assert f'HTTPie {httpie.__version__}' in r.stderr


def test_help():
    r = http('--help', tolerate_error_exit_status=True)
    assert r.exit_status == ExitStatus.SUCCESS
    assert 'https://github.com/httpie/cli/issues' in r


def test_version():
    r = http('--version', tolerate_error_exit_status=True)
    assert r.exit_status == ExitStatus.SUCCESS
    assert httpie.__version__ == r.strip()


def test_GET(httpbin_both):
    r = http('GET', httpbin_both + '/get')
    assert HTTP_OK in r


def test_path_dot_normalization():
    r = http(
        '--offline',
        'example.org/../../etc/password',
        'param==value'
    )
    assert 'GET /etc/password?param=value' in r


def test_path_as_is():
    r = http(
        '--offline',
        '--path-as-is',
        'example.org/../../etc/password',
        'param==value'
    )
    assert 'GET /../../etc/password?param=value' in r


def test_DELETE(httpbin_both):
    r = http('DELETE', httpbin_both + '/delete')
    assert HTTP_OK in r


def test_PUT(httpbin_both):
    r = http('PUT', httpbin_both + '/put', 'foo=bar')
    assert HTTP_OK in r
    assert r.json['json']['foo'] == 'bar'


def test_POST_JSON_data(httpbin_both):
    r = http('POST', httpbin_both + '/post', 'foo=bar')
    assert HTTP_OK in r
    assert r.json['json']['foo'] == 'bar'


def test_POST_form(httpbin_both):
    r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar')
    assert HTTP_OK in r
    assert '"foo": "bar"' in r


def test_POST_form_multiple_values(httpbin_both):
    r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar', 'foo=baz')
    assert HTTP_OK in r
    assert r.json['form'] == {
        'foo': ['bar', 'baz']
    }


def test_POST_raw(httpbin_both):
    r = http('--raw', 'foo bar', 'POST', httpbin_both + '/post')
    assert HTTP_OK in r
    assert '"foo bar"' in r


def test_POST_stdin(httpbin_both):
    env = MockEnvironment(
        stdin=StdinBytesIO(FILE_PATH.read_bytes()),
        stdin_isatty=False,
    )
    r = http('--form', 'POST', httpbin_both + '/post', env=env)
    assert HTTP_OK in r
    assert FILE_CONTENT in r


def test_POST_file(httpbin_both):
    r = http('--form', 'POST', httpbin_both + '/post', f'file@{FILE_PATH}')
    assert HTTP_OK in r
    assert FILE_CONTENT in r


def test_form_POST_file_redirected_stdin(httpbin):
    
    with open(FILE_PATH, encoding=UTF8):
        r = http(
            '--form',
            'POST',
            httpbin + '/post',
            f'file@{FILE_PATH}',
            tolerate_error_exit_status=True,
            env=MockEnvironment(
                stdin=StdinBytesIO(FILE_PATH.read_bytes()),
                stdin_isatty=False,
            ),
        )
    assert r.exit_status == ExitStatus.ERROR
    assert 'cannot be mixed' in r.stderr


def test_raw_POST_key_values_supplied(httpbin):
    r = http(
        '--raw',
        'foo bar',
        'POST',
        httpbin + '/post',
        'foo=bar',
        tolerate_error_exit_status=True,
    )
    assert r.exit_status == ExitStatus.ERROR
    assert 'cannot be mixed' in r.stderr


def test_raw_POST_redirected_stdin(httpbin):
    r = http(
        '--raw',
        'foo bar',
        'POST',
        httpbin + '/post',
        tolerate_error_exit_status=True,
        env=MockEnvironment(
            stdin='some=value',
            stdin_isatty=False,
        ),
    )
    assert r.exit_status == ExitStatus.ERROR
    assert 'cannot be mixed' in r.stderr


def test_headers(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar')
    assert HTTP_OK in r
    assert '"User-Agent": "HTTPie' in r, r
    assert '"Foo": "bar"' in r


def test_headers_unset(httpbin_both):
    r = http('GET', httpbin_both + '/headers')
    assert 'Accept' in r.json['headers']  

    r = http('GET', httpbin_both + '/headers', 'Accept:')
    assert 'Accept' not in r.json['headers']  


@pytest.mark.skip('unimplemented')
def test_unset_host_header(httpbin_both):
    r = http('GET', httpbin_both + '/headers')
    assert 'Host' in r.json['headers']  

    r = http('GET', httpbin_both + '/headers', 'Host:')
    assert 'Host' not in r.json['headers']  


def test_unset_useragent_header(httpbin_both):
    r = http('GET', httpbin_both + '/headers')
    assert 'User-Agent' in r.json['headers']  

    r = http('GET', httpbin_both + '/headers', 'User-Agent:')
    assert 'User-Agent' not in r.json['headers']  


def test_headers_empty_value(httpbin_both):
    r = http('GET', httpbin_both + '/headers')
    assert r.json['headers']['Accept']  

    r = http('GET', httpbin_both + '/headers', 'Accept;')
    assert r.json['headers']['Accept'] == ''  


def test_headers_empty_value_with_value_gives_error(httpbin):
    with pytest.raises(ParseError):
        http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR')


def test_headers_omit(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Accept:')
    assert 'Accept' not in r.json['headers']


def test_headers_multiple_omit(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Bar:baz',
             'Foo:', 'Baz:quux')
    assert 'Foo' not in r.json['headers']
    assert r.json['headers']['Bar'] == 'baz'
    assert r.json['headers']['Baz'] == 'quux'


def test_headers_same_after_omit(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:',
             'Foo:quux')
    assert r.json['headers']['Foo'] == 'quux'


def test_headers_fully_omit(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz',
             'Foo:')
    assert 'Foo' not in r.json['headers']


def test_headers_multiple_values(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz')
    assert r.json['headers']['Foo'] == 'bar,baz'


def test_headers_multiple_values_repeated(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz',
             'Foo:bar')
    assert r.json['headers']['Foo'] == 'bar,baz,bar'


@pytest.mark.parametrize("headers, expected", [
    (
        ["Foo;", "Foo:bar"],
        ",bar"
    ),
    (
        ["Foo:bar", "Foo;"],
        "bar,"
    ),
    (
        ["Foo:bar", "Foo;", "Foo:baz"],
        "bar,,baz"
    ),
])
def test_headers_multiple_values_with_empty(httpbin_both, headers, expected):
    r = http('GET', httpbin_both + '/headers', *headers)
    assert r.json['headers']['Foo'] == expected


def test_headers_multiple_values_mixed(httpbin_both):
    r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Vary:XXX',
             'Foo:baz', 'Vary:YYY', 'Foo:quux')
    assert r.json['headers']['Vary'] == 'XXX,YYY'
    assert r.json['headers']['Foo'] == 'bar,baz,quux'


def test_headers_preserve_prepared_headers(httpbin_both):
    r = http('POST', httpbin_both + '/post', 'Content-Length:0',
             '--raw', 'foo')
    assert r.json['headers']['Content-Length'] == '3'


@pytest.mark.parametrize('pretty', ['format', 'none'])
def test_headers_multiple_headers_representation(httpbin_both, pretty):
    r = http('--offline', '--pretty', pretty, 'example.org',
             'A:A', 'A:B', 'A:C', 'B:A', 'B:B', 'C:C', 'c:c')

    assert 'A: A' in r
    assert 'A: B' in r
    assert 'A: C' in r
    assert 'B: A' in r
    assert 'B: B' in r
    assert 'C: C' in r
    assert 'c: c' in r


def test_response_headers_multiple(http_server):
    r = http('GET', http_server + '/headers', 'Foo:bar', 'Foo:baz')
    assert 'Foo: bar' in r
    assert 'Foo: baz' in r


def test_response_headers_multiple_repeated(http_server):
    r = http('GET', http_server + '/headers', 'Foo:bar', 'Foo:baz',
             'Foo:bar')
    assert r.count('Foo: bar') == 2
    assert 'Foo: baz' in r


@pytest.mark.parametrize('pretty', ['format', 'none'])
def test_response_headers_multiple_representation(http_server, pretty):
    r = http('--pretty', pretty, http_server + '/headers',
             'A:A', 'A:B', 'A:C', 'B:A', 'B:B', 'C:C', 'C:c')

    assert 'A: A' in r
    assert 'A: B' in r
    assert 'A: C' in r
    assert 'B: A' in r
    assert 'B: B' in r
    assert 'C: C' in r
    assert 'C: c' in r


def test_json_input_preserve_order(httpbin_both):
    r = http('PATCH', httpbin_both + '/patch',
             'order:={"map":{"1":"first","2":"second"}}')
    assert HTTP_OK in r
    assert r.json['data'] == \
        '{"order": {"map": {"1": "first", "2": "second"}}}'


@pytest.mark.parametrize('extra_args, expected_content_length', [
    (
        ['Content-Length:0'],
        '0'
    ),
    (
        ['Content-Length:xxx'],
        'xxx',
    ),
    (
        ['--raw=data'],
        '4'
    ),
    (
        ['query[param]=something'],
        '33'
    )
])
def test_options_content_length_preservation(httpbin, extra_args, expected_content_length):
    r = http(
        '--offline',
        'OPTIONS',
        httpbin + '/anything',
        *extra_args
    )
    assert f'Content-Length: {expected_content_length}' in r


@pytest.mark.parametrize('method', ['options', 'Options', 'OPTIONS'])
def test_options_dropping_redundant_content_length(httpbin, method):
    r = http(
        '--offline',
        method,
        httpbin + '/anything'
    )
    assert 'Content-Length' not in r